feat: scene now renders and ticks

This commit is contained in:
Sara 2024-09-12 14:03:22 +02:00
parent ce130a7983
commit 7df5bd8e1e
18 changed files with 388 additions and 84 deletions

59
src/core/camera_node.c Normal file
View file

@ -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; }

View file

@ -1,18 +1,31 @@
#pragma once #ifndef CAMERA_NODE_H
#define CAMERA_NODE_H
#include "scene.h"
#include "scene_node_entity.h" #include "scene_node_entity.h"
#include "transformable.h"
#include "utils/drop.h" #include "utils/drop.h"
#include "raylib.h" #include "raylib.h"
typedef struct CameraNode { typedef struct CameraNode {
SceneNode *node; SceneNode *node;
Transform transform;
Transform global_transform;
} CameraNode; } CameraNode;
void CameraNodeEnterTree(CameraNode *self); extern SceneNode *CreateCameraNode();
void CameraNodeExitTree(CameraNode *self); extern void DestroyCameraNode(CameraNode *self);
void CameraNodeTick(CameraNode *self, double delta);
Camera3D CameraNodeGetCamera(CameraNode *self);
impl_default_Drop_for(CameraNode); extern void CameraNodeEnterTree(CameraNode *self);
impl_SceneNodeEntity_for(CameraNode, CameraNodeEnterTree, CameraNodeExitTree, CameraNodeTick);
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

13
src/core/engine_global.c Normal file
View file

@ -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;
}

9
src/core/engine_global.h Normal file
View file

@ -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

View file

@ -1,6 +1,8 @@
#include "engine_loop.h" #include "engine_loop.h"
#include "resources.h" #include "engine_global.h"
#include "render.h" #include "render.h"
#include "resources.h"
#include "utils/debug.h"
#include "stdlib.h" #include "stdlib.h"
#include "raylib.h" #include "raylib.h"
@ -13,11 +15,15 @@ void InitializeRaylibContext() {
ToggleFullscreen(); ToggleFullscreen();
} }
void RunGame() { void RunGame(Scene *initial_scene) {
SwitchScene(initial_scene);
ASSERT_RETURN(GetMainScene() != NULL,, "RunGame: Initial scene cannot be NULL.");
while (!WindowShouldClose()) { while (!WindowShouldClose()) {
SceneTick(GetMainScene(), 1.0);
RenderNextFrame(); RenderNextFrame();
} }
ShutDown(); ShutDown();
UNREACHABLE("RunGame: Reached beyond ShutDown call");
} }
void InitializeEngine() { void InitializeEngine() {

View file

@ -1,4 +1,7 @@
#pragma once #ifndef ENGINE_LOOP_H
#define ENGINE_LOOP_H
typedef struct Scene Scene;
typedef struct GameContext { typedef struct GameContext {
} GameContext; } GameContext;
@ -9,6 +12,8 @@ extern void InitializeGame(GameContext *settings);
//! initialize window and application context //! initialize window and application context
extern void InitializeEngine(); extern void InitializeEngine();
//! run the actual game, requires InitializeEngine to be called first //! run the actual game, requires InitializeEngine to be called first
extern void RunGame(); extern void RunGame(Scene *initial_scene);
// shut down game entirely // shut down game entirely
extern void ShutDown(); extern void ShutDown();
#endif // !ENGINE_LOOP_H

View file

@ -1,9 +1,10 @@
#include "render.h" #include "render.h"
#include "engine_global.h"
#include "scene.h"
#include "utils/debug.h" #include "utils/debug.h"
#include "utils/list.h" #include "utils/list.h"
static List g_render_objects = {}; //!< List of all registered rendering objects static List g_render_objects = {}; //!< List of all registered rendering objects
CameraNode *camera = NULL; //!< Reference to current main camera
void InitializeRenderingSubsystem() { void InitializeRenderingSubsystem() {
g_render_objects = list_from_type(Renderable); g_render_objects = list_from_type(Renderable);
@ -26,10 +27,17 @@ void RemoveRenderable(Renderable renderable) {
void RenderNextFrame() { void RenderNextFrame() {
BeginDrawing(); BeginDrawing();
ClearBackground(BLACK); ClearBackground(DARKGRAY);
BeginMode3D(CameraNodeGetCamera(camera)); CameraNode *camera = GetMainScene()->main_camera;
list_foreach(Renderable *,object, &g_render_objects) if(camera != NULL) { // can't draw anything if there is no camera
object->tc->draw(object->data); BeginMode3D(CameraNodeGetCamera(camera));
EndMode3D(); 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(); EndDrawing();
} }

View file

@ -1,4 +1,5 @@
#pragma once #ifndef RENDER_H
#define RENDER_H
#include "camera_node.h" #include "camera_node.h"
#include "renderable.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. //! Draw a frame to the screen based on the current state of the game.
extern void RenderNextFrame(); extern void RenderNextFrame();
#endif // !RENDER_H

View file

@ -1,4 +1,5 @@
#pragma once #ifndef RENDERABLE_H
#define RENDERABLE_H
#include "scene_node_entity.h" #include "scene_node_entity.h"
#include "utils/typeclass_helpers.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 };\ return (Renderable){ .tc = &tc, .data = x, .scene_node_entity = T##_as_SceneNodeEntity(x).tc };\
} }
#endif // !RENDERABLE_H

View file

@ -1,4 +1,5 @@
#pragma once #ifndef RESOURCES_H
#define RESOURCES_H
#include "raylib.h" #include "raylib.h"
@ -9,3 +10,5 @@ extern void CleanResourceSubsystem();
extern Model *ResourcesLoadModel(char const *res_path); extern Model *ResourcesLoadModel(char const *res_path);
//! Load a texture resource from disk, path is relative to the resource folder //! Load a texture resource from disk, path is relative to the resource folder
extern Texture *ResourcesLoadTexture(char const *res_path); extern Texture *ResourcesLoadTexture(char const *res_path);
#endif // !RESOURCES_H

View file

@ -1,54 +1,88 @@
#include "scene.h" #include "scene.h"
#include "scene_node_entity.h" #include "scene_node_entity.h"
#include "utils/debug.h" #include "utils/debug.h"
#include "utils/list.h"
#include "utils/drop.h" #include "utils/drop.h"
#include "utils/mirror.h" #include "utils/mirror.h"
struct SceneNode { //! Remove a single node (does NOT recurse to children children) from this scene.
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;
};
static static
void Internal_SceneRemoveNode(Scene *self, SceneNode *node) { 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); list_erase(&self->nodes, idx);
} }
//! Remove a node and all children from this scene recursively starting at the bottom of the tree.
static static
void Internal_SceneAddNode(Scene *self, SceneNode node) { void Internal_SceneRemoveNodeRecursive(Scene *self, SceneNode *node) {
ASSERT_RETURN(list_find(&self->nodes, &node) == self->nodes.len,, "Attempting to add node that is already in this scene"); // recurse to node's children first
ASSERT_RETURN(node.scene != NULL,, "Attempting to add node that is already in a scene, remove it from that scene first"); list_foreach(SceneNode **,child, &node->children)
list_add(&self->nodes, &node); Internal_SceneRemoveNodeRecursive(self, *child);
// remove node
Internal_SceneRemoveNode(self, node);
} }
SceneNode *CreateSceneNode() { //! Set the scene on a node (does NOT recurse to children), calls enter_tree
SceneNode *node = new(SceneNode); static
ASSERT_RETURN(node != NULL, NULL, "CreateSceneNode: Failed to instantiate new SceneNode"); void Internal_SceneNodeSetScene(SceneNode *self, Scene *scene) {
node->children = list_from_type(SceneNode*); ASSERT_RETURN(scene != NULL,, "Internal_SceneNodeSetScene: Attempting to set node scene to NULL. Use Internal_SceneRemoveNodeRercursive instead.");
return node; 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) { void DestroySceneNode(SceneNode *self) {
// remove all children from scene as well // destroy children *first*, then delete self
list_foreach(SceneNode **, child, &self->children) list_foreach(SceneNode **, child, &self->children)
DestroySceneNode(*child); 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 // remove node from scene if it is part of one
if(self->scene != NULL) if(self->scene != NULL)
Internal_SceneRemoveNode(self->scene, self); 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); self->entity.drop->drop(self->entity.data);
}
free(self); free(self);
} }
@ -58,14 +92,13 @@ SceneNode *SceneNodeGetChild(SceneNode *self, size_t idx) {
void SceneNodeAddChild(SceneNode *self, SceneNode *child) { void SceneNodeAddChild(SceneNode *self, SceneNode *child) {
// catch logic error of trying to attach a child that already has a parent // 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 // register parent-child relationship
list_add(&self->children, &child); list_add(&self->children, &child);
child->parent = self; child->parent = self;
// make sure scene matches // add child to same scene as self
child->scene = self->scene; if(self->scene != NULL)
// notify child of scene entrance Internal_SceneAddNode(self->scene, child);
child->entity.tc->enter_tree(child->entity.data);
} }
void SceneNodeRemoveChild(SceneNode *self, SceneNode *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 // 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); size_t const idx = list_find(&self->children, child);
ASSERT_RETURN(idx == self->children.len,, "IMPORTANT: SceneNodeRemoveChild: child is not registered with parent."); 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. if(self->scene != NULL) {
// notify child that it is being removed from the tree. Internal_SceneRemoveNodeRecursive(child->scene, child);
child->entity.tc->exit_tree(child->entity.data); }
// use the index to erase the object from the list // use the index to erase the object from the list
list_erase(&self->children, idx); list_erase(&self->children, idx);
Internal_SceneRemoveNode(child->scene, child);
child->scene = NULL;
} }
void Internal_SceneNodeAttachEntity(SceneNodeEntity object) { void SceneNodeAttachEntity(SceneNode *self, SceneNodeEntity entity) {
object.tc->get_node(object.data)->entity = object; 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 *scene = new(Scene);
scene->nodes = list_from_type(SceneNode); ASSERT_RETURN(scene != NULL, NULL, "CreateScene: Failed to allocate scene");
Internal_SceneAddNode(scene, *root); scene->main_camera = NULL;
root->entity.tc->enter_tree(root->entity.data); scene->nodes = list_from_type(SceneNode*);
scene->root = root;
Internal_SceneAddNode(scene, root);
return scene; 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);
}

View file

@ -1,15 +1,32 @@
#pragma once #ifndef SCENE_H
#define SCENE_H
#include "stddef.h" #include "stddef.h"
#include "scene_node_entity.h"
#include "utils/list.h"
#include "utils/typeclass_helpers.h" #include "utils/typeclass_helpers.h"
typedef struct SceneNodeEntity SceneNodeEntity; typedef struct SceneNodeEntity SceneNodeEntity;
typedef struct CameraNode CameraNode;
typedef struct SceneNode SceneNode;
typedef struct Scene Scene; 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. //! Instantiate a new scene node.
extern SceneNode *CreateSceneNode(); extern SceneNode *CreateSceneNode(SceneNodeEntity entity);
//! Free a scene node. //! Recursively destroy a scene node and all children, starting from the bottom.
extern void DestroySceneNode(SceneNode *self); extern void DestroySceneNode(SceneNode *self);
//! Get a child from a scene node. //! Get a child from a scene node.
extern SceneNode *SceneNodeGetChild(SceneNode *self, size_t idx); 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 //! Detach a child from a node, removing it from the scene
extern void SceneNodeRemoveChild(SceneNode *self, SceneNode *child); extern void SceneNodeRemoveChild(SceneNode *self, SceneNode *child);
//! INTERNAL FUNCTION, used to attach a scene node entity typeclass to an object. //! Attach an entity to a scene node
extern void Internal_SceneNodeAttachEntity(SceneNodeEntity object); 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. //! 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. //! 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

View file

@ -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/mirror.h"
#include "utils/drop.h" #include "utils/drop.h"
@ -21,6 +21,11 @@ typedef struct SceneNodeEntity {
IDrop const *drop; IDrop const *drop;
} SceneNodeEntity; } 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. //! Implement SceneNodeEntity for a struct.
//! IMPORTANT: requires Mirror and Drop to be implemented, //! IMPORTANT: requires Mirror and Drop to be implemented,
//! as well as a `SceneNode *node` member on T. //! 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)\ #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 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; }\ 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, enter_tree_f, T*);\
TC_FN_TYPECHECK(void, exit_tree_f, T*);\ TC_FN_TYPECHECK(void, exit_tree_f, T*);\
TC_FN_TYPECHECK(void, tick_f, T*, double);\ 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_,\ .get_node = (struct SceneNode *(*const)(void*)) T##_get_node_GEN_,\
.set_node = (void (*const)(void*, struct SceneNode*)) T##_set_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 };\ SceneNodeEntity e = { .tc = &tc, .data = x, .mirror = T##_as_Mirror(x).tc, .drop = T##_as_Drop(x).tc };\
Internal_SceneNodeAttachEntity(e);\
return e;\ return e;\
} }
#endif // !SCENE_NODE_ENTITY_H

41
src/core/transform_node.c Normal file
View file

@ -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;
}

27
src/core/transform_node.h Normal file
View file

@ -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

View file

@ -1,5 +1,14 @@
#include "transformable.h" #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 TransformGetMatrix(Transform const *self) {
Matrix mat = MatrixScale(self->scale.x, self->scale.y, self->scale.z); Matrix mat = MatrixScale(self->scale.x, self->scale.y, self->scale.z);
mat = MatrixMultiply(mat, QuaternionToMatrix(self->rotation)); mat = MatrixMultiply(mat, QuaternionToMatrix(self->rotation));

View file

@ -1,11 +1,14 @@
#pragma once #ifndef TRANSFORMABLE_H
#define TRANSFORMABLE_H
#include "scene.h"
#include "utils/mirror.h" #include "utils/mirror.h"
#include "utils/typeclass_helpers.h" #include "utils/typeclass_helpers.h"
#include "raylib.h" #include "raylib.h"
#include "raymath.h" #include "raymath.h"
typedef struct ITransformable { typedef struct ITransformable {
SceneNode *node;
Transform *(*const get_transform)(void*); Transform *(*const get_transform)(void*);
Transform *(*const get_global_transform)(void*); Transform *(*const get_global_transform)(void*);
} ITransformable; } ITransformable;
@ -16,16 +19,19 @@ typedef struct Transformable {
IMirror const *mirror; IMirror const *mirror;
} Transformable; } Transformable;
extern Transform TransformIdentity();
extern Matrix TransformGetMatrix(Transform const *self); extern Matrix TransformGetMatrix(Transform const *self);
extern void UpdateTransformable(Transformable *self, Transformable *parent); 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) {\ 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 = {\ static ITransformable const tc = {\
.get_transform = (Transform *(*const)(void*)) get_transform_f,\ .get_transform = (Transform *(*const)(void*)) get_transform_f,\
.get_global_transform = (Transform *(*const)(void*)) get_global_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

View file

@ -1,9 +1,24 @@
#include "raylib.h" #include "raylib.h"
#include "core/camera_node.h"
#include "core/engine_global.h"
#include "core/engine_loop.h" #include "core/engine_loop.h"
#include "core/scene.h"
#include "core/transform_node.h"
#include "utils/debug.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() { int main() {
InitializeEngine(); InitializeEngine();
RunGame(); RunGame(CreateInitialScene());
UNREACHABLE("End of main function reached. This is an error, call ShutDown() when exiting instead."); UNREACHABLE("End of main function reached. This is an error, call ShutDown() when exiting instead.");
} }