diff --git a/src/core/camera_node.c b/src/core/camera_node.c new file mode 100644 index 0000000..af64e39 --- /dev/null +++ b/src/core/camera_node.c @@ -0,0 +1,59 @@ +#include "camera_node.h" +#include "utils/debug.h" + +START_REFLECT(CameraNode); +REFLECT_TYPECLASS(CameraNode, Drop); +REFLECT_TYPECLASS(CameraNode, Transformable); +REFLECT_TYPECLASS(CameraNode, SceneNodeEntity); +END_REFLECT(CameraNode); + +impl_Drop_for(CameraNode, + DestroyCameraNode +) +impl_Transformable_for(CameraNode, + CameraNodeGetTransform, + CameraNodeGetGlobalTransform +) + +impl_SceneNodeEntity_defaults(CameraNode); +impl_SceneNodeEntity_for(CameraNode, + CameraNodeEnterTree, + CameraNode_default_exit_tree, + CameraNode_default_tick +) + +SceneNode *CreateCameraNode() { + CameraNode *camera_node = new(CameraNode); + camera_node->transform = TransformIdentity(); + camera_node->global_transform = TransformIdentity(); + camera_node->node = NULL; + return CreateSceneNode(CameraNode_as_SceneNodeEntity(camera_node)); +} + +void DestroyCameraNode(CameraNode *self) { + SceneNodeDetachEntity(self->node); + free(self); +} + +void CameraNodeEnterTree(CameraNode *self) { + if(self->node->scene->main_camera == NULL) { + self->node->scene->main_camera = self; + LOG_INFO("CameraNodeEnterTree"); + } +} + +Camera3D CameraNodeGetCamera(CameraNode *self) { + Matrix mat = TransformGetMatrix(&self->global_transform); + Vector3 forward = { mat.m8, mat.m9, mat.m10 }; + LOG_INFO("Forward: %f, %f, %f", forward.x, forward.y, forward.z); + return (Camera3D){ + .fovy = 90, + .position = self->global_transform.translation, + .projection = CAMERA_PERSPECTIVE, + .target = Vector3Add(self->global_transform.translation, Vector3Scale(forward, 1000.f)), + .up = (Vector3){mat.m4, mat.m5, mat.m6} + }; +} + +Transform *CameraNodeGetTransform(CameraNode *self) { return &self->transform; } +Transform *CameraNodeGetGlobalTransform(CameraNode *self) { return &self->global_transform; } diff --git a/src/core/camera_node.h b/src/core/camera_node.h index 4f3f4ee..69cb6ba 100644 --- a/src/core/camera_node.h +++ b/src/core/camera_node.h @@ -1,18 +1,31 @@ -#pragma once +#ifndef CAMERA_NODE_H +#define CAMERA_NODE_H +#include "scene.h" #include "scene_node_entity.h" +#include "transformable.h" #include "utils/drop.h" #include "raylib.h" typedef struct CameraNode { SceneNode *node; + Transform transform; + Transform global_transform; } CameraNode; -void CameraNodeEnterTree(CameraNode *self); -void CameraNodeExitTree(CameraNode *self); -void CameraNodeTick(CameraNode *self, double delta); -Camera3D CameraNodeGetCamera(CameraNode *self); +extern SceneNode *CreateCameraNode(); +extern void DestroyCameraNode(CameraNode *self); -impl_default_Drop_for(CameraNode); -impl_SceneNodeEntity_for(CameraNode, CameraNodeEnterTree, CameraNodeExitTree, CameraNodeTick); +extern void CameraNodeEnterTree(CameraNode *self); +extern Camera3D CameraNodeGetCamera(CameraNode *self); + +extern Transform *CameraNodeGetTransform(CameraNode *self); +extern Transform *CameraNodeGetGlobalTransform(CameraNode *self); + +DECL_REFLECT(CameraNode) +decl_typeclass_impl(Drop, CameraNode) +decl_typeclass_impl(Transformable, CameraNode) +decl_typeclass_impl(SceneNodeEntity, CameraNode) + +#endif // !CAMERA_NODE_H diff --git a/src/core/engine_global.c b/src/core/engine_global.c new file mode 100644 index 0000000..5e9a866 --- /dev/null +++ b/src/core/engine_global.c @@ -0,0 +1,13 @@ +#include "engine_global.h" + +static Scene *main_scene = NULL; + +Scene *GetMainScene() { + return main_scene; +} + +void SwitchScene(Scene *scene) { + if(main_scene != NULL) + DestroyScene(main_scene); + main_scene = scene; +} diff --git a/src/core/engine_global.h b/src/core/engine_global.h new file mode 100644 index 0000000..bd6e023 --- /dev/null +++ b/src/core/engine_global.h @@ -0,0 +1,9 @@ +#ifndef ENGINE_GLOBAL_H +#define ENGINE_GLOBAL_H + +#include "scene.h" + +extern Scene *GetMainScene(); +extern void SwitchScene(Scene *new_scene); + +#endif // !ENGINE_GLOBAL_H diff --git a/src/core/engine_loop.c b/src/core/engine_loop.c index 930cf6e..e875f48 100644 --- a/src/core/engine_loop.c +++ b/src/core/engine_loop.c @@ -1,6 +1,8 @@ #include "engine_loop.h" -#include "resources.h" +#include "engine_global.h" #include "render.h" +#include "resources.h" +#include "utils/debug.h" #include "stdlib.h" #include "raylib.h" @@ -13,11 +15,15 @@ void InitializeRaylibContext() { ToggleFullscreen(); } -void RunGame() { +void RunGame(Scene *initial_scene) { + SwitchScene(initial_scene); + ASSERT_RETURN(GetMainScene() != NULL,, "RunGame: Initial scene cannot be NULL."); while (!WindowShouldClose()) { + SceneTick(GetMainScene(), 1.0); RenderNextFrame(); } ShutDown(); + UNREACHABLE("RunGame: Reached beyond ShutDown call"); } void InitializeEngine() { diff --git a/src/core/engine_loop.h b/src/core/engine_loop.h index 5159d8a..8edfc3c 100644 --- a/src/core/engine_loop.h +++ b/src/core/engine_loop.h @@ -1,4 +1,7 @@ -#pragma once +#ifndef ENGINE_LOOP_H +#define ENGINE_LOOP_H + +typedef struct Scene Scene; typedef struct GameContext { } GameContext; @@ -9,6 +12,8 @@ extern void InitializeGame(GameContext *settings); //! initialize window and application context extern void InitializeEngine(); //! run the actual game, requires InitializeEngine to be called first -extern void RunGame(); +extern void RunGame(Scene *initial_scene); // shut down game entirely extern void ShutDown(); + +#endif // !ENGINE_LOOP_H diff --git a/src/core/render.c b/src/core/render.c index b06b1bc..8e86d06 100644 --- a/src/core/render.c +++ b/src/core/render.c @@ -1,9 +1,10 @@ #include "render.h" +#include "engine_global.h" +#include "scene.h" #include "utils/debug.h" #include "utils/list.h" static List g_render_objects = {}; //!< List of all registered rendering objects -CameraNode *camera = NULL; //!< Reference to current main camera void InitializeRenderingSubsystem() { g_render_objects = list_from_type(Renderable); @@ -26,10 +27,17 @@ void RemoveRenderable(Renderable renderable) { void RenderNextFrame() { BeginDrawing(); - ClearBackground(BLACK); - BeginMode3D(CameraNodeGetCamera(camera)); - list_foreach(Renderable *,object, &g_render_objects) - object->tc->draw(object->data); - EndMode3D(); + ClearBackground(DARKGRAY); + CameraNode *camera = GetMainScene()->main_camera; + if(camera != NULL) { // can't draw anything if there is no camera + BeginMode3D(CameraNodeGetCamera(camera)); + list_foreach(Renderable *,object, &g_render_objects) + object->tc->draw(object->data); + DrawGrid(100, 1.f); + EndMode3D(); + } else { + UNREACHABLE("RenderNextFrame: camera not found."); + } + DrawFPS(20, 20); EndDrawing(); } diff --git a/src/core/render.h b/src/core/render.h index 5ca062c..edeba5b 100644 --- a/src/core/render.h +++ b/src/core/render.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef RENDER_H +#define RENDER_H #include "camera_node.h" #include "renderable.h" @@ -22,3 +23,5 @@ extern void GetMainCamera(CameraNode *camera); //! Draw a frame to the screen based on the current state of the game. extern void RenderNextFrame(); + +#endif // !RENDER_H diff --git a/src/core/renderable.h b/src/core/renderable.h index f458001..723a778 100644 --- a/src/core/renderable.h +++ b/src/core/renderable.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef RENDERABLE_H +#define RENDERABLE_H #include "scene_node_entity.h" #include "utils/typeclass_helpers.h" @@ -21,3 +22,5 @@ Renderable T##_as_Renderable(T *x) {\ };\ return (Renderable){ .tc = &tc, .data = x, .scene_node_entity = T##_as_SceneNodeEntity(x).tc };\ } + +#endif // !RENDERABLE_H diff --git a/src/core/resources.h b/src/core/resources.h index bfe1866..f5848fc 100644 --- a/src/core/resources.h +++ b/src/core/resources.h @@ -1,4 +1,5 @@ -#pragma once +#ifndef RESOURCES_H +#define RESOURCES_H #include "raylib.h" @@ -9,3 +10,5 @@ extern void CleanResourceSubsystem(); extern Model *ResourcesLoadModel(char const *res_path); //! Load a texture resource from disk, path is relative to the resource folder extern Texture *ResourcesLoadTexture(char const *res_path); + +#endif // !RESOURCES_H diff --git a/src/core/scene.c b/src/core/scene.c index 5e37e2d..8c2a050 100644 --- a/src/core/scene.c +++ b/src/core/scene.c @@ -1,54 +1,88 @@ #include "scene.h" #include "scene_node_entity.h" #include "utils/debug.h" -#include "utils/list.h" #include "utils/drop.h" #include "utils/mirror.h" -struct SceneNode { - SceneNode *parent; - Scene *scene; - List children; //!< list of child SceneNodes - SceneNodeEntity entity; //!< scene node entity that adds functionality to the node -}; - -struct Scene { - SceneNode *root; - List nodes; -}; - +//! Remove a single node (does NOT recurse to children children) from this scene. static void Internal_SceneRemoveNode(Scene *self, SceneNode *node) { - size_t idx = list_find(&self->nodes, node); + // notify the node entity that it has exited the tree + node->entity.tc->exit_tree(node->entity.data); + // sever relationship + node->scene = NULL; + size_t idx = list_find(&self->nodes, &node); list_erase(&self->nodes, idx); } +//! Remove a node and all children from this scene recursively starting at the bottom of the tree. static -void Internal_SceneAddNode(Scene *self, SceneNode node) { - ASSERT_RETURN(list_find(&self->nodes, &node) == self->nodes.len,, "Attempting to add node that is already in this scene"); - ASSERT_RETURN(node.scene != NULL,, "Attempting to add node that is already in a scene, remove it from that scene first"); - list_add(&self->nodes, &node); +void Internal_SceneRemoveNodeRecursive(Scene *self, SceneNode *node) { + // recurse to node's children first + list_foreach(SceneNode **,child, &node->children) + Internal_SceneRemoveNodeRecursive(self, *child); + // remove node + Internal_SceneRemoveNode(self, node); } -SceneNode *CreateSceneNode() { - SceneNode *node = new(SceneNode); - ASSERT_RETURN(node != NULL, NULL, "CreateSceneNode: Failed to instantiate new SceneNode"); - node->children = list_from_type(SceneNode*); - return node; +//! Set the scene on a node (does NOT recurse to children), calls enter_tree +static +void Internal_SceneNodeSetScene(SceneNode *self, Scene *scene) { + ASSERT_RETURN(scene != NULL,, "Internal_SceneNodeSetScene: Attempting to set node scene to NULL. Use Internal_SceneRemoveNodeRercursive instead."); + self->scene = scene; + self->entity.tc->enter_tree(self->entity.data); +} + +//! Register a node and it's children as part of a scene recursively. +//! Will call enter_tree on all node entities +static +void Internal_SceneAddNode(Scene *self, SceneNode *node) { + ASSERT_RETURN(node->scene == NULL,, "Attempting to add node that is already in a scene, remove it from that scene first"); + ASSERT_RETURN(list_find(&self->nodes, &node) == self->nodes.len,, "Attempting to add node that is already in this scene"); + // add to internal list + list_add(&self->nodes, &node); + // establish two-way relationship + Internal_SceneNodeSetScene(node, self); + // do the same for all children (and their children) recursively + list_foreach(SceneNode **,child, &node->children) + Internal_SceneAddNode(self, *child); +} + +//! Tick a node and all children recursively +static +void Internal_SceneNodeTick(SceneNode *self, double delta) { + // tick self first + self->entity.tc->tick(self->entity.data, delta); + // fix the number of elements to update now, + // so that if/when new children are added, they don't get ticked until next frame + size_t const len = self->children.len; + for(size_t i = 0; i < len; ++i) + Internal_SceneNodeTick(*list_at_as(SceneNode*, &self->children, i), delta); +} + +SceneNode *CreateSceneNode(SceneNodeEntity entity) { + // initialize memory + SceneNode *self = new(SceneNode); + ASSERT_RETURN(self != NULL, NULL, "CreateSceneNode: Failed to allocate new SceneNode"); + self->children = list_from_type(SceneNode*); + self->entity = tc_null(SceneNodeEntity); + self->parent = NULL; + self->scene = NULL; + // attach initial entity + SceneNodeAttachEntity(self, entity); + return self; } void DestroySceneNode(SceneNode *self) { - // remove all children from scene as well + // destroy children *first*, then delete self list_foreach(SceneNode **, child, &self->children) DestroySceneNode(*child); - // inform entity of exit tree event - self->entity.tc->exit_tree(self->entity.data); // remove node from scene if it is part of one if(self->scene != NULL) Internal_SceneRemoveNode(self->scene, self); - if(self->entity.data != NULL) { + // destroy entity as well + if(!tc_is_null(self->entity)) self->entity.drop->drop(self->entity.data); - } free(self); } @@ -58,14 +92,13 @@ SceneNode *SceneNodeGetChild(SceneNode *self, size_t idx) { void SceneNodeAddChild(SceneNode *self, SceneNode *child) { // catch logic error of trying to attach a child that already has a parent - ASSERT_RETURN(child->parent != NULL,, "SceneNodeAddChild: New child node already has a parent"); + ASSERT_RETURN(child->parent == NULL,, "SceneNodeAddChild: New child node already has a parent"); // register parent-child relationship list_add(&self->children, &child); child->parent = self; - // make sure scene matches - child->scene = self->scene; - // notify child of scene entrance - child->entity.tc->enter_tree(child->entity.data); + // add child to same scene as self + if(self->scene != NULL) + Internal_SceneAddNode(self->scene, child); } void SceneNodeRemoveChild(SceneNode *self, SceneNode *child) { @@ -74,25 +107,49 @@ void SceneNodeRemoveChild(SceneNode *self, SceneNode *child) { // get the index and use it to ensure that the child is actually registered with the parent size_t const idx = list_find(&self->children, child); ASSERT_RETURN(idx == self->children.len,, "IMPORTANT: SceneNodeRemoveChild: child is not registered with parent."); - // we now know that the child is actually a child of self. - // notify child that it is being removed from the tree. - child->entity.tc->exit_tree(child->entity.data); + if(self->scene != NULL) { + Internal_SceneRemoveNodeRecursive(child->scene, child); + } // use the index to erase the object from the list list_erase(&self->children, idx); - Internal_SceneRemoveNode(child->scene, child); - child->scene = NULL; - } -void Internal_SceneNodeAttachEntity(SceneNodeEntity object) { - object.tc->get_node(object.data)->entity = object; +void SceneNodeAttachEntity(SceneNode *self, SceneNodeEntity entity) { + ASSERT_RETURN_WARN(!tc_is_null(entity),, "SceneNodeAttachEntity: Cannot attach null entity, use SceneNodeDetachEntity to remove entity instead."); + // establish two-way relationship + entity.tc->set_node(entity.data, self); + self->entity = entity; + // if this node is in a tree, notify the entity that it has entered one. + if(self->scene != NULL) + self->entity.tc->enter_tree(self->entity.data); } +SceneNodeEntity SceneNodeDetachEntity(SceneNode *self) { + ASSERT_RETURN_WARN(!tc_is_null(self->entity), tc_null(SceneNodeEntity), "SceneNodeDetachEntity: Cannot detach entity from node with no entity."); + // store the entity to return it. + SceneNodeEntity e = self->entity; + // null entity <-> node relationship + e.tc->set_node(e.data, NULL); + self->entity = tc_null(SceneNodeEntity); + return e; +} -Scene *CreateScene(SceneNode const *root) { +Scene *CreateScene(SceneNode *root) { Scene *scene = new(Scene); - scene->nodes = list_from_type(SceneNode); - Internal_SceneAddNode(scene, *root); - root->entity.tc->enter_tree(root->entity.data); + ASSERT_RETURN(scene != NULL, NULL, "CreateScene: Failed to allocate scene"); + scene->main_camera = NULL; + scene->nodes = list_from_type(SceneNode*); + scene->root = root; + Internal_SceneAddNode(scene, root); return scene; } + +void DestroyScene(Scene *self) { + DestroySceneNode(self->root); + list_empty(&self->nodes); + free(self); +} + +void SceneTick(Scene* self, double delta_time) { + Internal_SceneNodeTick(self->root, delta_time); +} diff --git a/src/core/scene.h b/src/core/scene.h index 9f60899..60d7b25 100644 --- a/src/core/scene.h +++ b/src/core/scene.h @@ -1,15 +1,32 @@ -#pragma once +#ifndef SCENE_H +#define SCENE_H #include "stddef.h" +#include "scene_node_entity.h" +#include "utils/list.h" #include "utils/typeclass_helpers.h" typedef struct SceneNodeEntity SceneNodeEntity; +typedef struct CameraNode CameraNode; -typedef struct SceneNode SceneNode; typedef struct Scene Scene; +typedef struct SceneNode SceneNode; + +struct SceneNode { + SceneNode *parent; //!< The parent of this node in a scene hierarchy, or NULL if this is the root node. + Scene *scene; //!< The scene this node is a part of + List children; //!< list of child SceneNodes + SceneNodeEntity entity; //!< scene node entity that defines the functionality for this node. HAS TO be defined before adding to a scene. +}; + +struct Scene { + SceneNode *root; //!< The root node of this scene. + List nodes; //!< An unordered list of all nodes in the hierarchy. + CameraNode *main_camera; //!< The current main camera node +}; //! Instantiate a new scene node. -extern SceneNode *CreateSceneNode(); -//! Free a scene node. +extern SceneNode *CreateSceneNode(SceneNodeEntity entity); +//! Recursively destroy a scene node and all children, starting from the bottom. extern void DestroySceneNode(SceneNode *self); //! Get a child from a scene node. extern SceneNode *SceneNodeGetChild(SceneNode *self, size_t idx); @@ -18,10 +35,16 @@ extern void SceneNodeAddChild(SceneNode *self, SceneNode *child); //! Detach a child from a node, removing it from the scene extern void SceneNodeRemoveChild(SceneNode *self, SceneNode *child); -//! INTERNAL FUNCTION, used to attach a scene node entity typeclass to an object. -extern void Internal_SceneNodeAttachEntity(SceneNodeEntity object); +//! Attach an entity to a scene node +extern void SceneNodeAttachEntity(SceneNode *self, SceneNodeEntity entity); +//! Detach an entity from a scene node +extern SceneNodeEntity SceneNodeDetachEntity(SceneNode *self); //! Instantiate a new scene with a root node. -extern Scene *CreateScene(SceneNode const *root); +extern Scene *CreateScene(SceneNode *root); //! Destroy a node and it's scene tree. -extern void DestroyScene(Scene *scene); +extern void DestroyScene(Scene *self); +//! Tick a scene and all entities +extern void SceneTick(Scene *self, double delta_time); + +#endif // !SCENE_H diff --git a/src/core/scene_node_entity.h b/src/core/scene_node_entity.h index 512cbe6..d7f2808 100644 --- a/src/core/scene_node_entity.h +++ b/src/core/scene_node_entity.h @@ -1,6 +1,6 @@ -#pragma once +#ifndef SCENE_NODE_ENTITY_H +#define SCENE_NODE_ENTITY_H -#include "scene.h" #include "utils/mirror.h" #include "utils/drop.h" @@ -21,6 +21,11 @@ typedef struct SceneNodeEntity { IDrop const *drop; } SceneNodeEntity; +#define impl_SceneNodeEntity_defaults(T)\ +static void T##_default_enter_tree(T *self) {}\ +static void T##_default_exit_tree(T *self) {}\ +static void T##_default_tick(T *self, double delta) {} + //! Implement SceneNodeEntity for a struct. //! IMPORTANT: requires Mirror and Drop to be implemented, //! as well as a `SceneNode *node` member on T. @@ -28,7 +33,7 @@ typedef struct SceneNodeEntity { #define impl_SceneNodeEntity_for(T, enter_tree_f, exit_tree_f, tick_f)\ static struct SceneNode *T##_get_node_GEN_(T *self) { return self->node; }\ static void T##_set_node_GEN_(T *self, struct SceneNode *node) { self->node = node; }\ -SceneNodeEntity T##AttachToSceneNode(T* x, SceneNode *node) {\ +SceneNodeEntity T##_as_SceneNodeEntity(T *x) {\ TC_FN_TYPECHECK(void, enter_tree_f, T*);\ TC_FN_TYPECHECK(void, exit_tree_f, T*);\ TC_FN_TYPECHECK(void, tick_f, T*, double);\ @@ -39,9 +44,8 @@ SceneNodeEntity T##AttachToSceneNode(T* x, SceneNode *node) {\ .get_node = (struct SceneNode *(*const)(void*)) T##_get_node_GEN_,\ .set_node = (void (*const)(void*, struct SceneNode*)) T##_set_node_GEN_\ };\ - Internal_AttachToSceneNode(object);\ - x->node = node;\ SceneNodeEntity e = { .tc = &tc, .data = x, .mirror = T##_as_Mirror(x).tc, .drop = T##_as_Drop(x).tc };\ - Internal_SceneNodeAttachEntity(e);\ return e;\ } + +#endif // !SCENE_NODE_ENTITY_H diff --git a/src/core/transform_node.c b/src/core/transform_node.c new file mode 100644 index 0000000..24cce1f --- /dev/null +++ b/src/core/transform_node.c @@ -0,0 +1,41 @@ +#include "transform_node.h" +#include "utils/typeclass_helpers.h" + +START_REFLECT(TransformNode); +REFLECT_TYPECLASS(TransformNode, SceneNodeEntity); +REFLECT_TYPECLASS(TransformNode, Transformable); +REFLECT_TYPECLASS(TransformNode, Drop); +END_REFLECT(TransformNode); + +impl_Drop_for(TransformNode, + DestroyTransformNode +) +impl_Transformable_for(TransformNode, + TransformNodeGetTransform, + TransformNodeGetGlobalTransform +) +impl_SceneNodeEntity_defaults(TransformNode); +impl_SceneNodeEntity_for(TransformNode, + TransformNode_default_enter_tree, + TransformNode_default_exit_tree, + TransformNode_default_tick +) + +SceneNode *CreateTransformNode() { + TransformNode *self = new(TransformNode); + self->global_transform = TransformIdentity(); + self->transform = TransformIdentity(); + return CreateSceneNode(TransformNode_as_SceneNodeEntity(self)); +} + +void DestroyTransformNode(TransformNode *self) { + free(self); +} + +Transform *TransformNodeGetTransform(TransformNode *self) { + return &self->transform; +} + +Transform *TransformNodeGetGlobalTransform(TransformNode *self) { + return &self->global_transform; +} diff --git a/src/core/transform_node.h b/src/core/transform_node.h new file mode 100644 index 0000000..80382c0 --- /dev/null +++ b/src/core/transform_node.h @@ -0,0 +1,27 @@ +#ifndef TRANSFORM_NODE_H +#define TRANSFORM_NODE_H + +#include "transformable.h" +#include "raylib.h" +#include "transformable.h" +#include "scene_node_entity.h" +#include "utils/drop.h" + +typedef struct TransformNode { + SceneNode *node; + Transform transform; + Transform global_transform; +} TransformNode; + +extern SceneNode *CreateTransformNode(); +extern void DestroyTransformNode(TransformNode *self); + +extern Transform *TransformNodeGetTransform(TransformNode *self); +extern Transform *TransformNodeGetGlobalTransform(TransformNode *self); + +DECL_REFLECT(TransformNode); +decl_typeclass_impl(Transformable, TransformNode); +decl_typeclass_impl(Drop, TransformNode); +decl_typeclass_impl(SceneNodeEntity, TransformNode); + +#endif // !TRANSFORM_NODE_H diff --git a/src/core/transformable.c b/src/core/transformable.c index 536db0d..a004da7 100644 --- a/src/core/transformable.c +++ b/src/core/transformable.c @@ -1,5 +1,14 @@ #include "transformable.h" +Transform TransformIdentity() { + return (Transform){ + .translation = { 0.f, 0.f, 0.f }, + .rotation = QuaternionIdentity(), + .scale = { 1.f, 1.f, 1.f } + }; +} + + Matrix TransformGetMatrix(Transform const *self) { Matrix mat = MatrixScale(self->scale.x, self->scale.y, self->scale.z); mat = MatrixMultiply(mat, QuaternionToMatrix(self->rotation)); diff --git a/src/core/transformable.h b/src/core/transformable.h index e8ef415..dfea8ad 100644 --- a/src/core/transformable.h +++ b/src/core/transformable.h @@ -1,11 +1,14 @@ -#pragma once +#ifndef TRANSFORMABLE_H +#define TRANSFORMABLE_H +#include "scene.h" #include "utils/mirror.h" #include "utils/typeclass_helpers.h" #include "raylib.h" #include "raymath.h" typedef struct ITransformable { + SceneNode *node; Transform *(*const get_transform)(void*); Transform *(*const get_global_transform)(void*); } ITransformable; @@ -16,16 +19,19 @@ typedef struct Transformable { IMirror const *mirror; } Transformable; +extern Transform TransformIdentity(); extern Matrix TransformGetMatrix(Transform const *self); extern void UpdateTransformable(Transformable *self, Transformable *parent); -#define impl_Transformable_for(T, get_transform_f)\ +#define impl_Transformable_for(T, get_transform_f, get_global_transform_f)\ Transformable T##_as_Transformable(T *x) {\ - TC_FN_TYPECHECK(Transform, get_transform_f, T*);\ + TC_FN_TYPECHECK(Transform *,get_transform_f, T*);\ + TC_FN_TYPECHECK(Transform *,get_global_transform_f, T*);\ static ITransformable const tc = {\ .get_transform = (Transform *(*const)(void*)) get_transform_f,\ .get_global_transform = (Transform *(*const)(void*)) get_global_transform_f\ };\ - return { .tc = &tc, data = x, .mirror = T##_as_Mirror(x).tc };\ + return (Transformable){ .tc = &tc, .data = x, .mirror = T##_as_Mirror(x).tc };\ } +#endif // !TRANSFORMABLE_H diff --git a/src/main.c b/src/main.c index 216a594..d1566cf 100644 --- a/src/main.c +++ b/src/main.c @@ -1,9 +1,24 @@ #include "raylib.h" +#include "core/camera_node.h" +#include "core/engine_global.h" #include "core/engine_loop.h" +#include "core/scene.h" +#include "core/transform_node.h" #include "utils/debug.h" +Scene *CreateInitialScene() { + SceneNode *root = CreateTransformNode(); + SceneNode *camera_node = CreateCameraNode(); + Transformable camera = TC_CAST(camera_node->entity, Transformable); + Transform *camera_global = camera.tc->get_global_transform(camera.data); + camera_global->translation = (Vector3){0.f, 10.f, -10.f}; + camera_global->rotation = QuaternionFromEuler(45.f * DEG2RAD, 0.f, 0.f); + SceneNodeAddChild(root, camera_node); + return CreateScene(root); +} + int main() { InitializeEngine(); - RunGame(); + RunGame(CreateInitialScene()); UNREACHABLE("End of main function reached. This is an error, call ShutDown() when exiting instead."); }