updates
This commit is contained in:
1
.clangd
1
.clangd
@@ -2,6 +2,7 @@ CompileFlags:
|
|||||||
Add:
|
Add:
|
||||||
- -std=c99
|
- -std=c99
|
||||||
- -xc
|
- -xc
|
||||||
|
- -Wno-initializer-overrides
|
||||||
# LINUX FLAGS
|
# LINUX FLAGS
|
||||||
- -DOS_LINUX
|
- -DOS_LINUX
|
||||||
- -DCOMPOSITOR_WAYLAND
|
- -DCOMPOSITOR_WAYLAND
|
||||||
|
|||||||
@@ -30,9 +30,9 @@ void main() {
|
|||||||
float interior_corner_radius = frag_border_radius * interior_radius_reduce_f * interior_radius_reduce_f;
|
float interior_corner_radius = frag_border_radius * interior_radius_reduce_f * interior_radius_reduce_f;
|
||||||
|
|
||||||
float inside_d = roundedRectSDF(
|
float inside_d = roundedRectSDF(
|
||||||
frag_dest_position,
|
frag_dest_position,
|
||||||
frag_dest_center,
|
frag_dest_center,
|
||||||
interior_half_size - softness_padding,
|
interior_half_size - softness_padding,
|
||||||
interior_corner_radius);
|
interior_corner_radius);
|
||||||
|
|
||||||
|
|
||||||
@@ -41,15 +41,15 @@ void main() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
float dist = roundedRectSDF(
|
float dist = roundedRectSDF(
|
||||||
frag_dest_position,
|
frag_dest_position,
|
||||||
frag_dest_center,
|
frag_dest_center,
|
||||||
frag_dest_half_size - softness_padding,
|
frag_dest_half_size - softness_padding,
|
||||||
frag_border_radius);
|
frag_border_radius);
|
||||||
|
|
||||||
// For texturing later
|
// For texturing later
|
||||||
float sample = 1;
|
float sample = 1;
|
||||||
|
|
||||||
float sdf_factor = 1.0f - smoothstep(0, 2*frag_softness, dist);
|
float sdf_factor = 1 - smoothstep(0, 2*frag_softness, dist);
|
||||||
|
|
||||||
pixel_color = frag_color * sample * sdf_factor * border_factor;
|
pixel_color = frag_color * sample * sdf_factor * border_factor;
|
||||||
};
|
};
|
||||||
|
|||||||
2
build
2
build
@@ -1,7 +1,7 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
|
|
||||||
LIB_INCLUDE="-lglfw -lGL -lm"
|
LIB_INCLUDE="-lglfw -lGL -lm"
|
||||||
COMMON_FLAGS="-DOS_LINUX=1 -xc -std=c99"
|
COMMON_FLAGS="-DOS_LINUX=1 -DCOMPOSITOR_WAYLAND=1 -xc -std=c99 -Wno-initializer-overrides"
|
||||||
|
|
||||||
echo [Building target]
|
echo [Building target]
|
||||||
if [ $DEBUG ]; then
|
if [ $DEBUG ]; then
|
||||||
|
|||||||
@@ -2,8 +2,7 @@
|
|||||||
#include "lib/djstdlib/core.h"
|
#include "lib/djstdlib/core.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
void printRLVec3(RLVector3* vector) {
|
void printRLVec3(RLVector3 vec) {
|
||||||
RLVector3 vec = *vector;
|
|
||||||
print(
|
print(
|
||||||
"┌ ┐\n"
|
"┌ ┐\n"
|
||||||
"│%7.2f%, %7.2f, %7.2f │\n"
|
"│%7.2f%, %7.2f, %7.2f │\n"
|
||||||
@@ -11,8 +10,7 @@ void printRLVec3(RLVector3* vector) {
|
|||||||
vec.x, vec.y, vec.z);
|
vec.x, vec.y, vec.z);
|
||||||
}
|
}
|
||||||
|
|
||||||
void printMatrix(Matrix* matrix) {
|
void printMatrix(Matrix mat) {
|
||||||
Matrix mat = *matrix;
|
|
||||||
print(
|
print(
|
||||||
"┌ ┐\n"
|
"┌ ┐\n"
|
||||||
"│%7.2f%, %7.2f, %7.2f, %7.2f │\n"
|
"│%7.2f%, %7.2f, %7.2f, %7.2f │\n"
|
||||||
|
|||||||
@@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
#include "lib/raymath.h"
|
#include "lib/raymath.h"
|
||||||
|
|
||||||
void printRLVec3(RLVector3* vector);
|
void printRLVec3(RLVector3 vector);
|
||||||
void printMatrix(Matrix* matrix);
|
void printMatrix(Matrix matrix);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
256
src/main.c
256
src/main.c
@@ -1,3 +1,4 @@
|
|||||||
|
#include "lib/djstdlib/core.h"
|
||||||
#define _POSIX_C_SOURCE 199309L
|
#define _POSIX_C_SOURCE 199309L
|
||||||
#include "time.h"
|
#include "time.h"
|
||||||
|
|
||||||
@@ -65,6 +66,7 @@ struct SomaState {
|
|||||||
bool displayingSolutions;
|
bool displayingSolutions;
|
||||||
RLVector3 rotAxisX;
|
RLVector3 rotAxisX;
|
||||||
RLVector3 rotAxisY;
|
RLVector3 rotAxisY;
|
||||||
|
UI_Rect *threedeePaneRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Soma Soma;
|
typedef struct Soma Soma;
|
||||||
@@ -84,6 +86,7 @@ struct Soma {
|
|||||||
SomaState prevState;
|
SomaState prevState;
|
||||||
SomaState state;
|
SomaState state;
|
||||||
|
|
||||||
|
UI_Context *ui;
|
||||||
PolycubeInputList polycubeInput;
|
PolycubeInputList polycubeInput;
|
||||||
HandleList polycubes;
|
HandleList polycubes;
|
||||||
SomaSolutionList solutions;
|
SomaSolutionList solutions;
|
||||||
@@ -101,7 +104,10 @@ void *executeSolve(void *ctx) {
|
|||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
void scheduleSolve(Soma *soma) {
|
void tryScheduleSolve(Soma *soma) {
|
||||||
|
if (soma->solveTaskCtx.taskStatus != SolveTaskStatus_Ready) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
VoxelSpaceReprList mappedInputs = PushList(soma->solveTaskCtx.arena, VoxelSpaceReprList, soma->polycubeInput.length);
|
VoxelSpaceReprList mappedInputs = PushList(soma->solveTaskCtx.arena, VoxelSpaceReprList, soma->polycubeInput.length);
|
||||||
for (EachEl(soma->polycubeInput, PolycubeInput, polycubeInput)) {
|
for (EachEl(soma->polycubeInput, PolycubeInput, polycubeInput)) {
|
||||||
ListAppend(mappedInputs, polycubeInput->repr.space);
|
ListAppend(mappedInputs, polycubeInput->repr.space);
|
||||||
@@ -130,7 +136,9 @@ RLVector3 centreFromPolycube(Scene *scene, uint32 p) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void framebufferSizeCallback(GLFWwindow *window, int width, int height) {
|
void framebufferSizeCallback(GLFWwindow *window, int width, int height) {
|
||||||
glViewport(0, 0, width, height);
|
Soma *soma = (Soma *)glfwGetWindowUserPointer(window);
|
||||||
|
soma->renderer->width = width;
|
||||||
|
soma->renderer->height = height;
|
||||||
}
|
}
|
||||||
|
|
||||||
GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) {
|
GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) {
|
||||||
@@ -168,7 +176,7 @@ GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
glViewport(0, 0, windowWidth, windowHeight);
|
glViewport(0, 0, windowWidth, windowHeight);
|
||||||
glfwSwapInterval(1);
|
glfwSwapInterval(0);
|
||||||
glfwSetFramebufferSizeCallback(window, framebufferSizeCallback);
|
glfwSetFramebufferSizeCallback(window, framebufferSizeCallback);
|
||||||
glfwSetInputMode(window, GLFW_CURSOR | GLFW_RAW_MOUSE_MOTION, GLFW_CURSOR_NORMAL);
|
glfwSetInputMode(window, GLFW_CURSOR | GLFW_RAW_MOUSE_MOTION, GLFW_CURSOR_NORMAL);
|
||||||
glfwSetWindowSize(window, windowWidth, windowHeight);
|
glfwSetWindowSize(window, windowWidth, windowHeight);
|
||||||
@@ -183,9 +191,47 @@ Texture wallTex = {0};
|
|||||||
Shader solidColorShader;
|
Shader solidColorShader;
|
||||||
Shader phongShader;
|
Shader phongShader;
|
||||||
|
|
||||||
void processInput(Soma *soma, UI_Context *ui) {
|
static void advanceDisplayReverse(Soma *soma) {
|
||||||
Input *input = ui->input;
|
if (soma->state.displayingSolutions) {
|
||||||
Input *prevInput = ui->prevInput;
|
if (soma->state.displayedSolution == 0) {
|
||||||
|
soma->state.displayedSolution = soma->solutions.length - 1;
|
||||||
|
} else {
|
||||||
|
soma->state.displayedSolution -= 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (soma->state.displayedPolycube == 0) {
|
||||||
|
soma->state.displayedPolycube = soma->polycubeInput.length - 1;
|
||||||
|
} else {
|
||||||
|
soma->state.displayedPolycube -= 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void advanceDisplay(Soma *soma) {
|
||||||
|
if (soma->state.displayingSolutions) {
|
||||||
|
if (soma->state.displayedSolution == soma->solutions.length - 1) {
|
||||||
|
soma->state.displayedSolution = 0;
|
||||||
|
} else {
|
||||||
|
soma->state.displayedSolution += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (soma->state.displayedPolycube == soma->polycubeInput.length - 1) {
|
||||||
|
soma->state.displayedPolycube = 0;
|
||||||
|
} else {
|
||||||
|
soma->state.displayedPolycube += 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void onMouseScroll(GLFWwindow *window, real64 deltaX, real64 deltaY) {
|
||||||
|
Soma *soma = (Soma *)glfwGetWindowUserPointer(window);
|
||||||
|
soma->ui->input->mouse.scroll.dX += deltaX;
|
||||||
|
soma->ui->input->mouse.scroll.dY += deltaY;
|
||||||
|
}
|
||||||
|
|
||||||
|
void processInput(Soma *soma) {
|
||||||
|
Input *input = soma->ui->input;
|
||||||
|
Input *prevInput = soma->ui->prevInput;
|
||||||
|
|
||||||
if (input->keyboard.escape) {
|
if (input->keyboard.escape) {
|
||||||
glfwSetWindowShouldClose(soma->window.handle, true);
|
glfwSetWindowShouldClose(soma->window.handle, true);
|
||||||
@@ -203,31 +249,19 @@ void processInput(Soma *soma, UI_Context *ui) {
|
|||||||
node->translation.z += 1.0 * input->keyboard.z * shiftMultiplier;
|
node->translation.z += 1.0 * input->keyboard.z * shiftMultiplier;
|
||||||
|
|
||||||
if (input->keyboard.space && !prevInput->keyboard.space) {
|
if (input->keyboard.space && !prevInput->keyboard.space) {
|
||||||
if (soma->state.displayingSolutions) {
|
advanceDisplay(soma);
|
||||||
if (soma->state.displayedSolution == soma->solutions.length - 1) {
|
|
||||||
soma->state.displayedSolution = 0;
|
|
||||||
} else {
|
|
||||||
soma->state.displayedSolution += 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (soma->state.displayedPolycube == soma->polycubeInput.length - 1) {
|
|
||||||
soma->state.displayedPolycube = 0;
|
|
||||||
} else {
|
|
||||||
soma->state.displayedPolycube += 1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input->keyboard.enter && !prevInput->keyboard.enter) {
|
if (input->keyboard.enter && !prevInput->keyboard.enter) {
|
||||||
if (soma->state.displayingSolutions) {
|
if (soma->state.displayingSolutions) {
|
||||||
soma->state.displayingSolutions = false;
|
soma->state.displayingSolutions = false;
|
||||||
soma->state.displayedSolution = -1;
|
soma->state.displayedSolution = -1;
|
||||||
} else if (soma->solveTaskCtx.taskStatus == SolveTaskStatus_Ready) {
|
} else {
|
||||||
scheduleSolve(soma);
|
tryScheduleSolve(soma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (input->mouse.btnLeft && ui->hotNode == 0) {
|
if (input->mouse.btnLeft && soma->ui->hotNode == 0) {
|
||||||
uint32 currentObject = soma->state.displayingSolutions
|
uint32 currentObject = soma->state.displayingSolutions
|
||||||
? soma->solutionNode
|
? soma->solutionNode
|
||||||
: soma->polycubes.data[soma->state.displayedPolycube];
|
: soma->polycubes.data[soma->state.displayedPolycube];
|
||||||
@@ -243,6 +277,29 @@ void processInput(Soma *soma, UI_Context *ui) {
|
|||||||
objectGraphNode->rotation = QuaternionMultiply(QuaternionFromAxisAngle(soma->state.rotAxisX, -(real32)deltaY), objectGraphNode->rotation);
|
objectGraphNode->rotation = QuaternionMultiply(QuaternionFromAxisAngle(soma->state.rotAxisX, -(real32)deltaY), objectGraphNode->rotation);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (soma->state.displayingSolutions) {
|
||||||
|
real64 scrollDelta = soma->ui->prevInput->mouse.scroll.dY;
|
||||||
|
if (scrollDelta > 0.001 || scrollDelta < -0.001) {
|
||||||
|
SceneGraphNode *rootNode = getSceneGraphNode(soma->scene, soma->solutionNode);
|
||||||
|
int32 nextChildHandle = rootNode->firstChild;
|
||||||
|
while (nextChildHandle) {
|
||||||
|
SceneGraphNode *nextChild = getSceneGraphNode(soma->scene, nextChildHandle);
|
||||||
|
RLVector3 centre = {0};
|
||||||
|
int32 subsegmentHandle = nextChild->firstChild;
|
||||||
|
int32 subsegmentCount = 0;
|
||||||
|
while (subsegmentHandle) {
|
||||||
|
subsegmentCount++;
|
||||||
|
SceneGraphNode *subSegment = getSceneGraphNode(soma->scene, subsegmentHandle);
|
||||||
|
centre = Vector3Add(centre, subSegment->translation);
|
||||||
|
subsegmentHandle = subSegment->nextSibling;
|
||||||
|
}
|
||||||
|
RLVector3 flyDirection = Vector3Normalize(Vector3Scale(Vector3Transform(centre, nextChild->local), -1.f/subsegmentCount));
|
||||||
|
nextChild->translation = Vector3Add(nextChild->translation, Vector3Scale(flyDirection, scrollDelta * 0.1));
|
||||||
|
nextChildHandle = nextChild->nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
uint32 createPolycubeFromRepr(Scene *s, VoxelSpace *repr, RLVector4 color) {
|
uint32 createPolycubeFromRepr(Scene *s, VoxelSpace *repr, RLVector4 color) {
|
||||||
@@ -273,67 +330,101 @@ uint32 createPolycubeFromRepr(Scene *s, VoxelSpace *repr, RLVector4 color) {
|
|||||||
return mainGraphNode;
|
return mainGraphNode;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void somaUIPass(Soma *soma, UI_Context *ui) {
|
static void ui_Interaction(UI_Context *ui, Soma *soma) {
|
||||||
real32 boxSize = 30;
|
real32 boxSize = 30;
|
||||||
real32 padding = 20;
|
real32 padding = 20;
|
||||||
real32 paddingBetween = 5;
|
real32 childGap = 5;
|
||||||
real32 currY = padding;
|
|
||||||
|
|
||||||
if (soma->state.displayingSolutions) {
|
UI(ui, .childGap=padding, .flags=UI_Flag_Vertical) {
|
||||||
if (soma->solutions.length > 0) {
|
if (soma->state.displayingSolutions && soma->solutions.length > 0) {
|
||||||
SomaSolution *currentSolution = &soma->solutions.data[soma->state.displayedSolution];
|
SomaSolution *currentSolution = &soma->solutions.data[soma->state.displayedSolution];
|
||||||
for (EachIn(*currentSolution, i)) {
|
for (int x = 0; x < soma->puzzleDims[0]; x++) UI(ui, .childGap=childGap, .flags=UI_Flag_Vertical) {
|
||||||
uint64 spaceRepr = currentSolution->data[i];
|
for (int y = 0; y < soma->puzzleDims[1]; y++) UI(ui, .childGap=childGap) {
|
||||||
for (int x = 0; x < soma->puzzleDims[0]; x++) {
|
for (int z = 0; z < soma->puzzleDims[2]; z++) {
|
||||||
for (int y = 0; y < soma->puzzleDims[1]; y++) {
|
for (EachIn(*currentSolution, i)) {
|
||||||
real32 currX = padding;
|
uint64 spaceRepr = currentSolution->data[i];
|
||||||
for (int z = 0; z < soma->puzzleDims[2]; z++) {
|
|
||||||
bool cellActive = filledAt(&(VoxelSpace){
|
bool cellActive = filledAt(&(VoxelSpace){
|
||||||
.space = spaceRepr,
|
.space = spaceRepr,
|
||||||
.dim_x = soma->puzzleDims[0],
|
.dim_x = soma->puzzleDims[0],
|
||||||
.dim_y = soma->puzzleDims[1],
|
.dim_y = soma->puzzleDims[1],
|
||||||
.dim_z = soma->puzzleDims[2],
|
.dim_z = soma->puzzleDims[2],
|
||||||
}, x, y, z);
|
}, x, y, z);
|
||||||
if (cellActive) {
|
if (cellActive) UI(ui,
|
||||||
rendererPlaceRectangle(ui->renderer,
|
.width=boxSize,
|
||||||
currX, currY,
|
.height=boxSize,
|
||||||
boxSize, boxSize,
|
.color=soma->polycubeInput.data[i].color,
|
||||||
soma->polycubeInput.data[i].color,
|
.borderRadius=5,
|
||||||
5, 0);
|
.borderThickness=0,
|
||||||
}
|
);
|
||||||
currX += paddingBetween + boxSize;
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
PolycubeInput *currentPolycube = &soma->polycubeInput.data[soma->state.displayedPolycube];
|
||||||
|
for (int x = 0; x < currentPolycube->repr.dim_x; x++) UI(ui, .childGap=childGap, .flags=UI_Flag_Vertical) {
|
||||||
|
for (int y = 0; y < currentPolycube->repr.dim_y; y++) UI(ui, .childGap=childGap) {
|
||||||
|
for (int z = 0; z < currentPolycube->repr.dim_z; z++) {
|
||||||
|
bool cellActive = filledAt(¤tPolycube->repr, x, y, z);
|
||||||
|
if (ui_CheckboxRect(ui, &cellActive, UI_CreateRect(
|
||||||
|
.width = boxSize,
|
||||||
|
.height = boxSize,
|
||||||
|
.borderRadius = 2,
|
||||||
|
.color = currentPolycube->color,
|
||||||
|
))) {
|
||||||
|
soma->state.polycubeDirty = true;
|
||||||
|
spaceSet(¤tPolycube->repr, cellActive, x, y, z);
|
||||||
}
|
}
|
||||||
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++) {
|
static void DJUI_Soma(UI_Context *ui, Soma *soma) {
|
||||||
real32 currX = padding;
|
UI(ui, .flags=UI_Flag_HeightGrow | UI_Flag_WidthGrow) {
|
||||||
for (int z = 0; z < currentPolycube->repr.dim_z; z++) {
|
UI(ui, .padding=UI_PadUniform(10), .color={0.2, 0.2, 0.2, 1}, .flags=UI_Flag_HeightGrow) {
|
||||||
bool cellActive = filledAt(¤tPolycube->repr, x, y, z);
|
ui_Interaction(ui, soma);
|
||||||
UI_Rect rect = {
|
}
|
||||||
.x = currX,
|
UI(ui, .flags=UI_Flag_Vertical | UI_Flag_HeightGrow | UI_Flag_WidthGrow) {
|
||||||
.y = currY,
|
UI(ui, .padding=UI_PadUniform(5), .color={0.2, 0.2, 0.2, 1}, .flags=UI_Flag_WidthGrow) {
|
||||||
.width = boxSize,
|
UI(ui, .width=65);
|
||||||
.height = boxSize,
|
UI(ui, .flags=UI_Flag_WidthGrow);
|
||||||
.borderRadius = 2,
|
UI(ui) {
|
||||||
.color = currentPolycube->color,
|
RLVector4 color = {0.5, 0.5, 0.5, 1};
|
||||||
};
|
UI(ui, .childGap=10) {
|
||||||
if (ui_checkboxRect(ui, &cellActive, rect)) {
|
if (ui_Button(ui, UI_CreateRect(.width=30, .height=30, .color=color))) {
|
||||||
soma->state.polycubeDirty = true;
|
advanceDisplayReverse(soma);
|
||||||
spaceSet(¤tPolycube->repr, cellActive, x, y, z);
|
}
|
||||||
|
if (ui_Button(ui, UI_CreateRect(.width=30, .height=30, .color=color))) {
|
||||||
|
advanceDisplay(soma);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
UI(ui, .flags=UI_Flag_WidthGrow);
|
||||||
|
UI(ui, .width=65, .childGap=5) {
|
||||||
|
if (ui_Button(ui, UI_CreateRect(
|
||||||
|
.width=30,
|
||||||
|
.height=30,
|
||||||
|
.color=soma->state.displayingSolutions ? (RLVector4){1,0,0,0.5} : COLOR_RED,
|
||||||
|
))) {
|
||||||
|
soma->state.displayingSolutions = false;
|
||||||
|
}
|
||||||
|
if (ui_Button(ui, UI_CreateRect(
|
||||||
|
.width=30,
|
||||||
|
.height=30,
|
||||||
|
.color=soma->state.displayingSolutions ? COLOR_GREEN : (RLVector4){0,1,0,0.5},
|
||||||
|
))) {
|
||||||
|
if (!soma->state.displayingSolutions) {
|
||||||
|
tryScheduleSolve(soma);
|
||||||
|
} else {
|
||||||
|
soma->state.displayingSolutions = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
currX += paddingBetween + boxSize;
|
|
||||||
}
|
}
|
||||||
currY += paddingBetween + boxSize;
|
|
||||||
}
|
}
|
||||||
currY += padding;
|
UI(ui, .flags=UI_Flag_WidthGrow | UI_Flag_HeightGrow | UI_Flag_3DScene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -399,8 +490,6 @@ static void updatePolycubeDisplay(Soma *soma) {
|
|||||||
|
|
||||||
static void updateWindow(Soma *soma) {
|
static void updateWindow(Soma *soma) {
|
||||||
glfwGetWindowSize(soma->window.handle, &soma->window.width, &soma->window.height);
|
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->width = soma->window.width;
|
||||||
soma->renderer->height = soma->window.height;
|
soma->renderer->height = soma->window.height;
|
||||||
}
|
}
|
||||||
@@ -450,6 +539,7 @@ int mainGfx() {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
.scene = &mainScene,
|
.scene = &mainScene,
|
||||||
|
.ui = &ui,
|
||||||
.renderer = &renderer,
|
.renderer = &renderer,
|
||||||
.polycubeInput = PushListZero(arena, PolycubeInputList, MAX_POLYCUBE_INPUT),
|
.polycubeInput = PushListZero(arena, PolycubeInputList, MAX_POLYCUBE_INPUT),
|
||||||
.polycubes = PushListZero(arena, HandleList, MAX_POLYCUBE_INPUT),
|
.polycubes = PushListZero(arena, HandleList, MAX_POLYCUBE_INPUT),
|
||||||
@@ -462,6 +552,7 @@ int mainGfx() {
|
|||||||
.taskStatus = SolveTaskStatus_Ready,
|
.taskStatus = SolveTaskStatus_Ready,
|
||||||
},
|
},
|
||||||
.state = {
|
.state = {
|
||||||
|
.threedeePaneRect=NULL,
|
||||||
.displayedPolycube = 0,
|
.displayedPolycube = 0,
|
||||||
.displayingSolutions = false,
|
.displayingSolutions = false,
|
||||||
.displayedSolution = -1,
|
.displayedSolution = -1,
|
||||||
@@ -469,6 +560,9 @@ int mainGfx() {
|
|||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
glfwSetWindowUserPointer(windowHandle, &soma);
|
||||||
|
glfwSetScrollCallback(windowHandle, onMouseScroll);
|
||||||
|
|
||||||
VoxelSpaceReprList stdSoma = AsList(VoxelSpaceReprList, STD_SOMA);
|
VoxelSpaceReprList stdSoma = AsList(VoxelSpaceReprList, STD_SOMA);
|
||||||
for (EachIn(stdSoma, i)) {
|
for (EachIn(stdSoma, i)) {
|
||||||
VoxelSpace voxelSpace = {
|
VoxelSpace voxelSpace = {
|
||||||
@@ -514,7 +608,7 @@ int mainGfx() {
|
|||||||
|
|
||||||
updateWindow(&soma);
|
updateWindow(&soma);
|
||||||
|
|
||||||
processInput(&soma, &ui);
|
processInput(&soma);
|
||||||
|
|
||||||
if (soma.solveTaskCtx.taskStatus == SolveTaskStatus_Complete) {
|
if (soma.solveTaskCtx.taskStatus == SolveTaskStatus_Complete) {
|
||||||
soma.solutions = PushList(solutionsArena, SomaSolutionList, soma.solveTaskCtx.solutions.length);
|
soma.solutions = PushList(solutionsArena, SomaSolutionList, soma.solveTaskCtx.solutions.length);
|
||||||
@@ -527,24 +621,22 @@ int mainGfx() {
|
|||||||
arenaFreeFrom(soma.solveTaskCtx.arena, 0);
|
arenaFreeFrom(soma.solveTaskCtx.arena, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Render(&renderer) {
|
||||||
|
UI_Pass(&ui) {
|
||||||
|
DJUI_Soma(&ui, &soma);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ui.cursorIsPointer) {
|
||||||
|
glfwSetCursor(soma.window.handle, soma.window.cursors.pointer);
|
||||||
|
} else {
|
||||||
|
glfwSetCursor(soma.window.handle, soma.window.cursors.arrow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
updatePolycubeDisplay(&soma);
|
updatePolycubeDisplay(&soma);
|
||||||
|
|
||||||
recalcScene(soma.scene);
|
recalcScene(soma.scene);
|
||||||
|
|
||||||
renderBegin(&renderer);
|
|
||||||
|
|
||||||
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(&renderer);
|
|
||||||
|
|
||||||
glfwSwapBuffers(soma.window.handle);
|
glfwSwapBuffers(soma.window.handle);
|
||||||
|
|
||||||
real64 frameEnd = glfwGetTime();
|
real64 frameEnd = glfwGetTime();
|
||||||
|
|||||||
16
src/render.c
16
src/render.c
@@ -100,12 +100,19 @@ void renderBegin(Renderer *r) {
|
|||||||
r->rects.borderRadius.length = 0;
|
r->rects.borderRadius.length = 0;
|
||||||
r->rects.borderThickness.length = 0;
|
r->rects.borderThickness.length = 0;
|
||||||
r->rects.edgeSoftness.length = 0;
|
r->rects.edgeSoftness.length = 0;
|
||||||
|
r->sceneWidth = 0;
|
||||||
|
r->sceneHeight = 0;
|
||||||
|
r->sceneX = 0;
|
||||||
|
r->sceneY = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderEnd(Renderer *r) {
|
void renderEnd(Renderer *r) {
|
||||||
// 3D Entities
|
// 3D Entities
|
||||||
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
|
||||||
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
||||||
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
glViewport(r->sceneX, r->height - r->sceneY - r->sceneHeight, r->sceneWidth, r->sceneHeight);
|
||||||
|
cameraSetAspect(r->camera, r->sceneWidth, r->sceneHeight);
|
||||||
|
|
||||||
glUseProgram(r->phongShader->progId);
|
glUseProgram(r->phongShader->progId);
|
||||||
setUniformMat4fv(r->phongShader, "projection", &r->camera->proj);
|
setUniformMat4fv(r->phongShader, "projection", &r->camera->proj);
|
||||||
@@ -133,15 +140,22 @@ void renderEnd(Renderer *r) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// 2D overlay
|
// 2D overlay
|
||||||
|
glViewport(0, 0, r->width, r->height);
|
||||||
|
|
||||||
glUseProgram(r->solidShader->progId);
|
glUseProgram(r->solidShader->progId);
|
||||||
|
|
||||||
updateRectangleObjectBuffers(r);
|
updateRectangleObjectBuffers(r);
|
||||||
|
|
||||||
|
glDisable(GL_DEPTH_TEST);
|
||||||
|
glEnable(GL_BLEND);
|
||||||
|
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
||||||
|
|
||||||
Matrix ortho = MatrixOrtho(0.0, r->width, r->height, 0.0, -1.0, 1.0);
|
Matrix ortho = MatrixOrtho(0.0, r->width, r->height, 0.0, -1.0, 1.0);
|
||||||
setUniformMat4fv(r->solidShader, "projection", &ortho);
|
setUniformMat4fv(r->solidShader, "projection", &ortho);
|
||||||
|
|
||||||
glBindVertexArray(r->rects.vao);
|
glBindVertexArray(r->rects.vao);
|
||||||
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, r->rects.p0.length);
|
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, r->rects.p0.length);
|
||||||
|
glDisable(GL_BLEND);
|
||||||
}
|
}
|
||||||
|
|
||||||
void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, RLVector4 color, real32 borderRadius, real32 borderThickness) {
|
void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, RLVector4 color, real32 borderRadius, real32 borderThickness) {
|
||||||
@@ -150,6 +164,6 @@ void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real3
|
|||||||
ListAppend(r->rects.color, color);
|
ListAppend(r->rects.color, color);
|
||||||
ListAppend(r->rects.borderRadius, borderRadius);
|
ListAppend(r->rects.borderRadius, borderRadius);
|
||||||
ListAppend(r->rects.borderThickness, borderThickness);
|
ListAppend(r->rects.borderThickness, borderThickness);
|
||||||
ListAppend(r->rects.edgeSoftness, 0.0f);
|
ListAppend(r->rects.edgeSoftness, 0.15f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@
|
|||||||
#include "gfx/Shader.h"
|
#include "gfx/Shader.h"
|
||||||
#include "gfx/gfx.h"
|
#include "gfx/gfx.h"
|
||||||
#include "world/world.h"
|
#include "world/world.h"
|
||||||
|
#include "lib/djstdlib/core.h"
|
||||||
|
|
||||||
DefineList(RLVector2, RLVec2);
|
DefineList(RLVector2, RLVec2);
|
||||||
DefineList(RLVector4, RLVec4);
|
DefineList(RLVector4, RLVec4);
|
||||||
@@ -43,6 +44,11 @@ struct Renderer {
|
|||||||
int32 width;
|
int32 width;
|
||||||
int32 height;
|
int32 height;
|
||||||
|
|
||||||
|
int32 sceneWidth;
|
||||||
|
int32 sceneHeight;
|
||||||
|
int32 sceneX;
|
||||||
|
int32 sceneY;
|
||||||
|
|
||||||
Scene *scene;
|
Scene *scene;
|
||||||
Camera *camera;
|
Camera *camera;
|
||||||
/** SceneGraphNode handle */
|
/** SceneGraphNode handle */
|
||||||
@@ -55,5 +61,6 @@ void renderBegin(Renderer *r);
|
|||||||
void renderEnd(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 rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, RLVector4 color, real32 borderRadius, real32 borderThickness);
|
||||||
void updateRectangleObjectBuffers(Renderer *r);
|
void updateRectangleObjectBuffers(Renderer *r);
|
||||||
|
#define Render(r) DeferLoop(renderBegin((r)), renderEnd((r)))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
250
src/ui.c
250
src/ui.c
@@ -1,5 +1,7 @@
|
|||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
|
#include "lib/djstdlib/core.h"
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
static bool glfwMouse(GLFWwindow *window, int mouseBtnCode) {
|
static bool glfwMouse(GLFWwindow *window, int mouseBtnCode) {
|
||||||
switch (glfwGetMouseButton(window, mouseBtnCode)) {
|
switch (glfwGetMouseButton(window, mouseBtnCode)) {
|
||||||
@@ -42,12 +44,13 @@ Input getCurrentInput(GLFWwindow *window) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
UI_Context ui_initContext(Arena *arena, Renderer *renderer) {
|
UI_Context ui_initContext(Arena *arena, Renderer *renderer) {
|
||||||
|
UI_RectList prevList = PushListZero(arena, UI_RectList, Thousand(10));
|
||||||
UI_RectList list = PushListZero(arena, UI_RectList, Thousand(10));
|
UI_RectList list = PushListZero(arena, UI_RectList, Thousand(10));
|
||||||
ListAppend(list, ((UI_Rect){0})); // empty item
|
ListAppend(list, ((UI_Rect){0})); // empty item
|
||||||
return (UI_Context){
|
return (UI_Context){
|
||||||
.rects=list,
|
.rects=list,
|
||||||
|
.prevRects=prevList,
|
||||||
.hotNode = 0,
|
.hotNode = 0,
|
||||||
.nextId = 1,
|
|
||||||
.cursorIsPointer = false,
|
.cursorIsPointer = false,
|
||||||
.input = NULL,
|
.input = NULL,
|
||||||
.prevInput = NULL,
|
.prevInput = NULL,
|
||||||
@@ -55,14 +58,161 @@ UI_Context ui_initContext(Arena *arena, Renderer *renderer) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void ui_playground(UI_Context *ui) {
|
||||||
|
UI(ui,
|
||||||
|
.width=ui->renderer->width,
|
||||||
|
.height=ui->renderer->height,
|
||||||
|
.color=COLOR_WHITE,
|
||||||
|
) {
|
||||||
|
UI(ui,
|
||||||
|
.color=COLOR_GREEN,
|
||||||
|
.childGap=10,
|
||||||
|
.flags=UI_Flag_HeightGrow,
|
||||||
|
.padding=UI_PadUniform(10),
|
||||||
|
) {
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
UI(ui,
|
||||||
|
.width=100,
|
||||||
|
.flags=UI_Flag_HeightGrow,
|
||||||
|
.color=COLOR_RED,
|
||||||
|
.borderRadius=10,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
UI(ui, .color=COLOR_CYAN, .flags=UI_Flag_HeightGrow | UI_Flag_WidthGrow);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_sizingPass(UI_Context *ui, bool isXAxis, int32 rectHandle) {
|
||||||
|
UI_Rect *rect = &ui->rects.data[rectHandle];
|
||||||
|
if (!rect->firstChild) return;
|
||||||
|
|
||||||
|
bool isVertical = rect->flags & UI_Flag_Vertical;
|
||||||
|
|
||||||
|
real32 remainingSpace = (isXAxis
|
||||||
|
? rect->resolvedWidth - rect->padding.left - rect->padding.right
|
||||||
|
: rect->resolvedHeight - rect->padding.top - rect->padding.bottom) + rect->childGap;
|
||||||
|
int32 growableChildrenCount = 0;
|
||||||
|
|
||||||
|
UI_Rect *child;
|
||||||
|
|
||||||
|
int32 childHandle = rect->firstChild;
|
||||||
|
if (isVertical != isXAxis) {
|
||||||
|
while (childHandle) {
|
||||||
|
child = &ui->rects.data[childHandle];
|
||||||
|
if (child->flags & UI_Flag_HeightGrow && !isXAxis || child->flags & UI_Flag_WidthGrow && isXAxis) {
|
||||||
|
growableChildrenCount++;
|
||||||
|
}
|
||||||
|
real32 childBreadth = isXAxis ? child->resolvedWidth : child->resolvedHeight;
|
||||||
|
remainingSpace -= childBreadth + rect->childGap;
|
||||||
|
childHandle = child->nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
real32 childBreadthInc = growableChildrenCount > 0 ? remainingSpace / (real32)growableChildrenCount : 0;
|
||||||
|
|
||||||
|
childHandle = rect->firstChild;
|
||||||
|
while (childHandle) {
|
||||||
|
child = &ui->rects.data[childHandle];
|
||||||
|
|
||||||
|
if (isVertical && (child->flags & UI_Flag_WidthGrow) && isXAxis) {
|
||||||
|
child->resolvedWidth = rect->resolvedWidth - rect->padding.left - rect->padding.right;
|
||||||
|
}
|
||||||
|
if (!isVertical && (child->flags & UI_Flag_HeightGrow) && !isXAxis) {
|
||||||
|
child->resolvedHeight = rect->resolvedHeight - rect->padding.top - rect->padding.bottom;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (child->flags & UI_Flag_WidthGrow && !isVertical && isXAxis) {
|
||||||
|
child->resolvedWidth += childBreadthInc;
|
||||||
|
}
|
||||||
|
if (child->flags & UI_Flag_HeightGrow && isVertical && !isXAxis) {
|
||||||
|
child->resolvedHeight += childBreadthInc;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_sizingPass(ui, isXAxis, childHandle);
|
||||||
|
|
||||||
|
childHandle = child->nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ui_calcLayout(UI_Context *ui, bool isXAxis, int32 rectHandle) {
|
||||||
|
UI_Rect *rect = &ui->rects.data[rectHandle];
|
||||||
|
if (!rect->firstChild) return;
|
||||||
|
|
||||||
|
bool isVertical = (rect->flags & UI_Flag_Vertical);
|
||||||
|
|
||||||
|
real32 coord = isXAxis ? rect->x + rect->xOffset + rect->padding.left : rect->y + rect->yOffset + rect->padding.top;
|
||||||
|
|
||||||
|
int32 childHandle = rect->firstChild;
|
||||||
|
UI_Rect *child;
|
||||||
|
while (childHandle) {
|
||||||
|
child = &ui->rects.data[childHandle];
|
||||||
|
|
||||||
|
if (isXAxis) {
|
||||||
|
child->x = coord;
|
||||||
|
} else {
|
||||||
|
child->y = coord;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui_calcLayout(ui, isXAxis, childHandle);
|
||||||
|
|
||||||
|
if (!isVertical == isXAxis) {
|
||||||
|
coord += isXAxis ? child->resolvedWidth : child->resolvedHeight;
|
||||||
|
coord += rect->childGap;
|
||||||
|
}
|
||||||
|
|
||||||
|
childHandle = child->nextSibling;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void ui_begin(UI_Context *ui) {
|
void ui_begin(UI_Context *ui) {
|
||||||
|
ClearList(ui->prevRects);
|
||||||
|
ListAppendList(ui->prevRects, ui->rects);
|
||||||
ui->cursorIsPointer = false;
|
ui->cursorIsPointer = false;
|
||||||
ui->nextId = 1;
|
|
||||||
ui->prevHotNode = ui->hotNode;
|
ui->prevHotNode = ui->hotNode;
|
||||||
ui->hotNode = 0;
|
ui->hotNode = 0;
|
||||||
|
ui->scene3DHandle = 0;
|
||||||
|
ui->rootRect = 0;
|
||||||
|
ui->currRect = 0;
|
||||||
|
ClearList(ui->rects);
|
||||||
|
ListAppend(ui->rects, (UI_Rect){0});
|
||||||
|
|
||||||
|
ui_openElement(ui, (UI_Rect){ .width=ui->renderer->width, .height=ui->renderer->height, .color=(RLVector4){0,0,0,0}});
|
||||||
}
|
}
|
||||||
|
|
||||||
void ui_end(UI_Context *ui) {
|
void ui_end(UI_Context *ui) {
|
||||||
|
ui_closeElement(ui);
|
||||||
|
|
||||||
|
// 1. Calculate layout
|
||||||
|
ui_sizingPass(ui, true, ui->rootRect);
|
||||||
|
ui_sizingPass(ui, false, ui->rootRect);
|
||||||
|
|
||||||
|
ui_calcLayout(ui, true, ui->rootRect);
|
||||||
|
ui_calcLayout(ui, false, ui->rootRect);
|
||||||
|
|
||||||
|
// 2. Create render commands:
|
||||||
|
|
||||||
|
for (EachEl(ui->rects, UI_Rect, rect)) {
|
||||||
|
rendererPlaceRectangle(
|
||||||
|
ui->renderer,
|
||||||
|
rect->x,
|
||||||
|
rect->y,
|
||||||
|
rect->resolvedWidth,
|
||||||
|
rect->resolvedHeight,
|
||||||
|
rect->color,
|
||||||
|
rect->borderRadius,
|
||||||
|
rect->borderThickness
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (ui->scene3DHandle) {
|
||||||
|
UI_Rect *scene3DRect = &ui->rects.data[ui->scene3DHandle];
|
||||||
|
ui->renderer->sceneX = (int32)scene3DRect->x;
|
||||||
|
ui->renderer->sceneY = (int32)scene3DRect->y;
|
||||||
|
ui->renderer->sceneWidth = (int32)scene3DRect->resolvedWidth;
|
||||||
|
ui->renderer->sceneHeight = (int32)scene3DRect->resolvedHeight;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool pointInRect(real32 x, real32 y, UI_Rect rect) {
|
static bool pointInRect(real32 x, real32 y, UI_Rect rect) {
|
||||||
@@ -70,31 +220,101 @@ static bool pointInRect(real32 x, real32 y, UI_Rect rect) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ui_openElement(UI_Context *ui, UI_Rect rect) {
|
void ui_openElement(UI_Context *ui, UI_Rect rect) {
|
||||||
ListAppend(ui->rects, rect);
|
ListAppend(ui->rects, (UI_Rect){0});
|
||||||
int32 nextHandle = ui->rects.length - 1;
|
int32 newHandle = ui->rects.length - 1;
|
||||||
|
UI_Rect *newRect = &ui->rects.data[newHandle];
|
||||||
UI_Rect *nextRect = &ui->rects.data[nextHandle];
|
|
||||||
UI_Rect *currRect = &ui->rects.data[ui->currRect];
|
UI_Rect *currRect = &ui->rects.data[ui->currRect];
|
||||||
|
|
||||||
nextRect->parent = ui->currRect;
|
*newRect = rect;
|
||||||
nextRect->nextSibling = currRect->firstChild;
|
newRect->parent = ui->currRect;
|
||||||
currRect->firstChild = nextHandle;
|
if (currRect->lastChild) {
|
||||||
|
ui->rects.data[currRect->lastChild].nextSibling = newHandle;
|
||||||
|
} else {
|
||||||
|
currRect->firstChild = newHandle;
|
||||||
|
}
|
||||||
|
currRect->lastChild = newHandle;
|
||||||
|
|
||||||
ui->currRect = nextHandle;
|
if (!ui->rootRect) {
|
||||||
|
ui->rootRect = newHandle;
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->currRect = newHandle;
|
||||||
|
|
||||||
|
if (newRect->flags & UI_Flag_3DScene) {
|
||||||
|
ui->scene3DHandle = newHandle;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ui_closeElement(UI_Context *ui) {
|
void ui_closeElement(UI_Context *ui) {
|
||||||
|
UI_Rect *currRect = &ui->rects.data[ui->currRect];
|
||||||
|
UI_Rect *parentRect = &ui->rects.data[currRect->parent];
|
||||||
|
|
||||||
|
if (currRect->width != -1) {
|
||||||
|
currRect->resolvedWidth = currRect->width;
|
||||||
|
}
|
||||||
|
currRect->resolvedWidth += currRect->padding.left + currRect->padding.right;
|
||||||
|
if (currRect->height != -1) {
|
||||||
|
currRect->resolvedHeight = currRect->height;
|
||||||
|
}
|
||||||
|
currRect->resolvedHeight += currRect->padding.top + currRect->padding.bottom;
|
||||||
|
|
||||||
|
bool vertical = parentRect->flags & UI_Flag_Vertical;
|
||||||
|
|
||||||
|
real32 currBreadth = vertical ? currRect->resolvedHeight : currRect->resolvedWidth;
|
||||||
|
real32 currCrossBreadth = vertical ? currRect->resolvedWidth : currRect->resolvedHeight;
|
||||||
|
real32 parentBreadth = vertical ? parentRect->height : parentRect->width;
|
||||||
|
real32 parentCrossBreadth = vertical ? parentRect->width : parentRect->height;
|
||||||
|
real32 gap = parentRect->childGap;
|
||||||
|
|
||||||
|
real32 breadthInc = (parentRect->firstChild == ui->currRect ? 0 : gap) + currBreadth;
|
||||||
|
|
||||||
|
if (parentBreadth == -1) {
|
||||||
|
if (vertical) {
|
||||||
|
parentRect->resolvedHeight += breadthInc;
|
||||||
|
} else {
|
||||||
|
parentRect->resolvedWidth += breadthInc;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
real32 newCrossBreadth = currCrossBreadth > parentCrossBreadth ? currCrossBreadth : parentCrossBreadth;
|
||||||
|
if (parentCrossBreadth == -1) {
|
||||||
|
if (vertical) {
|
||||||
|
parentRect->resolvedWidth = newCrossBreadth;
|
||||||
|
} else {
|
||||||
|
parentRect->resolvedHeight = newCrossBreadth;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ui->currRect = ui->rects.data[ui->currRect].parent;
|
ui->currRect = ui->rects.data[ui->currRect].parent;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ui_Button(UI_Context *ui, UI_Rect rect) {
|
||||||
|
int32 id = UI_NextID(ui);
|
||||||
|
bool clicked = false;
|
||||||
|
|
||||||
|
if (pointInRect(ui->input->mouse.point.x, ui->input->mouse.point.y, ui->prevRects.data[id])) {
|
||||||
|
ui->cursorIsPointer = true;
|
||||||
|
if (ui->prevHotNode == id && !ui->input->mouse.btnLeft) {
|
||||||
|
clicked = true;
|
||||||
|
} else if (ui->input->mouse.btnLeft && (!ui->prevInput->mouse.btnLeft || ui->prevHotNode == id)) {
|
||||||
|
ui->hotNode = id;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rect.borderRadius = 5;
|
||||||
|
rect.borderThickness = 0;
|
||||||
|
UI_FromRect(ui, rect);
|
||||||
|
|
||||||
|
return clicked;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns whether the checkbox was clicked
|
* Returns whether the checkbox was clicked
|
||||||
*/
|
*/
|
||||||
bool ui_checkboxRect(UI_Context *ui, bool *value, UI_Rect rect) {
|
bool ui_CheckboxRect(UI_Context *ui, bool *value, UI_Rect rect) {
|
||||||
uint32 id = ui->nextId++;
|
int32 id = UI_NextID(ui);
|
||||||
bool clicked = false;
|
bool clicked = false;
|
||||||
if (pointInRect(ui->input->mouse.point.x, ui->input->mouse.point.y, rect)) {
|
if (pointInRect(ui->input->mouse.point.x, ui->input->mouse.point.y, ui->prevRects.data[id])) {
|
||||||
ui->cursorIsPointer = true;
|
ui->cursorIsPointer = true;
|
||||||
if (ui->prevHotNode == id && !ui->input->mouse.btnLeft) {
|
if (ui->prevHotNode == id && !ui->input->mouse.btnLeft) {
|
||||||
*value = !*value;
|
*value = !*value;
|
||||||
@@ -106,12 +326,12 @@ bool ui_checkboxRect(UI_Context *ui, bool *value, UI_Rect rect) {
|
|||||||
if (*value) {
|
if (*value) {
|
||||||
rect.borderRadius = 5;
|
rect.borderRadius = 5;
|
||||||
rect.borderThickness = 0;
|
rect.borderThickness = 0;
|
||||||
DJUI(ui, rect);
|
UI_FromRect(ui, rect);
|
||||||
} else {
|
} else {
|
||||||
rect.borderRadius = 5;
|
rect.borderRadius = 5;
|
||||||
rect.borderThickness = 2;
|
rect.borderThickness = 2;
|
||||||
rect.color = COLOR_WHITE;
|
rect.color = COLOR_WHITE;
|
||||||
DJUI(ui, rect);
|
UI_FromRect(ui, rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
return clicked;
|
return clicked;
|
||||||
|
|||||||
45
src/ui.h
45
src/ui.h
@@ -26,26 +26,41 @@ struct Input {
|
|||||||
};
|
};
|
||||||
RLVector2 point;
|
RLVector2 point;
|
||||||
};
|
};
|
||||||
|
struct {
|
||||||
|
real64 dX;
|
||||||
|
real64 dY;
|
||||||
|
} scroll;
|
||||||
bool btnLeft;
|
bool btnLeft;
|
||||||
bool btnRight;
|
bool btnRight;
|
||||||
bool btnMiddle;
|
bool btnMiddle;
|
||||||
} mouse;
|
} mouse;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum UI_Rect_LayoutFlag {
|
enum UI_Flag {
|
||||||
UI_Rect_LayoutFlag_Width_Grow=1<<0, // Default is fixed
|
UI_Flag_WidthGrow=1<<0, // Default is fixed
|
||||||
UI_Rect_LayoutFlag_Height_Grow=1<<1,
|
UI_Flag_HeightGrow=1<<1,
|
||||||
UI_Rect_LayoutFlag_LayoutDirection_Vertical=1<<2, // Default is horizontal
|
UI_Flag_Vertical=1<<2, // Default is horizontal
|
||||||
|
UI_Flag_3DScene=1<<3,
|
||||||
// ..
|
// ..
|
||||||
UI_Rect_LayoutFlag_COUNT,
|
UI_Flag_COUNT,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct UI_Padding UI_Padding;
|
||||||
|
struct UI_Padding {
|
||||||
|
real32 top;
|
||||||
|
real32 right;
|
||||||
|
real32 bottom;
|
||||||
|
real32 left;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct UI_Rect UI_Rect;
|
typedef struct UI_Rect UI_Rect;
|
||||||
struct UI_Rect {
|
struct UI_Rect {
|
||||||
uint64 layoutFlags;
|
// UI_Rect_LayoutFlag
|
||||||
|
uint64 flags;
|
||||||
|
|
||||||
int32 parent;
|
int32 parent;
|
||||||
int32 firstChild;
|
int32 firstChild;
|
||||||
|
int32 lastChild;
|
||||||
int32 nextSibling;
|
int32 nextSibling;
|
||||||
|
|
||||||
real32 xOffset;
|
real32 xOffset;
|
||||||
@@ -65,6 +80,7 @@ struct UI_Rect {
|
|||||||
RLVector4 color;
|
RLVector4 color;
|
||||||
RLVector4 borderColor;
|
RLVector4 borderColor;
|
||||||
|
|
||||||
|
UI_Padding padding;
|
||||||
real32 childGap;
|
real32 childGap;
|
||||||
|
|
||||||
real32 x;
|
real32 x;
|
||||||
@@ -76,9 +92,10 @@ DefineList(UI_Rect, UI_Rect);
|
|||||||
|
|
||||||
typedef struct UI_Context UI_Context;
|
typedef struct UI_Context UI_Context;
|
||||||
struct UI_Context {
|
struct UI_Context {
|
||||||
|
UI_RectList prevRects;
|
||||||
UI_RectList rects;
|
UI_RectList rects;
|
||||||
int32 nextId;
|
|
||||||
int32 hotNode;
|
int32 hotNode;
|
||||||
|
int32 scene3DHandle;
|
||||||
int32 prevHotNode;
|
int32 prevHotNode;
|
||||||
Renderer *renderer;
|
Renderer *renderer;
|
||||||
|
|
||||||
@@ -86,19 +103,27 @@ struct UI_Context {
|
|||||||
Input *input;
|
Input *input;
|
||||||
bool cursorIsPointer;
|
bool cursorIsPointer;
|
||||||
|
|
||||||
|
int32 rootRect;
|
||||||
int32 currRect;
|
int32 currRect;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Input getCurrentInput(GLFWwindow *window);
|
||||||
|
|
||||||
void ui_begin(UI_Context *ui);
|
void ui_begin(UI_Context *ui);
|
||||||
void ui_end(UI_Context *ui);
|
void ui_end(UI_Context *ui);
|
||||||
UI_Context ui_initContext(Arena *arena, Renderer *renderer);
|
UI_Context ui_initContext(Arena *arena, Renderer *renderer);
|
||||||
Input getCurrentInput(GLFWwindow *window);
|
|
||||||
void ui_resolve();
|
void ui_resolve();
|
||||||
void ui_rect(UI_Context *ui, UI_Rect rect);
|
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_openElement(UI_Context *ui, UI_Rect rect);
|
||||||
void ui_closeElement(UI_Context *ui);
|
void ui_closeElement(UI_Context *ui);
|
||||||
|
|
||||||
#define DJUI(ui, rect) DeferLoop(ui_openElement((ui), (rect)), ui_closeElement((ui)))
|
bool ui_CheckboxRect(UI_Context *ui, bool *value, UI_Rect rect);
|
||||||
|
|
||||||
|
#define UI(ui, ...) DeferLoop(ui_openElement((ui), UI_CreateRect(__VA_ARGS__)), ui_closeElement((ui)))
|
||||||
|
#define UI_FromRect(ui, rect) DeferLoop(ui_openElement((ui), (rect)), ui_closeElement((ui)))
|
||||||
|
#define UI_CreateRect(...) ((UI_Rect){.width=-1, .height=-1, __VA_ARGS__})
|
||||||
|
#define UI_Pass(ui) DeferLoop(ui_begin((ui)), ui_end((ui)))
|
||||||
|
#define UI_PadUniform(padding) ((UI_Padding){ (padding), (padding), (padding), (padding) })
|
||||||
|
#define UI_NextID(ui) ((ui)->rects.length)
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user