From 2be8b213722166c67eb40c4d04dfaa2885706c90 Mon Sep 17 00:00:00 2001 From: Sara Date: Mon, 16 Sep 2024 23:28:55 +0200 Subject: [PATCH] feat: implemented MeshRenderEntity --- resources/spacefighter.glb | Bin 0 -> 19324 bytes src/core/camera_node.c | 2 +- src/core/mesh_render_entity.c | 50 +++++++++++ src/core/mesh_render_entity.h | 30 +++++++ src/core/resources.c | 159 ++++++++++++++++++++++++++++++++-- src/core/resources.h | 20 +++++ src/core/transformable.c | 56 ++++++------ src/core/transformable.h | 26 +++--- src/main.c | 2 + 9 files changed, 297 insertions(+), 48 deletions(-) create mode 100644 resources/spacefighter.glb create mode 100644 src/core/mesh_render_entity.c create mode 100644 src/core/mesh_render_entity.h diff --git a/resources/spacefighter.glb b/resources/spacefighter.glb new file mode 100644 index 0000000000000000000000000000000000000000..db98dc371c065cadf9063d66c3d7759872f7e7eb GIT binary patch literal 19324 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 hg24k%N#fhjY8a~GRTF7Zq!zJaMm{tvi6D*pfg literal 0 HcmV?d00001 diff --git a/src/core/camera_node.c b/src/core/camera_node.c index 8b8b849..1b6fa9b 100644 --- a/src/core/camera_node.c +++ b/src/core/camera_node.c @@ -46,7 +46,7 @@ void CameraNodeExitTree(CameraNode *self) { Camera3D CameraNodeGetCamera(CameraNode *self) { // Get the global transform matrix of the parent transformable Transform global_transform = self->transform.tc->get_global_transform(self->transform.data); - Matrix mat = TransformGetMatrix(&global_transform); + Matrix mat = TransformGetMatrix(global_transform); // get the forward row from the matrix Vector3 forward = MATRIX_FORWARD(mat); // construct a new camera at the global transform location and facing the forward vector diff --git a/src/core/mesh_render_entity.c b/src/core/mesh_render_entity.c new file mode 100644 index 0000000..f6de252 --- /dev/null +++ b/src/core/mesh_render_entity.c @@ -0,0 +1,50 @@ +#include "mesh_render_entity.h" +#include "render.h" + +START_REFLECT(MeshRenderEntity); +REFLECT_TYPECLASS(MeshRenderEntity, Drop); +REFLECT_TYPECLASS(MeshRenderEntity, SceneNodeEntity); +REFLECT_TYPECLASS(MeshRenderEntity, Renderable); +END_REFLECT(MeshRenderEntity); + +impl_SceneNodeEntity_defaults(MeshRenderEntity) +impl_SceneNodeEntity_for(MeshRenderEntity, + MeshRenderEntityEnterTree, + MeshRenderEntityExitTree, + MeshRenderEntity_default_tick +) + +impl_Drop_for(MeshRenderEntity, + DestroyMeshRenderEntity +) + +impl_Renderable_for(MeshRenderEntity, + MeshRenderEntityDraw +) + +SceneNode *CreateMeshRenderEntity(char const *resource_path) { + MeshRenderEntity *self = new(MeshRenderEntity); + GetModelResource(resource_path, &self->model); + return CreateSceneNode(MeshRenderEntity_as_SceneNodeEntity(self)); +} + +void DestroyMeshRenderEntity(MeshRenderEntity *self) { + free(self); +} + +void MeshRenderEntityEnterTree(MeshRenderEntity *self) { + SceneNodeEntity parent_entity = self->node->parent->entity; + self->transform = TC_CAST(parent_entity, Transformable); + LoadResource(self->model.handle); + AddRenderable(MeshRenderEntity_as_Renderable(self)); +} + +void MeshRenderEntityExitTree(MeshRenderEntity *self) { + ReleaseResource(self->model.handle); + RemoveRenderable(MeshRenderEntity_as_Renderable(self)); +} + +void MeshRenderEntityDraw(MeshRenderEntity *self) { + self->model.resource->transform = TransformGetMatrix(self->transform.tc->get_global_transform(self->transform.data)); + DrawModel(*self->model.resource, (Vector3){0.f, 0.f, 0.f}, 1.f, WHITE); +} diff --git a/src/core/mesh_render_entity.h b/src/core/mesh_render_entity.h new file mode 100644 index 0000000..ca726cb --- /dev/null +++ b/src/core/mesh_render_entity.h @@ -0,0 +1,30 @@ +#ifndef MESH_RENDER_ENTITY_H +#define MESH_RENDER_ENTITY_H + +#include "renderable.h" +#include "resources.h" +#include "scene_node_entity.h" +#include "transformable.h" +#include "utils/drop.h" +#include "utils/mirror.h" + +typedef struct MeshRenderEntity { + SceneNode *node; + Transformable transform; + ModelResource model; +} MeshRenderEntity; + +extern SceneNode *CreateMeshRenderEntity(char const *resource_path); +extern void DestroyMeshRenderEntity(MeshRenderEntity *self); + +extern void MeshRenderEntityEnterTree(MeshRenderEntity *self); +extern void MeshRenderEntityExitTree(MeshRenderEntity *self); + +extern void MeshRenderEntityDraw(MeshRenderEntity *self); + +DECL_REFLECT(MeshRenderEntity); +decl_typeclass_impl(Drop, MeshRenderEntity); +decl_typeclass_impl(SceneNodeEntity, MeshRenderEntity); +decl_typeclass_impl(Renderable, MeshRenderEntity); + +#endif // !MESH_RENDER_ENTITY_H diff --git a/src/core/resources.c b/src/core/resources.c index be78d8e..3160d36 100644 --- a/src/core/resources.c +++ b/src/core/resources.c @@ -1,31 +1,178 @@ #include "resources.h" -#include "stdint.h" +#include "stdbool.h" +#include "utils/hash_map.h" #include "utils/dictionary.h" #include "utils/debug.h" +#include "utils/strutil.h" char const *RESOURCE_DIRECTORY = "resources"; +typedef enum ResourceType { + RESOURCE_MODEL, RESOURCE_TEXTURE, + RESOURCE_MAX +} ResourceType; + +typedef struct ResourceContainer { + char const *path; + char const *name; + unsigned use_counter; + bool is_loaded; + ResourceType type; + union { + Model model; + Texture texture; + }; +} ResourceContainer; + +typedef void (*LoadResourceFn)(ResourceContainer *resource); +typedef void (*UnloadResourceFn)(ResourceContainer *resource); + +static void Internal_LoadModelResource(ResourceContainer *resource); +static void Internal_UnloadModelResource(ResourceContainer *resource); +static void Internal_LoadTextureResource(ResourceContainer *resource); +static void Internal_UnloadTextureResource(ResourceContainer *resource); + +LoadResourceFn g_load_functions[] = {Internal_LoadModelResource, Internal_LoadTextureResource}; +UnloadResourceFn g_unload_functions[] = {Internal_UnloadModelResource, Internal_UnloadTextureResource}; + +static HashMap g_resource_map; +static FilePathList g_resource_files; + +//! hash function for hashmaps with char* as key type. +static uintptr_t HashMapHashString(char const **str_ptr) { + return strhash(*str_ptr); +} + +//! Use file extensions to figure out the +static ResourceType ResourceGetTypeFromPath(char const *path) { + // Texture files + if(IsFileExtension(path, ".png")) return RESOURCE_TEXTURE; + if(IsFileExtension(path, ".jpg")) return RESOURCE_TEXTURE; + if(IsFileExtension(path, ".jpeg")) return RESOURCE_TEXTURE; + // Model files + if(IsFileExtension(path, ".glb")) return RESOURCE_MODEL; + if(IsFileExtension(path, ".gltf")) return RESOURCE_MODEL; + return RESOURCE_MAX; +} + +//! Find which resource directory to use: Relative to working directory, or relative to application directory +//! Working directory resources are only supposed to be used for debugging. static inline -void InitializeResourceDirectory() { +void Internal_InitializeResourceDirectory() { // if there is a resource directory in the working directory, prioritize that for debugging if(DirectoryExists(RESOURCE_DIRECTORY)) { ChangeDirectory(TextFormat("%s/%s", GetWorkingDirectory(), RESOURCE_DIRECTORY)); - LOG_WARNING("Using working dir resources, this is possible for debug purposes."); + LOG_WARNING("Using working dir resources, this is intended for debug purposes only."); + return; } // check application installation directory for a resource directory // this is the default running environment - char const *installation_resource_dir = TextFormat(GetApplicationDirectory(), RESOURCE_DIRECTORY); + char const *installation_resource_dir = TextFormat("%s/%s", GetApplicationDirectory(), RESOURCE_DIRECTORY); if(DirectoryExists(installation_resource_dir)) { ChangeDirectory(installation_resource_dir); return; } - UNREACHABLE("Failed to find resource directory"); + UNREACHABLE("Failed to find a valid resource directory"); +} + +static inline +void Internal_IndexResourceDirectory() { + g_resource_files = LoadDirectoryFilesEx(GetWorkingDirectory(), NULL, true); + g_resource_map = hash_map_from_types(char const *, ResourceContainer, HashMapHashString); + ResourceContainer placeholder; + for(size_t i = 0; i < g_resource_files.count; ++i) { + placeholder = (ResourceContainer){ + .is_loaded = false, + .use_counter = 0, + .path = g_resource_files.paths[i], + .name = GetFileName(g_resource_files.paths[i]), + .type = ResourceGetTypeFromPath(g_resource_files.paths[i]) + }; + // only index resources that the engine knows how to load + if(placeholder.type != RESOURCE_MAX) { + LOG_INFO("Internal_IndexResourceDirectory: Indexing %s as %s", placeholder.path, placeholder.name); + hash_map_insert(&g_resource_map, &placeholder.name, &placeholder); + } + } } void InitializeResourceSubsystem() { - InitializeResourceDirectory(); + Internal_InitializeResourceDirectory(); + Internal_IndexResourceDirectory(); } void CleanResourceSubsystem() { + List resources = hash_map_values(&g_resource_map); + list_foreach(ResourceContainer *,resource, &resources) + g_unload_functions[resource->type](resource); + hash_map_empty(&g_resource_map); + UnloadDirectoryFiles(g_resource_files); } +bool GetModelResource(char const *path, ModelResource *out) { + ResourceContainer *container = hash_map_get_as(ResourceContainer, &g_resource_map, &path); + *out = ResourceEmpty(Model); + // assert some assumptions about the found resource + ASSERT_RETURN(container != NULL, false, "GetTextureResource: Resource %s not in index.", path); + ASSERT_RETURN(container->type == RESOURCE_MODEL, false, "GetTextureResource: Resource %s is not a Texture.", path); + ++container->use_counter; + *out = (ModelResource) { + .handle = container, + .resource = &container->model + }; + return true; +} + +bool GetTextureResource(char const *path, TextureResource *out) { + ResourceContainer *container = hash_map_get_as(ResourceContainer, &g_resource_map, &path); + *out = ResourceEmpty(Texture); + // assert some assumptions about the found resource + ASSERT_RETURN(container != NULL, false, "GetTextureResource: Resource %s not in index.", path); + ASSERT_RETURN(container->type != RESOURCE_TEXTURE, false, "GetTextureResource: Resource %s is not a Texture.", path); + *out = (TextureResource) { + .handle = container, + .resource = &container->texture + }; + return true; +} + +bool IsResourceLoaded(ResourceHandle handle) { + return handle->is_loaded; +} + +void LoadResource(ResourceHandle handle) { + ASSERT_RETURN(handle != NULL,, "LoadResource: Resource handle invalid"); + g_load_functions[handle->type](handle); + handle->is_loaded = true; + ++handle->use_counter; +} + +void ReleaseResource(ResourceHandle handle) { + ASSERT_RETURN(handle != NULL,, "ReleaseResource: Resource handle invalid"); + ASSERT_RETURN_WARN(handle->is_loaded,, "ReleaseResource: Resource %s is not loaded.", handle->path); + g_unload_functions[handle->type](handle); + handle->is_loaded = false; + --handle->use_counter; +} + +static +void Internal_LoadModelResource(ResourceContainer *resource) { + resource->model = LoadModel(resource->path); +} + +static +void Internal_UnloadModelResource(ResourceContainer *resource) { + UnloadModel(resource->model); + resource->model = (Model){0}; +} + +static +void Internal_LoadTextureResource(ResourceContainer *resource) { + resource->texture = LoadTexture(resource->path); +} + +static +void Internal_UnloadTextureResource(ResourceContainer *resource) { + UnloadTexture(resource->texture); + resource->texture = (Texture){0}; +} diff --git a/src/core/resources.h b/src/core/resources.h index 84cacf1..1b1c5ca 100644 --- a/src/core/resources.h +++ b/src/core/resources.h @@ -2,10 +2,30 @@ #define RESOURCES_H #include "raylib.h" +#include "stdint.h" +#include "stdbool.h" + +typedef struct ResourceContainer* ResourceHandle; +#define ResourceType(T) typedef struct T##Resource { ResourceHandle handle; T *resource; } T##Resource +#define ResourceEmpty(T) ((T##Resource){.handle = NULL, .resource = NULL}) + +ResourceType(Model); +ResourceType(Texture); //! Allocate and initialize memory required to operate resource subsystem extern void InitializeResourceSubsystem(); //! Clean and shut down resource subsystem, all resource calls are invalid after this extern void CleanResourceSubsystem(); +//! Get model from resources. +extern bool GetModelResource(char const *path, ModelResource *out); +//! Get indexed texture from resources. +extern bool GetTextureResource(char const *path, TextureResource *out); + +//! Check if a resource is loaded or not. +extern bool IsResourceLoaded(ResourceHandle handle); +//! Load a resource using a handle returned from Get{Type}Resource, increments use count. +extern void LoadResource(ResourceHandle resource); +//! Release a resource using a handle returned from Get{Type}Resource, increments use count. +extern void ReleaseResource(ResourceHandle handle); #endif // !RESOURCES_H diff --git a/src/core/transformable.c b/src/core/transformable.c index 2e9af7c..ef596f9 100644 --- a/src/core/transformable.c +++ b/src/core/transformable.c @@ -9,45 +9,45 @@ Transform TransformIdentity() { } -Matrix TransformGetMatrix(Transform const *self) { - Matrix mat = MatrixScale(self->scale.x, self->scale.y, self->scale.z); - mat = MatrixMultiply(mat, QuaternionToMatrix(self->rotation)); - mat.m12 = self->translation.x; - mat.m13 = self->translation.y; - mat.m14 = self->translation.z; +Matrix TransformGetMatrix(Transform self) { + Matrix mat = MatrixScale(self.scale.x, self.scale.y, self.scale.z); + mat = MatrixMultiply(mat, QuaternionToMatrix(self.rotation)); + mat.m12 = self.translation.x; + mat.m13 = self.translation.y; + mat.m14 = self.translation.z; return mat; } -Vector3 TransformPosition(Transform const *self, Vector3 local_pos) { - return Vector3Add(TransformDirection(self, local_pos), self->translation); +Vector3 TransformPosition(Transform self, Vector3 local_pos) { + return Vector3Add(TransformDirection(self, local_pos), self.translation); } -Vector3 TransformDirection(Transform const *self, Vector3 local_direction) { +Vector3 TransformDirection(Transform self, Vector3 local_direction) { Matrix const m = TransformGetMatrix(self); return Vector3Add(Vector3Add(Vector3Scale(MATRIX_RIGHT(m), local_direction.x), Vector3Scale(MATRIX_UP(m), local_direction.y)), Vector3Scale(MATRIX_FORWARD(m), local_direction.z)); } -Vector3 TransformScale(Transform const *self, Vector3 local_scale) { - return Vector3Multiply(self->scale, TransformDirection(self, local_scale)); +Vector3 TransformScale(Transform self, Vector3 local_scale) { + return Vector3Multiply(self.scale, TransformDirection(self, local_scale)); } -Quaternion TransformRotation(Transform const *self, Quaternion local_rotation) { - return QuaternionMultiply(self->rotation, local_rotation); +Quaternion TransformRotation(Transform self, Quaternion local_rotation) { + return QuaternionMultiply(self.rotation, local_rotation); } -Transform TransformTransform(Transform const *self, Transform const *other) { +Transform TransformTransform(Transform self, Transform other) { return (Transform) { - .translation = TransformPosition(self, other->translation), - .scale = TransformScale(self, other->scale), - .rotation = TransformRotation(self, other->rotation) + .translation = TransformPosition(self, other.translation), + .scale = TransformScale(self, other.scale), + .rotation = TransformRotation(self, other.rotation) }; } -Vector3 InverseTransformPosition(Transform const *self, Vector3 global_pos) { - return Vector3Subtract(InverseTransformDirection(self, global_pos), self->translation); +Vector3 InverseTransformPosition(Transform self, Vector3 global_pos) { + return Vector3Subtract(InverseTransformDirection(self, global_pos), self.translation); } -Vector3 InverseTransformDirection(Transform const *self, Vector3 global_direction) { +Vector3 InverseTransformDirection(Transform self, Vector3 global_direction) { Matrix const mat = TransformGetMatrix(self); return (Vector3){ Vector3DotProduct(MATRIX_RIGHT(mat), Vector3Scale(VECTOR3_RIGHT, global_direction.x)), @@ -56,18 +56,18 @@ Vector3 InverseTransformDirection(Transform const *self, Vector3 global_directio }; } -Vector3 InverseTransformScale(Transform const *self, Vector3 global_scale) { - return Vector3Multiply(Vector3Invert(self->scale), InverseTransformDirection(self, global_scale)); +Vector3 InverseTransformScale(Transform self, Vector3 global_scale) { + return Vector3Multiply(Vector3Invert(self.scale), InverseTransformDirection(self, global_scale)); } -Quaternion InverseTransformRotation(Transform const *self, Quaternion global_rotation) { - return QuaternionMultiply(QuaternionInvert(self->rotation), global_rotation); +Quaternion InverseTransformRotation(Transform self, Quaternion global_rotation) { + return QuaternionMultiply(QuaternionInvert(self.rotation), global_rotation); } -Transform InverseTransformTransform(Transform const *self, Transform const *other) { +Transform InverseTransformTransform(Transform self, Transform other) { return (Transform) { - .translation = InverseTransformPosition(self, other->translation), - .scale = InverseTransformScale(self, other->scale), - .rotation = InverseTransformRotation(self, other->rotation) + .translation = InverseTransformPosition(self, other.translation), + .scale = InverseTransformScale(self, other.scale), + .rotation = InverseTransformRotation(self, other.rotation) }; } diff --git a/src/core/transformable.h b/src/core/transformable.h index 097eece..ac9db49 100644 --- a/src/core/transformable.h +++ b/src/core/transformable.h @@ -28,19 +28,19 @@ typedef struct Transformable { } Transformable; extern Transform TransformIdentity(); -extern Matrix TransformGetMatrix(Transform const *self); +extern Matrix TransformGetMatrix(Transform self); -extern Vector3 TransformPosition(Transform const *self, Vector3 local_pos); -extern Vector3 TransformDirection(Transform const *self, Vector3 local_direction); -extern Vector3 TransformScale(Transform const *self, Vector3 local_scale); -extern Quaternion TransformRotation(Transform const *self, Quaternion local_rotation); -extern Transform TransformTransform(Transform const *self, Transform const *other); +extern Vector3 TransformPosition(Transform self, Vector3 local_pos); +extern Vector3 TransformDirection(Transform self, Vector3 local_direction); +extern Vector3 TransformScale(Transform self, Vector3 local_scale); +extern Quaternion TransformRotation(Transform self, Quaternion local_rotation); +extern Transform TransformTransform(Transform self, Transform other); -extern Vector3 InverseTransformPosition(Transform const *self, Vector3 global_pos); -extern Vector3 InverseTransformDirection(Transform const *self, Vector3 global_direction); -extern Vector3 InverseTransformScale(Transform const *self, Vector3 global_scale); -extern Quaternion InverseTransformRotation(Transform const *self, Quaternion quat); -extern Transform InverseTransformTransform(Transform const *self, Transform const *other); +extern Vector3 InverseTransformPosition(Transform self, Vector3 global_pos); +extern Vector3 InverseTransformDirection(Transform self, Vector3 global_direction); +extern Vector3 InverseTransformScale(Transform self, Vector3 global_scale); +extern Quaternion InverseTransformRotation(Transform self, Quaternion quat); +extern Transform InverseTransformTransform(Transform self, Transform other); #define MATRIX_UP(self_) ((Vector3){self_.m0, self_.m1, self_.m2}) #define MATRIX_RIGHT(self_) ((Vector3){self_.m4, self_.m5, self_.m6}) @@ -66,7 +66,7 @@ static void T##_set_global_transform_GEN_(T* self, Transform value) {\ self->transform = value;\ } else {\ Transform parent_global = self->parent_transformable.tc->get_global_transform(self->parent_transformable.data);\ - self->transform = InverseTransformTransform(&parent_global, &value); /* Use parent transform to transform the local transform to the new global transform */\ + self->transform = InverseTransformTransform(parent_global, value); /* Use parent transform to transform the local transform to the new global transform */\ }\ }\ static void T##_force_update_GEN_(T *self) {\ @@ -75,7 +75,7 @@ static void T##_force_update_GEN_(T *self) {\ return;\ }\ Transform parent_global = self->parent_transformable.tc->get_global_transform(self->parent_transformable.data);\ - self->global_transform = TransformTransform(&parent_global, &self->transform);\ + self->global_transform = TransformTransform(parent_global, self->transform);\ }\ static unsigned char T##_get_dirty_bit_GEN_(T *self) { return self->dirty_bit; }\ static Transformable T##_get_parent_transformable_GEN_(T *self) { return self->parent_transformable; }\ diff --git a/src/main.c b/src/main.c index 153bdfa..22425b4 100644 --- a/src/main.c +++ b/src/main.c @@ -5,6 +5,7 @@ #include "core/engine_loop.h" #include "core/scene.h" #include "core/transform_node.h" +#include "core/mesh_render_entity.h" #include "utils/debug.h" Scene *CreateInitialScene() { @@ -28,6 +29,7 @@ Scene *CreateInitialScene() { SceneNodeAddChild(camera_parent_parent, camera_parent); SceneNodeAddChild(camera_parent, CreateCameraNode()); SceneNodeAddChild(camera_parent, CreateTestObject()); + SceneNodeAddChild(root, CreateMeshRenderEntity("spacefighter.glb")); return CreateScene(root); }