feat: defined various core engine concepts
- Scene Tree - Engine loop - Draw list - Renderables - Resources
This commit is contained in:
		
							parent
							
								
									ddd9323c60
								
							
						
					
					
						commit
						ba614edd29
					
				| 
						 | 
					@ -1,95 +0,0 @@
 | 
				
			||||||
/**********************************************************************************************
 | 
					 | 
				
			||||||
*
 | 
					 | 
				
			||||||
*   raylibExtras * Utilities and Shared Components for Raylib
 | 
					 | 
				
			||||||
*
 | 
					 | 
				
			||||||
*   Resource Dir * function to help find resource dir in common locations
 | 
					 | 
				
			||||||
*
 | 
					 | 
				
			||||||
*   LICENSE: MIT
 | 
					 | 
				
			||||||
*
 | 
					 | 
				
			||||||
*   Copyright (c) 2022 Jeffery Myers
 | 
					 | 
				
			||||||
*
 | 
					 | 
				
			||||||
*   Permission is hereby granted, free of charge, to any person obtaining a copy
 | 
					 | 
				
			||||||
*   of this software and associated documentation files (the "Software"), to deal
 | 
					 | 
				
			||||||
*   in the Software without restriction, including without limitation the rights
 | 
					 | 
				
			||||||
*   to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 | 
					 | 
				
			||||||
*   copies of the Software, and to permit persons to whom the Software is
 | 
					 | 
				
			||||||
*   furnished to do so, subject to the following conditions:
 | 
					 | 
				
			||||||
*
 | 
					 | 
				
			||||||
*   The above copyright notice and this permission notice shall be included in all
 | 
					 | 
				
			||||||
*   copies or substantial portions of the Software.
 | 
					 | 
				
			||||||
*
 | 
					 | 
				
			||||||
*   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 | 
					 | 
				
			||||||
*   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 | 
					 | 
				
			||||||
*   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 | 
					 | 
				
			||||||
*   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 | 
					 | 
				
			||||||
*   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 | 
					 | 
				
			||||||
*   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 | 
					 | 
				
			||||||
*   SOFTWARE.
 | 
					 | 
				
			||||||
*
 | 
					 | 
				
			||||||
**********************************************************************************************/
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#pragma once
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#include "raylib.h"
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(__cplusplus)
 | 
					 | 
				
			||||||
extern "C" {            // Prevents name mangling of functions
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
    /// <summary>
 | 
					 | 
				
			||||||
    /// Looks for the specified resource dir in several common locations
 | 
					 | 
				
			||||||
    /// The working dir
 | 
					 | 
				
			||||||
    /// The app dir
 | 
					 | 
				
			||||||
    /// Up to 3 levels above the app dir
 | 
					 | 
				
			||||||
    /// When found the dir will be set as the working dir so that assets can be loaded relative to that.
 | 
					 | 
				
			||||||
    /// </summary>
 | 
					 | 
				
			||||||
    /// <param name="folderName">The name of the resources dir to look for</param>
 | 
					 | 
				
			||||||
    /// <returns>True if a dir with the name was found, false if no change was made to the working dir</returns>
 | 
					 | 
				
			||||||
    inline static bool SearchAndSetResourceDir(const char* folderName)
 | 
					 | 
				
			||||||
    {
 | 
					 | 
				
			||||||
        // check the working dir
 | 
					 | 
				
			||||||
        if (DirectoryExists(folderName))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            ChangeDirectory(TextFormat("%s/%s", GetWorkingDirectory(), folderName));
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        const char* appDir = GetApplicationDirectory();
 | 
					 | 
				
			||||||
       
 | 
					 | 
				
			||||||
        // check the applicationDir
 | 
					 | 
				
			||||||
        const char* dir = TextFormat("%s%s", appDir, folderName);
 | 
					 | 
				
			||||||
        if (DirectoryExists(dir))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            ChangeDirectory(dir);
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // check one up from the app dir
 | 
					 | 
				
			||||||
        dir = TextFormat("%s../%s", appDir, folderName);
 | 
					 | 
				
			||||||
        if (DirectoryExists(dir))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            ChangeDirectory(dir);
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // check two up from the app dir
 | 
					 | 
				
			||||||
        dir = TextFormat("%s../../%s", appDir, folderName);
 | 
					 | 
				
			||||||
        if (DirectoryExists(dir))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            ChangeDirectory(dir);
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        // check three up from the app dir
 | 
					 | 
				
			||||||
        dir = TextFormat("%s../../../%s", appDir, folderName);
 | 
					 | 
				
			||||||
        if (DirectoryExists(dir))
 | 
					 | 
				
			||||||
        {
 | 
					 | 
				
			||||||
            ChangeDirectory(dir);
 | 
					 | 
				
			||||||
            return true;
 | 
					 | 
				
			||||||
        }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
        return false;
 | 
					 | 
				
			||||||
    }
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#if defined(__cplusplus)
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
#endif
 | 
					 | 
				
			||||||
							
								
								
									
										18
									
								
								src/core/camera_node.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										18
									
								
								src/core/camera_node.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,18 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "scene_node_entity.h"
 | 
				
			||||||
 | 
					#include "utils/drop.h"
 | 
				
			||||||
 | 
					#include "raylib.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct CameraNode {
 | 
				
			||||||
 | 
					    SceneNode *node;
 | 
				
			||||||
 | 
					} CameraNode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CameraNodeEnterTree(CameraNode *self);
 | 
				
			||||||
 | 
					void CameraNodeExitTree(CameraNode *self);
 | 
				
			||||||
 | 
					void CameraNodeTick(CameraNode *self, double delta);
 | 
				
			||||||
 | 
					Camera3D CameraNodeGetCamera(CameraNode *self);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					impl_default_Drop_for(CameraNode);
 | 
				
			||||||
 | 
					impl_SceneNodeEntity_for(CameraNode, CameraNodeEnterTree, CameraNodeExitTree, CameraNodeTick);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										35
									
								
								src/core/engine_loop.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/core/engine_loop.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					#include "engine_loop.h"
 | 
				
			||||||
 | 
					#include "resources.h"
 | 
				
			||||||
 | 
					#include "render.h"
 | 
				
			||||||
 | 
					#include "stdlib.h"
 | 
				
			||||||
 | 
					#include "raylib.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static
 | 
				
			||||||
 | 
					void InitializeRaylibContext() {
 | 
				
			||||||
 | 
					    // initialize fullscreen game window
 | 
				
			||||||
 | 
					    SetConfigFlags(FLAG_VSYNC_HINT | FLAG_WINDOW_HIGHDPI);
 | 
				
			||||||
 | 
					    InitWindow(1280, 800, "Hello Raylib");
 | 
				
			||||||
 | 
					    if(!IsWindowFullscreen())
 | 
				
			||||||
 | 
					        ToggleFullscreen();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RunGame() {
 | 
				
			||||||
 | 
					    while (!WindowShouldClose()) {
 | 
				
			||||||
 | 
					        RenderNextFrame();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    ShutDown();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InitializeEngine() {
 | 
				
			||||||
 | 
					    // initialize context
 | 
				
			||||||
 | 
					    InitializeRaylibContext();
 | 
				
			||||||
 | 
					    // initialize engine subsystems
 | 
				
			||||||
 | 
					    InitializeResourceSubsystem();
 | 
				
			||||||
 | 
					    InitializeRenderingSubsystem();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void ShutDown() {
 | 
				
			||||||
 | 
					    CleanResourceSubsystem();
 | 
				
			||||||
 | 
					    CloseWindow();
 | 
				
			||||||
 | 
					    exit(0);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										14
									
								
								src/core/engine_loop.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										14
									
								
								src/core/engine_loop.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,14 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct GameContext {
 | 
				
			||||||
 | 
					} GameContext;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					// IMPORTANT: should be implemented by game code
 | 
				
			||||||
 | 
					extern void InitializeGame(GameContext *settings);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//! initialize window and application context
 | 
				
			||||||
 | 
					extern void InitializeEngine();
 | 
				
			||||||
 | 
					//! run the actual game, requires InitializeEngine to be called first
 | 
				
			||||||
 | 
					extern void RunGame();
 | 
				
			||||||
 | 
					// shut down game entirely
 | 
				
			||||||
 | 
					extern void ShutDown();
 | 
				
			||||||
							
								
								
									
										35
									
								
								src/core/render.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								src/core/render.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,35 @@
 | 
				
			||||||
 | 
					#include "render.h"
 | 
				
			||||||
 | 
					#include "utils/debug.h"
 | 
				
			||||||
 | 
					#include "utils/list.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static List g_render_objects = {}; //!< List of all registered rendering objects
 | 
				
			||||||
 | 
					CameraNode *camera = NULL; //!< Reference to current main camera
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InitializeRenderingSubsystem() {
 | 
				
			||||||
 | 
					    g_render_objects = list_from_type(Renderable);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CleanupRenderingSubsystem() {
 | 
				
			||||||
 | 
					    list_empty(&g_render_objects);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void AddRenderable(Renderable renderable) {
 | 
				
			||||||
 | 
					    ASSERT_RETURN(list_find(&g_render_objects, &renderable) == g_render_objects.len,, "AddRenderable: Argument is already registered, cannot register twice");
 | 
				
			||||||
 | 
					    list_add(&g_render_objects, &renderable);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RemoveRenderable(Renderable renderable) {
 | 
				
			||||||
 | 
					    size_t idx = list_find(&g_render_objects, &renderable);
 | 
				
			||||||
 | 
					    ASSERT_RETURN(idx != g_render_objects.len,, "RemoveRenderable: Argument is not registered, cannot unregister.");
 | 
				
			||||||
 | 
					    list_erase(&g_render_objects, idx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void RenderNextFrame() {
 | 
				
			||||||
 | 
					    BeginDrawing();
 | 
				
			||||||
 | 
					    ClearBackground(BLACK);
 | 
				
			||||||
 | 
					    BeginMode3D(CameraNodeGetCamera(camera));
 | 
				
			||||||
 | 
					    list_foreach(Renderable *,object, &g_render_objects)
 | 
				
			||||||
 | 
					        object->tc->draw(object->data);
 | 
				
			||||||
 | 
					    EndMode3D();
 | 
				
			||||||
 | 
					    EndDrawing();
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										24
									
								
								src/core/render.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								src/core/render.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,24 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "camera_node.h"
 | 
				
			||||||
 | 
					#include "renderable.h"
 | 
				
			||||||
 | 
					#include "raylib.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//! Initialize the rendering subsystem.
 | 
				
			||||||
 | 
					extern void InitializeRenderingSubsystem();
 | 
				
			||||||
 | 
					//! Cleanup after rendering system,
 | 
				
			||||||
 | 
					//! assumes you won't want to re-initialize after.
 | 
				
			||||||
 | 
					extern void CleanupRenderingSubsystem();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//! Register a renderable object through a typeclass.
 | 
				
			||||||
 | 
					extern void AddRenderable(Renderable renderable);
 | 
				
			||||||
 | 
					//! Remove a renderable object from draw list
 | 
				
			||||||
 | 
					extern void RemoveRenderable(Renderable renderable);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//! Set a camera as the main rendering camera.
 | 
				
			||||||
 | 
					extern void SetMainCamera(CameraNode *camera);
 | 
				
			||||||
 | 
					//! Get the current main rendering camera.
 | 
				
			||||||
 | 
					extern void GetMainCamera(CameraNode *camera);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//! Draw a frame to the screen based on the current state of the game.
 | 
				
			||||||
 | 
					extern void RenderNextFrame();
 | 
				
			||||||
							
								
								
									
										23
									
								
								src/core/renderable.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								src/core/renderable.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,23 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "scene_node_entity.h"
 | 
				
			||||||
 | 
					#include "utils/typeclass_helpers.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct IRenderable {
 | 
				
			||||||
 | 
					    void (*const draw)(void *self);
 | 
				
			||||||
 | 
					} IRenderable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct Renderable {
 | 
				
			||||||
 | 
					    IRenderable const *tc;
 | 
				
			||||||
 | 
					    void *data;
 | 
				
			||||||
 | 
					    ISceneNodeEntity const *scene_node_entity;
 | 
				
			||||||
 | 
					} Renderable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define impl_Renderable_for(T, draw_f)\
 | 
				
			||||||
 | 
					Renderable T##_as_Renderable(T *x) {\
 | 
				
			||||||
 | 
					    TC_FN_TYPECHECK(void, draw_f, T*);\
 | 
				
			||||||
 | 
					    static IRenderable const tc = {\
 | 
				
			||||||
 | 
					        .draw = (void(*const)(void*)) draw_f\
 | 
				
			||||||
 | 
					    };\
 | 
				
			||||||
 | 
					    return (Renderable){ .tc = &tc, .data = x, .scene_node_entity = T##_as_SceneNodeEntity(x).tc };\
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										64
									
								
								src/core/resources.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										64
									
								
								src/core/resources.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,64 @@
 | 
				
			||||||
 | 
					#include "resources.h"
 | 
				
			||||||
 | 
					#include "stdint.h"
 | 
				
			||||||
 | 
					#include "utils/dictionary.h"
 | 
				
			||||||
 | 
					#include "utils/debug.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					char const *RESOURCE_DIRECTORY = "resources";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef enum ResourceType {
 | 
				
			||||||
 | 
					    MODEL_RESOURCE = 0, TEXTURE_RESOURCE
 | 
				
			||||||
 | 
					} ResourceType;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct ResourceContainer {
 | 
				
			||||||
 | 
					    uint32_t rid;
 | 
				
			||||||
 | 
					    char const *resource_name;
 | 
				
			||||||
 | 
					    ResourceType type;
 | 
				
			||||||
 | 
					    union {
 | 
				
			||||||
 | 
					        Model model;
 | 
				
			||||||
 | 
					        Texture texture;
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					} ResourceContainer;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static Dictionary g_resources = {};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline
 | 
				
			||||||
 | 
					void Internal_CleanResourceContainer(ResourceContainer *container) {
 | 
				
			||||||
 | 
					    switch(container->type) {
 | 
				
			||||||
 | 
					    case MODEL_RESOURCE:
 | 
				
			||||||
 | 
					        UnloadModel(container->model);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    case TEXTURE_RESOURCE:
 | 
				
			||||||
 | 
					        UnloadTexture(container->texture);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    UNREACHABLE("CleanResourceContainer: Cleanup function not defined for %u", container->type);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline
 | 
				
			||||||
 | 
					void 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.");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    // check application installation directory for a resource directory
 | 
				
			||||||
 | 
					    // this is the default running environment
 | 
				
			||||||
 | 
					    char const *installation_resource_dir = TextFormat(GetApplicationDirectory(), RESOURCE_DIRECTORY);
 | 
				
			||||||
 | 
					    if(DirectoryExists(installation_resource_dir)) {
 | 
				
			||||||
 | 
					        ChangeDirectory(installation_resource_dir);
 | 
				
			||||||
 | 
					        return;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    UNREACHABLE("Failed to find resource directory");
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void InitializeResourceSubsystem() {
 | 
				
			||||||
 | 
					    InitializeResourceDirectory();
 | 
				
			||||||
 | 
					    g_resources = dictionary_from_type(ResourceContainer);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void CleanResourceSubsystem() {
 | 
				
			||||||
 | 
					    list_foreach(ResourceContainer *,container, &g_resources.list)
 | 
				
			||||||
 | 
					        Internal_CleanResourceContainer(container);
 | 
				
			||||||
 | 
					    dictionary_empty(&g_resources);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
							
								
								
									
										11
									
								
								src/core/resources.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										11
									
								
								src/core/resources.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,11 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "raylib.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern void InitializeResourceSubsystem();
 | 
				
			||||||
 | 
					extern void CleanResourceSubsystem();
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//! Load a model resource from disk, path is relative to the resource folder
 | 
				
			||||||
 | 
					extern Model *ResourcesLoadModel(char const *res_path);
 | 
				
			||||||
 | 
					//! Load a texture resource from disk, path is relative to the resource folder
 | 
				
			||||||
 | 
					extern Texture *ResourcesLoadTexture(char const *res_path);
 | 
				
			||||||
							
								
								
									
										98
									
								
								src/core/scene.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										98
									
								
								src/core/scene.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,98 @@
 | 
				
			||||||
 | 
					#include "scene.h"
 | 
				
			||||||
 | 
					#include "scene_node_entity.h"
 | 
				
			||||||
 | 
					#include "utils/debug.h"
 | 
				
			||||||
 | 
					#include "utils/list.h"
 | 
				
			||||||
 | 
					#include "utils/drop.h"
 | 
				
			||||||
 | 
					#include "utils/mirror.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct SceneNode {
 | 
				
			||||||
 | 
					    SceneNode *parent;
 | 
				
			||||||
 | 
					    Scene *scene;
 | 
				
			||||||
 | 
					    List children; //!< list of child SceneNodes
 | 
				
			||||||
 | 
					    SceneNodeEntity entity; //!< scene node entity that adds functionality to the node
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct Scene {
 | 
				
			||||||
 | 
					    SceneNode *root;
 | 
				
			||||||
 | 
					    List nodes;
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static
 | 
				
			||||||
 | 
					void Internal_SceneRemoveNode(Scene *self, SceneNode *node) {
 | 
				
			||||||
 | 
					    size_t idx = list_find(&self->nodes, node);
 | 
				
			||||||
 | 
					    list_erase(&self->nodes, idx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static
 | 
				
			||||||
 | 
					void Internal_SceneAddNode(Scene *self, SceneNode node) {
 | 
				
			||||||
 | 
					    ASSERT_RETURN(list_find(&self->nodes, &node) == self->nodes.len,, "Attempting to add node that is already in this scene");
 | 
				
			||||||
 | 
					    ASSERT_RETURN(node.scene != NULL,, "Attempting to add node that is already in a scene, remove it from that scene first");
 | 
				
			||||||
 | 
					    list_add(&self->nodes, &node);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SceneNode *CreateSceneNode() {
 | 
				
			||||||
 | 
					    SceneNode *node = new(SceneNode);
 | 
				
			||||||
 | 
					    ASSERT_RETURN(node != NULL, NULL, "CreateSceneNode: Failed to instantiate new SceneNode");
 | 
				
			||||||
 | 
					    node->children = list_from_type(SceneNode*);
 | 
				
			||||||
 | 
					    return node;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void DestroySceneNode(SceneNode *self) {
 | 
				
			||||||
 | 
					    // remove all children from scene as well
 | 
				
			||||||
 | 
					    list_foreach(SceneNode **, child, &self->children)
 | 
				
			||||||
 | 
					        DestroySceneNode(*child);
 | 
				
			||||||
 | 
					    // inform entity of exit tree event
 | 
				
			||||||
 | 
					    self->entity.tc->exit_tree(self->entity.data);
 | 
				
			||||||
 | 
					    // remove node from scene if it is part of one
 | 
				
			||||||
 | 
					    if(self->scene != NULL)
 | 
				
			||||||
 | 
					        Internal_SceneRemoveNode(self->scene, self);
 | 
				
			||||||
 | 
					    if(self->entity.data != NULL) {
 | 
				
			||||||
 | 
					        self->entity.drop->drop(self->entity.data);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    free(self);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SceneNode *SceneNodeGetChild(SceneNode *self, size_t idx) {
 | 
				
			||||||
 | 
					    return *list_at_as(SceneNode*, &self->children, idx);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SceneNodeAddChild(SceneNode *self, SceneNode *child) {
 | 
				
			||||||
 | 
					    // catch logic error of trying to attach a child that already has a parent
 | 
				
			||||||
 | 
					    ASSERT_RETURN(child->parent != NULL,, "SceneNodeAddChild: New child node already has a parent");
 | 
				
			||||||
 | 
					    // register parent-child relationship
 | 
				
			||||||
 | 
					    list_add(&self->children, &child);
 | 
				
			||||||
 | 
					    child->parent = self;
 | 
				
			||||||
 | 
					    // make sure scene matches
 | 
				
			||||||
 | 
					    child->scene = self->scene;
 | 
				
			||||||
 | 
					    // notify child of scene entrance
 | 
				
			||||||
 | 
					    child->entity.tc->enter_tree(child->entity.data);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void SceneNodeRemoveChild(SceneNode *self, SceneNode *child) {
 | 
				
			||||||
 | 
					    // catch error of attempting to remove non-child node
 | 
				
			||||||
 | 
					    ASSERT_RETURN(child->parent == self,, "SceneNodeRemoveChild: Cannot remove node that is not a child of this node.");
 | 
				
			||||||
 | 
					    // get the index and use it to ensure that the child is actually registered with the parent
 | 
				
			||||||
 | 
					    size_t const idx = list_find(&self->children, child);
 | 
				
			||||||
 | 
					    ASSERT_RETURN(idx == self->children.len,, "IMPORTANT: SceneNodeRemoveChild: child is not registered with parent.");
 | 
				
			||||||
 | 
					    // we now know that the child is actually a child of self.
 | 
				
			||||||
 | 
					    // notify child that it is being removed from the tree.
 | 
				
			||||||
 | 
					    child->entity.tc->exit_tree(child->entity.data);
 | 
				
			||||||
 | 
					    // use the index to erase the object from the list
 | 
				
			||||||
 | 
					    list_erase(&self->children, idx);
 | 
				
			||||||
 | 
					    Internal_SceneRemoveNode(child->scene, child);
 | 
				
			||||||
 | 
					    child->scene = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void Internal_SceneNodeAttachEntity(SceneNodeEntity object) {
 | 
				
			||||||
 | 
					    object.tc->get_node(object.data)->entity = object;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					Scene *CreateScene(SceneNode const *root) {
 | 
				
			||||||
 | 
					    Scene *scene = new(Scene);
 | 
				
			||||||
 | 
					    scene->nodes = list_from_type(SceneNode);
 | 
				
			||||||
 | 
					    Internal_SceneAddNode(scene, *root);
 | 
				
			||||||
 | 
					    root->entity.tc->enter_tree(root->entity.data);
 | 
				
			||||||
 | 
					    return scene;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										27
									
								
								src/core/scene.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										27
									
								
								src/core/scene.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,27 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "stddef.h"
 | 
				
			||||||
 | 
					#include "utils/typeclass_helpers.h"
 | 
				
			||||||
 | 
					typedef struct SceneNodeEntity SceneNodeEntity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct SceneNode SceneNode;
 | 
				
			||||||
 | 
					typedef struct Scene Scene;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//! Instantiate a new scene node.
 | 
				
			||||||
 | 
					extern SceneNode *CreateSceneNode();
 | 
				
			||||||
 | 
					//! Free a scene node.
 | 
				
			||||||
 | 
					extern void DestroySceneNode(SceneNode *self);
 | 
				
			||||||
 | 
					//! Get a child from a scene node.
 | 
				
			||||||
 | 
					extern SceneNode *SceneNodeGetChild(SceneNode *self, size_t idx);
 | 
				
			||||||
 | 
					//! Attach a child to a node
 | 
				
			||||||
 | 
					extern void SceneNodeAddChild(SceneNode *self, SceneNode *child);
 | 
				
			||||||
 | 
					//! Detach a child from a node, removing it from the scene
 | 
				
			||||||
 | 
					extern void SceneNodeRemoveChild(SceneNode *self, SceneNode *child);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//! INTERNAL FUNCTION, used to attach a scene node entity typeclass to an object.
 | 
				
			||||||
 | 
					extern void Internal_SceneNodeAttachEntity(SceneNodeEntity object);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//! Instantiate a new scene with a root node.
 | 
				
			||||||
 | 
					extern Scene *CreateScene(SceneNode const *root);
 | 
				
			||||||
 | 
					//! Destroy a node and it's scene tree.
 | 
				
			||||||
 | 
					extern void DestroyScene(Scene *scene);
 | 
				
			||||||
							
								
								
									
										47
									
								
								src/core/scene_node_entity.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								src/core/scene_node_entity.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,47 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "scene.h"
 | 
				
			||||||
 | 
					#include "utils/mirror.h"
 | 
				
			||||||
 | 
					#include "utils/drop.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					struct SceneNode;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct ISceneNodeEntity {
 | 
				
			||||||
 | 
					    void(*const enter_tree)(void *self);
 | 
				
			||||||
 | 
					    void(*const exit_tree)(void *self);
 | 
				
			||||||
 | 
					    void(*const tick)(void *self, double delta);
 | 
				
			||||||
 | 
					    struct SceneNode *(*const get_node)(void *self);
 | 
				
			||||||
 | 
					    void (*const set_node)(void *self, struct SceneNode *node);
 | 
				
			||||||
 | 
					} ISceneNodeEntity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct SceneNodeEntity {
 | 
				
			||||||
 | 
					    ISceneNodeEntity const *tc;
 | 
				
			||||||
 | 
					    void *data;
 | 
				
			||||||
 | 
					    IMirror const *mirror;
 | 
				
			||||||
 | 
					    IDrop const *drop;
 | 
				
			||||||
 | 
					} SceneNodeEntity;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					//! Implement SceneNodeEntity for a struct.
 | 
				
			||||||
 | 
					//! IMPORTANT: requires Mirror and Drop to be implemented,
 | 
				
			||||||
 | 
					//! as well as a `SceneNode *node` member on T.
 | 
				
			||||||
 | 
					//! Generates functions called T##_get_node_GEN_ and T##_set_node_GEN_ as getter and setter for that member.
 | 
				
			||||||
 | 
					#define impl_SceneNodeEntity_for(T, enter_tree_f, exit_tree_f, tick_f)\
 | 
				
			||||||
 | 
					static struct SceneNode *T##_get_node_GEN_(T *self) { return self->node; }\
 | 
				
			||||||
 | 
					static void T##_set_node_GEN_(T *self, struct SceneNode *node) { self->node = node; }\
 | 
				
			||||||
 | 
					SceneNodeEntity T##AttachToSceneNode(T* x, SceneNode *node) {\
 | 
				
			||||||
 | 
					    TC_FN_TYPECHECK(void, enter_tree_f, T*);\
 | 
				
			||||||
 | 
					    TC_FN_TYPECHECK(void, exit_tree_f, T*);\
 | 
				
			||||||
 | 
					    TC_FN_TYPECHECK(void, tick_f, T*, double);\
 | 
				
			||||||
 | 
					    static ISceneNodeEntity const tc = {\
 | 
				
			||||||
 | 
					        .enter_tree     = (void(*const)(void*))                     enter_tree_f,\
 | 
				
			||||||
 | 
					        .exit_tree      = (void(*const)(void*))                     exit_tree_f,\
 | 
				
			||||||
 | 
					        .tick           = (void(*const)(void*,double))              tick_f,\
 | 
				
			||||||
 | 
					        .get_node       = (struct SceneNode *(*const)(void*))       T##_get_node_GEN_,\
 | 
				
			||||||
 | 
					        .set_node       = (void (*const)(void*, struct SceneNode*)) T##_set_node_GEN_\
 | 
				
			||||||
 | 
					    };\
 | 
				
			||||||
 | 
					    Internal_AttachToSceneNode(object);\
 | 
				
			||||||
 | 
					    x->node = node;\
 | 
				
			||||||
 | 
					    SceneNodeEntity e = { .tc = &tc, .data = x, .mirror = T##_as_Mirror(x).tc, .drop = T##_as_Drop(x).tc };\
 | 
				
			||||||
 | 
					    Internal_SceneNodeAttachEntity(e);\
 | 
				
			||||||
 | 
					    return e;\
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										19
									
								
								src/core/transformable.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										19
									
								
								src/core/transformable.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,19 @@
 | 
				
			||||||
 | 
					#include "transformable.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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;
 | 
				
			||||||
 | 
					    return mat;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					void UpdateTransformable(Transformable *self, Transformable *parent) {
 | 
				
			||||||
 | 
					    Transform *parent_global = self->tc->get_global_transform(self->data);
 | 
				
			||||||
 | 
					    Transform *global = self->tc->get_global_transform(self->data);
 | 
				
			||||||
 | 
					    Transform *local = self->tc->get_transform(self->data);
 | 
				
			||||||
 | 
					    global->translation = Vector3Add(parent_global->translation, local->translation);
 | 
				
			||||||
 | 
					    global->rotation = QuaternionMultiply(parent_global->rotation, local->rotation);
 | 
				
			||||||
 | 
					    global->scale = Vector3Multiply(parent_global->scale, local->scale);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										31
									
								
								src/core/transformable.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										31
									
								
								src/core/transformable.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,31 @@
 | 
				
			||||||
 | 
					#pragma once
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "utils/mirror.h"
 | 
				
			||||||
 | 
					#include "utils/typeclass_helpers.h"
 | 
				
			||||||
 | 
					#include "raylib.h"
 | 
				
			||||||
 | 
					#include "raymath.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct ITransformable {
 | 
				
			||||||
 | 
					    Transform *(*const get_transform)(void*);
 | 
				
			||||||
 | 
					    Transform *(*const get_global_transform)(void*);
 | 
				
			||||||
 | 
					} ITransformable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					typedef struct Transformable {
 | 
				
			||||||
 | 
					    ITransformable const *tc;
 | 
				
			||||||
 | 
					    void *data;
 | 
				
			||||||
 | 
					    IMirror const *mirror;
 | 
				
			||||||
 | 
					} Transformable;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					extern Matrix TransformGetMatrix(Transform const *self);
 | 
				
			||||||
 | 
					extern void UpdateTransformable(Transformable *self, Transformable *parent);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define impl_Transformable_for(T, get_transform_f)\
 | 
				
			||||||
 | 
					Transformable T##_as_Transformable(T *x) {\
 | 
				
			||||||
 | 
					    TC_FN_TYPECHECK(Transform, get_transform_f, T*);\
 | 
				
			||||||
 | 
					    static ITransformable const tc = {\
 | 
				
			||||||
 | 
					        .get_transform        = (Transform *(*const)(void*)) get_transform_f,\
 | 
				
			||||||
 | 
					        .get_global_transform = (Transform *(*const)(void*)) get_global_transform_f\
 | 
				
			||||||
 | 
					    };\
 | 
				
			||||||
 | 
					    return { .tc = &tc, data = x, .mirror = T##_as_Mirror(x).tc };\
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
		Loading…
	
		Reference in a new issue