mirror of
https://github.com/IllusionMan1212/cudoku.git
synced 2026-10-24 02:12:25 +00:00
added help overlay
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
BIN=cudoku
|
BIN=cudoku
|
||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-Wall -Wextra -pedantic -O3 -g `pkg-config --cflags freetype2` -I3rdparty/glad/include -I3rdparty/stb
|
CFLAGS=-Wall -Wextra -pedantic -O3 -g `pkg-config --cflags freetype2` -I3rdparty/glad/include -I3rdparty/stb
|
||||||
OBJ=main.o x11.o cudoku.o shader.o font.o 3rdparty/glad/src/gl.o 3rdparty/glad/src/glx.o 3rdparty/stb/stb.o
|
OBJ=main.o x11.o cudoku.o shader.o font.o helper.o 3rdparty/glad/src/gl.o 3rdparty/glad/src/glx.o 3rdparty/stb/stb.o
|
||||||
LDFLAGS=`pkg-config --libs x11 freetype2` -lm
|
LDFLAGS=`pkg-config --libs x11 freetype2` -lm
|
||||||
DEPS=3rdparty/glad/include/glad/gl.h 3rdparty/glad/include/glad/glx.h 3rdparty/stb/stb_image.h
|
DEPS=3rdparty/glad/include/glad/gl.h 3rdparty/glad/include/glad/glx.h 3rdparty/stb/stb_image.h
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,9 @@
|
|||||||
#include "cudoku.h"
|
#include "cudoku.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
#include "helper.h"
|
||||||
|
|
||||||
|
#define help_text_size 12
|
||||||
|
|
||||||
static const float quad_vertices[] = {
|
static const float quad_vertices[] = {
|
||||||
// positions // texture coords
|
// positions // texture coords
|
||||||
@@ -26,6 +29,23 @@ static const int quad_indices[] = {
|
|||||||
|
|
||||||
static const Color mistake_color = {1.f, 0.f, 0.f, 0.5f};
|
static const Color mistake_color = {1.f, 0.f, 0.f, 0.5f};
|
||||||
|
|
||||||
|
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",
|
||||||
|
"Right/D/L - Move selection right",
|
||||||
|
"Up/W/K - Move selection up",
|
||||||
|
"Down/S/J - Move selection down",
|
||||||
|
"Space/Enter - Toggle selection",
|
||||||
|
"N - New board",
|
||||||
|
"C - Check for mistakes",
|
||||||
|
"R - Reset board"
|
||||||
|
};
|
||||||
|
|
||||||
void set_scale_factor(int width, int height, float *x, float *y) {
|
void set_scale_factor(int width, int height, float *x, float *y) {
|
||||||
if (width > height) {
|
if (width > height) {
|
||||||
float ratio = (float)height / (float)width;
|
float ratio = (float)height / (float)width;
|
||||||
@@ -155,9 +175,8 @@ void draw_win_overlay(Shader win_shader, Shader font_shader, unsigned int vao, u
|
|||||||
|
|
||||||
glBindVertexArray(0);
|
glBindVertexArray(0);
|
||||||
|
|
||||||
const char *text = "You won!";
|
Size text_size = calculate_text_size(win_text, 1.0f);
|
||||||
Size text_size = calculate_text_size(text, 1.0f);
|
draw_text(font_shader, win_text, text_size, 1.5f, font_vao, font_vbo, transform);
|
||||||
draw_text(font_shader, text, text_size, 1.5f, font_vao, font_vbo, transform);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void prepare_selection_box(unsigned int *vao, unsigned int *vbo) {
|
void prepare_selection_box(unsigned int *vao, unsigned int *vbo) {
|
||||||
@@ -206,7 +225,6 @@ void draw_selection_box(Shader shader, unsigned int vao, unsigned int vbo, int x
|
|||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
@@ -261,6 +279,7 @@ void reset_state(Cudoku *game) {
|
|||||||
game->should_draw_selection = false;
|
game->should_draw_selection = false;
|
||||||
game->should_highlight_mistakes = false;
|
game->should_highlight_mistakes = false;
|
||||||
game->has_won = false;
|
game->has_won = false;
|
||||||
|
game->should_draw_help = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool check_win(Cudoku *game) {
|
bool check_win(Cudoku *game) {
|
||||||
@@ -274,6 +293,7 @@ bool check_win(Cudoku *game) {
|
|||||||
game->has_won = true;
|
game->has_won = true;
|
||||||
game->should_draw_selection = false;
|
game->should_draw_selection = false;
|
||||||
game->should_highlight_mistakes = false;
|
game->should_highlight_mistakes = false;
|
||||||
|
game->should_draw_help = false;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@@ -541,4 +561,53 @@ void reset_board(Cudoku *game) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void toggle_help(Cudoku *game) {
|
||||||
|
if (!game->has_won) {
|
||||||
|
game->should_draw_help = !game->should_draw_help;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_ui_element_at(Shader shader, unsigned int vao, unsigned int vbo, Matrix4x4 projection, Vec2 pos, Size size, Color color) {
|
||||||
|
use_shader(shader);
|
||||||
|
|
||||||
|
set_mat4f(shader, "transform", (float *)projection.m);
|
||||||
|
set_vec4f(shader, "aColor", color.r, color.g, color.b, color.a);
|
||||||
|
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
|
float vertices[6][2] = {
|
||||||
|
{pos.x, pos.y + size.height},
|
||||||
|
{pos.x, pos.y},
|
||||||
|
{pos.x + size.width, pos.y},
|
||||||
|
|
||||||
|
{pos.x, pos.y + size.height},
|
||||||
|
{pos.x + size.width, pos.y},
|
||||||
|
{pos.x + size.width, pos.y + size.height},
|
||||||
|
};
|
||||||
|
|
||||||
|
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 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) {
|
||||||
|
float scale = 0.3f;
|
||||||
|
int total_help_texts_height = 20;
|
||||||
|
int text_padding = 10;
|
||||||
|
|
||||||
|
Size size = {.width = 700, .height = 500};
|
||||||
|
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++) {
|
||||||
|
Size text_size = calculate_text_size(help_texts[i], 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, scale, font_vao, font_vbo, (float *)projection.m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -21,6 +21,7 @@ typedef struct Cudoku {
|
|||||||
Vec2 selection;
|
Vec2 selection;
|
||||||
bool should_draw_selection;
|
bool should_draw_selection;
|
||||||
bool should_highlight_mistakes;
|
bool should_highlight_mistakes;
|
||||||
|
bool should_draw_help;
|
||||||
} Cudoku;
|
} Cudoku;
|
||||||
|
|
||||||
typedef struct Color {
|
typedef struct Color {
|
||||||
@@ -47,3 +48,5 @@ void move_selection(Cudoku *game, int x, int y);
|
|||||||
void toggle_selection(Cudoku *game);
|
void toggle_selection(Cudoku *game);
|
||||||
void generate_random_board(Cudoku *game);
|
void generate_random_board(Cudoku *game);
|
||||||
void reset_board(Cudoku *game);
|
void reset_board(Cudoku *game);
|
||||||
|
void toggle_help(Cudoku *game);
|
||||||
|
void draw_help_overlay();
|
||||||
|
|||||||
@@ -223,3 +223,47 @@ void draw_text(Shader shader, const char *text, Size text_size, float scale, uns
|
|||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void draw_text_at(Shader shader, const char *text, Vec2 pos, float scale, unsigned int vao, unsigned int vbo, float *projection) {
|
||||||
|
use_shader(shader);
|
||||||
|
set_vec3f(shader, "textColor", 200.f / 255.f, 200.f / 255.f, 200.f / 255.f);
|
||||||
|
set_mat4f(shader, "transform", (float *)projection);
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindVertexArray(vao);
|
||||||
|
|
||||||
|
int c = 0;
|
||||||
|
while (text[c] != '\0') {
|
||||||
|
Character ch = characters[(int)text[c]];
|
||||||
|
|
||||||
|
float xpos = pos.x + ch.bearing.width * scale;
|
||||||
|
float ypos = pos.y - (ch.size.height - ch.bearing.height) * scale;
|
||||||
|
|
||||||
|
float w = (ch.size.width * scale);
|
||||||
|
float h = (ch.size.height * scale);
|
||||||
|
|
||||||
|
float vertices[6][4] = {
|
||||||
|
// top left tri
|
||||||
|
{ xpos, ypos + h, 0.0f, 0.0f },
|
||||||
|
{ xpos, ypos, 0.0f, 1.0f },
|
||||||
|
{ xpos + w, ypos, 1.0f, 1.0f },
|
||||||
|
|
||||||
|
// bottom right tri
|
||||||
|
{ xpos, ypos + h, 0.0f, 0.0f },
|
||||||
|
{ xpos + w, ypos, 1.0f, 1.0f },
|
||||||
|
{ xpos + w, ypos + h, 1.0f, 0.0f }
|
||||||
|
};
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, ch.texture_id);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
pos.x += (ch.advance >> 6) * scale;
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|||||||
@@ -20,3 +20,4 @@ void prepare_font(unsigned int *vao, unsigned int *vbo);
|
|||||||
Size calculate_text_size(const char *text, float scale);
|
Size calculate_text_size(const char *text, float scale);
|
||||||
void draw_number(Shader shader, Cell cell, int row, int column, float scale,unsigned int vao, unsigned int vbo, float* transform);
|
void draw_number(Shader shader, Cell cell, int row, int column, float scale,unsigned int vao, unsigned int vbo, float* transform);
|
||||||
void draw_text(Shader shader, const char *text, Size text_size, float scale, unsigned int vao, unsigned int vbo, float *transform);
|
void draw_text(Shader shader, const char *text, Size text_size, float scale, unsigned int vao, unsigned int vbo, float *transform);
|
||||||
|
void draw_text_at(Shader shader, const char *text, Vec2 pos, float scale, unsigned int vao, unsigned int vbo, float *projection);
|
||||||
|
|||||||
@@ -0,0 +1,21 @@
|
|||||||
|
#include "helper.h"
|
||||||
|
|
||||||
|
Matrix4x4 orthographicProjection2D(float left, float right, float bottom, float top) {
|
||||||
|
Matrix4x4 result;
|
||||||
|
|
||||||
|
// Identity matrix
|
||||||
|
for (int i = 0; i < 4; i++) {
|
||||||
|
for (int j = 0; j < 4; j++) {
|
||||||
|
result.m[i][j] = 0.0f;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
result.m[0][0] = 2.0f / (right - left);
|
||||||
|
result.m[3][0] = -(right + left) / (right - left);
|
||||||
|
result.m[1][1] = 2.0f / (top - bottom);
|
||||||
|
result.m[3][1] = -(top + bottom) / (top - bottom);
|
||||||
|
result.m[2][2] = -1.0f;
|
||||||
|
result.m[3][3] = 1.0f;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
typedef struct {
|
||||||
|
float m[4][4];
|
||||||
|
} Matrix4x4;
|
||||||
|
|
||||||
|
Matrix4x4 orthographicProjection2D(float left, float right, float bottom, float top);
|
||||||
@@ -9,6 +9,7 @@
|
|||||||
#include "x11.h"
|
#include "x11.h"
|
||||||
#include "cudoku.h"
|
#include "cudoku.h"
|
||||||
#include "font.h"
|
#include "font.h"
|
||||||
|
#include "helper.h"
|
||||||
|
|
||||||
Display *display;
|
Display *display;
|
||||||
Window window;
|
Window window;
|
||||||
@@ -60,8 +61,8 @@ void handle_keypress(XEvent xev, Cudoku *game) {
|
|||||||
toggle_check(game);
|
toggle_check(game);
|
||||||
/* } else if (XLookupKeysym(&xev.xkey, 0) == XK_m) { */
|
/* } else if (XLookupKeysym(&xev.xkey, 0) == XK_m) { */
|
||||||
/* toggle_mute(&game); */
|
/* toggle_mute(&game); */
|
||||||
/* } else if (XLookupKeysym(&xev.xkey, 0) == XK_F1) { */
|
} else if (XLookupKeysym(&xev.xkey, 0) == XK_F1) {
|
||||||
/* toggle_help(&game); */
|
toggle_help(game);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -120,6 +121,7 @@ int main(int argc, char *argv[]) {
|
|||||||
srand(time(NULL));
|
srand(time(NULL));
|
||||||
|
|
||||||
Cudoku game = {0};
|
Cudoku game = {0};
|
||||||
|
game.should_draw_help = true;
|
||||||
generate_random_board(&game);
|
generate_random_board(&game);
|
||||||
|
|
||||||
for (int i = 0; i < 9; i++) {
|
for (int i = 0; i < 9; i++) {
|
||||||
@@ -198,6 +200,8 @@ int main(int argc, char *argv[]) {
|
|||||||
{0, 0, 0, 1},
|
{0, 0, 0, 1},
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Matrix4x4 projection = orthographicProjection2D(0.0f, width, 0.0f, height);
|
||||||
|
|
||||||
if (!use_texture)
|
if (!use_texture)
|
||||||
draw_bg_grid_shader(grid_shader, board_vao, (float *)transform, width < height ? width : height);
|
draw_bg_grid_shader(grid_shader, board_vao, (float *)transform, width < height ? width : height);
|
||||||
else
|
else
|
||||||
@@ -218,6 +222,9 @@ int main(int argc, char *argv[]) {
|
|||||||
if (game.should_highlight_mistakes)
|
if (game.should_highlight_mistakes)
|
||||||
highlight_mistakes(selection_shader, selection_vao, selection_vbo, (float *)transform, &game);
|
highlight_mistakes(selection_shader, selection_vao, selection_vbo, (float *)transform, &game);
|
||||||
|
|
||||||
|
if (game.should_draw_help)
|
||||||
|
draw_help_overlay(selection_shader, font_shader, selection_vao, selection_vbo, font_vao, font_vbo, projection, height);
|
||||||
|
|
||||||
if (game.has_won) {
|
if (game.has_won) {
|
||||||
draw_win_overlay(win_shader, font_shader, win_vao, font_vao, font_vbo, (float *)transform);
|
draw_win_overlay(win_shader, font_shader, win_vao, font_vao, font_vbo, (float *)transform);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user