feat: scene now renders and ticks
This commit is contained in:
parent
ce130a7983
commit
7df5bd8e1e
59
src/core/camera_node.c
Normal file
59
src/core/camera_node.c
Normal 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; }
|
|
@ -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
13
src/core/engine_global.c
Normal 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
9
src/core/engine_global.h
Normal 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
|
|
@ -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() {
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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();
|
||||||
}
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
|
||||||
|
|
147
src/core/scene.c
147
src/core/scene.c
|
@ -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);
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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
41
src/core/transform_node.c
Normal 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
27
src/core/transform_node.h
Normal 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
|
|
@ -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));
|
||||||
|
|
|
@ -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
|
||||||
|
|
17
src/main.c
17
src/main.c
|
@ -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.");
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue