From 3d8041556403c2c9fc28a2c27a0676e36fde83be Mon Sep 17 00:00:00 2001 From: IllusionMan1212 Date: Sun, 26 Nov 2023 05:34:42 +0200 Subject: [PATCH] refactor: grid and timer using zephr --- cudoku.c | 182 ++++++++++++++++++++++++++------------------ cudoku.h | 3 +- main.c | 85 +++------------------ shaders/grid_f.frag | 51 ------------- shaders/quad.frag | 8 -- todo.txt | 15 ++++ ui.c | 6 +- 7 files changed, 141 insertions(+), 209 deletions(-) delete mode 100644 shaders/grid_f.frag delete mode 100644 shaders/quad.frag diff --git a/cudoku.c b/cudoku.c index 8821a09..5a0ca7f 100644 --- a/cudoku.c +++ b/cudoku.c @@ -74,15 +74,37 @@ void draw_win(Cudoku *game) { draw_text(time_text, 48.f, constraints, &text_color, ALIGN_CENTER); } -void set_scale_factor(int width, int height, float *x, float *y) { - if (width > height) { - float ratio = (float)height / (float)width; - *x = ratio; - *y = 1.f; - } else { - float ratio = (float)width / (float)height; - *x = 1.f; - *y = ratio; +void draw_grid(Size window_size) { + Color bg_color = {240.0f, 235.0f, 227.0f, 255.f}; + Color color = {0.0f, 0.0f, 0.0f, 255.f}; + UIConstraints constraints = {0}; + set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); + set_y_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); + set_width_constraint(&constraints, window_size.width, UI_CONSTRAINT_FIXED); + set_height_constraint(&constraints, window_size.height, UI_CONSTRAINT_FIXED); + + draw_quad(constraints, &bg_color, 0.0, ALIGN_TOP_LEFT); + + for (int i = 1; i < 10; i++) { + set_x_constraint(&constraints, i * 100, UI_CONSTRAINT_FIXED); + set_y_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); + if (i % 3 == 0) { + set_width_constraint(&constraints, 4, UI_CONSTRAINT_FIXED); + } else { + set_width_constraint(&constraints, 2, UI_CONSTRAINT_FIXED); + } + set_height_constraint(&constraints, window_size.height, UI_CONSTRAINT_FIXED); + draw_quad(constraints, &color, 0.0, ALIGN_TOP_LEFT); + + set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); + set_y_constraint(&constraints, i * 100, UI_CONSTRAINT_FIXED); + set_width_constraint(&constraints, window_size.width, UI_CONSTRAINT_FIXED); + if (i % 3 == 0) { + set_height_constraint(&constraints, 4, UI_CONSTRAINT_FIXED); + } else { + set_height_constraint(&constraints, 2, UI_CONSTRAINT_FIXED); + } + draw_quad(constraints, &color, 0.0, ALIGN_TOP_LEFT); } } @@ -617,82 +639,96 @@ void draw_ui_element_at(Shader shader, unsigned int vao, unsigned int vbo, Matri glBindVertexArray(0); } -void draw_help_overlay(Shader overlay_shader, Shader font_shader, unsigned int overlay_vao, unsigned int overlay_vbo, unsigned int font_vao, unsigned int font_vbo, Matrix4x4 *projection, int window_height, Timer *timer) { - int total_help_texts_height = 20; +/* void draw_help_overlay(Timer *timer) { */ +/* int total_help_texts_height = 20; */ - int const text_padding = 10; - float const text_scale = 0.3f; - int overlay_height = 0; - int overlay_width = 0; +/* int const text_padding = 10; */ +/* float const text_scale = 0.3f; */ +/* int overlay_height = 0; */ +/* int overlay_width = 0; */ - for (int i = 0; i < HELP_TEXT_SIZE; i++) { - /* Size text_size = calculate_text_size(help_texts[i], text_scale); */ - /* overlay_height += text_size.height + text_padding; */ - /* overlay_width = max(overlay_width, text_size.width + text_padding * 2); */ - } - Size size = {.width = overlay_width, .height = overlay_height + text_padding * 2}; - Vec2 pos = { - .x = 0, - .y = window_height - size.height - }; - Color color = { - .r = 0.1f, - .g = 0.1f, - .b = 0.1f, - .a = 0.95f - }; - draw_ui_element_at(overlay_shader, overlay_vao, overlay_vbo, projection, pos, size, color); +/* for (int i = 0; i < HELP_TEXT_SIZE; i++) { */ +/* /1* Size text_size = calculate_text_size(help_texts[i], text_scale); *1/ */ +/* /1* overlay_height += text_size.height + text_padding; *1/ */ +/* /1* overlay_width = max(overlay_width, text_size.width + text_padding * 2); *1/ */ +/* } */ +/* Size size = {.width = overlay_width, .height = overlay_height + text_padding * 2}; */ +/* /1* Vec2 pos = { *1/ */ +/* /1* .x = 0, *1/ */ +/* /1* .y = window_height - size.height *1/ */ +/* /1* }; *1/ */ +/* Color color = { */ +/* .r = 0.1f, */ +/* .g = 0.1f, */ +/* .b = 0.1f, */ +/* .a = 0.95f */ +/* }; */ +/* /1* draw_ui_element_at(overlay_shader, overlay_vao, overlay_vbo, projection, pos, size, color); *1/ */ - for (int i = 0; i < HELP_TEXT_SIZE; i++) { - /* Size text_size = calculate_text_size(help_texts[i], text_scale); */ - /* Vec2 text_pos = { */ - /* .x = text_padding, */ - /* .y = window_height - total_help_texts_height - (text_padding * 2) */ - /* }; */ - /* total_help_texts_height += text_size.height + text_padding; */ - /* draw_text_at(font_shader, help_texts[i], text_pos, text_scale, font_vao, font_vbo, (float *)projection->m, NULL); */ - } +/* for (int i = 0; i < HELP_TEXT_SIZE; i++) { */ +/* /1* Size text_size = calculate_text_size(help_texts[i], text_scale); *1/ */ +/* /1* Vec2 text_pos = { *1/ */ +/* /1* .x = text_padding, *1/ */ +/* /1* .y = window_height - total_help_texts_height - (text_padding * 2) *1/ */ +/* /1* }; *1/ */ +/* /1* total_help_texts_height += text_size.height + text_padding; *1/ */ +/* /1* draw_text_at(font_shader, help_texts[i], text_pos, text_scale, font_vao, font_vbo, (float *)projection->m, NULL); *1/ */ +/* } */ - if (timer->is_running) { - char closing_in_text[128]; - /* snprintf(closing_in_text, sizeof(closing_in_text), "Hiding in %ds", (int)timer_remaining(timer) + 1); */ - /* Size closing_in_text_size = calculate_text_size(closing_in_text, text_scale / 2.0); */ - /* Vec2 closing_in_text_pos = { */ - /* .x = overlay_width - closing_in_text_size.width, */ - /* .y = window_height - closing_in_text_size.height - text_padding, */ - /* }; */ - /* Color closing_in_text_color = { */ - /* .r = 255.0f, */ - /* .g = 150.0f, */ - /* .b = 0.0f, */ - /* .a = 1.0f, */ - /* }; */ - /* draw_text_at(font_shader, closing_in_text, closing_in_text_pos, text_scale / 2.0, font_vao, font_vbo, (float *)projection->m, &closing_in_text_color); */ - } -} +/* if (timer->is_running) { */ +/* char closing_in_text[128]; */ +/* /1* snprintf(closing_in_text, sizeof(closing_in_text), "Hiding in %ds", (int)timer_remaining(timer) + 1); *1/ */ +/* /1* Size closing_in_text_size = calculate_text_size(closing_in_text, text_scale / 2.0); *1/ */ +/* /1* Vec2 closing_in_text_pos = { *1/ */ +/* /1* .x = overlay_width - closing_in_text_size.width, *1/ */ +/* /1* .y = window_height - closing_in_text_size.height - text_padding, *1/ */ +/* /1* }; *1/ */ +/* /1* Color closing_in_text_color = { *1/ */ +/* /1* .r = 255.0f, *1/ */ +/* /1* .g = 150.0f, *1/ */ +/* /1* .b = 0.0f, *1/ */ +/* /1* .a = 1.0f, *1/ */ +/* /1* }; *1/ */ +/* /1* draw_text_at(font_shader, closing_in_text, closing_in_text_pos, text_scale / 2.0, font_vao, font_vbo, (float *)projection->m, &closing_in_text_color); *1/ */ +/* } */ +/* } */ -void draw_timer(Shader shader, unsigned int vao, unsigned int vbo, float *projection, Timer *timer, int win_width) { +void draw_timer(Timer *timer) { if (!timer->is_running) return; char timer_text[64]; + Color text_color = { + .r = 66.0f, + .g = 92.0f, + .b = 124.0f, + .a = 255.0f, + }; + Color bg_color = { + .r = 0.0f, + .g = 0.0f, + .b = 0.0f, + .a = 25.0f, + }; + float font_size = 32.f; + Alignment alignment = ALIGN_BOTTOM_RIGHT; float elapsed = timer_elapsed(timer); int minutes = elapsed / 60; int seconds = (int)elapsed % 60; - /* snprintf(timer_text, sizeof(timer_text), "Time: %02d:%02d", minutes, seconds); */ - /* float text_scale = 0.35f; */ - /* Size text_size = calculate_text_size(timer_text, text_scale); */ - /* Vec2 text_pos = { */ - /* .x = win_width - text_size.width - 10, */ - /* .y = 10, */ - /* }; */ - /* Color text_color = { */ - /* .r = 66.0f, */ - /* .g = 92.0f, */ - /* .b = 124.0f, */ - /* .a = 1.0f, */ - /* }; */ + snprintf(timer_text, sizeof(timer_text), "Time: %02d:%02d", minutes, seconds); - /* draw_text_at(shader, timer_text, text_pos, text_scale, vao, vbo, projection, &text_color); */ + Sizef text_size = calculate_text_size(timer_text, font_size); + + UIConstraints constraints = {0}; + set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); + set_y_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); + set_width_constraint(&constraints, text_size.width + 4, UI_CONSTRAINT_FIXED); + set_height_constraint(&constraints, text_size.height + 4, UI_CONSTRAINT_FIXED); + + draw_quad(constraints, &bg_color, 0.0, alignment); + + set_width_constraint(&constraints, 1, UI_CONSTRAINT_FIXED); + set_height_constraint(&constraints, 1, UI_CONSTRAINT_FIXED); + draw_text(timer_text, font_size, constraints, &text_color, alignment); } diff --git a/cudoku.h b/cudoku.h index 575b9dd..1cdeb70 100644 --- a/cudoku.h +++ b/cudoku.h @@ -53,5 +53,6 @@ void draw_help_overlay( int window_height, Timer *timer ); -void draw_timer(Shader shader, unsigned int vao, unsigned int vbo, float *projection, Timer *timer, int win_width); +void draw_timer(Timer *timer); void draw_win(Cudoku *game); +void draw_grid(Size window_size); diff --git a/main.c b/main.c index 2787035..54b0397 100644 --- a/main.c +++ b/main.c @@ -88,10 +88,6 @@ void handle_keypress(XEvent xev, Cudoku *game) { int main(int argc, char *argv[]) { bool use_texture = false; - // scale factors for the entire board to nicely fit as a square inside - // the window - float x_scale = 1.f, y_scale = 1.f; - if (argc > 1) { char *flag = argv[1]; if (strcmp(flag, "-h") == 0 || strcmp(flag, "--help") == 0) { @@ -121,8 +117,9 @@ int main(int argc, char *argv[]) { } } - Color clear_color = {0.2f, 0.15f, 0.5f, 1.f}; - int res = init_zephr(font_path, title, (Size){900, 900}, &clear_color); + Color clear_color = {0.0f, 0.0f, 0.0f, 1.f}; + Size window_size = {900, 900}; + int res = init_zephr(font_path, title, window_size, &clear_color); if (res != 0) { printf("[ERROR]: could not initialize zephr\n"); return 1; @@ -136,21 +133,14 @@ int main(int argc, char *argv[]) { generate_random_board(&game); Shader grid_shader; - unsigned int grid_texture; - if (!use_texture) - grid_shader = create_shader("shaders/board_v.vert", "shaders/grid_f.frag"); - else + if (use_texture) grid_shader = create_shader("shaders/board_v.vert", "shaders/board_f.frag"); - int board_vao = prepare_bg(use_texture, &grid_texture); - - Shader selection_shader = create_shader("shaders/board_v.vert", "shaders/quad.frag"); + /* Shader selection_shader = create_shader("shaders/board_v.vert", "shaders/quad.frag"); */ unsigned int selection_vao, selection_vbo; Color selection_color = {0.4f, 0.4f, 1.0f, 0.5f}; prepare_selection_box(&selection_vao, &selection_vbo); - Shader win_shader = create_shader("shaders/board_v.vert", "shaders/quad.frag"); - float delta_t, last_t = 0.0; timer_start(&game.help_timer, 5.0f); timer_start(&game.timer, 0.0f); @@ -160,49 +150,15 @@ int main(int argc, char *argv[]) { delta_t = now - last_t; last_t = now; - Size window_size = zephr_get_window_size(); - - /* int width = 15.f; */ - /* int height = 35.f; */ - /* int padding = 10.f; */ - - float ratio_w = (float)window_size.width / 1920.f; - float ratio_h = (float)window_size.height / 1080.f; - - int width = window_size.height; - int height = window_size.width; - - if (window_size.height > window_size.width) { - width = window_size.width; - height = window_size.width; - } else { - width = window_size.height; - height = window_size.height; + if (!use_texture) { + draw_grid(window_size); } - draw_win(&game); - - /* draw_quad( */ - /* (Vec2){0.0, 0.0}, */ - /* (Size){width, height}, */ - /* &(Color){240.f, 235.f, 227.f, 255.f}, */ - /* ALIGN_CENTER); */ - /* UIConstraints constraints = {0}; */ - /* set_x_constraint(&constraints, 0.0, UI_CONSTRAINT_FIXED); */ - /* set_y_constraint(&constraints, 0.0, UI_CONSTRAINT_FIXED); */ - /* set_width_constraint(&constraints, 50, UI_CONSTRAINT_FIXED); */ - /* set_height_constraint(&constraints, 50, UI_CONSTRAINT_FIXED); */ - - /* draw_quad( */ - /* constraints, */ - /* &(Color){240.f, 235.f, 227.f, 255.f}, */ - /* ALIGN_TOP_LEFT */ - /* ); */ - - /* Size size = calculate_text_size("Bruh", 1.0f); */ - /* float x = clampf(500.0f * timer_elapsed(&my_time), 0.0, window_size.width - size.width); */ - /* draw_text("Bruh", 1.0f, (Vec2){0.0, size.height}, &(Color){255.f, 0.f, 0.f, 255.f}); */ + draw_timer(&game.timer); + if (game.has_won) { + draw_win(&game); + } zephr_batch_text_draw(); zephr_swap_buffers(); @@ -240,18 +196,7 @@ int main(int argc, char *argv[]) { /* /1* } *1/ */ /* /1* } *1/ */ - /* float transform[4][4] = { */ - /* {x_scale, 0, 0, 0}, */ - /* {0, y_scale, 0, 0}, */ - /* {0, 0, 1, 0}, */ - /* {0, 0, 0, 1}, */ - /* }; */ - - /* /1* Matrix4x4 projection = orthographic_projection_2d(0.0f, width, 0.0f, height); *1/ */ - - /* /1* if (!use_texture) *1/ */ - /* /1* draw_bg_grid_shader(grid_shader, board_vao, (float *)transform, width < height ? width : height); *1/ */ - /* /1* else *1/ */ + /* /1* if (use_texture) *1/ */ /* /1* draw_bg_grid_texture(grid_shader, board_vao, grid_texture, (float *)transform); *1/ */ /* if (game.should_draw_selection) */ @@ -277,8 +222,6 @@ int main(int argc, char *argv[]) { /* /1* draw_text_at(font_shader, text, text_pos, text_scale, font_vao, font_vbo, (float *)projection.m, &text_color); *1/ */ /* /1* } *1/ */ - /* /1* draw_timer(font_shader, font_vao, font_vbo, (float *)projection.m, &game.timer, width); *1/ */ - /* if (timer_ended(&game.help_timer)) { */ /* timer_stop(&game.help_timer); */ /* game.should_draw_help = false; */ @@ -287,10 +230,6 @@ int main(int argc, char *argv[]) { /* /1* if (game.should_draw_help) *1/ */ /* /1* draw_help_overlay(selection_shader, font_shader, selection_vao, selection_vbo, font_vao, font_vbo, &projection, height, &game.help_timer); *1/ */ - /* /1* if (game.has_won) { *1/ */ - /* /1* draw_win_overlay(win_shader, font_shader, win_vao, font_vao, font_vbo, (float *)transform, &game); *1/ */ - /* /1* } *1/ */ - /* /1* glXSwapBuffers(display, window); *1/ */ /* } */ diff --git a/shaders/grid_f.frag b/shaders/grid_f.frag deleted file mode 100644 index 4475bd7..0000000 --- a/shaders/grid_f.frag +++ /dev/null @@ -1,51 +0,0 @@ -#version 330 core - -out vec4 FragColor; - -uniform mat4 transform; -uniform float resolution; - -void main() -{ - // Define the size of the grid - int gridSize = 9; - - // Calculate the step size for the grid lines - float stepSize = 2.0 / float(gridSize); - - // Calculate the UV coordinates of the current fragment - vec2 uv = (gl_FragCoord * transform).xy / vec2(resolution, resolution); // Adjust the resolution as needed - float scale_x = transform[0][0]; - float scale_y = transform[1][1]; - - // Calculate the coordinates of the current fragment in the [-1, 1] range - float fragCoordX = (uv.x - 0.5) * (2.0 / scale_x) - 1.0; - float fragCoordY = (uv.y - 0.5) * (2.0 / scale_y) - 1.0; - - // Colors for grid lines - vec3 gridColor = vec3(0.4, 0.4, 0.4); - vec3 gridColorThick = vec3(0.2, 0.2, 0.2); - - bool isInsideGridHorizontally = (fragCoordX >= -2.0 && fragCoordX <= 0.0); - bool isInsideGridVertically = (fragCoordY >= -2.0 && fragCoordY <= 0.0); - bool isInsideGrid = isInsideGridHorizontally && isInsideGridVertically; - - // Determine if the current fragment is on a thicker grid line - bool isThickLineX = isInsideGrid && mod(fragCoordX, (stepSize + 0.0007) * 3) <= 0.01; - bool isThickLineY = isInsideGrid && mod(fragCoordY, (stepSize + 0.0007) * 3) <= 0.01; - - // Check if the current fragment is on a grid line - // 0.0007 to shift the grid lines a bit to the left - bool isGridX = isInsideGrid && mod(fragCoordX, stepSize + 0.0007) <= 0.005; - bool isGridY = isInsideGrid && mod(fragCoordY, stepSize + 0.0007) <= 0.005; - - // Set the fragment color based on whether it's a grid line or a thicker grid line - if ((isThickLineX) || (isThickLineY)) { - FragColor = vec4(gridColorThick, 1.0); - } else if (isGridX || isGridY) { - FragColor = vec4(gridColor, 1.0); - } else { - FragColor = vec4(240.f/255.f, 235.f/255.f, 227.f/255.f, 1.0); - } -} - diff --git a/shaders/quad.frag b/shaders/quad.frag deleted file mode 100644 index e57a174..0000000 --- a/shaders/quad.frag +++ /dev/null @@ -1,8 +0,0 @@ -#version 330 core - -out vec4 FragColor; -uniform vec4 aColor; - -void main() { - FragColor = vec4(aColor); -} diff --git a/todo.txt b/todo.txt index a614d14..0e88f11 100644 --- a/todo.txt +++ b/todo.txt @@ -1,5 +1,20 @@ - "premade" (but also customizable) ui elements (buttons, text boxes, etc) with instanced rendering - border decorations for shapes (maybe. or maybe only for ui elements) +- some kind of ui layout/hierarchy system (for later, when we actually need it) +- grid texture (draw_image? or draw_texture? func) + +- sooo a bit of a problem... since we render all our text in one draw call + at the end of the frame. this means that we can't have text that's rendered + in behind anything else. This needs to be fixed because drawing any overlay + will result in all the text being drawn OVER everything else, which might not be + the desired behavior at times (e.g. help/win overlay where the board numbers need to be + rendered under the overlay(s)) + - possible solutions :Clueless: + - z-index based on the order of creation (e.g. the first drawable created has the lowest z-index) + I _think_ this works because we can just chuck a global z-index whenever we call + draw_text or draw_quad/etc.. and the shader _should_ take care of everything + - every draw_text call actually makes a single draw call (compromises on performance but way easier to use) + text rendering improvements - [ ] unicode support (allows for non-ascii characters) diff --git a/ui.c b/ui.c index 1e32930..22e4870 100644 --- a/ui.c +++ b/ui.c @@ -320,7 +320,6 @@ bool zephr_should_quit() { zephr_context.window_size = (Size){ .width = xce.width, .height = xce.height }; zephr_context.projection = orthographic_projection_2d(0.f, xce.width, xce.height, 0.f); resize_x11_window(display, window); - /* set_scale_factor(xce.width, xce.height, &x_scale, &y_scale); */ } } else if (xev.type == KeyPress) { @@ -354,8 +353,8 @@ bool zephr_should_quit() { return zephr_context.should_quit; } -// example of how to batch all text drawing in one drawcall -// this should be called at the end of the frame +/* This MUST be called at the end of the frame + if you wish to draw text */ void zephr_batch_text_draw() { glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo); glBufferData(GL_ARRAY_BUFFER, sizeof(TextInstance) * zephr_context.texts.size, zephr_context.texts.data, GL_DYNAMIC_DRAW); @@ -368,6 +367,7 @@ void zephr_batch_text_draw() { clear_text_instance_list(&zephr_context.texts); } +// This MUST be called at the end of the frame void zephr_swap_buffers() { glXSwapBuffers(display, window); }