|  | // | 
        
          |  |  | 
        
          |  | #include <SDL3/SDL.h> | 
        
          |  | #include <glad/gl.h> | 
        
          |  | #include <stdio.h> | 
        
          |  | #include <stdlib.h> | 
        
          |  |  | 
        
          |  | #include <cimgui.h> | 
        
          |  | #include <cimgui_impl.h> | 
        
          |  |  | 
        
          |  | #include "module_font.h" | 
        
          |  | #include <cglm/cglm.h> // Include CGLM | 
        
          |  | #include "flecs.h" | 
        
          |  |  | 
        
          |  | #define igGetIO igGetIO_Nil | 
        
          |  |  | 
        
          |  | typedef struct { | 
        
          |  | float x; | 
        
          |  | float y; | 
        
          |  | } Position; | 
        
          |  |  | 
        
          |  | typedef struct { | 
        
          |  | float x; | 
        
          |  | float y; | 
        
          |  | } Velocity; | 
        
          |  |  | 
        
          |  |  | 
        
          |  | typedef struct { | 
        
          |  | vec3 position; // Vector3 for position (x, y, z) | 
        
          |  | vec3 rotation; // Euler angles in degrees (x, y, z) | 
        
          |  | vec3 scale;    // Scale (x, y, z) | 
        
          |  | mat4 local;    // Local transformation matrix | 
        
          |  | mat4 world;    // World transformation matrix | 
        
          |  | bool isDirty;  // Flag to indicate if transform needs recalculation | 
        
          |  | } Transform3D; | 
        
          |  | ECS_COMPONENT_DECLARE(Transform3D); | 
        
          |  |  | 
        
          |  | typedef struct { | 
        
          |  | GLuint vao, vbo, ebo; // OpenGL buffer objects | 
        
          |  | GLuint shaderProgram; // Shader program for the cube | 
        
          |  | int indexCount;       // Number of indices for rendering | 
        
          |  | } CubeContext; | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // Cube vertices: position (x, y, z) | 
        
          |  | static const float cubeVertices[] = { | 
        
          |  | // Front face | 
        
          |  | -0.5f, -0.5f,  0.5f, // 0 | 
        
          |  | 0.5f, -0.5f,  0.5f, // 1 | 
        
          |  | 0.5f,  0.5f,  0.5f, // 2 | 
        
          |  | -0.5f,  0.5f,  0.5f, // 3 | 
        
          |  | // Back face | 
        
          |  | -0.5f, -0.5f, -0.5f, // 4 | 
        
          |  | 0.5f, -0.5f, -0.5f, // 5 | 
        
          |  | 0.5f,  0.5f, -0.5f, // 6 | 
        
          |  | -0.5f,  0.5f, -0.5f  // 7 | 
        
          |  | }; | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // Indices for the cube (6 faces, 2 triangles per face, 3 vertices per triangle) | 
        
          |  | static const unsigned int cubeIndices[] = { | 
        
          |  | // Front | 
        
          |  | 0, 1, 2,  2, 3, 0, | 
        
          |  | // Right | 
        
          |  | 1, 5, 6,  6, 2, 1, | 
        
          |  | // Back | 
        
          |  | 5, 4, 7,  7, 6, 5, | 
        
          |  | // Left | 
        
          |  | 4, 0, 3,  3, 7, 4, | 
        
          |  | // Top | 
        
          |  | 3, 2, 6,  6, 7, 3, | 
        
          |  | // Bottom | 
        
          |  | 4, 5, 1,  1, 0, 4 | 
        
          |  | }; | 
        
          |  |  | 
        
          |  | bool init_cube_mesh(CubeContext* cube) { | 
        
          |  | // Vertex Shader | 
        
          |  | const char* vertexShaderSource = "#version 330 core\n" | 
        
          |  | "layout (location = 0) in vec3 aPos;\n" | 
        
          |  | "uniform mat4 model;\n" | 
        
          |  | "uniform mat4 view;\n" | 
        
          |  | "uniform mat4 projection;\n" | 
        
          |  | "void main() {\n" | 
        
          |  | "   gl_Position = projection * view * model * vec4(aPos, 1.0);\n" | 
        
          |  | "}\n"; | 
        
          |  |  | 
        
          |  | // Fragment Shader (simple color) | 
        
          |  | const char* fragmentShaderSource = "#version 330 core\n" | 
        
          |  | "out vec4 FragColor;\n" | 
        
          |  | "void main() {\n" | 
        
          |  | "   FragColor = vec4(1.0, 0.5, 0.2, 1.0);\n" // Orange color | 
        
          |  | "}\n"; | 
        
          |  |  | 
        
          |  | // Compile shaders | 
        
          |  | GLuint vertexShader = glCreateShader(GL_VERTEX_SHADER); | 
        
          |  | glShaderSource(vertexShader, 1, &vertexShaderSource, NULL); | 
        
          |  | glCompileShader(vertexShader); | 
        
          |  | GLint success; | 
        
          |  | glGetShaderiv(vertexShader, GL_COMPILE_STATUS, &success); | 
        
          |  | if (!success) { | 
        
          |  | char infoLog[512]; | 
        
          |  | glGetShaderInfoLog(vertexShader, 512, NULL, infoLog); | 
        
          |  | printf("Vertex Shader Compilation Failed: %s\n", infoLog); | 
        
          |  | return false; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | GLuint fragmentShader = glCreateShader(GL_FRAGMENT_SHADER); | 
        
          |  | glShaderSource(fragmentShader, 1, &fragmentShaderSource, NULL); | 
        
          |  | glCompileShader(fragmentShader); | 
        
          |  | glGetShaderiv(fragmentShader, GL_COMPILE_STATUS, &success); | 
        
          |  | if (!success) { | 
        
          |  | char infoLog[512]; | 
        
          |  | glGetShaderInfoLog(fragmentShader, 512, NULL, infoLog); | 
        
          |  | printf("Fragment Shader Compilation Failed: %s\n", infoLog); | 
        
          |  | return false; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | cube->shaderProgram = glCreateProgram(); | 
        
          |  | glAttachShader(cube->shaderProgram, vertexShader); | 
        
          |  | glAttachShader(cube->shaderProgram, fragmentShader); | 
        
          |  | glLinkProgram(cube->shaderProgram); | 
        
          |  | glGetProgramiv(cube->shaderProgram, GL_LINK_STATUS, &success); | 
        
          |  | if (!success) { | 
        
          |  | char infoLog[512]; | 
        
          |  | glGetProgramInfoLog(cube->shaderProgram, 512, NULL, infoLog); | 
        
          |  | printf("Shader Program Linking Failed: %s\n", infoLog); | 
        
          |  | return false; | 
        
          |  | } | 
        
          |  | glDeleteShader(vertexShader); | 
        
          |  | glDeleteShader(fragmentShader); | 
        
          |  |  | 
        
          |  | // Setup VAO, VBO, EBO | 
        
          |  | glGenVertexArrays(1, &cube->vao); | 
        
          |  | glGenBuffers(1, &cube->vbo); | 
        
          |  | glGenBuffers(1, &cube->ebo); | 
        
          |  |  | 
        
          |  | glBindVertexArray(cube->vao); | 
        
          |  |  | 
        
          |  | glBindBuffer(GL_ARRAY_BUFFER, cube->vbo); | 
        
          |  | glBufferData(GL_ARRAY_BUFFER, sizeof(cubeVertices), cubeVertices, GL_STATIC_DRAW); | 
        
          |  |  | 
        
          |  | glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, cube->ebo); | 
        
          |  | glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cubeIndices), cubeIndices, GL_STATIC_DRAW); | 
        
          |  |  | 
        
          |  | glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0); | 
        
          |  | glEnableVertexAttribArray(0); | 
        
          |  |  | 
        
          |  | glBindVertexArray(0); | 
        
          |  |  | 
        
          |  | cube->indexCount = sizeof(cubeIndices) / sizeof(cubeIndices[0]); | 
        
          |  | return true; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | void update_transform_system(ecs_iter_t *it) { | 
        
          |  | Transform3D *transforms = ecs_field(it, Transform3D, 0); | 
        
          |  | for (int i = 0; i < it->count; i++) { | 
        
          |  | if (!transforms[i].isDirty) continue; | 
        
          |  | mat4 local; | 
        
          |  | glm_mat4_identity(local); | 
        
          |  | glm_scale(local, transforms[i].scale); | 
        
          |  | glm_rotate_x(local, glm_rad(transforms[i].rotation[0]), local); | 
        
          |  | glm_rotate_y(local, glm_rad(transforms[i].rotation[1]), local); | 
        
          |  | glm_rotate_z(local, glm_rad(transforms[i].rotation[2]), local); | 
        
          |  | glm_translate(local, transforms[i].position); | 
        
          |  | glm_mat4_copy(local, transforms[i].local); | 
        
          |  | glm_mat4_copy(local, transforms[i].world); // No parent transform | 
        
          |  | transforms[i].isDirty = false; | 
        
          |  | printf("Updated transform %d: Pos=(%.2f, %.2f, %.2f)\n", | 
        
          |  | i, transforms[i].position[0], transforms[i].position[1], transforms[i].position[2]); | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  | // void update_transform_system(ecs_iter_t *it) { | 
        
          |  | //     Transform3D *transforms = ecs_field(it, Transform3D, 0); | 
        
          |  | //     for (int i = 0; i < it->count; i++) { | 
        
          |  | //         if (!transforms[i].isDirty) continue; | 
        
          |  | //         // Calculate local matrix | 
        
          |  | //         mat4 local; | 
        
          |  | //         glm_mat4_identity(local); | 
        
          |  | //         // Apply scale | 
        
          |  | //         glm_scale(local, transforms[i].scale); | 
        
          |  | //         // Apply rotation (Euler angles in degrees) | 
        
          |  | //         glm_rotate_x(local, glm_rad(transforms[i].rotation[0]), local); | 
        
          |  | //         glm_rotate_y(local, glm_rad(transforms[i].rotation[1]), local); | 
        
          |  | //         glm_rotate_z(local, glm_rad(transforms[i].rotation[2]), local); | 
        
          |  | //         // Apply translation | 
        
          |  | //         glm_translate(local, transforms[i].position); | 
        
          |  | //         glm_mat4_copy(local, transforms[i].local); | 
        
          |  | //         // Check for parent transform | 
        
          |  | //         ecs_entity_t parent = ecs_get_parent(it->world, it->entities[i]); | 
        
          |  | //         if (parent && ecs_has(it->world, parent, Transform3D)) { | 
        
          |  | //             Transform3D *parent_transform = ecs_get_mut(it->world, parent, Transform3D); | 
        
          |  | //             mat4 world; | 
        
          |  | //             glm_mat4_mul(parent_transform->world, local, world); | 
        
          |  | //             glm_mat4_copy(world, transforms[i].world); | 
        
          |  | //         } else { | 
        
          |  | //             glm_mat4_copy(local, transforms[i].world); | 
        
          |  | //         } | 
        
          |  | //         transforms[i].isDirty = false; | 
        
          |  | //     } | 
        
          |  | // } | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  | void render_3d_cube_system(ecs_iter_t *it) { | 
        
          |  | Transform3D *transforms = ecs_field(it, Transform3D, 0); | 
        
          |  | CubeContext *cube = (CubeContext *)ecs_get_ctx(it->world); | 
        
          |  |  | 
        
          |  | if (!cube) { | 
        
          |  | printf("CubeContext is NULL in render_3d_cube_system!\n"); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | printf("Rendering %d cubes\n", it->count); | 
        
          |  | if (it->count == 0) { | 
        
          |  | printf("No entities with Transform3D found!\n"); | 
        
          |  | return; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | glUseProgram(cube->shaderProgram); | 
        
          |  |  | 
        
          |  | // Ensure depth testing is enabled | 
        
          |  | glEnable(GL_DEPTH_TEST); | 
        
          |  |  | 
        
          |  | // Setup view and projection matrices | 
        
          |  | mat4 view, projection; | 
        
          |  | glm_mat4_identity(view); | 
        
          |  | glm_lookat((vec3){0.0f, 0.0f, 5.0f}, (vec3){0.0f, 0.0f, 0.0f}, (vec3){0.0f, 1.0f, 0.0f}, view); | 
        
          |  |  | 
        
          |  | int ww, hh; | 
        
          |  | SDL_GetWindowSize(SDL_GL_GetCurrentWindow(), &ww, &hh); | 
        
          |  | glm_perspective(glm_rad(45.0f), (float)ww / hh, 0.1f, 100.0f, projection); | 
        
          |  |  | 
        
          |  | GLint modelLoc = glGetUniformLocation(cube->shaderProgram, "model"); | 
        
          |  | GLint viewLoc = glGetUniformLocation(cube->shaderProgram, "view"); | 
        
          |  | GLint projLoc = glGetUniformLocation(cube->shaderProgram, "projection"); | 
        
          |  |  | 
        
          |  | glUniformMatrix4fv(viewLoc, 1, GL_FALSE, (float*)view); | 
        
          |  | glUniformMatrix4fv(projLoc, 1, GL_FALSE, (float*)projection); | 
        
          |  |  | 
        
          |  | glBindVertexArray(cube->vao); | 
        
          |  | for (int i = 0; i < it->count; i++) { | 
        
          |  | printf("Rendering cube %d: Pos=(%.2f, %.2f, %.2f), Rot=(%.2f, %.2f, %.2f), Scale=(%.2f, %.2f, %.2f)\n", | 
        
          |  | i, transforms[i].position[0], transforms[i].position[1], transforms[i].position[2], | 
        
          |  | transforms[i].rotation[0], transforms[i].rotation[1], transforms[i].rotation[2], | 
        
          |  | transforms[i].scale[0], transforms[i].scale[1], transforms[i].scale[2]); | 
        
          |  | glUniformMatrix4fv(modelLoc, 1, GL_FALSE, (float*)transforms[i].world); | 
        
          |  | glDrawElements(GL_TRIANGLES, cube->indexCount, GL_UNSIGNED_INT, 0); | 
        
          |  | } | 
        
          |  | glBindVertexArray(0); | 
        
          |  |  | 
        
          |  | // Check for OpenGL errors | 
        
          |  | GLenum err; | 
        
          |  | while ((err = glGetError()) != GL_NO_ERROR) { | 
        
          |  | printf("OpenGL Error in render_3d_cube_system: %u\n", err); | 
        
          |  | } | 
        
          |  | } | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // nope error on attach child | 
        
          |  | // void start_up_system(ecs_iter_t *it) { | 
        
          |  | //     printf("start up\n"); | 
        
          |  | //     // Create parent cube | 
        
          |  | //     ecs_entity_t parent = ecs_entity(it->world, { .name = "ParentCube" }); | 
        
          |  | //     ecs_set(it->world, parent, Transform3D, { | 
        
          |  | //         .position = {0.0f, 0.0f, 0.0f}, | 
        
          |  | //         .rotation = {0.0f, 0.0f, 0.0f}, | 
        
          |  | //         .scale = {1.0f, 1.0f, 1.0f}, | 
        
          |  | //         .isDirty = true | 
        
          |  | //     }); | 
        
          |  | //     // Create child cube | 
        
          |  | //     ecs_entity_t child = ecs_entity(it->world, { .name = "ChildCube" }); | 
        
          |  | //     ecs_set(it->world, child, Transform3D, { | 
        
          |  | //         .position = {2.0f, 0.0f, 0.0f}, // Offset from parent | 
        
          |  | //         .rotation = {0.0f, 45.0f, 0.0f}, | 
        
          |  | //         .scale = {0.5f, 0.5f, 0.5f}, | 
        
          |  | //         .isDirty = true | 
        
          |  | //     }); | 
        
          |  | //     ecs_add_pair(it->world, child, EcsChildOf, parent); | 
        
          |  | //     // Initialize cube mesh | 
        
          |  | //     CubeContext* cube = malloc(sizeof(CubeContext)); | 
        
          |  | //     if (!init_cube_mesh(cube)) { | 
        
          |  | //         printf("Failed to initialize cube mesh\n"); | 
        
          |  | //         return; | 
        
          |  | //     } | 
        
          |  | //     ecs_set_ctx(it->world, cube, NULL); | 
        
          |  | // } | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  | int main() { | 
        
          |  | if (!SDL_Init(SDL_INIT_VIDEO | SDL_INIT_GAMEPAD)) { | 
        
          |  | fprintf(stderr, "Failed to init video! %s\n", SDL_GetError()); | 
        
          |  | return 1; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | float main_scale = SDL_GetDisplayContentScale(SDL_GetPrimaryDisplay()); | 
        
          |  | SDL_WindowFlags window_flags = SDL_WINDOW_RESIZABLE | SDL_WINDOW_HIDDEN | SDL_WINDOW_HIGH_PIXEL_DENSITY | SDL_WINDOW_OPENGL; | 
        
          |  | SDL_Window* window = SDL_CreateWindow("SDL3 OpenGL Font Tranformer 3d", (int)(1280 * main_scale), (int)(720 * main_scale), window_flags); | 
        
          |  | if (!window) { | 
        
          |  | printf("Error: SDL_CreateWindow(): %s\n", SDL_GetError()); | 
        
          |  | SDL_Quit(); | 
        
          |  | return -1; | 
        
          |  | } | 
        
          |  | SDL_SetWindowPosition(window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED); | 
        
          |  | SDL_ShowWindow(window); | 
        
          |  |  | 
        
          |  | // Create OpenGL context | 
        
          |  | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); | 
        
          |  | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); | 
        
          |  | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | 
        
          |  | SDL_GLContext gl_context = SDL_GL_CreateContext(window); | 
        
          |  | if (!gl_context) { | 
        
          |  | printf("Error: SDL_GL_CreateContext(): %s\n", SDL_GetError()); | 
        
          |  | SDL_DestroyWindow(window); | 
        
          |  | SDL_Quit(); | 
        
          |  | return -1; | 
        
          |  | } | 
        
          |  | SDL_GL_MakeCurrent(window, gl_context); | 
        
          |  |  | 
        
          |  | int version = gladLoadGL((GLADloadfunc)SDL_GL_GetProcAddress); | 
        
          |  | if (version == 0) { | 
        
          |  | printf("Failed to initialize GLAD\n"); | 
        
          |  | SDL_GL_DestroyContext(gl_context); | 
        
          |  | SDL_DestroyWindow(window); | 
        
          |  | SDL_Quit(); | 
        
          |  | return 1; | 
        
          |  | } | 
        
          |  | printf("OpenGL loaded: version %s\n", glGetString(GL_VERSION)); | 
        
          |  |  | 
        
          |  | FontData *font_data = NULL; | 
        
          |  | if (!init_font("resources/Kenney Mini.ttf", 32.0f, main_scale, &font_data)) { | 
        
          |  | SDL_GL_DestroyContext(gl_context); | 
        
          |  | SDL_DestroyWindow(window); | 
        
          |  | SDL_Quit(); | 
        
          |  | return -1; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | // Initialize shaders and buffers | 
        
          |  | GLuint program, vao, vbo; | 
        
          |  | if (!init_font_shaders_and_buffers(&program, &vao, &vbo)) { | 
        
          |  | // cleanup_font(&font_data); | 
        
          |  | cleanup_font(font_data); | 
        
          |  | SDL_GL_DestroyContext(gl_context); | 
        
          |  | SDL_DestroyWindow(window); | 
        
          |  | SDL_Quit(); | 
        
          |  | return -1; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | // Setup Dear ImGui context | 
        
          |  | igCreateContext(NULL); | 
        
          |  | ImGuiIO* io = igGetIO(); | 
        
          |  | io->ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; | 
        
          |  | io->ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; | 
        
          |  |  | 
        
          |  | // Setup Dear ImGui style | 
        
          |  | igStyleColorsDark(NULL); | 
        
          |  | ImGuiStyle* style = igGetStyle(); | 
        
          |  | ImGuiStyle_ScaleAllSizes(style, main_scale); | 
        
          |  |  | 
        
          |  | // Setup Platform/Renderer backends | 
        
          |  | ImGui_ImplSDL3_InitForOpenGL(window, gl_context); | 
        
          |  | ImGui_ImplOpenGL3_Init("#version 330"); | 
        
          |  |  | 
        
          |  | // Our state | 
        
          |  | bool show_demo_window = true; | 
        
          |  | bool show_another_window = false; | 
        
          |  |  | 
        
          |  | float clear_colorE4[4] = {0.45f, 0.55f, 0.60f, 1.00f}; | 
        
          |  |  | 
        
          |  | ImVec4 clearColorE3; | 
        
          |  | clearColorE3.x = 0.45f; | 
        
          |  | clearColorE3.y = 0.55f; | 
        
          |  | clearColorE3.z = 0.60f; | 
        
          |  | clearColorE3.w = 1.00f; | 
        
          |  |  | 
        
          |  | glEnable(GL_BLEND); | 
        
          |  | glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | 
        
          |  |  | 
        
          |  | float clear_color[4] = {0.45f, 0.55f, 0.60f, 1.00f}; | 
        
          |  | bool done = false; | 
        
          |  | const char* text = "Hello World! Glad 2.0.8"; | 
        
          |  |  | 
        
          |  |  | 
        
          |  | ecs_world_t *world = ecs_init(); | 
        
          |  | CubeContext* cube; | 
        
          |  |  | 
        
          |  | ECS_COMPONENT(world, Position); | 
        
          |  | ECS_COMPONENT(world, Velocity); | 
        
          |  | // ECS_COMPONENT(world, CubeContext); | 
        
          |  | ECS_COMPONENT(world, Transform3D); | 
        
          |  |  | 
        
          |  | // EcsOnStart | 
        
          |  | // EcsPreUpdate | 
        
          |  | // EcsOnUpdate | 
        
          |  | // EcsPostUpdate | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // start up system | 
        
          |  | // ECS_SYSTEM(world, start_up_system, EcsOnStart); | 
        
          |  | ECS_SYSTEM(world, update_transform_system, EcsPreUpdate, Transform3D); | 
        
          |  | //render 3d cube | 
        
          |  | ECS_SYSTEM(world, render_3d_cube_system, EcsOnUpdate, Transform3D); | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // Create parent cube | 
        
          |  | ecs_entity_t parent = ecs_entity(world, { .name = "ParentCube" }); | 
        
          |  | ecs_set(world, parent, Transform3D, { | 
        
          |  | .position = {0.0f, 0.0f, 0.0f}, | 
        
          |  | .rotation = {0.0f, 0.0f, 0.0f}, | 
        
          |  | .scale = {1.0f, 1.0f, 1.0f}, | 
        
          |  | .isDirty = true | 
        
          |  | }); | 
        
          |  |  | 
        
          |  | // Create child cube | 
        
          |  | ecs_entity_t child = ecs_entity(world, { .name = "ChildCube" }); | 
        
          |  | ecs_set(world, child, Transform3D, { | 
        
          |  | // .position = {2.0f, 0.0f, 0.0f}, // Offset from parent | 
        
          |  | .position = {0.0f, 0.0f, 0.0f}, // Offset from parent | 
        
          |  | // .rotation = {0.0f, 0.0f, 0.0f}, | 
        
          |  | .rotation = {0.0f, 45.0f, 0.0f}, | 
        
          |  | .scale = {1.0f, 1.0f, 1.0f}, | 
        
          |  | .isDirty = true | 
        
          |  | }); | 
        
          |  | ecs_add_pair(world, child, EcsChildOf, parent); | 
        
          |  |  | 
        
          |  | // Initialize cube mesh | 
        
          |  | cube = malloc(sizeof(CubeContext)); | 
        
          |  | if (!init_cube_mesh(cube)) { | 
        
          |  | printf("Failed to initialize cube mesh\n"); | 
        
          |  | // return; | 
        
          |  | } | 
        
          |  | ecs_set_ctx(world, cube, NULL); | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // Do the ECS stuff | 
        
          |  | ecs_entity_t e = ecs_entity(world, { .name = "Bob" }); | 
        
          |  | printf("Entity name: %s\n", ecs_get_name(world, e)); | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // glEnable(GL_DEPTH_TEST); | 
        
          |  |  | 
        
          |  | while (!done) { | 
        
          |  | SDL_Event event; | 
        
          |  | while (SDL_PollEvent(&event)) { | 
        
          |  | ImGui_ImplSDL3_ProcessEvent(&event); | 
        
          |  | if (event.type == SDL_EVENT_QUIT) | 
        
          |  | done = true; | 
        
          |  | if (event.type == SDL_EVENT_WINDOW_CLOSE_REQUESTED && event.window.windowID == SDL_GetWindowID(window)) | 
        
          |  | done = true; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | if (SDL_GetWindowFlags(window) & SDL_WINDOW_MINIMIZED) { | 
        
          |  | SDL_Delay(10); | 
        
          |  | continue; | 
        
          |  | } | 
        
          |  |  | 
        
          |  | // Start the Dear ImGui frame | 
        
          |  | ImGui_ImplOpenGL3_NewFrame(); | 
        
          |  | ImGui_ImplSDL3_NewFrame(); | 
        
          |  | igNewFrame(); | 
        
          |  |  | 
        
          |  | // Simple window | 
        
          |  | { | 
        
          |  | static float f = 0.0f; | 
        
          |  | static int counter = 0; | 
        
          |  | // igBegin("Hello, world!", NULL, 0); | 
        
          |  | // igText("This is some useful text."); | 
        
          |  | // igCheckbox("Demo Window", &show_demo_window); | 
        
          |  | // igCheckbox("Another Window", &show_another_window); | 
        
          |  | // igSliderFloat("float", &f, 0.0f, 1.0f, "%.3f", 0); | 
        
          |  | // igText("Choose a color:"); | 
        
          |  | // if(igColorEdit4("clear color E4", (float*)&clear_colorE4, 0)){ | 
        
          |  | //     // Log the new color values whenever they change | 
        
          |  | //     printf("Color changed to: R=%.2f, G=%.2f, B=%.2f, A=%.2f\n", | 
        
          |  | //         clear_colorE4[0], clear_colorE4[1], clear_colorE4[2], clear_colorE4[3]); | 
        
          |  | // } | 
        
          |  | // igColorEdit3("clear color E3", (float *)&clearColorE3, 0); | 
        
          |  |  | 
        
          |  | // ImVec2 buttonSize = {0, 0}; | 
        
          |  | // if (igButton("Button", buttonSize)) | 
        
          |  | //     counter++; | 
        
          |  | // igSameLine(0.0f, -1.0f); | 
        
          |  | // igText("counter = %d", counter); | 
        
          |  | // igText("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io->Framerate, io->Framerate); | 
        
          |  | // igEnd(); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | { | 
        
          |  | igBegin("transform3d", NULL, 0); | 
        
          |  | ImVec2 buttonSize = {0, 0}; | 
        
          |  | if (igButton("query", buttonSize)){ | 
        
          |  |  | 
        
          |  | } | 
        
          |  | igEnd(); | 
        
          |  | } | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // Rendering | 
        
          |  | igRender(); | 
        
          |  |  | 
        
          |  | int ww, hh; | 
        
          |  | SDL_GetWindowSize(window, &ww, &hh); | 
        
          |  | glViewport(0, 0, ww, hh); | 
        
          |  | glViewport(0, 0, (int)io->DisplaySize.x, (int)io->DisplaySize.y); //cimgui | 
        
          |  | glClearColor(clear_colorE4[0], clear_colorE4[1], clear_colorE4[2], clear_colorE4[3]); | 
        
          |  | // glClearColor(clear_color[0], clear_color[1], clear_color[2], clear_color[3]); | 
        
          |  | // glClear(GL_COLOR_BUFFER_BIT); | 
        
          |  | glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | 
        
          |  | // Enable depth testing for 3D rendering | 
        
          |  | glEnable(GL_DEPTH_TEST); | 
        
          |  |  | 
        
          |  | // Test cube rendering | 
        
          |  | // { | 
        
          |  | //     printf("Test cube rendering\n"); | 
        
          |  |  | 
        
          |  | //     glUseProgram(cube->shaderProgram); | 
        
          |  |  | 
        
          |  | //     // Setup view and projection matrices (same as render_3d_cube_system) | 
        
          |  | //     mat4 view, projection; | 
        
          |  | //     glm_mat4_identity(view); | 
        
          |  | //     glm_lookat((vec3){0.0f, 0.0f, 5.0f}, (vec3){0.0f, 0.0f, 0.0f}, (vec3){0.0f, 1.0f, 0.0f}, view); | 
        
          |  | //     glm_perspective(glm_rad(45.0f), (float)ww / hh, 0.1f, 100.0f, projection); | 
        
          |  |  | 
        
          |  | //     // Simple model matrix (e.g., translate to (0, 0, 0) with no rotation or scale) | 
        
          |  | //     mat4 model; | 
        
          |  | //     glm_mat4_identity(model); | 
        
          |  | //     // Optional: Translate to make sure it’s visible | 
        
          |  | //     glm_translate(model, (vec3){0.0f, 0.0f, 0.0f}); | 
        
          |  |  | 
        
          |  | //     // Set uniforms | 
        
          |  | //     GLint modelLoc = glGetUniformLocation(cube->shaderProgram, "model"); | 
        
          |  | //     GLint viewLoc = glGetUniformLocation(cube->shaderProgram, "view"); | 
        
          |  | //     GLint projLoc = glGetUniformLocation(cube->shaderProgram, "projection"); | 
        
          |  | //     glUniformMatrix4fv(modelLoc, 1, GL_FALSE, (float*)model); | 
        
          |  | //     glUniformMatrix4fv(viewLoc, 1, GL_FALSE, (float*)view); | 
        
          |  | //     glUniformMatrix4fv(projLoc, 1, GL_FALSE, (float*)projection); | 
        
          |  |  | 
        
          |  | //     // Draw the cube | 
        
          |  | //     glBindVertexArray(cube->vao); | 
        
          |  | //     glDrawElements(GL_TRIANGLES, cube->indexCount, GL_UNSIGNED_INT, 0); | 
        
          |  | //     glBindVertexArray(0); | 
        
          |  |  | 
        
          |  | //     // Check for OpenGL errors | 
        
          |  | //     GLenum err; | 
        
          |  | //     while ((err = glGetError()) != GL_NO_ERROR) { | 
        
          |  | //         printf("OpenGL Error during test render: %u\n", err); | 
        
          |  | //     } | 
        
          |  | // } | 
        
          |  |  | 
        
          |  |  | 
        
          |  | ecs_progress(world, 0); // run systems in default pipeline | 
        
          |  |  | 
        
          |  |  | 
        
          |  | // Render 2D text | 
        
          |  | // render_text(&font_data, program, vao, vbo, text, 25.0f, 150.0f, ww, hh, 1.0f, 1.0f, 1.0f, 1.0f);// test | 
        
          |  | render_text(font_data, program, vao, vbo, "Hello, World!", 100.0f, 100.0f, ww, hh, 1.0f, 1.0f, 1.0f, 1.0f); | 
        
          |  |  | 
        
          |  | ImGui_ImplOpenGL3_RenderDrawData(igGetDrawData()); | 
        
          |  | SDL_GL_SwapWindow(window); | 
        
          |  | } | 
        
          |  |  | 
        
          |  | // Cleanup | 
        
          |  |  | 
        
          |  | // CubeContext* cube = ecs_get_ctx(world); | 
        
          |  | // cube = ecs_get_ctx(world); | 
        
          |  | if (cube) { | 
        
          |  | glDeleteVertexArrays(1, &cube->vao); | 
        
          |  | glDeleteBuffers(1, &cube->vbo); | 
        
          |  | glDeleteBuffers(1, &cube->ebo); | 
        
          |  | glDeleteProgram(cube->shaderProgram); | 
        
          |  | free(cube); | 
        
          |  | } | 
        
          |  |  | 
        
          |  |  | 
        
          |  | ImGui_ImplOpenGL3_Shutdown(); | 
        
          |  | ImGui_ImplSDL3_Shutdown(); | 
        
          |  | igDestroyContext(NULL); | 
        
          |  |  | 
        
          |  | cleanup_font(font_data); // conflict due cimgui modified font match data type. | 
        
          |  | glDeleteProgram(program); | 
        
          |  | glDeleteBuffers(1, &vbo); | 
        
          |  | glDeleteVertexArrays(1, &vao); | 
        
          |  |  | 
        
          |  | ecs_fini(world); | 
        
          |  |  | 
        
          |  | SDL_GL_DestroyContext(gl_context); | 
        
          |  | SDL_DestroyWindow(window); | 
        
          |  | SDL_Quit(); | 
        
          |  |  | 
        
          |  | return 0; | 
        
          |  | } |