diff --git a/engine/samples/assets/bridge/main.cpp b/engine/samples/assets/bridge/main.cpp index dba996a0a0..645020b677 100644 --- a/engine/samples/assets/bridge/main.cpp +++ b/engine/samples/assets/bridge/main.cpp @@ -47,42 +47,33 @@ class TextBridge : public FileBridge }; /// [TextBridge::saveToFile] -static void configSystem(Settings& settings) +int main() { - settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); -} + auto cubos = Cubos(); -/// [Registering the bridge] -static void bridgeSystem(Assets& assets) -{ - // Add a custom bridge to load .txt files. - assets.registerBridge(".txt", std::make_unique()); -} -/// [Registering the bridge] + cubos.addPlugin(assetsPlugin); -/// [Loading the asset] -// Assets are identified through UUIDs which are defined in their .meta files. -static const Asset SampleAsset = AnyAsset("6f42ae5a-59d1-5df3-8720-83b8df6dd536"); + cubos.startupSystem("configure Assets plugin").tagged("cubos.settings").call([](Settings& settings) { + settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); + }); -static void loadSystem(const Assets& assets) -{ - // Access the text asset - will be loaded automatically. - auto text = assets.read(SampleAsset); - Stream::stdOut.print(*text); -} -/// [Loading the asset] + /// [Registering the bridge] + cubos.startupSystem("setup bridge to load .txt files").tagged("cubos.assets.bridge").call([](Assets& assets) { + assets.registerBridge(".txt", std::make_unique()); + }); + /// [Registering the bridge] -int main() -{ - auto cubos = Cubos(); + /// [Loading the asset] + // Assets are identified through UUIDs which are defined in their .meta files. + static const Asset SampleAsset = AnyAsset("6f42ae5a-59d1-5df3-8720-83b8df6dd536"); - /// [Configuration] - cubos.addPlugin(assetsPlugin); - cubos.startupSystem(bridgeSystem).tagged("cubos.assets.bridge"); - cubos.startupSystem(loadSystem).tagged("cubos.assets"); - /// [Configuration] + cubos.startupSystem("access .txt asset").tagged("cubos.assets").call([](const Assets& assets) { + // Access the text asset - will be loaded automatically. + auto text = assets.read(SampleAsset); + Stream::stdOut.print(*text); + }); + /// [Loading the asset] - cubos.startupSystem(configSystem).tagged("cubos.settings"); cubos.run(); return 0; } diff --git a/engine/samples/assets/bridge/page.md b/engine/samples/assets/bridge/page.md index 17cd5e141a..2c45395354 100644 --- a/engine/samples/assets/bridge/page.md +++ b/engine/samples/assets/bridge/page.md @@ -57,5 +57,3 @@ startup phase. Systems which add bridges should be tagged with `cubos.assets.bridge` so that they run before any assets are loaded. Similarly, startup systems which load assets should be tagged with `cubos.assets` so that they run after all bridges have been registered. - -@snippet assets/bridge/main.cpp Configuration diff --git a/engine/samples/assets/json/main.cpp b/engine/samples/assets/json/main.cpp index c7e1af6d93..cb998efdea 100644 --- a/engine/samples/assets/json/main.cpp +++ b/engine/samples/assets/json/main.cpp @@ -12,8 +12,6 @@ #include using cubos::core::data::FileSystem; -using cubos::core::data::old::Deserializer; -using cubos::core::data::old::Serializer; using cubos::core::memory::Stream; using cubos::core::reflection::FieldsTrait; using cubos::core::reflection::Type; @@ -34,59 +32,33 @@ CUBOS_REFLECT_IMPL(Strings) } /// [Asset type] -/// [Serialization definition] -template <> -void cubos::core::data::old::serialize(Serializer& ser, const Strings& obj, const char* name) -{ - ser.beginObject(name); - ser.write(obj.strings, "strings"); - ser.endObject(); -} - -template <> -void cubos::core::data::old::deserialize(Deserializer& des, Strings& obj) -{ - des.beginObject(); - des.read(obj.strings); - des.endObject(); -} -/// [Serialization definition] - -static void configSystem(Settings& settings) +int main() { - settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); -} + Cubos cubos{}; -/// [Register bridge] -static void bridgeSystem(Assets& assets) -{ - assets.registerBridge(".strings", std::make_unique>()); -} -/// [Register bridge] + cubos.addPlugin(assetsPlugin); -/// [Loading the asset] -static const Asset SampleAsset = AnyAsset("6f42ae5a-59d1-5df3-8720-83b8df6dd536"); + cubos.startupSystem("configure Assets plugin").tagged("cubos.settings").call([](Settings& settings) { + settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); + }); -static void loadSystem(Assets& assets) -{ - auto read = assets.read(SampleAsset); - for (const auto& str : read->strings) - { - Stream::stdOut.printf("String: {}\n", str); - } -} -/// [Loading the asset] + /// [Register bridge] + cubos.startupSystem("setup bridge to load .strings files").tagged("cubos.assets.bridge").call([](Assets& assets) { + assets.registerBridge(".strings", std::make_unique>()); + }); + /// [Register bridge] -int main() -{ - Cubos cubos{}; + /// [Loading the asset] + static const Asset SampleAsset = AnyAsset("6f42ae5a-59d1-5df3-8720-83b8df6dd536"); - /// [Configuration] - cubos.addPlugin(assetsPlugin); - cubos.startupSystem(bridgeSystem).tagged("cubos.assets.bridge"); - cubos.startupSystem(loadSystem).tagged("cubos.assets"); - /// [Configuration] + cubos.startupSystem("access .strings asset").tagged("cubos.assets").call([](Assets& assets) { + auto read = assets.read(SampleAsset); + for (const auto& str : read->strings) + { + Stream::stdOut.printf("String: {}\n", str); + } + }); + /// [Loading the asset] - cubos.startupSystem(configSystem).tagged("cubos.settings"); cubos.run(); } diff --git a/engine/samples/assets/json/page.md b/engine/samples/assets/json/page.md index dfa5965108..b3e7f36c77 100644 --- a/engine/samples/assets/json/page.md +++ b/engine/samples/assets/json/page.md @@ -1,6 +1,6 @@ -# Loading Serializable Assets {#examples-engine-assets-json} +# Loading Reflectable Assets {#examples-engine-assets-json} -@brief Loading serializable assets from JSON. +@brief Loading reflectable assets from JSON. @see Full source code [here](https://github.com/GameDevTecnico/cubos/tree/main/engine/samples/assets/json). @@ -8,13 +8,9 @@ We'll use the following type as an example: @snippet assets/json/main.cpp Asset type -We can make it serializable by implementing the following specializations: - -@snippet assets/json/main.cpp Serialization definition - Then, we must register a bridge for this type. We provide @ref cubos::engine::JSONBridge "JSONBridge" for easily loading and saving -serializable assets as JSON. +reflectable assets as JSON. @snippet assets/json/main.cpp Register bridge @@ -24,5 +20,3 @@ With the bridge registered, we can just load it from its handle: These sytems are configured the usual way, as explained in @ref examples-engine-assets-bridge. - -@snippet assets/json/main.cpp Configuration diff --git a/engine/samples/assets/saving/main.cpp b/engine/samples/assets/saving/main.cpp index 54510aff3a..19b9f0e1a0 100644 --- a/engine/samples/assets/saving/main.cpp +++ b/engine/samples/assets/saving/main.cpp @@ -9,8 +9,6 @@ #include using cubos::core::data::FileSystem; -using cubos::core::data::old::Deserializer; -using cubos::core::data::old::Serializer; using cubos::core::memory::Stream; using cubos::core::reflection::FieldsTrait; using cubos::core::reflection::Type; @@ -30,67 +28,43 @@ CUBOS_REFLECT_IMPL(IntegerAsset) } /// [Asset type] -template <> -void cubos::core::data::old::serialize(Serializer& ser, const IntegerAsset& obj, const char* name) +int main() { - ser.beginObject(name); - ser.write(obj.value, "value"); - ser.endObject(); -} + Cubos cubos{}; -template <> -void cubos::core::data::old::deserialize(Deserializer& des, IntegerAsset& obj) -{ - des.beginObject(); - des.read(obj.value); - des.endObject(); -} + cubos.addPlugin(assetsPlugin); -/// [Setting] -static void configSystem(Settings& settings) -{ - // If we want to save assets, we must set this to false. - settings.setBool("assets.io.readOnly", false); /// [Setting] + cubos.startupSystem("configure Assets plugin").tagged("cubos.settings").call([](Settings& settings) { + // If we want to save assets, we must set this to false. + settings.setBool("assets.io.readOnly", false); + /// [Setting] - settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); -} + settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); + }); -static void bridgeSystem(Assets& assets) -{ - assets.registerBridge(".int", std::make_unique>()); -} + cubos.startupSystem("setup bridge to load and save .int assets") + .tagged("cubos.assets.bridge") + .call([](Assets& assets) { assets.registerBridge(".int", std::make_unique>()); }); -/// [Create a new asset] -static void saveSystem(Assets& assets) -{ - // Create a new asset (with a random UUID). - auto handle = assets.create(IntegerAsset{1337}); /// [Create a new asset] + cubos.startupSystem("create and save asset").tagged("cubos.assets").call([](Assets& assets) { + // Create a new asset (with a random UUID). + auto handle = assets.create(IntegerAsset{1337}); + /// [Create a new asset] - /// [Save the asset] - assets.writeMeta(handle)->set("path", "/assets/sample/sample.int"); - assets.save(handle); - /// [Save the asset] + /// [Save the asset] + assets.writeMeta(handle)->set("path", "/assets/sample/sample.int"); + assets.save(handle); + /// [Save the asset] - // Wait for input before exiting. - Stream::stdOut.print("You can now check the contents of the file!\nPress enter to exit..."); - Stream::stdIn.get(); + // Wait for input before exiting. + Stream::stdOut.print("You can now check the contents of the file!\nPress enter to exit..."); + Stream::stdIn.get(); - // Cleanup the created asset. - FileSystem::destroy("/assets/sample"); -} - -int main() -{ - Cubos cubos{}; - - /// [Configure] - cubos.addPlugin(assetsPlugin); - cubos.startupSystem(saveSystem).tagged("cubos.assets"); - /// [Configure] + // Cleanup the created asset. + FileSystem::destroy("/assets/sample"); + }); - cubos.startupSystem(configSystem).tagged("cubos.settings"); - cubos.startupSystem(bridgeSystem).tagged("cubos.assets.bridge"); cubos.run(); } diff --git a/engine/samples/assets/saving/page.md b/engine/samples/assets/saving/page.md index 9319a96fb8..91f4516b6a 100644 --- a/engine/samples/assets/saving/page.md +++ b/engine/samples/assets/saving/page.md @@ -4,9 +4,9 @@ @see Full source code [here](https://github.com/GameDevTecnico/cubos/tree/main/engine/samples/assets/saving). -This example demonstrates how a new asset be created programatically and how it +This example demonstrates how a new asset can be created programatically and how it can be saved to the assets directory, which is useful while working on tools -such as **TESSERATOS.** +such as **TESSERATOS** Before we go any further, if we want to save assets to the filesystem, we must allow assets to be modified. This is done through the following setting: @@ -23,7 +23,7 @@ First, we'll create an asset of this type: @snippet assets/saving/main.cpp Create a new asset -Then, we'll assign it a path and save it. Its important that the path ends with +Then, we'll assign it a path and save it. It's important that the path ends with the correct extension, so that @ref cubos::engine::Assets "Assets" knows which bridge to use when loading it. @@ -33,8 +33,4 @@ With this, the files `sample/sample.int` and `sample/sample.int.meta` should have appeared on the `assets/` directory. The `.meta` file contains the UUID of the asset, which is used by the engine to identify it. -Finally, the engine is configured the following way: - -@snippet assets/saving/main.cpp Configure - Try running the sample yourself to see the files being created! diff --git a/engine/samples/collisions/main.cpp b/engine/samples/collisions/main.cpp index 216886a2c0..f8a304dddc 100644 --- a/engine/samples/collisions/main.cpp +++ b/engine/samples/collisions/main.cpp @@ -31,102 +31,6 @@ struct State glm::vec3 bRotationAxis; }; -static void settings(Settings& settings) -{ - settings.setBool("assets.io.enabled", false); -} - -static void init(Commands commands, Input& input, ActiveCameras& camera) -{ - // Add procedural asset for detecting a reset action on a space key press. - auto bindings = InputBindings{}; - bindings.actions()["reset"].keys().emplace_back(Key::Space, Modifiers::None); - input.bind(bindings); - - // Spawn the camera. - camera.entities[0] = - commands.create() - .add(Camera{.fovY = 60.0, .zNear = 0.1F, .zFar = 100.0F}) - .add(LocalToWorld{}) - .add(Position{{-4.0, 1.5, 0}}) - .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{3.0, -1.0, 0.0}), glm::vec3{0.0, 1.0, 0.0})}) - .entity(); -} - -static void addColliders(State& state, Commands commands) -{ - state.a = commands.create() - .add(Collider{}) - .add(CapsuleCollisionShape{{0.5F, 1.0F}}) - .add(LocalToWorld{}) - .add(Position{glm::vec3{0.0F, 0.0F, -2.0F}}) - .add(Rotation{}) - .entity(); - state.aRotationAxis = glm::sphericalRand(1.0F); - - state.b = commands.create() - .add(Collider{}) - .add(BoxCollisionShape{}) - .add(LocalToWorld{}) - .add(Position{glm::vec3{0.0F, 0.0F, 2.0F}}) - .add(Rotation{}) - .entity(); - state.bRotationAxis = glm::sphericalRand(1.0F); -} - -static void updateTransform(State& state, const Input& input, Query query) -{ - auto [aPos, aRot] = *query.at(state.a); - auto [bPos, bRot] = *query.at(state.b); - - if (state.collided) - { - if (input.pressed("reset")) - { - state.collided = false; - - aPos.vec = glm::vec3{0.0F, 0.0F, -2.0F}; - aRot.quat = glm::quat{1.0F, 0.0F, 0.0F, 0.0F}; - state.aRotationAxis = glm::sphericalRand(1.0F); - - bPos.vec = glm::vec3{0.0F, 0.0F, 2.0F}; - bRot.quat = glm::quat{1.0F, 0.0F, 0.0F, 0.0F}; - state.bRotationAxis = glm::sphericalRand(1.0F); - } - return; - } - - aRot.quat = glm::rotate(aRot.quat, 0.01F, state.aRotationAxis); - aPos.vec += glm::vec3{0.0F, 0.0F, 0.01F}; - - bRot.quat = glm::rotate(bRot.quat, 0.01F, state.bRotationAxis); - bPos.vec += glm::vec3{0.0F, 0.0F, -0.01F}; -} - -static void updateCollided(Query query, State& state) -{ - for (auto [ent1, colliding, ent2] : query) - { - if ((ent1 == state.a && ent2 == state.b) || (ent1 == state.b && ent2 == state.a)) - { - state.collided = true; - } - } -} - -static void render(Query query) -{ - for (auto [localToWorld, collider] : query) - { - cubos::core::gl::Debug::drawWireBox( - collider.localAABB.box(), - glm::translate(localToWorld.mat * collider.transform, collider.localAABB.center())); - cubos::core::gl::Debug::drawWireBox(collider.worldAABB.box(), - glm::translate(glm::mat4{1.0}, collider.worldAABB.center()), - glm::vec3{1.0, 0.0, 0.0}); - } -} - int main() { auto cubos = Cubos(); @@ -137,14 +41,102 @@ int main() cubos.addResource(); - cubos.startupSystem(settings).tagged("cubos.settings"); - cubos.startupSystem(init); - - cubos.startupSystem(addColliders); - - cubos.system(updateTransform).before("cubos.transform.update"); - cubos.system(updateCollided).tagged("updated").after("cubos.collisions.broad"); - cubos.system(render).after("updated"); + cubos.startupSystem("activate assets IO").tagged("cubos.settings").call([](Settings& settings) { + settings.setBool("assets.io.enabled", false); + }); + + cubos.startupSystem("setup input").call([](Input& input) { + // Add procedural asset for detecting a reset action on a space key press. + auto bindings = InputBindings{}; + bindings.actions()["reset"].keys().emplace_back(Key::Space, Modifiers::None); + input.bind(bindings); + }); + + cubos.startupSystem("setup camera").call([](Commands commands, ActiveCameras& cameras) { + // Spawn the camera. + cameras.entities[0] = + commands.create() + .add(Camera{.fovY = 60.0, .zNear = 0.1F, .zFar = 100.0F}) + .add(LocalToWorld{}) + .add(Position{{-4.0, 1.5, 0}}) + .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{3.0, -1.0, 0.0}), glm::vec3{0.0, 1.0, 0.0})}) + .entity(); + }); + + cubos.startupSystem("create colliders").call([](State& state, Commands commands) { + state.a = commands.create() + .add(Collider{}) + .add(CapsuleCollisionShape{{0.5F, 1.0F}}) + .add(LocalToWorld{}) + .add(Position{glm::vec3{0.0F, 0.0F, -2.0F}}) + .add(Rotation{}) + .entity(); + state.aRotationAxis = glm::sphericalRand(1.0F); + + state.b = commands.create() + .add(Collider{}) + .add(BoxCollisionShape{}) + .add(LocalToWorld{}) + .add(Position{glm::vec3{0.0F, 0.0F, 2.0F}}) + .add(Rotation{}) + .entity(); + state.bRotationAxis = glm::sphericalRand(1.0F); + }); + + cubos.system("move colliders") + .before("cubos.transform.update") + .call([](State& state, const Input& input, Query query) { + auto [aPos, aRot] = *query.at(state.a); + auto [bPos, bRot] = *query.at(state.b); + + if (state.collided) + { + if (input.pressed("reset")) + { + state.collided = false; + + aPos.vec = glm::vec3{0.0F, 0.0F, -2.0F}; + aRot.quat = glm::quat{1.0F, 0.0F, 0.0F, 0.0F}; + state.aRotationAxis = glm::sphericalRand(1.0F); + + bPos.vec = glm::vec3{0.0F, 0.0F, 2.0F}; + bRot.quat = glm::quat{1.0F, 0.0F, 0.0F, 0.0F}; + state.bRotationAxis = glm::sphericalRand(1.0F); + } + return; + } + + aRot.quat = glm::rotate(aRot.quat, 0.01F, state.aRotationAxis); + aPos.vec += glm::vec3{0.0F, 0.0F, 0.01F}; + + bRot.quat = glm::rotate(bRot.quat, 0.01F, state.bRotationAxis); + bPos.vec += glm::vec3{0.0F, 0.0F, -0.01F}; + }); + + cubos.system("check collisions") + .tagged("updated") + .after("cubos.collisions.broad") + .call([](Query query, State& state) { + for (auto [ent1, colliding, ent2] : query) + { + if ((ent1 == state.a && ent2 == state.b) || (ent1 == state.b && ent2 == state.a)) + { + state.collided = true; + } + } + }); + + cubos.system("render").after("updated").call([](Query query) { + for (auto [localToWorld, collider] : query) + { + cubos::core::gl::Debug::drawWireBox( + collider.localAABB.box(), + glm::translate(localToWorld.mat * collider.transform, collider.localAABB.center())); + cubos::core::gl::Debug::drawWireBox(collider.worldAABB.box(), + glm::translate(glm::mat4{1.0}, collider.worldAABB.center()), + glm::vec3{1.0, 0.0, 0.0}); + } + }); cubos.run(); return 0; diff --git a/engine/samples/events/main.cpp b/engine/samples/events/main.cpp index 049231d8cd..07b2774a1b 100644 --- a/engine/samples/events/main.cpp +++ b/engine/samples/events/main.cpp @@ -18,54 +18,6 @@ struct State int step; }; -/// [Event reader system] -static void firstSystem(EventReader reader) -{ - for (const auto& event : reader) - { - CUBOS_INFO("A read {}", event.value); - } -} -/// [Event reader system] - -/// [Event writer system] -static void secondSystem(EventWriter writer, State& state, ShouldQuit& quit) -{ - state.step += 1; - if (state.step == 1) // Write 1 2 3 on first run. - { - writer.push({1}); - writer.push({2}); - writer.push({3}); - CUBOS_INFO("B wrote 1 2 3"); - } - else if (state.step == 2) - { - quit.value = true; // Stop the loop. - writer.push({4}); - writer.push({5}); - writer.push({6}); - CUBOS_INFO("B wrote 4 5 6"); - } -} -/// [Event writer system] - -static void thirdSystem(EventReader reader) -{ - for (const auto& event : reader) - { - CUBOS_INFO("C read {}", event.value); - } -} - -static void fourthSystem(EventReader reader) -{ - for (const auto& event : reader) - { - CUBOS_INFO("D read {}", event.value); - } -} - int main() { cubos::engine::Cubos cubos; @@ -75,14 +27,51 @@ int main() cubos.addEvent(); /// [Adding event] - cubos.startupSystem([](ShouldQuit& quit) { quit.value = false; }); + cubos.startupSystem("set ShouldQuit to false").call([](ShouldQuit& quit) { quit.value = false; }); + + /// [Event reader systems] + cubos.system("A").before("b").call([](EventReader reader) { + for (const auto& event : reader) + { + CUBOS_INFO("A read {}", event.value); + } + }); + + cubos.system("C").tagged("c").after("b").call([](EventReader reader) { + for (const auto& event : reader) + { + CUBOS_INFO("C read {}", event.value); + } + }); + + cubos.system("D").after("c").call([](EventReader reader) { + for (const auto& event : reader) + { + CUBOS_INFO("D read {}", event.value); + } + }); + /// [Event reader system] - /// [Adding systems] - cubos.system(firstSystem).tagged("A").before("B"); - cubos.system(secondSystem).tagged("B"); - cubos.system(thirdSystem).tagged("C").after("B"); - cubos.system(fourthSystem).tagged("D").after("C"); - /// [Adding systems] + /// [Event writer system] + cubos.system("B").tagged("b").call([](EventWriter writer, State& state, ShouldQuit& quit) { + state.step += 1; + if (state.step == 1) // Write 1 2 3 on first run. + { + writer.push({1}); + writer.push({2}); + writer.push({3}); + CUBOS_INFO("B wrote 1 2 3"); + } + else if (state.step == 2) + { + quit.value = true; // Stop the loop. + writer.push({4}); + writer.push({5}); + writer.push({6}); + CUBOS_INFO("B wrote 4 5 6"); + } + }); + /// [Event writer system] /// [Expected results] // Should print: diff --git a/engine/samples/events/page.md b/engine/samples/events/page.md index a4de94b11c..8ed534d210 100644 --- a/engine/samples/events/page.md +++ b/engine/samples/events/page.md @@ -13,16 +13,12 @@ Firstly, we need to create and register the event we want to emit. Here, our eve To receive these events, we can make a simple system which takes the @ref cubos::core::ecs::EventReader "EventReader" system argument and iterates through all the events it has. This will be the layout of all our reader systems (A, C, D). -@snippet events/main.cpp Event reader system +@snippet events/main.cpp Event reader systems Now, to emit these events, we will use the @ref cubos::core::ecs::EventWriter "EventWriter" system argument. This system will emit 3 events on the first frame and another 3 on the second frame. By setting the value of the @ref cubos::engine::ShouldQuit "ShouldQuit" resource to true on the second frame, the engine stops before reaching the third frame. @snippet events/main.cpp Event writer system -Lastly, let's set the order we want these system to execute in. - -@snippet events/main.cpp Adding systems - These are the expected results with this order. @snippet events/main.cpp Expected results diff --git a/engine/samples/gizmos/main.cpp b/engine/samples/gizmos/main.cpp index 2267b094bf..b862130e71 100644 --- a/engine/samples/gizmos/main.cpp +++ b/engine/samples/gizmos/main.cpp @@ -6,88 +6,6 @@ using namespace cubos::engine; -static void settingsSystem(Settings& settings) -{ - // We don't load assets in this sample and we don't even have an assets folder, so we should - // disable assets IO. - settings.setBool("assets.io.enabled", false); -} - -static void setCameraSystem(ActiveCameras& camera, Commands cmds) -{ - camera.entities[0] = cmds.create() - .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) - .add(LocalToWorld{}) - .add(Position{{5.0F, 5.0F, 0.0F}}) - .add(Rotation{glm::quatLookAt(glm::vec3{-1.0F, -1.0F, 0.0F}, glm::vec3{0.0F, 1.0F, 0.0F})}) - .entity(); - camera.entities[1] = cmds.create() - .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) - .add(LocalToWorld{}) - .add(Position{{-25.0F, 25.0F, 0.0F}}) - .add(Rotation{glm::quatLookAt(glm::vec3{1.0F, -1.0F, 0.0F}, glm::vec3{0.0F, 1.0F, 0.0F})}) - .entity(); - camera.entities[2] = cmds.create() - .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) - .add(LocalToWorld{}) - .add(Position{{-25.0F, -25.0F, 0.0F}}) - .add(Rotation{glm::quatLookAt(glm::vec3{1.0F, 1.0F, 0.0F}, glm::vec3{0.0F, 1.0F, 0.0F})}) - .entity(); - camera.entities[3] = cmds.create() - .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) - .add(LocalToWorld{}) - .add(Position{{25.0F, -25.0F, 0.0F}}) - .add(Rotation{glm::quatLookAt(glm::vec3{-1.0F, 1.0F, 0.0F}, glm::vec3{0.0F, 1.0F, 0.0F})}) - .entity(); -} - -/// [System] -static void drawSystem(Gizmos& gizmos) -{ - /// [Lines] - gizmos.color({1.0F, 1.0F, 1.0F}); - gizmos.drawLine("separator line", {1.0F, 0.5F, 0.5F}, {0.0F, 0.5F, 0.5F}, 0, Gizmos::Space::Screen); - gizmos.drawLine("separator line", {0.5F, 1.0F, 0.5F}, {0.5F, 0.0F, 0.5F}, 0, Gizmos::Space::Screen); - /// [Lines] - - /// [WireBox] - gizmos.color({1.0F, 0.5F, 1.0F}); - gizmos.drawBox("box", {0.4, 0.4, 0}, {0.55, 0.55, 0}, 0, Gizmos::Space::View); - /// [WireBox] - - /// [Box] - gizmos.color({0.2F, 0.2F, 1.0F}); - gizmos.drawWireBox("wire box", {-5, -5, -5}, {-7, -7, -7}, 0, Gizmos::Space::World); - /// [Box] - - ///[Cut Cone] - if (gizmos.hovered("cut cone")) - { - gizmos.color({0.25F, 0.15F, 0.5F}); - } - else if (gizmos.pressed("cut cone")) - { - gizmos.color({0.5F, 0.3F, 1}); - } - else - { - gizmos.color({0.1F, 0.05F, 0.25F}); - } - - gizmos.drawCutCone("cut cone", {0.7F, 0.7F, 0.7F}, 5.0F, {-3, -3, -3}, 3.0F, 0, Gizmos::Space::World); - ///[Cut Cone] -} -/// [System] - -/// [Start Up System] -static void drawStartingLineSystem(Gizmos& gizmos) -{ - gizmos.color({1, 0, 1}); - gizmos.drawArrow("arrow", {0.6F, 0.6F, 0.0F}, {-0.1F, -0.1F, 0.0F}, 0.003F, 0.009F, 0.7F, 10.0F, - Gizmos::Space::Screen); -} -/// [Start Up System] - int main(int argc, char** argv) { /// [Adding plugin] @@ -96,11 +14,90 @@ int main(int argc, char** argv) /// [Adding plugin] cubos.addPlugin(rendererPlugin); - cubos.startupSystem(settingsSystem).tagged("cubos.settings"); - cubos.startupSystem(setCameraSystem); - cubos.startupSystem(drawStartingLineSystem).tagged("sample.init").after("cubos.gizmos.init"); + cubos.startupSystem("disable Assets IO").tagged("cubos.settings").call([](Settings& settings) { + // We don't load assets in this sample and we don't even have an assets folder, so we should + // disable assets IO. + settings.setBool("assets.io.enabled", false); + }); + + cubos.startupSystem("setup camera").call([](ActiveCameras& camera, Commands cmds) { + camera.entities[0] = + cmds.create() + .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) + .add(LocalToWorld{}) + .add(Position{{5.0F, 5.0F, 0.0F}}) + .add(Rotation{glm::quatLookAt(glm::vec3{-1.0F, -1.0F, 0.0F}, glm::vec3{0.0F, 1.0F, 0.0F})}) + .entity(); + camera.entities[1] = + cmds.create() + .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) + .add(LocalToWorld{}) + .add(Position{{-25.0F, 25.0F, 0.0F}}) + .add(Rotation{glm::quatLookAt(glm::vec3{1.0F, -1.0F, 0.0F}, glm::vec3{0.0F, 1.0F, 0.0F})}) + .entity(); + camera.entities[2] = + cmds.create() + .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) + .add(LocalToWorld{}) + .add(Position{{-25.0F, -25.0F, 0.0F}}) + .add(Rotation{glm::quatLookAt(glm::vec3{1.0F, 1.0F, 0.0F}, glm::vec3{0.0F, 1.0F, 0.0F})}) + .entity(); + camera.entities[3] = + cmds.create() + .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) + .add(LocalToWorld{}) + .add(Position{{25.0F, -25.0F, 0.0F}}) + .add(Rotation{glm::quatLookAt(glm::vec3{-1.0F, 1.0F, 0.0F}, glm::vec3{0.0F, 1.0F, 0.0F})}) + .entity(); + }); + + /// [Start Up System] + cubos.startupSystem("draw line at startup") + .tagged("sample.init") + .after("cubos.gizmos.init") + .call([](Gizmos& gizmos) { + gizmos.color({1, 0, 1}); + gizmos.drawArrow("arrow", {0.6F, 0.6F, 0.0F}, {-0.1F, -0.1F, 0.0F}, 0.003F, 0.009F, 0.7F, 10.0F, + Gizmos::Space::Screen); + }); + /// [Start Up System] + + /// [System] + cubos.system("draw gizmos").call([](Gizmos& gizmos) { + /// [Lines] + gizmos.color({1.0F, 1.0F, 1.0F}); + gizmos.drawLine("separator line", {1.0F, 0.5F, 0.5F}, {0.0F, 0.5F, 0.5F}, 0, Gizmos::Space::Screen); + gizmos.drawLine("separator line", {0.5F, 1.0F, 0.5F}, {0.5F, 0.0F, 0.5F}, 0, Gizmos::Space::Screen); + /// [Lines] + + /// [WireBox] + gizmos.color({1.0F, 0.5F, 1.0F}); + gizmos.drawBox("box", {0.4, 0.4, 0}, {0.55, 0.55, 0}, 0, Gizmos::Space::View); + /// [WireBox] + + /// [Box] + gizmos.color({0.2F, 0.2F, 1.0F}); + gizmos.drawWireBox("wire box", {-5, -5, -5}, {-7, -7, -7}, 0, Gizmos::Space::World); + /// [Box] + + ///[Cut Cone] + if (gizmos.hovered("cut cone")) + { + gizmos.color({0.25F, 0.15F, 0.5F}); + } + else if (gizmos.pressed("cut cone")) + { + gizmos.color({0.5F, 0.3F, 1}); + } + else + { + gizmos.color({0.1F, 0.05F, 0.25F}); + } - cubos.system(drawSystem); + gizmos.drawCutCone("cut cone", {0.7F, 0.7F, 0.7F}, 5.0F, {-3, -3, -3}, 3.0F, 0, Gizmos::Space::World); + ///[Cut Cone] + }); + /// [System] cubos.run(); } diff --git a/engine/samples/hello-cubos/components.hpp b/engine/samples/hello-cubos/components.hpp deleted file mode 100644 index 11c782f651..0000000000 --- a/engine/samples/hello-cubos/components.hpp +++ /dev/null @@ -1,11 +0,0 @@ -#pragma once - -#include -#include - -struct Num -{ - CUBOS_REFLECT; - - int value; -}; diff --git a/engine/samples/hello-cubos/main.cpp b/engine/samples/hello-cubos/main.cpp index 70d033af32..199cb856fc 100644 --- a/engine/samples/hello-cubos/main.cpp +++ b/engine/samples/hello-cubos/main.cpp @@ -1,24 +1,25 @@ -/// [Include Components] -#include "components.hpp" -/// [Include Components] - /// [Include] #include -using cubos::engine::Cubos; -/// [Include] - using namespace cubos::engine; +/// [Include] -/// [Component Refl] +/// [Component Decl] #include #include +struct Num +{ + CUBOS_REFLECT; + + int value; +}; + CUBOS_REFLECT_IMPL(Num) { return cubos::core::ecs::TypeBuilder("Num").withField("value", &Num::value).build(); } -/// [Component Refl] +/// [Component Decl] /// [Resource Decl] struct Pop @@ -27,65 +28,25 @@ struct Pop }; /// [Resource Decl] -/// [Hello Cubos] -static void sayHelloCubosSystem() -{ - CUBOS_INFO("Hello CUBOS"); -} -/// [Hello Cubos] - -/// [Hello World] -static void sayHelloSystem() -{ - CUBOS_INFO("Hello"); -} - -static void sayWorldSystem() -{ - CUBOS_INFO("World"); -} -/// [Hello World] - -/// [Entity Spawn] -static void spawnEntitiesSystem(Commands cmds, Pop& pop) -{ - for (int i = 0; i < 10; i++) - { - cmds.create().add(Num{i}); - pop.count += 1; - } -} -/// [Entity Spawn] - -/// [Entity Print] -static void checkEntitiesSystem(Query query, const Pop& pop) -{ - for (auto [num] : query) - { - CUBOS_INFO("Entity '{}' of '{}'", num.value, pop.count); - } -} -/// [Entity Print] - /// [Engine] int main() { Cubos cubos{}; /// [Engine] + /// [Hello CUBOS] + cubos.startupSystem("say Hello CUBOS").call([]() { CUBOS_INFO("Hello CUBOS"); }); + /// [Hello CUBOS] + + /// [Hello World] + cubos.system("say Hello").tagged("helloTag").call([]() { CUBOS_INFO("Hello"); }); + cubos.system("say World").tagged("worldTag").call([]() { CUBOS_INFO("World"); }); + /// [Hello World] + /// [Tags] cubos.tag("helloTag").before("worldTag"); /// [Tags] - /// [Set Startup] - cubos.startupSystem(sayHelloCubosSystem); - /// [Set Startup] - - /// [Set Systems] - cubos.system(sayHelloSystem).tagged("helloTag"); - cubos.system(sayWorldSystem).tagged("worldTag"); - /// [Set Systems] - /// [Component Add] cubos.addComponent(); /// [Component Add] @@ -94,11 +55,24 @@ int main() cubos.addResource(); /// [Resource Add] - /// [Entity System] - cubos.startupSystem(spawnEntitiesSystem); - - cubos.system(checkEntitiesSystem); - /// [Entity System] + /// [Entity Spawn] + cubos.startupSystem("spawn entities").call([](Commands cmds, Pop& pop) { + for (int i = 0; i < 10; i++) + { + cmds.create().add(Num{i}); + pop.count += 1; + } + }); + /// [Entity Spawn] + + /// [Entity Print] + cubos.system("check entities").call([](Query query, const Pop& pop) { + for (auto [num] : query) + { + CUBOS_INFO("Entity '{}' of '{}'", num.value, pop.count); + } + }); + /// [Entity Print] /// [Run] cubos.run(); diff --git a/engine/samples/hello-cubos/page.md b/engine/samples/hello-cubos/page.md index c0fdf17a8e..e3957da5e3 100644 --- a/engine/samples/hello-cubos/page.md +++ b/engine/samples/hello-cubos/page.md @@ -4,7 +4,6 @@ @see Full source code [here](https://github.com/GameDevTecnico/cubos/tree/main/engine/samples/hello-cubos). - This example shows the basics of how @ref cubos::engine::Cubos is used, by making a simple "Hello World" program. @snippet hello-cubos/main.cpp Include @@ -16,18 +15,14 @@ First we'll need to get a `Cubos` object. The @ref cubos::engine::Cubos "Cubos" class represents the engine. We'll need it to add functionality to our program. -Let's start by defining what functionality we want to add. +Let's start by defining what functionality we want to add, by adding our first system. -@snippet hello-cubos/main.cpp Hello Cubos +@snippet hello-cubos/main.cpp Hello CUBOS -This function simply prints `Hello CUBOS` to the console. -It uses one of CUBOS.'s logging macros. +This startup system simply prints `Hello CUBOS` to the console, using one of CUBOS's logging macros. You can find more about them @ref core/include/cubos/core/log.hpp "here". -However, this function is not currently called, so we'll need to tell CUBOS. that we want it to run. - -@snippet hello-cubos/main.cpp Set Startup - Startup systems run only once when the engine is loaded. + Now let's make things more interesting. Let's print `Hello World`, but split it over two different systems. @@ -38,42 +33,32 @@ This means the systems will be called after the startup systems and repeat every @note As we don't have anything that would require multiple cycles (such as a window to draw to), the CUBOS. main cycle will run only once. -However, we can't just do as we did for `sayHelloCubos` and call it a day. -We want `sayHello` to come before `sayWorld`, so we'll have to explicitly tell that to the engine, or else we risk having them in the wrong order. +Notice that we can't just do as we did for `Hello CUBOS` and call it a day. +We want `Hello` to come before `World`, so we'll have to explicitly tell that to the engine, or else we risk having them in the wrong order. To do that we use tags. -Let's create two tags, one for each system. @snippet hello-cubos/main.cpp Tags -@ref cubos::engine::Cubos::tag "Cubos::tag" creates a new tag, and @ref cubos::engine::TagBuilder::before "before" makes any systems tagged with it come before systems tagged with the one given as parameter. +@ref cubos::engine::Cubos::tag "Cubos::tag" can be used to apply properties to all systems with a given tag, and @ref cubos::engine::TagBuilder::before "before" makes any systems tagged with it come before systems tagged with the one given as parameter. There's also an @ref cubos::engine::TagBuilder::after "after" that has the inverse effect. -Now all we have to do is to assign these tags to our systems. -@note If we wanted to give these tags to a system running on startup, we'd have to use @ref cubos::engine::Cubos::startupTag "Cubos::startupTag" instead. -@snippet hello-cubos/main.cpp Set Systems +@note If we wanted to give these tags to a system running on startup, we'd have to use @ref cubos::engine::Cubos::startupTag "Cubos::startupTag" instead. Now let's see a bit about entities, components and resources. First we are going to need to use a few more things. We'll go over what each does as it comes up. -Entities have components, so let's create one to give our entities. -Because of how the engine works, we cannot declare a component on our `main.cpp` file. -We'll need to create a `components.hpp` for that. - -@include hello-cubos/components.hpp +Lets define a new component type, which stores a single integer, which we can use to identify the entity. -Here we create a component called "num" that stores a single integer. -We'll use it as the id of the entity it is attached to. -Back on our `main.cpp` file we'll need to include our new file. +@snippet hello-cubos/main.cpp Component Decl -@snippet hello-cubos/main.cpp Include Components +Notice that not only we define the type, but we also define reflection for it. This is a way to let CUBOS know what our data type is made of, making it compatible with serialization, UI debug tools and others automatically. -And the component needs to be registered. +We also need to register the component type with the `Cubos` object. @snippet hello-cubos/main.cpp Component Add -Let's create a resource now. -Unlike components, resources can be declared on the `main.cpp` file, so let's do that. +Now, lets create our own resource. @snippet hello-cubos/main.cpp Resource Decl @@ -88,21 +73,18 @@ Now let's create a startup system that spawns some entities. @ref cubos::core::ecs::Commands "Commands" is a system argument that allows us to interact with the world, in this case, by creating entities that have a `Num` component. -@ref cubos::core::ecs::Write "Write" is a system argument that allows us to modify a resource, in this case `Pop`. +To access the resource `Pop`, we just add a reference to it as a system argument (`Pop&`). Finally, we'll want a system that prints our entities. @snippet hello-cubos/main.cpp Entity Print -@ref cubos::core::ecs::Read "Read" is similar to `Write`, only it just gives us permission to read data from resources and components, we cannot alter them. +In this case, we don't change `Pop`, and only read its value. Thus, we use `const Pop&`. This allows CUBOS to make some optimizations behind the scenes. @ref cubos::core::ecs::Query "Query" allows us to access all entities with a given configuration of components. In this case, it will give us all entities with the `Num` component. -To finish configuring our program, we just need to register these two new systems. -We'll also have the entities be printed after our `Hello World` message. - -@snippet hello-cubos/main.cpp Entity System - With everything properly set up, all that remains is to run the engine. @snippet hello-cubos/main.cpp Run + +Try running the sample yourself, and you should see both the hello world messages and the list of entities we spawned! diff --git a/engine/samples/imgui/main.cpp b/engine/samples/imgui/main.cpp index d68333b231..0ba45de45e 100644 --- a/engine/samples/imgui/main.cpp +++ b/engine/samples/imgui/main.cpp @@ -68,34 +68,6 @@ struct DummyResource }; /// [Creating a dummy resource] -/// [DataInspector window example] -static void exampleDataInspectorSystem(DataInspector& inspector, DummyResource& data) -{ - ImGui::Begin("Data Inspector"); - ImGui::BeginTable("id1", 2); - - inspector.show("data.integer", data.integer); - inspector.edit("data.person", data.person); - inspector.edit("data.persons", data.persons); - inspector.edit("data.vec", data.vec); - inspector.edit("data.map", data.map); - - ImGui::EndTable(); - ImGui::End(); -} -/// [DataInspector window example] - -/// [ImGui window example] -static void exampleWindowSystem() -{ - ImGui::Begin("Dear ImGui + CUBOS."); - ImGui::Text("Hello world!"); - ImGui::End(); - - ImGui::ShowDemoWindow(); -} -/// [ImGui window example] - int main() { Cubos cubos{}; @@ -104,11 +76,17 @@ int main() cubos.addPlugin(imguiPlugin); /// [Adding the plugin] - /// [Adding the system] - cubos.system(exampleWindowSystem).tagged("cubos.imgui"); - /// [Adding the system] + /// [ImGui Demo] + cubos.system("show ImGui demo").tagged("cubos.imgui").call([]() { + ImGui::Begin("Dear ImGui + CUBOS."); + ImGui::Text("Hello world!"); + ImGui::End(); - /// [Filling the dummy resource 1] + ImGui::ShowDemoWindow(); + }); + /// [ImGui Demo] + + /// [Filling the dummy resource] cubos.addResource( DummyResource{.integer = 1337, .person = Person{"roby", 1337, 666.5F, false}, @@ -120,11 +98,25 @@ int main() {3, 6}, {4, 8}, }}); - /// [Filling the dummy resource 1] - - /// [Adding the system and a dummy resource with data] - cubos.system(exampleDataInspectorSystem).tagged("cubos.imgui"); - /// [Adding the system and a dummy resource with data] + /// [Filling the dummy resource] + + /// [DataInspector window example] + cubos.system("data inspector example") + .tagged("cubos.imgui") + .call([](DataInspector& inspector, DummyResource& data) { + ImGui::Begin("Data Inspector"); + ImGui::BeginTable("id1", 2); + + inspector.show("data.integer", data.integer); + inspector.edit("data.person", data.person); + inspector.edit("data.persons", data.persons); + inspector.edit("data.vec", data.vec); + inspector.edit("data.map", data.map); + + ImGui::EndTable(); + ImGui::End(); + }); + /// [DataInspector window example] cubos.run(); } diff --git a/engine/samples/imgui/page.md b/engine/samples/imgui/page.md index 4a34ec9b4c..9dcc8f7fb7 100644 --- a/engine/samples/imgui/page.md +++ b/engine/samples/imgui/page.md @@ -16,14 +16,12 @@ Then, make sure to add the plugin. @snippet imgui/main.cpp Adding the plugin -Once the ImGui plugin is added, you can create systems to display ImGui windows and widgets. Here's an example of how to create an ImGui window. +Once the ImGui plugin is added, you can create systems to display ImGui windows and widgets. Here's a system which opens an ImGui window, and its demo. -@snippet imgui/main.cpp ImGui window example +@snippet imgui/main.cpp ImGui Demo Ensure that you add your system with the `cubos.imgui` tag; otherwise, the ImGui elements from that system won't be be visible. -@snippet imgui/main.cpp Adding the system - Pretty simple right? You're now equipped to craft and utilize ImGui's functions to design your cool user interface. Now, we'll also show you how you can use the @ref cubos::engine::DataInspector resource in combination with @ref imgui-plugin plugin to inspect/modify data in real time. @@ -34,9 +32,9 @@ To start off, we'll need to have some sort of dummy data shared across our appli @snippet imgui/main.cpp Creating a dummy resource -@snippet imgui/main.cpp Filling the dummy resource 1 +@snippet imgui/main.cpp Filling the dummy resource -Well now, using the @ref cubos::engine::DataInspector is pretty easy, all you have to do is, obviously, access the resource on your system, and use the functions `DataInspector::edit` and `DataInspector::edit`. +Well now, using the @ref cubos::engine::DataInspector is pretty easy, all you have to do is access the resource on your system, and use the functions `DataInspector::edit` and `DataInspector::edit`. @snippet imgui/main.cpp DataInspector window example diff --git a/engine/samples/input/main.cpp b/engine/samples/input/main.cpp index c190b331fd..976173239b 100644 --- a/engine/samples/input/main.cpp +++ b/engine/samples/input/main.cpp @@ -164,59 +164,6 @@ static void showcaseMouseButtons(const Input& input, bool& explained) } /// [Showcase Mouse Buttons] -/// [Checking Type of Press] -static void update(const Input& input, const Window& window, State& state, ShouldQuit& shouldQuit) -{ - // FIXME: This is an hack to have one-shot actions while we don't have input events. - if (input.pressed("next-showcase")) - { - state.nextPressed = true; - } - else if (state.nextPressed) - { - state.nextPressed = false; - state.explained = false; - state.showcase++; - } - /// [Checking Type of Press] - - switch (state.showcase) - { - case 0: - return explain(state.explained); - case 1: - return showcaseXZ(input, state.explained); - case 2: - return showcaseModifiers(input, state.explained); - case 3: - return showcaseMultipleModifiers(input, state.explained); - case 4: - return showcaseAxis(input, state.explained); - case 5: - return showcaseModifierAxis(input, state.explained); - case 6: - return showcaseUnbound(window, state.explained); - case 7: - return showcaseMouseButtons(input, state.explained); - default: - shouldQuit.value = true; - } -} - -/// [Loading the bindings] -static void config(Settings& settings) -{ - settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); -} - -static void init(const Assets& assets, Input& input) -{ - auto bindings = assets.read(BindingsAsset); - input.bind(*bindings); - CUBOS_INFO("Loaded bindings: {}", input.bindings().at(0)); -} -/// [Loading the bindings] - int main() { auto cubos = Cubos(); @@ -227,12 +174,59 @@ int main() cubos.addResource(); - /// [Systems to load bindings] - cubos.startupSystem(config).tagged("cubos.settings"); - cubos.startupSystem(init).tagged("cubos.assets"); - /// [Systems to load bindings] + cubos.startupSystem("configure Assets").tagged("cubos.settings").call([](Settings& settings) { + settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); + }); - cubos.system(update).after("cubos.input.update"); + /// [Loading the bindings] + cubos.startupSystem("load and set the Input Bindings") + .tagged("cubos.assets") + .call([](const Assets& assets, Input& input) { + auto bindings = assets.read(BindingsAsset); + input.bind(*bindings); + CUBOS_INFO("Loaded bindings: {}", input.bindings().at(0)); + }); + /// [Loading the bindings] + + /// [Checking Type of Press] + cubos.system("detect input") + .after("cubos.input.update") + .call([](const Input& input, const Window& window, State& state, ShouldQuit& shouldQuit) { + // FIXME: This is an hack to have one-shot actions while we don't have input events. + if (input.pressed("next-showcase")) + { + state.nextPressed = true; + } + else if (state.nextPressed) + { + state.nextPressed = false; + state.explained = false; + state.showcase++; + } + /// [Checking Type of Press] + + switch (state.showcase) + { + case 0: + return explain(state.explained); + case 1: + return showcaseXZ(input, state.explained); + case 2: + return showcaseModifiers(input, state.explained); + case 3: + return showcaseMultipleModifiers(input, state.explained); + case 4: + return showcaseAxis(input, state.explained); + case 5: + return showcaseModifierAxis(input, state.explained); + case 6: + return showcaseUnbound(window, state.explained); + case 7: + return showcaseMouseButtons(input, state.explained); + default: + shouldQuit.value = true; + } + }); cubos.run(); return 0; diff --git a/engine/samples/input/page.md b/engine/samples/input/page.md index f5944e70ae..5c952255ca 100644 --- a/engine/samples/input/page.md +++ b/engine/samples/input/page.md @@ -35,9 +35,7 @@ For the purposes of this sample we can simply use an hardcoded reference to the @snippet input/main.cpp Setting the Bindings -To utilize the bindings, loading them is essential. This can be accomplished by establishing two startup systems: one to configure the `assets.io.path` path and the other to read from the asset and establish the required bindings. - -@snippet input/main.cpp Systems to load bindings +To utilize the bindings, loading them is essential. This can be accomplished by establishing a startup systems which reads from the asset and sets the required bindings. @snippet input/main.cpp Loading the bindings @@ -54,7 +52,7 @@ This avoids the state advancing more than once if the user presses it for more t Now let's see each of the prompt, to understand the full breadth of the plugin's functionalities. -@note All the functions henceforth are not systems, they are mere functions called by the `update` system, which passes the `Input` resource to them. +@note All the functions henceforth are not systems, they are mere functions called by the system above, which passes the `Input` resource to them. @snippet input/main.cpp Showcase Action Press diff --git a/engine/samples/physics/main.cpp b/engine/samples/physics/main.cpp index 8994b169d4..7fcaa8447f 100644 --- a/engine/samples/physics/main.cpp +++ b/engine/samples/physics/main.cpp @@ -19,71 +19,6 @@ struct MaxTime float current = 0.0F; }; -static void settingsSystem(Settings& settings) -{ - settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); -} - -static void setPaletteSystem(const Assets& assets, Renderer& renderer) -{ - // Read the palette's data and pass it to the renderer. - auto palette = assets.read(PaletteAsset); - renderer->setPalette(*palette); -} - -static void spawnCameraSystem(Commands cmds, ActiveCameras& activeCameras) -{ - // Spawn the camera entity. - activeCameras.entities[0] = - cmds.create() - .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 1000.0F}) - .add(Position{{50.0F, 50.0F, 50.0F}}) - .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{-1.0F, -1.0F, -1.0F}), glm::vec3{0.0F, 1.0F, 0.0F})}) - .entity(); -} - -static void spawnLightSystem(Commands cmds) -{ - // Spawn the sun. - cmds.create() - .add(DirectionalLight{glm::vec3(1.0F), 1.0F}) - .add(Rotation{glm::quat(glm::vec3(glm::radians(45.0F), glm::radians(45.0F), 0))}); -} - -static void spawnCarSystem(Commands cmds, const Assets& assets) -{ - // Calculate the necessary offset to center the model on (0, 0, 0). - auto car = assets.read(CarAsset); - glm::vec3 offset = glm::vec3(car->size().x, 0.0F, car->size().z) / -2.0F; - - // Create the car entity - cmds.create() - .add(RenderableGrid{CarAsset, offset}) - .add(Position{{0.0F, 0.0F, 0.0F}}) - .add(PreviousPosition{{0.0F, 0.0F, 0.0F}}) - .add( - PhysicsVelocity{.velocity = {0.0F, 0.0F, 0.0F}, .force = {0.0F, 0.0F, 0.0F}, .impulse = {0.0F, 0.0F, 0.0F}}) - .add(PhysicsMass{.mass = 500.0F, .inverseMass = 1.0F / 500.0F}) - .add(AccumulatedCorrection{{0.0F, 0.0F, 0.0F}}) - .add(LocalToWorld{}); -} - -static void pushCarSystem(Query query, MaxTime& time, const DeltaTime& deltaTime) -{ - for (auto [velocity] : query) - { - if (time.current < time.max) - { - if (time.current == 0.0F) - { - velocity.impulse += glm::vec3(0.0F, 5000.0F, 0.0F); - } - velocity.force += glm::vec3(0.0F, 0.0F, -5000.0F); - time.current += deltaTime.value; - } - } -} - int main(int argc, char** argv) { Cubos cubos{argc, argv}; @@ -94,13 +29,68 @@ int main(int argc, char** argv) cubos.addPlugin(voxelsPlugin); cubos.addPlugin(physicsPlugin); - cubos.startupSystem(settingsSystem).tagged("cubos.settings"); - cubos.startupSystem(spawnCameraSystem); - cubos.startupSystem(spawnLightSystem); - cubos.startupSystem(setPaletteSystem).after("cubos.renderer.init"); - cubos.startupSystem(spawnCarSystem).after("cubos.settings").after("cubos.assets.bridge"); + cubos.startupSystem("configure Assets").tagged("cubos.settings").call([](Settings& settings) { + settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); + }); + + cubos.startupSystem("create Camera").call([](Commands cmds, ActiveCameras& activeCameras) { + activeCameras.entities[0] = cmds.create() + .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 1000.0F}) + .add(Position{{50.0F, 50.0F, 50.0F}}) + .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{-1.0F, -1.0F, -1.0F}), + glm::vec3{0.0F, 1.0F, 0.0F})}) + .entity(); + }); - cubos.system(pushCarSystem).tagged("cubos.physics.apply_forces"); + cubos.startupSystem("create the sun").call([](Commands cmds) { + cmds.create() + .add(DirectionalLight{glm::vec3(1.0F), 1.0F}) + .add(Rotation{glm::quat(glm::vec3(glm::radians(45.0F), glm::radians(45.0F), 0))}); + }); + + cubos.startupSystem("load the palette") + .after("cubos.renderer.init") + .call([](const Assets& assets, Renderer& renderer) { + auto palette = assets.read(PaletteAsset); + renderer->setPalette(*palette); + }); + + cubos.startupSystem("create a car") + .after("cubos.settings") + .after("cubos.assets.bridge") + .call([](Commands cmds, const Assets& assets) { + // Calculate the necessary offset to center the model on (0, 0, 0). + auto car = assets.read(CarAsset); + glm::vec3 offset = glm::vec3(car->size().x, 0.0F, car->size().z) / -2.0F; + + // Create the car entity + cmds.create() + .add(RenderableGrid{CarAsset, offset}) + .add(Position{{0.0F, 0.0F, 0.0F}}) + .add(PreviousPosition{{0.0F, 0.0F, 0.0F}}) + .add(PhysicsVelocity{ + .velocity = {0.0F, 0.0F, 0.0F}, .force = {0.0F, 0.0F, 0.0F}, .impulse = {0.0F, 0.0F, 0.0F}}) + .add(PhysicsMass{.mass = 500.0F, .inverseMass = 1.0F / 500.0F}) + .add(AccumulatedCorrection{{0.0F, 0.0F, 0.0F}}) + .add(LocalToWorld{}); + }); + + cubos.system("push the car") + .tagged("cubos.physics.apply_forces") + .call([](Query query, MaxTime& time, const DeltaTime& deltaTime) { + for (auto [velocity] : query) + { + if (time.current < time.max) + { + if (time.current == 0.0F) + { + velocity.impulse += glm::vec3(0.0F, 5000.0F, 0.0F); + } + velocity.force += glm::vec3(0.0F, 0.0F, -5000.0F); + time.current += deltaTime.value; + } + } + }); cubos.run(); } diff --git a/engine/samples/renderer/main.cpp b/engine/samples/renderer/main.cpp index 4139deb7d6..4f262c462d 100644 --- a/engine/samples/renderer/main.cpp +++ b/engine/samples/renderer/main.cpp @@ -7,100 +7,84 @@ using namespace cubos::engine; -static void settingsSystem(Settings& settings) -{ - // We don't load assets in this sample and we don't even have an assets folder, so we should - // disable assets IO. - settings.setBool("assets.io.enabled", false); -} - -/// [Setting the palette] -static void setPaletteSystem(Renderer& renderer) -{ - // Create a simple palette with 3 materials (red, green and blue). - renderer->setPalette(VoxelPalette{{ - {{1, 0, 0, 1}}, - {{0, 1, 0, 1}}, - {{0, 0, 1, 1}}, - }}); -} -/// [Setting the palette] - -/// [Spawning a voxel grid] -static void spawnVoxelGridSystem(Commands commands, Assets& assets) +int main() { - // Create a 2x2x2 grid whose voxels alternate between the materials defined in the palette. - auto gridAsset = assets.create(VoxelGrid{{2, 2, 2}, {1, 2, 3, 1, 2, 3, 1, 2}}); + Cubos cubos{}; - // Spawn an entity with a renderable grid component and a identity transform. - commands.create().add(RenderableGrid{gridAsset, {-1.0F, 0.0F, -1.0F}}).add(LocalToWorld{}); -} -/// [Spawning a voxel grid] + /// [Adding the plugin] + cubos.addPlugin(splitscreenPlugin); + cubos.addPlugin(rendererPlugin); + /// [Adding the plugin] -/// [Spawning a point light] -static void spawnLightSystem(Commands commands) -{ - // Spawn a point light. - commands.create() - .add(PointLight{.color = {1.0F, 1.0F, 1.0F}, .intensity = 1.0F, .range = 10.0F}) - .add(Position{{1.0F, 3.0F, -2.0F}}); -} -/// [Spawning a point light] + cubos.startupSystem("configure Assets").tagged("cubos.settings").call([](Settings& settings) { + // We don't load assets in this sample and we don't even have an assets folder, so we should + // disable assets IO. + settings.setBool("assets.io.enabled", false); + }); -/// [Setting the environment] -static void setEnvironmentSystem(RendererEnvironment& env) -{ - env.ambient = {0.2F, 0.2F, 0.2F}; - env.skyGradient[0] = {0.1F, 0.2F, 0.4F}; - env.skyGradient[1] = {0.6F, 0.6F, 0.8F}; -} -/// [Setting the environment] + /// [Setting the palette] + cubos.startupSystem("set the palette").after("cubos.renderer.init").call([](Renderer& renderer) { + // Create a simple palette with 3 materials (red, green and blue). + renderer->setPalette(VoxelPalette{{ + {{1, 0, 0, 1}}, + {{0, 1, 0, 1}}, + {{0, 0, 1, 1}}, + }}); + }); + /// [Setting the palette] -/// [Spawn the cameras] -static void spawnCamerasSystem(Commands commands, ActiveCameras& camera) -{ - // Spawn the a camera entity for the first viewport. - camera.entities[0] = - commands.create() - .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) - .add(Position{{-3.0, 1.0F, -3.0F}}) - .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{1.0F, 0.0F, 1.0F}), glm::vec3{0.0F, 1.0F, 0.0F})}) - .entity(); + /// [Spawning a voxel grid] + cubos.startupSystem("create a voxel grid").call([](Commands commands, Assets& assets) { + // Create a 2x2x2 grid whose voxels alternate between the materials defined in the palette. + auto gridAsset = assets.create(VoxelGrid{{2, 2, 2}, {1, 2, 3, 1, 2, 3, 1, 2}}); - camera.entities[1] = - commands.create() - .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) - .add(Position{{-3.0, 1.0F, -3.0F}}) - .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{1.0F, 0.0F, 1.0F}), glm::vec3{0.0F, 1.0F, 0.0F})}) - .entity(); + // Spawn an entity with a renderable grid component and a identity transform. + commands.create().add(RenderableGrid{gridAsset, {-1.0F, 0.0F, -1.0F}}).add(LocalToWorld{}); + }); + /// [Spawning a voxel grid] - camera.entities[2] = + /// [Spawning a point light] + cubos.startupSystem("create a point light").call([](Commands commands) { + // Spawn a point light. commands.create() - .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) - .add(Position{{-3.0, 1.0F, -3.0F}}) - .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{1.0F, 0.0F, 1.0F}), glm::vec3{0.0F, 1.0F, 0.0F})}) - .entity(); -} -/// [Spawn the cameras] + .add(PointLight{.color = {1.0F, 1.0F, 1.0F}, .intensity = 1.0F, .range = 10.0F}) + .add(Position{{1.0F, 3.0F, -2.0F}}); + }); + /// [Spawning a point light] -int main() -{ - Cubos cubos{}; + /// [Setting the environment] + cubos.startupSystem("set the environment").call([](RendererEnvironment& env) { + env.ambient = {0.2F, 0.2F, 0.2F}; + env.skyGradient[0] = {0.1F, 0.2F, 0.4F}; + env.skyGradient[1] = {0.6F, 0.6F, 0.8F}; + }); + /// [Setting the environment] - /// [Adding the plugin] - cubos.addPlugin(splitscreenPlugin); - cubos.addPlugin(rendererPlugin); - /// [Adding the plugin] + /// [Spawn the cameras] + cubos.startupSystem("create cameras").call([](Commands commands, ActiveCameras& camera) { + // Spawn the a camera entity for the first viewport. + camera.entities[0] = commands.create() + .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) + .add(Position{{-3.0, 1.0F, -3.0F}}) + .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{1.0F, 0.0F, 1.0F}), + glm::vec3{0.0F, 1.0F, 0.0F})}) + .entity(); - cubos.startupSystem(settingsSystem).tagged("cubos.settings"); + camera.entities[1] = commands.create() + .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) + .add(Position{{-3.0, 1.0F, -3.0F}}) + .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{1.0F, 0.0F, 1.0F}), + glm::vec3{0.0F, 1.0F, 0.0F})}) + .entity(); - /// [Adding the systems] - cubos.startupSystem(setPaletteSystem).after("cubos.renderer.init"); - cubos.startupSystem(spawnVoxelGridSystem); - cubos.startupSystem(spawnLightSystem); - cubos.startupSystem(setEnvironmentSystem); - cubos.startupSystem(spawnCamerasSystem); - /// [Adding the systems] + camera.entities[2] = commands.create() + .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 100.0F}) + .add(Position{{-3.0, 1.0F, -3.0F}}) + .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{1.0F, 0.0F, 1.0F}), + glm::vec3{0.0F, 1.0F, 0.0F})}) + .entity(); + }); + /// [Spawn the cameras] cubos.run(); } diff --git a/engine/samples/renderer/page.md b/engine/samples/renderer/page.md index e0e41ae999..ea544f65c7 100644 --- a/engine/samples/renderer/page.md +++ b/engine/samples/renderer/page.md @@ -12,6 +12,8 @@ configured with a simple scene, lighting and split-screen rendering. The plugin function is included from the @ref engine/renderer/plugin.hpp header. You may need to include other headers, depending on what you want to access. +In this sample we also use the split-screen plugin which automatically sets the viewport of each camera to achieve split-screen. + @snippet renderer/main.cpp Adding the plugin The first thing we're going to worry about is setting the @@ -19,6 +21,9 @@ The first thing we're going to worry about is setting the would usually be loaded from a file, but for this example we'll just create it manually. +Since this system accesses the @ref cubos::engine::Renderer "Renderer" resource, which is only +initialized on the tag `cubos.renderer.init`, we should specify that it must run after it. + @snippet renderer/main.cpp Setting the palette We should also spawn a @ref cubos::engine::VoxelGrid "voxel grid", so we have @@ -40,10 +45,3 @@ Lastly, without a camera, we won't be able to see anything. Cameras can be set using the @ref cubos::engine::ActiveCameras "ActiveCameras" resource. @snippet renderer/main.cpp Spawn the cameras - -Then, its just a matter of adding these systems to the engine. The only one -which requires special attention is the `setPaletteSystem`. This system -accesses the @ref cubos::engine::Renderer "Renderer" resource, which is only -initialized on the tag `cubos.renderer.init`. - -@snippet renderer/main.cpp Adding the systems diff --git a/engine/samples/scene/main.cpp b/engine/samples/scene/main.cpp index 5921665047..056e6fc8fd 100644 --- a/engine/samples/scene/main.cpp +++ b/engine/samples/scene/main.cpp @@ -30,43 +30,6 @@ CUBOS_REFLECT_IMPL(Parent) static const Asset SceneAsset = AnyAsset("f0d86ba8-5f34-440f-a180-d9d12c8e8b91"); /// [Setting the asset] -static void settings(Settings& settings) -{ - settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); -} - -/// [Spawning the scene] -static void spawnScene(Commands commands, const Assets& assets) -{ - auto sceneRead = assets.read(SceneAsset); - commands.spawn(sceneRead->blueprint); -} -/// [Spawning the scene] - -/// [Displaying the scene] -static void printStuff(const World& world, Query query) -{ - using cubos::core::data::DebugSerializer; - using cubos::core::memory::Stream; - - DebugSerializer ser{Stream::stdOut}; - - for (auto [entity] : query) - { - Stream::stdOut.printf("Entity "); - ser.write(entity); - Stream::stdOut.put('\n'); - for (auto [type, value] : world.components(entity)) - { - Stream::stdOut.printf("- {}: ", type->name()); - ser.write(*type, value); - Stream::stdOut.put('\n'); - } - Stream::stdOut.put('\n'); - } -} -/// [Displaying the scene] - int main(int argc, char** argv) { Cubos cubos(argc, argv); @@ -78,12 +41,42 @@ int main(int argc, char** argv) cubos.addComponent(); cubos.addComponent(); - cubos.startupSystem(settings).tagged("cubos.settings"); + cubos.startupSystem("configure Assets").tagged("cubos.settings").call([](Settings& settings) { + settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); + }); + + /// [Spawning the scene] + cubos.startupSystem("spawn the scene") + .tagged("spawn") + .tagged("cubos.assets") + .call([](Commands commands, const Assets& assets) { + auto sceneRead = assets.read(SceneAsset); + commands.spawn(sceneRead->blueprint); + }); + /// [Spawning the scene] + + /// [Printing the scene] + cubos.startupSystem("print the scene").after("spawn").call([](const World& world, Query query) { + using cubos::core::data::DebugSerializer; + using cubos::core::memory::Stream; - /// [Adding the system] - cubos.startupSystem(spawnScene).tagged("spawn").tagged("cubos.assets"); - /// [Adding the system] + DebugSerializer ser{Stream::stdOut}; + + for (auto [entity] : query) + { + Stream::stdOut.printf("Entity "); + ser.write(entity); + Stream::stdOut.put('\n'); + for (auto [type, value] : world.components(entity)) + { + Stream::stdOut.printf("- {}: ", type->name()); + ser.write(*type, value); + Stream::stdOut.put('\n'); + } + Stream::stdOut.put('\n'); + } + }); + /// [Printing the scene] - cubos.startupSystem(printStuff).after("spawn"); cubos.run(); } diff --git a/engine/samples/scene/page.md b/engine/samples/scene/page.md index 248e5f1df6..5060795c2f 100644 --- a/engine/samples/scene/page.md +++ b/engine/samples/scene/page.md @@ -52,7 +52,7 @@ In this case, we'll run this system at startup, since we want to spawn it a sing Since it's a startup system, we'll have to tag it with `cubos.assets` to make sure it runs only after the scene bridge has been registered. On a real game, you could have, for example, a scene for an enemy which you spawn multiple times, instead of just once at startup. -@snippet scene/main.cpp Adding the system +@snippet scene/main.cpp Printing the scene This sample will output the list of every entity in the scene, so you can check that everything is working as expected. If you run it, it should give you a list that has: diff --git a/engine/samples/settings/main.cpp b/engine/samples/settings/main.cpp index 658b546613..93426e6794 100644 --- a/engine/samples/settings/main.cpp +++ b/engine/samples/settings/main.cpp @@ -5,19 +5,17 @@ using namespace cubos::engine; -/// [System] -static void checkSettings(Settings& settings) -{ - CUBOS_INFO("{}", settings.getString("greeting", "Hello!")); -} -/// [System] - /// [Run] int main(int argc, char** argv) { Cubos cubos{argc, argv}; + cubos.addPlugin(settingsPlugin); - cubos.startupSystem(checkSettings).after("cubos.settings"); + + cubos.startupSystem("print setting value").after("cubos.settings").call([](Settings& settings) { + CUBOS_INFO("{}", settings.getString("greeting", "Hello!")); + }); + cubos.run(); } /// [Run] diff --git a/engine/samples/settings/page.md b/engine/samples/settings/page.md index 7bc6db386e..1703aac143 100644 --- a/engine/samples/settings/page.md +++ b/engine/samples/settings/page.md @@ -7,18 +7,16 @@ This example shows how the @ref settings-plugin plugin can be used to load settings from a file and command-line arguments. -Accesing the settings is straightforward: +@snippet settings/main.cpp Run -@snippet settings/main.cpp System +We add a system which prints the value of the setting `greetings`. +Notice that we make it run after the tag `cubos.settings`, so that the settings have already been loaded. If the setting `greetings` has been set on the `settings.json` file next to the sample's executable, or if it has been passed as a command-line argument (e.g. `./engine-sample.settings --greetings "Hello, world!"`), the sample will output that value. Otherwise, it will output `Hello!`, which we set as a default. -We want this system to run after the settings have been loaded, so we run it -after the tag `cubos.settings`. Notice that if we want the command-line -arguments to be loaded as settings, we need to pass `argc` and `argv` to the +Notice that if we want the command-line arguments to be loaded as settings, we need to pass `argc` and `argv` to the @ref cubos::engine::Cubos::Cubos(int, char**) "Cubos::Cubos(int, char**)" constructor. -@snippet settings/main.cpp Run diff --git a/engine/samples/voxels/main.cpp b/engine/samples/voxels/main.cpp index 997383bbee..278270853d 100644 --- a/engine/samples/voxels/main.cpp +++ b/engine/samples/voxels/main.cpp @@ -12,52 +12,6 @@ static const Asset CarAsset = AnyAsset("059c16e7-a439-44c7-9bdc-6e069 static const Asset PaletteAsset = AnyAsset("1aa5e234-28cb-4386-99b4-39386b0fc215"); /// [Get handles to assets] -static void settingsSystem(Settings& settings) -{ - settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); -} - -/// [Load and set palette] -static void setPaletteSystem(const Assets& assets, Renderer& renderer) -{ - // Read the palette's data and pass it to the renderer. - auto palette = assets.read(PaletteAsset); - renderer->setPalette(*palette); -} -/// [Load and set palette] - -static void spawnCameraSystem(Commands cmds, ActiveCameras& activeCameras) -{ - // Spawn the camera entity. - activeCameras.entities[0] = - cmds.create() - .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 1000.0F}) - .add(Position{{50.0F, 50.0F, 50.0F}}) - .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{-1.0F, -1.0F, -1.0F}), glm::vec3{0.0F, 1.0F, 0.0F})}) - .add(FreeCameraController{}) - .entity(); -} - -static void spawnLightSystem(Commands cmds) -{ - // Spawn the sun. - cmds.create() - .add(DirectionalLight{glm::vec3(1.0F), 1.0F}) - .add(Rotation{glm::quat(glm::vec3(glm::radians(45.0F), glm::radians(45.0F), 0))}); -} - -/// [Spawn car system] -static void spawnCarSystem(Commands cmds, const Assets& assets) -{ - // Calculate the necessary offset to center the model on (0, 0, 0). - auto car = assets.read(CarAsset); - glm::vec3 offset = glm::vec3(car->size().x, 0.0F, car->size().z) / -2.0F; - - // Create the car entity - cmds.create().add(RenderableGrid{CarAsset, offset}).add(LocalToWorld{}); -} -/// [Spawn car system] - int main(int argc, char** argv) { Cubos cubos{argc, argv}; @@ -68,13 +22,47 @@ int main(int argc, char** argv) /// [Adding the plugin] cubos.addPlugin(freeCameraControllerPlugin); - cubos.startupSystem(settingsSystem).tagged("cubos.settings"); - cubos.startupSystem(spawnCameraSystem); - cubos.startupSystem(spawnLightSystem); - /// [Adding systems] - cubos.startupSystem(setPaletteSystem).after("cubos.renderer.init"); - cubos.startupSystem(spawnCarSystem).tagged("cubos.assets"); - /// [Adding systems] + cubos.startupSystem("configure Assets").tagged("cubos.settings").call([](Settings& settings) { + settings.setString("assets.io.path", SAMPLE_ASSETS_FOLDER); + }); + + cubos.startupSystem("create a camera").call([](Commands cmds, ActiveCameras& activeCameras) { + // Spawn the camera entity. + activeCameras.entities[0] = cmds.create() + .add(Camera{.fovY = 60.0F, .zNear = 0.1F, .zFar = 1000.0F}) + .add(Position{{50.0F, 50.0F, 50.0F}}) + .add(Rotation{glm::quatLookAt(glm::normalize(glm::vec3{-1.0F, -1.0F, -1.0F}), + glm::vec3{0.0F, 1.0F, 0.0F})}) + .add(FreeCameraController{}) + .entity(); + }); + + cubos.startupSystem("create the sun").call([](Commands cmds) { + cmds.create() + .add(DirectionalLight{glm::vec3(1.0F), 1.0F}) + .add(Rotation{glm::quat(glm::vec3(glm::radians(45.0F), glm::radians(45.0F), 0))}); + }); + + /// [Load and set palette] + cubos.startupSystem("load and set pallete") + .after("cubos.renderer.init") + .call([](const Assets& assets, Renderer& renderer) { + // Read the palette's data and pass it to the renderer. + auto palette = assets.read(PaletteAsset); + renderer->setPalette(*palette); + }); + /// [Load and set palette] + + /// [Spawn car system] + cubos.startupSystem("create a car").tagged("cubos.assets").call([](Commands cmds, const Assets& assets) { + // Calculate the necessary offset to center the model on (0, 0, 0). + auto car = assets.read(CarAsset); + glm::vec3 offset = glm::vec3(car->size().x, 0.0F, car->size().z) / -2.0F; + + // Create the car entity + cmds.create().add(RenderableGrid{CarAsset, offset}).add(LocalToWorld{}); + }); + /// [Spawn car system] cubos.run(); } \ No newline at end of file diff --git a/engine/samples/voxels/page.md b/engine/samples/voxels/page.md index 14bbbc5ed8..9733485f51 100644 --- a/engine/samples/voxels/page.md +++ b/engine/samples/voxels/page.md @@ -27,8 +27,4 @@ Now, we can create an entity with our car asset. @snippet voxels/main.cpp Spawn car system -Finally, we just add these systems. - -@snippet voxels/main.cpp Adding systems - -And voilá, you now have a car floating in space. \ No newline at end of file +And voilá, you now have a car floating in space.