getting text rendering working with stb_truetype
This commit is contained in:
BIN
assets/fonts/KodeMono.ttf
Normal file
BIN
assets/fonts/KodeMono.ttf
Normal file
Binary file not shown.
11
assets/shaders/text.fragment.glsl
Normal file
11
assets/shaders/text.fragment.glsl
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#version 330 core
|
||||||
|
out vec4 pixel_color;
|
||||||
|
|
||||||
|
in vec4 frag_color;
|
||||||
|
in vec2 frag_uv_position;
|
||||||
|
|
||||||
|
uniform sampler2D glyph_atlas;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
pixel_color = vec4(1,1,1,texture(glyph_atlas, frag_uv_position).r);
|
||||||
|
};
|
||||||
73
assets/shaders/text.vertex.glsl
Normal file
73
assets/shaders/text.vertex.glsl
Normal file
@@ -0,0 +1,73 @@
|
|||||||
|
#version 330 core
|
||||||
|
layout (location = 0) in vec2 begin;
|
||||||
|
layout (location = 1) in int glyph;
|
||||||
|
layout (location = 2) in float lineHeight;
|
||||||
|
layout (location = 3) in vec4 color;
|
||||||
|
|
||||||
|
/*
|
||||||
|
typedef struct GlyphMeta GlyphMeta;
|
||||||
|
struct GlyphMeta {
|
||||||
|
// chunk 1
|
||||||
|
RLVector2 uv0;
|
||||||
|
RLVector2 uv1;
|
||||||
|
|
||||||
|
// chunk 2
|
||||||
|
real32 xOffset;
|
||||||
|
real32 yOffset;
|
||||||
|
real32 width;
|
||||||
|
real32 height;
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
uniform samplerBuffer glyph_table;
|
||||||
|
|
||||||
|
uniform mat4 projection;
|
||||||
|
uniform sampler2D font;
|
||||||
|
|
||||||
|
out vec4 frag_color;
|
||||||
|
out vec2 frag_uv_position;
|
||||||
|
|
||||||
|
const vec2 rectangle_vertices[4] = vec2[](
|
||||||
|
vec2(-1, -1), // bl
|
||||||
|
vec2(-1, 1), // tl
|
||||||
|
vec2( 1, -1), // br
|
||||||
|
vec2( 1, 1) // tr
|
||||||
|
);
|
||||||
|
|
||||||
|
const vec2 uv0_vertices[4] = vec2[](
|
||||||
|
vec2(1, 0), // bl
|
||||||
|
vec2(1, 1), // tl
|
||||||
|
vec2(0, 0), // br
|
||||||
|
vec2(0, 1) // tr
|
||||||
|
);
|
||||||
|
|
||||||
|
const vec2 uv1_vertices[4] = vec2[](
|
||||||
|
vec2(0, 1),
|
||||||
|
vec2(0, 0),
|
||||||
|
vec2(1, 1),
|
||||||
|
vec2(1, 0)
|
||||||
|
);
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
vec4 chunk1 = texelFetch(glyph_table, glyph * 2 + 0);
|
||||||
|
vec4 chunk2 = texelFetch(glyph_table, glyph * 2 + 1);
|
||||||
|
|
||||||
|
vec2 uv0 = chunk1.xy;
|
||||||
|
vec2 uv1 = chunk1.zw;
|
||||||
|
vec2 offset = chunk2.xy;
|
||||||
|
vec2 dims = chunk2.zw;
|
||||||
|
|
||||||
|
vec2 p0 = begin + offset*lineHeight;
|
||||||
|
vec2 p1 = begin + (offset + dims)*lineHeight;
|
||||||
|
|
||||||
|
vec2 dest_half_size = (p1 - p0) / 2;
|
||||||
|
vec2 dest_center = (p1 + p0) / 2;
|
||||||
|
vec2 dest_position = rectangle_vertices[gl_VertexID] * dest_half_size + dest_center;
|
||||||
|
|
||||||
|
vec2 uv_position = uv0 * uv0_vertices[gl_VertexID] + uv1 * uv1_vertices[gl_VertexID];
|
||||||
|
|
||||||
|
gl_Position = projection * vec4(dest_position, 0, 1);
|
||||||
|
|
||||||
|
frag_color = color;
|
||||||
|
frag_uv_position = vec2(uv_position.x, uv_position.y);
|
||||||
|
}
|
||||||
2
build
2
build
@@ -7,7 +7,7 @@ echo [Building target]
|
|||||||
if [ $DEBUG ]; then
|
if [ $DEBUG ]; then
|
||||||
time clang -O0 -g -g2 $COMMON_FLAGS -DDJSTDLIB_DEBUG=1 ./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
|
else
|
||||||
time clang -O3 $COMMON_FLAGS ./src/main.c -o ./target/somaesque $LIB_INCLUDE
|
time clang -O2 $COMMON_FLAGS ./src/main.c -o ./target/somaesque $LIB_INCLUDE
|
||||||
fi
|
fi
|
||||||
echo [Target built]
|
echo [Target built]
|
||||||
|
|
||||||
|
|||||||
12
src/common.h
Normal file
12
src/common.h
Normal file
@@ -0,0 +1,12 @@
|
|||||||
|
#ifndef COMMON_H
|
||||||
|
#define COMMON_H
|
||||||
|
|
||||||
|
#include "lib/djstdlib/core.h"
|
||||||
|
#include "lib/raymath.h"
|
||||||
|
|
||||||
|
DefineList(RLVector2, RLVec2);
|
||||||
|
DefineList(RLVector4, RLVec4);
|
||||||
|
DefineList(real32, Float);
|
||||||
|
DefineList(uint32, UInt32);
|
||||||
|
|
||||||
|
#endif
|
||||||
@@ -83,6 +83,13 @@ void setUniform3fvByLoc(int uniformLocation, RLVector3 *vector) {
|
|||||||
glUniform3fv(uniformLocation, 1, Vector3ToFloat(*vector));
|
glUniform3fv(uniformLocation, 1, Vector3ToFloat(*vector));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void setUniform1i(Shader *s, const char *uniformName, int32 i) {
|
||||||
|
glUniform1i(glGetUniformLocation(s->progId, uniformName), (GLint)i);
|
||||||
|
}
|
||||||
|
void setUniform1iByLoc(int uniformLocation, int32 i) {
|
||||||
|
glUniform1i(uniformLocation, (GLint)i);
|
||||||
|
}
|
||||||
|
|
||||||
void setUniform2fv(Shader *s, const char *uniformName, RLVector2 *vector) {
|
void setUniform2fv(Shader *s, const char *uniformName, RLVector2 *vector) {
|
||||||
glUniform2fv(glGetUniformLocation(s->progId, uniformName), 1, (const GLfloat *)vector);
|
glUniform2fv(glGetUniformLocation(s->progId, uniformName), 1, (const GLfloat *)vector);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,6 +22,9 @@ void setUniform3fvByLoc(int uniformLocation, RLVector3 *vector);
|
|||||||
void setUniform2fv(Shader *s, const char *uniformName, RLVector2 *vector);
|
void setUniform2fv(Shader *s, const char *uniformName, RLVector2 *vector);
|
||||||
void setUniform2fvByLoc(int uniformLocation, RLVector2 *vector);
|
void setUniform2fvByLoc(int uniformLocation, RLVector2 *vector);
|
||||||
|
|
||||||
|
void setUniform1i(Shader *s, const char *uniformName, int32 i);
|
||||||
|
void setUniform1iByLoc(int uniformLocation, int32 i);
|
||||||
|
|
||||||
int getUniformLocation(Shader *s, const char *uniformName);
|
int getUniformLocation(Shader *s, const char *uniformName);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
@@ -1,9 +1,88 @@
|
|||||||
#include "Texture.h"
|
#include "Texture.h"
|
||||||
#include "../lib/loaders/stb_image.h"
|
|
||||||
#include "../lib/glad/glad.h"
|
|
||||||
#include "../lib/djstdlib/core.h"
|
|
||||||
|
|
||||||
Texture createTexture(const char* source_path) {
|
Texture createTexture(const char* bitmap, int32 width, int32 height) {
|
||||||
|
Texture result = {0};
|
||||||
|
result.width = width;
|
||||||
|
result.height = height;
|
||||||
|
glGenTextures(1, &result.tex_id);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, result.tex_id);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, result.width, result.height, 0, GL_RGB, GL_UNSIGNED_BYTE, bitmap);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DefineList(stbtt_bakedchar, STBBakedChar);
|
||||||
|
|
||||||
|
Font createFont(Arena *arena, string ttfLocation, real32 lineHeight) {
|
||||||
|
const int CODEPOINT_START = 32;
|
||||||
|
const int CODEPOINT_END = 126;
|
||||||
|
|
||||||
|
int32 atlasWidth = 16 * lineHeight;
|
||||||
|
int32 atlasHeight = 6 * lineHeight;
|
||||||
|
|
||||||
|
STBBakedCharList bakedCharlist = PushFullListZero(arena, STBBakedCharList, CODEPOINT_END - CODEPOINT_START);
|
||||||
|
string fontFile = os_readEntireFile(arena, ttfLocation);
|
||||||
|
|
||||||
|
char *bakedFontBitmap = PushArrayZero(arena, char, atlasWidth*atlasHeight);
|
||||||
|
int32 bake_result = stbtt_BakeFontBitmap(
|
||||||
|
(unsigned char *)fontFile.str, 0,
|
||||||
|
lineHeight,
|
||||||
|
(unsigned char *)bakedFontBitmap, atlasWidth, atlasHeight,
|
||||||
|
CODEPOINT_START, CODEPOINT_END - CODEPOINT_START,
|
||||||
|
bakedCharlist.data);
|
||||||
|
|
||||||
|
GlyphMetaList glyphMeta = PushFullListZero(arena, GlyphMetaList, bakedCharlist.length);
|
||||||
|
real32 x, y;
|
||||||
|
real32 lastX, lastY;
|
||||||
|
for (EachIn(bakedCharlist, i)) {
|
||||||
|
stbtt_aligned_quad q;
|
||||||
|
stbtt_GetBakedQuad(bakedCharlist.data, atlasWidth, atlasHeight, i, &x, &y, &q, 1);
|
||||||
|
glyphMeta.data[i] = (GlyphMeta){
|
||||||
|
.uv0=(RLVector2){q.s0, q.t1},
|
||||||
|
.uv1=(RLVector2){q.s1, q.t0},
|
||||||
|
.xOffset=q.x0 - lastX,
|
||||||
|
.yOffset=q.y0 + lineHeight,
|
||||||
|
.width=q.x1-q.x0,
|
||||||
|
.height=q.y1-q.y0,
|
||||||
|
};
|
||||||
|
lastX = x;
|
||||||
|
lastY = y;
|
||||||
|
}
|
||||||
|
|
||||||
|
Font result = {0};
|
||||||
|
result.glyphMeta = glyphMeta;
|
||||||
|
result.lineHeight = lineHeight;
|
||||||
|
result.charWidth = bakedCharlist.data[0].xadvance;
|
||||||
|
|
||||||
|
glGenTextures(1, &result.texId);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, result.texId);
|
||||||
|
//glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, atlasWidth, atlasHeight, 0, GL_RED, GL_UNSIGNED_BYTE, bakedFontBitmap);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
glGenerateMipmap(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
glGenBuffers(1, &result.glyphTableBufId);
|
||||||
|
glBindBuffer(GL_TEXTURE_BUFFER, result.glyphTableBufId);
|
||||||
|
glBufferData(GL_TEXTURE_BUFFER, sizeof(result.glyphMeta.data[0])*result.glyphMeta.length, result.glyphMeta.data, GL_STATIC_DRAW);
|
||||||
|
|
||||||
|
glGenTextures(1, &result.glyphTableTexId);
|
||||||
|
glBindTexture(GL_TEXTURE_BUFFER, result.glyphTableTexId);
|
||||||
|
glTexBuffer(GL_TEXTURE_BUFFER, GL_RGBA32F, result.glyphTableBufId);
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
Texture createTextureFromFile(const char* source_path) {
|
||||||
Texture result = {0};
|
Texture result = {0};
|
||||||
glGenTextures(1, &result.tex_id);
|
glGenTextures(1, &result.tex_id);
|
||||||
glBindTexture(GL_TEXTURE_2D, result.tex_id);
|
glBindTexture(GL_TEXTURE_2D, result.tex_id);
|
||||||
|
|||||||
@@ -1,12 +1,45 @@
|
|||||||
#ifndef LEDDA_TEXTURE_H
|
#ifndef LEDDA_TEXTURE_H
|
||||||
#define LEDDA_TEXTURE_H
|
#define LEDDA_TEXTURE_H
|
||||||
|
|
||||||
typedef struct {
|
#include "../lib/djstdlib/core.h"
|
||||||
unsigned int tex_id;
|
#include "../lib/loaders/stb_truetype.h"
|
||||||
int width;
|
#include "../lib/loaders/stb_image.h"
|
||||||
int height;
|
#include "../lib/glad/glad.h"
|
||||||
} Texture;
|
#include "../lib/djstdlib/core.h"
|
||||||
|
#include "../lib/djstdlib/os.h"
|
||||||
|
#include "../common.h"
|
||||||
|
|
||||||
Texture createTexture(const char* source_path);
|
typedef struct Texture Texture;
|
||||||
|
struct Texture {
|
||||||
|
uint32 tex_id;
|
||||||
|
int32 width;
|
||||||
|
int32 height;
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef struct GlyphMeta GlyphMeta;
|
||||||
|
struct GlyphMeta {
|
||||||
|
RLVector2 uv0;
|
||||||
|
RLVector2 uv1;
|
||||||
|
real32 xOffset;
|
||||||
|
real32 yOffset;
|
||||||
|
real32 width;
|
||||||
|
real32 height;
|
||||||
|
};
|
||||||
|
|
||||||
|
DefineList(GlyphMeta, GlyphMeta);
|
||||||
|
|
||||||
|
typedef struct Font Font;
|
||||||
|
struct Font {
|
||||||
|
GlyphMetaList glyphMeta;
|
||||||
|
real32 lineHeight;
|
||||||
|
real32 charWidth;
|
||||||
|
uint32 texId;
|
||||||
|
uint32 glyphTableTexId;
|
||||||
|
uint32 glyphTableBufId;
|
||||||
|
};
|
||||||
|
|
||||||
|
Texture createTexture(const char* bitmap, int32 width, int32 height);
|
||||||
|
Texture createTextureFromFile(const char* source_path);
|
||||||
|
Font createFont(Arena *arena, string ttfLocation, real32 lineHeight);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
148
src/main.c
148
src/main.c
@@ -1,10 +1,7 @@
|
|||||||
#include "lib/djstdlib/core.h"
|
|
||||||
#define _POSIX_C_SOURCE 199309L
|
|
||||||
#include "time.h"
|
|
||||||
|
|
||||||
// Library initialisation
|
// Library initialisation
|
||||||
#define RAYMATH_IMPLEMENTATION
|
#define RAYMATH_IMPLEMENTATION
|
||||||
#define STB_IMAGE_IMPLEMENTATION
|
#define STB_IMAGE_IMPLEMENTATION
|
||||||
|
#define STB_TRUETYPE_IMPLEMENTATION
|
||||||
#define TINYOBJ_LOADER_C_IMPLEMENTATION
|
#define TINYOBJ_LOADER_C_IMPLEMENTATION
|
||||||
|
|
||||||
// Project
|
// Project
|
||||||
@@ -67,6 +64,7 @@ struct SomaState {
|
|||||||
RLVector3 rotAxisX;
|
RLVector3 rotAxisX;
|
||||||
RLVector3 rotAxisY;
|
RLVector3 rotAxisY;
|
||||||
UI_Rect *threedeePaneRect;
|
UI_Rect *threedeePaneRect;
|
||||||
|
real64 explosionOffset;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Soma Soma;
|
typedef struct Soma Soma;
|
||||||
@@ -209,17 +207,12 @@ static void advanceDisplayReverse(Soma *soma) {
|
|||||||
|
|
||||||
static void advanceDisplay(Soma *soma) {
|
static void advanceDisplay(Soma *soma) {
|
||||||
if (soma->state.displayingSolutions) {
|
if (soma->state.displayingSolutions) {
|
||||||
if (soma->state.displayedSolution == soma->solutions.length - 1) {
|
soma->state.explosionOffset = 0;
|
||||||
soma->state.displayedSolution = 0;
|
soma->state.displayedSolution += 1;
|
||||||
} else {
|
soma->state.displayedSolution %= soma->solutions.length;
|
||||||
soma->state.displayedSolution += 1;
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (soma->state.displayedPolycube == soma->polycubeInput.length - 1) {
|
soma->state.displayedPolycube += 1;
|
||||||
soma->state.displayedPolycube = 0;
|
soma->state.displayedPolycube %= soma->polycubes.length;
|
||||||
} else {
|
|
||||||
soma->state.displayedPolycube += 1;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -281,6 +274,11 @@ void processInput(Soma *soma) {
|
|||||||
if (soma->state.displayingSolutions) {
|
if (soma->state.displayingSolutions) {
|
||||||
real64 scrollDelta = soma->ui->prevInput->mouse.scroll.dY;
|
real64 scrollDelta = soma->ui->prevInput->mouse.scroll.dY;
|
||||||
if (scrollDelta > 0.001 || scrollDelta < -0.001) {
|
if (scrollDelta > 0.001 || scrollDelta < -0.001) {
|
||||||
|
soma->state.explosionOffset += scrollDelta;
|
||||||
|
if (soma->state.explosionOffset > 0) {
|
||||||
|
scrollDelta -= soma->state.explosionOffset;
|
||||||
|
soma->state.explosionOffset = 0;
|
||||||
|
}
|
||||||
SceneGraphNode *rootNode = getSceneGraphNode(soma->scene, soma->solutionNode);
|
SceneGraphNode *rootNode = getSceneGraphNode(soma->scene, soma->solutionNode);
|
||||||
int32 nextChildHandle = rootNode->firstChild;
|
int32 nextChildHandle = rootNode->firstChild;
|
||||||
while (nextChildHandle) {
|
while (nextChildHandle) {
|
||||||
@@ -335,45 +333,47 @@ static void ui_Interaction(UI_Context *ui, Soma *soma) {
|
|||||||
real32 padding = 20;
|
real32 padding = 20;
|
||||||
real32 childGap = 5;
|
real32 childGap = 5;
|
||||||
|
|
||||||
UI(ui, .childGap=padding, .flags=UI_Flag_Vertical) {
|
UI(.flags=UI_Flag_Center | UI_Flag_HeightGrow) {
|
||||||
if (soma->state.displayingSolutions && soma->solutions.length > 0) {
|
UI(.childGap=padding, .flags=UI_Flag_Vertical | UI_Flag_Center) {
|
||||||
SomaSolution *currentSolution = &soma->solutions.data[soma->state.displayedSolution];
|
if (soma->state.displayingSolutions && soma->solutions.length > 0) {
|
||||||
for (int x = 0; x < soma->puzzleDims[0]; x++) UI(ui, .childGap=childGap, .flags=UI_Flag_Vertical) {
|
SomaSolution *currentSolution = &soma->solutions.data[soma->state.displayedSolution];
|
||||||
for (int y = 0; y < soma->puzzleDims[1]; y++) UI(ui, .childGap=childGap) {
|
for (int x = 0; x < soma->puzzleDims[0]; x++) UI(.childGap=childGap, .flags=UI_Flag_Vertical) {
|
||||||
for (int z = 0; z < soma->puzzleDims[2]; z++) {
|
for (int y = 0; y < soma->puzzleDims[1]; y++) UI(.childGap=childGap) {
|
||||||
for (EachIn(*currentSolution, i)) {
|
for (int z = 0; z < soma->puzzleDims[2]; z++) {
|
||||||
uint64 spaceRepr = currentSolution->data[i];
|
for (EachIn(*currentSolution, i)) {
|
||||||
bool cellActive = filledAt(&(VoxelSpace){
|
uint64 spaceRepr = currentSolution->data[i];
|
||||||
.space = spaceRepr,
|
bool cellActive = filledAt(&(VoxelSpace){
|
||||||
.dim_x = soma->puzzleDims[0],
|
.space = spaceRepr,
|
||||||
.dim_y = soma->puzzleDims[1],
|
.dim_x = soma->puzzleDims[0],
|
||||||
.dim_z = soma->puzzleDims[2],
|
.dim_y = soma->puzzleDims[1],
|
||||||
}, x, y, z);
|
.dim_z = soma->puzzleDims[2],
|
||||||
if (cellActive) UI(ui,
|
}, x, y, z);
|
||||||
.width=boxSize,
|
if (cellActive) UI(
|
||||||
.height=boxSize,
|
.width=boxSize,
|
||||||
.color=soma->polycubeInput.data[i].color,
|
.height=boxSize,
|
||||||
.borderRadius=5,
|
.color=soma->polycubeInput.data[i].color,
|
||||||
.borderThickness=0,
|
.borderRadius=5,
|
||||||
);
|
.borderThickness=0,
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
} else {
|
||||||
} else {
|
PolycubeInput *currentPolycube = &soma->polycubeInput.data[soma->state.displayedPolycube];
|
||||||
PolycubeInput *currentPolycube = &soma->polycubeInput.data[soma->state.displayedPolycube];
|
for (int x = 0; x < currentPolycube->repr.dim_x; x++) UI(.childGap=childGap, .flags=UI_Flag_Vertical) {
|
||||||
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(.childGap=childGap) {
|
||||||
for (int y = 0; y < currentPolycube->repr.dim_y; y++) UI(ui, .childGap=childGap) {
|
for (int z = 0; z < currentPolycube->repr.dim_z; z++) {
|
||||||
for (int z = 0; z < currentPolycube->repr.dim_z; z++) {
|
bool cellActive = filledAt(¤tPolycube->repr, x, y, z);
|
||||||
bool cellActive = filledAt(¤tPolycube->repr, x, y, z);
|
if (ui_CheckboxRect(ui, &cellActive, UI_CreateRect(
|
||||||
if (ui_CheckboxRect(ui, &cellActive, UI_CreateRect(
|
.width = boxSize,
|
||||||
.width = boxSize,
|
.height = boxSize,
|
||||||
.height = boxSize,
|
.borderRadius = 2,
|
||||||
.borderRadius = 2,
|
.color = currentPolycube->color,
|
||||||
.color = currentPolycube->color,
|
))) {
|
||||||
))) {
|
soma->state.polycubeDirty = true;
|
||||||
soma->state.polycubeDirty = true;
|
spaceSet(¤tPolycube->repr, cellActive, x, y, z);
|
||||||
spaceSet(¤tPolycube->repr, cellActive, x, y, z);
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -383,39 +383,41 @@ static void ui_Interaction(UI_Context *ui, Soma *soma) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void DJUI_Soma(UI_Context *ui, Soma *soma) {
|
static void DJUI_Soma(UI_Context *ui, Soma *soma) {
|
||||||
UI(ui, .flags=UI_Flag_HeightGrow | UI_Flag_WidthGrow) {
|
RLVector4 darkgrey = {0.2, 0.2, 0.2, 1};
|
||||||
UI(ui, .padding=UI_PadUniform(10), .color={0.2, 0.2, 0.2, 1}, .flags=UI_Flag_HeightGrow) {
|
RLVector4 grey = {0.4, 0.4, 0.4, 1};
|
||||||
|
|
||||||
|
UI(.flags=UI_Flag_HeightGrow | UI_Flag_WidthGrow) {
|
||||||
|
UI(.padding={.left=20, .right=20, .top=5}, .color=darkgrey, .flags=UI_Flag_HeightGrow | UI_Flag_Vertical) {
|
||||||
|
UI() UI_Text(s("Somaesque"), .lineHeight=26);
|
||||||
ui_Interaction(ui, soma);
|
ui_Interaction(ui, soma);
|
||||||
}
|
}
|
||||||
UI(ui, .flags=UI_Flag_Vertical | UI_Flag_HeightGrow | UI_Flag_WidthGrow) {
|
UI(.flags=UI_Flag_Vertical | UI_Flag_HeightGrow | UI_Flag_WidthGrow) {
|
||||||
UI(ui, .padding=UI_PadUniform(5), .color={0.2, 0.2, 0.2, 1}, .flags=UI_Flag_WidthGrow) {
|
UI(.padding=UI_PadUniform(10), .color=darkgrey, .flags=UI_Flag_WidthGrow) {
|
||||||
UI(ui, .width=65);
|
UI(.flags=UI_Flag_WidthGrow) {
|
||||||
UI(ui, .flags=UI_Flag_WidthGrow);
|
UI(.childGap=10) {
|
||||||
UI(ui) {
|
if (ui_Button(ui, UI_CreateRect(.height=30, .padding={.left=10, .right=10}, .color=grey), UI_CreateText(s("Previous"), .lineHeight=20))) {
|
||||||
RLVector4 color = {0.5, 0.5, 0.5, 1};
|
|
||||||
UI(ui, .childGap=10) {
|
|
||||||
if (ui_Button(ui, UI_CreateRect(.width=30, .height=30, .color=color))) {
|
|
||||||
advanceDisplayReverse(soma);
|
advanceDisplayReverse(soma);
|
||||||
}
|
}
|
||||||
if (ui_Button(ui, UI_CreateRect(.width=30, .height=30, .color=color))) {
|
if (ui_Button(ui, UI_CreateRect(.height=30, .padding={.left=10, .right=10}, .color=grey), UI_CreateText(s("Next"), .lineHeight=20))) {
|
||||||
advanceDisplay(soma);
|
advanceDisplay(soma);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UI(ui, .flags=UI_Flag_WidthGrow);
|
UI(.childGap=10) {
|
||||||
UI(ui, .width=65, .childGap=5) {
|
|
||||||
if (ui_Button(ui, UI_CreateRect(
|
if (ui_Button(ui, UI_CreateRect(
|
||||||
.width=30,
|
.width=30,
|
||||||
.height=30,
|
.height=30,
|
||||||
.color=soma->state.displayingSolutions ? (RLVector4){1,0,0,0.5} : COLOR_RED,
|
.padding={.left=10, .right=10},
|
||||||
))) {
|
.color=soma->state.displayingSolutions ? grey : (RLVector4){0.2, 0.2, 0.7, 1},
|
||||||
|
), UI_CreateText(s("Design"), .lineHeight=20))) {
|
||||||
soma->state.displayingSolutions = false;
|
soma->state.displayingSolutions = false;
|
||||||
}
|
}
|
||||||
if (ui_Button(ui, UI_CreateRect(
|
if (ui_Button(ui, UI_CreateRect(
|
||||||
.width=30,
|
.width=30,
|
||||||
.height=30,
|
.height=30,
|
||||||
.color=soma->state.displayingSolutions ? COLOR_GREEN : (RLVector4){0,1,0,0.5},
|
.padding={.left=10, .right=10},
|
||||||
))) {
|
.color=soma->state.displayingSolutions ? (RLVector4){0.2, 0.2, 0.7, 1} : grey,
|
||||||
|
), UI_CreateText(s("Solve"), .lineHeight=20))) {
|
||||||
if (!soma->state.displayingSolutions) {
|
if (!soma->state.displayingSolutions) {
|
||||||
tryScheduleSolve(soma);
|
tryScheduleSolve(soma);
|
||||||
} else {
|
} else {
|
||||||
@@ -424,7 +426,7 @@ static void DJUI_Soma(UI_Context *ui, Soma *soma) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
UI(ui, .flags=UI_Flag_WidthGrow | UI_Flag_HeightGrow | UI_Flag_3DScene);
|
UI(.flags=UI_Flag_WidthGrow | UI_Flag_HeightGrow | UI_Flag_3DScene);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -526,7 +528,8 @@ int mainGfx() {
|
|||||||
renderer.phongShader = &phongShader;
|
renderer.phongShader = &phongShader;
|
||||||
renderer.cubeMesh = &cubeMesh;
|
renderer.cubeMesh = &cubeMesh;
|
||||||
|
|
||||||
UI_Context ui = ui_initContext(arena, &renderer);
|
Arena *uiArena = arenaAlloc(Megabytes(64));
|
||||||
|
UI_Context ui = ui_initContext(uiArena, &renderer);
|
||||||
|
|
||||||
Soma soma = {
|
Soma soma = {
|
||||||
.window = {
|
.window = {
|
||||||
@@ -591,6 +594,13 @@ int mainGfx() {
|
|||||||
|
|
||||||
getSceneGraphNode(&mainScene, renderer.light)->translation = (RLVector3){4.0f, 6.0f, 24.0f};
|
getSceneGraphNode(&mainScene, renderer.light)->translation = (RLVector3){4.0f, 6.0f, 24.0f};
|
||||||
|
|
||||||
|
Font kodeMono = createFont(arena, s("./assets/fonts/KodeMono.ttf"), 96.0f);
|
||||||
|
renderer.activeFont = &kodeMono;
|
||||||
|
|
||||||
|
Shader textShader = createShader(s("./assets/shaders/text.vertex.glsl"), s("./assets/shaders/text.fragment.glsl"));
|
||||||
|
renderer.textShader = &textShader;
|
||||||
|
|
||||||
|
// Render loop
|
||||||
real64 lastFrame = glfwGetTime();
|
real64 lastFrame = glfwGetTime();
|
||||||
real64 timeDelta = 1.0f / TARGET_FPS;
|
real64 timeDelta = 1.0f / TARGET_FPS;
|
||||||
real64 frameStart = lastFrame;
|
real64 frameStart = lastFrame;
|
||||||
|
|||||||
231
src/render.c
231
src/render.c
@@ -1,87 +1,144 @@
|
|||||||
#include "render.h"
|
#include "render.h"
|
||||||
#include "debug.h"
|
#include "debug.h"
|
||||||
|
|
||||||
RenderObjects_Rectangle createRectangleObjects(Arena *arena, size_t count) {
|
static RenderObjects_Char createCharObjects(Arena *arena, size_t count) {
|
||||||
RenderObjects_Rectangle result = {0};
|
RenderObjects_Char result = {0};
|
||||||
result.count = count;
|
result.count = count;
|
||||||
|
|
||||||
result.p0 = PushFullList(arena, RLVec2List, count);
|
result.begin.buf = PushFullList(arena, RLVec2List, count);
|
||||||
result.p1 = PushFullList(arena, RLVec2List, count);
|
result.glyph.buf = PushFullList(arena, IntList, count);
|
||||||
result.color = PushFullList(arena, RLVec4List, count);
|
result.lineHeight.buf = PushFullList(arena, FloatList, count);
|
||||||
result.borderRadius = PushFullList(arena, FloatList, count);
|
result.color.buf = PushFullList(arena, RLVec4List, count);
|
||||||
result.borderThickness = PushFullList(arena, FloatList, count);
|
|
||||||
result.edgeSoftness = PushFullList(arena, FloatList, count);
|
|
||||||
|
|
||||||
glGenVertexArrays(1, &result.vao);
|
glGenVertexArrays(1, &result.vao);
|
||||||
|
|
||||||
glGenBuffers(1, &result.p0BufferId);
|
glGenBuffers(1, &result.begin.bufId);
|
||||||
glGenBuffers(1, &result.p1BufferId);
|
glGenBuffers(1, &result.glyph.bufId);
|
||||||
glGenBuffers(1, &result.colorBufferId);
|
glGenBuffers(1, &result.lineHeight.bufId);
|
||||||
glGenBuffers(1, &result.borderRadiusBufferId);
|
glGenBuffers(1, &result.color.bufId);
|
||||||
glGenBuffers(1, &result.borderThicknessBufferId);
|
|
||||||
glGenBuffers(1, &result.edgeSoftnessBufferId);
|
|
||||||
|
|
||||||
glBindVertexArray(result.vao);
|
glBindVertexArray(result.vao);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, result.p0BufferId);
|
int32 bufItemSize = sizeof(result.begin.buf.data[0]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, result.p0.length * sizeof(RLVec2List_underlying), 0, GL_DYNAMIC_DRAW);
|
glBindBuffer(GL_ARRAY_BUFFER, result.begin.bufId);
|
||||||
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, sizeof(RLVec2List_underlying), NULL);
|
glBufferData(GL_ARRAY_BUFFER, result.begin.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||||
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, bufItemSize, NULL);
|
||||||
glVertexAttribDivisor(0, 1);
|
glVertexAttribDivisor(0, 1);
|
||||||
glEnableVertexAttribArray(0);
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, result.p1BufferId);
|
bufItemSize = sizeof(result.glyph.buf.data[0]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, result.p1.length * sizeof(RLVec2List_underlying), 0, GL_DYNAMIC_DRAW);
|
glBindBuffer(GL_ARRAY_BUFFER, result.glyph.bufId);
|
||||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, sizeof(RLVec2List_underlying), NULL);
|
glBufferData(GL_ARRAY_BUFFER, result.glyph.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||||
|
glVertexAttribIPointer(1, 1, GL_INT, bufItemSize, NULL);
|
||||||
glVertexAttribDivisor(1, 1);
|
glVertexAttribDivisor(1, 1);
|
||||||
glEnableVertexAttribArray(1);
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, result.colorBufferId);
|
bufItemSize = sizeof(result.lineHeight.buf.data[0]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, result.color.length * sizeof(RLVec4List_underlying), 0, GL_DYNAMIC_DRAW);
|
glBindBuffer(GL_ARRAY_BUFFER, result.lineHeight.bufId);
|
||||||
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, sizeof(RLVec4List_underlying), NULL);
|
glBufferData(GL_ARRAY_BUFFER, result.lineHeight.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||||
|
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, bufItemSize, NULL);
|
||||||
glVertexAttribDivisor(2, 1);
|
glVertexAttribDivisor(2, 1);
|
||||||
glEnableVertexAttribArray(2);
|
glEnableVertexAttribArray(2);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, result.borderRadiusBufferId);
|
bufItemSize = sizeof(result.color.buf.data[0]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, result.borderRadius.length * sizeof(FloatList_underlying), 0, GL_DYNAMIC_DRAW);
|
glBindBuffer(GL_ARRAY_BUFFER, result.color.bufId);
|
||||||
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, sizeof(FloatList_underlying), NULL);
|
glBufferData(GL_ARRAY_BUFFER, result.color.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||||
|
glVertexAttribPointer(3, 4, GL_FLOAT, GL_FALSE, bufItemSize, NULL);
|
||||||
glVertexAttribDivisor(3, 1);
|
glVertexAttribDivisor(3, 1);
|
||||||
glEnableVertexAttribArray(3);
|
glEnableVertexAttribArray(3);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, result.borderThicknessBufferId);
|
return result;
|
||||||
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);
|
|
||||||
|
static RenderObjects_Rect createRectangleObjects(Arena *arena, size_t count) {
|
||||||
|
RenderObjects_Rect result = {0};
|
||||||
|
result.count = count;
|
||||||
|
|
||||||
|
result.p0.buf = PushFullList(arena, RLVec2List, count);
|
||||||
|
result.p1.buf = PushFullList(arena, RLVec2List, count);
|
||||||
|
result.color.buf = PushFullList(arena, RLVec4List, count);
|
||||||
|
result.borderRadius.buf = PushFullList(arena, FloatList, count);
|
||||||
|
result.borderThickness.buf = PushFullList(arena, FloatList, count);
|
||||||
|
result.edgeSoftness.buf = PushFullList(arena, FloatList, count);
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &result.vao);
|
||||||
|
|
||||||
|
glGenBuffers(1, &result.p0.bufId);
|
||||||
|
glGenBuffers(1, &result.p1.bufId);
|
||||||
|
glGenBuffers(1, &result.color.bufId);
|
||||||
|
glGenBuffers(1, &result.borderRadius.bufId);
|
||||||
|
glGenBuffers(1, &result.borderThickness.bufId);
|
||||||
|
glGenBuffers(1, &result.edgeSoftness.bufId);
|
||||||
|
glGenBuffers(1, &result.edgeSoftness.bufId);
|
||||||
|
|
||||||
|
glBindVertexArray(result.vao);
|
||||||
|
|
||||||
|
int32 bufItemSize = sizeof(result.p0.buf.data[0]);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, result.p0.bufId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, result.p0.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||||
|
glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, bufItemSize, NULL);
|
||||||
|
glVertexAttribDivisor(0, 1);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
|
||||||
|
bufItemSize = sizeof(result.p1.buf.data[0]);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, result.p1.bufId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, result.p1.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||||
|
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, bufItemSize, NULL);
|
||||||
|
glVertexAttribDivisor(1, 1);
|
||||||
|
glEnableVertexAttribArray(1);
|
||||||
|
|
||||||
|
bufItemSize = sizeof(result.color.buf.data[0]);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, result.color.bufId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, result.color.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||||
|
glVertexAttribPointer(2, 4, GL_FLOAT, GL_FALSE, bufItemSize, NULL);
|
||||||
|
glVertexAttribDivisor(2, 1);
|
||||||
|
glEnableVertexAttribArray(2);
|
||||||
|
|
||||||
|
bufItemSize = sizeof(result.borderRadius.buf.data[0]);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, result.borderRadius.bufId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, result.borderRadius.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||||
|
glVertexAttribPointer(3, 1, GL_FLOAT, GL_FALSE, bufItemSize, NULL);
|
||||||
|
glVertexAttribDivisor(3, 1);
|
||||||
|
glEnableVertexAttribArray(3);
|
||||||
|
|
||||||
|
bufItemSize = sizeof(result.borderThickness.buf.data[0]);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, result.borderThickness.bufId);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, result.borderThickness.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||||
|
glVertexAttribPointer(4, 1, GL_FLOAT, GL_FALSE, bufItemSize, NULL);
|
||||||
glVertexAttribDivisor(4, 1);
|
glVertexAttribDivisor(4, 1);
|
||||||
glEnableVertexAttribArray(4);
|
glEnableVertexAttribArray(4);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, result.edgeSoftnessBufferId);
|
bufItemSize = sizeof(result.edgeSoftness.buf.data[0]);
|
||||||
glBufferData(GL_ARRAY_BUFFER, result.edgeSoftness.length * sizeof(FloatList_underlying), 0, GL_DYNAMIC_DRAW);
|
glBindBuffer(GL_ARRAY_BUFFER, result.edgeSoftness.bufId);
|
||||||
glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, sizeof(FloatList_underlying), NULL);
|
glBufferData(GL_ARRAY_BUFFER, result.edgeSoftness.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||||
|
glVertexAttribPointer(5, 1, GL_FLOAT, GL_FALSE, bufItemSize, NULL);
|
||||||
glVertexAttribDivisor(5, 1);
|
glVertexAttribDivisor(5, 1);
|
||||||
glEnableVertexAttribArray(5);
|
glEnableVertexAttribArray(5);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
void updateRectangleObjectBuffers(Renderer *r) {
|
#define GL_UpdateBuffer(buffer) \
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, (buffer).bufId);\
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, (buffer).buf.length * sizeof((buffer).underlying), (buffer).buf.data);
|
||||||
|
|
||||||
|
static void updateCharObjectBuffers(Renderer *r) {
|
||||||
|
glBindVertexArray(r->chars.vao);
|
||||||
|
GL_UpdateBuffer(r->chars.begin);
|
||||||
|
GL_UpdateBuffer(r->chars.glyph);
|
||||||
|
GL_UpdateBuffer(r->chars.lineHeight);
|
||||||
|
GL_UpdateBuffer(r->chars.color);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void updateRectangleObjectBuffers(Renderer *r) {
|
||||||
glBindVertexArray(r->rects.vao);
|
glBindVertexArray(r->rects.vao);
|
||||||
|
GL_UpdateBuffer(r->rects.p0);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, r->rects.p0BufferId);
|
GL_UpdateBuffer(r->rects.p1);
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.p0.length * sizeof(RLVec2List_underlying), r->rects.p0.data);
|
GL_UpdateBuffer(r->rects.color);
|
||||||
|
GL_UpdateBuffer(r->rects.borderRadius);
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, r->rects.p1BufferId);
|
GL_UpdateBuffer(r->rects.borderThickness);
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, r->rects.p1.length * sizeof(RLVec2List_underlying), r->rects.p1.data);
|
GL_UpdateBuffer(r->rects.edgeSoftness);
|
||||||
|
|
||||||
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) {
|
Renderer createRenderer(Arena *arena, Scene *scene, Camera *cam, int32 light) {
|
||||||
@@ -90,16 +147,23 @@ Renderer createRenderer(Arena *arena, Scene *scene, Camera *cam, int32 light) {
|
|||||||
.light = light,
|
.light = light,
|
||||||
.camera = cam,
|
.camera = cam,
|
||||||
.rects = createRectangleObjects(arena, 1024),
|
.rects = createRectangleObjects(arena, 1024),
|
||||||
|
.chars = createCharObjects(arena, 10000),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void renderBegin(Renderer *r) {
|
void renderBegin(Renderer *r) {
|
||||||
r->rects.p0.length = 0;
|
r->rects.p0.buf.length = 0;
|
||||||
r->rects.p1.length = 0;
|
r->rects.p1.buf.length = 0;
|
||||||
r->rects.color.length = 0;
|
r->rects.color.buf.length = 0;
|
||||||
r->rects.borderRadius.length = 0;
|
r->rects.borderRadius.buf.length = 0;
|
||||||
r->rects.borderThickness.length = 0;
|
r->rects.borderThickness.buf.length = 0;
|
||||||
r->rects.edgeSoftness.length = 0;
|
r->rects.edgeSoftness.buf.length = 0;
|
||||||
|
|
||||||
|
r->chars.begin.buf.length = 0;
|
||||||
|
r->chars.glyph.buf.length = 0;
|
||||||
|
r->chars.lineHeight.buf.length = 0;
|
||||||
|
r->chars.color.buf.length = 0;
|
||||||
|
|
||||||
r->sceneWidth = 0;
|
r->sceneWidth = 0;
|
||||||
r->sceneHeight = 0;
|
r->sceneHeight = 0;
|
||||||
r->sceneX = 0;
|
r->sceneX = 0;
|
||||||
@@ -107,10 +171,11 @@ void renderBegin(Renderer *r) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void renderEnd(Renderer *r) {
|
void renderEnd(Renderer *r) {
|
||||||
// 3D Entities
|
// 3D Scene
|
||||||
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);
|
glEnable(GL_DEPTH_TEST);
|
||||||
|
|
||||||
glViewport(r->sceneX, r->height - r->sceneY - r->sceneHeight, r->sceneWidth, r->sceneHeight);
|
glViewport(r->sceneX, r->height - r->sceneY - r->sceneHeight, r->sceneWidth, r->sceneHeight);
|
||||||
cameraSetAspect(r->camera, r->sceneWidth, r->sceneHeight);
|
cameraSetAspect(r->camera, r->sceneWidth, r->sceneHeight);
|
||||||
|
|
||||||
@@ -124,8 +189,6 @@ void renderEnd(Renderer *r) {
|
|||||||
|
|
||||||
glBindVertexArray(r->cubeMesh->vao);
|
glBindVertexArray(r->cubeMesh->vao);
|
||||||
|
|
||||||
// TODO(djledda): sort by mesh, texture, etc.
|
|
||||||
|
|
||||||
int model_uniform = getUniformLocation(r->phongShader, "model");
|
int model_uniform = getUniformLocation(r->phongShader, "model");
|
||||||
int solid_color_uniform = getUniformLocation(r->phongShader, "solid_color");
|
int solid_color_uniform = getUniformLocation(r->phongShader, "solid_color");
|
||||||
for (EachIn(r->scene->entities, i)) {
|
for (EachIn(r->scene->entities, i)) {
|
||||||
@@ -141,29 +204,55 @@ void renderEnd(Renderer *r) {
|
|||||||
|
|
||||||
// 2D overlay
|
// 2D overlay
|
||||||
glViewport(0, 0, r->width, r->height);
|
glViewport(0, 0, r->width, r->height);
|
||||||
|
|
||||||
glUseProgram(r->solidShader->progId);
|
glUseProgram(r->solidShader->progId);
|
||||||
|
|
||||||
updateRectangleObjectBuffers(r);
|
|
||||||
|
|
||||||
glDisable(GL_DEPTH_TEST);
|
glDisable(GL_DEPTH_TEST);
|
||||||
glEnable(GL_BLEND);
|
glEnable(GL_BLEND);
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
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);
|
|
||||||
|
|
||||||
|
// 1. Rects
|
||||||
|
updateRectangleObjectBuffers(r);
|
||||||
|
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.buf.length);
|
||||||
|
|
||||||
|
// 2. Text
|
||||||
|
updateCharObjectBuffers(r);
|
||||||
|
glUseProgram(r->textShader->progId);
|
||||||
|
setUniformMat4fv(r->textShader, "projection", &ortho);
|
||||||
|
glEnable(GL_TEXTURE_2D);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, r->activeFont->texId);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE1);
|
||||||
|
glBindTexture(GL_TEXTURE_BUFFER, r->activeFont->glyphTableTexId);
|
||||||
|
setUniform1i(r->textShader, "glyph_table", 1);
|
||||||
|
|
||||||
|
glBindVertexArray(r->chars.vao);
|
||||||
|
glDrawArraysInstanced(GL_TRIANGLE_STRIP, 0, 4, r->chars.begin.buf.length);
|
||||||
|
|
||||||
glDisable(GL_BLEND);
|
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) {
|
||||||
ListAppend(r->rects.p0, ((RLVector2){ x, y }));
|
ListAppend(r->rects.p0.buf, ((RLVector2){ x, y }));
|
||||||
ListAppend(r->rects.p1, ((RLVector2){ x + width, y + height }));
|
ListAppend(r->rects.p1.buf, ((RLVector2){ x + width, y + height }));
|
||||||
ListAppend(r->rects.color, color);
|
ListAppend(r->rects.color.buf, color);
|
||||||
ListAppend(r->rects.borderRadius, borderRadius);
|
ListAppend(r->rects.borderRadius.buf, borderRadius);
|
||||||
ListAppend(r->rects.borderThickness, borderThickness);
|
ListAppend(r->rects.borderThickness.buf, borderThickness);
|
||||||
ListAppend(r->rects.edgeSoftness, 0.15f);
|
ListAppend(r->rects.edgeSoftness.buf, 0.15f);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void rendererPlaceString(Renderer *r, string s, real32 x, real32 y, RLVector4 color, real32 lineHeight) {
|
||||||
|
real32 ratio = lineHeight / r->activeFont->lineHeight;
|
||||||
|
real32 charWidth = ratio * r->activeFont->charWidth;
|
||||||
|
for (int i = 0; i < s.length; i++) {
|
||||||
|
ListAppend(r->chars.begin.buf, ((RLVector2){ .x=x + i*charWidth, .y=y }));
|
||||||
|
ListAppend(r->chars.glyph.buf, s.str[i] - 32);
|
||||||
|
ListAppend(r->chars.lineHeight.buf, ratio);
|
||||||
|
ListAppend(r->chars.color.buf, (color));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
80
src/render.h
80
src/render.h
@@ -4,42 +4,74 @@
|
|||||||
#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"
|
#include "common.h"
|
||||||
|
|
||||||
DefineList(RLVector2, RLVec2);
|
typedef struct RenderObject_BufferInt32 RenderObject_BufferInt32;
|
||||||
DefineList(RLVector4, RLVec4);
|
struct RenderObject_BufferInt32 {
|
||||||
DefineList(real32, Float);
|
IntList buf;
|
||||||
|
uint32 bufId;
|
||||||
|
IntList_underlying underlying;
|
||||||
|
};
|
||||||
|
typedef struct RenderObject_BufferFloat RenderObject_BufferFloat;
|
||||||
|
struct RenderObject_BufferFloat {
|
||||||
|
FloatList buf;
|
||||||
|
uint32 bufId;
|
||||||
|
FloatList_underlying underlying;
|
||||||
|
};
|
||||||
|
typedef struct RenderObject_BufferVec2 RenderObject_BufferVec2;
|
||||||
|
struct RenderObject_BufferVec2 {
|
||||||
|
RLVec2List buf;
|
||||||
|
uint32 bufId;
|
||||||
|
RLVec2List_underlying underlying;
|
||||||
|
};
|
||||||
|
typedef struct RenderObject_BufferVec4 RenderObject_BufferVec4;
|
||||||
|
struct RenderObject_BufferVec4 {
|
||||||
|
RLVec4List buf;
|
||||||
|
uint32 bufId;
|
||||||
|
RLVec4List_underlying underlying;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct RenderObjects_Rectangle RenderObjects_Rectangle;
|
|
||||||
struct RenderObjects_Rectangle {
|
typedef struct RenderObjects_Rect RenderObjects_Rect;
|
||||||
|
struct RenderObjects_Rect {
|
||||||
uint32 vao;
|
uint32 vao;
|
||||||
uint64 count;
|
uint64 count;
|
||||||
|
RenderObject_BufferVec2 p0;
|
||||||
|
RenderObject_BufferVec2 p1;
|
||||||
|
RenderObject_BufferVec4 color;
|
||||||
|
RenderObject_BufferFloat borderRadius;
|
||||||
|
RenderObject_BufferFloat borderThickness;
|
||||||
|
RenderObject_BufferFloat edgeSoftness;
|
||||||
|
};
|
||||||
|
|
||||||
RLVec2List p0;
|
typedef struct RenderObjects_Char RenderObjects_Char;
|
||||||
uint32 p0BufferId;
|
struct RenderObjects_Char {
|
||||||
|
uint32 vao;
|
||||||
|
uint64 count;
|
||||||
|
RenderObject_BufferVec2 begin;
|
||||||
|
RenderObject_BufferInt32 glyph;
|
||||||
|
RenderObject_BufferFloat lineHeight;
|
||||||
|
RenderObject_BufferVec4 color;
|
||||||
|
};
|
||||||
|
|
||||||
RLVec2List p1;
|
typedef struct GlyphData GlyphData;
|
||||||
uint32 p1BufferId;
|
struct GlyphData {
|
||||||
|
real32 x0;
|
||||||
RLVec4List color;
|
real32 y0;
|
||||||
uint32 colorBufferId;
|
real32 x1;
|
||||||
|
real32 y1;
|
||||||
FloatList borderRadius;
|
|
||||||
uint32 borderRadiusBufferId;
|
|
||||||
|
|
||||||
FloatList borderThickness;
|
|
||||||
uint32 borderThicknessBufferId;
|
|
||||||
|
|
||||||
FloatList edgeSoftness;
|
|
||||||
uint32 edgeSoftnessBufferId;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef struct Renderer Renderer;
|
typedef struct Renderer Renderer;
|
||||||
struct Renderer {
|
struct Renderer {
|
||||||
RenderObjects_Rectangle rects;
|
RenderObjects_Rect rects;
|
||||||
|
RenderObjects_Char chars;
|
||||||
|
|
||||||
Shader *phongShader;
|
Shader *phongShader;
|
||||||
Shader *solidShader;
|
Shader *solidShader;
|
||||||
|
Shader *textShader;
|
||||||
|
|
||||||
|
Font *activeFont;
|
||||||
|
|
||||||
int32 width;
|
int32 width;
|
||||||
int32 height;
|
int32 height;
|
||||||
@@ -60,7 +92,7 @@ Renderer createRenderer(Arena *arena, Scene *scene, Camera *cam, int32 light);
|
|||||||
void renderBegin(Renderer *r);
|
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 rendererPlaceString(Renderer *r, string s, real32 x, real32 y, RLVector4 color, real32 fontSize);
|
||||||
#define Render(r) DeferLoop(renderBegin((r)), renderEnd((r)))
|
#define Render(r) DeferLoop(renderBegin((r)), renderEnd((r)))
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
131
src/ui.c
131
src/ui.c
@@ -2,6 +2,9 @@
|
|||||||
#include "GLFW/glfw3.h"
|
#include "GLFW/glfw3.h"
|
||||||
#include "lib/djstdlib/core.h"
|
#include "lib/djstdlib/core.h"
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
UI_Context *__UI_current_ctx__ = NULL;
|
||||||
|
|
||||||
static bool glfwMouse(GLFWwindow *window, int mouseBtnCode) {
|
static bool glfwMouse(GLFWwindow *window, int mouseBtnCode) {
|
||||||
switch (glfwGetMouseButton(window, mouseBtnCode)) {
|
switch (glfwGetMouseButton(window, mouseBtnCode)) {
|
||||||
@@ -48,6 +51,7 @@ UI_Context ui_initContext(Arena *arena, Renderer *renderer) {
|
|||||||
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){
|
||||||
|
.arena=arena,
|
||||||
.rects=list,
|
.rects=list,
|
||||||
.prevRects=prevList,
|
.prevRects=prevList,
|
||||||
.hotNode = 0,
|
.hotNode = 0,
|
||||||
@@ -58,30 +62,16 @@ UI_Context ui_initContext(Arena *arena, Renderer *renderer) {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
static void ui_playground(UI_Context *ui) {
|
void ui_placeText(UI_Context *ui, UI_RectStr strData) {
|
||||||
UI(ui,
|
UI_RectStr *strDataCopy = PushStruct(ui->arena, UI_RectStr);
|
||||||
.width=ui->renderer->width,
|
*strDataCopy = strData;
|
||||||
.height=ui->renderer->height,
|
if (strDataCopy->lineHeight == -1) {
|
||||||
.color=COLOR_WHITE,
|
strDataCopy->lineHeight = ui->renderer->activeFont->lineHeight;
|
||||||
) {
|
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
strDataCopy->s = PushString(ui->arena, strData.s.length);
|
||||||
|
memcpy(strDataCopy->s.str, strData.s.str, strData.s.length);
|
||||||
|
UI_Rect *currRect = &ui->rects.data[ui->currRect];
|
||||||
|
currRect->stringData = strDataCopy;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ui_sizingPass(UI_Context *ui, bool isXAxis, int32 rectHandle) {
|
void ui_sizingPass(UI_Context *ui, bool isXAxis, int32 rectHandle) {
|
||||||
@@ -116,18 +106,22 @@ void ui_sizingPass(UI_Context *ui, bool isXAxis, int32 rectHandle) {
|
|||||||
while (childHandle) {
|
while (childHandle) {
|
||||||
child = &ui->rects.data[childHandle];
|
child = &ui->rects.data[childHandle];
|
||||||
|
|
||||||
if (isVertical && (child->flags & UI_Flag_WidthGrow) && isXAxis) {
|
if (isXAxis) {
|
||||||
child->resolvedWidth = rect->resolvedWidth - rect->padding.left - rect->padding.right;
|
if (child->flags & UI_Flag_WidthGrow) {
|
||||||
}
|
if (isVertical) {
|
||||||
if (!isVertical && (child->flags & UI_Flag_HeightGrow) && !isXAxis) {
|
child->resolvedWidth = rect->resolvedWidth - rect->padding.left - rect->padding.right;
|
||||||
child->resolvedHeight = rect->resolvedHeight - rect->padding.top - rect->padding.bottom;
|
} else {
|
||||||
}
|
child->resolvedWidth += childBreadthInc;
|
||||||
|
}
|
||||||
if (child->flags & UI_Flag_WidthGrow && !isVertical && isXAxis) {
|
}
|
||||||
child->resolvedWidth += childBreadthInc;
|
} else {
|
||||||
}
|
if (child->flags & UI_Flag_HeightGrow) {
|
||||||
if (child->flags & UI_Flag_HeightGrow && isVertical && !isXAxis) {
|
if (!isVertical) {
|
||||||
child->resolvedHeight += childBreadthInc;
|
child->resolvedHeight = rect->resolvedHeight - rect->padding.top - rect->padding.bottom;
|
||||||
|
} else {
|
||||||
|
child->resolvedHeight += childBreadthInc;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_sizingPass(ui, isXAxis, childHandle);
|
ui_sizingPass(ui, isXAxis, childHandle);
|
||||||
@@ -142,7 +136,9 @@ void ui_calcLayout(UI_Context *ui, bool isXAxis, int32 rectHandle) {
|
|||||||
|
|
||||||
bool isVertical = (rect->flags & UI_Flag_Vertical);
|
bool isVertical = (rect->flags & UI_Flag_Vertical);
|
||||||
|
|
||||||
real32 coord = isXAxis ? rect->x + rect->xOffset + rect->padding.left : rect->y + rect->yOffset + rect->padding.top;
|
real32 coord = isXAxis
|
||||||
|
? rect->x + rect->xOffset + rect->padding.left
|
||||||
|
: rect->y + rect->yOffset + rect->padding.top;
|
||||||
|
|
||||||
int32 childHandle = rect->firstChild;
|
int32 childHandle = rect->firstChild;
|
||||||
UI_Rect *child;
|
UI_Rect *child;
|
||||||
@@ -150,9 +146,13 @@ void ui_calcLayout(UI_Context *ui, bool isXAxis, int32 rectHandle) {
|
|||||||
child = &ui->rects.data[childHandle];
|
child = &ui->rects.data[childHandle];
|
||||||
|
|
||||||
if (isXAxis) {
|
if (isXAxis) {
|
||||||
child->x = coord;
|
child->x = child->flags & UI_Flag_Center && isVertical
|
||||||
|
? coord + (rect->resolvedWidth - rect->padding.left - rect->padding.right)/2 - child->resolvedWidth/2
|
||||||
|
: coord;
|
||||||
} else {
|
} else {
|
||||||
child->y = coord;
|
child->y = child->flags & UI_Flag_Center && !isVertical
|
||||||
|
? coord + (rect->resolvedHeight - rect->padding.top - rect->padding.bottom)/2 - child->resolvedHeight/2
|
||||||
|
: coord;
|
||||||
}
|
}
|
||||||
|
|
||||||
ui_calcLayout(ui, isXAxis, childHandle);
|
ui_calcLayout(ui, isXAxis, childHandle);
|
||||||
@@ -167,6 +167,8 @@ void ui_calcLayout(UI_Context *ui, bool isXAxis, int32 rectHandle) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void ui_begin(UI_Context *ui) {
|
void ui_begin(UI_Context *ui) {
|
||||||
|
__UI_current_ctx__ = ui;
|
||||||
|
arenaFreeFrom(ui->arena, 0);
|
||||||
ClearList(ui->prevRects);
|
ClearList(ui->prevRects);
|
||||||
ListAppendList(ui->prevRects, ui->rects);
|
ListAppendList(ui->prevRects, ui->rects);
|
||||||
ui->cursorIsPointer = false;
|
ui->cursorIsPointer = false;
|
||||||
@@ -204,6 +206,17 @@ void ui_end(UI_Context *ui) {
|
|||||||
rect->borderRadius,
|
rect->borderRadius,
|
||||||
rect->borderThickness
|
rect->borderThickness
|
||||||
);
|
);
|
||||||
|
if (rect->stringData) {
|
||||||
|
UI_RectStr *str = rect->stringData;
|
||||||
|
rendererPlaceString(
|
||||||
|
ui->renderer,
|
||||||
|
str->s,
|
||||||
|
rect->x + str->xOffset,
|
||||||
|
rect->y + str->yOffset,
|
||||||
|
str->color,
|
||||||
|
str->lineHeight
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ui->scene3DHandle) {
|
if (ui->scene3DHandle) {
|
||||||
@@ -213,10 +226,12 @@ void ui_end(UI_Context *ui) {
|
|||||||
ui->renderer->sceneWidth = (int32)scene3DRect->resolvedWidth;
|
ui->renderer->sceneWidth = (int32)scene3DRect->resolvedWidth;
|
||||||
ui->renderer->sceneHeight = (int32)scene3DRect->resolvedHeight;
|
ui->renderer->sceneHeight = (int32)scene3DRect->resolvedHeight;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
__UI_current_ctx__ = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool pointInRect(real32 x, real32 y, UI_Rect rect) {
|
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);
|
return x > rect.x && y > rect.y && x < (rect.x + rect.resolvedWidth) && y < (rect.y + rect.resolvedHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ui_openElement(UI_Context *ui, UI_Rect rect) {
|
void ui_openElement(UI_Context *ui, UI_Rect rect) {
|
||||||
@@ -252,18 +267,35 @@ void ui_closeElement(UI_Context *ui) {
|
|||||||
if (currRect->width != -1) {
|
if (currRect->width != -1) {
|
||||||
currRect->resolvedWidth = currRect->width;
|
currRect->resolvedWidth = currRect->width;
|
||||||
}
|
}
|
||||||
currRect->resolvedWidth += currRect->padding.left + currRect->padding.right;
|
if (currRect->minWidth == -1) {
|
||||||
|
if (currRect->stringData) {
|
||||||
|
real32 charWidth = currRect->stringData->lineHeight / ui->renderer->activeFont->lineHeight * ui->renderer->activeFont->charWidth;
|
||||||
|
currRect->minWidth = charWidth*currRect->stringData->s.length;
|
||||||
|
} else {
|
||||||
|
currRect->minWidth = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
currRect->resolvedWidth = currRect->padding.left + currRect->padding.right + (currRect->resolvedWidth < currRect->minWidth ? currRect->minWidth : currRect->resolvedWidth);
|
||||||
|
|
||||||
if (currRect->height != -1) {
|
if (currRect->height != -1) {
|
||||||
currRect->resolvedHeight = currRect->height;
|
currRect->resolvedHeight = currRect->height;
|
||||||
|
} else if (currRect->minHeight == -1) {
|
||||||
|
if (currRect->stringData) {
|
||||||
|
currRect->minHeight = currRect->stringData->lineHeight;
|
||||||
|
} else {
|
||||||
|
currRect->minHeight = 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
currRect->resolvedHeight += currRect->padding.top + currRect->padding.bottom;
|
currRect->resolvedHeight = currRect->padding.top + currRect->padding.bottom + (currRect->resolvedHeight < currRect->minHeight ? currRect->minHeight : currRect->resolvedHeight);
|
||||||
|
|
||||||
bool vertical = parentRect->flags & UI_Flag_Vertical;
|
bool vertical = parentRect->flags & UI_Flag_Vertical;
|
||||||
|
|
||||||
real32 currBreadth = vertical ? currRect->resolvedHeight : currRect->resolvedWidth;
|
real32 currBreadth = vertical ? currRect->resolvedHeight : currRect->resolvedWidth;
|
||||||
real32 currCrossBreadth = vertical ? currRect->resolvedWidth : currRect->resolvedHeight;
|
real32 currCrossBreadth = vertical ? currRect->resolvedWidth : currRect->resolvedHeight;
|
||||||
real32 parentBreadth = vertical ? parentRect->height : parentRect->width;
|
real32 parentBreadth = vertical ? parentRect->height : parentRect->width;
|
||||||
|
real32 currParentBreadth = vertical ? parentRect->resolvedHeight : parentRect->resolvedWidth;
|
||||||
real32 parentCrossBreadth = vertical ? parentRect->width : parentRect->height;
|
real32 parentCrossBreadth = vertical ? parentRect->width : parentRect->height;
|
||||||
|
real32 currParentCrossBreadth = vertical ? parentRect->resolvedWidth : parentRect->resolvedHeight;
|
||||||
real32 gap = parentRect->childGap;
|
real32 gap = parentRect->childGap;
|
||||||
|
|
||||||
real32 breadthInc = (parentRect->firstChild == ui->currRect ? 0 : gap) + currBreadth;
|
real32 breadthInc = (parentRect->firstChild == ui->currRect ? 0 : gap) + currBreadth;
|
||||||
@@ -276,7 +308,7 @@ void ui_closeElement(UI_Context *ui) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
real32 newCrossBreadth = currCrossBreadth > parentCrossBreadth ? currCrossBreadth : parentCrossBreadth;
|
real32 newCrossBreadth = currCrossBreadth > currParentCrossBreadth ? currCrossBreadth : currParentCrossBreadth;
|
||||||
if (parentCrossBreadth == -1) {
|
if (parentCrossBreadth == -1) {
|
||||||
if (vertical) {
|
if (vertical) {
|
||||||
parentRect->resolvedWidth = newCrossBreadth;
|
parentRect->resolvedWidth = newCrossBreadth;
|
||||||
@@ -288,8 +320,8 @@ void ui_closeElement(UI_Context *ui) {
|
|||||||
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) {
|
bool ui_Button(UI_Context *ui, UI_Rect rect, UI_RectStr textAttr) {
|
||||||
int32 id = UI_NextID(ui);
|
int32 id = UI_NextID();
|
||||||
bool clicked = false;
|
bool clicked = false;
|
||||||
|
|
||||||
if (pointInRect(ui->input->mouse.point.x, ui->input->mouse.point.y, ui->prevRects.data[id])) {
|
if (pointInRect(ui->input->mouse.point.x, ui->input->mouse.point.y, ui->prevRects.data[id])) {
|
||||||
@@ -302,8 +334,9 @@ bool ui_Button(UI_Context *ui, UI_Rect rect) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
rect.borderRadius = 5;
|
rect.borderRadius = 5;
|
||||||
rect.borderThickness = 0;
|
UI_FromRect(rect) {
|
||||||
UI_FromRect(ui, rect);
|
ui_placeText(ui, textAttr);
|
||||||
|
}
|
||||||
|
|
||||||
return clicked;
|
return clicked;
|
||||||
}
|
}
|
||||||
@@ -312,7 +345,7 @@ bool ui_Button(UI_Context *ui, UI_Rect rect) {
|
|||||||
* 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) {
|
||||||
int32 id = UI_NextID(ui);
|
int32 id = UI_NextID();
|
||||||
bool clicked = false;
|
bool clicked = false;
|
||||||
if (pointInRect(ui->input->mouse.point.x, ui->input->mouse.point.y, ui->prevRects.data[id])) {
|
if (pointInRect(ui->input->mouse.point.x, ui->input->mouse.point.y, ui->prevRects.data[id])) {
|
||||||
ui->cursorIsPointer = true;
|
ui->cursorIsPointer = true;
|
||||||
@@ -326,12 +359,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;
|
||||||
UI_FromRect(ui, rect);
|
UI_FromRect(rect);
|
||||||
} else {
|
} else {
|
||||||
rect.borderRadius = 5;
|
rect.borderRadius = 5;
|
||||||
rect.borderThickness = 2;
|
rect.borderThickness = 2;
|
||||||
rect.color = COLOR_WHITE;
|
rect.color = COLOR_WHITE;
|
||||||
UI_FromRect(ui, rect);
|
UI_FromRect(rect);
|
||||||
}
|
}
|
||||||
|
|
||||||
return clicked;
|
return clicked;
|
||||||
|
|||||||
28
src/ui.h
28
src/ui.h
@@ -41,6 +41,7 @@ enum UI_Flag {
|
|||||||
UI_Flag_HeightGrow=1<<1,
|
UI_Flag_HeightGrow=1<<1,
|
||||||
UI_Flag_Vertical=1<<2, // Default is horizontal
|
UI_Flag_Vertical=1<<2, // Default is horizontal
|
||||||
UI_Flag_3DScene=1<<3,
|
UI_Flag_3DScene=1<<3,
|
||||||
|
UI_Flag_Center=1<<4,
|
||||||
// ..
|
// ..
|
||||||
UI_Flag_COUNT,
|
UI_Flag_COUNT,
|
||||||
};
|
};
|
||||||
@@ -53,9 +54,18 @@ struct UI_Padding {
|
|||||||
real32 left;
|
real32 left;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
typedef struct UI_RectStr UI_RectStr;
|
||||||
|
struct UI_RectStr {
|
||||||
|
string s;
|
||||||
|
real32 xOffset;
|
||||||
|
real32 yOffset;
|
||||||
|
real32 lineHeight;
|
||||||
|
RLVector4 color;
|
||||||
|
};
|
||||||
|
|
||||||
typedef struct UI_Rect UI_Rect;
|
typedef struct UI_Rect UI_Rect;
|
||||||
struct UI_Rect {
|
struct UI_Rect {
|
||||||
// UI_Rect_LayoutFlag
|
/** UI_Rect_LayoutFlag */
|
||||||
uint64 flags;
|
uint64 flags;
|
||||||
|
|
||||||
int32 parent;
|
int32 parent;
|
||||||
@@ -87,11 +97,14 @@ struct UI_Rect {
|
|||||||
real32 y;
|
real32 y;
|
||||||
real32 resolvedWidth;
|
real32 resolvedWidth;
|
||||||
real32 resolvedHeight;
|
real32 resolvedHeight;
|
||||||
|
|
||||||
|
UI_RectStr *stringData;
|
||||||
};
|
};
|
||||||
DefineList(UI_Rect, UI_Rect);
|
DefineList(UI_Rect, UI_Rect);
|
||||||
|
|
||||||
typedef struct UI_Context UI_Context;
|
typedef struct UI_Context UI_Context;
|
||||||
struct UI_Context {
|
struct UI_Context {
|
||||||
|
Arena *arena;
|
||||||
UI_RectList prevRects;
|
UI_RectList prevRects;
|
||||||
UI_RectList rects;
|
UI_RectList rects;
|
||||||
int32 hotNode;
|
int32 hotNode;
|
||||||
@@ -114,16 +127,21 @@ void ui_end(UI_Context *ui);
|
|||||||
UI_Context ui_initContext(Arena *arena, Renderer *renderer);
|
UI_Context ui_initContext(Arena *arena, Renderer *renderer);
|
||||||
void ui_resolve();
|
void ui_resolve();
|
||||||
void ui_rect(UI_Context *ui, UI_Rect rect);
|
void ui_rect(UI_Context *ui, UI_Rect rect);
|
||||||
|
void ui_placeText(UI_Context *ui, UI_RectStr strData);
|
||||||
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);
|
||||||
|
|
||||||
bool ui_CheckboxRect(UI_Context *ui, bool *value, UI_Rect rect);
|
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)))
|
extern UI_Context *__UI_current_ctx__;
|
||||||
#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(...) DeferLoop(ui_openElement((__UI_current_ctx__), UI_CreateRect(__VA_ARGS__)), ui_closeElement((__UI_current_ctx__)))
|
||||||
|
#define UI_CreateRect(...) ((UI_Rect){.minHeight=-1, .minWidth=-1, .width=-1, .height=-1, __VA_ARGS__})
|
||||||
|
#define UI_FromRect(rect) DeferLoop(ui_openElement((__UI_current_ctx__), (rect)), ui_closeElement((__UI_current_ctx__)))
|
||||||
#define UI_Pass(ui) DeferLoop(ui_begin((ui)), ui_end((ui)))
|
#define UI_Pass(ui) DeferLoop(ui_begin((ui)), ui_end((ui)))
|
||||||
#define UI_PadUniform(padding) ((UI_Padding){ (padding), (padding), (padding), (padding) })
|
#define UI_PadUniform(padding) ((UI_Padding){ (padding), (padding), (padding), (padding) })
|
||||||
#define UI_NextID(ui) ((ui)->rects.length)
|
#define UI_NextID() ((__UI_current_ctx__)->rects.length)
|
||||||
|
#define UI_Text(str, ...) (ui_placeText((__UI_current_ctx__), ((UI_RectStr){ .xOffset=0, .yOffset=0, .lineHeight=-1, .s=(str), __VA_ARGS__ })))
|
||||||
|
#define UI_CreateText(str, ...) ((UI_RectStr){ .xOffset=0, .yOffset=0, .lineHeight=-1, .s=(str), __VA_ARGS__ })
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|||||||
Reference in New Issue
Block a user