mirror of
https://github.com/IllusionMan1212/cudoku.git
synced 2026-10-24 02:12:25 +00:00
finish refactor
This commit is contained in:
@@ -1,7 +1,7 @@
|
|||||||
BIN=cudoku
|
BIN=cudoku
|
||||||
CC=gcc
|
CC=gcc
|
||||||
CFLAGS=-Wall -Wextra -O3 -pedantic -g `pkg-config --cflags freetype2` -I3rdparty/glad/include -I3rdparty/stb -I3rdparty/fmod/include
|
CFLAGS=-Wall -Wextra -Werror -Wfloat-conversion -Wimplicit-fallthrough -pedantic -g `pkg-config --cflags freetype2` -I3rdparty/glad/include -I3rdparty/stb -I3rdparty/fmod/include
|
||||||
OBJ=main.o x11.o cudoku.o shader.o text.o audio.o timer.o ui.o zephr.o zephr_math.o 3rdparty/glad/src/gl.o 3rdparty/glad/src/glx.o 3rdparty/stb/stb.o
|
OBJ=main.o cudoku.o core.o shader.o text.o audio.o timer.o ui.o zephr.o zephr_math.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/stb/stb_ds.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/stb/stb_ds.h 3rdparty/fmod/include/fmod.h
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
|
Before Width: | Height: | Size: 4.5 KiB |
@@ -0,0 +1,33 @@
|
|||||||
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
|
|
||||||
|
void _core_assert_failed(const char* cond, const char* file, int line, const char* message, ...) {
|
||||||
|
fprintf(stderr, "assertion failed: %s\nmessage: ", cond);
|
||||||
|
|
||||||
|
va_list va_args;
|
||||||
|
va_start(va_args, message);
|
||||||
|
vfprintf(stderr, message, va_args);
|
||||||
|
va_end(va_args);
|
||||||
|
|
||||||
|
fprintf(stderr, "\nfile: %s:%u\n", file, line);
|
||||||
|
/* char* stacktrace = core_get_stacktrace(); */
|
||||||
|
/* fprintf(stderr, "stacktrace:\n%s\n\n", stacktrace); */
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
_Noreturn uintptr_t _core_abort(const char* file, int line, const char* message, ...) {
|
||||||
|
fprintf(stderr, "abort: ");
|
||||||
|
|
||||||
|
va_list va_args;
|
||||||
|
va_start(va_args, message);
|
||||||
|
vfprintf(stderr, message, va_args);
|
||||||
|
va_end(va_args);
|
||||||
|
|
||||||
|
fprintf(stderr, "\nfile: %s:%u\n", file, line);
|
||||||
|
/* char* stacktrace = core_get_stacktrace(); */
|
||||||
|
/* fprintf(stderr, "stacktrace:\n%s\n\n", stacktrace); */
|
||||||
|
abort();
|
||||||
|
}
|
||||||
@@ -0,0 +1,126 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#ifdef __GNUC__
|
||||||
|
#define CORE_LIKELY(expr) __builtin_expect((expr), 1)
|
||||||
|
#define CORE_UNLIKELY(expr) __builtin_expect((expr), 0)
|
||||||
|
#else
|
||||||
|
#define CORE_LIKELY(expr) expr
|
||||||
|
#define CORE_UNLIKELY(expr) expr
|
||||||
|
#endif
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Number and Pointer Utilities
|
||||||
|
//
|
||||||
|
//
|
||||||
|
///////////////////////////
|
||||||
|
|
||||||
|
#define CORE_MIN(a, b) (((a) < (b)) ? (a) : (b))
|
||||||
|
#define CORE_MAX(a, b) (((a) > (b)) ? (a) : (b))
|
||||||
|
#define CORE_CLAMP(v, min, max) (((v) > (max)) ? (max) : ((v) < (min)) ? : (min) : (v))
|
||||||
|
#define CORE_UNUSED(expr) ((void)(expr))
|
||||||
|
|
||||||
|
// align must be a power of 2
|
||||||
|
#define CORE_INT_ROUND_UP_ALIGN(i, align) (((i) + ((align) - )) & ~((align) - 1))
|
||||||
|
// align must be a power of 2
|
||||||
|
#define CORE_INT_ROUND_DOWN_ALIGN(i, align) ((i) & ~((align) - 1))
|
||||||
|
|
||||||
|
#define CORE_ARRAY_COUNT(array) (sizeof(array) / sizeof(*(array)))
|
||||||
|
#define CORE_IS_POWER_OF_TWO_OR_ZERO(v) (((v) & ((v) - 1)) == 0)
|
||||||
|
#define CORE_IS_POWER_OF_TWO(v) (((v) != 0) && (((v) & ((v) - 1)) == 0))
|
||||||
|
#define CORE_PTR_ADD(ptr, by) (void*)((uintptr_t)(ptr) + (uintptr_t)(by))
|
||||||
|
#define CORE_PTR_SUB(ptr, by) (void*)((uintptr_t)(ptr) - (uintptr_t)(by))
|
||||||
|
#define CORE_PTR_DIFF(to, from) ((char*)(to) - (char*)(from))
|
||||||
|
// aling must be a power of 2
|
||||||
|
#define CORE_PTR_ROUND_UP_ALIGN(ptr, align) ((void*)CORE_INT_ROUND_UP_ALIGN((uintptr_t)(ptr), (uintptr_t)(align)))
|
||||||
|
// aling must be a power of 2
|
||||||
|
#define CORE_PTR_ROUND_DOWN_ALIGN(ptr, align) ((void*)CORE_INT_ROUND_DOWN_ALIGN((uintptr_t)(ptr), (uintptr_t)(align)))
|
||||||
|
#define CORE_ZERO_ELMT(ptr) memset(ptr, 0, sizeof(*(ptr)))
|
||||||
|
#define CORE_ONE_ELMT(ptr) memset(ptr, 0xff, sizeof(*(ptr)))
|
||||||
|
#define CORE_ZERO_ELMT_MANY(ptr, elmts_count) memset(ptr, 0, sizeof(*(ptr)) * (elmts_count))
|
||||||
|
#define CORE_ONE_ELMT_MANY(ptr, elmts_count) memset(ptr, 0xff, sizeof(*(ptr)) * (elmts_count))
|
||||||
|
#define CORE_ZERO_ARRAY(array) memset(array, 0, sizeof(array))
|
||||||
|
#define CORE_ONE_ARRAY(array) memset(array, 0xff, sizeof(array))
|
||||||
|
#define CORE_COPY_ARRAY(dst, src) memcpy(dst, src, sizeof(dst))
|
||||||
|
#define CORE_COPY_ELMT_MANY(dst, src, elmts_count) memcpy(dst, src, sizeof(*(dst)) * (elmts_count))
|
||||||
|
#define CORE_COPY_OVERLAP_ELMT_MANY(dst, src, elmts_count) memmove(dst, src, sizeof(*(dst)) * (elmts_count))
|
||||||
|
#define CORE_CMP_ARRAY(a, b) (memcmp(a, b, sizeof(a)) == 0)
|
||||||
|
#define CORE_CMP_ELMT(a, b) (memcmp(a, b, sizeof(*(a))) == 0)
|
||||||
|
#define CORE_CMP_ELMT_MANY(a, b, elmts_count) (memcmp(a, b, sizeof(*(a)) * elmts_count) == 0)
|
||||||
|
|
||||||
|
#define CORE_DIV_ROUND_UP(a, b) (((a) / (b)) + ((a) % (b) != 0))
|
||||||
|
|
||||||
|
typedef uint8_t u8;
|
||||||
|
typedef uint16_t u16;
|
||||||
|
typedef uint32_t u32;
|
||||||
|
typedef uint64_t u64;
|
||||||
|
|
||||||
|
typedef int8_t i8;
|
||||||
|
typedef int16_t i16;
|
||||||
|
typedef int32_t i32;
|
||||||
|
typedef int64_t i64;
|
||||||
|
|
||||||
|
typedef uint64_t uptr;
|
||||||
|
typedef int64_t sptr;
|
||||||
|
|
||||||
|
typedef float f32;
|
||||||
|
typedef double f64;
|
||||||
|
|
||||||
|
#define U8_MAX UINT8_MAX
|
||||||
|
#define U16_MAX UINT16_MAX
|
||||||
|
#define U32_MAX UINT32_MAX
|
||||||
|
#define U64_MAX UINT64_MAX
|
||||||
|
#define UPTR_MAX UINT64_MAX
|
||||||
|
|
||||||
|
#define I8_MIN INT8_MIN
|
||||||
|
#define I8_MAX INT8_MAX
|
||||||
|
#define I16_MIN INT16_MIN
|
||||||
|
#define I16_MAX INT16_MAX
|
||||||
|
#define I32_MIN INT32_MIN
|
||||||
|
#define I32_MAX INT32_MAX
|
||||||
|
#define I64_MIN INT64_MIN
|
||||||
|
#define I64_MAX INT64_MAX
|
||||||
|
|
||||||
|
///////////////////////////
|
||||||
|
//
|
||||||
|
//
|
||||||
|
// Abort and Assertions
|
||||||
|
//
|
||||||
|
//
|
||||||
|
///////////////////////////
|
||||||
|
|
||||||
|
#ifndef CORE_ENABLE_DEBUG_ASSERTIONS
|
||||||
|
#define CORE_ENABLE_DEBUG_ASSERTIONS 1
|
||||||
|
#endif
|
||||||
|
#ifndef CORE_ABORT
|
||||||
|
#define CORE_ABORT(...) _core_abort(__FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef CORE_ASSERT
|
||||||
|
#define CORE_ASSERT(cond, ...) if (CORE_UNLIKELY(!(cond))) _core_assert_failed(#cond, __FILE__, __LINE__, __VA_ARGS__)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if CORE_ENABLE_DEBUG_ASSERTIONS
|
||||||
|
#define CORE_DEBUG_ASSERT CORE_ASSERT
|
||||||
|
#else
|
||||||
|
#define CORE_DEBUG_ASSERT(cond, ...) (void)(cond)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define CORE_DEBUG_ASSERT_NON_ZERO(value) CORE_DEBUG_ASSERT(value, "'%s' must be a non zero value", #value)
|
||||||
|
#define CORE_DEBUG_ASSERT_ARRAY_BOUNDS(idx, count) (((idx) < (count)) ? (idx) : CORE_ABORT("idx %d out of bounds for array of size %d", idx, count))
|
||||||
|
#define CORE_DEBUG_ASSERT_ARRAY_RESIZE(count, cap) CORE_DEBUG_ASSERT((count) <= (cap), "cannot resize array to count '%zu' when it has a capacity of '%zu'", count, cap)
|
||||||
|
#define CORE_DEBUG_ASSERT_POWER_OF_TWO(v) CORE_DEBUG_ASSERT(CORE_IS_POWER_OF_TWO(v), #v "must be a power of two but got '%zu'", v)
|
||||||
|
|
||||||
|
#define CORE_BREAKPOINT() asm ("int $3") // x86 specific breakpoint instruction
|
||||||
|
|
||||||
|
void _core_assert_failed(const char* cond, const char* file, int line, const char* message, ...);
|
||||||
|
_Noreturn uintptr_t _core_abort(const char* file, int line, const char* message, ...);
|
||||||
|
|
||||||
|
/* static inline bool core_bitset_is_set(u64* bitset, uptr bit_idx) { */
|
||||||
|
/* return (bool)(bitset[bit_idx >> 6] & (1 << (bit_idx & 63))); */
|
||||||
|
/* } */
|
||||||
|
|
||||||
@@ -4,9 +4,7 @@
|
|||||||
#include <math.h>
|
#include <math.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
|
||||||
#include <glad/gl.h>
|
#include "core.h"
|
||||||
#include "3rdparty/stb/stb_image.h"
|
|
||||||
|
|
||||||
#include "cudoku.h"
|
#include "cudoku.h"
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
@@ -43,7 +41,7 @@ void draw_win(Cudoku *game) {
|
|||||||
|
|
||||||
char time_text[64];
|
char time_text[64];
|
||||||
|
|
||||||
float time_elapsed = game->win_time - game->timer.start + game->timer.elapsed;
|
double time_elapsed = game->win_time - game->timer.start + game->timer.elapsed;
|
||||||
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);
|
||||||
|
|
||||||
UIConstraints constraints = {0};
|
UIConstraints constraints = {0};
|
||||||
@@ -203,8 +201,8 @@ void toggle_check(Cudoku *game) {
|
|||||||
void do_selection(Cudoku *game, int x, int y) {
|
void do_selection(Cudoku *game, int x, int y) {
|
||||||
if (game->has_won || game->timer.state == TIMER_PAUSED) return;
|
if (game->has_won || game->timer.state == TIMER_PAUSED) return;
|
||||||
|
|
||||||
int cell_x = floor(x / 100.f);
|
int cell_x = (int)floor(x / 100.f);
|
||||||
int cell_y = floor(y / 100.f);
|
int cell_y = (int)floor(y / 100.f);
|
||||||
|
|
||||||
if (cell_x < 0 || cell_x > 8 || cell_y < 0 || cell_y > 8) {
|
if (cell_x < 0 || cell_x > 8 || cell_y < 0 || cell_y > 8) {
|
||||||
game->should_draw_selection = false;
|
game->should_draw_selection = false;
|
||||||
@@ -306,8 +304,8 @@ void get_candidates(Cell board[9][9], int row, int col, int candidates[], int *s
|
|||||||
}
|
}
|
||||||
|
|
||||||
// check box
|
// check box
|
||||||
int box_row = floor(row / 3.f) * 3;
|
int box_row = (int)floor(row / 3.f) * 3;
|
||||||
int box_col = floor(col / 3.f) * 3;
|
int box_col = (int)floor(col / 3.f) * 3;
|
||||||
for (int i = box_row; i < box_row + 3; i++) {
|
for (int i = box_row; i < box_row + 3; i++) {
|
||||||
for (int j = box_col; j < box_col + 3; j++) {
|
for (int j = box_col; j < box_col + 3; j++) {
|
||||||
if (board[i][j].value != 0) {
|
if (board[i][j].value != 0) {
|
||||||
@@ -360,8 +358,8 @@ bool backtracker(Cudoku *game, int start_row, int start_col) {
|
|||||||
|
|
||||||
// try every candidate until we find one that uniquely solves the board.
|
// try every candidate until we find one that uniquely solves the board.
|
||||||
while (num_candidates) {
|
while (num_candidates) {
|
||||||
uint rand_idx = rand() % num_candidates;
|
u32 rand_idx = rand() % num_candidates;
|
||||||
uint candidate = candidates[rand_idx];
|
u32 candidate = candidates[rand_idx];
|
||||||
remove_arr_element(candidates, rand_idx, num_candidates);
|
remove_arr_element(candidates, rand_idx, num_candidates);
|
||||||
num_candidates--;
|
num_candidates--;
|
||||||
game->board[start_row][start_col].value = candidate;
|
game->board[start_row][start_col].value = candidate;
|
||||||
@@ -433,7 +431,7 @@ void remove_numbers(Cudoku *game) {
|
|||||||
int rand_idx = rand() % filled_cells_size;
|
int rand_idx = rand() % filled_cells_size;
|
||||||
int cell = filled_cells[rand_idx];
|
int cell = filled_cells[rand_idx];
|
||||||
remove_arr_element(filled_cells, rand_idx, filled_cells_size--);
|
remove_arr_element(filled_cells, rand_idx, filled_cells_size--);
|
||||||
int removed_row = floor(cell / 9.f);
|
int removed_row = (int)floor(cell / 9.f);
|
||||||
int removed_col = cell % 9;
|
int removed_col = cell % 9;
|
||||||
|
|
||||||
Cell removed_cell = game->board[removed_row][removed_col];
|
Cell removed_cell = game->board[removed_row][removed_col];
|
||||||
@@ -481,7 +479,7 @@ void generate_random_board(Cudoku *game) {
|
|||||||
size = 9;
|
size = 9;
|
||||||
}
|
}
|
||||||
|
|
||||||
const int k = floor(row / 3.f) * 3;
|
const int k = (int)floor(row / 3.f) * 3;
|
||||||
for (int j = k; j < k + 3; j++) {
|
for (int j = k; j < k + 3; j++) {
|
||||||
int rand_idx = rand() % size;
|
int rand_idx = rand() % size;
|
||||||
int num = digits[rand_idx];
|
int num = digits[rand_idx];
|
||||||
@@ -527,8 +525,8 @@ bool toggle_help(Cudoku *game) {
|
|||||||
|
|
||||||
void draw_help(Timer *timer) {
|
void draw_help(Timer *timer) {
|
||||||
int const text_padding = 10;
|
int const text_padding = 10;
|
||||||
float const help_font_size = 24.f;
|
int const help_font_size = 24;
|
||||||
float const closing_in_font_size = 18.f;
|
int const closing_in_font_size = 18;
|
||||||
Color const bg_color = {
|
Color const bg_color = {
|
||||||
.r = 0.f,
|
.r = 0.f,
|
||||||
.g = 0.f,
|
.g = 0.f,
|
||||||
@@ -548,16 +546,16 @@ void draw_help(Timer *timer) {
|
|||||||
.a = 255.0f,
|
.a = 255.0f,
|
||||||
};
|
};
|
||||||
|
|
||||||
int overlay_height = 0;
|
float overlay_height = 0;
|
||||||
int overlay_width = 0;
|
float overlay_width = 0;
|
||||||
int total_help_texts_height = 10;
|
float total_help_texts_height = 10;
|
||||||
|
|
||||||
for (int i = 0; i < HELP_TEXT_SIZE; i++) {
|
for (int i = 0; i < HELP_TEXT_SIZE; i++) {
|
||||||
Sizef text_size = calculate_text_size(help_texts[i], help_font_size);
|
Sizef text_size = calculate_text_size(help_texts[i], help_font_size);
|
||||||
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 = CORE_MAX(overlay_width, text_size.width + text_padding * 2);
|
||||||
}
|
}
|
||||||
Size size = {.width = overlay_width, .height = overlay_height + text_padding * 2};
|
Sizef size = {.width = overlay_width, .height = overlay_height + text_padding * 2};
|
||||||
UIConstraints constraints = {0};
|
UIConstraints constraints = {0};
|
||||||
set_width_constraint(&constraints, size.width, UI_CONSTRAINT_FIXED);
|
set_width_constraint(&constraints, size.width, UI_CONSTRAINT_FIXED);
|
||||||
set_height_constraint(&constraints, size.height, UI_CONSTRAINT_FIXED);
|
set_height_constraint(&constraints, size.height, UI_CONSTRAINT_FIXED);
|
||||||
@@ -592,30 +590,31 @@ void draw_help(Timer *timer) {
|
|||||||
void draw_timer(Timer *timer) {
|
void draw_timer(Timer *timer) {
|
||||||
if (timer->state == TIMER_STOPPED) return;
|
if (timer->state == TIMER_STOPPED) return;
|
||||||
|
|
||||||
char timer_text[64];
|
const int font_size = 32;
|
||||||
Color text_color = {
|
const Color text_color = {
|
||||||
.r = 66.0f,
|
.r = 66.0f,
|
||||||
.g = 92.0f,
|
.g = 92.0f,
|
||||||
.b = 124.0f,
|
.b = 124.0f,
|
||||||
.a = 255.0f,
|
.a = 255.0f,
|
||||||
};
|
};
|
||||||
Color bg_color = {
|
const Color bg_color = {
|
||||||
.r = 0.0f,
|
.r = 0.0f,
|
||||||
.g = 0.0f,
|
.g = 0.0f,
|
||||||
.b = 0.0f,
|
.b = 0.0f,
|
||||||
.a = 25.0f,
|
.a = 25.0f,
|
||||||
};
|
};
|
||||||
float font_size = 32.f;
|
const Alignment alignment = ALIGN_BOTTOM_RIGHT;
|
||||||
Alignment alignment = ALIGN_BOTTOM_RIGHT;
|
|
||||||
|
|
||||||
float elapsed = timer_elapsed(timer);
|
char timer_text[64];
|
||||||
|
|
||||||
|
double elapsed = timer_elapsed(timer);
|
||||||
|
|
||||||
if (timer->state == TIMER_PAUSED) {
|
if (timer->state == TIMER_PAUSED) {
|
||||||
// if the timer is paused, we want to show the time at which it was paused
|
// if the timer is paused, we want to show the time at which it was paused
|
||||||
elapsed = timer->elapsed;
|
elapsed = timer->elapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
int minutes = elapsed / 60;
|
int minutes = (int)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);
|
||||||
|
|||||||
@@ -2,9 +2,8 @@
|
|||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
|
||||||
#include "shader.h"
|
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
#include "ui.h"
|
#include "zephr_math.h"
|
||||||
|
|
||||||
typedef struct Cell {
|
typedef struct Cell {
|
||||||
int value;
|
int value;
|
||||||
@@ -21,7 +20,7 @@ typedef struct Cudoku {
|
|||||||
bool should_draw_help;
|
bool should_draw_help;
|
||||||
Timer help_timer;
|
Timer help_timer;
|
||||||
Timer timer;
|
Timer timer;
|
||||||
float win_time;
|
double win_time;
|
||||||
} Cudoku;
|
} Cudoku;
|
||||||
|
|
||||||
void draw_selection_box(int x, int y, const Color color);
|
void draw_selection_box(int x, int y, const Color color);
|
||||||
|
|||||||
@@ -1,34 +1,39 @@
|
|||||||
#include <math.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
|
#include <stdlib.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <time.h>
|
#include <time.h>
|
||||||
|
|
||||||
#include <glad/glx.h>
|
#include <X11/Xlib.h>
|
||||||
#include <stb_image.h>
|
|
||||||
|
|
||||||
#include "cudoku.h"
|
|
||||||
#include "audio.h"
|
#include "audio.h"
|
||||||
|
#include "cudoku.h"
|
||||||
|
#include "timer.h"
|
||||||
#include "zephr.h"
|
#include "zephr.h"
|
||||||
|
#include "zephr_math.h"
|
||||||
|
|
||||||
#define DEBUG 1
|
#define DEBUG 1
|
||||||
|
|
||||||
extern Display *display;
|
|
||||||
const char *font_path = "assets/fonts/Rubik/Rubik-VariableFont_wght.ttf";
|
const char *font_path = "assets/fonts/Rubik/Rubik-VariableFont_wght.ttf";
|
||||||
const char *title = "Cudoku";
|
const char *title = "Cudoku";
|
||||||
|
|
||||||
void usage() {
|
void usage() {
|
||||||
printf("Usage: cudoku [OPTION]\n\n");
|
printf("Usage: cudoku [OPTION]\n\n");
|
||||||
printf(" %-20s%-20s", "-h, --help", "prints this help message\n");
|
printf(" %-30s%-20s", "-h, --help", "prints this help message\n");
|
||||||
printf(" %-20s%-20s", "-f, --font FONT", "use a custom font file to render text\n");
|
printf(" %-30s%-20s", "-f, --font <path_to_font>", "use a custom font file to render text\n");
|
||||||
}
|
}
|
||||||
|
|
||||||
void handle_keypress(XEvent xev, Cudoku *game) {
|
void handle_keypress(ZephrEvent e, Cudoku *game) {
|
||||||
if (XLookupKeysym(&xev.xkey, 0) == XK_r) {
|
if (e.key.code == ZEPHR_KEYCODE_R) {
|
||||||
reset_board(game);
|
reset_board(game);
|
||||||
} else if (
|
} else if (
|
||||||
xev.xkey.state & ControlMask &&
|
e.key.code == ZEPHR_KEYCODE_ESCAPE ||
|
||||||
xev.xkey.state & Mod1Mask &&
|
((e.key.mods & ZEPHR_KEY_MOD_CTRL) && e.key.code == ZEPHR_KEYCODE_Q)
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_w) {
|
) {
|
||||||
|
zephr_quit();
|
||||||
|
} else if (
|
||||||
|
e.key.mods & (ZEPHR_KEY_MOD_CTRL | ZEPHR_KEY_MOD_SHIFT) &&
|
||||||
|
e.key.code == ZEPHR_KEYCODE_W) {
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
printf("DEBUG: Ctrl + Shift + W pressed. Winning game\n");
|
printf("DEBUG: Ctrl + Shift + W pressed. Winning game\n");
|
||||||
|
|
||||||
@@ -41,42 +46,44 @@ void handle_keypress(XEvent xev, Cudoku *game) {
|
|||||||
|
|
||||||
audio_play_win();
|
audio_play_win();
|
||||||
#endif
|
#endif
|
||||||
} else if (XLookupKeysym(&xev.xkey, 0) >= XK_0 && XLookupKeysym(&xev.xkey, 0) <= XK_9) {
|
} else if (e.key.code >= ZEPHR_KEYCODE_1 && e.key.code <= ZEPHR_KEYCODE_9) {
|
||||||
set_selected_number(game, XLookupKeysym(&xev.xkey, 0) - XK_0);
|
set_selected_number(game, e.key.code - ZEPHR_KEYCODE_1 + 1);
|
||||||
} else if (XLookupKeysym(&xev.xkey, 0) == XK_BackSpace ||
|
} else if (e.key.code == ZEPHR_KEYCODE_0) {
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_Delete) {
|
set_selected_number(game, 0);
|
||||||
|
} else if (e.key.code == ZEPHR_KEYCODE_BACKSPACE ||
|
||||||
|
e.key.code == ZEPHR_KEYCODE_DELETE) {
|
||||||
set_selected_number(game, 0);
|
set_selected_number(game, 0);
|
||||||
} else if (
|
} else if (
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_Left ||
|
e.key.code == ZEPHR_KEYCODE_LEFT ||
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_a ||
|
e.key.code == ZEPHR_KEYCODE_A ||
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_h) {
|
e.key.code == ZEPHR_KEYCODE_H) {
|
||||||
move_selection(game, -1, 0);
|
move_selection(game, -1, 0);
|
||||||
} else if (
|
} else if (
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_Right ||
|
e.key.code == ZEPHR_KEYCODE_RIGHT ||
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_d ||
|
e.key.code == ZEPHR_KEYCODE_D ||
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_l) {
|
e.key.code == ZEPHR_KEYCODE_L) {
|
||||||
move_selection(game, 1, 0);
|
move_selection(game, 1, 0);
|
||||||
} else if (
|
} else if (
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_Up ||
|
e.key.code == ZEPHR_KEYCODE_UP ||
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_w ||
|
e.key.code == ZEPHR_KEYCODE_W ||
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_k) {
|
e.key.code == ZEPHR_KEYCODE_K) {
|
||||||
move_selection(game, 0, -1);
|
move_selection(game, 0, -1);
|
||||||
} else if (
|
} else if (
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_Down ||
|
e.key.code == ZEPHR_KEYCODE_DOWN ||
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_s ||
|
e.key.code == ZEPHR_KEYCODE_S ||
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_j) {
|
e.key.code == ZEPHR_KEYCODE_J) {
|
||||||
move_selection(game, 0, 1);
|
move_selection(game, 0, 1);
|
||||||
} else if (
|
} else if (
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_Return ||
|
e.key.code == ZEPHR_KEYCODE_ENTER ||
|
||||||
XLookupKeysym(&xev.xkey, 0) == XK_space) {
|
e.key.code == ZEPHR_KEYCODE_SPACE) {
|
||||||
toggle_selection(game);
|
toggle_selection(game);
|
||||||
} else if (XLookupKeysym(&xev.xkey, 0) == XK_n) {
|
} else if (e.key.code == ZEPHR_KEYCODE_N) {
|
||||||
generate_random_board(game);
|
generate_random_board(game);
|
||||||
} else if (XLookupKeysym(&xev.xkey, 0) == XK_c) {
|
} else if (e.key.code == ZEPHR_KEYCODE_C) {
|
||||||
toggle_check(game);
|
toggle_check(game);
|
||||||
} else if (XLookupKeysym(&xev.xkey, 0) == XK_p) {
|
} else if (e.key.code == ZEPHR_KEYCODE_P) {
|
||||||
pause_game(game);
|
pause_game(game);
|
||||||
} else if (XLookupKeysym(&xev.xkey, 0) == XK_F1) {
|
} else if (e.key.code == ZEPHR_KEYCODE_F1) {
|
||||||
if (!toggle_help(game)) {
|
if (!toggle_help(game)) {
|
||||||
timer_stop(&game->help_timer);
|
timer_stop(&game->help_timer);
|
||||||
}
|
}
|
||||||
@@ -92,9 +99,9 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 1; i < argc; i++) {
|
for (int i = 1; i < argc; i++) {
|
||||||
char *flag = argv[i];
|
char *option = argv[i];
|
||||||
|
|
||||||
if (strcmp(flag, "-f") == 0 || strcmp(flag, "--font") == 0) {
|
if (strcmp(option, "-f") == 0 || strcmp(option, "--font") == 0) {
|
||||||
if (i + 1 < argc) {
|
if (i + 1 < argc) {
|
||||||
font_path = argv[i + 1];
|
font_path = argv[i + 1];
|
||||||
i++;
|
i++;
|
||||||
@@ -105,9 +112,8 @@ int main(int argc, char *argv[]) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Color clear_color = {0.0f, 0.0f, 0.0f, 1.f};
|
|
||||||
Size window_size = {900, 900};
|
Size window_size = {900, 900};
|
||||||
int res = init_zephr(font_path, title, window_size, &clear_color);
|
int res = init_zephr(font_path, title, window_size);
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
printf("[ERROR]: could not initialize zephr\n");
|
printf("[ERROR]: could not initialize zephr\n");
|
||||||
return 1;
|
return 1;
|
||||||
@@ -124,31 +130,30 @@ int main(int argc, char *argv[]) {
|
|||||||
timer_start(&game.timer, 0.0f);
|
timer_start(&game.timer, 0.0f);
|
||||||
|
|
||||||
while (!zephr_should_quit()) {
|
while (!zephr_should_quit()) {
|
||||||
while (XPending(display)) {
|
ZephrEvent event;
|
||||||
XEvent xev;
|
|
||||||
XNextEvent(display, &xev);
|
|
||||||
|
|
||||||
if (xev.type == KeyPress) {
|
while (zephr_iter_events(&event)) {
|
||||||
if (XLookupKeysym(&xev.xkey, 0) == XK_Escape ||
|
switch (event.type) {
|
||||||
(XLookupKeysym(&xev.xkey, 0) == XK_q && xev.xkey.state & ControlMask)) {
|
case ZEPHR_EVENT_UNKNOWN:
|
||||||
|
printf("[WARN]: Unknown event\n");
|
||||||
|
break;
|
||||||
|
case ZEPHR_EVENT_KEY_PRESSED:
|
||||||
|
handle_keypress(event, &game);
|
||||||
|
break;
|
||||||
|
case ZEPHR_EVENT_MOUSE_BUTTON_PRESSED:
|
||||||
|
if (event.mouse.button == ZEPHR_MOUSE_BUTTON_LEFT) {
|
||||||
|
do_selection(&game, event.mouse.position.x, event.mouse.position.y);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case ZEPHR_EVENT_WINDOW_CLOSED:
|
||||||
zephr_quit();
|
zephr_quit();
|
||||||
break;
|
break;
|
||||||
} else {
|
default:
|
||||||
handle_keypress(xev, &game);
|
case ZEPHR_EVENT_WINDOW_RESIZED:
|
||||||
}
|
case ZEPHR_EVENT_KEY_RELEASED:
|
||||||
} else if (xev.type == ButtonPress) {
|
break;
|
||||||
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_board(&game, window_size);
|
||||||
draw_timer(&game.timer);
|
draw_timer(&game.timer);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
#include <glad/gl.h>
|
#include <glad/gl.h>
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
|
|
||||||
void read_shader_file(const char *path, char **buf) {
|
void read_shader_file(const char *path, char **buf) {
|
||||||
@@ -14,13 +15,15 @@ void read_shader_file(const char *path, char **buf) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fseek(fp, 0, SEEK_END);
|
fseek(fp, 0, SEEK_END);
|
||||||
long filesize = ftell(fp);
|
u64 filesize = ftell(fp);
|
||||||
fseek(fp, 0, SEEK_SET);
|
fseek(fp, 0, SEEK_SET);
|
||||||
|
|
||||||
*buf = malloc(filesize + 1);
|
*buf = malloc(filesize + 1);
|
||||||
(*buf)[filesize] = '\0';
|
(*buf)[filesize] = '\0';
|
||||||
|
|
||||||
fread(*buf, filesize, 1, fp);
|
u64 read = fread(*buf, filesize, 1, fp);
|
||||||
|
|
||||||
|
CORE_UNUSED(read);
|
||||||
|
|
||||||
fclose(fp);
|
fclose(fp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -4,16 +4,14 @@
|
|||||||
|
|
||||||
#include <ft2build.h>
|
#include <ft2build.h>
|
||||||
#include FT_FREETYPE_H
|
#include FT_FREETYPE_H
|
||||||
#include <freetype/ftmm.h>
|
|
||||||
#include <glad/glx.h>
|
#include <glad/glx.h>
|
||||||
|
|
||||||
#include "zephr.h"
|
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
|
#include "zephr.h"
|
||||||
|
|
||||||
#define FONT_PIXEL_SIZE 64
|
#define FONT_PIXEL_SIZE 64
|
||||||
|
|
||||||
extern Context zephr_context;
|
|
||||||
Shader font_shader;
|
Shader font_shader;
|
||||||
unsigned int font_vao;
|
unsigned int font_vao;
|
||||||
unsigned int font_instance_vbo;
|
unsigned int font_instance_vbo;
|
||||||
@@ -33,7 +31,7 @@ void extend_glyph_instance_list(GlyphInstanceList *dest, GlyphInstanceList *src)
|
|||||||
dest->size += src->size;
|
dest->size += src->size;
|
||||||
}
|
}
|
||||||
|
|
||||||
void new_glyph_instance_list(GlyphInstanceList *list, uint capacity) {
|
void new_glyph_instance_list(GlyphInstanceList *list, u32 capacity) {
|
||||||
list->size = 0;
|
list->size = 0;
|
||||||
list->capacity = capacity;
|
list->capacity = capacity;
|
||||||
list->data = malloc(list->capacity * sizeof(GlyphInstance));
|
list->data = malloc(list->capacity * sizeof(GlyphInstance));
|
||||||
@@ -89,8 +87,8 @@ int init_freetype(const char* font_path) {
|
|||||||
/* FT_UInt glyph_idx; */
|
/* FT_UInt glyph_idx; */
|
||||||
/* FT_ULong c = FT_Get_First_Char(face, &glyph_idx); */
|
/* FT_ULong c = FT_Get_First_Char(face, &glyph_idx); */
|
||||||
|
|
||||||
uint tex_width = 0, tex_height = 0;
|
u32 tex_width = 0, tex_height = 0;
|
||||||
for (uint i = 32; i < 128; i++) {
|
for (u32 i = 32; i < 128; i++) {
|
||||||
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
|
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
|
||||||
printf("[ERROR]: failed to load glyph for char '0x%x'\n", i);
|
printf("[ERROR]: failed to load glyph for char '0x%x'\n", i);
|
||||||
}
|
}
|
||||||
@@ -98,12 +96,12 @@ int init_freetype(const char* font_path) {
|
|||||||
/* FT_Render_Glyph(face->glyph, FT_RENDER_MODE_SDF); */
|
/* FT_Render_Glyph(face->glyph, FT_RENDER_MODE_SDF); */
|
||||||
|
|
||||||
tex_width += face->glyph->bitmap.width + 1;
|
tex_width += face->glyph->bitmap.width + 1;
|
||||||
tex_height = max(tex_height, face->glyph->bitmap.rows);
|
tex_height = CORE_MAX(tex_height, face->glyph->bitmap.rows);
|
||||||
}
|
}
|
||||||
|
|
||||||
char *pixels = (char *)calloc(tex_width * tex_height, 1);
|
char *pixels = (char *)calloc(tex_width * tex_height, 1);
|
||||||
|
|
||||||
for (uint i = 32; i < 128; i++) {
|
for (u32 i = 32; i < 128; i++) {
|
||||||
/* while (glyph_idx) { */
|
/* while (glyph_idx) { */
|
||||||
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
|
if (FT_Load_Char(face, i, FT_LOAD_RENDER)) {
|
||||||
printf("[ERROR]: failed to load glyph for char '0x%x'\n", i);
|
printf("[ERROR]: failed to load glyph for char '0x%x'\n", i);
|
||||||
@@ -118,8 +116,8 @@ int init_freetype(const char* font_path) {
|
|||||||
pen_y += (1 + (face->size->metrics.height >> 6));
|
pen_y += (1 + (face->size->metrics.height >> 6));
|
||||||
}
|
}
|
||||||
|
|
||||||
for (uint row = 0; row < bmp->rows; row++) {
|
for (u32 row = 0; row < bmp->rows; row++) {
|
||||||
for (uint col = 0; col < bmp->width; col++) {
|
for (u32 col = 0; col < bmp->width; col++) {
|
||||||
int x = pen_x + col;
|
int x = pen_x + col;
|
||||||
int y = pen_y + row;
|
int y = pen_y + row;
|
||||||
pixels[y * tex_width + x] = bmp->buffer[row * bmp->pitch + col];
|
pixels[y * tex_width + x] = bmp->buffer[row * bmp->pitch + col];
|
||||||
@@ -146,7 +144,7 @@ int init_freetype(const char* font_path) {
|
|||||||
character.size = (Size){ .width = face->glyph->bitmap.width, .height = face->glyph->bitmap.rows };
|
character.size = (Size){ .width = face->glyph->bitmap.width, .height = face->glyph->bitmap.rows };
|
||||||
character.bearing = (Size){ .width = face->glyph->bitmap_left, .height = face->glyph->bitmap_top };
|
character.bearing = (Size){ .width = face->glyph->bitmap_left, .height = face->glyph->bitmap_top };
|
||||||
|
|
||||||
zephr_context.font.characters[i] = character;
|
zephr_ctx.font.characters[i] = character;
|
||||||
|
|
||||||
pen_x += bmp->width + 1;
|
pen_x += bmp->width + 1;
|
||||||
|
|
||||||
@@ -165,7 +163,7 @@ int init_freetype(const char* font_path) {
|
|||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
|
||||||
|
|
||||||
zephr_context.font.atlas_texture_id = texture;
|
zephr_ctx.font.atlas_texture_id = texture;
|
||||||
|
|
||||||
glBindTexture(GL_TEXTURE_2D, 0);
|
glBindTexture(GL_TEXTURE_2D, 0);
|
||||||
|
|
||||||
@@ -178,8 +176,8 @@ int init_freetype(const char* font_path) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int init_fonts(const char *font_path) {
|
int init_fonts(const char *font_path) {
|
||||||
uint font_vbo;
|
u32 font_vbo;
|
||||||
uint font_ebo;
|
u32 font_ebo;
|
||||||
|
|
||||||
int res = init_freetype(font_path);
|
int res = init_freetype(font_path);
|
||||||
if (res != 0) {
|
if (res != 0) {
|
||||||
@@ -247,7 +245,7 @@ int init_fonts(const char *font_path) {
|
|||||||
for (int j = 0; j < 4; j++) {
|
for (int j = 0; j < 4; j++) {
|
||||||
char text[32];
|
char text[32];
|
||||||
snprintf(text, 32, "texcoords[%d]", (i - 32) * 4 + j);
|
snprintf(text, 32, "texcoords[%d]", (i - 32) * 4 + j);
|
||||||
set_vec2f(font_shader, text, zephr_context.font.characters[i].tex_coords[j].x, zephr_context.font.characters[i].tex_coords[j].y);
|
set_vec2f(font_shader, text, zephr_ctx.font.characters[i].tex_coords[j].x, zephr_ctx.font.characters[i].tex_coords[j].y);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -266,12 +264,12 @@ Sizef calculate_text_size(const char *text, int font_size) {
|
|||||||
|
|
||||||
// NOTE: I don't like looping through the characters twice, but it's fine for now
|
// NOTE: I don't like looping through the characters twice, but it's fine for now
|
||||||
for (int i = 0; text[i] != '\0'; i++) {
|
for (int i = 0; text[i] != '\0'; i++) {
|
||||||
Character ch = zephr_context.font.characters[(uint)text[i]];
|
Character ch = zephr_ctx.font.characters[(u32)text[i]];
|
||||||
max_bearing_h = max(max_bearing_h, ch.bearing.height);
|
max_bearing_h = CORE_MAX(max_bearing_h, ch.bearing.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; text[i] != '\0'; i++) {
|
for (u64 i = 0; text[i] != '\0'; i++) {
|
||||||
Character ch = zephr_context.font.characters[(uint)text[i]];
|
Character ch = zephr_ctx.font.characters[(u32)text[i]];
|
||||||
w += ch.advance / 64;
|
w += ch.advance / 64;
|
||||||
|
|
||||||
// remove bearing of first character
|
// remove bearing of first character
|
||||||
@@ -289,7 +287,7 @@ Sizef calculate_text_size(const char *text, int font_size) {
|
|||||||
w -= (ch.bearing.width);
|
w -= (ch.bearing.width);
|
||||||
}
|
}
|
||||||
|
|
||||||
h = max(h, max_bearing_h - ch.bearing.height + ch.size.height);
|
h = CORE_MAX(h, max_bearing_h - ch.bearing.height + ch.size.height);
|
||||||
}
|
}
|
||||||
size.width = (float)w * scale;
|
size.width = (float)w * scale;
|
||||||
size.height = (float)h * scale;
|
size.height = (float)h * scale;
|
||||||
@@ -302,7 +300,7 @@ GlyphInstanceList get_glyph_instance_list_from_text(const char *text, int font_s
|
|||||||
if (color) {
|
if (color) {
|
||||||
text_color = (Color){ color->r / 255.f, color->g / 255.f, color->b / 255.f, color->a / 255.f };
|
text_color = (Color){ color->r / 255.f, color->g / 255.f, color->b / 255.f, color->a / 255.f };
|
||||||
}
|
}
|
||||||
set_mat4f(font_shader, "projection", (float *)zephr_context.projection.m);
|
set_mat4f(font_shader, "projection", (float *)zephr_ctx.projection.m);
|
||||||
|
|
||||||
Vec2f pos = { 0.f, 0.f };
|
Vec2f pos = { 0.f, 0.f };
|
||||||
Sizef size = {0};
|
Sizef size = {0};
|
||||||
@@ -326,11 +324,11 @@ GlyphInstanceList get_glyph_instance_list_from_text(const char *text, int font_s
|
|||||||
|
|
||||||
int max_bearing_h = 0;
|
int max_bearing_h = 0;
|
||||||
for (int i = 0; (i < text[i]) != '\0'; i++) {
|
for (int i = 0; (i < text[i]) != '\0'; i++) {
|
||||||
Character ch = zephr_context.font.characters[(int)text[i]];
|
Character ch = zephr_ctx.font.characters[(int)text[i]];
|
||||||
max_bearing_h = max(max_bearing_h, ch.bearing.height);
|
max_bearing_h = CORE_MAX(max_bearing_h, ch.bearing.height);
|
||||||
}
|
}
|
||||||
|
|
||||||
float first_char_bearing_w = zephr_context.font.characters[(int)text[0]].bearing.width;
|
float first_char_bearing_w = zephr_ctx.font.characters[(int)text[0]].bearing.width;
|
||||||
|
|
||||||
GlyphInstanceList glyph_instance_list;
|
GlyphInstanceList glyph_instance_list;
|
||||||
new_glyph_instance_list(&glyph_instance_list, 16);
|
new_glyph_instance_list(&glyph_instance_list, 16);
|
||||||
@@ -342,7 +340,7 @@ GlyphInstanceList get_glyph_instance_list_from_text(const char *text, int font_s
|
|||||||
int c = 0;
|
int c = 0;
|
||||||
int x = 0;
|
int x = 0;
|
||||||
while (text[c] != '\0') {
|
while (text[c] != '\0') {
|
||||||
Character ch = zephr_context.font.characters[(int)text[c]];
|
Character ch = zephr_ctx.font.characters[(int)text[c]];
|
||||||
// subtract the bearing width of the first character to remove the extra space
|
// 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
|
// 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));
|
float xpos = (x + (ch.bearing.width - first_char_bearing_w));
|
||||||
@@ -352,7 +350,7 @@ GlyphInstanceList get_glyph_instance_list_from_text(const char *text, int font_s
|
|||||||
.position = (Vec4f){xpos, ypos, ch.size.width, ch.size.height},
|
.position = (Vec4f){xpos, ypos, ch.size.width, ch.size.height},
|
||||||
.tex_coords_index = (int)text[c] - 32,
|
.tex_coords_index = (int)text[c] - 32,
|
||||||
.color = text_color,
|
.color = text_color,
|
||||||
.model = {0},
|
.model = {{0}},
|
||||||
};
|
};
|
||||||
|
|
||||||
memcpy(instance.model, model.m, sizeof(float[4][4]));
|
memcpy(instance.model, model.m, sizeof(float[4][4]));
|
||||||
@@ -370,7 +368,7 @@ void draw_text(const char* text, int font_size, UIConstraints constraints, const
|
|||||||
GlyphInstanceList glyph_instance_list = get_glyph_instance_list_from_text(text, font_size, constraints, color, alignment);
|
GlyphInstanceList glyph_instance_list = get_glyph_instance_list_from_text(text, font_size, constraints, color, alignment);
|
||||||
|
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, zephr_context.font.atlas_texture_id);
|
glBindTexture(GL_TEXTURE_2D, zephr_ctx.font.atlas_texture_id);
|
||||||
glBindVertexArray(font_vao);
|
glBindVertexArray(font_vao);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
|
||||||
@@ -386,7 +384,7 @@ void draw_text(const char* text, int font_size, UIConstraints constraints, const
|
|||||||
|
|
||||||
void draw_text_batch(GlyphInstanceList *batch) {
|
void draw_text_batch(GlyphInstanceList *batch) {
|
||||||
glActiveTexture(GL_TEXTURE0);
|
glActiveTexture(GL_TEXTURE0);
|
||||||
glBindTexture(GL_TEXTURE_2D, zephr_context.font.atlas_texture_id);
|
glBindTexture(GL_TEXTURE_2D, zephr_ctx.font.atlas_texture_id);
|
||||||
glBindVertexArray(font_vao);
|
glBindVertexArray(font_vao);
|
||||||
|
|
||||||
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
|
glBindBuffer(GL_ARRAY_BUFFER, font_instance_vbo);
|
||||||
|
|||||||
@@ -1,6 +1,8 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include "core.h"
|
||||||
#include "ui.h"
|
#include "ui.h"
|
||||||
|
#include "zephr_math.h"
|
||||||
|
|
||||||
typedef struct Character {
|
typedef struct Character {
|
||||||
Size size;
|
Size size;
|
||||||
@@ -9,10 +11,10 @@ typedef struct Character {
|
|||||||
Vec2f tex_coords[4]; // the 4 corners of the character quad
|
Vec2f tex_coords[4]; // the 4 corners of the character quad
|
||||||
} Character;
|
} Character;
|
||||||
|
|
||||||
typedef struct ZephFont {
|
typedef struct ZephrFont {
|
||||||
Character characters[128];
|
Character characters[128];
|
||||||
unsigned int atlas_texture_id;
|
unsigned int atlas_texture_id;
|
||||||
} ZephFont;
|
} ZephrFont;
|
||||||
|
|
||||||
typedef struct TextInstance {
|
typedef struct TextInstance {
|
||||||
Vec4f position;
|
Vec4f position;
|
||||||
@@ -27,7 +29,7 @@ typedef struct GlyphInstanceList {
|
|||||||
int capacity;
|
int capacity;
|
||||||
} GlyphInstanceList;
|
} GlyphInstanceList;
|
||||||
|
|
||||||
void new_glyph_instance_list(GlyphInstanceList *list, uint capacity);
|
void new_glyph_instance_list(GlyphInstanceList *list, u32 capacity);
|
||||||
int init_fonts(const char *font_path);
|
int init_fonts(const char *font_path);
|
||||||
Sizef calculate_text_size(const char *text, int font_size);
|
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);
|
void draw_text(const char* text, int font_size, UIConstraints constraints, const Color *color, Alignment alignment);
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
#include <sys/time.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include "timer.h"
|
#include "timer.h"
|
||||||
|
|
||||||
struct timeval start_time;
|
struct timeval start_time;
|
||||||
@@ -36,11 +39,11 @@ void timer_reset(Timer *timer) {
|
|||||||
timer->state = TIMER_RUNNING;
|
timer->state = TIMER_RUNNING;
|
||||||
}
|
}
|
||||||
|
|
||||||
float timer_remaining(Timer *timer) {
|
double timer_remaining(Timer *timer) {
|
||||||
return timer->duration - (get_time() - timer->start);
|
return timer->duration - (get_time() - timer->start);
|
||||||
}
|
}
|
||||||
|
|
||||||
float timer_elapsed(Timer *timer) {
|
double timer_elapsed(Timer *timer) {
|
||||||
return get_time() - timer->start + timer->elapsed;
|
return get_time() - timer->start + timer->elapsed;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1,8 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <sys/time.h>
|
|
||||||
|
|
||||||
typedef enum TimerState {
|
typedef enum TimerState {
|
||||||
TIMER_RUNNING,
|
TIMER_RUNNING,
|
||||||
@@ -11,8 +9,8 @@ typedef enum TimerState {
|
|||||||
} TimerState;
|
} TimerState;
|
||||||
|
|
||||||
typedef struct Timer {
|
typedef struct Timer {
|
||||||
float start;
|
double start;
|
||||||
float elapsed;
|
double elapsed;
|
||||||
float duration;
|
float duration;
|
||||||
TimerState state;
|
TimerState state;
|
||||||
} Timer;
|
} Timer;
|
||||||
@@ -23,7 +21,7 @@ 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_stop(Timer *timer);
|
||||||
void timer_reset(Timer *timer);
|
void timer_reset(Timer *timer);
|
||||||
float timer_remaining(Timer *timer);
|
double timer_remaining(Timer *timer);
|
||||||
float timer_elapsed(Timer *timer);
|
double timer_elapsed(Timer *timer);
|
||||||
void timer_pause(Timer *timer);
|
void timer_pause(Timer *timer);
|
||||||
void timer_resume(Timer *timer);
|
void timer_resume(Timer *timer);
|
||||||
|
|||||||
@@ -1,33 +0,0 @@
|
|||||||
zephr stuff
|
|
||||||
- "premade" (but also customizable) ui elements (buttons, text boxes, etc) with instanced rendering
|
|
||||||
- border decorations for shapes (maybe. or maybe only for ui elements)
|
|
||||||
- some kind of ui layout/hierarchy system (for later, when we actually need it)
|
|
||||||
- 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)
|
|
||||||
- unicode support removed for the foreseeable future
|
|
||||||
- [x] atlas texture for text glyphs (this means we only load in one texture for all text)
|
|
||||||
- [x] better estimation of atlas width and height (currently the generated atlas texture
|
|
||||||
has a lot of empty space (over 50% of the texture's height))
|
|
||||||
- ended up just looping over the ascii glyphs and finding the max width and height
|
|
||||||
|
|
||||||
- SDF generation allowing for better text scaling (slower but visually better)
|
|
||||||
- SDF is too slow if we want to support unicode. it's acceptably fast for ascii only though.
|
|
||||||
- An alternative is to use MSDF at a much lower pixel height (e.g 16) which results in
|
|
||||||
better scaling than SDF (almost perfect) and is fast enough to include unicode.
|
|
||||||
- Another alternative is using a pre-baked SDF texture atlas. This is the fastest
|
|
||||||
but it's also the least flexible because we can't load arbitrary fonts
|
|
||||||
- Maybe also rendering text as vector using bezier curves. Sounds like a lot of work though.
|
|
||||||
|
|
||||||
Will probably end up using MSDF (if I can get it to work with C lol)
|
|
||||||
|
|
||||||
- [x] instanced rendering for text (this means we only have to do one draw call for all text)
|
|
||||||
running into problems. we got the positions to instance correctly but the texture coordinates
|
|
||||||
are more difficult to work with because we can't just send a texcoord per vertex per instance
|
|
||||||
- Ended up passing hardcoded texcoords of all glyphs to the shader using a uniform array which allows us to render infinite
|
|
||||||
instances of text in one draw call without exceeding any buffer limits. Of course this does mean that if we were to support
|
|
||||||
unicode we'd have to make the uniform array bigger and its size dynamic. So unicode is dropped for now
|
|
||||||
|
|
||||||
@@ -1,23 +1,17 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <math.h>
|
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
#include <glad/glx.h>
|
#include <glad/glx.h>
|
||||||
|
|
||||||
#include "cudoku.h"
|
|
||||||
#include "shader.h"
|
#include "shader.h"
|
||||||
#include "ui.h"
|
|
||||||
#include "x11.h"
|
|
||||||
#include "zephr.h"
|
#include "zephr.h"
|
||||||
|
|
||||||
extern Context zephr_context;
|
|
||||||
Shader ui_shader;
|
Shader ui_shader;
|
||||||
unsigned int ui_vao;
|
unsigned int ui_vao;
|
||||||
unsigned int ui_vbo;
|
unsigned int ui_vbo;
|
||||||
|
|
||||||
int init_ui(const char* font_path, Size window_size) {
|
int init_ui(const char* font_path, Size window_size) {
|
||||||
zephr_context.window.size = window_size;
|
zephr_ctx.window.size = window_size;
|
||||||
zephr_context.projection = orthographic_projection_2d(0.f, window_size.width, window_size.height, 0.f);
|
zephr_ctx.projection = orthographic_projection_2d(0.f, window_size.width, window_size.height, 0.f);
|
||||||
|
|
||||||
int res = init_fonts(font_path);
|
int res = init_fonts(font_path);
|
||||||
if (res == -1) {
|
if (res == -1) {
|
||||||
@@ -54,7 +48,7 @@ void set_x_constraint(UIConstraints *constraints, float value, UIConstraint type
|
|||||||
constraints->x = value;
|
constraints->x = value;
|
||||||
break;
|
break;
|
||||||
case UI_CONSTRAINT_RELATIVE:
|
case UI_CONSTRAINT_RELATIVE:
|
||||||
constraints->x = (value * zephr_context.window.size.width);
|
constraints->x = (value * zephr_ctx.window.size.width);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -68,7 +62,7 @@ void set_y_constraint(UIConstraints *constraints, float value, UIConstraint type
|
|||||||
constraints->y = value;
|
constraints->y = value;
|
||||||
break;
|
break;
|
||||||
case UI_CONSTRAINT_RELATIVE:
|
case UI_CONSTRAINT_RELATIVE:
|
||||||
constraints->y = (value * zephr_context.window.size.height);
|
constraints->y = (value * zephr_ctx.window.size.height);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -79,10 +73,10 @@ void set_width_constraint(UIConstraints *constraints, float value, UIConstraint
|
|||||||
constraints->width = value;
|
constraints->width = value;
|
||||||
break;
|
break;
|
||||||
case UI_CONSTRAINT_RELATIVE:
|
case UI_CONSTRAINT_RELATIVE:
|
||||||
constraints->width = (value * zephr_context.window.size.width);
|
constraints->width = (value * zephr_ctx.window.size.width);
|
||||||
break;
|
break;
|
||||||
case UI_CONSTRAINT_RELATIVE_PIXELS:
|
case UI_CONSTRAINT_RELATIVE_PIXELS:
|
||||||
constraints->width = zephr_context.window.size.width / (float)zephr_context.screen_size.width * value;
|
constraints->width = zephr_ctx.window.size.width / (float)zephr_ctx.screen_size.width * value;
|
||||||
break;
|
break;
|
||||||
case UI_CONSTRAINT_ASPECT_RATIO:
|
case UI_CONSTRAINT_ASPECT_RATIO:
|
||||||
constraints->width = constraints->height * value;
|
constraints->width = constraints->height * value;
|
||||||
@@ -96,10 +90,10 @@ void set_height_constraint(UIConstraints *constraints, float value, UIConstraint
|
|||||||
constraints->height = value;
|
constraints->height = value;
|
||||||
break;
|
break;
|
||||||
case UI_CONSTRAINT_RELATIVE:
|
case UI_CONSTRAINT_RELATIVE:
|
||||||
constraints->height = (value * zephr_context.window.size.height);
|
constraints->height = (value * zephr_ctx.window.size.height);
|
||||||
break;
|
break;
|
||||||
case UI_CONSTRAINT_RELATIVE_PIXELS:
|
case UI_CONSTRAINT_RELATIVE_PIXELS:
|
||||||
constraints->height = zephr_context.window.size.height / (float)zephr_context.screen_size.height * value;
|
constraints->height = zephr_ctx.window.size.height / (float)zephr_ctx.screen_size.height * value;
|
||||||
break;
|
break;
|
||||||
case UI_CONSTRAINT_ASPECT_RATIO:
|
case UI_CONSTRAINT_ASPECT_RATIO:
|
||||||
constraints->height = constraints->width * value;
|
constraints->height = constraints->width * value;
|
||||||
@@ -123,36 +117,36 @@ void apply_alignment(Alignment align, Vec2f *pos, Sizef size) {
|
|||||||
pos->y = pos->y;
|
pos->y = pos->y;
|
||||||
break;
|
break;
|
||||||
case ALIGN_TOP_CENTER:
|
case ALIGN_TOP_CENTER:
|
||||||
pos->x += zephr_context.window.size.width / 2.f - size.width / 2.f;
|
pos->x += zephr_ctx.window.size.width / 2.f - size.width / 2.f;
|
||||||
pos->y = pos->y;
|
pos->y = pos->y;
|
||||||
break;
|
break;
|
||||||
case ALIGN_TOP_RIGHT:
|
case ALIGN_TOP_RIGHT:
|
||||||
pos->x += zephr_context.window.size.width - size.width;
|
pos->x += zephr_ctx.window.size.width - size.width;
|
||||||
pos->y = pos->y;
|
pos->y = pos->y;
|
||||||
break;
|
break;
|
||||||
case ALIGN_BOTTOM_LEFT:
|
case ALIGN_BOTTOM_LEFT:
|
||||||
pos->x = pos->x;
|
pos->x = pos->x;
|
||||||
pos->y += zephr_context.window.size.height - size.height;
|
pos->y += zephr_ctx.window.size.height - size.height;
|
||||||
break;
|
break;
|
||||||
case ALIGN_BOTTOM_CENTER:
|
case ALIGN_BOTTOM_CENTER:
|
||||||
pos->x += zephr_context.window.size.width / 2.f - size.width / 2.f;
|
pos->x += zephr_ctx.window.size.width / 2.f - size.width / 2.f;
|
||||||
pos->y += zephr_context.window.size.height - size.height;
|
pos->y += zephr_ctx.window.size.height - size.height;
|
||||||
break;
|
break;
|
||||||
case ALIGN_BOTTOM_RIGHT:
|
case ALIGN_BOTTOM_RIGHT:
|
||||||
pos->x += zephr_context.window.size.width - size.width;
|
pos->x += zephr_ctx.window.size.width - size.width;
|
||||||
pos->y += zephr_context.window.size.height - size.height;
|
pos->y += zephr_ctx.window.size.height - size.height;
|
||||||
break;
|
break;
|
||||||
case ALIGN_LEFT_CENTER:
|
case ALIGN_LEFT_CENTER:
|
||||||
pos->x = pos->x;
|
pos->x = pos->x;
|
||||||
pos->y += zephr_context.window.size.height / 2.f - size.height / 2.f;
|
pos->y += zephr_ctx.window.size.height / 2.f - size.height / 2.f;
|
||||||
break;
|
break;
|
||||||
case ALIGN_RIGHT_CENTER:
|
case ALIGN_RIGHT_CENTER:
|
||||||
pos->x += zephr_context.window.size.width - size.width;
|
pos->x += zephr_ctx.window.size.width - size.width;
|
||||||
pos->y += zephr_context.window.size.height / 2.f - size.height / 2.f;
|
pos->y += zephr_ctx.window.size.height / 2.f - size.height / 2.f;
|
||||||
break;
|
break;
|
||||||
case ALIGN_CENTER:
|
case ALIGN_CENTER:
|
||||||
pos->x += zephr_context.window.size.width / 2.f - size.width / 2.f;
|
pos->x += zephr_ctx.window.size.width / 2.f - size.width / 2.f;
|
||||||
pos->y += zephr_context.window.size.height / 2.f - size.height / 2.f;
|
pos->y += zephr_ctx.window.size.height / 2.f - size.height / 2.f;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -169,7 +163,7 @@ void draw_quad(UIConstraints constraints, const Color *color, float border_radiu
|
|||||||
set_float(ui_shader, "uiWidth", constraints.width);
|
set_float(ui_shader, "uiWidth", constraints.width);
|
||||||
set_float(ui_shader, "uiHeight", constraints.height);
|
set_float(ui_shader, "uiHeight", constraints.height);
|
||||||
set_float(ui_shader, "borderRadius", border_radius);
|
set_float(ui_shader, "borderRadius", border_radius);
|
||||||
set_mat4f(ui_shader, "projection", (float *)zephr_context.projection.m);
|
set_mat4f(ui_shader, "projection", (float *)zephr_ctx.projection.m);
|
||||||
|
|
||||||
Vec2f pos = { 0.f, 0.f };
|
Vec2f pos = { 0.f, 0.f };
|
||||||
Sizef size = { 0.f, 0.f };
|
Sizef size = { 0.f, 0.f };
|
||||||
@@ -228,7 +222,7 @@ void draw_triangle(UIConstraints constraints, const Color *color, Alignment alig
|
|||||||
} else {
|
} else {
|
||||||
set_vec4f(ui_shader, "aColor", 0.f, 0.f, 0.f, 1.f);
|
set_vec4f(ui_shader, "aColor", 0.f, 0.f, 0.f, 1.f);
|
||||||
}
|
}
|
||||||
set_mat4f(ui_shader, "projection", (float *)zephr_context.projection.m);
|
set_mat4f(ui_shader, "projection", (float *)zephr_ctx.projection.m);
|
||||||
|
|
||||||
Vec2f pos = { 0.f, 0.f };
|
Vec2f pos = { 0.f, 0.f };
|
||||||
Sizef size = { 0.f, 0.f };
|
Sizef size = { 0.f, 0.f };
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
#include <stdlib.h>
|
|
||||||
|
|
||||||
#include "zephr_math.h"
|
#include "zephr_math.h"
|
||||||
|
|
||||||
typedef enum Alignment {
|
typedef enum Alignment {
|
||||||
|
|||||||
@@ -1,186 +0,0 @@
|
|||||||
#include <stdbool.h>
|
|
||||||
#include <stdio.h>
|
|
||||||
#include <string.h>
|
|
||||||
|
|
||||||
#include <X11/Xatom.h>
|
|
||||||
#include <glad/glx.h>
|
|
||||||
|
|
||||||
Colormap colormap;
|
|
||||||
GLXContext glx_context;
|
|
||||||
|
|
||||||
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 x11_init(Display **display, Window *window, const char* title, int window_width, int window_height) {
|
|
||||||
*display = XOpenDisplay(NULL);
|
|
||||||
|
|
||||||
if (display == NULL) {
|
|
||||||
fprintf(stderr, "Cannot open display\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int screen = DefaultScreen(*display);
|
|
||||||
Window root = RootWindow(*display, screen);
|
|
||||||
Visual *visual = DefaultVisual(*display, screen);
|
|
||||||
|
|
||||||
colormap = XCreateColormap(*display, root, visual, AllocNone);
|
|
||||||
|
|
||||||
XSetWindowAttributes attributes;
|
|
||||||
attributes.event_mask = ExposureMask | KeyPressMask | KeyReleaseMask |
|
|
||||||
StructureNotifyMask | ButtonPressMask;
|
|
||||||
attributes.colormap = colormap;
|
|
||||||
|
|
||||||
*window = XCreateWindow(*display, root, 0, 0, window_width, window_height, 0,
|
|
||||||
DefaultDepth(*display, screen), InputOutput, visual,
|
|
||||||
CWColormap | CWEventMask, &attributes);
|
|
||||||
|
|
||||||
// hints to the WM that the window is a dialog window which makes it a floating
|
|
||||||
// window in titling WMs (only tested on DWM though)
|
|
||||||
Atom net_wm_window_type = XInternAtom(*display, "_NET_WM_WINDOW_TYPE", False);
|
|
||||||
Atom net_wm_window_type_dialog = XInternAtom(*display, "_NET_WM_WINDOW_TYPE_DIALOG", False);
|
|
||||||
XChangeProperty(*display, *window, net_wm_window_type, XA_ATOM, 32, PropModeReplace, (unsigned char*)&net_wm_window_type_dialog, 1);
|
|
||||||
|
|
||||||
XMapWindow(*display, *window);
|
|
||||||
XStoreName(*display, *window, title);
|
|
||||||
|
|
||||||
if (!window) {
|
|
||||||
printf("Failed to create window\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int glx_version = gladLoaderLoadGLX(*display, screen);
|
|
||||||
|
|
||||||
if (!glx_version) {
|
|
||||||
printf("Failed to load GLX\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
printf("Loaded GLX %d.%d\n",
|
|
||||||
GLAD_VERSION_MAJOR(glx_version), GLAD_VERSION_MINOR(glx_version));
|
|
||||||
|
|
||||||
GLint visual_attributes[] = {
|
|
||||||
GLX_RENDER_TYPE, GLX_RGBA_BIT,
|
|
||||||
GLX_DEPTH_SIZE, 24,
|
|
||||||
GLX_DOUBLEBUFFER, 1,
|
|
||||||
GLX_SAMPLES, 4, // MSAA
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
int num_fbc = 0;
|
|
||||||
GLXFBConfig *fbc =
|
|
||||||
glXChooseFBConfig(*display, screen, visual_attributes, &num_fbc);
|
|
||||||
|
|
||||||
GLint context_attributes[] = {
|
|
||||||
GLX_CONTEXT_MAJOR_VERSION_ARB, 3,
|
|
||||||
GLX_CONTEXT_MINOR_VERSION_ARB, 3,
|
|
||||||
GLX_CONTEXT_PROFILE_MASK_ARB, GLX_CONTEXT_CORE_PROFILE_BIT_ARB,
|
|
||||||
None
|
|
||||||
};
|
|
||||||
|
|
||||||
glx_context = glXCreateContextAttribsARB(*display, fbc[0], NULL, 1,
|
|
||||||
context_attributes);
|
|
||||||
|
|
||||||
if (!glx_context) {
|
|
||||||
printf("Failed to create GLX context\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
glXMakeCurrent(*display, *window, glx_context);
|
|
||||||
|
|
||||||
int gl_version = gladLoaderLoadGL();
|
|
||||||
|
|
||||||
if (!gl_version) {
|
|
||||||
printf("Failed to load GL\n");
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
printf("Loaded GL %d.%d\n",
|
|
||||||
GLAD_VERSION_MAJOR(gl_version), GLAD_VERSION_MINOR(gl_version));
|
|
||||||
|
|
||||||
XWindowAttributes win_attrs;
|
|
||||||
XGetWindowAttributes(*display, *window, &win_attrs);
|
|
||||||
|
|
||||||
glad_glXSwapIntervalEXT(*display, *window, 1);
|
|
||||||
// we enable blending for text
|
|
||||||
glEnable(GL_BLEND);
|
|
||||||
glEnable(GL_MULTISAMPLE);
|
|
||||||
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
|
|
||||||
glViewport(0, 0, win_attrs.width, win_attrs.height);
|
|
||||||
x11_resize_window(*display, *window);
|
|
||||||
|
|
||||||
XFree(fbc);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void x11_close(Display **display, Window *window) {
|
|
||||||
glXMakeCurrent(*display, 0, 0);
|
|
||||||
glXDestroyContext(*display, glx_context);
|
|
||||||
|
|
||||||
XDestroyWindow(*display, *window);
|
|
||||||
XFreeColormap(*display, colormap);
|
|
||||||
XCloseDisplay(*display);
|
|
||||||
|
|
||||||
gladLoaderUnloadGLX();
|
|
||||||
}
|
|
||||||
|
|
||||||
void go_fullscreen(Display *display, Window window)
|
|
||||||
{
|
|
||||||
XEvent xev;
|
|
||||||
Atom wm_state = XInternAtom(display, "_NET_WM_STATE", False);
|
|
||||||
Atom fullscreen = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", False);
|
|
||||||
memset(&xev, 0, sizeof(xev));
|
|
||||||
xev.type = ClientMessage;
|
|
||||||
xev.xclient.window = window;
|
|
||||||
xev.xclient.message_type = wm_state;
|
|
||||||
xev.xclient.format = 32;
|
|
||||||
xev.xclient.data.l[0] = 1; // _NET_WM_STATE_ADD
|
|
||||||
xev.xclient.data.l[1] = fullscreen;
|
|
||||||
xev.xclient.data.l[2] = 0;
|
|
||||||
XSendEvent(display, DefaultRootWindow(display), False,
|
|
||||||
SubstructureNotifyMask | SubstructureRedirectMask, &xev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void return_fullscreen(Display *display, Window window)
|
|
||||||
{
|
|
||||||
XEvent xev;
|
|
||||||
Atom wm_state = XInternAtom(display, "_NET_WM_STATE", False);
|
|
||||||
Atom fullscreen = XInternAtom(display, "_NET_WM_STATE_FULLSCREEN", False);
|
|
||||||
memset(&xev, 0, sizeof(xev));
|
|
||||||
xev.type = ClientMessage;
|
|
||||||
xev.xclient.window = window;
|
|
||||||
xev.xclient.message_type = wm_state;
|
|
||||||
xev.xclient.format = 32;
|
|
||||||
xev.xclient.data.l[0] = 0; // _NET_WM_STATE_REMOVE
|
|
||||||
xev.xclient.data.l[1] = fullscreen;
|
|
||||||
xev.xclient.data.l[2] = 0;
|
|
||||||
XSendEvent(display, DefaultRootWindow(display), False,
|
|
||||||
SubstructureNotifyMask | SubstructureRedirectMask, &xev);
|
|
||||||
}
|
|
||||||
|
|
||||||
void x11_toggle_fullscreen(bool fullscreen, Display *display, Window window) {
|
|
||||||
if (fullscreen) {
|
|
||||||
return_fullscreen(display, window);
|
|
||||||
} else {
|
|
||||||
go_fullscreen(display, window);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void x11_get_screen_size(Display *display, int *width, int *height) {
|
|
||||||
Screen *screen = DefaultScreenOfDisplay(display);
|
|
||||||
|
|
||||||
*width = screen->width;
|
|
||||||
*height = screen->height;
|
|
||||||
}
|
|
||||||
|
|
||||||
void x11_make_window_non_resizable(Display *display, Window window, int width, int height) {
|
|
||||||
XSizeHints *size_hints = XAllocSizeHints();
|
|
||||||
size_hints->flags = PMinSize | PMaxSize;
|
|
||||||
size_hints->min_width = width;
|
|
||||||
size_hints->min_height = height;
|
|
||||||
size_hints->max_width = width;
|
|
||||||
size_hints->max_height = height;
|
|
||||||
XSetWMNormalHints(display, window, size_hints);
|
|
||||||
XFree(size_hints);
|
|
||||||
}
|
|
||||||
@@ -1,12 +0,0 @@
|
|||||||
#pragma once
|
|
||||||
|
|
||||||
#include <stdbool.h>
|
|
||||||
|
|
||||||
#include <X11/Xlib.h>
|
|
||||||
|
|
||||||
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);
|
|
||||||
@@ -1,29 +1,375 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <stdbool.h>
|
#include <stdbool.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
#include <X11/XKBlib.h>
|
||||||
|
|
||||||
#include "text.h"
|
#include "text.h"
|
||||||
|
#include "zephr_math.h"
|
||||||
|
|
||||||
typedef struct ZephWindow {
|
typedef struct ZephrWindow {
|
||||||
Size size;
|
Size size;
|
||||||
bool is_fullscreen;
|
bool is_fullscreen;
|
||||||
} ZephWindow;
|
} ZephrWindow;
|
||||||
|
|
||||||
|
typedef enum ZephrEventType {
|
||||||
|
ZEPHR_EVENT_UNKNOWN,
|
||||||
|
ZEPHR_EVENT_KEY_PRESSED,
|
||||||
|
ZEPHR_EVENT_KEY_RELEASED,
|
||||||
|
ZEPHR_EVENT_MOUSE_BUTTON_PRESSED,
|
||||||
|
ZEPHR_EVENT_MOUSE_BUTTON_RELEASED,
|
||||||
|
ZEPHR_EVENT_MOUSE_SCROLL,
|
||||||
|
ZEPHR_EVENT_WINDOW_RESIZED,
|
||||||
|
ZEPHR_EVENT_WINDOW_CLOSED
|
||||||
|
} ZephrEventType;
|
||||||
|
|
||||||
|
typedef enum ZephrMouseScrollDirection {
|
||||||
|
ZEPHR_MOUSE_SCROLL_UP,
|
||||||
|
ZEPHR_MOUSE_SCROLL_DOWN,
|
||||||
|
} ZephrMouseScrollDirection;
|
||||||
|
|
||||||
|
typedef enum ZephrMouseButton {
|
||||||
|
ZEPHR_MOUSE_BUTTON_LEFT,
|
||||||
|
ZEPHR_MOUSE_BUTTON_RIGHT,
|
||||||
|
ZEPHR_MOUSE_BUTTON_MIDDLE,
|
||||||
|
ZEPHR_MOUSE_BUTTON_BACK,
|
||||||
|
ZEPHR_MOUSE_BUTTON_FORWARD,
|
||||||
|
ZEPHR_MOUSE_BUTTON_3,
|
||||||
|
ZEPHR_MOUSE_BUTTON_4,
|
||||||
|
ZEPHR_MOUSE_BUTTON_5,
|
||||||
|
ZEPHR_MOUSE_BUTTON_6,
|
||||||
|
ZEPHR_MOUSE_BUTTON_7,
|
||||||
|
} ZephrMouseButton;
|
||||||
|
|
||||||
|
|
||||||
|
typedef u16 ZephrScancode;
|
||||||
|
typedef u16 ZephrKeycode;
|
||||||
|
|
||||||
|
// these are actually scancodes as documented by the USB HID Usage Tables
|
||||||
|
// https://usb.org/sites/default/files/documents/hut1_12v2.pdf
|
||||||
|
enum {
|
||||||
|
ZEPHR_KEYCODE_NULL = 0,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_A = 4,
|
||||||
|
ZEPHR_KEYCODE_B = 5,
|
||||||
|
ZEPHR_KEYCODE_C = 6,
|
||||||
|
ZEPHR_KEYCODE_D = 7,
|
||||||
|
ZEPHR_KEYCODE_E = 8,
|
||||||
|
ZEPHR_KEYCODE_F = 9,
|
||||||
|
ZEPHR_KEYCODE_G = 10,
|
||||||
|
ZEPHR_KEYCODE_H = 11,
|
||||||
|
ZEPHR_KEYCODE_I = 12,
|
||||||
|
ZEPHR_KEYCODE_J = 13,
|
||||||
|
ZEPHR_KEYCODE_K = 14,
|
||||||
|
ZEPHR_KEYCODE_L = 15,
|
||||||
|
ZEPHR_KEYCODE_M = 16,
|
||||||
|
ZEPHR_KEYCODE_N = 17,
|
||||||
|
ZEPHR_KEYCODE_O = 18,
|
||||||
|
ZEPHR_KEYCODE_P = 19,
|
||||||
|
ZEPHR_KEYCODE_Q = 20,
|
||||||
|
ZEPHR_KEYCODE_R = 21,
|
||||||
|
ZEPHR_KEYCODE_S = 22,
|
||||||
|
ZEPHR_KEYCODE_T = 23,
|
||||||
|
ZEPHR_KEYCODE_U = 24,
|
||||||
|
ZEPHR_KEYCODE_V = 25,
|
||||||
|
ZEPHR_KEYCODE_W = 26,
|
||||||
|
ZEPHR_KEYCODE_X = 27,
|
||||||
|
ZEPHR_KEYCODE_Y = 28,
|
||||||
|
ZEPHR_KEYCODE_Z = 29,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_1 = 30,
|
||||||
|
ZEPHR_KEYCODE_2 = 31,
|
||||||
|
ZEPHR_KEYCODE_3 = 32,
|
||||||
|
ZEPHR_KEYCODE_4 = 33,
|
||||||
|
ZEPHR_KEYCODE_5 = 34,
|
||||||
|
ZEPHR_KEYCODE_6 = 35,
|
||||||
|
ZEPHR_KEYCODE_7 = 36,
|
||||||
|
ZEPHR_KEYCODE_8 = 37,
|
||||||
|
ZEPHR_KEYCODE_9 = 38,
|
||||||
|
ZEPHR_KEYCODE_0 = 39,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_ENTER = 40,
|
||||||
|
ZEPHR_KEYCODE_ESCAPE = 41,
|
||||||
|
ZEPHR_KEYCODE_BACKSPACE = 42,
|
||||||
|
ZEPHR_KEYCODE_TAB = 43,
|
||||||
|
ZEPHR_KEYCODE_SPACE = 44,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_MINUS = 45,
|
||||||
|
ZEPHR_KEYCODE_EQUALS = 46,
|
||||||
|
ZEPHR_KEYCODE_LEFT_BRACKET = 47,
|
||||||
|
ZEPHR_KEYCODE_RIGHT_BRACKET = 48,
|
||||||
|
ZEPHR_KEYCODE_BACKSLASH = 49,
|
||||||
|
ZEPHR_KEYCODE_NON_US_HASH = 50,
|
||||||
|
ZEPHR_KEYCODE_SEMICOLON = 51,
|
||||||
|
ZEPHR_KEYCODE_APOSTROPHE = 52,
|
||||||
|
ZEPHR_KEYCODE_GRAVE = 53,
|
||||||
|
ZEPHR_KEYCODE_COMMA = 54,
|
||||||
|
ZEPHR_KEYCODE_PERIOD = 55,
|
||||||
|
ZEPHR_KEYCODE_SLASH = 56,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_CAPS_LOCK = 57,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_F1 = 58,
|
||||||
|
ZEPHR_KEYCODE_F2 = 59,
|
||||||
|
ZEPHR_KEYCODE_F3 = 60,
|
||||||
|
ZEPHR_KEYCODE_F4 = 61,
|
||||||
|
ZEPHR_KEYCODE_F5 = 62,
|
||||||
|
ZEPHR_KEYCODE_F6 = 63,
|
||||||
|
ZEPHR_KEYCODE_F7 = 64,
|
||||||
|
ZEPHR_KEYCODE_F8 = 65,
|
||||||
|
ZEPHR_KEYCODE_F9 = 66,
|
||||||
|
ZEPHR_KEYCODE_F10 = 67,
|
||||||
|
ZEPHR_KEYCODE_F11 = 68,
|
||||||
|
ZEPHR_KEYCODE_F12 = 69,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_PRINT_SCREEN = 70,
|
||||||
|
ZEPHR_KEYCODE_SCROLL_LOCK = 71,
|
||||||
|
ZEPHR_KEYCODE_PAUSE = 72,
|
||||||
|
ZEPHR_KEYCODE_INSERT = 73,
|
||||||
|
ZEPHR_KEYCODE_HOME = 74,
|
||||||
|
ZEPHR_KEYCODE_PAGE_UP = 75,
|
||||||
|
ZEPHR_KEYCODE_DELETE = 76,
|
||||||
|
ZEPHR_KEYCODE_END = 77,
|
||||||
|
ZEPHR_KEYCODE_PAGE_DOWN = 78,
|
||||||
|
ZEPHR_KEYCODE_RIGHT = 79,
|
||||||
|
ZEPHR_KEYCODE_LEFT = 80,
|
||||||
|
ZEPHR_KEYCODE_DOWN = 81,
|
||||||
|
ZEPHR_KEYCODE_UP = 82,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_NUM_LOCK_OR_CLEAR = 83,
|
||||||
|
ZEPHR_KEYCODE_KP_DIVIDE = 84,
|
||||||
|
ZEPHR_KEYCODE_KP_MULTIPLY = 85,
|
||||||
|
ZEPHR_KEYCODE_KP_MINUS = 86,
|
||||||
|
ZEPHR_KEYCODE_KP_PLUS = 87,
|
||||||
|
ZEPHR_KEYCODE_KP_ENTER = 88,
|
||||||
|
ZEPHR_KEYCODE_KP_1 = 89,
|
||||||
|
ZEPHR_KEYCODE_KP_2 = 90,
|
||||||
|
ZEPHR_KEYCODE_KP_3 = 91,
|
||||||
|
ZEPHR_KEYCODE_KP_4 = 92,
|
||||||
|
ZEPHR_KEYCODE_KP_5 = 93,
|
||||||
|
ZEPHR_KEYCODE_KP_6 = 94,
|
||||||
|
ZEPHR_KEYCODE_KP_7 = 95,
|
||||||
|
ZEPHR_KEYCODE_KP_8 = 96,
|
||||||
|
ZEPHR_KEYCODE_KP_9 = 97,
|
||||||
|
ZEPHR_KEYCODE_KP_0 = 98,
|
||||||
|
ZEPHR_KEYCODE_KP_PERIOD = 99,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_NON_US_BACKSLASH = 100,
|
||||||
|
ZEPHR_KEYCODE_APPLICATION = 101,
|
||||||
|
ZEPHR_KEYCODE_POWER = 102,
|
||||||
|
ZEPHR_KEYCODE_KP_EQUALS = 103,
|
||||||
|
ZEPHR_KEYCODE_F13 = 104,
|
||||||
|
ZEPHR_KEYCODE_F14 = 105,
|
||||||
|
ZEPHR_KEYCODE_F15 = 106,
|
||||||
|
ZEPHR_KEYCODE_F16 = 107,
|
||||||
|
ZEPHR_KEYCODE_F17 = 108,
|
||||||
|
ZEPHR_KEYCODE_F18 = 109,
|
||||||
|
ZEPHR_KEYCODE_F19 = 110,
|
||||||
|
ZEPHR_KEYCODE_F20 = 111,
|
||||||
|
ZEPHR_KEYCODE_F21 = 112,
|
||||||
|
ZEPHR_KEYCODE_F22 = 113,
|
||||||
|
ZEPHR_KEYCODE_F23 = 114,
|
||||||
|
ZEPHR_KEYCODE_F24 = 115,
|
||||||
|
ZEPHR_KEYCODE_EXECUTE = 116,
|
||||||
|
ZEPHR_KEYCODE_HELP = 117,
|
||||||
|
ZEPHR_KEYCODE_MENU = 118,
|
||||||
|
ZEPHR_KEYCODE_SELECT = 119,
|
||||||
|
ZEPHR_KEYCODE_STOP = 120,
|
||||||
|
ZEPHR_KEYCODE_AGAIN = 121,
|
||||||
|
ZEPHR_KEYCODE_UNDO = 122,
|
||||||
|
ZEPHR_KEYCODE_CUT = 123,
|
||||||
|
ZEPHR_KEYCODE_COPY = 124,
|
||||||
|
ZEPHR_KEYCODE_PASTE = 125,
|
||||||
|
ZEPHR_KEYCODE_FIND = 126,
|
||||||
|
ZEPHR_KEYCODE_MUTE = 127,
|
||||||
|
ZEPHR_KEYCODE_VOLUME_UP = 128,
|
||||||
|
ZEPHR_KEYCODE_VOLUME_DOWN = 129,
|
||||||
|
ZEPHR_KEYCODE_KP_COMMA = 133,
|
||||||
|
ZEPHR_KEYCODE_KP_EQUALSAS400 = 134,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_INTERNATIONAL1 = 135,
|
||||||
|
ZEPHR_KEYCODE_INTERNATIONAL2 = 136,
|
||||||
|
ZEPHR_KEYCODE_INTERNATIONAL3 = 137,
|
||||||
|
ZEPHR_KEYCODE_INTERNATIONAL4 = 138,
|
||||||
|
ZEPHR_KEYCODE_INTERNATIONAL5 = 139,
|
||||||
|
ZEPHR_KEYCODE_INTERNATIONAL6 = 140,
|
||||||
|
ZEPHR_KEYCODE_INTERNATIONAL7 = 141,
|
||||||
|
ZEPHR_KEYCODE_INTERNATIONAL8 = 142,
|
||||||
|
ZEPHR_KEYCODE_INTERNATIONAL9 = 143,
|
||||||
|
ZEPHR_KEYCODE_LANG1 = 144,
|
||||||
|
ZEPHR_KEYCODE_LANG2 = 145,
|
||||||
|
ZEPHR_KEYCODE_LANG3 = 146,
|
||||||
|
ZEPHR_KEYCODE_LANG4 = 147,
|
||||||
|
ZEPHR_KEYCODE_LANG5 = 148,
|
||||||
|
ZEPHR_KEYCODE_LANG6 = 149,
|
||||||
|
ZEPHR_KEYCODE_LANG7 = 150,
|
||||||
|
ZEPHR_KEYCODE_LANG8 = 151,
|
||||||
|
ZEPHR_KEYCODE_LANG9 = 152,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_ALT_ERASE = 153,
|
||||||
|
ZEPHR_KEYCODE_SYSREQ = 154,
|
||||||
|
ZEPHR_KEYCODE_CANCEL = 155,
|
||||||
|
ZEPHR_KEYCODE_CLEAR = 156,
|
||||||
|
ZEPHR_KEYCODE_PRIOR = 157,
|
||||||
|
ZEPHR_KEYCODE_ENTER_2 = 158,
|
||||||
|
ZEPHR_KEYCODE_SEPARATOR = 159,
|
||||||
|
ZEPHR_KEYCODE_OUT = 160,
|
||||||
|
ZEPHR_KEYCODE_OPER = 161,
|
||||||
|
ZEPHR_KEYCODE_CLEARAGAIN = 162,
|
||||||
|
ZEPHR_KEYCODE_CRSEL = 163,
|
||||||
|
ZEPHR_KEYCODE_EXSEL = 164,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_KP_00 = 176,
|
||||||
|
ZEPHR_KEYCODE_KP_000 = 177,
|
||||||
|
ZEPHR_KEYCODE_THOUSANDSSEPARATOR = 178,
|
||||||
|
ZEPHR_KEYCODE_DECIMALSEPARATOR = 179,
|
||||||
|
ZEPHR_KEYCODE_CURRENCYUNIT = 180,
|
||||||
|
ZEPHR_KEYCODE_CURRENCYSUBUNIT = 181,
|
||||||
|
ZEPHR_KEYCODE_KP_LEFT_PAREN = 182,
|
||||||
|
ZEPHR_KEYCODE_KP_RIGHT_PAREN = 183,
|
||||||
|
ZEPHR_KEYCODE_KP_LEFT_BRACE = 184,
|
||||||
|
ZEPHR_KEYCODE_KP_RIGHT_BRACE = 185,
|
||||||
|
ZEPHR_KEYCODE_KP_TAB = 186,
|
||||||
|
ZEPHR_KEYCODE_KP_BACKSPACE = 187,
|
||||||
|
ZEPHR_KEYCODE_KP_A = 188,
|
||||||
|
ZEPHR_KEYCODE_KP_B = 189,
|
||||||
|
ZEPHR_KEYCODE_KP_C = 190,
|
||||||
|
ZEPHR_KEYCODE_KP_D = 191,
|
||||||
|
ZEPHR_KEYCODE_KP_E = 192,
|
||||||
|
ZEPHR_KEYCODE_KP_F = 193,
|
||||||
|
ZEPHR_KEYCODE_KP_XOR = 194,
|
||||||
|
ZEPHR_KEYCODE_KP_POWER = 195,
|
||||||
|
ZEPHR_KEYCODE_KP_PERCENT = 196,
|
||||||
|
ZEPHR_KEYCODE_KP_LESS = 197,
|
||||||
|
ZEPHR_KEYCODE_KP_GREATER = 198,
|
||||||
|
ZEPHR_KEYCODE_KP_AMPERSAND = 199,
|
||||||
|
ZEPHR_KEYCODE_KP_DBLAMPERSAND = 200,
|
||||||
|
ZEPHR_KEYCODE_KP_VERTICALBAR = 201,
|
||||||
|
ZEPHR_KEYCODE_KP_DBLVERTICALBAR = 202,
|
||||||
|
ZEPHR_KEYCODE_KP_COLON = 203,
|
||||||
|
ZEPHR_KEYCODE_KP_HASH = 204,
|
||||||
|
ZEPHR_KEYCODE_KP_SPACE = 205,
|
||||||
|
ZEPHR_KEYCODE_KP_AT = 206,
|
||||||
|
ZEPHR_KEYCODE_KP_EXCLAM = 207,
|
||||||
|
ZEPHR_KEYCODE_KP_MEMSTORE = 208,
|
||||||
|
ZEPHR_KEYCODE_KP_MEMRECALL = 209,
|
||||||
|
ZEPHR_KEYCODE_KP_MEMCLEAR = 210,
|
||||||
|
ZEPHR_KEYCODE_KP_MEMADD = 211,
|
||||||
|
ZEPHR_KEYCODE_KP_MEMSUBTRACT = 212,
|
||||||
|
ZEPHR_KEYCODE_KP_MEMMULTIPLY = 213,
|
||||||
|
ZEPHR_KEYCODE_KP_MEMDIVIDE = 214,
|
||||||
|
ZEPHR_KEYCODE_KP_PLUS_MINUS = 215,
|
||||||
|
ZEPHR_KEYCODE_KP_CLEAR = 216,
|
||||||
|
ZEPHR_KEYCODE_KP_CLEARENTRY = 217,
|
||||||
|
ZEPHR_KEYCODE_KP_BINARY = 218,
|
||||||
|
ZEPHR_KEYCODE_KP_OCTAL = 219,
|
||||||
|
ZEPHR_KEYCODE_KP_DECIMAL = 220,
|
||||||
|
ZEPHR_KEYCODE_KP_HEXADECIMAL = 221,
|
||||||
|
|
||||||
|
ZEPHR_KEYCODE_LEFT_CTRL = 224,
|
||||||
|
ZEPHR_KEYCODE_LEFT_SHIFT = 225,
|
||||||
|
ZEPHR_KEYCODE_LEFT_ALT = 226,
|
||||||
|
ZEPHR_KEYCODE_LEFT_META = 227,
|
||||||
|
ZEPHR_KEYCODE_RIGHT_CTRL = 228,
|
||||||
|
ZEPHR_KEYCODE_RIGHT_SHIFT = 229,
|
||||||
|
ZEPHR_KEYCODE_RIGHT_ALT = 230,
|
||||||
|
ZEPHR_KEYCODE_RIGHT_META = 231,
|
||||||
|
|
||||||
|
/** Not a key. Marks the number of scancodes. */
|
||||||
|
ZEPHR_KEYCODE_COUNT = 512,
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef enum ZephrKeyMod {
|
||||||
|
ZEPHR_KEY_MOD_NONE = 0x0000,
|
||||||
|
|
||||||
|
ZEPHR_KEY_MOD_LEFT_SHIFT = 0x0001,
|
||||||
|
ZEPHR_KEY_MOD_RIGHT_SHIFT = 0x0002,
|
||||||
|
ZEPHR_KEY_MOD_SHIFT = 0x0003,
|
||||||
|
|
||||||
|
ZEPHR_KEY_MOD_LEFT_CTRL = 0x0040,
|
||||||
|
ZEPHR_KEY_MOD_RIGHT_CTRL = 0x0080,
|
||||||
|
ZEPHR_KEY_MOD_CTRL = 0x00C0,
|
||||||
|
|
||||||
|
ZEPHR_KEY_MOD_LEFT_ALT = 0x0100,
|
||||||
|
ZEPHR_KEY_MOD_RIGHT_ALT = 0x0200,
|
||||||
|
ZEPHR_KEY_MOD_ALT = 0x0300,
|
||||||
|
|
||||||
|
ZEPHR_KEY_MOD_LEFT_META = 0x0400,
|
||||||
|
ZEPHR_KEY_MOD_RIGHT_META = 0x0800,
|
||||||
|
ZEPHR_KEY_MOD_META = 0x0C00,
|
||||||
|
|
||||||
|
ZEPHR_KEY_MOD_CAPS_LOCK = 0x1000,
|
||||||
|
ZEPHR_KEY_MOD_NUM_LOCK = 0x2000,
|
||||||
|
} ZephrKeyMod;
|
||||||
|
|
||||||
|
typedef struct ZephrKeyboard {
|
||||||
|
ZephrKeycode scancode_to_keycode[ZEPHR_KEYCODE_COUNT];
|
||||||
|
ZephrScancode keycode_to_scancode[ZEPHR_KEYCODE_COUNT];
|
||||||
|
/* u64 scancode_is_pressed_bitset[CORE_DIV_ROUND_UP(ZEPHR_KEYCODE_COUNT, 64)]; */
|
||||||
|
/* u64 scancode_has_been_pressed_bitset[CORE_DIV_ROUND_UP(ZEPHR_KEYCODE_COUNT, 64)]; */
|
||||||
|
/* u64 scancode_has_been_released_bitset[CORE_DIV_ROUND_UP(ZEPHR_KEYCODE_COUNT, 64)]; */
|
||||||
|
/* u64 keycode_is_pressed_bitset[CORE_DIV_ROUND_UP(ZEPHR_KEYCODE_COUNT, 64)]; */
|
||||||
|
/* u64 keycode_has_been_pressed_bitset[CORE_DIV_ROUND_UP(ZEPHR_KEYCODE_COUNT, 64)]; */
|
||||||
|
/* u64 keycode_has_been_released_bitset[CORE_DIV_ROUND_UP(ZEPHR_KEYCODE_COUNT, 64)]; */
|
||||||
|
} ZephrKeyboard;
|
||||||
|
|
||||||
|
typedef struct ZephrEvent {
|
||||||
|
ZephrEventType type;
|
||||||
|
|
||||||
|
union {
|
||||||
|
struct {
|
||||||
|
bool is_pressed;
|
||||||
|
bool is_repeat;
|
||||||
|
ZephrScancode scancode;
|
||||||
|
ZephrKeycode code;
|
||||||
|
ZephrKeyMod mods;
|
||||||
|
} key;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
ZephrMouseButton button;
|
||||||
|
Vec2 position;
|
||||||
|
ZephrMouseScrollDirection scroll_direction;
|
||||||
|
} mouse;
|
||||||
|
|
||||||
|
struct {
|
||||||
|
u32 width;
|
||||||
|
u32 height;
|
||||||
|
} window;
|
||||||
|
};
|
||||||
|
} ZephrEvent;
|
||||||
|
/* CORE_DEFINE_STACK(ZephrEvent); */
|
||||||
|
|
||||||
typedef struct Context {
|
typedef struct Context {
|
||||||
|
Atom window_delete_atom;
|
||||||
bool should_quit;
|
bool should_quit;
|
||||||
Color clear_color;
|
|
||||||
Size screen_size;
|
Size screen_size;
|
||||||
ZephWindow window;
|
ZephrWindow window;
|
||||||
ZephFont font;
|
ZephrFont font;
|
||||||
|
/* ZephrKeyboard keyboard; */
|
||||||
|
/* XkbDescPtr xkb; */
|
||||||
|
/* XIM xim; */
|
||||||
|
/* CoreStack(ZephrEvent) event_queue; */
|
||||||
|
/* u32 event_queue_cursor; */
|
||||||
|
|
||||||
Matrix4x4 projection;
|
Matrix4x4 projection;
|
||||||
} Context;
|
} Context;
|
||||||
|
|
||||||
int init_zephr(const char* font_path, const char* window_title, Size window_size, Color *clear_color);
|
u32 init_zephr(const char* font_path, const char* window_title, Size window_size);
|
||||||
void deinit_zephr();
|
void deinit_zephr(void);
|
||||||
bool zephr_should_quit();
|
bool zephr_should_quit(void);
|
||||||
void zephr_swap_buffers();
|
void zephr_swap_buffers(void);
|
||||||
Size zephr_get_window_size();
|
Size zephr_get_window_size(void);
|
||||||
void zephr_make_window_non_resizable();
|
void zephr_make_window_non_resizable(void);
|
||||||
void zephr_toggle_fullscreen();
|
void zephr_toggle_fullscreen(void);
|
||||||
void zephr_quit();
|
void zephr_quit(void);
|
||||||
|
bool zephr_iter_events(ZephrEvent *event_out);
|
||||||
|
|
||||||
|
/* bool zephr_keyboard_keycode_is_pressed(ZephrKeycode keycode); */
|
||||||
|
/* bool zephr_keyboard_keycode_has_been_pressed(ZephrKeycode keycode); */
|
||||||
|
/* bool zephr_keyboard_keycode_has_been_released(ZephrKeycode keycode); */
|
||||||
|
|
||||||
|
/* ZephrScancode zephr_keyboard_keycode_to_scancode(ZephrKeycode keycode); */
|
||||||
|
/* ZephrKeycode zephr_keyboard_scancode_to_keycode(ZephrScancode scancode); */
|
||||||
|
|
||||||
|
extern Context zephr_ctx;
|
||||||
|
|||||||
+5
-23
@@ -2,26 +2,8 @@
|
|||||||
|
|
||||||
#include "zephr_math.h"
|
#include "zephr_math.h"
|
||||||
|
|
||||||
int max(int a, int 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;
|
|
||||||
}
|
|
||||||
|
|
||||||
float to_radians(float degrees) {
|
float to_radians(float degrees) {
|
||||||
return degrees * (M_PI / 180.f);
|
return degrees * ((float)M_PI / 180.f);
|
||||||
}
|
}
|
||||||
|
|
||||||
Matrix4x4 orthographic_projection_2d(float left, float right, float bottom, float top) {
|
Matrix4x4 orthographic_projection_2d(float left, float right, float bottom, float top) {
|
||||||
@@ -75,10 +57,10 @@ void apply_scale(Matrix4x4 *matrix, Sizef scale) {
|
|||||||
void apply_rotation(Matrix4x4 *model, float angle) {
|
void apply_rotation(Matrix4x4 *model, float angle) {
|
||||||
Matrix4x4 temp = identity();
|
Matrix4x4 temp = identity();
|
||||||
|
|
||||||
temp.m[0][0] = cos(angle);
|
temp.m[0][0] = (float)cos(angle);
|
||||||
temp.m[0][1] = sin(angle);
|
temp.m[0][1] = (float)sin(angle);
|
||||||
temp.m[1][0] = -sin(angle);
|
temp.m[1][0] = -(float)sin(angle);
|
||||||
temp.m[1][1] = cos(angle);
|
temp.m[1][1] = (float)cos(angle);
|
||||||
|
|
||||||
mult_4x4(model, &temp);
|
mult_4x4(model, &temp);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -38,9 +38,6 @@ typedef struct Color {
|
|||||||
float a;
|
float a;
|
||||||
} Color;
|
} Color;
|
||||||
|
|
||||||
int max(int a, int b);
|
|
||||||
float maxf(float a, float b);
|
|
||||||
float clampf(float value, float min, float max);
|
|
||||||
float to_radians(float degrees);
|
float to_radians(float degrees);
|
||||||
Matrix4x4 identity();
|
Matrix4x4 identity();
|
||||||
void mult_4x4(Matrix4x4 *multiplicant, Matrix4x4 *multiplier);
|
void mult_4x4(Matrix4x4 *multiplicant, Matrix4x4 *multiplier);
|
||||||
|
|||||||
Reference in New Issue
Block a user