diff --git a/build b/build index 0c38577..b95fd09 100755 --- a/build +++ b/build @@ -1,13 +1,13 @@ #!/bin/bash LIB_INCLUDE="-lglfw -lGL -lm" -COMMON_FLAGS="-DOS_LINUX=1 -DCOMPOSITOR_WAYLAND=1 -xc -std=c99" +COMMON_FLAGS="-DOS_LINUX=1 -xc -std=c99" echo [Building target] if [ $DEBUG ]; then time clang -O0 -g -g2 $COMMON_FLAGS -DDJSTDLIB_DEBUG=1 ./src/main.c -o ./target/somaesque $LIB_INCLUDE else - time clang -O2 $COMMON_FLAGS ./src/main.c -o ./target/somaesque $LIB_INCLUDE + time clang -O3 $COMMON_FLAGS ./src/main.c -o ./target/somaesque $LIB_INCLUDE fi echo [Target built] diff --git a/src/debug.c b/src/debug.c new file mode 100644 index 0000000..17db16e --- /dev/null +++ b/src/debug.c @@ -0,0 +1,28 @@ +#include "lib/raymath.h" +#include "lib/djstdlib/core.h" +#include "debug.h" + +void printRLVec3(RLVector3* vector) { + RLVector3 vec = *vector; + print( + "┌ ┐\n" + "│%7.2f%, %7.2f, %7.2f │\n" + "└ ┘\n", + vec.x, vec.y, vec.z); +} + +void printMatrix(Matrix* matrix) { + Matrix mat = *matrix; + print( + "┌ ┐\n" + "│%7.2f%, %7.2f, %7.2f, %7.2f │\n" + "│%7.2f%, %7.2f, %7.2f, %7.2f │\n" + "│%7.2f%, %7.2f, %7.2f, %7.2f │\n" + "│%7.2f%, %7.2f, %7.2f, %7.2f │\n" + "└ ┘\n", + mat.m0, mat.m1, mat.m2, mat.m3, + mat.m4, mat.m5, mat.m6, mat.m7, + mat.m8, mat.m9, mat.m10, mat.m11, + mat.m12, mat.m13, mat.m14, mat.m15); +} + diff --git a/src/debug.h b/src/debug.h new file mode 100644 index 0000000..2b97be5 --- /dev/null +++ b/src/debug.h @@ -0,0 +1,9 @@ +#ifndef DEBUG_H +#define DEBUG_H + +#include "lib/raymath.h" + +void printRLVec3(RLVector3* vector); +void printMatrix(Matrix* matrix); + +#endif diff --git a/src/lib/djstdlib b/src/lib/djstdlib index 3f3ef53..0fcbb41 160000 --- a/src/lib/djstdlib +++ b/src/lib/djstdlib @@ -1 +1 @@ -Subproject commit 3f3ef5351fa083095984642bc408850deb23f7f1 +Subproject commit 0fcbb4154bb1f7900441d13f4f16a8769064b9f2 diff --git a/src/lib/raymath.h b/src/lib/raymath.h index 8a3ba21..47c056e 100644 --- a/src/lib/raymath.h +++ b/src/lib/raymath.h @@ -51,6 +51,8 @@ * **********************************************************************************************/ +// NOTE(djledda): this file has been modified from the original to rename types that conflict with other library types (RLVector4, RLVector3, RLVector2) + #ifndef RAYMATH_H #define RAYMATH_H diff --git a/src/main.c b/src/main.c index 0dd1243..0114b9c 100644 --- a/src/main.c +++ b/src/main.c @@ -1,71 +1,27 @@ +#define _POSIX_C_SOURCE 199309L +#include "time.h" + // Library initialisation #define RAYMATH_IMPLEMENTATION #define STB_IMAGE_IMPLEMENTATION #define TINYOBJ_LOADER_C_IMPLEMENTATION // Project -#include "SomaSolve.c" +#include "lib/djstdlib/core.c" #include "gfx/gfx.c" #include "world/world.c" +#include "ui.c" +#include "render.c" +#include "SomaSolve.c" #include "VoxelSpace.c" #include "./tests.c" -#include "lib/djstdlib/core.c" +#include "debug.c" // Graphics bindings and libs #include "lib/raymath.h" #include "lib/glad/glad.c" #include "GLFW/glfw3.h" -void printRLVec3(RLVector3* vector) { - RLVector3 vec = *vector; - print( - "┌ ┐\n" - "│%7.2f%, %7.2f, %7.2f │\n" - "└ ┘\n", - vec.x, vec.y, vec.z); -} - -void printMatrix(Matrix* matrix) { - Matrix mat = *matrix; - print( - "┌ ┐\n" - "│%7.2f%, %7.2f, %7.2f, %7.2f │\n" - "│%7.2f%, %7.2f, %7.2f, %7.2f │\n" - "│%7.2f%, %7.2f, %7.2f, %7.2f │\n" - "│%7.2f%, %7.2f, %7.2f, %7.2f │\n" - "└ ┘\n", - mat.m0, mat.m1, mat.m2, mat.m3, - mat.m4, mat.m5, mat.m6, mat.m7, - mat.m8, mat.m9, mat.m10, mat.m11, - mat.m12, mat.m13, mat.m14, mat.m15); -} - -typedef struct Camera Camera; -struct Camera { - Matrix view; - Matrix proj; - RLVector3 pos; - RLVector3 up; - RLVector3 target; -}; - -Camera *createCamera(Arena *arena, real32 aspect_ratio) { - Camera *result = PushStruct(arena, Camera); - result->view = (Matrix){0}; - result->proj = MatrixPerspective(DEG2RAD * 45.0f, aspect_ratio, 0.1f, 100.0f); - result->pos = (RLVector3){0}; - result->up = (RLVector3){0,1,0}; - return result; -} - -void cameraLookAt(Camera *c, float x, float y, float z) { - c->target = (RLVector3){x, y, z}; - c->view = MatrixLookAt(c->pos, c->target, c->up); -} - -void cameraSetUp(Camera *c, real32 up_x, real32 up_y, real32 up_z) { - c->up = (RLVector3){up_x, up_y, up_z}; -} typedef struct Frame Frame; struct Frame { @@ -73,95 +29,7 @@ struct Frame { uint32 height; int32 x; int32 y; - Camera* cam; -}; - -DefineList(RLVector2, RLVec2); -DefineList(RLVector4, RLVec4); -DefineList(real32, Float); - -typedef struct RenderObjects_Rectangle RenderObjects_Rectangle; -struct RenderObjects_Rectangle { - uint32 vao; - uint64 count; - - RLVec2List p0; - uint32 p0BufferId; - - RLVec2List p1; - uint32 p1BufferId; - - RLVec4List color; - uint32 colorBufferId; - - FloatList borderRadius; - uint32 borderRadiusBufferId; - - FloatList borderThickness; - uint32 borderThicknessBufferId; - - FloatList edgeSoftness; - uint32 edgeSoftnessBufferId; -}; - -typedef struct Input Input; -struct Input { - struct { - bool escape; - bool enter; - bool space; - bool lshift; - bool x; - bool y; - bool z; - bool w; - } keyboard; - struct { - union { - struct { - real32 x; - real32 y; - }; - RLVector2 point; - }; - bool btnLeft; - bool btnRight; - bool btnMiddle; - } mouse; -}; - -typedef struct Renderer Renderer; -struct Renderer { - Scene *scene; - RenderObjects_Rectangle rects; -}; - -typedef struct PolycubeInput PolycubeInput; -struct PolycubeInput { - VoxelSpace repr; - RLVector4 color; -}; -DefineList(PolycubeInput, PolycubeInput); - -typedef struct UI_Context UI_Context; -struct UI_Context { - uint32 nextId; - uint32 hotNode; - uint32 prevHotNode; - Renderer *renderer; - Input *prevInput; - Input *input; - bool cursorIsPointer; -}; - -typedef struct UI_Rect UI_Rect; -struct UI_Rect { - real32 x; - real32 y; - real32 width; - real32 height; - real32 borderRadius; - RLVector4 color; + Camera cam; }; typedef enum SolveTaskStatus SolveTaskStatus; @@ -180,19 +48,23 @@ struct SolveTaskCtx { SolveTaskStatus taskStatus; }; +typedef struct PolycubeInput PolycubeInput; +struct PolycubeInput { + VoxelSpace repr; + RLVector4 color; +}; +DefineList(PolycubeInput, PolycubeInput); + typedef struct SomaState SomaState; struct SomaState { bool isInitialState; bool wireframe; bool polycubeDirty; - uint32 displayedPolycube; + int32 displayedPolycube; size_t displayedSolution; bool displayingSolutions; - uint32 light; - Camera* camera; RLVector3 rotAxisX; RLVector3 rotAxisY; - Input input; }; typedef struct Soma Soma; @@ -201,8 +73,8 @@ struct Soma { Renderer *renderer; struct { GLFWwindow *handle; - uint32 width; - uint32 height; + int32 width; + int32 height; struct { GLFWcursor *pointer; GLFWcursor *arrow; @@ -216,7 +88,7 @@ struct Soma { HandleList polycubes; SomaSolutionList solutions; SolveTaskCtx solveTaskCtx; - uint32 puzzleDims[3]; + int32 puzzleDims[3]; int32 solutionNode; }; @@ -243,30 +115,6 @@ void scheduleSolve(Soma *soma) { os_createThread(&executeSolve, &soma->solveTaskCtx); } -void show(Scene *s, uint32 graphNodeHandle) { - SceneGraphNode *node = getSceneGraphNode(s, graphNodeHandle); - if (node->entityHandle) { - getEntity(s, node->entityHandle)->flags |= EntityFlags_Visible; - } - int32 next = node->firstChild; - while (next) { - show(s, next); - next = getSceneGraphNode(s, next)->nextSibling; - } -} - -void hide(Scene *s, uint32 graphNodeHandle) { - SceneGraphNode *node = getSceneGraphNode(s, graphNodeHandle); - if (node->entityHandle) { - getEntity(s, node->entityHandle)->flags &= ~EntityFlags_Visible; - } - int32 next = node->firstChild; - while (next) { - hide(s, next); - next = getSceneGraphNode(s, next)->nextSibling; - } -} - RLVector3 centreFromPolycube(Scene *scene, uint32 p) { RLVector3 centre = (RLVector3){0,0,0}; int32 childCount = 0; @@ -281,23 +129,13 @@ RLVector3 centreFromPolycube(Scene *scene, uint32 p) { return centre; } -Frame createFrame(Arena *arena, uint32 width, uint32 height, uint32 x, uint32 y) { - return (Frame){ - .width = width, - .height = height, - .x = x, - .y = y, - .cam = createCamera(arena, (real32)width / (real32)height), - }; -} - void framebufferSizeCallback(GLFWwindow *window, int width, int height) { glViewport(0, 0, width, height); } GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) { #ifdef OS_LINUX - //glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11); + glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11); #endif glfwInit(); @@ -329,8 +167,8 @@ GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) { return NULL; } - glViewport(0, 0, 800, 600); - glfwSwapInterval(0); + glViewport(0, 0, windowWidth, windowHeight); + glfwSwapInterval(1); glfwSetFramebufferSizeCallback(window, framebufferSizeCallback); glfwSetInputMode(window, GLFW_CURSOR | GLFW_RAW_MOUSE_MOTION, GLFW_CURSOR_NORMAL); glfwSetWindowSize(window, windowWidth, windowHeight); @@ -339,59 +177,15 @@ GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) { return window; } -void updateViewportFromFrame(uint32 windowWidth, uint32 windowHeight, Frame* frame) { - glViewport(frame->x, windowHeight - frame->y - frame->height, frame->width, frame->height); -} - Mesh cubeMesh = {0}; Texture wallTex = {0}; Shader solidColorShader; Shader phongShader; -bool glfwMouse(GLFWwindow *window, int mouseBtnCode) { - switch (glfwGetMouseButton(window, mouseBtnCode)) { - case GLFW_RELEASE: return false; - case GLFW_PRESS: return true; - default: return false; - } -} - -bool glfwKey(GLFWwindow *window, int keyCode) { - switch (glfwGetKey(window, keyCode)) { - case GLFW_RELEASE: return false; - case GLFW_PRESS: return true; - default: return false; - } -} - -Input getCurrentInput(GLFWwindow *window) { - Input input = {0}; - - input.keyboard.escape = glfwKey(window, GLFW_KEY_ESCAPE); - input.keyboard.enter = glfwKey(window, GLFW_KEY_ENTER); - input.keyboard.space = glfwKey(window, GLFW_KEY_SPACE); - input.keyboard.lshift = glfwKey(window, GLFW_KEY_LEFT_SHIFT); - input.keyboard.w = glfwKey(window, GLFW_KEY_W); - input.keyboard.x = glfwKey(window, GLFW_KEY_X); - input.keyboard.y = glfwKey(window, GLFW_KEY_Y); - input.keyboard.z = glfwKey(window, GLFW_KEY_Z); - - input.mouse.btnLeft = glfwMouse(window, GLFW_MOUSE_BUTTON_LEFT); - input.mouse.btnRight = glfwMouse(window, GLFW_MOUSE_BUTTON_RIGHT); - input.mouse.btnMiddle = glfwMouse(window, GLFW_MOUSE_BUTTON_MIDDLE); - - real64 mouseX; - real64 mouseY; - glfwGetCursorPos(window, &mouseX, &mouseY); - input.mouse.point = (RLVector2){(real32)mouseX, (real32)mouseY}; - - return input; -} - void processInput(Soma *soma, UI_Context *ui) { - Input *input = &soma->state.input; - Input *prevInput = &soma->prevState.input; + Input *input = ui->input; + Input *prevInput = ui->prevInput; if (input->keyboard.escape) { glfwSetWindowShouldClose(soma->window.handle, true); @@ -402,7 +196,7 @@ void processInput(Soma *soma, UI_Context *ui) { soma->state.wireframe = !soma->state.wireframe; } - SceneGraphNode *node = getSceneGraphNode(soma->scene, soma->state.light); + SceneGraphNode *node = getSceneGraphNode(soma->scene, soma->renderer->light); int shiftMultiplier = input->keyboard.lshift ? -1 : 1; node->translation.x += 1.0 * input->keyboard.x * shiftMultiplier; node->translation.y += 1.0 * input->keyboard.y * shiftMultiplier; @@ -479,196 +273,7 @@ uint32 createPolycubeFromRepr(Scene *s, VoxelSpace *repr, RLVector4 color) { return mainGraphNode; } -RenderObjects_Rectangle createRectangleObjects(Arena *arena, size_t count) { - RenderObjects_Rectangle result = {0}; - result.count = count; - - result.p0 = PushFullList(arena, RLVec2List, count); - result.p1 = PushFullList(arena, RLVec2List, count); - result.color = PushFullList(arena, RLVec4List, count); - result.borderRadius = PushFullList(arena, FloatList, count); - result.borderThickness = PushFullList(arena, FloatList, count); - result.edgeSoftness = PushFullList(arena, FloatList, count); - - glGenVertexArrays(1, &result.vao); - - glGenBuffers(1, &result.p0BufferId); - glGenBuffers(1, &result.p1BufferId); - glGenBuffers(1, &result.colorBufferId); - glGenBuffers(1, &result.borderRadiusBufferId); - glGenBuffers(1, &result.borderThicknessBufferId); - glGenBuffers(1, &result.edgeSoftnessBufferId); - - glBindVertexArray(result.vao); - - glBindBuffer(GL_ARRAY_BUFFER, result.p0BufferId); - glBufferData(GL_ARRAY_BUFFER, result.p0.length * sizeof(RLVec2List_underlying), 0, GL_DYNAMIC_DRAW); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(RLVec2List_underlying), NULL); - glVertexAttribDivisor(0, 1); - glEnableVertexAttribArray(0); - - glBindBuffer(GL_ARRAY_BUFFER, result.p1BufferId); - glBufferData(GL_ARRAY_BUFFER, result.p1.length * sizeof(RLVec2List_underlying), 0, GL_DYNAMIC_DRAW); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(RLVec2List_underlying), NULL); - glVertexAttribDivisor(1, 1); - glEnableVertexAttribArray(1); - - glBindBuffer(GL_ARRAY_BUFFER, result.colorBufferId); - glBufferData(GL_ARRAY_BUFFER, result.color.length * sizeof(RLVec4List_underlying), 0, GL_DYNAMIC_DRAW); - glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(RLVec4List_underlying), NULL); - glVertexAttribDivisor(2, 1); - glEnableVertexAttribArray(2); - - glBindBuffer(GL_ARRAY_BUFFER, result.borderRadiusBufferId); - glBufferData(GL_ARRAY_BUFFER, result.borderRadius.length * sizeof(FloatList_underlying), 0, GL_DYNAMIC_DRAW); - glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(FloatList_underlying), NULL); - glVertexAttribDivisor(3, 1); - glEnableVertexAttribArray(3); - - glBindBuffer(GL_ARRAY_BUFFER, result.borderThicknessBufferId); - glBufferData(GL_ARRAY_BUFFER, result.borderThickness.length * sizeof(FloatList_underlying), 0, GL_DYNAMIC_DRAW); - glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(FloatList_underlying), NULL); - glVertexAttribDivisor(4, 1); - glEnableVertexAttribArray(4); - - glBindBuffer(GL_ARRAY_BUFFER, result.edgeSoftnessBufferId); - glBufferData(GL_ARRAY_BUFFER, result.edgeSoftness.length * sizeof(FloatList_underlying), 0, GL_DYNAMIC_DRAW); - glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(FloatList_underlying), NULL); - glVertexAttribDivisor(5, 1); - glEnableVertexAttribArray(5); - - return result; -} - -void updateRectangleObjectBuffers(Renderer *r) { - glBindVertexArray(r->rects.vao); - - glBindBuffer(GL_ARRAY_BUFFER, r->rects.p0BufferId); - glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.p0.length * sizeof(RLVec2List_underlying), r->rects.p0.data); - - glBindBuffer(GL_ARRAY_BUFFER, r->rects.p1BufferId); - glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.p1.length * sizeof(RLVec2List_underlying), r->rects.p1.data); - - glBindBuffer(GL_ARRAY_BUFFER, r->rects.colorBufferId); - glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.color.length * sizeof(RLVec4List_underlying), r->rects.color.data); - - glBindBuffer(GL_ARRAY_BUFFER, r->rects.borderRadiusBufferId); - glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.borderRadius.length * sizeof(FloatList_underlying), r->rects.borderRadius.data); - - glBindBuffer(GL_ARRAY_BUFFER, r->rects.borderThicknessBufferId); - glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.borderThickness.length * sizeof(FloatList_underlying), r->rects.borderThickness.data); - - glBindBuffer(GL_ARRAY_BUFFER, r->rects.edgeSoftnessBufferId); - glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.edgeSoftness.length * sizeof(FloatList_underlying), r->rects.edgeSoftness.data); -} - -Renderer createRenderer(Arena *arena, Scene *scene) { - return (Renderer){ - .scene = scene, - .rects = createRectangleObjects(arena, 1024), - }; -} - -void renderBegin(Renderer *r) { - r->rects.p0.length = 0; - r->rects.p1.length = 0; - r->rects.color.length = 0; - r->rects.borderRadius.length = 0; - r->rects.borderThickness.length = 0; - r->rects.edgeSoftness.length = 0; -} - -void renderEnd(Soma *soma, Renderer *renderer) { - // 3D Entities - glClearColor(0.0f, 0.0f, 0.0f, 1.0f); - glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); - - glUseProgram(phongShader.progId); - setUniformMat4fv(&phongShader, "projection", &soma->state.camera->proj); - setUniformMat4fv(&phongShader, "view", &soma->state.camera->view); - - SceneGraphNode *lightGraphNode = getSceneGraphNode(soma->scene, soma->state.light); - setUniform3fv(&phongShader, "light_pos", &lightGraphNode->translation); - setUniform3fv(&phongShader, "camera", &soma->state.camera->pos); - - uint32 currentPolycube = soma->polycubes.data[soma->state.displayedPolycube]; - glBindVertexArray(cubeMesh.vao); - - int model_uniform = getUniformLocation(&phongShader, "model"); - int solid_color_uniform = getUniformLocation(&phongShader, "solid_color"); - for (EachIn(renderer->scene->entities, i)) { - Entity *entity = &renderer->scene->entities.data[i]; - if (entity->flags & EntityFlags_Render && entity->flags & EntityFlags_Visible) { - setUniform4fvByLoc(solid_color_uniform, &entity->color); - setUniformMat4fvByLoc(model_uniform, &getSceneGraphNode(renderer->scene, entity->graphNodeHandle)->world); - glBindTexture(GL_TEXTURE_2D, entity->tex->tex_id); - glDrawArrays(GL_TRIANGLES, 0, (GLsizei)entity->mesh->num_indices); - entity->flags &= ~EntityFlags_Render; - } - } - - // 2D overlay - glUseProgram(solidColorShader.progId); - - updateRectangleObjectBuffers(renderer); - - Matrix ortho = MatrixOrtho(0.0, 800.0, 600.0, 0.0, -1.0, 1.0); - setUniformMat4fv(&solidColorShader, "projection", &ortho); - - glBindVertexArray(renderer->rects.vao); - glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, renderer->rects.p0.length); -} - -void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, RLVector4 color, real32 borderRadius, real32 borderThickness) { - ListAppend(r->rects.p0, ((RLVector2){ x, y })); - ListAppend(r->rects.p1, ((RLVector2){ x + width, y + height })); - ListAppend(r->rects.color, color); - ListAppend(r->rects.borderRadius, borderRadius); - ListAppend(r->rects.borderThickness, borderThickness); - ListAppend(r->rects.edgeSoftness, 0.0f); -} - -bool pointInRect(RLVector2 point, UI_Rect rect) { - return point.x > rect.x && point.y > rect.y && point.x < (rect.x + rect.width) && point.y < (rect.y + rect.height); -} - -bool ui_checkboxRect(UI_Context *ui, bool *value, UI_Rect rect) { - uint32 id = ui->nextId++; - bool clicked = false; - if (pointInRect(ui->input->mouse.point, rect)) { - ui->cursorIsPointer = true; - if (ui->prevHotNode == id && !ui->input->mouse.btnLeft) { - *value = !*value; - clicked = true; - } else if (ui->input->mouse.btnLeft && (!ui->prevInput->mouse.btnLeft || ui->prevHotNode == id)) { - ui->hotNode = id; - } - } - if (*value) { - rendererPlaceRectangle(ui->renderer, - rect.x, rect.y, - rect.width, rect.height, - rect.color, - 5, 0); - } else { - rendererPlaceRectangle(ui->renderer, - rect.x, rect.y, - rect.width, rect.height, - COLOR_WHITE, - 5, 2); - } - - return clicked; -} - -void uiPass(Soma *soma, UI_Context *ui) { - ui->cursorIsPointer = false; - ui->nextId = 1; - ui->prevInput = &soma->prevState.input; - ui->input = &soma->state.input; - ui->prevHotNode = ui->hotNode; - ui->hotNode = 0; - +static void somaUIPass(Soma *soma, UI_Context *ui) { real32 boxSize = 30; real32 padding = 20; real32 paddingBetween = 5; @@ -733,7 +338,7 @@ void uiPass(Soma *soma, UI_Context *ui) { } } -void updatePolycubeDisplay(Arena *arena, Soma *soma) { +static void updatePolycubeDisplay(Soma *soma) { Scene *s = soma->scene; if (soma->state.displayingSolutions && soma->state.displayedSolution != soma->prevState.displayedSolution) { @@ -744,7 +349,7 @@ void updatePolycubeDisplay(Arena *arena, Soma *soma) { for (EachIn(soln, i)) { uint32 polycubeGraphNodeHandle = createPolycubeFromRepr( s, - &(VoxelSpace){ soln.data[i], 3, 3, 3 }, + &(VoxelSpace){ soln.data[i], soma->puzzleDims[0], soma->puzzleDims[1], soma->puzzleDims[2] }, colorFromIndex(i) ); sceneNodeAddNode(s, soma->solutionNode, polycubeGraphNodeHandle); @@ -792,34 +397,52 @@ void updatePolycubeDisplay(Arena *arena, Soma *soma) { } } +static void updateWindow(Soma *soma) { + glfwGetWindowSize(soma->window.handle, &soma->window.width, &soma->window.height); + glViewport(0, 0, soma->window.width, soma->window.height); + cameraSetAspect(soma->renderer->camera, soma->window.width, soma->window.height); + soma->renderer->width = soma->window.width; + soma->renderer->height = soma->window.height; +} + +const int32 MAX_POLYCUBE_INPUT = 64; +const int32 TARGET_FPS = 144; + int mainGfx() { Arena *arena = arenaAlloc(Megabytes(128)); Arena *solutionsArena = arenaAlloc(Megabytes(128)); - int winWidth = 800; - int winHeight = 600; + int32 winWidth = 800; + int32 winHeight = 600; GLFWwindow *windowHandle = initWindowAndGL(winWidth, winHeight); if (!windowHandle) { return 1; } Scene mainScene = createScene(arena); - Renderer renderer = createRenderer(arena, &mainScene); - Frame mainFrame = createFrame(arena, winWidth, winHeight, 0, 0); + Camera cam = createCamera(winWidth, winHeight); + Renderer renderer = createRenderer(arena, &mainScene, &cam, createSceneGraphNode(&mainScene)); - UI_Context ui = { - .hotNode = 0, - .nextId = 1, - .cursorIsPointer = false, - .input = NULL, - .prevInput = NULL, - .renderer = &renderer, - }; + solidColorShader = createShader( + s("./assets/shaders/2d-solid.vertex.glsl"), + s("./assets/shaders/2d-solid.fragment.glsl")); + + phongShader = createShader( + s("./assets/shaders/phong-solid.vertex.glsl"), + s("./assets/shaders/phong-solid.fragment.glsl")); + + cubeMesh = createMesh("./assets/models/cube.obj"); + + renderer.solidShader = &solidColorShader; + renderer.phongShader = &phongShader; + renderer.cubeMesh = &cubeMesh; + + UI_Context ui = ui_initContext(arena, &renderer); Soma soma = { .window = { - .width = 800, - .height = 600, + .width = winWidth, + .height = winHeight, .handle = windowHandle, .cursors = { .pointer = glfwCreateStandardCursor(GLFW_HAND_CURSOR), @@ -828,8 +451,8 @@ int mainGfx() { }, .scene = &mainScene, .renderer = &renderer, - .polycubeInput = PushListZero(arena, PolycubeInputList, 64), - .polycubes = PushListZero(arena, HandleList, 64), + .polycubeInput = PushListZero(arena, PolycubeInputList, MAX_POLYCUBE_INPUT), + .polycubes = PushListZero(arena, HandleList, MAX_POLYCUBE_INPUT), .puzzleDims = {3, 3, 3}, .solveTaskCtx = (SolveTaskCtx){ .arena = arenaAlloc(Megabytes(128)), @@ -843,33 +466,19 @@ int mainGfx() { .displayingSolutions = false, .displayedSolution = -1, .isInitialState = true, - .light = createEntity(&mainScene), - .camera = mainFrame.cam, }, }; - /* - Shader solid_texture_shader = createShader( - "./assets/shaders/2d.vertex.glsl"_s, - "./assets/shaders/2d-tex.fragment.glsl"_s); - */ - - solidColorShader = createShader( - s("./assets/shaders/2d-solid.vertex.glsl"), - s("./assets/shaders/2d-solid.fragment.glsl")); - - phongShader = createShader( - s("./assets/shaders/phong-solid.vertex.glsl"), - s("./assets/shaders/phong-solid.fragment.glsl")); - - cubeMesh = createMesh("./assets/models/cube.obj"); - wallTex = createTexture("./assets/textures/brick-wall.jpg"); - VoxelSpaceReprList stdSoma = AsList(VoxelSpaceReprList, STD_SOMA); for (EachIn(stdSoma, i)) { - VoxelSpace voxelSpace = { stdSoma.data[i], 3, 3, 3 }; + VoxelSpace voxelSpace = { + .space=stdSoma.data[i], + .dim_x=soma.puzzleDims[0], + .dim_y=soma.puzzleDims[1], + .dim_z=soma.puzzleDims[2], + }; RLVector4 color = colorFromIndex(i); - PolycubeInput input = (PolycubeInput){ voxelSpace, color }; + PolycubeInput input = (PolycubeInput){ .repr=voxelSpace, .color=color }; ListAppend(soma.polycubeInput, input); cullEmptySpace(&voxelSpace); uint32 polycubeGraphNodeHandle = createPolycubeFromRepr(soma.scene, &voxelSpace, color); @@ -877,27 +486,33 @@ int mainGfx() { sceneNodeAddNode(renderer.scene, renderer.scene->sceneRoot, polycubeGraphNodeHandle); } - // TODO(dledda): only actually create and render one solution/polycube at a time, save lots of space! - - soma.state.camera->pos = (RLVector3){0.0f, 0.0f, 8.0f}; - cameraLookAt(soma.state.camera, 0.0f, 0.0f, 0.0f); + cam.pos = (RLVector3){0.0f, 0.0f, 8.0f}; + cameraLookAt(&cam, 0.0f, 0.0f, 0.0f); SceneGraphNode *referencePolycube = getSceneGraphNode(soma.scene, soma.polycubes.data[0]); Matrix worldInverse = MatrixInvert(referencePolycube->world); soma.state.rotAxisY = Vector3Normalize((RLVector3){worldInverse.m4, worldInverse.m5, worldInverse.m6}); - RLVector3 eyes = Vector3Normalize(Vector3Subtract(soma.state.camera->pos, referencePolycube->translation)); + RLVector3 eyes = Vector3Normalize(Vector3Subtract(cam.pos, referencePolycube->translation)); soma.state.rotAxisX = Vector3Normalize(Vector3CrossProduct(eyes, soma.state.rotAxisY)); - getSceneGraphNode(&mainScene, soma.state.light)->translation = (RLVector3){4.0f, 6.0f, 24.0f}; + getSceneGraphNode(&mainScene, renderer.light)->translation = (RLVector3){4.0f, 6.0f, 24.0f}; real64 lastFrame = glfwGetTime(); - real64 timeDelta = 1.0f/60.0f; + real64 timeDelta = 1.0f / TARGET_FPS; + real64 frameStart = lastFrame; + Input lastInput = {0}; + Input currInput = {0}; while (!glfwWindowShouldClose(soma.window.handle)) { - real64 frameStart = glfwGetTime(); - glfwPollEvents(); - soma.state.input = getCurrentInput(soma.window.handle); + + lastInput = currInput; + currInput = getCurrentInput(soma.window.handle); + + ui.prevInput = &lastInput; + ui.input = &currInput; + + updateWindow(&soma); processInput(&soma, &ui); @@ -912,28 +527,33 @@ int mainGfx() { arenaFreeFrom(soma.solveTaskCtx.arena, 0); } - updatePolycubeDisplay(arena, &soma); + updatePolycubeDisplay(&soma); - updateViewportFromFrame(soma.window.width, soma.window.height, &mainFrame); recalcScene(soma.scene); renderBegin(&renderer); - uiPass(&soma, &ui); + ui_begin(&ui); + somaUIPass(&soma, &ui); + ui_end(&ui); + if (ui.cursorIsPointer) { glfwSetCursor(soma.window.handle, soma.window.cursors.pointer); } else { glfwSetCursor(soma.window.handle, soma.window.cursors.arrow); } - renderEnd(&soma, &renderer); + renderEnd(&renderer); + + glfwSwapBuffers(soma.window.handle); real64 frameEnd = glfwGetTime(); real64 frameTime = frameEnd - frameStart; lastFrame = frameStart; - // print("FPS: %.7f\n", 1 / frameTime); - glfwSwapBuffers(soma.window.handle); + //println("FPS: %.7f", 1/(frameTime)); + + frameStart = glfwGetTime(); soma.prevState = soma.state; soma.state.isInitialState = false; diff --git a/src/render.c b/src/render.c new file mode 100644 index 0000000..3619545 --- /dev/null +++ b/src/render.c @@ -0,0 +1,155 @@ +#include "render.h" +#include "debug.h" + +RenderObjects_Rectangle createRectangleObjects(Arena *arena, size_t count) { + RenderObjects_Rectangle result = {0}; + result.count = count; + + result.p0 = PushFullList(arena, RLVec2List, count); + result.p1 = PushFullList(arena, RLVec2List, count); + result.color = PushFullList(arena, RLVec4List, count); + result.borderRadius = PushFullList(arena, FloatList, count); + result.borderThickness = PushFullList(arena, FloatList, count); + result.edgeSoftness = PushFullList(arena, FloatList, count); + + glGenVertexArrays(1, &result.vao); + + glGenBuffers(1, &result.p0BufferId); + glGenBuffers(1, &result.p1BufferId); + glGenBuffers(1, &result.colorBufferId); + glGenBuffers(1, &result.borderRadiusBufferId); + glGenBuffers(1, &result.borderThicknessBufferId); + glGenBuffers(1, &result.edgeSoftnessBufferId); + + glBindVertexArray(result.vao); + + glBindBuffer(GL_ARRAY_BUFFER, result.p0BufferId); + glBufferData(GL_ARRAY_BUFFER, result.p0.length * sizeof(RLVec2List_underlying), 0, GL_DYNAMIC_DRAW); + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(RLVec2List_underlying), NULL); + glVertexAttribDivisor(0, 1); + glEnableVertexAttribArray(0); + + glBindBuffer(GL_ARRAY_BUFFER, result.p1BufferId); + glBufferData(GL_ARRAY_BUFFER, result.p1.length * sizeof(RLVec2List_underlying), 0, GL_DYNAMIC_DRAW); + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(RLVec2List_underlying), NULL); + glVertexAttribDivisor(1, 1); + glEnableVertexAttribArray(1); + + glBindBuffer(GL_ARRAY_BUFFER, result.colorBufferId); + glBufferData(GL_ARRAY_BUFFER, result.color.length * sizeof(RLVec4List_underlying), 0, GL_DYNAMIC_DRAW); + glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(RLVec4List_underlying), NULL); + glVertexAttribDivisor(2, 1); + glEnableVertexAttribArray(2); + + glBindBuffer(GL_ARRAY_BUFFER, result.borderRadiusBufferId); + glBufferData(GL_ARRAY_BUFFER, result.borderRadius.length * sizeof(FloatList_underlying), 0, GL_DYNAMIC_DRAW); + glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(FloatList_underlying), NULL); + glVertexAttribDivisor(3, 1); + glEnableVertexAttribArray(3); + + glBindBuffer(GL_ARRAY_BUFFER, result.borderThicknessBufferId); + glBufferData(GL_ARRAY_BUFFER, result.borderThickness.length * sizeof(FloatList_underlying), 0, GL_DYNAMIC_DRAW); + glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, sizeof(FloatList_underlying), NULL); + glVertexAttribDivisor(4, 1); + glEnableVertexAttribArray(4); + + glBindBuffer(GL_ARRAY_BUFFER, result.edgeSoftnessBufferId); + glBufferData(GL_ARRAY_BUFFER, result.edgeSoftness.length * sizeof(FloatList_underlying), 0, GL_DYNAMIC_DRAW); + glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(FloatList_underlying), NULL); + glVertexAttribDivisor(5, 1); + glEnableVertexAttribArray(5); + + return result; +} + +void updateRectangleObjectBuffers(Renderer *r) { + glBindVertexArray(r->rects.vao); + + glBindBuffer(GL_ARRAY_BUFFER, r->rects.p0BufferId); + glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.p0.length * sizeof(RLVec2List_underlying), r->rects.p0.data); + + glBindBuffer(GL_ARRAY_BUFFER, r->rects.p1BufferId); + glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.p1.length * sizeof(RLVec2List_underlying), r->rects.p1.data); + + glBindBuffer(GL_ARRAY_BUFFER, r->rects.colorBufferId); + glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.color.length * sizeof(RLVec4List_underlying), r->rects.color.data); + + glBindBuffer(GL_ARRAY_BUFFER, r->rects.borderRadiusBufferId); + glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.borderRadius.length * sizeof(FloatList_underlying), r->rects.borderRadius.data); + + glBindBuffer(GL_ARRAY_BUFFER, r->rects.borderThicknessBufferId); + glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.borderThickness.length * sizeof(FloatList_underlying), r->rects.borderThickness.data); + + glBindBuffer(GL_ARRAY_BUFFER, r->rects.edgeSoftnessBufferId); + glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.edgeSoftness.length * sizeof(FloatList_underlying), r->rects.edgeSoftness.data); +} + +Renderer createRenderer(Arena *arena, Scene *scene, Camera *cam, int32 light) { + return (Renderer){ + .scene = scene, + .light = light, + .camera = cam, + .rects = createRectangleObjects(arena, 1024), + }; +} + +void renderBegin(Renderer *r) { + r->rects.p0.length = 0; + r->rects.p1.length = 0; + r->rects.color.length = 0; + r->rects.borderRadius.length = 0; + r->rects.borderThickness.length = 0; + r->rects.edgeSoftness.length = 0; +} + +void renderEnd(Renderer *r) { + // 3D Entities + glClearColor(0.0f, 0.0f, 0.0f, 1.0f); + glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); + + glUseProgram(r->phongShader->progId); + setUniformMat4fv(r->phongShader, "projection", &r->camera->proj); + setUniformMat4fv(r->phongShader, "view", &r->camera->view); + + SceneGraphNode *lightGraphNode = getSceneGraphNode(r->scene, r->light); + setUniform3fv(r->phongShader, "light_pos", &lightGraphNode->translation); + setUniform3fv(r->phongShader, "camera", &r->camera->pos); + + glBindVertexArray(r->cubeMesh->vao); + + // TODO(djledda): sort by mesh, texture, etc. + + int model_uniform = getUniformLocation(r->phongShader, "model"); + int solid_color_uniform = getUniformLocation(r->phongShader, "solid_color"); + for (EachIn(r->scene->entities, i)) { + Entity *entity = &r->scene->entities.data[i]; + if (entity->flags & EntityFlags_Render && entity->flags & EntityFlags_Visible) { + setUniform4fvByLoc(solid_color_uniform, &entity->color); + setUniformMat4fvByLoc(model_uniform, &getSceneGraphNode(r->scene, entity->graphNodeHandle)->world); + glBindTexture(GL_TEXTURE_2D, entity->tex->tex_id); + glDrawArrays(GL_TRIANGLES, 0, (GLsizei)entity->mesh->num_indices); + entity->flags &= ~EntityFlags_Render; + } + } + + // 2D overlay + glUseProgram(r->solidShader->progId); + + updateRectangleObjectBuffers(r); + + Matrix ortho = MatrixOrtho(0.0, r->width, r->height, 0.0, -1.0, 1.0); + setUniformMat4fv(r->solidShader, "projection", &ortho); + + glBindVertexArray(r->rects.vao); + glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, r->rects.p0.length); +} + +void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, RLVector4 color, real32 borderRadius, real32 borderThickness) { + ListAppend(r->rects.p0, ((RLVector2){ x, y })); + ListAppend(r->rects.p1, ((RLVector2){ x + width, y + height })); + ListAppend(r->rects.color, color); + ListAppend(r->rects.borderRadius, borderRadius); + ListAppend(r->rects.borderThickness, borderThickness); + ListAppend(r->rects.edgeSoftness, 0.0f); +} + diff --git a/src/render.h b/src/render.h new file mode 100644 index 0000000..56ffa5a --- /dev/null +++ b/src/render.h @@ -0,0 +1,59 @@ +#ifndef RENDER_H +#define RENDER_H + +#include "gfx/Shader.h" +#include "gfx/gfx.h" +#include "world/world.h" + +DefineList(RLVector2, RLVec2); +DefineList(RLVector4, RLVec4); +DefineList(real32, Float); + +typedef struct RenderObjects_Rectangle RenderObjects_Rectangle; +struct RenderObjects_Rectangle { + uint32 vao; + uint64 count; + + RLVec2List p0; + uint32 p0BufferId; + + RLVec2List p1; + uint32 p1BufferId; + + RLVec4List color; + uint32 colorBufferId; + + FloatList borderRadius; + uint32 borderRadiusBufferId; + + FloatList borderThickness; + uint32 borderThicknessBufferId; + + FloatList edgeSoftness; + uint32 edgeSoftnessBufferId; +}; + +typedef struct Renderer Renderer; +struct Renderer { + RenderObjects_Rectangle rects; + + Shader *phongShader; + Shader *solidShader; + + int32 width; + int32 height; + + Scene *scene; + Camera *camera; + /** SceneGraphNode handle */ + int32 light; + Mesh *cubeMesh; +}; + +Renderer createRenderer(Arena *arena, Scene *scene, Camera *cam, int32 light); +void renderBegin(Renderer *r); +void renderEnd(Renderer *r); +void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, RLVector4 color, real32 borderRadius, real32 borderThickness); +void updateRectangleObjectBuffers(Renderer *r); + +#endif diff --git a/src/ui.c b/src/ui.c new file mode 100644 index 0000000..b4fb3aa --- /dev/null +++ b/src/ui.c @@ -0,0 +1,118 @@ +#include "ui.h" +#include "GLFW/glfw3.h" + +static bool glfwMouse(GLFWwindow *window, int mouseBtnCode) { + switch (glfwGetMouseButton(window, mouseBtnCode)) { + case GLFW_RELEASE: return false; + case GLFW_PRESS: return true; + default: return false; + } +} + +static bool glfwKey(GLFWwindow *window, int keyCode) { + switch (glfwGetKey(window, keyCode)) { + case GLFW_RELEASE: return false; + case GLFW_PRESS: return true; + default: return false; + } +} + +Input getCurrentInput(GLFWwindow *window) { + Input input = {0}; + + input.keyboard.escape = glfwKey(window, GLFW_KEY_ESCAPE); + input.keyboard.enter = glfwKey(window, GLFW_KEY_ENTER); + input.keyboard.space = glfwKey(window, GLFW_KEY_SPACE); + input.keyboard.lshift = glfwKey(window, GLFW_KEY_LEFT_SHIFT); + input.keyboard.w = glfwKey(window, GLFW_KEY_W); + input.keyboard.x = glfwKey(window, GLFW_KEY_X); + input.keyboard.y = glfwKey(window, GLFW_KEY_Y); + input.keyboard.z = glfwKey(window, GLFW_KEY_Z); + + input.mouse.btnLeft = glfwMouse(window, GLFW_MOUSE_BUTTON_LEFT); + input.mouse.btnRight = glfwMouse(window, GLFW_MOUSE_BUTTON_RIGHT); + input.mouse.btnMiddle = glfwMouse(window, GLFW_MOUSE_BUTTON_MIDDLE); + + real64 mouseX; + real64 mouseY; + glfwGetCursorPos(window, &mouseX, &mouseY); + input.mouse.point = (RLVector2){(real32)mouseX, (real32)mouseY}; + + return input; +} + +UI_Context ui_initContext(Arena *arena, Renderer *renderer) { + UI_RectList list = PushListZero(arena, UI_RectList, Thousand(10)); + ListAppend(list, ((UI_Rect){0})); // empty item + return (UI_Context){ + .rects=list, + .hotNode = 0, + .nextId = 1, + .cursorIsPointer = false, + .input = NULL, + .prevInput = NULL, + .renderer = renderer, + }; +} + +void ui_begin(UI_Context *ui) { + ui->cursorIsPointer = false; + ui->nextId = 1; + ui->prevHotNode = ui->hotNode; + ui->hotNode = 0; +} + +void ui_end(UI_Context *ui) { +} + +static bool pointInRect(real32 x, real32 y, UI_Rect rect) { + return x > rect.x && y > rect.y && x < (rect.x + rect.width) && y < (rect.y + rect.height); +} + +void ui_openElement(UI_Context *ui, UI_Rect rect) { + ListAppend(ui->rects, rect); + int32 nextHandle = ui->rects.length - 1; + + UI_Rect *nextRect = &ui->rects.data[nextHandle]; + UI_Rect *currRect = &ui->rects.data[ui->currRect]; + + nextRect->parent = ui->currRect; + nextRect->nextSibling = currRect->firstChild; + currRect->firstChild = nextHandle; + + ui->currRect = nextHandle; +} + +void ui_closeElement(UI_Context *ui) { + ui->currRect = ui->rects.data[ui->currRect].parent; +} + + +/** + * Returns whether the checkbox was clicked + */ +bool ui_checkboxRect(UI_Context *ui, bool *value, UI_Rect rect) { + uint32 id = ui->nextId++; + bool clicked = false; + if (pointInRect(ui->input->mouse.point.x, ui->input->mouse.point.y, rect)) { + ui->cursorIsPointer = true; + if (ui->prevHotNode == id && !ui->input->mouse.btnLeft) { + *value = !*value; + clicked = true; + } else if (ui->input->mouse.btnLeft && (!ui->prevInput->mouse.btnLeft || ui->prevHotNode == id)) { + ui->hotNode = id; + } + } + if (*value) { + rect.borderRadius = 5; + rect.borderThickness = 0; + DJUI(ui, rect); + } else { + rect.borderRadius = 5; + rect.borderThickness = 2; + rect.color = COLOR_WHITE; + DJUI(ui, rect); + } + + return clicked; +} diff --git a/src/ui.h b/src/ui.h new file mode 100644 index 0000000..2ead88a --- /dev/null +++ b/src/ui.h @@ -0,0 +1,104 @@ +#ifndef UI_H +#define UI_H + +#include "render.h" +#include "lib/djstdlib/core.h" +#include "GLFW/glfw3.h" +#include "lib/djstdlib/core.h" + +typedef struct Input Input; +struct Input { + struct { + bool escape; + bool enter; + bool space; + bool lshift; + bool x; + bool y; + bool z; + bool w; + } keyboard; + struct { + union { + struct { + real32 x; + real32 y; + }; + RLVector2 point; + }; + bool btnLeft; + bool btnRight; + bool btnMiddle; + } mouse; +}; + +enum UI_Rect_LayoutFlag { + UI_Rect_LayoutFlag_Width_Grow=1<<0, // Default is fixed + UI_Rect_LayoutFlag_Height_Grow=1<<1, + UI_Rect_LayoutFlag_LayoutDirection_Vertical=1<<2, // Default is horizontal + // .. + UI_Rect_LayoutFlag_COUNT, +}; + +typedef struct UI_Rect UI_Rect; +struct UI_Rect { + uint64 layoutFlags; + + int32 parent; + int32 firstChild; + int32 nextSibling; + + real32 xOffset; + real32 yOffset; + + real32 width; + real32 minWidth; + real32 maxWidth; + + real32 height; + real32 minHeight; + real32 maxHeight; + + real32 borderRadius; + real32 borderThickness; + + RLVector4 color; + RLVector4 borderColor; + + real32 childGap; + + real32 x; + real32 y; + real32 resolvedWidth; + real32 resolvedHeight; +}; +DefineList(UI_Rect, UI_Rect); + +typedef struct UI_Context UI_Context; +struct UI_Context { + UI_RectList rects; + int32 nextId; + int32 hotNode; + int32 prevHotNode; + Renderer *renderer; + + Input *prevInput; + Input *input; + bool cursorIsPointer; + + int32 currRect; +}; + +void ui_begin(UI_Context *ui); +void ui_end(UI_Context *ui); +UI_Context ui_initContext(Arena *arena, Renderer *renderer); +Input getCurrentInput(GLFWwindow *window); +void ui_resolve(); +void ui_rect(UI_Context *ui, UI_Rect rect); +bool ui_checkboxRect(UI_Context *ui, bool *value, UI_Rect rect); +void ui_openElement(UI_Context *ui, UI_Rect rect); +void ui_closeElement(UI_Context *ui); + +#define DJUI(ui, rect) DeferLoop(ui_openElement((ui), (rect)), ui_closeElement((ui))) + +#endif diff --git a/src/world/camera.c b/src/world/camera.c new file mode 100644 index 0000000..9794100 --- /dev/null +++ b/src/world/camera.c @@ -0,0 +1,26 @@ +#include "camera.h" +#include "../lib/raymath.h" + +Camera createCamera(int32 width, int32 height) { + return (Camera){ + .view = (Matrix){0}, + .proj = MatrixPerspective(DEG2RAD * 45.0f, (real32)width/(real32)height, 0.1f, 100.0f), + .pos = (RLVector3){0}, + .up = (RLVector3){0,1,0}, + }; +} + +void cameraSetAspect(Camera *c, int32 width, int32 height) { + real32 aspectRatio = (real32)width/(real32)height; + c->proj = MatrixPerspective(DEG2RAD * 45.0f, aspectRatio, 0.1f, 100.0f); +} + +void cameraLookAt(Camera *c, float x, float y, float z) { + c->target = (RLVector3){x, y, z}; + c->view = MatrixLookAt(c->pos, c->target, c->up); +} + +void cameraSetUp(Camera *c, real32 up_x, real32 up_y, real32 up_z) { + c->up = (RLVector3){up_x, up_y, up_z}; +} + diff --git a/src/world/camera.h b/src/world/camera.h new file mode 100644 index 0000000..94ae1ea --- /dev/null +++ b/src/world/camera.h @@ -0,0 +1,21 @@ +#ifndef CAMERA_H +#define CAMERA_H + +#include "../lib/djstdlib/core.h" +#include "../lib/raymath.h" + +typedef struct Camera Camera; +struct Camera { + Matrix view; + Matrix proj; + RLVector3 pos; + RLVector3 up; + RLVector3 target; +}; + +Camera createCamera(int32 width, int32 height); +void cameraSetAspect(Camera *c, int32 width, int32 height); +void cameraLookAt(Camera *c, float x, float y, float z); +void cameraSetUp(Camera *c, real32 up_x, real32 up_y, real32 up_z); + +#endif diff --git a/src/world/scene.c b/src/world/scene.c index b654403..abb6988 100644 --- a/src/world/scene.c +++ b/src/world/scene.c @@ -37,7 +37,6 @@ int32 createSceneGraphNode(Scene *s) { int32 createEntity(Scene *s) { Entity *newEntity; int32 newEntityHandle; - println("%d", s->nextFreeEntity); if (s->nextFreeEntity) { newEntityHandle = s->nextFreeEntity; newEntity = getEntity(s, newEntityHandle); @@ -98,36 +97,36 @@ void recalcScene(Scene *s) { recalcSceneGraphNode(s, s->sceneRoot); } -function void removeSceneGraphNodeRecursive(Scene *s, int32 graphNodeHandle, bool deletingParent) { - if (!graphNodeHandle) return; - SceneGraphNode *graphNode = getSceneGraphNode(s, graphNodeHandle); +static void removeSceneGraphNodeRecursive(Scene *s, int32 deletedNodeHandle, bool deletingParent) { + if (!deletedNodeHandle) return; + SceneGraphNode *deletedNode = getSceneGraphNode(s, deletedNodeHandle); - int32 nextChild = graphNode->firstChild; + int32 nextChild = deletedNode->firstChild; while (nextChild) { int32 sibling = getSceneGraphNode(s, nextChild)->nextSibling; removeSceneGraphNodeRecursive(s, nextChild, true); nextChild = sibling; } - if (graphNode->entityHandle) { - Entity *entity = getEntity(s, graphNode->entityHandle); + if (deletedNode->entityHandle) { + Entity *entity = getEntity(s, deletedNode->entityHandle); *entity = (Entity){0}; if (s->nextFreeEntity) { entity->next = s->nextFreeEntity; } - s->nextFreeEntity = graphNode->entityHandle; + s->nextFreeEntity = deletedNode->entityHandle; } if (s->nextFreeNode) { - graphNode->next = s->nextFreeNode; + deletedNode->next = s->nextFreeNode; } - s->nextFreeNode = graphNodeHandle; + s->nextFreeNode = deletedNodeHandle; - if (!deletingParent && graphNode->parentHandle) { - SceneGraphNode *parentNode = getSceneGraphNode(s, graphNode->parentHandle); - if (parentNode->firstChild == graphNodeHandle) { - if (graphNode->nextSibling) { - parentNode->firstChild = graphNode->nextSibling; + if (!deletingParent && deletedNode->parentHandle) { + SceneGraphNode *parentNode = getSceneGraphNode(s, deletedNode->parentHandle); + if (parentNode->firstChild == deletedNodeHandle) { + if (deletedNode->nextSibling) { + parentNode->firstChild = deletedNode->nextSibling; } else { parentNode->firstChild = 0; } @@ -136,20 +135,21 @@ function void removeSceneGraphNodeRecursive(Scene *s, int32 graphNodeHandle, boo int32 nextSibling = getSceneGraphNode(s, parentNode->firstChild)->nextSibling; while (nextSibling) { SceneGraphNode *siblingNode = getSceneGraphNode(s, nextSibling); - if (nextSibling == graphNodeHandle) { + if (nextSibling == deletedNodeHandle) { SceneGraphNode *prevSiblingNode = getSceneGraphNode(s, prevSibling); - prevSiblingNode->nextSibling = graphNode->nextSibling; + prevSiblingNode->nextSibling = deletedNode->nextSibling; break; } + prevSibling = nextSibling; nextSibling = siblingNode->nextSibling; } } } - graphNode->firstChild = 0; - graphNode->parentHandle = 0; - graphNode->entityHandle = 0; - graphNode->nextSibling = 0; + deletedNode->firstChild = 0; + deletedNode->parentHandle = 0; + deletedNode->entityHandle = 0; + deletedNode->nextSibling = 0; } void removeSceneGraphNode(Scene *s, int32 graphNodeHandle) { @@ -168,3 +168,28 @@ void sceneNodeAddNode(Scene *s, int32 parentHandle, int32 childHandle) { parentNode->firstChild = childHandle; childNode->parentHandle = parentHandle; } + +void show(Scene *s, uint32 graphNodeHandle) { + SceneGraphNode *node = getSceneGraphNode(s, graphNodeHandle); + if (node->entityHandle) { + getEntity(s, node->entityHandle)->flags |= EntityFlags_Visible; + } + int32 next = node->firstChild; + while (next) { + show(s, next); + next = getSceneGraphNode(s, next)->nextSibling; + } +} + +void hide(Scene *s, uint32 graphNodeHandle) { + SceneGraphNode *node = getSceneGraphNode(s, graphNodeHandle); + if (node->entityHandle) { + getEntity(s, node->entityHandle)->flags &= ~EntityFlags_Visible; + } + int32 next = node->firstChild; + while (next) { + hide(s, next); + next = getSceneGraphNode(s, next)->nextSibling; + } +} + diff --git a/src/world/scene.h b/src/world/scene.h index b30e63d..c6558cc 100644 --- a/src/world/scene.h +++ b/src/world/scene.h @@ -1,3 +1,6 @@ +#ifndef SCENE_H +#define SCENE_H + #include "../gfx/gfx.h" #include "../lib/raymath.h" @@ -33,10 +36,10 @@ struct SceneGraphNode { int32 entityHandle; int32 parentHandle; - // Free list + /** Next free in the free list */ int32 next; - // Children + /** Next child in child list in scene hierarchy */ int32 nextSibling; int32 firstChild; }; @@ -47,6 +50,7 @@ struct Scene { int32 sceneRoot; EntityList entities; int32 nextFreeEntity; + /** @internal */ SceneGraphNodeList graphNodes; int32 nextFreeNode; }; @@ -63,3 +67,7 @@ void removeEntity(Scene *s, int32 entityHandle); void removeSceneGraphNode(Scene *s, int32 graphNodeHandle); void sceneNodeAddNode(Scene *s, int32 recipientNodeHandle, int32 graphNodeHandle); SceneGraphNode *getSceneGraphNodeForEntity(Scene *s, int32 entityHandle); +void show(Scene *s, uint32 graphNodeHandle); +void hide(Scene *s, uint32 graphNodeHandle); + +#endif diff --git a/src/world/world.c b/src/world/world.c index 9484efa..dae2497 100644 --- a/src/world/world.c +++ b/src/world/world.c @@ -1 +1,2 @@ #include "scene.c" +#include "camera.c" diff --git a/src/world/world.h b/src/world/world.h new file mode 100644 index 0000000..a40897e --- /dev/null +++ b/src/world/world.h @@ -0,0 +1,8 @@ +#ifndef WORLD_H +#define WORLD_H + +#include "scene.h" +#include "camera.h" + +#endif +