mirror of
https://github.com/IllusionMan1212/cudoku.git
synced 2026-10-24 02:12:25 +00:00
super basic UI constraint and alignment system with a super basic "game framework"
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
BIN=cudoku
|
BIN=cudoku
|
||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-Wall -Wextra -pedantic -g `pkg-config --cflags freetype2` -I3rdparty/glad/include -I3rdparty/stb -I3rdparty/fmod/include
|
CFLAGS=-Wall -Wextra -O3 -pedantic -g `pkg-config --cflags freetype2` -I3rdparty/glad/include -I3rdparty/stb -I3rdparty/fmod/include
|
||||||
OBJ=main.o x11.o cudoku.o shader.o font.o helper.o audio.o timer.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 audio.o timer.o ui.o 3rdparty/glad/src/gl.o 3rdparty/glad/src/glx.o 3rdparty/stb/stb.o
|
||||||
LDFLAGS=`pkg-config --libs x11 freetype2` -lm -L3rdparty/fmod/lib -Wl,-rpath=3rdparty/fmod/lib -lfmod
|
LDFLAGS=`pkg-config --libs x11 freetype2` -lm -L3rdparty/fmod/lib -Wl,-rpath=3rdparty/fmod/lib -lfmod
|
||||||
DEPS=3rdparty/glad/include/glad/gl.h 3rdparty/glad/include/glad/glx.h 3rdparty/stb/stb_image.h 3rdparty/fmod/include/fmod.h
|
DEPS=3rdparty/glad/include/glad/gl.h 3rdparty/glad/include/glad/glx.h 3rdparty/stb/stb_image.h 3rdparty/fmod/include/fmod.h
|
||||||
|
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ void audio_play_win() {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
void audio_cleanup() {
|
void audio_close() {
|
||||||
FMOD_Sound_Release(win_sound);
|
FMOD_Sound_Release(win_sound);
|
||||||
FMOD_Sound_Release(scribble_sound);
|
FMOD_Sound_Release(scribble_sound);
|
||||||
FMOD_ChannelGroup_Release(sfx_channel_group);
|
FMOD_ChannelGroup_Release(sfx_channel_group);
|
||||||
|
|||||||
@@ -1,5 +1,7 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
int audio_init();
|
int audio_init();
|
||||||
void audio_cleanup();
|
void audio_close();
|
||||||
void audio_update();
|
void audio_update();
|
||||||
void audio_play_scribble();
|
void audio_play_scribble();
|
||||||
void audio_play_win();
|
void audio_play_win();
|
||||||
|
|||||||
@@ -8,9 +8,9 @@
|
|||||||
#include "3rdparty/stb/stb_image.h"
|
#include "3rdparty/stb/stb_image.h"
|
||||||
|
|
||||||
#include "cudoku.h"
|
#include "cudoku.h"
|
||||||
#include "font.h"
|
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
#include "ui.h"
|
||||||
|
|
||||||
#define HELP_TEXT_SIZE 13
|
#define HELP_TEXT_SIZE 13
|
||||||
|
|
||||||
@@ -47,6 +47,32 @@ static const char *help_texts[HELP_TEXT_SIZE] = {
|
|||||||
"Ctrl+Q/Esc - Quit"
|
"Ctrl+Q/Esc - Quit"
|
||||||
};
|
};
|
||||||
|
|
||||||
|
void draw_win() {
|
||||||
|
Size window = zephr_get_window_size();
|
||||||
|
Color bg_color = {233.f, 84.f, 32.f, 200.f};
|
||||||
|
Color text_color = {237.f, 225.f, 215.f, 255.f};
|
||||||
|
|
||||||
|
UIConstraints constraints;
|
||||||
|
/* set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); */
|
||||||
|
/* set_y_constraint(&constraints, 0, UI_CONSTRAINT_FIXED); */
|
||||||
|
/* set_width_constraint(&constraints, window.width, UI_CONSTRAINT_FIXED); */
|
||||||
|
/* set_height_constraint(&constraints, window.height, UI_CONSTRAINT_FIXED); */
|
||||||
|
|
||||||
|
Alignment align = ALIGN_TOP_RIGHT;
|
||||||
|
float scale = 1.0f;
|
||||||
|
|
||||||
|
Sizef text_size = calculate_text_size(win_text, scale);
|
||||||
|
|
||||||
|
set_x_constraint(&constraints, 0, UI_CONSTRAINT_FIXED);
|
||||||
|
set_y_constraint(&constraints, 0, UI_CONSTRAINT_FIXED);
|
||||||
|
set_width_constraint(&constraints, text_size.width, UI_CONSTRAINT_FIXED);
|
||||||
|
set_height_constraint(&constraints, text_size.height, UI_CONSTRAINT_FIXED);
|
||||||
|
|
||||||
|
draw_quad(constraints, &bg_color, align);
|
||||||
|
|
||||||
|
draw_text(win_text, scale, (Vec2f){0.0, 0.0}, &text_color, align);
|
||||||
|
}
|
||||||
|
|
||||||
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;
|
||||||
@@ -134,7 +160,7 @@ void draw_numbers(Shader shader, unsigned int vao, unsigned int vbo, float *tran
|
|||||||
for (int i = 0; i < 9; i++) {
|
for (int i = 0; i < 9; i++) {
|
||||||
for (int j = 0; j < 9; j++) {
|
for (int j = 0; j < 9; j++) {
|
||||||
if (board[i][j].value != 0) {
|
if (board[i][j].value != 0) {
|
||||||
draw_number(shader, board[i][j], i, j, 5.0f, vao, vbo, transform);
|
/* draw_number(shader, board[i][j], i, j, 5.0f, vao, vbo, transform); */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -180,12 +206,30 @@ void draw_win_overlay(Shader win_shader, Shader font_shader, unsigned int vao, u
|
|||||||
float time_elapsed = game->win_time - game->timer.time;
|
float time_elapsed = game->win_time - game->timer.time;
|
||||||
snprintf(time_text, 64, "Solved in: %02dm%02ds", (int)time_elapsed / 60, (int)time_elapsed % 60);
|
snprintf(time_text, 64, "Solved in: %02dm%02ds", (int)time_elapsed / 60, (int)time_elapsed % 60);
|
||||||
|
|
||||||
Size win_text_size = calculate_text_size(win_text, 1.0f);
|
/* Size win_text_size = calculate_text_size(win_text, 1.0f); */
|
||||||
Size time_text_size = calculate_text_size(time_text, 1.0f);
|
/* Size time_text_size = calculate_text_size(time_text, 1.0f); */
|
||||||
draw_text_center(font_shader, win_text, win_text_size, 1.5f, font_vao, font_vbo, transform, 0.0, 75.0);
|
/* draw_text_center(font_shader, win_text, win_text_size, 1.5f, font_vao, font_vbo, transform, 0.0, 75.0); */
|
||||||
draw_text_center(font_shader, time_text, time_text_size, 0.8f, font_vao, font_vbo, transform, 0.0, -75.0);
|
/* draw_text_center(font_shader, time_text, time_text_size, 0.8f, font_vao, font_vbo, transform, 0.0, -75.0); */
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* void draw_pause_overlay(Cudoku *game) { */
|
||||||
|
/* timer_pause(&game->timer); */
|
||||||
|
|
||||||
|
/* // */
|
||||||
|
/* // this is my basic idea of drawing ui elements */
|
||||||
|
/* // */
|
||||||
|
/* // examples of drawing shapes */
|
||||||
|
/* draw_quad(beginning_x, beginning_y, win_width, win_height); */
|
||||||
|
/* draw_circle(); */
|
||||||
|
/* draw_triangle(); */
|
||||||
|
|
||||||
|
/* // 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) {
|
void prepare_selection_box(unsigned int *vao, unsigned int *vbo) {
|
||||||
glGenVertexArrays(1, &(*vao));
|
glGenVertexArrays(1, &(*vao));
|
||||||
glGenBuffers(1, &(*vbo));
|
glGenBuffers(1, &(*vbo));
|
||||||
@@ -625,9 +669,9 @@ void draw_help_overlay(Shader overlay_shader, Shader font_shader, unsigned int o
|
|||||||
int overlay_width = 0;
|
int overlay_width = 0;
|
||||||
|
|
||||||
for (int i = 0; i < HELP_TEXT_SIZE; i++) {
|
for (int i = 0; i < HELP_TEXT_SIZE; i++) {
|
||||||
Size text_size = calculate_text_size(help_texts[i], text_scale);
|
/* Size text_size = calculate_text_size(help_texts[i], text_scale); */
|
||||||
overlay_height += text_size.height + text_padding;
|
/* overlay_height += text_size.height + text_padding; */
|
||||||
overlay_width = max(overlay_width, text_size.width + text_padding * 2);
|
/* overlay_width = max(overlay_width, text_size.width + text_padding * 2); */
|
||||||
}
|
}
|
||||||
Size size = {.width = overlay_width, .height = overlay_height + text_padding * 2};
|
Size size = {.width = overlay_width, .height = overlay_height + text_padding * 2};
|
||||||
Vec2 pos = {
|
Vec2 pos = {
|
||||||
@@ -643,30 +687,30 @@ void draw_help_overlay(Shader overlay_shader, Shader font_shader, unsigned int o
|
|||||||
draw_ui_element_at(overlay_shader, overlay_vao, overlay_vbo, projection, pos, size, color);
|
draw_ui_element_at(overlay_shader, overlay_vao, overlay_vbo, projection, pos, size, color);
|
||||||
|
|
||||||
for (int i = 0; i < HELP_TEXT_SIZE; i++) {
|
for (int i = 0; i < HELP_TEXT_SIZE; i++) {
|
||||||
Size text_size = calculate_text_size(help_texts[i], text_scale);
|
/* Size text_size = calculate_text_size(help_texts[i], text_scale); */
|
||||||
Vec2 text_pos = {
|
/* Vec2 text_pos = { */
|
||||||
.x = text_padding,
|
/* .x = text_padding, */
|
||||||
.y = window_height - total_help_texts_height - (text_padding * 2)
|
/* .y = window_height - total_help_texts_height - (text_padding * 2) */
|
||||||
};
|
/* }; */
|
||||||
total_help_texts_height += text_size.height + text_padding;
|
/* 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);
|
/* draw_text_at(font_shader, help_texts[i], text_pos, text_scale, font_vao, font_vbo, (float *)projection->m, NULL); */
|
||||||
}
|
}
|
||||||
|
|
||||||
if (timer->is_running) {
|
if (timer->is_running) {
|
||||||
char closing_in_text[128];
|
char closing_in_text[128];
|
||||||
snprintf(closing_in_text, sizeof(closing_in_text), "Hiding in %ds", (int)timer_remaining(timer) + 1);
|
/* 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);
|
/* Size closing_in_text_size = calculate_text_size(closing_in_text, text_scale / 2.0); */
|
||||||
Vec2 closing_in_text_pos = {
|
/* Vec2 closing_in_text_pos = { */
|
||||||
.x = overlay_width - closing_in_text_size.width,
|
/* .x = overlay_width - closing_in_text_size.width, */
|
||||||
.y = window_height - closing_in_text_size.height - text_padding,
|
/* .y = window_height - closing_in_text_size.height - text_padding, */
|
||||||
};
|
/* }; */
|
||||||
Color closing_in_text_color = {
|
/* Color closing_in_text_color = { */
|
||||||
.r = 255.0f,
|
/* .r = 255.0f, */
|
||||||
.g = 150.0f,
|
/* .g = 150.0f, */
|
||||||
.b = 0.0f,
|
/* .b = 0.0f, */
|
||||||
.a = 1.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);
|
/* 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); */
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -679,19 +723,19 @@ void draw_timer(Shader shader, unsigned int vao, unsigned int vbo, float *projec
|
|||||||
int minutes = elapsed / 60;
|
int minutes = elapsed / 60;
|
||||||
int seconds = (int)elapsed % 60;
|
int seconds = (int)elapsed % 60;
|
||||||
|
|
||||||
snprintf(timer_text, sizeof(timer_text), "Time: %02d:%02d", minutes, seconds);
|
/* snprintf(timer_text, sizeof(timer_text), "Time: %02d:%02d", minutes, seconds); */
|
||||||
float text_scale = 0.35f;
|
/* float text_scale = 0.35f; */
|
||||||
Size text_size = calculate_text_size(timer_text, text_scale);
|
/* Size text_size = calculate_text_size(timer_text, text_scale); */
|
||||||
Vec2 text_pos = {
|
/* Vec2 text_pos = { */
|
||||||
.x = win_width - text_size.width - 10,
|
/* .x = win_width - text_size.width - 10, */
|
||||||
.y = 10,
|
/* .y = 10, */
|
||||||
};
|
/* }; */
|
||||||
Color text_color = {
|
/* Color text_color = { */
|
||||||
.r = 66.0f,
|
/* .r = 66.0f, */
|
||||||
.g = 92.0f,
|
/* .g = 92.0f, */
|
||||||
.b = 124.0f,
|
/* .b = 124.0f, */
|
||||||
.a = 1.0f,
|
/* .a = 1.0f, */
|
||||||
};
|
/* }; */
|
||||||
|
|
||||||
draw_text_at(shader, timer_text, text_pos, text_scale, vao, vbo, projection, &text_color);
|
/* draw_text_at(shader, timer_text, text_pos, text_scale, vao, vbo, projection, &text_color); */
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,11 +5,7 @@
|
|||||||
#include "helper.h"
|
#include "helper.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
#include "ui.h"
|
||||||
typedef struct Vec2 {
|
|
||||||
int x;
|
|
||||||
int y;
|
|
||||||
} Vec2;
|
|
||||||
|
|
||||||
typedef struct Cell {
|
typedef struct Cell {
|
||||||
int value;
|
int value;
|
||||||
@@ -29,13 +25,6 @@ typedef struct Cudoku {
|
|||||||
float win_time;
|
float win_time;
|
||||||
} Cudoku;
|
} Cudoku;
|
||||||
|
|
||||||
typedef struct Color {
|
|
||||||
float r;
|
|
||||||
float g;
|
|
||||||
float b;
|
|
||||||
float a;
|
|
||||||
} Color;
|
|
||||||
|
|
||||||
void set_scale_factor(int width, int height, float *x, float *y);
|
void set_scale_factor(int width, int height, float *x, float *y);
|
||||||
unsigned int prepare_bg(bool use_texture, unsigned int *texture);
|
unsigned int prepare_bg(bool use_texture, unsigned int *texture);
|
||||||
void draw_bg_grid_shader(Shader shader, unsigned int vao, float* transform, float resolution);
|
void draw_bg_grid_shader(Shader shader, unsigned int vao, float* transform, float resolution);
|
||||||
@@ -66,3 +55,4 @@ void draw_help_overlay(
|
|||||||
Timer *timer
|
Timer *timer
|
||||||
);
|
);
|
||||||
void draw_timer(Shader shader, unsigned int vao, unsigned int vbo, float *projection, Timer *timer, int win_width);
|
void draw_timer(Shader shader, unsigned int vao, unsigned int vbo, float *projection, Timer *timer, int win_width);
|
||||||
|
void draw_win();
|
||||||
|
|||||||
@@ -1,248 +1,155 @@
|
|||||||
#include <ft2build.h>
|
/* #include <glad/gl.h> */
|
||||||
#include FT_FREETYPE_H
|
|
||||||
#include <freetype/ftmm.h>
|
|
||||||
#include <glad/gl.h>
|
|
||||||
|
|
||||||
#include "font.h"
|
/* #include "font.h" */
|
||||||
#include "shader.h"
|
/* #include "shader.h" */
|
||||||
|
|
||||||
Character characters[128];
|
/* void draw_number(Shader shader, Cell cell, int row, int column, float scale, unsigned int vao, unsigned int vbo, float *transform) { */
|
||||||
|
/* use_shader(shader); */
|
||||||
|
/* if (cell.is_locked) { */
|
||||||
|
/* set_vec3f(shader, "textColor", 44.f / 255.f, 54.f / 255.f, 57.f / 255.f); */
|
||||||
|
/* } else { */
|
||||||
|
/* set_vec3f(shader, "textColor", 110.f / 255.f, 133.f / 255.f, 183.f / 255.f); */
|
||||||
|
/* } */
|
||||||
|
/* set_mat4f(shader, "transform", transform); */
|
||||||
|
/* glActiveTexture(GL_TEXTURE0); */
|
||||||
|
/* glBindVertexArray(vao); */
|
||||||
|
|
||||||
int init_fonts(const char *font_path) {
|
/* // get ascii value of cell value and use it to index into characters */
|
||||||
FT_Library ft;
|
/* Character ch = characters['0' + cell.value]; */
|
||||||
if (FT_Init_FreeType(&ft)) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
FT_Face face;
|
/* float w = ch.size.width; */
|
||||||
if (FT_New_Face(ft, font_path, 0, &face)) {
|
/* float h = ch.size.height; */
|
||||||
return -2;
|
/* float ratio = w / h; */
|
||||||
}
|
|
||||||
|
|
||||||
if ((face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
|
/* // draw the glyph over the entire board and then scale it down to the size */
|
||||||
printf("[INFO] Got a variable font\n");
|
/* // of a single cell */
|
||||||
FT_MM_Var *mm;
|
/* float vert_h = 1.0; */
|
||||||
FT_Get_MM_Var(face, &mm);
|
/* float vert_w = vert_h * ratio; */
|
||||||
|
/* // 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 * (column - 4); */
|
||||||
|
/* float offset_y = single_cell * (row - 4); */
|
||||||
|
|
||||||
FT_Set_Var_Design_Coordinates(face, mm->num_namedstyles, mm->namedstyle[mm->num_namedstyles - 4].coords);
|
/* // texture coords are y-flipped */
|
||||||
|
/* float vertices[6][4] = { */
|
||||||
|
/* // top left tri */
|
||||||
|
/* { ((-(vert_w) / w * ratio) * scale) + offset_x, (-vert_h / h * scale) - offset_y, 0.0f, 1.0f }, */
|
||||||
|
/* { ((-(vert_w) / w * ratio) * scale) + offset_x, ( vert_h / h * scale) - offset_y, 0.0f, 0.0f }, */
|
||||||
|
/* { (( (vert_w) / w * ratio) * scale) + offset_x, ( vert_h / h * scale) - offset_y, 1.0f, 0.0f }, */
|
||||||
|
|
||||||
FT_Done_MM_Var(ft, mm);
|
/* // bottom right tri */
|
||||||
}
|
/* { ((-(vert_w) / w * ratio) * scale) + offset_x, (-vert_h / h * scale) - offset_y, 0.0f, 1.0f }, */
|
||||||
|
/* { (( (vert_w) / w * ratio) * scale) + offset_x, ( vert_h / h * scale) - offset_y, 1.0f, 0.0f }, */
|
||||||
|
/* { (( (vert_w) / w * ratio) * scale) + offset_x, (-vert_h / h * scale) - offset_y, 1.0f, 1.0f } */
|
||||||
|
/* }; */
|
||||||
|
|
||||||
FT_Set_Pixel_Sizes(face, 0, 128);
|
/* glBindTexture(GL_TEXTURE_2D, ch.texture_id); */
|
||||||
|
|
||||||
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
/* glBindBuffer(GL_ARRAY_BUFFER, vbo); */
|
||||||
|
/* glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); */
|
||||||
|
|
||||||
for (int c = 0; c < 128; c++) {
|
/* glBindBuffer(GL_ARRAY_BUFFER, 0); */
|
||||||
if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
|
|
||||||
printf("[ERROR]: failed to load glyph for char '%c'\n", c);
|
|
||||||
}
|
|
||||||
|
|
||||||
unsigned int texture;
|
/* glDrawArrays(GL_TRIANGLES, 0, 6); */
|
||||||
glGenTextures(1, &texture);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, texture);
|
|
||||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width,
|
|
||||||
face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE,
|
|
||||||
face->glyph->bitmap.buffer);
|
|
||||||
|
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
/* glBindVertexArray(0); */
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
/* glBindTexture(GL_TEXTURE_2D, 0); */
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
/* } */
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
|
||||||
|
|
||||||
characters[c].texture_id = texture;
|
/* void draw_text_center(Shader shader, const char *text, Size text_size, float scale, unsigned int vao, unsigned int vbo, float *transform, float offset_x, float offset_y) { */
|
||||||
characters[c].advance = face->glyph->advance.x;
|
/* use_shader(shader); */
|
||||||
characters[c].size = (Size){ .width = face->glyph->bitmap.width, .height = face->glyph->bitmap.rows };
|
/* set_vec3f(shader, "textColor", 200.f / 255.f, 200.f / 255.f, 200.f / 255.f); */
|
||||||
characters[c].bearing = (Size){ .width = face->glyph->bitmap_left, .height = face->glyph->bitmap_top };
|
/* set_mat4f(shader, "transform", transform); */
|
||||||
}
|
/* glActiveTexture(GL_TEXTURE0); */
|
||||||
|
/* glBindVertexArray(vao); */
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
/* int c = 0; */
|
||||||
|
/* int x = 0; */
|
||||||
|
/* while (text[c] != '\0') { */
|
||||||
|
/* Character ch = characters[(int)text[c]]; */
|
||||||
|
|
||||||
FT_Done_Face(face);
|
/* float xpos = ((x + ch.bearing.width * scale + offset_x) / 900.f) - ((text_size.width / 2.f) * scale / 900.f); */
|
||||||
FT_Done_FreeType(ft);
|
/* float ypos = (((ch.bearing.height - ch.size.height + offset_y) * scale) / 900.f) - ((text_size.height / 2.f) * scale / 900.f); */
|
||||||
|
|
||||||
return 0;
|
/* float w = (ch.size.width * scale / 900.f); */
|
||||||
}
|
/* float h = (ch.size.height * scale / 900.f); */
|
||||||
|
|
||||||
void prepare_font(unsigned int *vao, unsigned int *vbo) {
|
/* float vertices[6][4] = { */
|
||||||
glGenVertexArrays(1, &(*vao));
|
/* // top left tri */
|
||||||
glGenBuffers(1, &(*vbo));
|
/* { xpos, ypos + h, 0.0f, 0.0f }, */
|
||||||
|
/* { xpos, ypos, 0.0f, 1.0f }, */
|
||||||
|
/* { xpos + w, ypos, 1.0f, 1.0f }, */
|
||||||
|
|
||||||
glBindVertexArray(*vao);
|
/* // bottom right tri */
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, *vbo);
|
/* { xpos, ypos + h, 0.0f, 0.0f }, */
|
||||||
|
/* { xpos + w, ypos, 1.0f, 1.0f }, */
|
||||||
|
/* { xpos + w, ypos + h, 1.0f, 0.0f } */
|
||||||
|
/* }; */
|
||||||
|
|
||||||
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6*4, NULL, GL_DYNAMIC_DRAW);
|
/* glBindTexture(GL_TEXTURE_2D, ch.texture_id); */
|
||||||
|
|
||||||
glEnableVertexAttribArray(0);
|
/* glBindBuffer(GL_ARRAY_BUFFER, vbo); */
|
||||||
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
|
/* glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); */
|
||||||
|
/* glBindBuffer(GL_ARRAY_BUFFER, 0); */
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
/* glDrawArrays(GL_TRIANGLES, 0, 6); */
|
||||||
glBindVertexArray(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Size calculate_text_size(const char *text, float scale) {
|
/* x += (ch.advance >> 6) * scale; */
|
||||||
Size size = { .width = 0, .height = 0 };
|
/* c++; */
|
||||||
float w = 0;
|
/* } */
|
||||||
float h = 0;
|
|
||||||
for (uint i = 0; i < strlen(text); i++) {
|
|
||||||
Character ch = characters[(uint)text[i]];
|
|
||||||
w += ch.advance / 64.0;
|
|
||||||
if (ch.size.height > h) {
|
|
||||||
h = ch.size.height;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
size.width = w * scale;
|
|
||||||
size.height = h * scale;
|
|
||||||
return size;
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_number(Shader shader, Cell cell, int row, int column, float scale, unsigned int vao, unsigned int vbo, float *transform) {
|
/* glBindVertexArray(0); */
|
||||||
use_shader(shader);
|
/* glBindTexture(GL_TEXTURE_2D, 0); */
|
||||||
if (cell.is_locked) {
|
/* } */
|
||||||
set_vec3f(shader, "textColor", 44.f / 255.f, 54.f / 255.f, 57.f / 255.f);
|
|
||||||
} else {
|
|
||||||
set_vec3f(shader, "textColor", 110.f / 255.f, 133.f / 255.f, 183.f / 255.f);
|
|
||||||
}
|
|
||||||
set_mat4f(shader, "transform", transform);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindVertexArray(vao);
|
|
||||||
|
|
||||||
// get ascii value of cell value and use it to index into characters
|
/* Color default_text_color = { 200.f / 255.f, 200.f / 255.f, 200.f / 255.f, 1.f }; */
|
||||||
Character ch = characters['0' + cell.value];
|
|
||||||
|
|
||||||
float w = ch.size.width;
|
/* void draw_text_at(Shader shader, const char *text, Vec2 pos, float scale, unsigned int vao, unsigned int vbo, float *projection, Color *color) { */
|
||||||
float h = ch.size.height;
|
/* use_shader(shader); */
|
||||||
float ratio = w / h;
|
/* if (color != NULL) { */
|
||||||
|
/* set_vec3f(shader, "textColor", color->r / 255.f, color->g / 255.f, color->b / 255.f); */
|
||||||
|
/* } else { */
|
||||||
|
/* 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); */
|
||||||
|
|
||||||
// draw the glyph over the entire board and then scale it down to the size
|
/* int c = 0; */
|
||||||
// of a single cell
|
/* while (text[c] != '\0') { */
|
||||||
float vert_h = 1.0;
|
/* Character ch = characters[(int)text[c]]; */
|
||||||
float vert_w = vert_h * ratio;
|
|
||||||
// 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 * (column - 4);
|
|
||||||
float offset_y = single_cell * (row - 4);
|
|
||||||
|
|
||||||
// texture coords are y-flipped
|
/* float xpos = pos.x + ch.bearing.width * scale; */
|
||||||
float vertices[6][4] = {
|
/* float ypos = pos.y - (ch.size.height - ch.bearing.height) * scale; */
|
||||||
// top left tri
|
|
||||||
{ ((-(vert_w) / w * ratio) * scale) + offset_x, (-vert_h / h * scale) - offset_y, 0.0f, 1.0f },
|
|
||||||
{ ((-(vert_w) / w * ratio) * scale) + offset_x, ( vert_h / h * scale) - offset_y, 0.0f, 0.0f },
|
|
||||||
{ (( (vert_w) / w * ratio) * scale) + offset_x, ( vert_h / h * scale) - offset_y, 1.0f, 0.0f },
|
|
||||||
|
|
||||||
// bottom right tri
|
/* float w = (ch.size.width * scale); */
|
||||||
{ ((-(vert_w) / w * ratio) * scale) + offset_x, (-vert_h / h * scale) - offset_y, 0.0f, 1.0f },
|
/* float h = (ch.size.height * scale); */
|
||||||
{ (( (vert_w) / w * ratio) * scale) + offset_x, ( vert_h / h * scale) - offset_y, 1.0f, 0.0f },
|
|
||||||
{ (( (vert_w) / w * ratio) * scale) + offset_x, (-vert_h / h * scale) - offset_y, 1.0f, 1.0f }
|
|
||||||
};
|
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, ch.texture_id);
|
/* 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 }, */
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, vbo);
|
/* // bottom right tri */
|
||||||
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
/* { xpos, ypos + h, 0.0f, 0.0f }, */
|
||||||
|
/* { xpos + w, ypos, 1.0f, 1.0f }, */
|
||||||
|
/* { xpos + w, ypos + h, 1.0f, 0.0f } */
|
||||||
|
/* }; */
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
/* glBindTexture(GL_TEXTURE_2D, ch.texture_id); */
|
||||||
|
|
||||||
glDrawArrays(GL_TRIANGLES, 0, 6);
|
/* glBindBuffer(GL_ARRAY_BUFFER, vbo); */
|
||||||
|
/* glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); */
|
||||||
|
/* glBindBuffer(GL_ARRAY_BUFFER, 0); */
|
||||||
|
|
||||||
glBindVertexArray(0);
|
/* glDrawArrays(GL_TRIANGLES, 0, 6); */
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void draw_text_center(Shader shader, const char *text, Size text_size, float scale, unsigned int vao, unsigned int vbo, float *transform, float offset_x, float offset_y) {
|
/* pos.x += (ch.advance >> 6) * scale; */
|
||||||
use_shader(shader);
|
/* c++; */
|
||||||
set_vec3f(shader, "textColor", 200.f / 255.f, 200.f / 255.f, 200.f / 255.f);
|
/* } */
|
||||||
set_mat4f(shader, "transform", transform);
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
|
||||||
glBindVertexArray(vao);
|
|
||||||
|
|
||||||
int c = 0;
|
/* glBindVertexArray(0); */
|
||||||
int x = 0;
|
/* glBindTexture(GL_TEXTURE_2D, 0); */
|
||||||
while (text[c] != '\0') {
|
/* } */
|
||||||
Character ch = characters[(int)text[c]];
|
|
||||||
|
|
||||||
float xpos = ((x + ch.bearing.width * scale + offset_x) / 900.f) - ((text_size.width / 2.f) * scale / 900.f);
|
|
||||||
float ypos = (((ch.bearing.height - ch.size.height + offset_y) * scale) / 900.f) - ((text_size.height / 2.f) * scale / 900.f);
|
|
||||||
|
|
||||||
float w = (ch.size.width * scale / 900.f);
|
|
||||||
float h = (ch.size.height * scale / 900.f);
|
|
||||||
|
|
||||||
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);
|
|
||||||
|
|
||||||
x += (ch.advance >> 6) * scale;
|
|
||||||
c++;
|
|
||||||
}
|
|
||||||
|
|
||||||
glBindVertexArray(0);
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
Color default_text_color = { 200.f / 255.f, 200.f / 255.f, 200.f / 255.f, 1.f };
|
|
||||||
|
|
||||||
void draw_text_at(Shader shader, const char *text, Vec2 pos, float scale, unsigned int vao, unsigned int vbo, float *projection, Color *color) {
|
|
||||||
use_shader(shader);
|
|
||||||
if (color != NULL) {
|
|
||||||
set_vec3f(shader, "textColor", color->r / 255.f, color->g / 255.f, color->b / 255.f);
|
|
||||||
} else {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -3,17 +3,6 @@
|
|||||||
#include "cudoku.h"
|
#include "cudoku.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
|
||||||
typedef struct Size {
|
|
||||||
int width;
|
|
||||||
int height;
|
|
||||||
} Size;
|
|
||||||
|
|
||||||
typedef struct Character {
|
|
||||||
unsigned int texture_id;
|
|
||||||
Size size;
|
|
||||||
Size bearing;
|
|
||||||
unsigned int advance;
|
|
||||||
} Character;
|
|
||||||
|
|
||||||
int init_fonts(const char *font_path);
|
int init_fonts(const char *font_path);
|
||||||
void prepare_font(unsigned int *vao, unsigned int *vbo);
|
void prepare_font(unsigned int *vao, unsigned int *vbo);
|
||||||
|
|||||||
@@ -27,3 +27,17 @@ Matrix4x4 orthographic_projection_2d(float left, float right, float bottom, floa
|
|||||||
int max(int a, int b) {
|
int max(int a, int b) {
|
||||||
return a > b ? a : b;
|
return a > b ? a : b;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
float maxf(float a, float b) {
|
||||||
|
return a > b ? a : b;
|
||||||
|
}
|
||||||
|
|
||||||
|
float clampf(float value, float min, float max) {
|
||||||
|
if (value < min) {
|
||||||
|
return min;
|
||||||
|
} else if (value > max) {
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|||||||
@@ -4,5 +4,8 @@ typedef struct {
|
|||||||
float m[4][4];
|
float m[4][4];
|
||||||
} Matrix4x4;
|
} Matrix4x4;
|
||||||
|
|
||||||
|
Matrix4x4 identity();
|
||||||
Matrix4x4 orthographic_projection_2d(float left, float right, float bottom, float top);
|
Matrix4x4 orthographic_projection_2d(float left, float right, float bottom, float top);
|
||||||
int max(int a, int b);
|
int max(int a, int b);
|
||||||
|
float maxf(float a, float b);
|
||||||
|
float clampf(float value, float min, float max);
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
#include <math.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
@@ -5,15 +6,14 @@
|
|||||||
#include <glad/glx.h>
|
#include <glad/glx.h>
|
||||||
#include "3rdparty/stb/stb_image.h"
|
#include "3rdparty/stb/stb_image.h"
|
||||||
|
|
||||||
#include "x11.h"
|
|
||||||
#include "cudoku.h"
|
#include "cudoku.h"
|
||||||
#include "font.h"
|
#include "ui.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
|
||||||
#define DEBUG 1
|
#define DEBUG 1
|
||||||
|
|
||||||
Display *display;
|
const char *font_path = "assets/fonts/Rubik/Rubik-VariableFont_wght.ttf";
|
||||||
Window window;
|
const char *title = "Cudoku";
|
||||||
|
|
||||||
void usage() {
|
void usage() {
|
||||||
printf("Usage: cudoku [OPTION]\n\n");
|
printf("Usage: cudoku [OPTION]\n\n");
|
||||||
@@ -73,7 +73,7 @@ void handle_keypress(XEvent xev, Cudoku *game) {
|
|||||||
} else if (XLookupKeysym(&xev.xkey, 0) == XK_n) {
|
} else if (XLookupKeysym(&xev.xkey, 0) == XK_n) {
|
||||||
generate_random_board(game);
|
generate_random_board(game);
|
||||||
} else if (XLookupKeysym(&xev.xkey, 0) == XK_F11) {
|
} else if (XLookupKeysym(&xev.xkey, 0) == XK_F11) {
|
||||||
toggle_fullscreen(display, window);
|
/* toggle_fullscreen(display, window); */
|
||||||
} else if (XLookupKeysym(&xev.xkey, 0) == XK_c) {
|
} else if (XLookupKeysym(&xev.xkey, 0) == XK_c) {
|
||||||
toggle_check(game);
|
toggle_check(game);
|
||||||
/* } else if (XLookupKeysym(&xev.xkey, 0) == XK_m) { */
|
/* } else if (XLookupKeysym(&xev.xkey, 0) == XK_m) { */
|
||||||
@@ -86,17 +86,8 @@ void handle_keypress(XEvent xev, Cudoku *game) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[]) {
|
int main(int argc, char *argv[]) {
|
||||||
int res = audio_init();
|
|
||||||
if (res != 0) {
|
|
||||||
printf("[ERROR]: failed to initialize audio\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const char *font_path = "assets/fonts/Rubik/Rubik-VariableFont_wght.ttf";
|
|
||||||
bool use_texture = false;
|
bool use_texture = false;
|
||||||
|
|
||||||
// 900 is the initial width and height
|
|
||||||
int width = 900, height = 900;
|
|
||||||
// scale factors for the entire board to nicely fit as a square inside
|
// scale factors for the entire board to nicely fit as a square inside
|
||||||
// the window
|
// the window
|
||||||
float x_scale = 1.f, y_scale = 1.f;
|
float x_scale = 1.f, y_scale = 1.f;
|
||||||
@@ -130,15 +121,10 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res = init_x11(&display, &window);
|
Color clear_color = {0.2f, 0.15f, 0.5f, 1.f};
|
||||||
if (res < 0) return 1;
|
int res = init_zephr(font_path, title, (Size){800, 600}, &clear_color);
|
||||||
|
if (res != 0) {
|
||||||
res = init_fonts(font_path);
|
printf("[ERROR]: could not initialize zephr\n");
|
||||||
if (res == -1) {
|
|
||||||
printf("[ERROR]: could not initialize freetype library\n");
|
|
||||||
return 1;
|
|
||||||
} else if (res == -2) {
|
|
||||||
printf("[ERROR]: could not load font file: \"%s\"\n", font_path);
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -148,10 +134,6 @@ int main(int argc, char *argv[]) {
|
|||||||
game.should_draw_help = true;
|
game.should_draw_help = true;
|
||||||
generate_random_board(&game);
|
generate_random_board(&game);
|
||||||
|
|
||||||
unsigned int font_vao, font_vbo;
|
|
||||||
prepare_font(&font_vao, &font_vbo);
|
|
||||||
Shader font_shader = create_shader("shaders/font_v.vert", "shaders/font_f.frag");
|
|
||||||
|
|
||||||
Shader grid_shader;
|
Shader grid_shader;
|
||||||
unsigned int grid_texture;
|
unsigned int grid_texture;
|
||||||
if (!use_texture)
|
if (!use_texture)
|
||||||
@@ -170,107 +152,147 @@ int main(int argc, char *argv[]) {
|
|||||||
unsigned int win_vao = prepare_win_overlay();
|
unsigned int win_vao = prepare_win_overlay();
|
||||||
|
|
||||||
float delta_t, last_t = 0.0;
|
float delta_t, last_t = 0.0;
|
||||||
start_internal_timer();
|
|
||||||
timer_start(&game.help_timer, 5.0f);
|
timer_start(&game.help_timer, 5.0f);
|
||||||
timer_start(&game.timer, 0.0f);
|
timer_start(&game.timer, 0.0f);
|
||||||
|
|
||||||
bool quit = false;
|
while (!zephr_should_quit()) {
|
||||||
while (!quit) {
|
|
||||||
float now = get_time();
|
float now = get_time();
|
||||||
delta_t = now - last_t;
|
delta_t = now - last_t;
|
||||||
last_t = now;
|
last_t = now;
|
||||||
|
|
||||||
while (XPending(display)) {
|
Size window_size = zephr_get_window_size();
|
||||||
XEvent xev;
|
|
||||||
XNextEvent(display, &xev);
|
|
||||||
|
|
||||||
if (xev.type == ConfigureNotify) {
|
/* int width = 15.f; */
|
||||||
XConfigureEvent xce = xev.xconfigure;
|
/* int height = 35.f; */
|
||||||
|
/* int padding = 10.f; */
|
||||||
|
|
||||||
if (xce.width != width || xce.height != height) {
|
float ratio_w = (float)window_size.width / 1920.f;
|
||||||
width = xce.width;
|
float ratio_h = (float)window_size.height / 1080.f;
|
||||||
height = xce.height;
|
|
||||||
resize_x11_window(display, window);
|
|
||||||
set_scale_factor(xce.width, xce.height, &x_scale, &y_scale);
|
|
||||||
}
|
|
||||||
|
|
||||||
} else if (xev.type == KeyPress) {
|
int width = window_size.height;
|
||||||
if (XLookupKeysym(&xev.xkey, 0) == XK_Escape ||
|
int height = window_size.width;
|
||||||
(XLookupKeysym(&xev.xkey, 0) == XK_q && xev.xkey.state & ControlMask)) {
|
|
||||||
quit = true;
|
if (window_size.height > window_size.width) {
|
||||||
break;
|
width = window_size.width;
|
||||||
} else {
|
height = window_size.width;
|
||||||
handle_keypress(xev, &game);
|
} else {
|
||||||
}
|
width = window_size.height;
|
||||||
} else if (xev.type == ButtonPress) {
|
height = window_size.height;
|
||||||
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);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
glClearColor(0.2, 0.2, 0.2, 1.0);
|
draw_win();
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
|
||||||
|
|
||||||
float transform[4][4] = {
|
/* draw_quad( */
|
||||||
{x_scale, 0, 0, 0},
|
/* (Vec2){0.0, 0.0}, */
|
||||||
{0, y_scale, 0, 0},
|
/* (Size){width, height}, */
|
||||||
{0, 0, 1, 0},
|
/* &(Color){240.f, 235.f, 227.f, 255.f}, */
|
||||||
{0, 0, 0, 1},
|
/* 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); */
|
||||||
|
|
||||||
Matrix4x4 projection = orthographic_projection_2d(0.0f, width, 0.0f, height);
|
/* draw_quad( */
|
||||||
|
/* constraints, */
|
||||||
|
/* &(Color){240.f, 235.f, 227.f, 255.f}, */
|
||||||
|
/* ALIGN_TOP_LEFT */
|
||||||
|
/* ); */
|
||||||
|
|
||||||
if (!use_texture)
|
/* Size size = calculate_text_size("Bruh", 1.0f); */
|
||||||
draw_bg_grid_shader(grid_shader, board_vao, (float *)transform, width < height ? width : height);
|
/* float x = clampf(500.0f * timer_elapsed(&my_time), 0.0, window_size.width - size.width); */
|
||||||
else
|
/* draw_text("Bruh", 1.0f, (Vec2){0.0, size.height}, &(Color){255.f, 0.f, 0.f, 255.f}); */
|
||||||
draw_bg_grid_texture(grid_shader, board_vao, grid_texture, (float *)transform);
|
|
||||||
|
|
||||||
if (game.should_draw_selection)
|
zephr_swap_buffers();
|
||||||
draw_selection_box(
|
|
||||||
selection_shader,
|
|
||||||
selection_vao,
|
|
||||||
selection_vbo,
|
|
||||||
game.selection.x,
|
|
||||||
game.selection.y,
|
|
||||||
(float *)transform,
|
|
||||||
selection_color);
|
|
||||||
|
|
||||||
draw_numbers(font_shader, font_vao, font_vbo, (float *)transform, game.board);
|
|
||||||
|
|
||||||
if (game.should_highlight_mistakes) {
|
|
||||||
highlight_mistakes(selection_shader, selection_vao, selection_vbo, (float *)transform, &game);
|
|
||||||
|
|
||||||
char* text = "Mistake highlighter is ON";
|
|
||||||
float text_scale = 0.2;
|
|
||||||
Size text_size = calculate_text_size(text, text_scale);
|
|
||||||
Vec2 text_pos = { 0.0f, text_size.height - 10.f };
|
|
||||||
Color text_color = { 200.0f, 50.0f, 50.0f, 1.0f };
|
|
||||||
draw_text_at(font_shader, text, text_pos, text_scale, font_vao, font_vbo, (float *)projection.m, &text_color);
|
|
||||||
}
|
|
||||||
|
|
||||||
draw_timer(font_shader, font_vao, font_vbo, (float *)projection.m, &game.timer, width);
|
|
||||||
|
|
||||||
if (timer_ended(&game.help_timer)) {
|
|
||||||
timer_stop(&game.help_timer);
|
|
||||||
game.should_draw_help = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (game.should_draw_help)
|
|
||||||
draw_help_overlay(selection_shader, font_shader, selection_vao, selection_vbo, font_vao, font_vbo, &projection, height, &game.help_timer);
|
|
||||||
|
|
||||||
if (game.has_won) {
|
|
||||||
draw_win_overlay(win_shader, font_shader, win_vao, font_vao, font_vbo, (float *)transform, &game);
|
|
||||||
}
|
|
||||||
|
|
||||||
glXSwapBuffers(display, window);
|
|
||||||
audio_update();
|
|
||||||
}
|
}
|
||||||
|
/* while (!quit) { */
|
||||||
|
|
||||||
audio_cleanup();
|
/* /1* while (XPending(display)) { *1/ */
|
||||||
close_x11(&display, &window);
|
/* /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* set_scale_factor(xce.width, xce.height, &x_scale, &y_scale); *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/ */
|
||||||
|
|
||||||
|
/* 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* 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* draw_numbers(font_shader, font_vao, font_vbo, (float *)transform, game.board); *1/ */
|
||||||
|
|
||||||
|
/* /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* 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; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
/* /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/ */
|
||||||
|
/* } */
|
||||||
|
|
||||||
|
deinit_zephr();
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ in vec2 TexCoords;
|
|||||||
out vec4 FragColor;
|
out vec4 FragColor;
|
||||||
|
|
||||||
uniform sampler2D text;
|
uniform sampler2D text;
|
||||||
uniform vec3 textColor;
|
uniform vec4 textColor;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
|
vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);
|
||||||
FragColor = vec4(textColor, 1.0) * sampled;
|
FragColor = textColor * sampled;
|
||||||
}
|
}
|
||||||
@@ -2,9 +2,10 @@
|
|||||||
layout (location = 0) in vec4 vertex;
|
layout (location = 0) in vec4 vertex;
|
||||||
|
|
||||||
out vec2 TexCoords;
|
out vec2 TexCoords;
|
||||||
uniform mat4 transform;
|
uniform mat4 projection;
|
||||||
|
uniform mat4 model;
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
gl_Position = transform * vec4(vertex.xy, 0.0, 1.0);
|
gl_Position = projection * model * vec4(vertex.xy, 0.0, 1.0);
|
||||||
TexCoords = vertex.zw;
|
TexCoords = vertex.zw;
|
||||||
}
|
}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
#version 330 core
|
||||||
|
|
||||||
|
in vec2 texCoords;
|
||||||
|
out vec4 FragColor;
|
||||||
|
uniform vec4 aColor;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
FragColor = vec4(aColor);
|
||||||
|
}
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
#version 330 core
|
||||||
|
layout (location = 0) in vec3 aPos;
|
||||||
|
layout (location = 1) in vec2 aTexCoords;
|
||||||
|
out vec2 texCoords;
|
||||||
|
|
||||||
|
uniform mat4 projection;
|
||||||
|
|
||||||
|
void main() {
|
||||||
|
gl_Position = projection * vec4(aPos, 1.0f);
|
||||||
|
texCoords = aTexCoords;
|
||||||
|
}
|
||||||
@@ -25,6 +25,10 @@ void timer_start(Timer *timer, float duration) {
|
|||||||
timer->is_running = true;
|
timer->is_running = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void timer_stop(Timer *timer) {
|
||||||
|
timer->is_running = false;
|
||||||
|
}
|
||||||
|
|
||||||
void timer_reset(Timer *timer) {
|
void timer_reset(Timer *timer) {
|
||||||
timer->time = get_time();
|
timer->time = get_time();
|
||||||
timer->is_running = true;
|
timer->is_running = true;
|
||||||
@@ -34,10 +38,6 @@ float timer_remaining(Timer *timer) {
|
|||||||
return timer->duration - (get_time() - timer->time);
|
return timer->duration - (get_time() - timer->time);
|
||||||
}
|
}
|
||||||
|
|
||||||
void timer_stop(Timer *timer) {
|
|
||||||
timer->is_running = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
float timer_elapsed(Timer *timer) {
|
float timer_elapsed(Timer *timer) {
|
||||||
return get_time() - timer->time;
|
return get_time() - timer->time;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ double get_time();
|
|||||||
void start_internal_timer();
|
void start_internal_timer();
|
||||||
bool timer_ended(Timer *timer);
|
bool timer_ended(Timer *timer);
|
||||||
void timer_start(Timer *timer, float duration);
|
void timer_start(Timer *timer, float duration);
|
||||||
|
void timer_stop(Timer *timer);
|
||||||
void timer_reset(Timer *timer);
|
void timer_reset(Timer *timer);
|
||||||
float timer_remaining(Timer *timer);
|
float timer_remaining(Timer *timer);
|
||||||
void timer_stop(Timer *timer);
|
|
||||||
float timer_elapsed(Timer *timer);
|
float timer_elapsed(Timer *timer);
|
||||||
|
|||||||
@@ -0,0 +1,499 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <math.h>
|
||||||
|
|
||||||
|
#include <ft2build.h>
|
||||||
|
#include FT_FREETYPE_H
|
||||||
|
#include <freetype/ftmm.h>
|
||||||
|
#include <X11/Xlib.h>
|
||||||
|
#include <glad/glx.h>
|
||||||
|
|
||||||
|
#include "cudoku.h"
|
||||||
|
#include "shader.h"
|
||||||
|
#include "audio.h"
|
||||||
|
#include "ui.h"
|
||||||
|
#include "x11.h"
|
||||||
|
|
||||||
|
Display *display;
|
||||||
|
Window window;
|
||||||
|
|
||||||
|
Context zephr_context;
|
||||||
|
Character characters[128];
|
||||||
|
Shader font_shader;
|
||||||
|
Shader ui_shader;
|
||||||
|
unsigned int font_vao;
|
||||||
|
unsigned int ui_vao;
|
||||||
|
unsigned int font_vbo;
|
||||||
|
unsigned int ui_vbo;
|
||||||
|
|
||||||
|
// TODO: instanced rendering of ui elements and text??
|
||||||
|
|
||||||
|
int init_fonts(const char *font_path) {
|
||||||
|
FT_Library ft;
|
||||||
|
if (FT_Init_FreeType(&ft)) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Face face;
|
||||||
|
if (FT_New_Face(ft, font_path, 0, &face)) {
|
||||||
|
return -2;
|
||||||
|
}
|
||||||
|
|
||||||
|
if ((face->face_flags & FT_FACE_FLAG_MULTIPLE_MASTERS)) {
|
||||||
|
printf("[INFO] Got a variable font\n");
|
||||||
|
FT_MM_Var *mm;
|
||||||
|
FT_Get_MM_Var(face, &mm);
|
||||||
|
|
||||||
|
FT_Set_Var_Design_Coordinates(face, mm->num_namedstyles, mm->namedstyle[mm->num_namedstyles - 4].coords);
|
||||||
|
|
||||||
|
FT_Done_MM_Var(ft, mm);
|
||||||
|
}
|
||||||
|
|
||||||
|
FT_Set_Pixel_Sizes(face, 0, 128);
|
||||||
|
|
||||||
|
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
|
||||||
|
|
||||||
|
for (int c = 0; c < 128; c++) {
|
||||||
|
if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
|
||||||
|
printf("[ERROR]: failed to load glyph for char '%c'\n", c);
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned int texture;
|
||||||
|
glGenTextures(1, &texture);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, texture);
|
||||||
|
glTexImage2D(GL_TEXTURE_2D, 0, GL_RED, face->glyph->bitmap.width,
|
||||||
|
face->glyph->bitmap.rows, 0, GL_RED, GL_UNSIGNED_BYTE,
|
||||||
|
face->glyph->bitmap.buffer);
|
||||||
|
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
|
characters[c].texture_id = texture;
|
||||||
|
characters[c].advance = face->glyph->advance.x;
|
||||||
|
characters[c].size = (Size){ .width = face->glyph->bitmap.width, .height = face->glyph->bitmap.rows };
|
||||||
|
characters[c].bearing = (Size){ .width = face->glyph->bitmap_left, .height = face->glyph->bitmap_top };
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
|
FT_Done_Face(face);
|
||||||
|
FT_Done_FreeType(ft);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_ui(const char* font_path, 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);
|
||||||
|
if (res == -1) {
|
||||||
|
printf("[ERROR]: could not initialize freetype library\n");
|
||||||
|
return 1;
|
||||||
|
} else if (res == -2) {
|
||||||
|
printf("[ERROR]: could not load font file: \"%s\"\n", font_path);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
font_shader = create_shader("shaders/font.vert", "shaders/font.frag");
|
||||||
|
ui_shader = create_shader("shaders/ui.vert", "shaders/ui.frag");
|
||||||
|
|
||||||
|
|
||||||
|
glGenVertexArrays(1, &font_vao);
|
||||||
|
glGenVertexArrays(1, &ui_vao);
|
||||||
|
glGenBuffers(1, &font_vbo);
|
||||||
|
glGenBuffers(1, &ui_vbo);
|
||||||
|
|
||||||
|
glBindVertexArray(font_vao);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, font_vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
|
||||||
|
|
||||||
|
glBindVertexArray(ui_vao);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, ui_vbo);
|
||||||
|
glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
|
||||||
|
glEnableVertexAttribArray(0);
|
||||||
|
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), (void *)0);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
glBindVertexArray(0);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int init_zephr(const char* font_path, const char* window_title, Size window_size, Color *clear_color) {
|
||||||
|
int res = audio_init();
|
||||||
|
if (res != 0) {
|
||||||
|
printf("[ERROR]: failed to initialize audio\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
res = init_x11(&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 });
|
||||||
|
if (res != 0) {
|
||||||
|
printf("[ERROR]: failed to initialize ui\n");
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (clear_color) {
|
||||||
|
zephr_context.clear_color = *clear_color;
|
||||||
|
} else {
|
||||||
|
zephr_context.clear_color = (Color){0.0, 0.0, 0.0, 1.0};
|
||||||
|
}
|
||||||
|
|
||||||
|
start_internal_timer();
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void deinit_zephr() {
|
||||||
|
close_x11(&display, &window);
|
||||||
|
audio_close();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool zephr_should_quit() {
|
||||||
|
// TODO: input events
|
||||||
|
// TODO: window events
|
||||||
|
// TODO: ui update??
|
||||||
|
|
||||||
|
while (XPending(display)) {
|
||||||
|
XEvent xev;
|
||||||
|
XNextEvent(display, &xev);
|
||||||
|
|
||||||
|
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 };
|
||||||
|
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) {
|
||||||
|
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); */
|
||||||
|
/* } */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
float r = zephr_context.clear_color.r;
|
||||||
|
float g = zephr_context.clear_color.g;
|
||||||
|
float b = zephr_context.clear_color.b;
|
||||||
|
float a = zephr_context.clear_color.a;
|
||||||
|
glClearColor(r, g, b, a);
|
||||||
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
|
|
||||||
|
/* update_ui(); */
|
||||||
|
audio_update();
|
||||||
|
|
||||||
|
return zephr_context.should_quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void zephr_swap_buffers() {
|
||||||
|
glXSwapBuffers(display, window);
|
||||||
|
}
|
||||||
|
|
||||||
|
Size zephr_get_window_size() {
|
||||||
|
return zephr_context.window_size;
|
||||||
|
}
|
||||||
|
|
||||||
|
Sizef calculate_text_size(const char *text, float scale) {
|
||||||
|
Sizef size = { .width = 0, .height = 0 };
|
||||||
|
int w = 0;
|
||||||
|
int h = 0;
|
||||||
|
int max_bearing_h = 0;
|
||||||
|
|
||||||
|
// NOTE: I don't like looping through the characters twice, but it's fine for now
|
||||||
|
for (uint i = 0; i < strlen(text); i++) {
|
||||||
|
Character ch = characters[(uint)text[i]];
|
||||||
|
max_bearing_h = max(max_bearing_h, ch.bearing.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (uint i = 0; i < strlen(text); i++) {
|
||||||
|
Character ch = characters[(uint)text[i]];
|
||||||
|
w += ch.advance / 64;
|
||||||
|
|
||||||
|
// remove bearing of first character
|
||||||
|
if (i == 0 && strlen(text) > 1) {
|
||||||
|
w -= ch.bearing.width;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the trailing width of the last character
|
||||||
|
if (i == strlen(text) - 1) {
|
||||||
|
w -= ((ch.advance / 64) - (ch.bearing.width + ch.size.width));
|
||||||
|
}
|
||||||
|
|
||||||
|
// if we only have one character in the text, then remove the bearing width
|
||||||
|
if (strlen(text) == 1) {
|
||||||
|
w -= (ch.bearing.width);
|
||||||
|
}
|
||||||
|
|
||||||
|
h = max(h, max_bearing_h - ch.bearing.height + ch.size.height);
|
||||||
|
}
|
||||||
|
size.width = (float)w * scale;
|
||||||
|
size.height = (float)h * scale;
|
||||||
|
return size;
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_x_constraint(UIConstraints *constraints, float value, UIConstraint type) {
|
||||||
|
switch (type) {
|
||||||
|
case UI_CONSTRAINT_RELATIVE_PIXELS:
|
||||||
|
case UI_CONSTRAINT_ASPECT_RATIO:
|
||||||
|
// no-op. fallback to FIXED
|
||||||
|
case UI_CONSTRAINT_FIXED:
|
||||||
|
constraints->x = value;
|
||||||
|
break;
|
||||||
|
case UI_CONSTRAINT_RELATIVE:
|
||||||
|
constraints->x = (value * zephr_context.window_size.width);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_y_constraint(UIConstraints *constraints, float value, UIConstraint type) {
|
||||||
|
switch (type) {
|
||||||
|
case UI_CONSTRAINT_RELATIVE_PIXELS:
|
||||||
|
case UI_CONSTRAINT_ASPECT_RATIO:
|
||||||
|
// no-op. fallback to FIXED
|
||||||
|
case UI_CONSTRAINT_FIXED:
|
||||||
|
constraints->y = value;
|
||||||
|
break;
|
||||||
|
case UI_CONSTRAINT_RELATIVE:
|
||||||
|
constraints->y = (value * zephr_context.window_size.height);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_width_constraint(UIConstraints *constraints, float value, UIConstraint type) {
|
||||||
|
switch (type) {
|
||||||
|
case UI_CONSTRAINT_FIXED:
|
||||||
|
constraints->width = value;
|
||||||
|
break;
|
||||||
|
case UI_CONSTRAINT_RELATIVE:
|
||||||
|
constraints->width = (value * zephr_context.window_size.width);
|
||||||
|
break;
|
||||||
|
case UI_CONSTRAINT_RELATIVE_PIXELS:
|
||||||
|
constraints->width = zephr_context.window_size.width / 1920.f * value;
|
||||||
|
break;
|
||||||
|
case UI_CONSTRAINT_ASPECT_RATIO:
|
||||||
|
constraints->width = constraints->height * value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_height_constraint(UIConstraints *constraints, float value, UIConstraint type) {
|
||||||
|
switch (type) {
|
||||||
|
case UI_CONSTRAINT_FIXED:
|
||||||
|
constraints->height = value;
|
||||||
|
break;
|
||||||
|
case UI_CONSTRAINT_RELATIVE:
|
||||||
|
constraints->height = (value * zephr_context.window_size.height);
|
||||||
|
break;
|
||||||
|
case UI_CONSTRAINT_RELATIVE_PIXELS:
|
||||||
|
constraints->height = zephr_context.window_size.height / 1080.f * value;
|
||||||
|
break;
|
||||||
|
case UI_CONSTRAINT_ASPECT_RATIO:
|
||||||
|
constraints->height = constraints->width * value;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_constraints(UIConstraints constraints, Vec2f *pos, Sizef *size) {
|
||||||
|
*pos = (Vec2f){constraints.x, constraints.y};
|
||||||
|
*size = (Sizef){constraints.width, constraints.height};
|
||||||
|
}
|
||||||
|
|
||||||
|
void apply_alignment(Alignment align, Vec2f *pos, Sizef size) {
|
||||||
|
switch (align) {
|
||||||
|
case ALIGN_TOP_LEFT:
|
||||||
|
pos->x = pos->x;
|
||||||
|
pos->y = pos->y;
|
||||||
|
break;
|
||||||
|
case ALIGN_TOP_CENTER:
|
||||||
|
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->y = pos->y;
|
||||||
|
break;
|
||||||
|
case ALIGN_BOTTOM_LEFT:
|
||||||
|
pos->x = pos->x;
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
case ALIGN_BOTTOM_RIGHT:
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void draw_quad(UIConstraints constraints, Color *color, Alignment align) {
|
||||||
|
use_shader(ui_shader);
|
||||||
|
|
||||||
|
if (color) {
|
||||||
|
set_vec4f(ui_shader, "aColor", color->r / 255.f, color->g / 255.f, color->b / 255.f, color->a / 255.f);
|
||||||
|
} else {
|
||||||
|
set_vec4f(ui_shader, "aColor", 0.f, 0.f, 0.f, 1.f);
|
||||||
|
}
|
||||||
|
|
||||||
|
set_mat4f(ui_shader, "projection", (float *)zephr_context.projection.m);
|
||||||
|
|
||||||
|
glBindVertexArray(ui_vao);
|
||||||
|
|
||||||
|
Vec2f pos = { 0.f, 0.f };
|
||||||
|
Sizef size = { 0.f, 0.f };
|
||||||
|
|
||||||
|
apply_constraints(constraints, &pos, &size);
|
||||||
|
apply_alignment(align, &pos, size);
|
||||||
|
|
||||||
|
float vertices[6][4] = {
|
||||||
|
{pos.x, pos.y + size.height, 0.0, 1.0},
|
||||||
|
{pos.x, pos.y, 0.0, 0.0},
|
||||||
|
{pos.x + size.width, pos.y, 1.0, 0.0},
|
||||||
|
|
||||||
|
{pos.x, pos.y + size.height, 0.0, 1.0},
|
||||||
|
{pos.x + size.width, pos.y, 1.0, 0.0},
|
||||||
|
{pos.x + size.width, pos.y + size.height, 1.0, 1.0},
|
||||||
|
};
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, ui_vbo);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO: remove scaling and replace it with standardized font sizes with 16.0f being the default
|
||||||
|
void draw_text(const char* text, float scale, Vec2f pos, Color *color, Alignment alignment) {
|
||||||
|
use_shader(font_shader);
|
||||||
|
if (color) {
|
||||||
|
set_vec4f(font_shader, "textColor", color->r / 255.f, color->g / 255.f, color->b / 255.f, color->a / 255.f);
|
||||||
|
} else {
|
||||||
|
set_vec4f(font_shader, "textColor", 0.f, 0.f, 0.f, 1.f);
|
||||||
|
}
|
||||||
|
set_mat4f(font_shader, "projection", (float *)zephr_context.projection.m);
|
||||||
|
Matrix4x4 model = identity();
|
||||||
|
model.m[3][0] = pos.x;
|
||||||
|
model.m[3][1] = pos.y;
|
||||||
|
|
||||||
|
set_mat4f(font_shader, "model", (float *)model.m);
|
||||||
|
|
||||||
|
glActiveTexture(GL_TEXTURE0);
|
||||||
|
glBindVertexArray(font_vao);
|
||||||
|
|
||||||
|
Sizef text_size = calculate_text_size(text, 1.0);
|
||||||
|
|
||||||
|
int max_bearing_h = 0;
|
||||||
|
for (uint i = 0; i < strlen(text); i++) {
|
||||||
|
Character ch = characters[(int)text[i]];
|
||||||
|
max_bearing_h = max(max_bearing_h, ch.bearing.height);
|
||||||
|
}
|
||||||
|
|
||||||
|
float first_char_bearing_w = characters[(int)text[0]].bearing.width;
|
||||||
|
|
||||||
|
int c = 0;
|
||||||
|
int x = 0;
|
||||||
|
while (text[c] != '\0') {
|
||||||
|
Character ch = characters[(int)text[c]];
|
||||||
|
|
||||||
|
// subtract the bearing width of the first character to remove the extra space
|
||||||
|
// at the start of the text and move every char to the left by that width
|
||||||
|
float xpos = (x + (ch.bearing.width - first_char_bearing_w)) * scale;
|
||||||
|
|
||||||
|
float ypos = (text_size.height - ch.bearing.height - (text_size.height - max_bearing_h)) * scale;
|
||||||
|
Vec2f final_pos = { xpos, ypos };
|
||||||
|
|
||||||
|
float w = (ch.size.width * scale);
|
||||||
|
float h = (ch.size.height * scale);
|
||||||
|
|
||||||
|
apply_alignment(alignment, &final_pos, (Sizef){ text_size.width * scale, text_size.height * scale });
|
||||||
|
|
||||||
|
float vertices[6][4] = {
|
||||||
|
// top left tri
|
||||||
|
{final_pos.x, final_pos.y + h, 0.0, 1.0},
|
||||||
|
{final_pos.x, final_pos.y, 0.0, 0.0},
|
||||||
|
{final_pos.x + w, final_pos.y, 1.0, 0.0},
|
||||||
|
|
||||||
|
// bottom right tri
|
||||||
|
{final_pos.x, final_pos.y + h, 0.0, 1.0},
|
||||||
|
{final_pos.x + w, final_pos.y, 1.0, 0.0},
|
||||||
|
{final_pos.x + w, final_pos.y + h, 1.0, 1.0},
|
||||||
|
};
|
||||||
|
|
||||||
|
glBindTexture(GL_TEXTURE_2D, ch.texture_id);
|
||||||
|
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, font_vbo);
|
||||||
|
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
|
||||||
|
glBindBuffer(GL_ARRAY_BUFFER, 0);
|
||||||
|
|
||||||
|
glDrawArrays(GL_TRIANGLES, 0, 6);
|
||||||
|
|
||||||
|
x += (ch.advance >> 6);
|
||||||
|
c++;
|
||||||
|
}
|
||||||
|
|
||||||
|
glBindVertexArray(0);
|
||||||
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* enum Element { */
|
||||||
|
/* Rect, */
|
||||||
|
/* Circle, */
|
||||||
|
/* }; */
|
||||||
|
|
||||||
|
/* struct UIElement { */
|
||||||
|
/* Vec2 pos; */
|
||||||
|
/* Size size; */
|
||||||
|
/* Color *color; */
|
||||||
|
/* enum Element type; */
|
||||||
|
/* }; */
|
||||||
|
|
||||||
|
/* struct UIText { */
|
||||||
|
/* Vec2 pos; */
|
||||||
|
/* float scale; */
|
||||||
|
/* Color *color; */
|
||||||
|
/* const char* text; */
|
||||||
|
/* }; */
|
||||||
|
|
||||||
|
/* struct UIElement *create_element(Vec2 pos, Size size, Color *color, enum Element type) { */
|
||||||
|
/* struct UIElement *element = malloc(sizeof(struct UIElement)); */
|
||||||
|
/* element->pos = pos; */
|
||||||
|
/* element->size = size; */
|
||||||
|
/* element->color = color; */
|
||||||
|
/* element->type = type; */
|
||||||
|
/* return element; */
|
||||||
|
/* } */
|
||||||
|
|
||||||
@@ -0,0 +1,86 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
|
||||||
|
#include "helper.h"
|
||||||
|
|
||||||
|
typedef struct Size {
|
||||||
|
int width;
|
||||||
|
int height;
|
||||||
|
} Size;
|
||||||
|
|
||||||
|
typedef struct Sizef {
|
||||||
|
float width;
|
||||||
|
float height;
|
||||||
|
} Sizef;
|
||||||
|
|
||||||
|
typedef struct Vec2 {
|
||||||
|
int x;
|
||||||
|
int y;
|
||||||
|
} Vec2;
|
||||||
|
|
||||||
|
typedef struct Vec2f {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
} Vec2f;
|
||||||
|
|
||||||
|
typedef struct Color {
|
||||||
|
float r;
|
||||||
|
float g;
|
||||||
|
float b;
|
||||||
|
float a;
|
||||||
|
} Color;
|
||||||
|
|
||||||
|
typedef struct Character {
|
||||||
|
unsigned int texture_id;
|
||||||
|
Size size;
|
||||||
|
Size bearing;
|
||||||
|
unsigned int advance;
|
||||||
|
} Character;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
bool should_quit;
|
||||||
|
Color clear_color;
|
||||||
|
Size window_size;
|
||||||
|
|
||||||
|
Matrix4x4 projection;
|
||||||
|
} Context;
|
||||||
|
|
||||||
|
typedef enum Alignment {
|
||||||
|
ALIGN_TOP_LEFT,
|
||||||
|
ALIGN_TOP_CENTER,
|
||||||
|
ALIGN_TOP_RIGHT,
|
||||||
|
ALIGN_LEFT_CENTER,
|
||||||
|
ALIGN_CENTER,
|
||||||
|
ALIGN_RIGHT_CENTER,
|
||||||
|
ALIGN_BOTTOM_LEFT,
|
||||||
|
ALIGN_BOTTOM_CENTER,
|
||||||
|
ALIGN_BOTTOM_RIGHT,
|
||||||
|
} Alignment;
|
||||||
|
|
||||||
|
typedef enum UIConstraint {
|
||||||
|
UI_CONSTRAINT_FIXED,
|
||||||
|
UI_CONSTRAINT_RELATIVE,
|
||||||
|
UI_CONSTRAINT_RELATIVE_PIXELS,
|
||||||
|
UI_CONSTRAINT_ASPECT_RATIO,
|
||||||
|
} UIConstraint;
|
||||||
|
|
||||||
|
typedef struct UIConstraints {
|
||||||
|
float x;
|
||||||
|
float y;
|
||||||
|
float width;
|
||||||
|
float height;
|
||||||
|
} UIConstraints;
|
||||||
|
|
||||||
|
int init_zephr(const char* font_path, const char* window_title, Size window_size, Color *clear_color);
|
||||||
|
void deinit_zephr();
|
||||||
|
bool zephr_should_quit();
|
||||||
|
void zephr_swap_buffers();
|
||||||
|
Size zephr_get_window_size();
|
||||||
|
void set_x_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
||||||
|
void set_y_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
||||||
|
void set_width_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
||||||
|
void set_height_constraint(UIConstraints *constraints, float value, UIConstraint type);
|
||||||
|
void draw_quad(UIConstraints constraints, Color *color, Alignment align);
|
||||||
|
void draw_text(const char* text, float scale, Vec2f pos, Color *color, Alignment align);
|
||||||
|
Sizef calculate_text_size(const char *text, float scale);
|
||||||
@@ -4,12 +4,10 @@
|
|||||||
|
|
||||||
#include <glad/glx.h>
|
#include <glad/glx.h>
|
||||||
|
|
||||||
static const uint win_width = 900;
|
|
||||||
static const uint win_height = 900;
|
|
||||||
static bool fullscreen = false;
|
static bool fullscreen = false;
|
||||||
|
|
||||||
Colormap colormap;
|
Colormap colormap;
|
||||||
GLXContext context;
|
GLXContext glx_context;
|
||||||
|
|
||||||
void resize_x11_window(Display *display, Window window) {
|
void resize_x11_window(Display *display, Window window) {
|
||||||
XWindowAttributes win_attrs;
|
XWindowAttributes win_attrs;
|
||||||
@@ -17,7 +15,7 @@ void resize_x11_window(Display *display, Window window) {
|
|||||||
glViewport(0, 0, win_attrs.width, win_attrs.height);
|
glViewport(0, 0, win_attrs.width, win_attrs.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
int init_x11(Display **display, Window *window) {
|
int init_x11(Display **display, Window *window, const char* title, int window_width, int window_height) {
|
||||||
*display = XOpenDisplay(NULL);
|
*display = XOpenDisplay(NULL);
|
||||||
|
|
||||||
if (display == NULL) {
|
if (display == NULL) {
|
||||||
@@ -36,12 +34,12 @@ int init_x11(Display **display, Window *window) {
|
|||||||
StructureNotifyMask | ButtonPressMask;
|
StructureNotifyMask | ButtonPressMask;
|
||||||
attributes.colormap = colormap;
|
attributes.colormap = colormap;
|
||||||
|
|
||||||
*window = XCreateWindow(*display, root, 0, 0, win_width, win_height, 0,
|
*window = XCreateWindow(*display, root, 0, 0, window_width, window_height, 0,
|
||||||
DefaultDepth(*display, screen), InputOutput, visual,
|
DefaultDepth(*display, screen), InputOutput, visual,
|
||||||
CWColormap | CWEventMask, &attributes);
|
CWColormap | CWEventMask, &attributes);
|
||||||
|
|
||||||
XMapWindow(*display, *window);
|
XMapWindow(*display, *window);
|
||||||
XStoreName(*display, *window, "Cudoku");
|
XStoreName(*display, *window, title);
|
||||||
|
|
||||||
if (!window) {
|
if (!window) {
|
||||||
printf("Failed to create window\n");
|
printf("Failed to create window\n");
|
||||||
@@ -74,15 +72,15 @@ int init_x11(Display **display, Window *window) {
|
|||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
context = glXCreateContextAttribsARB(*display, fbc[0], NULL, 1,
|
glx_context = glXCreateContextAttribsARB(*display, fbc[0], NULL, 1,
|
||||||
context_attributes);
|
context_attributes);
|
||||||
|
|
||||||
if (!context) {
|
if (!glx_context) {
|
||||||
printf("Failed to create GLX context\n");
|
printf("Failed to create GLX context\n");
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
glXMakeCurrent(*display, *window, context);
|
glXMakeCurrent(*display, *window, glx_context);
|
||||||
|
|
||||||
int gl_version = gladLoaderLoadGL();
|
int gl_version = gladLoaderLoadGL();
|
||||||
|
|
||||||
@@ -108,7 +106,7 @@ int init_x11(Display **display, Window *window) {
|
|||||||
|
|
||||||
void close_x11(Display **display, Window *window) {
|
void close_x11(Display **display, Window *window) {
|
||||||
glXMakeCurrent(*display, 0, 0);
|
glXMakeCurrent(*display, 0, 0);
|
||||||
glXDestroyContext(*display, context);
|
glXDestroyContext(*display, glx_context);
|
||||||
|
|
||||||
XDestroyWindow(*display, *window);
|
XDestroyWindow(*display, *window);
|
||||||
XFreeColormap(*display, colormap);
|
XFreeColormap(*display, colormap);
|
||||||
|
|||||||
@@ -2,7 +2,7 @@
|
|||||||
|
|
||||||
#include <X11/Xlib.h>
|
#include <X11/Xlib.h>
|
||||||
|
|
||||||
void resize_x11_window(Display *display, Window window);
|
int init_x11(Display **display, Window *window, const char* title, int window_width, int window_height);
|
||||||
int init_x11(Display **display, Window *window);
|
|
||||||
void close_x11(Display **display, Window *window);
|
void close_x11(Display **display, Window *window);
|
||||||
|
void resize_x11_window(Display *display, Window window);
|
||||||
void toggle_fullscreen(Display *display, Window window);
|
void toggle_fullscreen(Display *display, Window window);
|
||||||
|
|||||||
Reference in New Issue
Block a user