Browse Source

Component+Scene: Restructure scene .json to allow multiple components

master
Riyyi 11 months ago
parent
commit
0dd7a05d46
  1. 58
      assets/scene/scene1.json
  2. 26
      src/inferno/component/cameracomponent.cpp
  3. 3
      src/inferno/component/cameracomponent.h
  4. 22
      src/inferno/component/id-component.cpp
  5. 28
      src/inferno/component/id-component.h
  6. 21
      src/inferno/component/luascriptcomponent.cpp
  7. 7
      src/inferno/component/luascriptcomponent.h
  8. 21
      src/inferno/component/nativescriptcomponent.cpp
  9. 19
      src/inferno/component/nativescriptcomponent.h
  10. 22
      src/inferno/component/tagcomponent.cpp
  11. 4
      src/inferno/component/tagcomponent.h
  12. 108
      src/inferno/scene/scene.cpp
  13. 10
      src/inferno/scene/scene.h
  14. 4
      src/inferno/script/nativescript.h
  15. 38
      src/inferno/uid.cpp
  16. 47
      src/inferno/uid.h

58
assets/scene/scene1.json

@ -1,50 +1,68 @@
{
"init": "assets/lua/scene1-init.lua",
"camera": {
"name": "Camera",
"translate": [ 0.0, 0.0, 1.0 ],
"rotate": [ 0.0, 0.0, -1.0 ],
"scale": [ 1.0, 1.0, 1.0 ],
"type": "perspective",
"script": {
"type": "lua",
"name": "assets/lua/cameracontroller.lua"
}
"entities": [
{
"id": { "id": 12312312 },
"tag": { "tag": "Camera" },
"transform" : {
"translate": [0.0, 0.0, 1.0],
"rotate": [0.0, 0.0, -1.0],
"scale": [1.0, 1.0, 1.0]
},
"camera": { "type": "perspective" },
"lua-scripts": [
{ "path": "assets/lua/cameracontroller.lua" }
]
},
"quad": [
{
"name": "Quad",
"id": { "id": 564564564 },
"tag": { "tag": "Quad" },
"transform" : {
"translate": [ 0.0, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 1.0, 1.0, 1.0 ],
"scale": [ 1.0, 1.0, 1.0 ]
},
"sprite": {
"color": [ 1.0, 1.0, 1.0, 1.0 ],
"texture": "assets/gfx/test.png"
}
},
{
"name": "Quad 2",
"id": { "id": 97897897 },
"tag": { "tag": "Quad 2" },
"transform" : {
"translate": [ 1.1, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 1.0, 1.0, 1.0 ],
"scale": [ 1.0, 1.0, 1.0 ]
},
"sprite": {
"color": [ 0.5, 0.6, 0.8, 1.0 ],
"texture": "assets/gfx/test.png"
}
},
{
"name": "Quad 3",
"id": { "id": 3424242 },
"tag": { "tag": "Quad 3" },
"transform" : {
"translate": [ 2.2, 0.0, 0.0 ],
"rotate": [ 0.0, 0.0, 0.0 ],
"scale": [ 1.0, 1.0, 1.0 ],
"scale": [ 1.0, 1.0, 1.0 ]
},
"sprite": {
"color": [ 1.0, 1.0, 1.0, 1.0 ],
"texture": "assets/gfx/test-inverted.png"
}
],
"text": [
},
{
"name": "Text",
"id": { "id": 675754 },
"tag": { "tag": "Text" },
"text": {
"content": "Hello World!",
"font": "assets/fnt/open-sans",
"font-size": 24,
"line-spacing": 1.0,
"width": 150
}
}
]
}

26
src/inferno/component/cameracomponent.cpp

@ -0,0 +1,26 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "ruc/format/print.h"
#include "ruc/json/json.h"
#include "inferno/component/cameracomponent.h"
namespace Inferno {
void fromJson(const ruc::Json& json, CameraComponent& value)
{
VERIFY(json.type() == ruc::Json::Type::Object);
if (json.exists("type")) {
value.type = json.at("type").get<std::string>() == "orthographic" ? CameraType::Orthographic : CameraType::Perspective;
}
if (json.exists("zoom-level")) {
json.at("zoom-level").getTo(value.zoomLevel);
}
}
} // namespace Inferno

3
src/inferno/component/cameracomponent.h

@ -8,6 +8,7 @@
#include "glm/ext/matrix_float4x4.hpp" // glm::mat4
#include "glm/ext/vector_float3.hpp" // glm::vec3
#include "ruc/json/json.h"
namespace Inferno {
@ -32,4 +33,6 @@ struct CameraComponent {
glm::mat4 projection { 1.0f }; // Identity matrix
};
void fromJson(const ruc::Json& json, CameraComponent& value);
} // namespace Inferno

22
src/inferno/component/id-component.cpp

@ -0,0 +1,22 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "ruc/json/json.h"
#include "inferno/component/id-component.h"
namespace Inferno {
void fromJson(const ruc::Json& json, IDComponent& value)
{
VERIFY(json.type() == ruc::Json::Type::Object);
if (json.exists("id")) {
json.at("id").getTo(value.id);
}
}
} // namespace Inferno

28
src/inferno/component/id-component.h

@ -0,0 +1,28 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include "ruc/json/json.h"
#include "inferno/uid.h"
namespace Inferno {
struct IDComponent {
UID id;
IDComponent() = default;
IDComponent(UID id)
: id(id)
{
}
IDComponent(const IDComponent&) = default;
};
void fromJson(const ruc::Json& json, IDComponent& value);
} // namespace Inferno

21
src/inferno/component/luascriptcomponent.cpp

@ -0,0 +1,21 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "ruc/json/json.h"
#include "inferno/component/luascriptcomponent.h"
namespace Inferno {
void fromJson(const ruc::Json& json, LuaScriptComponent& value)
{
VERIFY(json.type() == ruc::Json::Type::Object);
VERIFY(json.exists("path"), "path not found");
json.at("path").getTo(value.path);
}
} // namespace Inferno

7
src/inferno/component/luascriptcomponent.h

@ -6,9 +6,11 @@
#pragma once
#include <string> // std::string
#include <string>
#include <utility> // std::move
#include "ruc/json/json.h"
namespace Inferno {
class LuaScript;
@ -24,4 +26,7 @@ struct LuaScriptComponent {
{
}
};
void fromJson(const ruc::Json& json, LuaScriptComponent& value);
} // namespace Inferno

21
src/inferno/component/nativescriptcomponent.cpp

@ -0,0 +1,21 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "ruc/json/json.h"
#include "inferno/component/nativescriptcomponent.h"
namespace Inferno {
void fromJson(const ruc::Json& json, NativeScriptComponent& value)
{
VERIFY(json.type() == ruc::Json::Type::Object);
VERIFY(json.exists("name"), "name not found");
json.at("name").getTo(value.name);
}
} // namespace Inferno

19
src/inferno/component/nativescriptcomponent.h

@ -7,6 +7,7 @@
#pragma once
#include <string>
#include <utility> // std::move
#include "inferno/script/nativescript.h"
@ -14,17 +15,29 @@ namespace Inferno {
struct NativeScriptComponent {
NativeScript* instance { nullptr };
std::string name;
NativeScript::InitializeFunction initialize { nullptr };
NativeScript::DestroyFunction destroy { nullptr };
// Dont allow manually setting instance during construction
NativeScriptComponent() {}
NativeScriptComponent(const std::string& binding)
NativeScriptComponent(const std::string& name)
: name(std::move(name))
{
initialize = NativeScriptBinding::the().initializeBinding(binding);
destroy = NativeScriptBinding::the().destroyBinding(binding);
bind();
}
void bind()
{
VERIFY(initialize == nullptr && destroy == nullptr, "NativeScript already bound");
VERIFY(name != "", "name not set");
initialize = NativeScriptBinding::the().initializeBinding(name);
destroy = NativeScriptBinding::the().destroyBinding(name);
}
};
void fromJson(const ruc::Json& json, NativeScriptComponent& value);
} // namespace Inferno

22
src/inferno/component/tagcomponent.cpp

@ -0,0 +1,22 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include "ruc/json/json.h"
#include "inferno/component/tagcomponent.h"
namespace Inferno {
void fromJson(const ruc::Json& json, TagComponent& value)
{
VERIFY(json.type() == ruc::Json::Type::Object);
if (json.exists("tag")) {
json.at("tag").getTo(value.tag);
}
}
} // namespace Inferno

4
src/inferno/component/tagcomponent.h

@ -9,6 +9,8 @@
#include <string> // std::string
#include <utility> // std::move
#include "ruc/json/json.h"
namespace Inferno {
struct TagComponent {
@ -23,4 +25,6 @@ struct TagComponent {
operator const std::string&() const { return tag; }
};
void fromJson(const ruc::Json& json, TagComponent& value);
} // namespace Inferno

108
src/inferno/scene/scene.cpp

@ -4,6 +4,7 @@
* SPDX-License-Identifier: MIT
*/
#include <cstddef> // size_t
#include <cstdint> // uint32_t
#include <limits> // std::numeric_limits
@ -13,6 +14,7 @@
#include "ruc/meta/assert.h"
#include "inferno/component/cameracomponent.h"
#include "inferno/component/id-component.h"
#include "inferno/component/luascriptcomponent.h"
#include "inferno/component/nativescriptcomponent.h"
#include "inferno/component/spritecomponent.h"
@ -26,6 +28,7 @@
#include "inferno/system/scriptsystem.h"
#include "inferno/system/textareasystem.h"
#include "inferno/system/transformsystem.h"
#include "inferno/uid.h"
namespace Inferno {
@ -47,54 +50,66 @@ void Scene::initialize()
auto sceneJson = ruc::Json::parse(ruc::File("assets/scene/scene1.json").data());
// Camera
if (sceneJson.exists("init")) {
// TODO: load either NativeScript or LuaScript?
}
// Entities
// -------------------------------------
if (sceneJson.exists("entities")) {
const auto& entityJson = sceneJson.at("entities");
VERIFY(entityJson.type() == ruc::Json::Type::Array);
const auto& entities = entityJson.asArray();
for (size_t i = 0; i < entities.size(); ++i) {
uint32_t entity = createEntity();
VERIFY(entities.at(i).type() == ruc::Json::Type::Object);
const auto& components = entities.at(i);
VERIFY(sceneJson.exists("camera"), "scene doesnt contain a camera");
auto& cameraJson = sceneJson.at("camera");
uint32_t camera = loadEntity(cameraJson);
// ID is required
VERIFY(components.exists("id"), "id not found");
auto& id = getComponent<IDComponent>(entity);
components.at("id").getTo(id);
auto& cameraComponent = addComponent<CameraComponent>(camera);
if (cameraJson.exists("type") && cameraJson.at("type").get<std::string>() == "orthographic") {
cameraComponent.type = CameraType::Orthographic;
if (components.exists("tag")) {
auto& tag = getComponent<TagComponent>(entity);
components.at("tag").getTo(tag);
}
if (cameraJson.exists("zoom-level") && cameraJson.at("zoom-level").type() == ruc::Json::Type::Number) {
cameraComponent.zoomLevel = cameraJson.at("zoom-level").asDouble();
if (components.exists("transform")) {
auto& transform = getComponent<TransformComponent>(entity);
components.at("transform").getTo(transform);
}
if (cameraJson.exists("script")) {
auto& cameraScript = cameraJson.at("script");
if (cameraScript.exists("type") && cameraScript.exists("name")) {
auto name = cameraScript.at("name").get<std::string>();
if (cameraScript.at("type").get<std::string>() == "lua") {
addComponent<LuaScriptComponent>(camera, name);
if (components.exists("camera")) {
auto& camera = addComponent<CameraComponent>(entity);
components.at("camera").getTo(camera);
}
else {
addComponent<NativeScriptComponent>(camera, name);
if (components.exists("lua-scripts")) {
VERIFY(components.at("lua-scripts").type() == ruc::Json::Type::Array);
const auto& scripts = components.at("lua-scripts").asArray();
for (size_t j = 0; j < scripts.size(); ++j) {
auto& script = addComponent<LuaScriptComponent>(entity);
scripts.at(j).getTo(script);
}
}
if (components.exists("native-scripts")) {
VERIFY(components.at("native-scripts").type() == ruc::Json::Type::Array);
const auto& scripts = components.at("native-scripts").asArray();
for (size_t j = 0; j < scripts.size(); ++j) {
auto& script = addComponent<NativeScriptComponent>(entity);
scripts.at(j).getTo(script);
script.bind();
}
// Quads
if (sceneJson.exists("quad") && sceneJson.at("quad").type() == ruc::Json::Type::Array) {
auto& quads = sceneJson.at("quad").asArray().elements();
for (const auto& quad : quads) {
uint32_t quadEntity = loadEntity(quad);
addComponent<SpriteComponent>(quadEntity);
auto& spriteComponent = getComponent<SpriteComponent>(quadEntity);
quad.getTo(spriteComponent);
}
if (components.exists("sprite")) {
auto& sprite = addComponent<SpriteComponent>(entity);
components.at("sprite").getTo(sprite);
}
if (components.exists("text")) {
auto& text = addComponent<TextAreaComponent>(entity);
components.at("text").getTo(text);
}
// Text
if (sceneJson.exists("text") && sceneJson.at("text").type() == ruc::Json::Type::Array) {
auto& texts = sceneJson.at("text").asArray().elements();
for (const auto& text : texts) {
uint32_t textEntity = loadEntity(text);
addComponent<TextAreaComponent>(textEntity);
auto& textAreaComponent = getComponent<TextAreaComponent>(textEntity);
text.getTo(textAreaComponent);
}
}
@ -125,20 +140,15 @@ void Scene::destroy()
uint32_t Scene::createEntity(const std::string& name)
{
uint32_t entity = static_cast<uint32_t>(m_registry->create());
addComponent<TagComponent>(entity, name.empty() ? "Unnamed Entity" : name);
addComponent<TransformComponent>(entity);
return entity;
return createEntityWithUID(UID(), name);
}
uint32_t Scene::loadEntity(ruc::Json json)
uint32_t Scene::createEntityWithUID(UID id, const std::string& name)
{
uint32_t entity = createEntity((json.exists("name"))
? json.at("name").get<std::string>()
: "");
auto& transform = getComponent<TransformComponent>(entity);
json.getTo(transform);
uint32_t entity = static_cast<uint32_t>(m_registry->create());
addComponent<IDComponent>(entity, id);
addComponent<TagComponent>(entity, name.empty() ? "Unnamed Entity" : name);
addComponent<TransformComponent>(entity);
return entity;
}

10
src/inferno/scene/scene.h

@ -6,6 +6,7 @@
#pragma once
#include <cstddef> // size_t
#include <cstdint> // uint32_t
#include <memory> // std::shared_ptr
@ -14,6 +15,8 @@
#include "ruc/format/format.h"
#include "ruc/json/json.h"
#include "inferno/uid.h"
namespace Inferno {
class Camera;
@ -27,7 +30,7 @@ public:
void destroy();
uint32_t createEntity(const std::string& name = "");
uint32_t loadEntity(ruc::Json json);
uint32_t createEntityWithUID(UID id, const std::string& name = "");
uint32_t findEntity(std::string_view name);
void destroyEntity(uint32_t entity);
@ -49,7 +52,8 @@ public:
return m_registry->any<T...>(entt::entity { entity });
}
// @Todo Should replace be allowed? could trigger memory leaks with nativescript
// TODO: Should replace be allowed? could trigger memory leaks with nativescript
// TODO: Replace will make it so an entity cant have multiple scripts
template<typename T, typename... P>
T& addComponent(uint32_t entity, P&&... parameters) const
{
@ -64,7 +68,7 @@ public:
return m_registry->remove_if_exists<T>(entt::entity { entity });
}
// @Todo Should replace be allowed? could trigger memory leaks with nativescript
// TODO: Should replace be allowed? could trigger memory leaks with nativescript
template<typename T, typename... P>
T& getComponent(uint32_t entity, P&&... parameters) const
{

4
src/inferno/script/nativescript.h

@ -55,8 +55,8 @@ public:
m_detroyBindings.emplace(binding, destroy);
}
NativeScript::InitializeFunction initializeBinding(const std::string& binding) { return m_initializeBindings[binding]; }
NativeScript::DestroyFunction destroyBinding(const std::string& binding) { return m_detroyBindings[binding]; }
NativeScript::InitializeFunction initializeBinding(const std::string& name) { return m_initializeBindings[name]; }
NativeScript::DestroyFunction destroyBinding(const std::string& name) { return m_detroyBindings[name]; }
private:
std::unordered_map<std::string, NativeScript::InitializeFunction> m_initializeBindings;

38
src/inferno/uid.cpp

@ -0,0 +1,38 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#include <cstdint>
#include <random>
#include "ruc/format/log.h"
#include "ruc/json/json.h"
#include "inferno/uid.h"
namespace Inferno {
static std::random_device s_seed;
static std::mt19937_64 s_engine(s_seed());
static std::uniform_int_distribution<uint64_t> s_distribution;
UID::UID()
: m_uid(s_distribution(s_engine))
{
}
UID::UID(uint64_t uid)
: m_uid(uid)
{
}
void fromJson(const ruc::Json& json, UID& value)
{
VERIFY(json.type() == ruc::Json::Type::Number);
value = UID((int64_t)json.asDouble());
}
} // namespace Inferno

47
src/inferno/uid.h

@ -0,0 +1,47 @@
/*
* Copyright (C) 2023 Riyyi
*
* SPDX-License-Identifier: MIT
*/
#pragma once
#include <cstdint> // uint64_t
#include "ruc/json/json.h"
namespace Inferno {
class UID {
public:
UID();
UID(uint64_t uid);
// Comparison operator for std::map
bool operator<(const UID& other) const
{
return m_uid < other.m_uid;
}
operator uint64_t() const { return m_uid; }
private:
uint64_t m_uid;
};
void fromJson(const ruc::Json& json, UID& value);
} // namespace Inferno
namespace std {
// Hash function for std::unordered_map
template<>
struct hash<Inferno::UID> {
size_t operator()(const Inferno::UID& uid) const
{
return hash<uint64_t>()(static_cast<uint64_t>(uid));
}
};
} // namespace std
Loading…
Cancel
Save