big progress

This commit is contained in:
2025-11-23 15:30:05 +01:00
parent c300276c7d
commit ff41c8ace4
6 changed files with 372 additions and 188 deletions

View File

@@ -4,6 +4,8 @@ CompileFlags:
- -xc
# LINUX FLAGS
- -DOS_LINUX
- -DCOMPOSITOR_WAYLAND
- -DDJSTDLIB_DEBUG
# WINDOW FLAGS
# - -DOS_WINDOWS
# - "-IC:\\source\\libs\\include"

5
build
View File

@@ -1,12 +1,13 @@
#!/bin/bash
LIB_INCLUDE="-lglfw -lGL -lm"
COMMON_FLAGS="-DOS_LINUX=1 -DCOMPOSITOR_WAYLAND=1 -xc -std=c99"
echo [Building target]
if [ $DEBUG ]; then
time clang -O0 -g -g2 -DOS_LINUX=1 -DDJSTDLIB_DEBUG=1 -xc -std=c99 ./src/main.c -o ./target/somaesque $LIB_INCLUDE
time clang -O0 -g -g2 $COMMON_FLAGS -DDJSTDLIB_DEBUG=1 ./src/main.c -o ./target/somaesque $LIB_INCLUDE
else
time clang -O2 -DOS_LINUX=1 -xc -std=c99 ./src/main.c -o ./target/somaesque $LIB_INCLUDE
time clang -O2 $COMMON_FLAGS ./src/main.c -o ./target/somaesque $LIB_INCLUDE
fi
echo [Target built]
./target/somaesque

View File

@@ -3,6 +3,7 @@
#include "SomaSolve.h"
#include "math.h"
#include <stdlib.h>
#include <unistd.h>
/*
void get_dims_input(int dims[3]) {

View File

@@ -10,6 +10,7 @@
#include "VoxelSpace.c"
#include "./tests.c"
#include "lib/djstdlib/core.c"
#include "pthread.h"
// Graphics bindings and libs
#include "lib/raymath.h"
@@ -114,6 +115,7 @@ struct Input {
bool x;
bool y;
bool z;
bool w;
} keyboard;
struct {
union {
@@ -142,8 +144,46 @@ struct PolycubeInput {
};
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;
};
typedef enum SolveTaskStatus SolveTaskStatus;
enum SolveTaskStatus {
SolveTaskStatus_Ready,
SolveTaskStatus_Solving,
SolveTaskStatus_Complete,
SolveTaskStatus_Error,
};
typedef struct SolveTaskCtx SolveTaskCtx;
struct SolveTaskCtx {
Arena *arena;
SomaSolutionList solutions;
VoxelSpaceReprList input;
int dims[3];
SolveTaskStatus taskStatus;
};
typedef struct SomaState SomaState;
struct SomaState {
bool isInitialState;
bool wireframe;
bool polycubeDirty;
uint32 displayedPolycube;
@@ -164,6 +204,10 @@ struct Soma {
GLFWwindow *handle;
uint32 width;
uint32 height;
struct {
GLFWcursor *pointer;
GLFWcursor *arrow;
} cursors;
} window;
SomaState prevState;
@@ -172,9 +216,42 @@ struct Soma {
PolycubeInputList polycubeInput;
HandleList polycubes;
SomaSolutionList solutions;
Arena *solveArena;
SolveTaskCtx *solveTaskCtx;
uint32 puzzleDims[3];
HandleList solutionEntities;
};
void *executeSolve(void *ctx) {
SolveTaskCtx *solveTaskCtx = (SolveTaskCtx *)ctx;
solveTaskCtx->taskStatus = SolveTaskStatus_Solving;
solveTaskCtx->solutions = solveSoma(solveTaskCtx->arena, solveTaskCtx->input, solveTaskCtx->dims);
solveTaskCtx->taskStatus = SolveTaskStatus_Complete;
return NULL;
}
SolveTaskCtx *scheduleSolve(Soma *soma) {
SolveTaskCtx *threadCtx = PushStructZero(soma->solveArena, SolveTaskCtx);
VoxelSpaceReprList mappedInputs = PushList(soma->solveArena, VoxelSpaceReprList, soma->polycubeInput.length);
for (EachEl(soma->polycubeInput, PolycubeInput, polycubeInput)) {
AppendList(&mappedInputs, polycubeInput->repr.space);
}
*threadCtx = (SolveTaskCtx){
.arena = soma->solveArena,
.solutions = EmptyList(),
.input = mappedInputs,
.taskStatus = SolveTaskStatus_Ready,
.dims = { soma->puzzleDims[0], soma->puzzleDims[1], soma->puzzleDims[2] },
};
soma->solveTaskCtx = threadCtx;
pthread_t threadId;
pthread_attr_t attr;
pthread_attr_init(&attr);
pthread_create(&threadId, &attr, &executeSolve, threadCtx);
pthread_attr_destroy(&attr);
return threadCtx;
}
void show(Scene *s, uint32 graphNodeHandle) {
SceneGraphNode *node = getSceneGraphNode(s, graphNodeHandle);
if (node->entityHandle) {
@@ -223,10 +300,16 @@ void framebufferSizeCallback(GLFWwindow *window, int width, int height) {
}
GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) {
#ifdef OS_LINUX
glfwInitHint(GLFW_PLATFORM, GLFW_PLATFORM_X11);
#endif
glfwInit();
glfwWindowHintString(GLFW_WAYLAND_APP_ID, "Somaesque");
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
GLFWwindow *window = glfwCreateWindow(
windowWidth,
windowHeight,
@@ -242,6 +325,7 @@ GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) {
glfwTerminate();
return NULL;
}
glfwMakeContextCurrent(window);
if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) {
@@ -253,7 +337,13 @@ GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) {
glfwSwapInterval(0);
glfwSetFramebufferSizeCallback(window, framebufferSizeCallback);
glfwSetInputMode(window, GLFW_CURSOR | GLFW_RAW_MOUSE_MOTION, GLFW_CURSOR_NORMAL);
glfwSetWindowSize(window, windowWidth, windowHeight);
glEnable(GL_DEPTH_TEST);
glfwSetWindowAttrib(window, GLFW_DECORATED, GLFW_FALSE);
glfwSetWindowAttrib(window, GLFW_DECORATED, GLFW_TRUE);
glfwSetWindowAttrib(window, GLFW_DECORATED, GLFW_FALSE);
return window;
}
@@ -261,24 +351,6 @@ void updateViewportFromFrame(uint32 windowWidth, uint32 windowHeight, Frame* fra
glViewport(frame->x, windowHeight - frame->y - frame->height, frame->width, frame->height);
}
typedef struct UI_Context UI_Context;
struct UI_Context {
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;
};
Mesh cubeMesh = {0};
Texture wallTex = {0};
@@ -308,6 +380,7 @@ Input getCurrentInput(GLFWwindow *window) {
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);
@@ -324,7 +397,7 @@ Input getCurrentInput(GLFWwindow *window) {
return input;
}
void processInput(Soma *soma) {
void processInput(Soma *soma, UI_Context *ui) {
Input *input = &soma->state.input;
Input *prevInput = &soma->prevState.input;
@@ -332,18 +405,18 @@ void processInput(Soma *soma) {
glfwSetWindowShouldClose(soma->window.handle, true);
}
if (input->keyboard.space && !prevInput->keyboard.space) {
if (input->keyboard.w && !prevInput->keyboard.w) {
glPolygonMode(GL_FRONT_AND_BACK, !soma->state.wireframe ? GL_LINE : GL_FILL);
soma->state.wireframe = !soma->state.wireframe;
}
SceneGraphNode *node = getSceneGraphNode(soma->scene, getEntity(soma->scene, soma->state.light)->graphNodeHandle);
SceneGraphNode *node = getSceneGraphNode(soma->scene, soma->state.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;
node->translation.z += 1.0 * input->keyboard.z * shiftMultiplier;
if (input->keyboard.enter && !prevInput->keyboard.enter) {
if (input->keyboard.space && !prevInput->keyboard.space) {
if (soma->state.displayingSolutions) {
if (soma->state.displayedSolution == soma->solutions.length - 1) {
soma->state.displayedSolution = 0;
@@ -359,8 +432,15 @@ void processInput(Soma *soma) {
}
}
bool dragScene = false;
if (input->mouse.btnLeft) {
if (input->keyboard.enter && !prevInput->keyboard.enter) {
if (soma->state.displayingSolutions) {
soma->state.displayingSolutions = false;
} else {
scheduleSolve(soma);
}
}
if (input->mouse.btnLeft && ui->hotNode == 0) {
uint32 currentObject = soma->state.displayingSolutions
? soma->solutionEntities.data[soma->state.displayedSolution]
: soma->polycubes.data[soma->state.displayedPolycube];
@@ -378,13 +458,13 @@ void processInput(Soma *soma) {
}
}
uint32 createPolycubeFromRepr(Arena *arena, Scene *s, VoxelSpace *repr, RLVector4 color) {
uint32 mainGraphNode = createSceneGraphNode(arena, s);
uint32 createPolycubeFromRepr(Scene *s, VoxelSpace *repr, RLVector4 color) {
uint32 mainGraphNode = createSceneGraphNode(s);
for (int x = 0; x < repr->dim_x; x++) {
for (int y = 0; y < repr->dim_y; y++) {
for (int z = 0; z < repr->dim_z; z++) {
if (filledAt(repr, x, y, z)) {
uint32 segmentEntityHandle = createEntity(arena, s);
uint32 segmentEntityHandle = createEntity(s);
Entity *polycubeSegment = getEntity(s, segmentEntityHandle);
polycubeSegment->color = color;
polycubeSegment->mesh = &cubeMesh;
@@ -429,72 +509,72 @@ RenderObjects_Rectangle createRectangleObjects(Arena *arena, size_t count) {
glBindVertexArray(result.vao);
glBindBuffer(GL_ARRAY_BUFFER, result.p0BufferId);
glBufferData(GL_ARRAY_BUFFER, result.p0.length * sizeof(RLVector2), 0, GL_DYNAMIC_DRAW);
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(RLVector2), (void*)0);
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(RLVector2), 0, GL_DYNAMIC_DRAW);
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(RLVector2), (void*)0);
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(RLVector4), 0, GL_DYNAMIC_DRAW);
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(RLVector4), (void*)0);
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), (void*)0);
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), (void*)0);
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), (void*)0);
glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(FloatList_underlying), NULL);
glVertexAttribDivisor(5, 1);
glEnableVertexAttribArray(5);
return result;
}
void reinitRectangleObjectBuffers(Renderer *r) {
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), r->rects.p0.data);
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), r->rects.p1.data);
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), r->rects.color.data);
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), r->rects.borderRadius.data);
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), r->rects.borderThickness.data);
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), r->rects.edgeSoftness.data);
glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.edgeSoftness.length * sizeof(FloatList_underlying), r->rects.edgeSoftness.data);
}
Renderer createRenderer(Arena *arena, Scene *scene) {
Renderer result = {0};
result.scene = scene;
result.scene->sceneRoot = createSceneGraphNode(arena, scene);
result.rects = createRectangleObjects(arena, 100);
return result;
scene->sceneRoot = createSceneGraphNode(scene);
return (Renderer){
.scene = scene,
.rects = createRectangleObjects(arena, 100),
};
}
void renderBegin(Renderer *r) {
@@ -515,19 +595,19 @@ void renderEnd(Soma *soma, Renderer *renderer) {
setUniformMat4fv(&phongShader, "projection", &soma->state.camera->proj);
setUniformMat4fv(&phongShader, "view", &soma->state.camera->view);
SceneGraphNode *lightGraphNode = getSceneGraphNode(soma->scene, getEntity(soma->scene, soma->state.light)->graphNodeHandle);
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) {
setUniform4fv(&phongShader, "solid_color", &entity->color);
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);
@@ -538,7 +618,7 @@ void renderEnd(Soma *soma, Renderer *renderer) {
// 2D overlay
glUseProgram(solidColorShader.progId);
reinitRectangleObjectBuffers(renderer);
updateRectangleObjectBuffers(renderer);
Matrix ortho = MatrixOrtho(0.0, 800.0, 600.0, 0.0, -1.0, 1.0);
setUniformMat4fv(&solidColorShader, "projection", &ortho);
@@ -548,10 +628,8 @@ void renderEnd(Soma *soma, Renderer *renderer) {
}
void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, RLVector4 color, real32 borderRadius, real32 borderThickness) {
RLVector2 p0 = {x, y};
AppendList(&r->rects.p0, p0);
RLVector2 p1 = {x + width, y + height};
AppendList(&r->rects.p1, p1);
AppendList(&r->rects.p0, ((RLVector2){ x, y }));
AppendList(&r->rects.p1, ((RLVector2){ x + width, y + height }));
AppendList(&r->rects.color, color);
AppendList(&r->rects.borderRadius, borderRadius);
AppendList(&r->rects.borderThickness, borderThickness);
@@ -563,12 +641,15 @@ bool pointInRect(RLVector2 point, UI_Rect rect) {
}
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->prevInput->mouse.btnLeft && !ui->input->mouse.btnLeft) {
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) {
@@ -576,7 +657,7 @@ bool ui_checkboxRect(UI_Context *ui, bool *value, UI_Rect rect) {
rect.x, rect.y,
rect.width, rect.height,
rect.color,
5, 2);
5, 0);
} else {
rendererPlaceRectangle(ui->renderer,
rect.x, rect.y,
@@ -588,13 +669,52 @@ bool ui_checkboxRect(UI_Context *ui, bool *value, UI_Rect rect) {
return clicked;
}
void uiPass(Soma *soma, UI_Context *ui, Renderer *renderer) {
PolycubeInput *currentPolycube = &soma->polycubeInput.data[soma->state.displayedPolycube];
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;
real32 boxSize = 30;
real32 padding = 20;
real32 paddingBetween = 5;
real32 currY = padding;
if (soma->state.displayingSolutions) {
if (soma->solutions.length > 0) {
SomaSolution *currentSolution = &soma->solutions.data[soma->state.displayedSolution];
for (EachIn(*currentSolution, i)) {
uint64 spaceRepr = currentSolution->data[i];
for (int x = 0; x < soma->puzzleDims[0]; x++) {
for (int y = 0; y < soma->puzzleDims[1]; y++) {
real32 currX = padding;
for (int z = 0; z < soma->puzzleDims[2]; z++) {
bool cellActive = filledAt(&(VoxelSpace){
.space = spaceRepr,
.dim_x = soma->puzzleDims[0],
.dim_y = soma->puzzleDims[1],
.dim_z = soma->puzzleDims[2],
}, x, y, z);
if (cellActive) {
rendererPlaceRectangle(ui->renderer,
currX, currY,
boxSize, boxSize,
soma->polycubeInput.data[i].color,
5, 0);
}
currX += paddingBetween + boxSize;
}
currY += paddingBetween + boxSize;
}
currY += padding;
}
currY = padding;
}
}
} else {
PolycubeInput *currentPolycube = &soma->polycubeInput.data[soma->state.displayedPolycube];
for (int x = 0; x < currentPolycube->repr.dim_x; x++) {
for (int y = 0; y < currentPolycube->repr.dim_y; y++) {
real32 currX = padding;
@@ -605,7 +725,7 @@ void uiPass(Soma *soma, UI_Context *ui, Renderer *renderer) {
.y = currY,
.width = boxSize,
.height = boxSize,
.borderRadius = 0,
.borderRadius = 2,
.color = currentPolycube->color,
};
if (ui_checkboxRect(ui, &cellActive, rect)) {
@@ -619,46 +739,127 @@ void uiPass(Soma *soma, UI_Context *ui, Renderer *renderer) {
currY += padding;
}
}
}
int mainCmd() {
interactiveCmdLineSolveSoma();
return 0;
void updatePolycubeDisplay(Arena *arena, Soma *soma) {
if (soma->prevState.displayingSolutions) {
if (soma->prevState.displayedPolycube < soma->polycubes.length) {
hide(soma->scene, soma->polycubes.data[soma->prevState.displayedPolycube]);
show(soma->scene, soma->solutionEntities.data[soma->state.displayedSolution]);
}
} else {
if (soma->prevState.displayedSolution < soma->solutionEntities.length) {
hide(soma->scene, soma->solutionEntities.data[soma->prevState.displayedSolution]);
show(soma->scene, soma->polycubes.data[soma->state.displayedPolycube]);
}
}
if (soma->state.displayingSolutions) {
if (soma->solutions.length > 0) {
if (soma->state.displayedSolution != soma->prevState.displayedSolution) {
show(soma->scene, soma->solutionEntities.data[soma->state.displayedSolution]);
hide(soma->scene, soma->solutionEntities.data[soma->prevState.displayedSolution]);
}
}
} else {
if (soma->state.isInitialState) {
show(soma->scene, soma->polycubes.data[soma->state.displayedPolycube]);
} else if (soma->state.displayedPolycube != soma->prevState.displayedPolycube) {
show(soma->scene, soma->polycubes.data[soma->state.displayedPolycube]);
hide(soma->scene, soma->polycubes.data[soma->prevState.displayedPolycube]);
}
}
if (soma->state.polycubeDirty) {
if (soma->state.displayedPolycube >= 0 && soma->state.displayedPolycube < soma->polycubes.length) {
uint32 currentPolycubeHandle = soma->polycubes.data[soma->state.displayedPolycube];
PolycubeInput *pinput = &soma->polycubeInput.data[soma->state.displayedPolycube];
VoxelSpace culledRepr = pinput->repr;
cullEmptySpace(&culledRepr);
uint32 newPolycubeHandle = createPolycubeFromRepr(soma->scene, &culledRepr, pinput->color);
SceneGraphNode *newPolycubeGraphNode = getSceneGraphNode(soma->scene, newPolycubeHandle);
newPolycubeGraphNode->rotation = getSceneGraphNode(soma->scene, currentPolycubeHandle)->rotation;
removeEntity(soma->scene, currentPolycubeHandle);
soma->polycubes.data[soma->state.displayedPolycube] = newPolycubeHandle;
sceneNodeAddNode(soma->scene, soma->scene->sceneRoot, newPolycubeHandle);
soma->state.polycubeDirty = false;
hide(soma->scene, currentPolycubeHandle);
show(soma->scene, newPolycubeHandle);
}
}
}
void createSolutionEntities(Arena *arena, Soma *soma) {
if (soma->solutions.length > 0) {
soma->solutionEntities = PushList(arena, HandleList, soma->solutions.length);
for (EachEl(soma->solutions, SomaSolution, solution)) {
uint32 solutionGraphNodeHandle = createSceneGraphNode(soma->scene);
AppendList(&soma->solutionEntities, solutionGraphNodeHandle);
sceneNodeAddNode(soma->renderer->scene, soma->renderer->scene->sceneRoot, solutionGraphNodeHandle);
for (EachIn(*solution, soln_i)) {
uint32 polycubeGraphNodeHandle = createPolycubeFromRepr(
soma->scene,
&(VoxelSpace){ solution->data[soln_i], 3, 3, 3 },
colorFromIndex(soln_i)
);
sceneNodeAddNode(soma->renderer->scene, solutionGraphNodeHandle, polycubeGraphNodeHandle);
}
}
show(soma->scene, soma->solutionEntities.data[soma->state.displayedSolution]);
}
}
int mainGfx() {
Arena *arena = arenaAlloc(Megabytes(128));
Arena *solutionsArena = arenaAlloc(Megabytes(128));
Scene mainScene = createScene(arena);
Soma soma = {};
soma.window.width = 800;
soma.window.height = 600;
soma.window.handle = initWindowAndGL(soma.window.width, soma.window.height);
soma.scene = &mainScene;
Renderer renderer = createRenderer(arena, &mainScene);
soma.renderer = &renderer;
if (!soma.window.handle) {
return -1;
int winWidth = 800, winHeight = 600;
GLFWwindow *windowHandle = initWindowAndGL(winWidth, winHeight);
if (!windowHandle) {
return 1;
}
Frame mainFrame = createFrame(arena, soma.window.width, soma.window.height, 0, 0);
UI_Context ui = {};
Scene mainScene = createScene(arena);
Renderer renderer = createRenderer(arena, &mainScene);
Frame mainFrame = createFrame(arena, winWidth, winHeight, 0, 0);
GLFWcursor *pointerCursor = glfwCreateStandardCursor(GLFW_HAND_CURSOR);
GLFWcursor *arrowCursor = glfwCreateStandardCursor(GLFW_ARROW_CURSOR);
UI_Context ui = {
.hotNode = 0,
.nextId = 1,
.cursorIsPointer = false,
.input = NULL,
.prevInput = NULL,
.renderer = &renderer,
};
soma.polycubeInput = PushListZero(arena, PolycubeInputList, 64);
soma.polycubes = PushListZero(arena, HandleList, 64);
Soma soma = {
.window = {
.width = 800,
.height = 600,
.handle = windowHandle,
.cursors = {
.pointer = glfwCreateStandardCursor(GLFW_HAND_CURSOR),
.arrow = glfwCreateStandardCursor(GLFW_ARROW_CURSOR),
},
},
.scene = &mainScene,
.renderer = &renderer,
.polycubeInput = PushListZero(arena, PolycubeInputList, 64),
.polycubes = PushListZero(arena, HandleList, 64),
.puzzleDims = {3, 3, 3},
.solveTaskCtx = NULL,
.solveArena = arenaAlloc(Megabytes(128)),
.state = {
.displayingSolutions = false,
.displayedPolycube = 0,
.displayedSolution = 0,
.isInitialState = true,
.light = createEntity(&mainScene),
.camera = mainFrame.cam,
},
};
soma.state.displayingSolutions = true;
soma.state.displayedPolycube = 0;
soma.state.displayedSolution = 0;
soma.state.light = createEntity(arena, &mainScene);
soma.state.camera = mainFrame.cam;
SceneGraphNode *light = getSceneGraphNode(&mainScene, getEntity(&mainScene, soma.state.light)->graphNodeHandle);
light->translation = (RLVector3){4.0f, 6.0f, 24.0f};
getSceneGraphNode(&mainScene, soma.state.light)->translation = (RLVector3){4.0f, 6.0f, 24.0f};
/*
Shader solid_texture_shader = createShader(
@@ -684,31 +885,12 @@ int mainGfx() {
PolycubeInput input = (PolycubeInput){ voxelSpace, color };
AppendList(&soma.polycubeInput, input);
cullEmptySpace(&voxelSpace);
uint32 polycubeGraphNodeHandle = createPolycubeFromRepr(arena, soma.scene, &voxelSpace, color);
uint32 polycubeGraphNodeHandle = createPolycubeFromRepr(soma.scene, &voxelSpace, color);
AppendList(&soma.polycubes, polycubeGraphNodeHandle);
sceneNodeAddNode(renderer.scene, renderer.scene->sceneRoot, polycubeGraphNodeHandle);
}
soma.solutions = solveSoma(arena, AsList(VoxelSpaceReprList, STD_SOMA), (int[]){ 3, 3, 3 });
soma.solutionEntities = PushList(arena, HandleList, soma.solutions.length);
for (EachEl(soma.solutions, SomaSolution, solution)) {
uint32 solutionGraphNodeHandle = createSceneGraphNode(arena, soma.scene);
AppendList(&soma.solutionEntities, solutionGraphNodeHandle);
sceneNodeAddNode(renderer.scene, renderer.scene->sceneRoot, solutionGraphNodeHandle);
for (EachIn(*solution, soln_i)) {
uint32 polycubeGraphNodeHandle = createPolycubeFromRepr(
arena,
soma.scene,
&(VoxelSpace){ solution->data[soln_i], 3, 3, 3 },
colorFromIndex(soln_i)
);
sceneNodeAddNode(renderer.scene, solutionGraphNodeHandle, polycubeGraphNodeHandle);
}
}
show(soma.scene, soma.solutionEntities.data[soma.state.displayedSolution]);
print("%zu\n", soma.scene->entities.length);
print("%zu\n", soma.scene->graphNodes.length);
// 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);
@@ -727,34 +909,21 @@ int mainGfx() {
glfwPollEvents();
soma.state.input = getCurrentInput(soma.window.handle);
processInput(&soma);
/*
if (soma.state.lastPolycubeVisible != soma.state.currentPolycube) {
hide(soma.scene, soma.state.polycubes.data[soma.state.lastPolycubeVisible].graphNodeHandle);
show(soma.scene, soma.state.polycubes.data[soma.state.currentPolycube].graphNodeHandle);
soma.state.lastPolycubeVisible = soma.state.currentPolycube;
processInput(&soma, &ui);
updatePolycubeDisplay(arena, &soma);
if (soma.solveTaskCtx != NULL && soma.solveTaskCtx->taskStatus == SolveTaskStatus_Complete) {
soma.solutions = PushFullList(solutionsArena, SomaSolutionList, soma.solveTaskCtx->solutions.length);
memcpy(soma.solutions.data, soma.solveTaskCtx->solutions.data, soma.solutions.length*sizeof(soma.solutions.data[0]));
for (EachIn(soma.solutions, i)) {
soma.solutions.data[i] = PushFullList(solutionsArena, SomaSolution, soma.solveTaskCtx->input.length);
memcpy(&soma.solutions.data[i], &soma.solveTaskCtx->solutions.data[i], soma.solveTaskCtx->input.length*sizeof(uint64));
}
*/
if (soma.state.displayedSolution != soma.prevState.displayedSolution) {
show(soma.scene, soma.solutionEntities.data[soma.state.displayedSolution]);
hide(soma.scene, soma.solutionEntities.data[soma.prevState.displayedSolution]);
}
if (soma.state.polycubeDirty) {
uint32 currentPolycube = soma.polycubes.data[soma.state.displayedPolycube];
PolycubeInput *pinput = &soma.polycubeInput.data[soma.state.displayedPolycube];
removeEntity(soma.scene, currentPolycube);
VoxelSpace culledRepr = pinput->repr;
cullEmptySpace(&culledRepr);
uint32 newPolycube = createPolycubeFromRepr(arena, soma.scene, &culledRepr, pinput->color);
SceneGraphNode *graphNode = getSceneGraphNode(soma.scene, newPolycube);
graphNode->rotation = getSceneGraphNode(soma.scene, currentPolycube)->rotation;
soma.polycubes.data[soma.state.displayedPolycube] = newPolycube;
sceneNodeAddNode(soma.scene, soma.scene->sceneRoot, newPolycube);
soma.state.polycubeDirty = false;
show(soma.scene, newPolycube);
createSolutionEntities(soma.solveTaskCtx->arena, &soma);
soma.solveTaskCtx->taskStatus = SolveTaskStatus_Ready;
soma.state.displayingSolutions = true;
arenaFreeFrom(soma.solveTaskCtx->arena, 0);
}
updateViewportFromFrame(soma.window.width, soma.window.height, &mainFrame);
@@ -762,15 +931,11 @@ int mainGfx() {
renderBegin(&renderer);
ui.cursorIsPointer = false;
ui.prevInput = &soma.prevState.input;
ui.input = &soma.state.input;
ui.renderer = &renderer;
uiPass(&soma, &ui, &renderer);
uiPass(&soma, &ui);
if (ui.cursorIsPointer) {
glfwSetCursor(soma.window.handle, pointerCursor);
glfwSetCursor(soma.window.handle, soma.window.cursors.pointer);
} else {
glfwSetCursor(soma.window.handle, arrowCursor);
glfwSetCursor(soma.window.handle, soma.window.cursors.arrow);
}
renderEnd(&soma, &renderer);
@@ -783,6 +948,7 @@ int mainGfx() {
glfwSwapBuffers(soma.window.handle);
soma.prevState = soma.state;
soma.state.isInitialState = false;
}
glfwTerminate();

View File

@@ -1,29 +1,39 @@
#include "string.h"
#include "scene.h"
Entity *getEntity(Scene *s, uint32 id) {
return &s->entities.data[id - 1];
Entity *getEntity(Scene *s, uint32 entityHandle) {
if (entityHandle) {
return &s->entities.data[entityHandle - 1];
}
SceneGraphNode *getSceneGraphNodeForEntity(Scene *s, uint32 entityHandle) {
return &s->graphNodes.data[s->entities.data[entityHandle - 1].graphNodeHandle - 1];
return NULL;
}
SceneGraphNode *getSceneGraphNode(Scene *s, uint32 sceneGraphNodeHandle) {
if (sceneGraphNodeHandle) {
return &s->graphNodes.data[sceneGraphNodeHandle - 1];
}
return NULL;
}
uint32 createSceneGraphNode(Arena *arena, Scene *s) {
SceneGraphNode *getSceneGraphNodeForEntity(Scene *s, uint32 entityHandle) {
Entity *e = getEntity(s, entityHandle);
if (e) {
return getSceneGraphNode(s, e->graphNodeHandle);
}
return NULL;
}
uint32 createSceneGraphNode(Scene *s) {
AppendList(&s->graphNodes, (SceneGraphNode){0});
SceneGraphNode *node = &s->graphNodes.data[s->graphNodes.length - 1];
node->children = PushList(arena, HandleList, 1000);
node->children = PushList(s->arena, HandleList, 1000);
initGraphNode(node);
return (uint32)s->graphNodes.length;
}
uint32 createEntity(Arena *arena, Scene *s) {
uint32 createEntity(Scene *s) {
AppendList(&s->entities, (Entity){0});
uint32 graphNodeId = createSceneGraphNode(arena, s);
uint32 graphNodeId = createSceneGraphNode(s);
s->entities.data[s->entities.length - 1].graphNodeHandle = graphNodeId;
getSceneGraphNode(s, graphNodeId)->entityHandle = (uint32)s->entities.length;
uint32 handle = (uint32)s->entities.length;
@@ -44,10 +54,12 @@ void recalcGraphNode(SceneGraphNode *n) {
}
Scene createScene(Arena *arena) {
Scene result = {};
result.entities = PushList(arena, EntityList, 100000);
result.graphNodes = PushList(arena, SceneGraphNodeList, 100000);
result.sceneRoot = createSceneGraphNode(arena, &result);
Scene result = {
.arena = arena,
.entities = PushList(arena, EntityList, 100000),
.graphNodes = PushList(arena, SceneGraphNodeList, 100000),
};
result.sceneRoot = createSceneGraphNode(&result);
return result;
}
@@ -74,18 +86,19 @@ void removeEntity(Scene *s, uint32 entityHandle) {
Entity *entity = getEntity(s, entityHandle);
entity->flags |= EntityFlags_Dead;
SceneGraphNode *graphNode = getSceneGraphNode(s, entity->graphNodeHandle);
if (graphNode->parentHandle) {
if (graphNode != NULL && graphNode->parentHandle) {
SceneGraphNode *parentNode = getSceneGraphNode(s, graphNode->parentHandle);
for (int i = 0; i < parentNode->children.length; i++) {
if (parentNode != NULL) {
for (EachIn(parentNode->children, i)) {
if (parentNode->children.data[i] == entity->graphNodeHandle) {
memcpy(&parentNode->children.data[i], &parentNode->children.data[i + 1], parentNode->children.length - i);
parentNode->children.length -= 1;
ListRemove(&parentNode->children, i);
graphNode->parentHandle = 0;
break;
}
}
}
}
}
void sceneNodeAddEntity(Scene *s, uint32 graphNodeHandle, uint32 entityHandle) {
HandleList *childList = &getSceneGraphNode(s, graphNodeHandle)->children;

View File

@@ -37,12 +37,13 @@ struct Scene {
uint32 sceneRoot;
EntityList entities;
SceneGraphNodeList graphNodes;
Arena *arena;
};
uint32 createEntity(Arena *arena, Scene *s);
uint32 createEntity(Scene *s);
Entity *getEntity(Scene *s, uint32 id);
SceneGraphNode *getSceneGraphNode(Scene *s, uint32 id);
uint32 createSceneGraphNode(Arena *arena, Scene *s);
uint32 createSceneGraphNode(Scene *s);
Scene createScene(Arena *arena);
void initGraphNode(SceneGraphNode *n);
void recalcGraphNode(SceneGraphNode *n);