// Copyright (c) 2023 Dominic Masters // // This software is released under the MIT License. // https://opensource.org/licenses/MIT #include "scene/SceneItem.hpp" #include "scene/Scene.hpp" #include "util/JSON.hpp" #include "assert/assert.hpp" #include "asset/loader/scene/PrefabLoader.hpp" using namespace Dawn; SceneItem::SceneItem(const std::weak_ptr scene) : scene(scene), SceneItemTransform(), SceneItemComponents() { } std::shared_ptr SceneItem::sceneItemComponentsSelf() { return shared_from_this(); } std::shared_ptr SceneItem::getScene() { auto s = scene.lock(); assertNotNull(s, "Scene has unloaded?"); return s; } void SceneItem::init() { assertFlagOff(state, SceneItemState::INITIALIZED, "Already initialized."); assertFlagOff(state, SceneItemState::DEINITIALIZED, "Already deinited."); Flag::turnOn(state, SceneItemState::INITIALIZED); auto sharedThis = shared_from_this(); // Loop until all components initialized... while(true) { // Create copy of the components, components may chose to add more // components but those sub components will not be initialized at this time. auto components = this->components; for(auto &component : components) { if(component->isInitialized()) continue; component->init(sharedThis); } // If they are all initalized we are fine. components = this->components; bool_t allInitialized = std::all_of( components.begin(), components.end(), [](auto &component) { return component->isInitialized(); } ); if(allInitialized) break; } } void SceneItem::deinit() { assertFlagOn(state, SceneItemState::INITIALIZED, "SceneItem not ready."); assertFlagOff(state, SceneItemState::DEINITIALIZED, "Already deinited"); Flag::turnOn(state, SceneItemState::DEINITIALIZED); // Create copy of the components, components may chose to add more components // but those sub components will not be disposed at this time. auto components = this->components; for(auto &component : components) { if(!component->isInitialized()) continue; component->dispose(); } this->components.clear(); } void SceneItem::load(std::shared_ptr ctx) { // Load prefab first, it can be overriden by other properties. if(ctx->data.contains("prefab")) { this->name = ctx->data["prefab"].get(); auto prefabLoader = ctx->getAsset(this->name); prefabLoader->stagePrefab(shared_from_this()); } if(ctx->data.contains("name")) { this->name = ctx->data["name"].get(); } // Transforms if(ctx->data.contains("position")) { this->setLocalPosition(JSON::vec3(ctx->data["position"])); } if(ctx->data.contains("lookAt")) { auto &lookAt = ctx->data["lookAt"]; glm::vec3 pos = glm::vec3(3, 3, 3); glm::vec3 look = glm::vec3(0, 0, 0); glm::vec3 up = glm::vec3(0, 1, 0); if(lookAt.contains("position")) pos = JSON::vec3(lookAt["position"]); if(lookAt.contains("look")) look = JSON::vec3(lookAt["look"]); if(lookAt.contains("up")) up = JSON::vec3(lookAt["up"]); this->lookAt(pos, look, up); } if(ctx->data.contains("scale")) { this->setLocalScale(JSON::vec3(ctx->data["scale"])); } } void SceneItem::remove() { auto scene = getScene(); if(!scene) return; scene->removeItem(shared_from_this()); } SceneItem::~SceneItem() { if(Flag::isOn(state, SceneItemState::INITIALIZED)) { assertFlagOn(state, SceneItemState::DEINITIALIZED, "Not deinited"); } }