feat: implemented MeshRenderEntity

This commit is contained in:
Sara 2024-09-16 23:28:55 +02:00
parent dda35f69f0
commit 2be8b21372
9 changed files with 297 additions and 48 deletions

BIN
resources/spacefighter.glb Normal file

Binary file not shown.

View file

@ -46,7 +46,7 @@ void CameraNodeExitTree(CameraNode *self) {
Camera3D CameraNodeGetCamera(CameraNode *self) { Camera3D CameraNodeGetCamera(CameraNode *self) {
// Get the global transform matrix of the parent transformable // Get the global transform matrix of the parent transformable
Transform global_transform = self->transform.tc->get_global_transform(self->transform.data); 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 // get the forward row from the matrix
Vector3 forward = MATRIX_FORWARD(mat); Vector3 forward = MATRIX_FORWARD(mat);
// construct a new camera at the global transform location and facing the forward vector // construct a new camera at the global transform location and facing the forward vector

View file

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

View file

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

View file

@ -1,31 +1,178 @@
#include "resources.h" #include "resources.h"
#include "stdint.h" #include "stdbool.h"
#include "utils/hash_map.h"
#include "utils/dictionary.h" #include "utils/dictionary.h"
#include "utils/debug.h" #include "utils/debug.h"
#include "utils/strutil.h"
char const *RESOURCE_DIRECTORY = "resources"; 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 static inline
void InitializeResourceDirectory() { void Internal_InitializeResourceDirectory() {
// if there is a resource directory in the working directory, prioritize that for debugging // if there is a resource directory in the working directory, prioritize that for debugging
if(DirectoryExists(RESOURCE_DIRECTORY)) { if(DirectoryExists(RESOURCE_DIRECTORY)) {
ChangeDirectory(TextFormat("%s/%s", GetWorkingDirectory(), 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 // check application installation directory for a resource directory
// this is the default running environment // 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)) { if(DirectoryExists(installation_resource_dir)) {
ChangeDirectory(installation_resource_dir); ChangeDirectory(installation_resource_dir);
return; 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() { void InitializeResourceSubsystem() {
InitializeResourceDirectory(); Internal_InitializeResourceDirectory();
Internal_IndexResourceDirectory();
} }
void CleanResourceSubsystem() { 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};
}

View file

@ -2,10 +2,30 @@
#define RESOURCES_H #define RESOURCES_H
#include "raylib.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 //! Allocate and initialize memory required to operate resource subsystem
extern void InitializeResourceSubsystem(); extern void InitializeResourceSubsystem();
//! Clean and shut down resource subsystem, all resource calls are invalid after this //! Clean and shut down resource subsystem, all resource calls are invalid after this
extern void CleanResourceSubsystem(); 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 #endif // !RESOURCES_H

View file

@ -9,45 +9,45 @@ Transform TransformIdentity() {
} }
Matrix TransformGetMatrix(Transform const *self) { Matrix TransformGetMatrix(Transform 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));
mat.m12 = self->translation.x; mat.m12 = self.translation.x;
mat.m13 = self->translation.y; mat.m13 = self.translation.y;
mat.m14 = self->translation.z; mat.m14 = self.translation.z;
return mat; return mat;
} }
Vector3 TransformPosition(Transform const *self, Vector3 local_pos) { Vector3 TransformPosition(Transform self, Vector3 local_pos) {
return Vector3Add(TransformDirection(self, local_pos), self->translation); 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); 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)); 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) { Vector3 TransformScale(Transform self, Vector3 local_scale) {
return Vector3Multiply(self->scale, TransformDirection(self, local_scale)); return Vector3Multiply(self.scale, TransformDirection(self, local_scale));
} }
Quaternion TransformRotation(Transform const *self, Quaternion local_rotation) { Quaternion TransformRotation(Transform self, Quaternion local_rotation) {
return QuaternionMultiply(self->rotation, local_rotation); return QuaternionMultiply(self.rotation, local_rotation);
} }
Transform TransformTransform(Transform const *self, Transform const *other) { Transform TransformTransform(Transform self, Transform other) {
return (Transform) { return (Transform) {
.translation = TransformPosition(self, other->translation), .translation = TransformPosition(self, other.translation),
.scale = TransformScale(self, other->scale), .scale = TransformScale(self, other.scale),
.rotation = TransformRotation(self, other->rotation) .rotation = TransformRotation(self, other.rotation)
}; };
} }
Vector3 InverseTransformPosition(Transform const *self, Vector3 global_pos) { Vector3 InverseTransformPosition(Transform self, Vector3 global_pos) {
return Vector3Subtract(InverseTransformDirection(self, global_pos), self->translation); 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); Matrix const mat = TransformGetMatrix(self);
return (Vector3){ return (Vector3){
Vector3DotProduct(MATRIX_RIGHT(mat), Vector3Scale(VECTOR3_RIGHT, global_direction.x)), 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) { Vector3 InverseTransformScale(Transform self, Vector3 global_scale) {
return Vector3Multiply(Vector3Invert(self->scale), InverseTransformDirection(self, global_scale)); return Vector3Multiply(Vector3Invert(self.scale), InverseTransformDirection(self, global_scale));
} }
Quaternion InverseTransformRotation(Transform const *self, Quaternion global_rotation) { Quaternion InverseTransformRotation(Transform self, Quaternion global_rotation) {
return QuaternionMultiply(QuaternionInvert(self->rotation), 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) { return (Transform) {
.translation = InverseTransformPosition(self, other->translation), .translation = InverseTransformPosition(self, other.translation),
.scale = InverseTransformScale(self, other->scale), .scale = InverseTransformScale(self, other.scale),
.rotation = InverseTransformRotation(self, other->rotation) .rotation = InverseTransformRotation(self, other.rotation)
}; };
} }

View file

@ -28,19 +28,19 @@ typedef struct Transformable {
} Transformable; } Transformable;
extern Transform TransformIdentity(); 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 TransformPosition(Transform self, Vector3 local_pos);
extern Vector3 TransformDirection(Transform const *self, Vector3 local_direction); extern Vector3 TransformDirection(Transform self, Vector3 local_direction);
extern Vector3 TransformScale(Transform const *self, Vector3 local_scale); extern Vector3 TransformScale(Transform self, Vector3 local_scale);
extern Quaternion TransformRotation(Transform const *self, Quaternion local_rotation); extern Quaternion TransformRotation(Transform self, Quaternion local_rotation);
extern Transform TransformTransform(Transform const *self, Transform const *other); extern Transform TransformTransform(Transform self, Transform other);
extern Vector3 InverseTransformPosition(Transform const *self, Vector3 global_pos); extern Vector3 InverseTransformPosition(Transform self, Vector3 global_pos);
extern Vector3 InverseTransformDirection(Transform const *self, Vector3 global_direction); extern Vector3 InverseTransformDirection(Transform self, Vector3 global_direction);
extern Vector3 InverseTransformScale(Transform const *self, Vector3 global_scale); extern Vector3 InverseTransformScale(Transform self, Vector3 global_scale);
extern Quaternion InverseTransformRotation(Transform const *self, Quaternion quat); extern Quaternion InverseTransformRotation(Transform self, Quaternion quat);
extern Transform InverseTransformTransform(Transform const *self, Transform const *other); extern Transform InverseTransformTransform(Transform self, Transform other);
#define MATRIX_UP(self_) ((Vector3){self_.m0, self_.m1, self_.m2}) #define MATRIX_UP(self_) ((Vector3){self_.m0, self_.m1, self_.m2})
#define MATRIX_RIGHT(self_) ((Vector3){self_.m4, self_.m5, self_.m6}) #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;\ self->transform = value;\
} else {\ } else {\
Transform parent_global = self->parent_transformable.tc->get_global_transform(self->parent_transformable.data);\ 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) {\ static void T##_force_update_GEN_(T *self) {\
@ -75,7 +75,7 @@ static void T##_force_update_GEN_(T *self) {\
return;\ return;\
}\ }\
Transform parent_global = self->parent_transformable.tc->get_global_transform(self->parent_transformable.data);\ 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 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; }\ static Transformable T##_get_parent_transformable_GEN_(T *self) { return self->parent_transformable; }\

View file

@ -5,6 +5,7 @@
#include "core/engine_loop.h" #include "core/engine_loop.h"
#include "core/scene.h" #include "core/scene.h"
#include "core/transform_node.h" #include "core/transform_node.h"
#include "core/mesh_render_entity.h"
#include "utils/debug.h" #include "utils/debug.h"
Scene *CreateInitialScene() { Scene *CreateInitialScene() {
@ -28,6 +29,7 @@ Scene *CreateInitialScene() {
SceneNodeAddChild(camera_parent_parent, camera_parent); SceneNodeAddChild(camera_parent_parent, camera_parent);
SceneNodeAddChild(camera_parent, CreateCameraNode()); SceneNodeAddChild(camera_parent, CreateCameraNode());
SceneNodeAddChild(camera_parent, CreateTestObject()); SceneNodeAddChild(camera_parent, CreateTestObject());
SceneNodeAddChild(root, CreateMeshRenderEntity("spacefighter.glb"));
return CreateScene(root); return CreateScene(root);
} }