diff --git a/cudoku.c b/cudoku.c index d3d2541..ff0e6ea 100644 --- a/cudoku.c +++ b/cudoku.c @@ -13,28 +13,15 @@ #include "text.h" #include "zephr.h" -#define HELP_TEXT_SIZE 13 +#define HELP_TEXT_SIZE 12 -static const float quad_vertices[] = { - // positions // texture coords - -1.0f, 1.0f, 0.0f, 0.0f, 1.0f, // top left - 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, // top right - -1.0f, -1.0f, 0.0f, 0.0f, 0.0f, // bottom left - 1.0f, -1.0f, 0.0f, 1.0f, 0.0f // bottom right -}; - -static const int quad_indices[] = { - 0, 1, 2, - 1, 2, 3 -}; - -static const Color mistake_color = {1.f, 0.f, 0.f, 0.5f}; +static const Color mistake_color = {255.f, 0.f, 0.f, 127}; +static const Color selection_color = {102, 102, 255, 255}; static const char *win_text = "You won!"; static const char *help_texts[HELP_TEXT_SIZE] = { "F1 - Toggle help", - "F11 - Toggle fullscreen", "1-9 - Set number", "0/Del/Backspace - Remove number", "Left/A/H - Move selection left", @@ -77,7 +64,6 @@ void draw_win(Cudoku *game) { void draw_board(Cudoku *game, Size window_size) { Color bg_color = {240.0f, 235.0f, 227.0f, 255.f}; - Color color = {0.0f, 0.0f, 0.0f, 255.f}; Size cell_size = {window_size.width / 9, window_size.height / 9}; UIConstraints constraints = {0}; set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); @@ -96,7 +82,7 @@ void draw_board(Cudoku *game, Size window_size) { 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); + draw_quad(constraints, NULL, 0.0, ALIGN_TOP_LEFT); set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); set_y_constraint(&constraints, i * 100, UI_CONSTRAINT_FIXED); @@ -106,7 +92,7 @@ void draw_board(Cudoku *game, Size window_size) { } else { set_height_constraint(&constraints, 2, UI_CONSTRAINT_FIXED); } - draw_quad(constraints, &color, 0.0, ALIGN_TOP_LEFT); + draw_quad(constraints, NULL, 0.0, ALIGN_TOP_LEFT); } set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); @@ -124,82 +110,15 @@ void draw_board(Cudoku *game, Size window_size) { Sizef text_size = calculate_text_size(num, 72.f); set_y_constraint(&constraints, i * 100 + cell_size.height / 2.f - text_size.height / 2.f, UI_CONSTRAINT_FIXED); set_x_constraint(&constraints, j * 100 + cell_size.width / 2.f - text_size.width / 2.f, UI_CONSTRAINT_FIXED); - draw_text(num, 72.f, constraints, &color, ALIGN_TOP_LEFT); + if (game->board[i][j].is_locked) { + draw_text(num, 72.f, constraints, NULL, ALIGN_TOP_LEFT); + } else { + draw_text(num, 72.f, constraints, &selection_color, ALIGN_TOP_LEFT); + } } } } -unsigned int prepare_bg(bool use_texture, unsigned int *texture) { - unsigned int vbo, vao, ebo; - glGenVertexArrays(1, &vao); - glGenBuffers(1, &vbo); - glGenBuffers(1, &ebo); - - glBindVertexArray(vao); - - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferData(GL_ARRAY_BUFFER, sizeof(quad_vertices), quad_vertices, GL_STATIC_DRAW); - - glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebo); - glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(quad_indices), quad_indices, GL_STATIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0); - - if (use_texture) { - int tex_width = 0, tex_height = 0; - unsigned char *tex_data = NULL; - - glGenTextures(1, &(*texture)); - glBindTexture(GL_TEXTURE_2D, *texture); - - 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); - - tex_data = stbi_load("assets/sudoku-grid.png", &tex_width, &tex_height, NULL, 0); - if (tex_data) { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, tex_width, tex_height, 0, GL_RGB, GL_UNSIGNED_BYTE, tex_data); - glGenerateMipmap(GL_TEXTURE_2D); - - stbi_image_free(tex_data); - } else { - printf("[ERROR] could not load texture image\n"); - } - - glEnableVertexAttribArray(1); - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float))); - } - - glBindVertexArray(0); - - return vao; -} - -void draw_bg_grid_shader(Shader shader, unsigned int vao, float* transform, float resolution) { - use_shader(shader); - - set_mat4f(shader, "transform", transform); - set_float(shader, "resolution", resolution); - - glBindVertexArray(vao); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - - glBindVertexArray(0); -} - -void draw_bg_grid_texture(Shader shader, unsigned int vao, unsigned int texture, float* transform) { - use_shader(shader); - set_mat4f(shader, "transform", transform); - - glBindVertexArray(vao); - glBindTexture(GL_TEXTURE_2D, texture); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0); - - glBindVertexArray(0); -} - /* void draw_pause_overlay(Cudoku *game) { */ /* timer_pause(&game->timer); */ @@ -214,90 +133,52 @@ void draw_bg_grid_texture(Shader shader, unsigned int vao, unsigned int texture, /* // example of drawing text */ /* draw_text_at(pause_text, font_scale, posx, posy, color); */ -/* // TODO: rotations, translation, scaling */ /* // TODO: buttons and other elements */ /* } */ -void prepare_selection_box(unsigned int *vao, unsigned int *vbo) { - glGenVertexArrays(1, &(*vao)); - glGenBuffers(1, &(*vbo)); +void draw_selection_box(int x, int y, const Color color) { + UIConstraints constraints = {0}; + set_x_constraint(&constraints, x * 100, UI_CONSTRAINT_FIXED); + set_y_constraint(&constraints, y * 100, UI_CONSTRAINT_FIXED); + set_width_constraint(&constraints, 100, UI_CONSTRAINT_FIXED); + set_height_constraint(&constraints, 100, UI_CONSTRAINT_FIXED); - glBindVertexArray(*vao); - glBindBuffer(GL_ARRAY_BUFFER, *vbo); - - glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6*2, NULL, GL_DYNAMIC_DRAW); - - glEnableVertexAttribArray(0); - glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), 0); - - glBindBuffer(GL_ARRAY_BUFFER, 0); - glBindVertexArray(0); + draw_quad(constraints, &color, 0.0, ALIGN_TOP_LEFT); } - -void draw_selection_box(Shader shader, unsigned int vao, unsigned int vbo, int x, int y, float *transform, Color color) { - use_shader(shader); - - set_mat4f(shader, "transform", transform); - set_vec4f(shader, "aColor", color.r, color.g, color.b, color.a); - - glBindVertexArray(vao); - - float vert = 0.11f; - // get size of a single cell in opengl coords (-1, 1) - float single_cell = (1.f/9.f) * 2; - // we minus 4 since we start at column and row 4 (0-indexed) - float offset_x = single_cell * (y - 4); - float offset_y = single_cell * (x - 4); - - float vertices[6][2] = { - // top left tri - { -vert + offset_x, -vert - offset_y }, - { -vert + offset_x, vert - offset_y }, - { vert + offset_x, vert - offset_y }, - - // bottom right tri - { -vert + offset_x, -vert - offset_y }, - { vert + offset_x, vert - offset_y }, - { vert + offset_x, -vert - offset_y } - }; - - glBindBuffer(GL_ARRAY_BUFFER, vbo); - glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); - glBindBuffer(GL_ARRAY_BUFFER, 0); - - glDrawArrays(GL_TRIANGLES, 0, 6); - - glBindVertexArray(0); -} - -void highlight_mistakes(Shader shader, unsigned int vao, unsigned vbo, float *transform, Cudoku *game) { +void highlight_mistakes(Cudoku *game) { for (int i = 0; i < 9; i++) { for (int j = 0; j < 9; j++) { Cell cell = game->board[i][j]; if (cell.value != 0 && cell.value != game->solution[i][j]) { - draw_selection_box(shader, vao, vbo, i, j, transform, mistake_color); + draw_selection_box(j, i, mistake_color); } } } + + UIConstraints constraints = {0}; + + const int font_size = 24; + const char *text = "Mistake highlighter is ON"; + Sizef text_size = calculate_text_size(text, font_size); + set_width_constraint(&constraints, text_size.width, UI_CONSTRAINT_FIXED); + set_height_constraint(&constraints, text_size.height, UI_CONSTRAINT_FIXED); + draw_quad(constraints, &(Color){0, 0, 0, 30}, 0.0, ALIGN_BOTTOM_LEFT); + + set_width_constraint(&constraints, 1, UI_CONSTRAINT_FIXED); + set_height_constraint(&constraints, 1, UI_CONSTRAINT_FIXED); + draw_text(text, font_size, constraints, &(Color){255, 0, 0, 255}, ALIGN_BOTTOM_LEFT); } void toggle_check(Cudoku *game) { game->should_highlight_mistakes = !game->should_highlight_mistakes; } -void do_selection(Cudoku *game, int x, int y, int width, int height, float x_scale, float y_scale) { +void do_selection(Cudoku *game, int x, int y) { if (game->has_won) return; - float board_x_start = (width / 2.f) - ((width * x_scale) / 2); - float board_y_start = (height / 2.f) - ((height * y_scale) / 2); - - float cell_width = (width * x_scale) / 9.f; - float cell_height = (height * y_scale) / 9.f; - - - int cell_x = floor((x - board_x_start) / cell_width); - int cell_y = floor((y - board_y_start) / cell_height); + int cell_x = floor(x / 100.f); + int cell_y = floor(y / 100.f); if (cell_x < 0 || cell_x > 8 || cell_y < 0 || cell_y > 8) { game->should_draw_selection = false; diff --git a/cudoku.h b/cudoku.h index 318407b..eb85648 100644 --- a/cudoku.h +++ b/cudoku.h @@ -24,12 +24,10 @@ typedef struct Cudoku { float win_time; } Cudoku; -void draw_bg_grid_texture(Shader shader, unsigned int vao, unsigned int texture, float* transform); -void prepare_selection_box(unsigned int *vao, unsigned int *vbo); -void draw_selection_box(Shader shader, unsigned int vao, unsigned int vbo, int x, int y, float *transform, Color color); -void highlight_mistakes(Shader shader, unsigned int vao, unsigned vbo, float *transform, Cudoku *game); +void draw_selection_box(int x, int y, const Color color); +void highlight_mistakes(Cudoku *game); void toggle_check(Cudoku *game); -void do_selection(Cudoku *game, int x, int y, int width, int height, float x_scale, float y_scale); +void do_selection(Cudoku *game, int x, int y); void set_selected_number(Cudoku *game, int number); void move_selection(Cudoku *game, int x, int y); void toggle_selection(Cudoku *game); diff --git a/main.c b/main.c index 5d60a72..448428d 100644 --- a/main.c +++ b/main.c @@ -12,13 +12,13 @@ #define DEBUG 1 +extern Display *display; const char *font_path = "assets/fonts/Rubik/Rubik-VariableFont_wght.ttf"; const char *title = "Cudoku"; void usage() { printf("Usage: cudoku [OPTION]\n\n"); printf(" %-20s%-20s", "-h, --help", "prints this help message\n"); - printf(" %-20s%-20s", "--use-texture", "use a texture instead of generating the grid using shaders\n"); printf(" %-20s%-20s", "-f, --font FONT", "use a custom font file to render text\n"); } @@ -72,12 +72,10 @@ void handle_keypress(XEvent xev, Cudoku *game) { toggle_selection(game); } else if (XLookupKeysym(&xev.xkey, 0) == XK_n) { generate_random_board(game); - } else if (XLookupKeysym(&xev.xkey, 0) == XK_F11) { - /* toggle_fullscreen(display, window); */ } else if (XLookupKeysym(&xev.xkey, 0) == XK_c) { toggle_check(game); - /* } else if (XLookupKeysym(&xev.xkey, 0) == XK_m) { */ - /* toggle_mute(&game); */ + /* } else if (XLookupKeysym(&xev.xkey, 0) == XK_p) { */ + /* pause(&game); */ } else if (XLookupKeysym(&xev.xkey, 0) == XK_F1) { if (!toggle_help(game)) { timer_stop(&game->help_timer); @@ -86,8 +84,6 @@ void handle_keypress(XEvent xev, Cudoku *game) { } int main(int argc, char *argv[]) { - bool use_texture = false; - if (argc > 1) { char *flag = argv[1]; if (strcmp(flag, "-h") == 0 || strcmp(flag, "--help") == 0) { @@ -103,15 +99,7 @@ int main(int argc, char *argv[]) { font_path = argv[i + 1]; i++; } else { - printf("[ERROR]: used font flag with no provided font, defaulting to Rubik\n"); - } - } else if (strcmp(flag, "--use-texture") == 0) { - FILE *fp = fopen("assets/sudoku-grid.png", "r"); - if (fp == NULL) { - printf("[ERROR]: could not open board texture, falling back to shader grid\n"); - } else { - fclose(fp); - use_texture = true; + printf("[WARN]: Used font flag with no provided font, defaulting to Rubik\n"); } } } @@ -132,30 +120,47 @@ int main(int argc, char *argv[]) { game.should_draw_help = true; generate_random_board(&game); - Shader grid_shader; - if (use_texture) - grid_shader = create_shader("shaders/board_v.vert", "shaders/board_f.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); - - float delta_t, last_t = 0.0; timer_start(&game.help_timer, 5.0f); timer_start(&game.timer, 0.0f); while (!zephr_should_quit()) { - float now = get_time(); - delta_t = now - last_t; - last_t = now; + while (XPending(display)) { + XEvent xev; + XNextEvent(display, &xev); - if (!use_texture) { - draw_board(&game, window_size); + if (xev.type == KeyPress) { + if (XLookupKeysym(&xev.xkey, 0) == XK_Escape || + (XLookupKeysym(&xev.xkey, 0) == XK_q && xev.xkey.state & ControlMask)) { + zephr_quit(); + break; + } else { + handle_keypress(xev, &game); + } + } else if (xev.type == ButtonPress) { + if (xev.xbutton.button == Button1) { + int x = xev.xbutton.x; + int y = xev.xbutton.y; + do_selection(&game, x, y); + } + } } + // TODO: how do I want the input handling to look like + //zephr_poll_events();? + //for event in zephr_events()?? + // + + draw_board(&game, window_size); draw_timer(&game.timer); + if (game.should_draw_selection) { + draw_selection_box(game.selection.y, game.selection.x, (Color){102, 102, 255, 127}); + } + + if (game.should_highlight_mistakes) { + highlight_mistakes(&game); + } + if (timer_ended(&game.help_timer)) { timer_stop(&game.help_timer); game.should_draw_help = false; @@ -171,64 +176,6 @@ int main(int argc, char *argv[]) { zephr_swap_buffers(); } - /* while (!quit) { */ - - /* /1* while (XPending(display)) { *1/ */ - /* /1* XEvent xev; *1/ */ - /* /1* XNextEvent(display, &xev); *1/ */ - - /* /1* if (xev.type == ConfigureNotify) { *1/ */ - /* /1* XConfigureEvent xce = xev.xconfigure; *1/ */ - - /* /1* if (xce.width != width || xce.height != height) { *1/ */ - /* /1* width = xce.width; *1/ */ - /* /1* height = xce.height; *1/ */ - /* /1* resize_x11_window(display, window); *1/ */ - /* /1* } *1/ */ - - /* /1* } else if (xev.type == KeyPress) { *1/ */ - /* /1* if (XLookupKeysym(&xev.xkey, 0) == XK_Escape || *1/ */ - /* /1* (XLookupKeysym(&xev.xkey, 0) == XK_q && xev.xkey.state & ControlMask)) { *1/ */ - /* /1* quit = true; *1/ */ - /* /1* break; *1/ */ - /* /1* } else { *1/ */ - /* /1* handle_keypress(xev, &game); *1/ */ - /* /1* } *1/ */ - /* /1* } else if (xev.type == ButtonPress) { *1/ */ - /* /1* if (xev.xbutton.button == Button1) { *1/ */ - /* /1* int x = xev.xbutton.x; *1/ */ - /* /1* int y = xev.xbutton.y; *1/ */ - /* /1* do_selection(&game, x, y, width, height, x_scale, y_scale); *1/ */ - /* /1* } *1/ */ - /* /1* } *1/ */ - /* /1* } *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) */ - /* draw_selection_box( */ - /* selection_shader, */ - /* selection_vao, */ - /* selection_vbo, */ - /* game.selection.x, */ - /* game.selection.y, */ - /* (float *)transform, */ - /* selection_color); */ - - /* /1* if (game.should_highlight_mistakes) { *1/ */ - /* /1* highlight_mistakes(selection_shader, selection_vao, selection_vbo, (float *)transform, &game); *1/ */ - - /* /1* char* text = "Mistake highlighter is ON"; *1/ */ - /* /1* float text_scale = 0.2; *1/ */ - /* /1* Size text_size = calculate_text_size(text, text_scale); *1/ */ - /* /1* Vec2 text_pos = { 0.0f, text_size.height - 10.f }; *1/ */ - /* /1* Color text_color = { 200.0f, 50.0f, 50.0f, 1.0f }; *1/ */ - /* /1* draw_text_at(font_shader, text, text_pos, text_scale, font_vao, font_vbo, (float *)projection.m, &text_color); *1/ */ - /* /1* } *1/ */ - - /* /1* glXSwapBuffers(display, window); *1/ */ - /* } */ deinit_zephr(); diff --git a/shaders/board_f.frag b/shaders/board_f.frag deleted file mode 100644 index 727cf0c..0000000 --- a/shaders/board_f.frag +++ /dev/null @@ -1,10 +0,0 @@ -#version 330 core -out vec4 FragColor; - -in vec2 texCoords; - -uniform sampler2D aTexture; - -void main() { - FragColor = texture(aTexture, texCoords); -} diff --git a/shaders/board_v.vert b/shaders/board_v.vert deleted file mode 100644 index 38e8b51..0000000 --- a/shaders/board_v.vert +++ /dev/null @@ -1,11 +0,0 @@ -#version 330 core -layout (location = 0) in vec3 aPos; -layout (location = 1) in vec2 aTexCoords; -out vec2 texCoords; - -uniform mat4 transform; - -void main() { - gl_Position = transform * vec4(aPos, 1.0f); - texCoords = aTexCoords; -} diff --git a/text.c b/text.c index af8fd5e..a411197 100644 --- a/text.c +++ b/text.c @@ -283,7 +283,7 @@ Sizef calculate_text_size(const char *text, int font_size) { void draw_text(const char* text, int font_size, UIConstraints constraints, const Color *color, Alignment alignment) { use_shader(font_shader); - Color text_color = { 0 }; + Color text_color = { 0, 0, 0, 1.f }; if (color) { text_color = (Color){ color->r / 255.f, color->g / 255.f, color->b / 255.f, color->a / 255.f }; } diff --git a/todo.txt b/todo.txt index 9650dc9..30b4f4e 100644 --- a/todo.txt +++ b/todo.txt @@ -3,6 +3,8 @@ zephr stuff - 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) - texture func (draw_image? or draw_texture? func) +- input handling (mouse, keyboard, gamepad?) with an event system + Watch youtu.be/watch?v=oheNg0k_WDc and related videos to get ideas for the keyboard and gamepad handling text rendering improvements - [ ] unicode support (allows for non-ascii characters) diff --git a/ui.c b/ui.c index 51804a9..2f5734d 100644 --- a/ui.c +++ b/ui.c @@ -16,7 +16,7 @@ unsigned int ui_vao; unsigned int ui_vbo; int init_ui(const char* font_path, Size window_size) { - zephr_context.window_size = window_size; + zephr_context.window.size = window_size; zephr_context.projection = orthographic_projection_2d(0.f, window_size.width, window_size.height, 0.f); int res = init_fonts(font_path); @@ -54,7 +54,7 @@ void set_x_constraint(UIConstraints *constraints, float value, UIConstraint type constraints->x = value; break; case UI_CONSTRAINT_RELATIVE: - constraints->x = (value * zephr_context.window_size.width); + constraints->x = (value * zephr_context.window.size.width); break; } } @@ -68,7 +68,7 @@ void set_y_constraint(UIConstraints *constraints, float value, UIConstraint type constraints->y = value; break; case UI_CONSTRAINT_RELATIVE: - constraints->y = (value * zephr_context.window_size.height); + constraints->y = (value * zephr_context.window.size.height); break; } } @@ -79,10 +79,10 @@ void set_width_constraint(UIConstraints *constraints, float value, UIConstraint constraints->width = value; break; case UI_CONSTRAINT_RELATIVE: - constraints->width = (value * zephr_context.window_size.width); + constraints->width = (value * zephr_context.window.size.width); break; case UI_CONSTRAINT_RELATIVE_PIXELS: - constraints->width = zephr_context.window_size.width / (float)zephr_context.screen_size.width * value; + constraints->width = zephr_context.window.size.width / (float)zephr_context.screen_size.width * value; break; case UI_CONSTRAINT_ASPECT_RATIO: constraints->width = constraints->height * value; @@ -96,10 +96,10 @@ void set_height_constraint(UIConstraints *constraints, float value, UIConstraint constraints->height = value; break; case UI_CONSTRAINT_RELATIVE: - constraints->height = (value * zephr_context.window_size.height); + constraints->height = (value * zephr_context.window.size.height); break; case UI_CONSTRAINT_RELATIVE_PIXELS: - constraints->height = zephr_context.window_size.height / (float)zephr_context.screen_size.height * value; + constraints->height = zephr_context.window.size.height / (float)zephr_context.screen_size.height * value; break; case UI_CONSTRAINT_ASPECT_RATIO: constraints->height = constraints->width * value; @@ -123,36 +123,36 @@ void apply_alignment(Alignment align, Vec2f *pos, Sizef size) { pos->y = pos->y; break; case ALIGN_TOP_CENTER: - pos->x += zephr_context.window_size.width / 2.f - size.width / 2.f; + pos->x += zephr_context.window.size.width / 2.f - size.width / 2.f; pos->y = pos->y; break; case ALIGN_TOP_RIGHT: - pos->x += zephr_context.window_size.width - size.width; + pos->x += zephr_context.window.size.width - size.width; pos->y = pos->y; break; case ALIGN_BOTTOM_LEFT: pos->x = pos->x; - pos->y += zephr_context.window_size.height - size.height; + pos->y += zephr_context.window.size.height - size.height; break; case ALIGN_BOTTOM_CENTER: - pos->x += zephr_context.window_size.width / 2.f - size.width / 2.f; - pos->y += zephr_context.window_size.height - size.height; + pos->x += zephr_context.window.size.width / 2.f - size.width / 2.f; + pos->y += zephr_context.window.size.height - size.height; break; case ALIGN_BOTTOM_RIGHT: - pos->x += zephr_context.window_size.width - size.width; - pos->y += zephr_context.window_size.height - size.height; + pos->x += zephr_context.window.size.width - size.width; + pos->y += zephr_context.window.size.height - size.height; break; case ALIGN_LEFT_CENTER: pos->x = pos->x; - pos->y += zephr_context.window_size.height / 2.f - size.height / 2.f; + pos->y += zephr_context.window.size.height / 2.f - size.height / 2.f; break; case ALIGN_RIGHT_CENTER: - pos->x += zephr_context.window_size.width - size.width; - pos->y += zephr_context.window_size.height / 2.f - size.height / 2.f; + pos->x += zephr_context.window.size.width - size.width; + pos->y += zephr_context.window.size.height / 2.f - size.height / 2.f; break; case ALIGN_CENTER: - pos->x += zephr_context.window_size.width / 2.f - size.width / 2.f; - pos->y += zephr_context.window_size.height / 2.f - size.height / 2.f; + pos->x += zephr_context.window.size.width / 2.f - size.width / 2.f; + pos->y += zephr_context.window.size.height / 2.f - size.height / 2.f; break; } } diff --git a/x11.c b/x11.c index 8fb99fd..aaf70f7 100644 --- a/x11.c +++ b/x11.c @@ -5,18 +5,16 @@ #include #include -static bool fullscreen = false; - Colormap colormap; GLXContext glx_context; -void resize_x11_window(Display *display, Window window) { +void x11_resize_window(Display *display, Window window) { XWindowAttributes win_attrs; XGetWindowAttributes(display, window, &win_attrs); glViewport(0, 0, win_attrs.width, win_attrs.height); } -int init_x11(Display **display, Window *window, const char* title, int window_width, int window_height) { +int x11_init(Display **display, Window *window, const char* title, int window_width, int window_height) { *display = XOpenDisplay(NULL); if (display == NULL) { @@ -109,14 +107,14 @@ int init_x11(Display **display, Window *window, const char* title, int window_wi glEnable(GL_MULTISAMPLE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glViewport(0, 0, win_attrs.width, win_attrs.height); - resize_x11_window(*display, *window); + x11_resize_window(*display, *window); XFree(fbc); return 0; } -void close_x11(Display **display, Window *window) { +void x11_close(Display **display, Window *window) { glXMakeCurrent(*display, 0, 0); glXDestroyContext(*display, glx_context); @@ -161,17 +159,15 @@ void return_fullscreen(Display *display, Window window) SubstructureNotifyMask | SubstructureRedirectMask, &xev); } -void toggle_fullscreen(Display *display, Window window) { +void x11_toggle_fullscreen(bool fullscreen, Display *display, Window window) { if (fullscreen) { return_fullscreen(display, window); } else { go_fullscreen(display, window); } - - fullscreen = !fullscreen; } -void get_screen_size(Display *display, int *width, int *height) { +void x11_get_screen_size(Display *display, int *width, int *height) { Screen *screen = DefaultScreenOfDisplay(display); *width = screen->width; diff --git a/x11.h b/x11.h index 6c3d737..36961fb 100644 --- a/x11.h +++ b/x11.h @@ -1,10 +1,12 @@ #pragma once +#include + #include -int init_x11(Display **display, Window *window, const char* title, int window_width, int window_height); -void close_x11(Display **display, Window *window); -void resize_x11_window(Display *display, Window window); -void toggle_fullscreen(Display *display, Window window); -void get_screen_size(Display *display, int *width, int *height); +int x11_init(Display **display, Window *window, const char* title, int window_width, int window_height); +void x11_close(Display **display, Window *window); +void x11_resize_window(Display *display, Window window); +void x11_toggle_fullscreen(bool fullscreen, Display *display, Window window); +void x11_get_screen_size(Display *display, int *width, int *height); void x11_make_window_non_resizable(Display *display, Window window, int width, int height); diff --git a/zephr.c b/zephr.c index 3d467c7..6021dc0 100644 --- a/zephr.c +++ b/zephr.c @@ -21,7 +21,7 @@ int init_zephr(const char* font_path, const char* window_title, Size window_size return 1; } - res = init_x11(&display, &window, window_title, window_size.width, window_size.height); + res = x11_init(&display, &window, window_title, window_size.width, window_size.height); if (res < 0) return 1; res = init_ui(font_path, (Size){ .width = window_size.width, .height = window_size.height }); @@ -36,21 +36,20 @@ int init_zephr(const char* font_path, const char* window_title, Size window_size zephr_context.clear_color = (Color){0.0, 0.0, 0.0, 1.0}; } - get_screen_size(display, &zephr_context.screen_size.width, &zephr_context.screen_size.height); + x11_get_screen_size(display, &zephr_context.screen_size.width, &zephr_context.screen_size.height); start_internal_timer(); return 0; } void deinit_zephr() { - close_x11(&display, &window); + x11_close(&display, &window); audio_close(); } bool zephr_should_quit() { // TODO: input events // TODO: window events - // TODO: ui update?? while (XPending(display)) { XEvent xev; @@ -59,26 +58,11 @@ bool zephr_should_quit() { if (xev.type == ConfigureNotify) { XConfigureEvent xce = xev.xconfigure; - if (xce.width != zephr_context.window_size.width || xce.height != zephr_context.window_size.height) { - zephr_context.window_size = (Size){ .width = xce.width, .height = xce.height }; + if (xce.width != zephr_context.window.size.width || xce.height != zephr_context.window.size.height) { + 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); + x11_resize_window(display, window); } - - } else if (xev.type == KeyPress) { - if (XLookupKeysym(&xev.xkey, 0) == XK_Escape || - (XLookupKeysym(&xev.xkey, 0) == XK_q && xev.xkey.state & ControlMask)) { - zephr_context.should_quit = true; - break; - } else { - /* handle_keypress(xev, &game); */ - } - } else if (xev.type == ButtonPress) { - /* if (xev.xbutton.button == Button1) { */ - /* int x = xev.xbutton.x; */ - /* int y = xev.xbutton.y; */ - /* do_selection(&game, x, y, width, height, x_scale, y_scale); */ - /* } */ } } @@ -89,10 +73,8 @@ bool zephr_should_quit() { glClearColor(r, g, b, a); glClear(GL_COLOR_BUFFER_BIT); - /* update_ui(); */ audio_update(); - return zephr_context.should_quit; } @@ -102,10 +84,20 @@ void zephr_swap_buffers() { } Size zephr_get_window_size() { - return zephr_context.window_size; + return zephr_context.window.size; } -// Has to be called after calling init_zephr() +// This MUST be called after calling init_zephr() void zephr_make_window_non_resizable() { - x11_make_window_non_resizable(display, window, zephr_context.window_size.width, zephr_context.window_size.height); + x11_make_window_non_resizable(display, window, zephr_context.window.size.width, zephr_context.window.size.height); +} + +void zephr_toggle_fullscreen() { + x11_toggle_fullscreen(zephr_context.window.is_fullscreen, display, window); + + zephr_context.window.is_fullscreen = !zephr_context.window.is_fullscreen; +} + +void zephr_quit() { + zephr_context.should_quit = true; } diff --git a/zephr.h b/zephr.h index a24ea68..361ad31 100644 --- a/zephr.h +++ b/zephr.h @@ -4,11 +4,16 @@ #include "text.h" +typedef struct ZephWindow { + Size size; + bool is_fullscreen; +} ZephWindow; + typedef struct Context { bool should_quit; Color clear_color; Size screen_size; - Size window_size; + ZephWindow window; ZephFont font; Matrix4x4 projection; @@ -20,3 +25,5 @@ bool zephr_should_quit(); void zephr_swap_buffers(); Size zephr_get_window_size(); void zephr_make_window_non_resizable(); +void zephr_toggle_fullscreen(); +void zephr_quit();