update
This commit is contained in:
@@ -8,6 +8,7 @@ in vec2 frag_dest_half_size;
|
||||
in float frag_softness;
|
||||
in float frag_border_radius;
|
||||
in float frag_border_thickness;
|
||||
in vec4 frag_border_color;
|
||||
|
||||
float roundedRectSDF(vec2 sample_pos, vec2 rect_center, vec2 rect_half_size, float r) {
|
||||
vec2 d2 = (abs(rect_center - sample_pos) - rect_half_size + vec2(r, r));
|
||||
@@ -51,5 +52,6 @@ void main() {
|
||||
|
||||
float sdf_factor = 1 - smoothstep(0, 2*frag_softness, dist);
|
||||
|
||||
pixel_color = frag_color * sample * sdf_factor * border_factor;
|
||||
pixel_color = frag_border_color * sample * sdf_factor * border_factor
|
||||
+ frag_color * sample * sdf_factor;
|
||||
};
|
||||
|
||||
@@ -4,7 +4,8 @@ layout (location = 1) in vec2 p1;
|
||||
layout (location = 2) in vec4 color;
|
||||
layout (location = 3) in float border_radius;
|
||||
layout (location = 4) in float border_thickness;
|
||||
layout (location = 5) in float edge_softness;
|
||||
layout (location = 5) in vec4 border_color;
|
||||
layout (location = 6) in float edge_softness;
|
||||
|
||||
uniform mat4 projection;
|
||||
|
||||
@@ -15,6 +16,7 @@ out vec2 frag_dest_half_size;
|
||||
out float frag_softness;
|
||||
out float frag_border_radius;
|
||||
out float frag_border_thickness;
|
||||
out vec4 frag_border_color;
|
||||
|
||||
const vec2 rectangle_vertices[4] = vec2[](
|
||||
vec2(-1, -1),
|
||||
@@ -40,5 +42,6 @@ void main() {
|
||||
frag_dest_half_size = dest_half_size;
|
||||
frag_border_radius = border_radius;
|
||||
frag_border_thickness = border_thickness;
|
||||
frag_border_color = border_color;
|
||||
frag_softness = edge_softness;
|
||||
}
|
||||
|
||||
@@ -1,24 +1,9 @@
|
||||
#version 330 core
|
||||
layout (location = 0) in vec2 begin;
|
||||
layout (location = 1) in int glyph;
|
||||
layout (location = 2) in float lineHeight;
|
||||
layout (location = 2) in float fontSize;
|
||||
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;
|
||||
@@ -57,8 +42,8 @@ void main() {
|
||||
vec2 offset = chunk2.xy;
|
||||
vec2 dims = chunk2.zw;
|
||||
|
||||
vec2 p0 = begin + offset*lineHeight;
|
||||
vec2 p1 = begin + (offset + dims)*lineHeight;
|
||||
vec2 p0 = begin + offset*fontSize;
|
||||
vec2 p1 = begin + (offset + dims)*fontSize;
|
||||
|
||||
vec2 dest_half_size = (p1 - p0) / 2;
|
||||
vec2 dest_center = (p1 + p0) / 2;
|
||||
|
||||
2
build
2
build
@@ -5,7 +5,7 @@ COMMON_FLAGS="-DOS_LINUX=1 -DCOMPOSITOR_WAYLAND=1 -xc -std=c99 -Wno-initializer-
|
||||
|
||||
echo [Building target]
|
||||
if [ $DEBUG ]; then
|
||||
time clang -O1 -g -g2 $COMMON_FLAGS -O1 -fsanitize=address,undefined -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
|
||||
time clang -O2 $COMMON_FLAGS ./src/main.c -o ./target/somaesque $LIB_INCLUDE
|
||||
fi
|
||||
|
||||
@@ -68,18 +68,18 @@ Mesh createMesh(const char* obj_file) {
|
||||
glBindVertexArray(result.vao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, result.buffers.xyz);
|
||||
glBufferData(GL_ARRAY_BUFFER, vertices.length * sizeof(float), vertices.data, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||
glBufferData(GL_ARRAY_BUFFER, vertices.length * sizeof(real32), vertices.data, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(real32), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, result.buffers.uv);
|
||||
glBufferData(GL_ARRAY_BUFFER, texcoords.length * sizeof(float), texcoords.data, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
|
||||
glBufferData(GL_ARRAY_BUFFER, texcoords.length * sizeof(real32), texcoords.data, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(real32), (void*)0);
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, result.buffers.normals);
|
||||
glBufferData(GL_ARRAY_BUFFER, normals.length * sizeof(float), normals.data, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||
glBufferData(GL_ARRAY_BUFFER, normals.length * sizeof(real32), normals.data, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(2, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(real32), (void*)0);
|
||||
glEnableVertexAttribArray(2);
|
||||
|
||||
//glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo);
|
||||
@@ -92,24 +92,24 @@ Mesh createMesh(const char* obj_file) {
|
||||
Mesh createMeshFromShape(const Shape* shape) {
|
||||
Mesh result = {0};
|
||||
|
||||
result.num_indices = shape->indices_size;
|
||||
result.num_indices = shape->indices.length;
|
||||
glGenVertexArrays(1, &result.vao);
|
||||
glGenBuffers(3, result.vbos);
|
||||
|
||||
glBindVertexArray(result.vao);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, result.buffers.xyz);
|
||||
glBufferData(GL_ARRAY_BUFFER, shape->xyz_size * sizeof(float), shape->xyz, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ARRAY_BUFFER, shape->xyz.length * sizeof(float), shape->xyz.data, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), (void*)0);
|
||||
glEnableVertexAttribArray(0);
|
||||
|
||||
glBindBuffer(GL_ARRAY_BUFFER, result.buffers.uv);
|
||||
glBufferData(GL_ARRAY_BUFFER, shape->uv_size * sizeof(float), shape->uv, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0);
|
||||
glBufferData(GL_ARRAY_BUFFER, shape->uv.length * sizeof(real32), shape->uv.data, GL_STATIC_DRAW);
|
||||
glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(real32), (void*)0);
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, result.buffers.elements);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, shape->indices_size * sizeof(unsigned int), shape->indices, GL_STATIC_DRAW);
|
||||
glBufferData(GL_ELEMENT_ARRAY_BUFFER, shape->indices.length * sizeof(uint32), shape->indices.data, GL_STATIC_DRAW);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -10,53 +10,51 @@ typedef enum {
|
||||
} ShaderType;
|
||||
|
||||
uint32 createGlShader(string file_path, ShaderType shader_type) {
|
||||
Scratch temp = scratchStart(0, 0);
|
||||
string shader_code = os_readEntireFile(temp.arena, file_path);
|
||||
GLuint shader = glCreateShader(shader_type);
|
||||
const char *shader_code_cstr = cstring(temp.arena, shader_code);
|
||||
glShaderSource(shader, 1, &shader_code_cstr, NULL);
|
||||
glCompileShader(shader);
|
||||
int success;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
GLint info_log_length;
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);
|
||||
string info_log = PushString(temp.arena, (size_t)info_log_length + 1);
|
||||
glGetShaderInfoLog(shader, info_log_length, NULL, info_log.str);
|
||||
const char* shader_type_name = shader_type == ShaderType_fragment ? "FRAGMENT" : "VERTEX";
|
||||
print("%s shader compilation error (%S):\n%S", shader_type_name, file_path, info_log);
|
||||
GLuint shader;
|
||||
WithScratch(scratch) {
|
||||
string shader_code = os_readEntireFile(scratch.arena, file_path);
|
||||
shader = glCreateShader(shader_type);
|
||||
const char *shader_code_cstr = cstring(scratch.arena, shader_code);
|
||||
glShaderSource(shader, 1, &shader_code_cstr, NULL);
|
||||
glCompileShader(shader);
|
||||
int success;
|
||||
glGetShaderiv(shader, GL_COMPILE_STATUS, &success);
|
||||
if (!success) {
|
||||
GLint info_log_length;
|
||||
glGetShaderiv(shader, GL_INFO_LOG_LENGTH, &info_log_length);
|
||||
string info_log = PushString(scratch.arena, (size_t)info_log_length + 1);
|
||||
glGetShaderInfoLog(shader, info_log_length, NULL, info_log.str);
|
||||
string shader_type_name = shader_type == ShaderType_fragment ? s("FRAGMENT") : s("VERTEX");
|
||||
print("%S shader compilation error (%S):\n%S", shader_type_name, file_path, info_log);
|
||||
}
|
||||
}
|
||||
scratchEnd(temp);
|
||||
return shader;
|
||||
}
|
||||
|
||||
Shader createShader(string vertex_path, string fragment_path) {
|
||||
Scratch temp = scratchStart(0, 0);
|
||||
|
||||
Shader result = {0};
|
||||
WithScratch(temp) {
|
||||
uint32 vertex_shader = createGlShader(vertex_path, ShaderType_vertex);
|
||||
uint32 fragment_shader = createGlShader(fragment_path, ShaderType_fragment);
|
||||
|
||||
uint32 vertex_shader = createGlShader(vertex_path, ShaderType_vertex);
|
||||
uint32 fragment_shader = createGlShader(fragment_path, ShaderType_fragment);
|
||||
result.progId = glCreateProgram();
|
||||
glAttachShader(result.progId, vertex_shader);
|
||||
glAttachShader(result.progId, fragment_shader);
|
||||
glLinkProgram(result.progId);
|
||||
|
||||
result.progId = glCreateProgram();
|
||||
glAttachShader(result.progId, vertex_shader);
|
||||
glAttachShader(result.progId, fragment_shader);
|
||||
glLinkProgram(result.progId);
|
||||
int success;
|
||||
glGetProgramiv(result.progId, GL_LINK_STATUS, &success);
|
||||
if (!success) {
|
||||
GLint info_log_length;
|
||||
glGetShaderiv(result.progId, GL_INFO_LOG_LENGTH, &info_log_length);
|
||||
string info_log_prog = PushString(temp.arena, (size_t)info_log_length + 1);
|
||||
glGetProgramInfoLog(result.progId, info_log_length, NULL, info_log_prog.str);
|
||||
print("Shader program link error:\n%S", info_log_prog);
|
||||
}
|
||||
|
||||
int success;
|
||||
glGetProgramiv(result.progId, GL_LINK_STATUS, &success);
|
||||
if (!success) {
|
||||
GLint info_log_length;
|
||||
glGetShaderiv(result.progId, GL_INFO_LOG_LENGTH, &info_log_length);
|
||||
string info_log_prog = PushString(temp.arena, (size_t)info_log_length + 1);
|
||||
glGetProgramInfoLog(result.progId, info_log_length, NULL, info_log_prog.str);
|
||||
print("Shader program link error:\n%S", info_log_prog);
|
||||
glDeleteShader(vertex_shader);
|
||||
glDeleteShader(fragment_shader);
|
||||
}
|
||||
|
||||
glDeleteShader(vertex_shader);
|
||||
glDeleteShader(fragment_shader);
|
||||
|
||||
scratchEnd(temp);
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,4 @@
|
||||
#include "Texture.h"
|
||||
#include <asm-generic/errno-base.h>
|
||||
#include <errno.h>
|
||||
|
||||
Texture createTexture(const char* bitmap, int32 width, int32 height) {
|
||||
Texture result = {0};
|
||||
@@ -25,11 +23,11 @@ DefineList(stbtt_bakedchar, STBBakedChar);
|
||||
static void saveGrayscaleTarga(string location, const char *bytes, int width, int height) {
|
||||
char tgaHeader[18] = {
|
||||
// Image ID length
|
||||
0x0,
|
||||
0x00,
|
||||
// Color map type
|
||||
0x0,
|
||||
0x00,
|
||||
// Image type
|
||||
0x3,
|
||||
0x03,
|
||||
// Color map info (unused)
|
||||
0x0, 0x0, 0x0, 0x0, 0x0,
|
||||
// Image spec
|
||||
@@ -38,7 +36,7 @@ static void saveGrayscaleTarga(string location, const char *bytes, int width, in
|
||||
width & 0xFF, (width >> 8) & 0xFF, // width
|
||||
height & 0xFF, (height >> 8) & 0xFF, // width
|
||||
0x8, // bits per px (depth)
|
||||
0b00001000, // image descriptor
|
||||
0b00000000, // image descriptor
|
||||
};
|
||||
os_writeEntireFile(location, tgaHeader, ArrayCount(tgaHeader));
|
||||
os_fileAppend(location, bytes, width * height);
|
||||
@@ -48,8 +46,8 @@ Font createFont(Arena *arena, string ttfLocation, real32 lineHeight) {
|
||||
const int CODEPOINT_START = 32;
|
||||
const int CODEPOINT_END = 126;
|
||||
|
||||
int32 atlasWidth = 512;//16 * lineHeight;
|
||||
int32 atlasHeight = 512;// * lineHeight;
|
||||
int32 atlasWidth = ((int32)lineHeight)*(int32)sqrt(CODEPOINT_END - CODEPOINT_START);
|
||||
int32 atlasHeight = ((int32)lineHeight)*(int32)sqrt(CODEPOINT_END - CODEPOINT_START);
|
||||
|
||||
STBBakedCharList bakedCharlist = PushFullListZero(arena, STBBakedCharList, CODEPOINT_END - CODEPOINT_START);
|
||||
string fontFile = os_readEntireFile(arena, ttfLocation);
|
||||
@@ -58,7 +56,7 @@ Font createFont(Arena *arena, string ttfLocation, real32 lineHeight) {
|
||||
stbtt_InitFont(&info, (unsigned char *)fontFile.str, stbtt_GetFontOffsetForIndex((unsigned char *)fontFile.str, 0));
|
||||
int ascent, descent, lineGap;
|
||||
stbtt_GetFontVMetrics(&info, &ascent, &descent, &lineGap);
|
||||
real32 scale = stbtt_ScaleForPixelHeight(&info, 96);
|
||||
real32 scale = stbtt_ScaleForPixelHeight(&info, lineHeight);
|
||||
|
||||
char *bakedFontBitmap = PushArrayZero(arena, char, atlasWidth*atlasHeight);
|
||||
int32 bake_result = stbtt_BakeFontBitmap(
|
||||
@@ -68,8 +66,6 @@ Font createFont(Arena *arena, string ttfLocation, real32 lineHeight) {
|
||||
CODEPOINT_START, CODEPOINT_END - CODEPOINT_START,
|
||||
bakedCharlist.data);
|
||||
|
||||
saveGrayscaleTarga(s("bakedfont.tga"), bakedFontBitmap, atlasWidth, atlasHeight);
|
||||
|
||||
GlyphMetaList glyphMeta = PushFullListZero(arena, GlyphMetaList, bakedCharlist.length);
|
||||
real32 x, y;
|
||||
real32 lastX, lastY;
|
||||
@@ -93,6 +89,8 @@ Font createFont(Arena *arena, string ttfLocation, real32 lineHeight) {
|
||||
result.lineHeight = lineHeight;
|
||||
result.charWidth = bakedCharlist.data[0].xadvance;
|
||||
|
||||
//saveGrayscaleTarga(s("atlas.tga"), bakedFontBitmap, atlasWidth, atlasHeight);
|
||||
|
||||
glGenTextures(1, &result.texId);
|
||||
glBindTexture(GL_TEXTURE_2D, result.texId);
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, atlasWidth, atlasHeight, 0, GL_RED, GL_UNSIGNED_BYTE, bakedFontBitmap);
|
||||
|
||||
@@ -1,20 +1,21 @@
|
||||
#include "geometry.h"
|
||||
#include "../common.h"
|
||||
#include "../lib/djstdlib/core.h"
|
||||
|
||||
// Buffer layout:
|
||||
// X, Y, Z, U, V
|
||||
|
||||
real32 triangle_vertices[] = {
|
||||
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
|
||||
const FloatList triangle_vertices = AsList(FloatList, {
|
||||
-0.5f, -0.5f, 0.0f, 1.0f, 1.0f,
|
||||
0.5f, -0.5f, 0.0f, 0.5f, 0.5f,
|
||||
0.0f, 0.5f, 0.0f, 0.0f, 0.0f,
|
||||
};
|
||||
});
|
||||
|
||||
uint32 triangle_indices[] = {
|
||||
const UInt32List triangle_indices = AsList(UInt32List, {
|
||||
0, 1, 2
|
||||
};
|
||||
});
|
||||
|
||||
real32 cube_vertices[] = {
|
||||
const FloatList cube_vertices = AsList(FloatList, {
|
||||
-0.5f, -0.5f, -0.5f, 0.0f, 0.0f,
|
||||
0.5f, -0.5f, -0.5f, 1.0f, 0.0f,
|
||||
0.5f, 0.5f, -0.5f, 1.0f, 1.0f,
|
||||
@@ -56,55 +57,46 @@ real32 cube_vertices[] = {
|
||||
0.5f, 0.5f, 0.5f, 1.0f, 0.0f,
|
||||
-0.5f, 0.5f, 0.5f, 0.0f, 0.0f,
|
||||
-0.5f, 0.5f, -0.5f, 0.0f, 1.0f
|
||||
};
|
||||
});
|
||||
|
||||
uint32 cube_indices[] = {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
|
||||
};
|
||||
const UInt32List cube_indices = AsList(UInt32List, {
|
||||
0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16,
|
||||
17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31
|
||||
});
|
||||
|
||||
real32 square_xyz[] = {
|
||||
const FloatList square_xyz = AsList(FloatList, {
|
||||
200.0f, 200.0f, 0.0f,
|
||||
200.0f, -200.0f, 0.0f,
|
||||
-200.0f, -200.0f, 0.0f,
|
||||
-200.0f, 200.0f, 0.0f,
|
||||
};
|
||||
});
|
||||
|
||||
real32 square_uv[] = {
|
||||
1.0f, 1.0f,
|
||||
const FloatList square_uv = AsList(FloatList, {
|
||||
1.0f, 1.0f,
|
||||
1.0f, 0.0f,
|
||||
0.0f, 0.0f,
|
||||
0.0f, 1.0f,
|
||||
};
|
||||
});
|
||||
|
||||
uint32 square_indices[] = {
|
||||
0, 1, 3,
|
||||
const UInt32List square_indices = AsList(UInt32List, {
|
||||
0, 1, 3,
|
||||
1, 2, 3,
|
||||
};
|
||||
});
|
||||
|
||||
const Shape TRIANGLE = {
|
||||
triangle_indices,
|
||||
ArrayCount(triangle_indices),
|
||||
triangle_vertices,
|
||||
ArrayCount(triangle_vertices),
|
||||
triangle_vertices,
|
||||
ArrayCount(triangle_vertices),
|
||||
};
|
||||
|
||||
const Shape SQUARE = {
|
||||
square_indices,
|
||||
ArrayCount(square_indices),
|
||||
square_uv,
|
||||
ArrayCount(square_uv),
|
||||
square_xyz,
|
||||
ArrayCount(square_xyz),
|
||||
};
|
||||
|
||||
const Shape CUBE = {
|
||||
cube_indices,
|
||||
ArrayCount(cube_indices),
|
||||
triangle_vertices,
|
||||
ArrayCount(triangle_vertices),
|
||||
triangle_vertices,
|
||||
ArrayCount(triangle_vertices),
|
||||
};
|
||||
|
||||
@@ -1,15 +1,12 @@
|
||||
#ifndef LEDDA_GEOMETRY_H
|
||||
#define LEDDA_GEOMETRY_H
|
||||
|
||||
#include "stddef.h"
|
||||
#include "../common.h"
|
||||
|
||||
typedef struct {
|
||||
unsigned int* indices;
|
||||
size_t indices_size;
|
||||
float* uv;
|
||||
size_t uv_size;
|
||||
float* xyz;
|
||||
size_t xyz_size;
|
||||
UInt32List indices;
|
||||
FloatList uv;
|
||||
FloatList xyz;
|
||||
} Shape;
|
||||
|
||||
extern const Shape TRIANGLE;
|
||||
|
||||
52
src/main.c
52
src/main.c
@@ -143,7 +143,9 @@ GLFWwindow *initWindowAndGL(uint32 windowWidth, uint32 windowHeight) {
|
||||
if (!glfwInit()) {
|
||||
return NULL;
|
||||
}
|
||||
#ifdef GLFW_WAYLAND_APP_ID
|
||||
glfwWindowHintString(GLFW_WAYLAND_APP_ID, "Somaesque");
|
||||
#endif
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4);
|
||||
glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6);
|
||||
glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE);
|
||||
@@ -381,38 +383,49 @@ static void ui_Interaction(UI_Context *ui, Soma *soma) {
|
||||
}
|
||||
}
|
||||
|
||||
static void DJUI_Soma(UI_Context *ui, Soma *soma) {
|
||||
static void ui_Soma(UI_Context *ui, Soma *soma) {
|
||||
RLVector4 darkgrey = {0.2, 0.2, 0.2, 1};
|
||||
RLVector4 grey = {0.4, 0.4, 0.4, 1};
|
||||
RLVector4 lightgrey = {0.6, 0.6, 0.6, 1};
|
||||
UI_Padding btnPad = {.left=10, .right=10, .top=5, .bottom=5};
|
||||
RLVector4 blueHighlight = {0.2, 0.2, 0.7, 1};
|
||||
RLVector4 lightblueHighlight = {0.3, 0.3, 0.8, 1};
|
||||
|
||||
UI_Rect btnRect = UI_RectAttr(.padding=btnPad, .color=grey, .borderRadius=5);
|
||||
UI_Rect btnHoverRect = btnRect;
|
||||
btnHoverRect.color = lightgrey;
|
||||
|
||||
UI_Rect btnRectBlue = UI_RectAttr(.padding=btnPad, .color=blueHighlight, .borderRadius=5);
|
||||
UI_Rect btnHoverRectBlue = btnRectBlue;
|
||||
btnHoverRectBlue.color = lightblueHighlight;
|
||||
|
||||
UI(.flags=UI_Flag_HeightGrow | UI_Flag_WidthGrow) {
|
||||
UI_SetTxtAttr(.lineHeight=20, .fontSize=20);
|
||||
UI(.padding={.left=20, .right=20}, .color=darkgrey, .flags=UI_Flag_HeightGrow | UI_Flag_Vertical) {
|
||||
UI(.padding=UI_PadUniform(10)) UI_Txt(s("Somaesque"), .lineHeight=26);
|
||||
UI(.padding=UI_PadUniform(10)) UI_Txt(s("Somaesque"), .fontSize=26);
|
||||
ui_Interaction(ui, soma);
|
||||
}
|
||||
UI(.flags=UI_Flag_Vertical | UI_Flag_HeightGrow | UI_Flag_WidthGrow) {
|
||||
UI(.padding=UI_PadUniform(10), .color=darkgrey, .flags=UI_Flag_WidthGrow) {
|
||||
UI(.childGap=10) {
|
||||
if (ui_Button(ui, UI_RectAttr(.padding=btnPad, .color=grey), UI_TxtAttr(s("Previous"), .lineHeight=20))) {
|
||||
if (ui_ButtonWithHover(ui, btnRect, btnHoverRect, UI_TxtAttr(s("Previous")))) {
|
||||
advanceDisplayReverse(soma);
|
||||
}
|
||||
if (ui_Button(ui, UI_RectAttr(.padding=btnPad, .color=grey), UI_TxtAttr(s("Next"), .lineHeight=20))) {
|
||||
|
||||
if (ui_ButtonWithHover(ui, btnRect, btnHoverRect, UI_TxtAttr(s("Next")))) {
|
||||
advanceDisplay(soma);
|
||||
}
|
||||
}
|
||||
UI(.flags=UI_Flag_WidthGrow);
|
||||
UI(.childGap=10) {
|
||||
if (ui_Button(ui, UI_RectAttr(
|
||||
.padding=btnPad,
|
||||
.color=soma->state.displayingSolutions ? grey : (RLVector4){0.2, 0.2, 0.7, 1},
|
||||
), UI_TxtAttr(s("Design"), .lineHeight=20))) {
|
||||
UI_Rect *rect = soma->state.displayingSolutions ? &btnRect : &btnRectBlue;
|
||||
UI_Rect *hoverRect = soma->state.displayingSolutions ? &btnHoverRect : &btnHoverRectBlue;
|
||||
if (ui_ButtonWithHover(ui, *rect, *hoverRect, UI_TxtAttr(s("Design")))) {
|
||||
soma->state.displayingSolutions = false;
|
||||
}
|
||||
if (ui_Button(ui, UI_RectAttr(
|
||||
.padding=btnPad,
|
||||
.color=soma->state.displayingSolutions ? (RLVector4){0.2, 0.2, 0.7, 1} : grey,
|
||||
), UI_TxtAttr(s("Solve"), .lineHeight=20))) {
|
||||
rect = soma->state.displayingSolutions ? &btnRectBlue : &btnRect;
|
||||
hoverRect = soma->state.displayingSolutions ? &btnHoverRectBlue : &btnHoverRect;
|
||||
if (ui_ButtonWithHover(ui, *rect, *hoverRect, UI_TxtAttr(s("Solve")))) {
|
||||
if (!soma->state.displayingSolutions) {
|
||||
tryScheduleSolve(soma);
|
||||
} else {
|
||||
@@ -422,18 +435,19 @@ static void DJUI_Soma(UI_Context *ui, Soma *soma) {
|
||||
}
|
||||
}
|
||||
UI(.flags=UI_Flag_Vertical | UI_Flag_WidthGrow | UI_Flag_HeightGrow | UI_Flag_3DScene) {
|
||||
UI_SetTxtAttr(.fontSize=26, .alignment=UI_TxtAlign_Right);
|
||||
UI(.flags=UI_Flag_HeightGrow);
|
||||
UI(.flags=UI_Flag_WidthGrow, .padding=UI_PadUniform(10)) {
|
||||
UI(.padding=UI_PadUniform(10), .flags=UI_Flag_WidthGrow) {
|
||||
if (soma->solveTaskCtx.taskStatus == SolveTaskStatus_Solving) {
|
||||
UI_Txt(s("Solving..."), .lineHeight=26);
|
||||
UI_Txt(s("Solving..."));
|
||||
} else {
|
||||
bool soln = soma->state.displayingSolutions;
|
||||
UI_TxtSeg(soln ? s("Solution") : s("Polycube"), .lineHeight=26);
|
||||
UI_TxtSeg(
|
||||
strPrintf(ui->arena, " #%d (%d total)",
|
||||
UI_Txt(
|
||||
strPrintf(ui->arena, "%S #%d (%d total)",
|
||||
soln ? s("Solution") : s("Polycube"),
|
||||
(soln ? soma->state.displayedSolution : soma->state.displayedPolycube) + 1,
|
||||
soln ? soma->solutions.length : soma->polycubeInput.length),
|
||||
.lineHeight=26);
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -655,7 +669,7 @@ glDebugMessageCallback(glDebugCallback, NULL);
|
||||
|
||||
Render(&renderer) {
|
||||
UI_Pass(&ui) {
|
||||
DJUI_Soma(&ui, &soma);
|
||||
ui_Soma(&ui, &soma);
|
||||
}
|
||||
|
||||
if (ui.cursorIsPointer) {
|
||||
|
||||
41
src/render.c
41
src/render.c
@@ -7,14 +7,14 @@ static RenderObjects_Char createCharObjects(Arena *arena, size_t count) {
|
||||
|
||||
result.begin.buf = PushFullList(arena, RLVec2List, count);
|
||||
result.glyph.buf = PushFullList(arena, IntList, count);
|
||||
result.lineHeight.buf = PushFullList(arena, FloatList, count);
|
||||
result.fontSize.buf = PushFullList(arena, FloatList, count);
|
||||
result.color.buf = PushFullList(arena, RLVec4List, count);
|
||||
|
||||
glGenVertexArrays(1, &result.vao);
|
||||
|
||||
glGenBuffers(1, &result.begin.bufId);
|
||||
glGenBuffers(1, &result.glyph.bufId);
|
||||
glGenBuffers(1, &result.lineHeight.bufId);
|
||||
glGenBuffers(1, &result.fontSize.bufId);
|
||||
glGenBuffers(1, &result.color.bufId);
|
||||
|
||||
glBindVertexArray(result.vao);
|
||||
@@ -33,9 +33,9 @@ static RenderObjects_Char createCharObjects(Arena *arena, size_t count) {
|
||||
glVertexAttribDivisor(1, 1);
|
||||
glEnableVertexAttribArray(1);
|
||||
|
||||
bufItemSize = sizeof(result.lineHeight.buf.data[0]);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, result.lineHeight.bufId);
|
||||
glBufferData(GL_ARRAY_BUFFER, result.lineHeight.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||
bufItemSize = sizeof(result.fontSize.buf.data[0]);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, result.fontSize.bufId);
|
||||
glBufferData(GL_ARRAY_BUFFER, result.fontSize.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||
glVertexAttribPointer(2, 1, GL_FLOAT, GL_FALSE, bufItemSize, NULL);
|
||||
glVertexAttribDivisor(2, 1);
|
||||
glEnableVertexAttribArray(2);
|
||||
@@ -59,6 +59,7 @@ static RenderObjects_Rect createRectangleObjects(Arena *arena, size_t count) {
|
||||
result.color.buf = PushFullList(arena, RLVec4List, count);
|
||||
result.borderRadius.buf = PushFullList(arena, FloatList, count);
|
||||
result.borderThickness.buf = PushFullList(arena, FloatList, count);
|
||||
result.borderColor.buf = PushFullList(arena, RLVec4List, count);
|
||||
result.edgeSoftness.buf = PushFullList(arena, FloatList, count);
|
||||
|
||||
glGenVertexArrays(1, &result.vao);
|
||||
@@ -68,7 +69,7 @@ static RenderObjects_Rect createRectangleObjects(Arena *arena, size_t count) {
|
||||
glGenBuffers(1, &result.color.bufId);
|
||||
glGenBuffers(1, &result.borderRadius.bufId);
|
||||
glGenBuffers(1, &result.borderThickness.bufId);
|
||||
glGenBuffers(1, &result.edgeSoftness.bufId);
|
||||
glGenBuffers(1, &result.borderColor.bufId);
|
||||
glGenBuffers(1, &result.edgeSoftness.bufId);
|
||||
|
||||
glBindVertexArray(result.vao);
|
||||
@@ -108,12 +109,19 @@ static RenderObjects_Rect createRectangleObjects(Arena *arena, size_t count) {
|
||||
glVertexAttribDivisor(4, 1);
|
||||
glEnableVertexAttribArray(4);
|
||||
|
||||
bufItemSize = sizeof(result.borderColor.buf.data[0]);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, result.borderColor.bufId);
|
||||
glBufferData(GL_ARRAY_BUFFER, result.borderColor.buf.length * bufItemSize, 0, GL_STREAM_DRAW);
|
||||
glVertexAttribPointer(5, 4, GL_FLOAT, GL_FALSE, bufItemSize, NULL);
|
||||
glVertexAttribDivisor(5, 1);
|
||||
glEnableVertexAttribArray(5);
|
||||
|
||||
bufItemSize = sizeof(result.edgeSoftness.buf.data[0]);
|
||||
glBindBuffer(GL_ARRAY_BUFFER, result.edgeSoftness.bufId);
|
||||
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);
|
||||
glEnableVertexAttribArray(5);
|
||||
glVertexAttribPointer(6, 1, GL_FLOAT, GL_FALSE, bufItemSize, NULL);
|
||||
glVertexAttribDivisor(6, 1);
|
||||
glEnableVertexAttribArray(6);
|
||||
|
||||
return result;
|
||||
}
|
||||
@@ -126,7 +134,7 @@ 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.fontSize);
|
||||
GL_UpdateBuffer(r->chars.color);
|
||||
}
|
||||
|
||||
@@ -137,6 +145,7 @@ static void updateRectangleObjectBuffers(Renderer *r) {
|
||||
GL_UpdateBuffer(r->rects.color);
|
||||
GL_UpdateBuffer(r->rects.borderRadius);
|
||||
GL_UpdateBuffer(r->rects.borderThickness);
|
||||
GL_UpdateBuffer(r->rects.borderColor);
|
||||
GL_UpdateBuffer(r->rects.edgeSoftness);
|
||||
}
|
||||
|
||||
@@ -156,11 +165,12 @@ void renderBegin(Renderer *r) {
|
||||
r->rects.color.buf.length = 0;
|
||||
r->rects.borderRadius.buf.length = 0;
|
||||
r->rects.borderThickness.buf.length = 0;
|
||||
r->rects.borderColor.buf.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.fontSize.buf.length = 0;
|
||||
r->chars.color.buf.length = 0;
|
||||
|
||||
r->sceneWidth = 0;
|
||||
@@ -237,7 +247,7 @@ void renderEnd(Renderer *r) {
|
||||
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, RLVector4 borderColor) {
|
||||
x = roundf(x);
|
||||
y = roundf(y);
|
||||
width = roundf(width);
|
||||
@@ -247,16 +257,17 @@ void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real3
|
||||
ListAppend(r->rects.color.buf, color);
|
||||
ListAppend(r->rects.borderRadius.buf, borderRadius);
|
||||
ListAppend(r->rects.borderThickness.buf, borderThickness);
|
||||
ListAppend(r->rects.borderColor.buf, borderColor);
|
||||
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;
|
||||
void rendererPlaceString(Renderer *r, string s, real32 x, real32 y, RLVector4 color, real32 fontSize) {
|
||||
real32 ratio = fontSize / 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.fontSize.buf, ratio);
|
||||
ListAppend(r->chars.color.buf, (color));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@ struct RenderObjects_Rect {
|
||||
RenderObject_BufferVec4 color;
|
||||
RenderObject_BufferFloat borderRadius;
|
||||
RenderObject_BufferFloat borderThickness;
|
||||
RenderObject_BufferVec4 borderColor;
|
||||
RenderObject_BufferFloat edgeSoftness;
|
||||
};
|
||||
|
||||
@@ -50,7 +51,7 @@ struct RenderObjects_Char {
|
||||
uint64 count;
|
||||
RenderObject_BufferVec2 begin;
|
||||
RenderObject_BufferInt32 glyph;
|
||||
RenderObject_BufferFloat lineHeight;
|
||||
RenderObject_BufferFloat fontSize;
|
||||
RenderObject_BufferVec4 color;
|
||||
};
|
||||
|
||||
@@ -91,7 +92,7 @@ struct Renderer {
|
||||
Renderer createRenderer(Arena *arena, Scene *scene, Camera *cam, int32 light);
|
||||
void renderBegin(Renderer *r);
|
||||
void renderEnd(Renderer *r);
|
||||
void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, RLVector4 color, real32 borderRadius, real32 borderThickness);
|
||||
void rendererPlaceRectangle(Renderer *r, real32 x, real32 y, real32 width, real32 height, RLVector4 color, real32 borderRadius, real32 borderThickness, RLVector4 borderColor);
|
||||
void rendererPlaceString(Renderer *r, string s, real32 x, real32 y, RLVector4 color, real32 fontSize);
|
||||
#define Render(r) DeferLoop(renderBegin((r)), renderEnd((r)))
|
||||
|
||||
|
||||
121
src/ui.c
121
src/ui.c
@@ -52,24 +52,50 @@ UI_Context ui_initContext(Arena *arena, Renderer *renderer) {
|
||||
.arena=arena,
|
||||
.rects=list,
|
||||
.prevRects=prevList,
|
||||
.hotNode = 0,
|
||||
.cursorIsPointer = false,
|
||||
.input = NULL,
|
||||
.prevInput = NULL,
|
||||
.renderer = renderer,
|
||||
.hotNode=0,
|
||||
.prevHotNode=0,
|
||||
.cursorIsPointer=false,
|
||||
.scene3DHandle=0,
|
||||
.input=NULL,
|
||||
.prevInput=NULL,
|
||||
.renderer=renderer,
|
||||
};
|
||||
}
|
||||
|
||||
void ui_placeText(UI_Context *ui, UI_RectStr strData) {
|
||||
UI_Rect *currRect = &ui->rects.data[ui->currRect];
|
||||
UI_RectStr *strDataCopy = PushStruct(ui->arena, UI_RectStr);
|
||||
*strDataCopy = strData;
|
||||
if (strDataCopy->lineHeight == -1) {
|
||||
strDataCopy->lineHeight = ui->renderer->activeFont->lineHeight;
|
||||
if (strDataCopy->fontSize == -1) {
|
||||
strDataCopy->fontSize = currRect->inheritedTextAttr->fontSize;
|
||||
if (strDataCopy->fontSize == -1) {
|
||||
strDataCopy->fontSize = ui->renderer->activeFont->lineHeight;
|
||||
}
|
||||
}
|
||||
if (strDataCopy->lineHeight == -1) {
|
||||
strDataCopy->lineHeight = currRect->inheritedTextAttr->lineHeight;
|
||||
if (strDataCopy->lineHeight == -1) {
|
||||
strDataCopy->lineHeight = strDataCopy->fontSize;
|
||||
}
|
||||
if (strDataCopy->fontSize > strDataCopy->lineHeight) {
|
||||
strDataCopy->lineHeight = strDataCopy->fontSize;
|
||||
}
|
||||
}
|
||||
if (strDataCopy->alignment < 0) {
|
||||
if (currRect->inheritedTextAttr) {
|
||||
strDataCopy->alignment = currRect->inheritedTextAttr->alignment;
|
||||
} else {
|
||||
strDataCopy->alignment = 0;
|
||||
}
|
||||
}
|
||||
currRect->inheritedTextAttr = strDataCopy;
|
||||
if (strData.s.str != NULL) {
|
||||
strDataCopy->s = PushString(ui->arena, strData.s.length);
|
||||
memcpy(strDataCopy->s.str, strData.s.str, strData.s.length);
|
||||
currRect->stringData = strDataCopy;
|
||||
} else {
|
||||
// NOTE(djledda): Not real text data if empty string -> just style attributes. Ignore
|
||||
}
|
||||
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) {
|
||||
@@ -203,17 +229,28 @@ void ui_end(UI_Context *ui) {
|
||||
rect->resolvedHeight,
|
||||
rect->color,
|
||||
rect->borderRadius,
|
||||
rect->borderThickness
|
||||
rect->borderThickness,
|
||||
rect->borderColor
|
||||
);
|
||||
if (rect->stringData) {
|
||||
UI_RectStr *str = rect->stringData;
|
||||
real32 alignmentXOffset = 0;
|
||||
real32 alignmentYOffset = rect->padding.top;
|
||||
real32 textWidth = str->s.length * str->fontSize / ui->renderer->activeFont->lineHeight * ui->renderer->activeFont->charWidth;
|
||||
if (str->alignment & UI_TxtAlign_Right) {
|
||||
alignmentXOffset = rect->resolvedWidth - rect->padding.right - textWidth;
|
||||
} else if (str->alignment & UI_TxtAlign_Center) {
|
||||
alignmentXOffset = rect->resolvedWidth/2.0 - textWidth/2.0;
|
||||
} else {
|
||||
alignmentXOffset = rect->padding.left;
|
||||
}
|
||||
rendererPlaceString(
|
||||
ui->renderer,
|
||||
str->s,
|
||||
rect->x + str->xOffset + rect->padding.left,
|
||||
rect->y + str->yOffset + rect->padding.top,
|
||||
rect->x + alignmentXOffset + str->xOffset,
|
||||
rect->y + alignmentYOffset + str->yOffset,
|
||||
str->color,
|
||||
str->lineHeight
|
||||
str->fontSize
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -257,6 +294,15 @@ void ui_openElement(UI_Context *ui, UI_Rect rect) {
|
||||
if (newRect->flags & UI_Flag_3DScene) {
|
||||
ui->scene3DHandle = newHandle;
|
||||
}
|
||||
|
||||
if (currRect->stringData) {
|
||||
UI_RectStr *inheritedTextAttr = PushStructZero(ui->arena, UI_RectStr);
|
||||
*inheritedTextAttr = *currRect->stringData;
|
||||
inheritedTextAttr->s = s("");
|
||||
newRect->inheritedTextAttr = inheritedTextAttr;
|
||||
} else {
|
||||
newRect->inheritedTextAttr = currRect->inheritedTextAttr;
|
||||
}
|
||||
}
|
||||
|
||||
void ui_closeElement(UI_Context *ui) {
|
||||
@@ -267,7 +313,7 @@ void ui_closeElement(UI_Context *ui) {
|
||||
currRect->resolvedWidth = currRect->width;
|
||||
} else if (currRect->minWidth == -1) {
|
||||
if (currRect->stringData) {
|
||||
real32 charWidth = currRect->stringData->lineHeight / ui->renderer->activeFont->lineHeight * ui->renderer->activeFont->charWidth;
|
||||
real32 charWidth = currRect->stringData->fontSize / ui->renderer->activeFont->lineHeight * ui->renderer->activeFont->charWidth;
|
||||
currRect->minWidth = charWidth*currRect->stringData->s.length;
|
||||
} else {
|
||||
currRect->minWidth = 0;
|
||||
@@ -318,11 +364,15 @@ void ui_closeElement(UI_Context *ui) {
|
||||
ui->currRect = ui->rects.data[ui->currRect].parent;
|
||||
}
|
||||
|
||||
bool ui_Button(UI_Context *ui, UI_Rect rect, UI_RectStr textAttr) {
|
||||
/**
|
||||
* Returns whether the checkbox was clicked
|
||||
*/
|
||||
bool ui_ButtonWithHover(UI_Context *ui, UI_Rect rect, UI_Rect hovered, UI_RectStr textAttr) {
|
||||
int32 id = UI_NextID();
|
||||
bool clicked = false;
|
||||
|
||||
if (pointInRect(ui->input->mouse.point.x, ui->input->mouse.point.y, ui->prevRects.data[id])) {
|
||||
bool inRect = pointInRect(ui->input->mouse.point.x, ui->input->mouse.point.y, ui->prevRects.data[id]);
|
||||
if (inRect) {
|
||||
ui->cursorIsPointer = true;
|
||||
if (ui->prevHotNode == id && !ui->input->mouse.btnLeft) {
|
||||
clicked = true;
|
||||
@@ -331,21 +381,32 @@ bool ui_Button(UI_Context *ui, UI_Rect rect, UI_RectStr textAttr) {
|
||||
}
|
||||
}
|
||||
|
||||
rect.borderRadius = 5;
|
||||
UI_FromRect(rect) {
|
||||
ui_placeText(ui, textAttr);
|
||||
bool useHover = inRect && !(hovered.flags & UI_Flag_Ignore);
|
||||
UI_Rect *rectToRender = useHover ? &hovered : ▭
|
||||
if (rectToRender->borderRadius == -1) {
|
||||
rectToRender->borderRadius = 5;
|
||||
}
|
||||
|
||||
UI_FromRect(*rectToRender) ui_placeText(ui, textAttr);
|
||||
|
||||
return clicked;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the checkbox was clicked
|
||||
*/
|
||||
bool ui_Button(UI_Context *ui, UI_Rect rect, UI_RectStr textAttr) {
|
||||
return ui_ButtonWithHover(ui, rect, UI_RectAttr(.flags=UI_Flag_Ignore), textAttr);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the checkbox was clicked
|
||||
*/
|
||||
bool ui_CheckboxRect(UI_Context *ui, bool *value, UI_Rect rect) {
|
||||
int32 id = UI_NextID();
|
||||
bool clicked = false;
|
||||
if (pointInRect(ui->input->mouse.point.x, ui->input->mouse.point.y, ui->prevRects.data[id])) {
|
||||
bool pointerInRect = pointInRect(ui->input->mouse.point.x, ui->input->mouse.point.y, ui->prevRects.data[id]);
|
||||
if (pointerInRect) {
|
||||
ui->cursorIsPointer = true;
|
||||
if (ui->prevHotNode == id && !ui->input->mouse.btnLeft) {
|
||||
*value = !*value;
|
||||
@@ -357,11 +418,25 @@ bool ui_CheckboxRect(UI_Context *ui, bool *value, UI_Rect rect) {
|
||||
if (*value) {
|
||||
rect.borderRadius = 5;
|
||||
rect.borderThickness = 0;
|
||||
if (pointerInRect) {
|
||||
rect.color.x += 0.5;
|
||||
rect.color.y += 0.5;
|
||||
rect.color.z += 0.5;
|
||||
rect.color.x = rect.color.x <= 1.0 ? rect.color.x : 1.0;
|
||||
rect.color.y = rect.color.y <= 1.0 ? rect.color.y : 1.0;
|
||||
rect.color.z = rect.color.z <= 1.0 ? rect.color.z : 1.0;
|
||||
}
|
||||
UI_FromRect(rect);
|
||||
} else {
|
||||
rect.borderRadius = 5;
|
||||
rect.borderThickness = 2;
|
||||
rect.color = COLOR_WHITE;
|
||||
rect.borderColor = COLOR_WHITE;
|
||||
if (pointerInRect) {
|
||||
rect.color = COLOR_WHITE;
|
||||
rect.color.w = 0.2;
|
||||
} else {
|
||||
rect.color = (RLVector4){0,0,0,0};
|
||||
}
|
||||
UI_FromRect(rect);
|
||||
}
|
||||
|
||||
|
||||
60
src/ui.h
60
src/ui.h
@@ -42,8 +42,7 @@ enum UI_Flag {
|
||||
UI_Flag_Vertical=1<<2, // Default is horizontal
|
||||
UI_Flag_3DScene=1<<3,
|
||||
UI_Flag_Center=1<<4,
|
||||
UI_Flag_Textalign_Right=1<<5, // Default is left
|
||||
UI_Flag_Textalign_Center=1<<6,
|
||||
UI_Flag_Ignore=1<<7, // For optional parameters
|
||||
// ..
|
||||
UI_Flag_COUNT,
|
||||
};
|
||||
@@ -56,19 +55,25 @@ struct UI_Padding {
|
||||
real32 left;
|
||||
};
|
||||
|
||||
enum UI_TxtAlign {
|
||||
UI_TxtAlign_Left=1<<0, // Default
|
||||
UI_TxtAlign_Center=1<<1,
|
||||
UI_TxtAlign_Right=1<<2,
|
||||
};
|
||||
|
||||
typedef struct UI_RectStr UI_RectStr;
|
||||
struct UI_RectStr {
|
||||
string s;
|
||||
real32 xOffset;
|
||||
real32 yOffset;
|
||||
real32 lineHeight;
|
||||
real32 fontSize;
|
||||
RLVector4 color;
|
||||
int8 alignment;
|
||||
enum UI_TxtAlign alignment;
|
||||
};
|
||||
|
||||
typedef struct UI_Rect UI_Rect;
|
||||
struct UI_Rect {
|
||||
/** UI_Rect_LayoutFlag */
|
||||
enum UI_Flag flags;
|
||||
|
||||
int32 parent;
|
||||
@@ -102,6 +107,13 @@ struct UI_Rect {
|
||||
real32 resolvedHeight;
|
||||
|
||||
UI_RectStr *stringData;
|
||||
/**
|
||||
* Inherited from parent to propagate attributes. Actual string is ignored, only used for filling out defaults in
|
||||
* the next stringData pointer that is set.
|
||||
* This pointer is always set, as the global UI context will set it on the root not if it does not present its own
|
||||
* text data.
|
||||
*/
|
||||
UI_RectStr *inheritedTextAttr;
|
||||
};
|
||||
DefineList(UI_Rect, UI_Rect);
|
||||
|
||||
@@ -135,23 +147,47 @@ void ui_openElement(UI_Context *ui, UI_Rect rect);
|
||||
void ui_closeElement(UI_Context *ui);
|
||||
|
||||
bool ui_CheckboxRect(UI_Context *ui, bool *value, UI_Rect rect);
|
||||
bool ui_Button(UI_Context *ui, UI_Rect rect, UI_RectStr textAttr);
|
||||
bool ui_ButtonWithHover(UI_Context *ui, UI_Rect rect, UI_Rect hovered, UI_RectStr textAttr);
|
||||
|
||||
extern UI_Context *__UI_current_ctx__;
|
||||
|
||||
#if 0
|
||||
#define UI_WIREFRAME .color=COLOR_RED, .borderThickness=1,
|
||||
#define UI_DEBUG .borderColor=COLOR_RED, .borderThickness=1,
|
||||
#else
|
||||
#define UI_WIREFRAME
|
||||
#define UI_DEBUG
|
||||
#endif
|
||||
|
||||
#define UI(...) DeferLoop(ui_openElement((__UI_current_ctx__), UI_RectAttr(__VA_ARGS__)), ui_closeElement((__UI_current_ctx__)))
|
||||
#define UI_RectAttr(...) ((UI_Rect){UI_WIREFRAME .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_PadUniform(padding) ((UI_Padding){ (padding), (padding), (padding), (padding) })
|
||||
#define UI_NextID() ((__UI_current_ctx__)->rects.length)
|
||||
#define UI_Txt(str, ...) (ui_placeText((__UI_current_ctx__), ((UI_RectStr){ .xOffset=0, .yOffset=0, .lineHeight=-1, .s=(str), __VA_ARGS__ })))
|
||||
#define UI_TxtSeg(str, ...) UI() (UI_Txt((str), __VA_ARGS__))
|
||||
#define UI_TxtAttr(str, ...) ((UI_RectStr){ .xOffset=0, .yOffset=0, .lineHeight=-1, .s=(str), __VA_ARGS__ })
|
||||
|
||||
#define UI(...)\
|
||||
/** Place a UI_Rect defined in-place in the current position in the UI tree */\
|
||||
DeferLoop(ui_openElement((__UI_current_ctx__), UI_RectAttr(__VA_ARGS__)), ui_closeElement((__UI_current_ctx__)))
|
||||
|
||||
#define UI_RectAttr(...)\
|
||||
/** Generate a UI_Rect to be passed as a value */\
|
||||
((UI_Rect){UI_DEBUG .minHeight=-1, .minWidth=-1, .width=-1, .height=-1, __VA_ARGS__})
|
||||
|
||||
#define UI_FromRect(rect)\
|
||||
/** Place a UI_Rect in the current position in the UI tree, as defined by an existing value */\
|
||||
DeferLoop(ui_openElement((__UI_current_ctx__), (rect)), ui_closeElement((__UI_current_ctx__)))
|
||||
|
||||
#define UI_TxtAttr(str, ...)\
|
||||
/** Generate UI text to be used as a value */\
|
||||
((UI_RectStr){ .alignment=-1, .xOffset=0, .yOffset=0, .fontSize=-1, .lineHeight=-1, .s=(str), __VA_ARGS__ })
|
||||
|
||||
#define UI_Txt(str, ...)\
|
||||
/** Place UI text in the current position in the UI tree. Attaches to the current UI_Rect */\
|
||||
(ui_placeText((__UI_current_ctx__), (UI_TxtAttr(str, __VA_ARGS__))))
|
||||
|
||||
#define UI_SetTxtAttr(...)\
|
||||
/** Attach "phantom" text to the current rect in order to set its heritable attributes for subsequent text in the UI subtrees */\
|
||||
(ui_placeText((__UI_current_ctx__), (UI_TxtAttr(((string){.str=NULL,.length=0}), __VA_ARGS__))))
|
||||
|
||||
#define UI_TxtSeg(str, ...)\
|
||||
/** Place a text fragment in its own box (useful for placing many text fragments in a row */\
|
||||
UI() (UI_Txt((str), __VA_ARGS__))
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user