diff --git a/.githooks/pre-commit b/.githooks/pre-commit index 53b5c441a9..98d2cee035 100755 --- a/.githooks/pre-commit +++ b/.githooks/pre-commit @@ -1,3 +1,4 @@ +#!/bin/sh for file in $(git diff --cached --name-only | grep -E '.*\.(c|cpp|h|hpp)$') do clang-format -i $file diff --git a/.github/workflows/clang-format-check.yml b/.github/workflows/clang-format-check.yml index b9f40ab268..226b02be46 100644 --- a/.github/workflows/clang-format-check.yml +++ b/.github/workflows/clang-format-check.yml @@ -22,5 +22,5 @@ jobs: - name: Check run: | for file in $(git diff -U0 --name-only HEAD^ | grep -E '.*\.(c|cpp|h|hpp)$'); do - clang-format --dry-run -Werror $file || exit 1 + clang-format --dry-run -Werror $file || echo $file done diff --git a/docs/pages/3_examples/2_engine/main.md b/docs/pages/3_examples/2_engine/main.md index 02b1991383..06d0ab0c53 100644 --- a/docs/pages/3_examples/2_engine/main.md +++ b/docs/pages/3_examples/2_engine/main.md @@ -5,6 +5,7 @@ The following examples have fully documented tutorials on how to use the multiple plugins of the engine: +- @subpage examples-engine-hello-cubos - @copybrief examples-engine-hello-cubos - @subpage examples-engine-settings - @copybrief examples-engine-settings - @subpage examples-engine-renderer - @copybrief examples-engine-renderer - @subpage examples-engine-scene - @copybrief examples-engine-scene diff --git a/engine/samples/CMakeLists.txt b/engine/samples/CMakeLists.txt index d20ce90a65..5471d5d57c 100644 --- a/engine/samples/CMakeLists.txt +++ b/engine/samples/CMakeLists.txt @@ -17,6 +17,7 @@ macro(make_sample) # Get the source files set(sources "${CMAKE_CURRENT_SOURCE_DIR}/${MAKE_SAMPLE_DIR}/main.cpp") + foreach(source IN LISTS MAKE_SAMPLE_SOURCES) list(APPEND sources "${CMAKE_CURRENT_SOURCE_DIR}/${MAKE_SAMPLE_DIR}/${source}") endforeach() @@ -36,9 +37,9 @@ macro(make_sample) endmacro() # Add samples +make_sample(DIR "hello-cubos" COMPONENTS) make_sample(DIR "settings") make_sample(DIR "events") -make_sample(DIR "systems") make_sample(DIR "input" ASSETS) make_sample(DIR "assets/bridge" ASSETS) make_sample(DIR "assets/json" ASSETS) diff --git a/engine/samples/hello-cubos/components.hpp b/engine/samples/hello-cubos/components.hpp new file mode 100644 index 0000000000..b52a042f48 --- /dev/null +++ b/engine/samples/hello-cubos/components.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include + +struct [[cubos::component("num", VecStorage)]] Num +{ + int value; +}; diff --git a/engine/samples/hello-cubos/main.cpp b/engine/samples/hello-cubos/main.cpp new file mode 100644 index 0000000000..b6eda924b9 --- /dev/null +++ b/engine/samples/hello-cubos/main.cpp @@ -0,0 +1,102 @@ +/// [Include Components] +#include "components.hpp" +/// [Include Components] + +/// [Include] +#include + +using cubos::engine::Cubos; +/// [Include] + +/// [Include Entity Stuff] +using cubos::core::ecs::Commands; +using cubos::core::ecs::Query; +using cubos::core::ecs::Read; +using cubos::core::ecs::Write; +/// [Include Entity Stuff] + +/// [Resource Decl] +struct Pop +{ + int count; +}; +/// [Resource Decl] + +/// [Hello Cubos] +static void sayHelloCubos() +{ + CUBOS_INFO("Hello CUBOS"); +} +/// [Hello Cubos] + +/// [Hello World] +static void sayHello() +{ + CUBOS_INFO("Hello"); +} + +static void sayWorld() +{ + CUBOS_INFO("World"); +} +/// [Hello World] + +/// [Entity Spawn] +static void spawnEntities(Commands cmds, Write pop) +{ + for (int i = 0; i < 10; i++) + { + cmds.create(Num{i}); + pop->count += 1; + } +} +/// [Entity Spawn] + +/// [Entity Print] +static void checkEntities(Query> query, Read pop) +{ + for (auto [entity, num] : query) + { + CUBOS_INFO("Entity '{}' of '{}'", num->value, pop->count); + } +} +/// [Entity Print] + +/// [Engine] +int main() +{ + Cubos cubos{}; + /// [Engine] + + /// [Tags] + cubos.tag("helloTag").before("worldTag"); + /// [Tags] + + /// [Set Startup] + cubos.startupSystem(sayHelloCubos); + /// [Set Startup] + + /// [Set Systems] + cubos.system(sayHello).tagged("helloTag"); + cubos.system(sayWorld).tagged("worldTag"); + /// [Set Systems] + + /// [Component Add] + cubos.addComponent(); + /// [Component Add] + + /// [Resource Add] + cubos.addResource(); + /// [Resource Add] + + /// [Entity System] + cubos.startupSystem(spawnEntities); + + cubos.tag("entityCheckUp").after("worldTag"); + cubos.system(checkEntities).tagged("entityCheckUp"); + /// [Entity System] + + /// [Run] + cubos.run(); +} +/// [Run] diff --git a/engine/samples/hello-cubos/page.md b/engine/samples/hello-cubos/page.md new file mode 100644 index 0000000000..816ac3966f --- /dev/null +++ b/engine/samples/hello-cubos/page.md @@ -0,0 +1,107 @@ +# Hello CUBOS. {#examples-engine-hello-cubos} + +@brief Using @ref cubos::engine::Cubos "Cubos" to create a simple program. + +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 + +First we'll need to get a `Cubos` object. + +@snippet hello-cubos/main.cpp Engine + +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. + +@snippet hello-cubos/main.cpp Hello Cubos + +This function simply prints `Hello CUBOS` to the console. +It uses 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. + +@snippet hello-cubos/main.cpp Hello World + +Instead of using `startupSystem`, we'll use @ref cubos::engine::Cubos::system "Cubos::system". +This means the systems will be called every cycle, instead of just once at startup. + +@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. +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. +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 + +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. + +@snippet hello-cubos/main.cpp Include Entity Stuff + +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 + +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 Include Components + +And the component needs to be registered. + +@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. + +@snippet hello-cubos/main.cpp Resource Decl + +This resource will store the total number of spawned entities, a population counter of sorts. +It too needs to be registered. + +@snippet hello-cubos/main.cpp Resource Add + +Now let's create a startup system that spawns some entities. + +@snippet hello-cubos/main.cpp Entity Spawn + +@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`. + +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. + +@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 diff --git a/engine/samples/systems/main.cpp b/engine/samples/systems/main.cpp deleted file mode 100644 index 6b904211c0..0000000000 --- a/engine/samples/systems/main.cpp +++ /dev/null @@ -1,67 +0,0 @@ -#include - -void tagA() -{ - CUBOS_INFO("[By Tag] A"); -} -void tagB() -{ - CUBOS_INFO("[By Tag] B"); -} -void tagC() -{ - CUBOS_INFO("[By Tag] C"); -} - -void systemA() -{ - CUBOS_INFO("[By System] A"); -} -void systemB() -{ - CUBOS_INFO("[By System] B"); -} -void systemC() -{ - CUBOS_INFO("[By System] C"); -} - -void systemInherit1() -{ - CUBOS_INFO("[By System] Inheritance 1"); -} - -void systemInherit2() -{ - CUBOS_INFO("[By System] Inheritance 2"); -} - -int main() -{ - cubos::engine::Cubos cubos; - - cubos.startupTag("B").before("C"); - cubos.startupTag("C").after("A"); - cubos.startupTag("A"); - - // Order using tags - cubos.startupSystem(tagB).tagged("B"); - cubos.startupSystem(tagC).tagged("C"); - cubos.startupSystem(tagA).tagged("A"); - - // Closed loop. This will prevent chain compilation! - // cubos.startupTag("A").after("C"); - - // Conditions, determining system execution - auto lambdaCondYes = []() { CUBOS_INFO("System ran with condition true!"); }; - cubos.startupSystem(lambdaCondYes).runIf([]() { return true; }); - - auto lambdaCondNo = []() { CUBOS_INFO("System ran with condition false, you should not be reading this!"); }; - cubos.startupSystem(lambdaCondNo).runIf([]() { return false; }).runIf([]() { return true; }); - - // Conditions can also be inherited by systems and tags - cubos.startupTag("conditionInherit").runIf([]() { return false; }); - cubos.startupSystem(lambdaCondNo).tagged("conditionInherit"); - - cubos.run(); -}