Add context sharing on prefabs.

This commit is contained in:
2024-12-03 17:15:39 -06:00
parent 68fab7c94d
commit 5998037994
30 changed files with 166 additions and 177 deletions

View File

@@ -35,7 +35,9 @@ void LoaderForSceneItems::setupDependencies() {
loader = getAssetManager()->get<JSONLoader>(path);
} else if(type == "prefab") {
loader = getAssetManager()->get<PrefabLoader>(path);
auto prefabLoader = getAssetManager()->get<PrefabLoader>(path);
prefabLoader->parentLoader = weak_from_this();
loader = prefabLoader;
} else {
assertUnreachable("Unknown asset type: %s", type.c_str());

View File

@@ -8,10 +8,14 @@
#include "scene/Scene.hpp"
namespace Dawn {
class LoaderForSceneItems : public AssetLoader {
class LoaderForSceneitems;
class LoaderForSceneItems :
public AssetLoader,
public std::enable_shared_from_this<LoaderForSceneItems>
{
protected:
std::shared_ptr<JSONLoader> jsonLoader;
struct SceneComponentLoadContext ctx;
/**
* Loads the dependencies into the context for the data available in
@@ -20,6 +24,8 @@ namespace Dawn {
void setupDependencies();
public:
struct SceneComponentLoadContext ctx;
LoaderForSceneItems(
const std::shared_ptr<AssetManager> assetManager,
const std::string name

View File

@@ -4,6 +4,7 @@
// https://opensource.org/licenses/MIT
#include "PrefabLoader.hpp"
#include "SceneLoader.hpp"
#include "game/Game.hpp"
#include "assert/assert.hpp"
#include "asset/loader/TextureLoader.hpp"
@@ -64,6 +65,11 @@ std::string PrefabLoader::getAssetType() const {
void PrefabLoader::stagePrefab(std::shared_ptr<SceneItem> item) {
assertTrue(this->loaded, "Prefab not loaded");
// Can we merge with the parent context?
auto parentLoaderLock = this->parentLoader.lock();
if(parentLoaderLock) this->ctx.merge(parentLoaderLock->ctx);
// Force-set new context values
ctx.scene = item->getScene();
ctx.data = this->jsonLoader->data;

View File

@@ -8,6 +8,7 @@
#include "scene/Scene.hpp"
namespace Dawn {
enum class PrefabLoaderState {
INITIAL,
LOADING_JSON,
@@ -23,6 +24,7 @@ namespace Dawn {
public:
const static std::string ASSET_TYPE;
std::weak_ptr<LoaderForSceneItems> parentLoader;
PrefabLoader(
const std::shared_ptr<AssetManager> assetManager,

View File

@@ -5,48 +5,29 @@
#include "SceneComponentRegistry.hpp"
#include "component/display/Camera.hpp"
#include "component/display/material/SimpleTexturedMaterial.hpp"
#include "component/display/MeshRenderer.hpp"
#include "component/display/mesh/CubeMeshComponent.hpp"
#ifdef DAWN_ENABLE_PHYSICS
#include "component/physics/CubeCollider.hpp"
#include "component/physics/SphereCollider.hpp"
#endif
using namespace Dawn;
std::unordered_map<
std::string,
std::function<std::shared_ptr<SceneComponent>(
const std::shared_ptr<SceneItem> &
)>
> SceneComponentRegistry::REGISTRY = {
};
std::shared_ptr<SceneComponent> SceneComponentRegistry::createComponent(
const std::string &type,
const std::shared_ptr<SceneItem> &item
) {
if(type.length() == 0) {
assertUnreachable("Component type is empty!");
auto typeLower = String::toLowercase(type);
assertMapHasKey(
SceneComponentRegistry::REGISTRY,
typeLower,
"Component type not registered: %s",
type.c_str()
);
} else if(type == "Camera") {
return item->addComponent<Camera>();
} else if(type == "SimpleTexturedMaterial") {
return item->addComponent<SimpleTexturedMaterial>();
} else if(type == "MeshRenderer") {
return item->addComponent<MeshRenderer>();
} else if(type == "CubeMesh" || type == "CubeMeshComponent") {
return item->addComponent<CubeMeshComponent>();
#ifdef DAWN_ENABLE_PHYSICS
} else if(type == "CubeCollider") {
return item->addComponent<CubeCollider>();
} else if(type == "SphereCollider") {
return item->addComponent<SphereCollider>();
#endif
} else {
assertUnreachable("Unknown component type: %s", type.c_str());
}
return nullptr;
return SceneComponentRegistry::REGISTRY[typeLower](item);
}

View File

@@ -5,10 +5,30 @@
#pragma once
#include "scene/Scene.hpp"
#include "util/String.hpp"
namespace Dawn {
class SceneComponentRegistry final {
private:
public:
static std::unordered_map<
std::string,
std::function<std::shared_ptr<SceneComponent>(
const std::shared_ptr<SceneItem> &
)>
> REGISTRY;
template<class T>
static void reg(const std::string name) {
auto nameLower = String::toLowercase(name);
SceneComponentRegistry::REGISTRY[nameLower] = [](
const std::shared_ptr<SceneItem> &item
) {
return item->addComponent<T>();
};
}
/**
* Creates a scene component by its type name. Type names are unique and
* must be registered in order to be constructed by their string name.

View File

@@ -21,7 +21,7 @@ void Camera::onDispose() {
renderTarget = nullptr;
}
void Camera::load(const SceneComponentLoadContext &ctx) {
void Camera::load(SceneComponentLoadContext &ctx) {
SceneComponent::load(ctx);
if(ctx.data.contains("fov")) {

View File

@@ -33,7 +33,7 @@ namespace Dawn {
void onInit() override;
void onDispose() override;
void load(const SceneComponentLoadContext &ctx) override;
void load(SceneComponentLoadContext &ctx) override;
/**
* Returns the aspect ratio that the camera is using. In future I may

View File

@@ -9,7 +9,7 @@
using namespace Dawn;
void SimpleTexturedMaterial::load(const SceneComponentLoadContext &ctx) {
void SimpleTexturedMaterial::load(SceneComponentLoadContext &ctx) {
if(ctx.data.contains("color")) {
this->setColor(JSON::color(ctx.data["color"]));
}

View File

@@ -15,7 +15,7 @@ namespace Dawn {
std::shared_ptr<Texture> texture;
public:
void load(const SceneComponentLoadContext &ctx) override;
void load(SceneComponentLoadContext &ctx) override;
/**
* Returns the color of this material.

View File

@@ -27,7 +27,7 @@ void CubeMeshComponent::onDispose() {
mesh = nullptr;
}
void CubeMeshComponent::load(const SceneComponentLoadContext &ctx) {
void CubeMeshComponent::load(SceneComponentLoadContext &ctx) {
if(!mesh) mesh = std::make_shared<Mesh>();
}

View File

@@ -14,6 +14,6 @@ namespace Dawn {
void onInit() override;
void onDispose() override;
void load(const SceneComponentLoadContext &ctx) override;
void load(SceneComponentLoadContext &ctx) override;
};
}

View File

@@ -6,13 +6,26 @@
#include "game/Game.hpp"
#include "scene/Scene.hpp"
#include "util/Flag.hpp"
#include "asset/loader/SceneLoader.hpp"
#include "component/SceneComponentRegistry.hpp"
// Components to register
#include "component/display/Camera.hpp"
#include "component/display/material/SimpleTexturedMaterial.hpp"
#include "component/display/MeshRenderer.hpp"
#include "component/display/mesh/CubeMeshComponent.hpp"
#ifdef DAWN_ENABLE_PHYSICS
#endif
using namespace Dawn;
IGame::IGame() {
SceneComponentRegistry::reg<Camera>("Camera");
SceneComponentRegistry::reg<SimpleTexturedMaterial>("SimpleTexturedMaterial");
SceneComponentRegistry::reg<MeshRenderer>("MeshRenderer");
SceneComponentRegistry::reg<CubeMeshComponent>("CubeMeshComponent");
SceneComponentRegistry::reg<CubeMeshComponent>("CubeMesh");
}
void IGame::init() {

View File

@@ -59,7 +59,7 @@ std::shared_ptr<Game> SceneComponent::getGame() {
return this->getScene()->getGame();
}
void SceneComponent::load(const SceneComponentLoadContext &context) {
void SceneComponent::load(SceneComponentLoadContext &context) {
// Override this method to load data from a JSON object.
}

View File

@@ -35,6 +35,21 @@ namespace Dawn {
assertNotNull(asset, "Asset is not of the correct type.");
return asset;
}
void merge(const struct SceneComponentLoadContext &ctx) {
for(auto &item : ctx.items) {
if(items.find(item.first) != items.end()) continue;
this->items[item.first] = item.second;
}
for(auto &cmp : ctx.components) {
if(components.find(cmp.first) != components.end()) continue;
this->components[cmp.first] = cmp.second;
}
for(auto &asset : ctx.assets) {
if(assets.find(asset.first) != assets.end()) continue;
this->assets[asset.first] = asset.second;
}
}
};
class SceneComponent : std::enable_shared_from_this<SceneComponent> {
@@ -104,7 +119,7 @@ namespace Dawn {
*
* @param json JSON Data that this object needs to load.
*/
virtual void load(const SceneComponentLoadContext &context);
virtual void load(SceneComponentLoadContext &context);
/**
* Disposes this scene component.

View File

@@ -76,7 +76,7 @@ void SceneItem::deinit() {
this->components.clear();
}
void SceneItem::load(const SceneComponentLoadContext &ctx) {
void SceneItem::load(SceneComponentLoadContext &ctx) {
// Load prefab first, it can be overriden by other properties.
if(ctx.data.contains("prefab")) {
auto prefabLoader = ctx.getAsset<PrefabLoader>(

View File

@@ -55,7 +55,7 @@ namespace Dawn {
*
* @param ctx Context to load this scene item from.
*/
void load(const SceneComponentLoadContext &ctx);
void load(SceneComponentLoadContext &ctx);
/**
* Returns the scene that this scene item belongs to.