diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 40af6a3..2c7b8e1 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -9,7 +9,7 @@ jobs: - name: install dependencies run: | sudo apt-get update - sudo apt-get install -qq libsdl2-dev + sudo apt-get install -qq libgl-dev libxcursor-dev libxrandr-dev libxi-dev - name: build sowon run: | make @@ -22,7 +22,7 @@ jobs: - name: install dependencies run: | sudo apt-get update - sudo apt-get install -qq libsdl2-dev + sudo apt-get install -qq libgl-dev libxcursor-dev libxrandr-dev libxi-dev - name: build sowon run: | make @@ -32,8 +32,6 @@ jobs: runs-on: macOS-latest steps: - uses: actions/checkout@v1 - - name: install dependencies - run: brew install sdl2 pkg-config - name: build sowon run: | make @@ -43,11 +41,6 @@ jobs: runs-on: windows-latest steps: - uses: actions/checkout@v4 - - name: download sdl2 - run: | - curl -fsSL -o SDL2-devel-2.0.12-VC.zip https://www.libsdl.org/release/SDL2-devel-2.0.12-VC.zip - tar -xf SDL2-devel-2.0.12-VC.zip - mv SDL2-2.0.12 SDL2 - name: build sowon shell: cmd run: | diff --git a/.gitignore b/.gitignore index 561269d..e8d8ee5 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,6 @@ sowon_rgfw build/ *.kra *~ -SDL2 *.obj *.exe .dSYM/ diff --git a/Makefile b/Makefile index 9b379a3..2a1a81c 100644 --- a/Makefile +++ b/Makefile @@ -1,10 +1,8 @@ UNAMEOS = $(shell uname) COMMON_CFLAGS= -Wall -Wextra -ggdb -std=c99 -pedantic -Ithirdparty -Ibuild -DPENGER -SDL2_CFLAGS= `pkg-config --cflags sdl2` $(COMMON_CFLAGS) RGFW_CFLAGS= $(COMMON_CFLAGS) COMMON_LIBS= -lm -SDL2_LIBS= `pkg-config --libs sdl2` $(COMMON_LIBS) ifeq ($(UNAMEOS),Darwin) RGFW_LIBS= $(COMMON_LIBS) -framework CoreVideo -framework Cocoa -framework OpenGL -framework IOKit else @@ -14,13 +12,10 @@ PREFIX?= /usr/local INSTALL?= install .PHONY: all -all: Makefile sowon sowon_rgfw man - -sowon_rgfw: src/main_rgfw.c build/digits.h build/penger_walk_sheet.h - $(CC) $(RGFW_CFLAGS) -o sowon_rgfw src/main_rgfw.c $(RGFW_LIBS) +all: Makefile sowon man sowon: src/main.c build/digits.h build/penger_walk_sheet.h - $(CC) $(SDL2_CFLAGS) -o sowon src/main.c $(SDL2_LIBS) + $(CC) $(RGFW_CFLAGS) -o sowon src/main.c $(RGFW_LIBS) build/digits.h: build/png2c ./assets/digits.png ./build/png2c ./assets/digits.png digits > build/digits.h @@ -42,12 +37,11 @@ man: docs/sowon.6.gz .PHONY: clean clean: - rm -r sowon sowon_rgfw build docs/sowon.6.gz + rm -r sowon build docs/sowon.6.gz .PHONY: install install: all $(INSTALL) -d $(DESTDIR)$(PREFIX)/bin $(INSTALL) -C ./sowon $(DESTDIR)$(PREFIX)/bin - $(INSTALL) -C ./sowon_rgfw $(DESTDIR)$(PREFIX)/bin $(INSTALL) -d $(DESTDIR)$(PREFIX)/man/man6 $(INSTALL) -C docs/sowon.6.gz $(DESTDIR)$(PREFIX)/man/man6 diff --git a/README.md b/README.md index 609e690..2d3d127 100644 --- a/README.md +++ b/README.md @@ -6,11 +6,10 @@ ## Build -Dependencies: [SDL2](https://www.libsdl.org/download-2.0.php) +### Ubuntu -### Debian ```console -$ sudo apt-get install libsdl2-dev +$ sudo apt-get install -qq libgl-dev libxcursor-dev libxrandr-dev libxi-dev $ make $ ./sowon ``` @@ -18,7 +17,6 @@ $ ./sowon ### MacOS ```console -$ brew install sdl2 pkg-config $ make $ ./sowon ``` @@ -27,15 +25,10 @@ $ ./sowon #### Visual Studio -- Enter the Visual Studio Command Line Development Environment https://docs.microsoft.com/en-us/cpp/build/building-on-the-command-line - - Basically just find `vcvarsall.bat` and run `vcvarsall.bat x64` inside of cmd -- Download [SDL2 VC Development Libraries](https://libsdl.org/release/SDL2-devel-2.0.12-VC.zip) and copy it to `path\to\sowon` +- Enter the Visual Studio Command Line Development Environment . Basically just find `vcvarsall.bat` and run `vcvarsall.bat x64` inside of cmd ```console > cd path\to\sowon -> tar -xf SDL2-devel-2.0.12-VC.zip -> move SDL2-2.0.12 SDL2 -> del SDL2-devel-2.0.12-VC.zip > build_msvc ``` diff --git a/build_msvc.bat b/build_msvc.bat index b019a1b..de320b2 100644 --- a/build_msvc.bat +++ b/build_msvc.bat @@ -2,15 +2,12 @@ rem launch this from msvc-enabled console set COMMON_CXXFLAGS=/std:c++17 /O2 /FC /W4 /nologo /I thirdparty /I build -set SDL2_CXXFLAGS=%COMMON_CXXFLAGS% /I SDL2\include set RGFW_CXXFLAGS=%COMMON_CXXFLAGS% set COMMON_LIBS=Shell32.lib -set SDL2_LIBS=%COMMON_LIBS% SDL2\lib\x64\SDL2.lib SDL2\lib\x64\SDL2main.lib -SUBSYSTEM:windows set RGFW_LIBS=%COMMON_LIBS% -SUBSYSTEM:windows /entry:mainCRTStartup mkdir build cl.exe %COMMON_CXXFLAGS% /Febuild\png2c src\png2c.c /link %COMMON_LIBS% -SUBSYSTEM:console build\png2c.exe assets\digits.png digits > build\digits.h build\png2c.exe assets\penger_walk_sheet.png penger > build\penger_walk_sheet.h -cl.exe %SDL2_CXXFLAGS% /Fesowon src/main.c /link %SDL2_LIBS% -cl.exe %RGFW_CXXFLAGS% /Fesowon_rgfw src/main_rgfw.c /link %RGFW_LIBS% +cl.exe %RGFW_CXXFLAGS% /Fesowon src/main.c /link %RGFW_LIBS% diff --git a/src/main.c b/src/main.c index 3692a9d..79f2e98 100644 --- a/src/main.c +++ b/src/main.c @@ -1,90 +1,237 @@ #define _CRT_SECURE_NO_WARNINGS #include #include +#include #include #include -#include -#include +#ifdef __APPLE__ +#define GL_SILENCE_DEPRECATION +#endif + +#ifdef _WIN32 +#define WIN32_LEAN_AND_MEAN +#define OEMRESOURCE +#include +#endif + +#ifndef __APPLE__ +#include +#else +#include +#endif + +#define RGFW_IMPLEMENTATION +#define RGFW_OPENGL +#include "RGFW.h" +typedef struct { i32 x, y, w, h; } RGFW_rect; + +#ifdef _WIN32 +void RGFW_sleep(u64 ms) { + Sleep((u32)ms); +} + +u64 RGFW_getTimerFreq(void) { + static u64 frequency = 0; + if (frequency == 0) QueryPerformanceFrequency((LARGE_INTEGER*)&frequency); + + return frequency; +} + +u64 RGFW_getTimerValue(void) { + u64 value; + QueryPerformanceCounter((LARGE_INTEGER*)&value); + return value; +} +#else +// TODO: make RGFW_getTimerFreq, RGFW_getTimerValue, RGFW_sleep compile on the rest of the platforms (Windows, MacOS) +void RGFW_sleep(u64 ms) { + struct timespec time; + time.tv_sec = 0; + time.tv_nsec = (long int)((double)ms * 1e+6); + + #ifndef RGFW_NO_UNIX_CLOCK + nanosleep(&time, NULL); + #endif +} + +u64 RGFW_getTimerFreq(void) { return 1000000000LLU; } +u64 RGFW_getTimerValue(void) { + struct timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return (u64)ts.tv_sec * RGFW_getTimerFreq() + (u64)ts.tv_nsec; +} + +#endif // _WIN32 + +#define RGL_LOAD_IMPLEMENTATION +#include "rglLoad.h" #include "common.c" -void secc(int code) +const char *vert_shader_source = + "#version 330\n" + "precision mediump float;\n" + "uniform vec2 scr_size;\n" + "uniform vec4 dst_rect;\n" + "out vec2 uv;\n" + "void main(void)\n" + "{\n" + " uv.x = (gl_VertexID & 1);\n" + " uv.y = ((gl_VertexID >> 1) & 1);\n" + " vec2 p = (dst_rect.xy + dst_rect.zw*uv)/scr_size;\n" + " p.y = 1.0 - p.y;\n" + " gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);\n" + "}\n"; + +const char *frag_shader_source = + "#version 330\n" + "precision mediump float;\n" + "uniform sampler2D tex;\n" + "uniform vec2 tex_size;\n" + "uniform vec4 src_rect;\n" + "uniform vec4 color_mod;\n" + "in vec2 uv;\n" + "out vec4 out_color;\n" + "void main(void) {\n" + " vec2 coord = (src_rect.xy + src_rect.zw*uv)/tex_size;\n" + " out_color = texture(tex, coord)*color_mod;\n" + "}\n"; + +const char *shader_type_as_cstr(GLuint shader) { - if (code < 0) { - fprintf(stderr, "SDL pooped itself: %s\n", SDL_GetError()); - abort(); + switch (shader) { + case GL_VERTEX_SHADER: + return "GL_VERTEX_SHADER"; + case GL_FRAGMENT_SHADER: + return "GL_FRAGMENT_SHADER"; + default: + return "(Unknown)"; } } -void *secp(void *ptr) +bool compile_shader_source(const GLchar *source, GLenum shader_type, GLuint *shader) { - if (ptr == NULL) { - fprintf(stderr, "SDL pooped itself: %s\n", SDL_GetError()); - abort(); + *shader = glCreateShader(shader_type); + glShaderSource(*shader, 1, &source, NULL); + glCompileShader(*shader); + + GLint compiled = 0; + glGetShaderiv(*shader, GL_COMPILE_STATUS, &compiled); + + if (!compiled) { + GLchar message[1024]; + GLsizei message_size = 0; + glGetShaderInfoLog(*shader, sizeof(message), &message_size, message); + fprintf(stderr, "ERROR: could not compile %s\n", shader_type_as_cstr(shader_type)); + fprintf(stderr, "%.*s\n", message_size, message); + return false; + } + + return true; +} + +bool link_program(GLuint vert_shader, GLuint frag_shader, GLuint *program) +{ + *program = glCreateProgram(); + + glAttachShader(*program, vert_shader); + glAttachShader(*program, frag_shader); + glLinkProgram(*program); + + GLint linked = 0; + glGetProgramiv(*program, GL_LINK_STATUS, &linked); + if (!linked) { + GLsizei message_size = 0; + GLchar message[1024]; + + glGetProgramInfoLog(*program, sizeof(message), &message_size, message); + fprintf(stderr, "Program Linking: %.*s\n", message_size, message); + return false; } - return ptr; + glDeleteShader(vert_shader); + glDeleteShader(frag_shader); + + return true; } -SDL_Surface *load_png_file_as_surface(uint32_t *data, size_t width, size_t height) + +GLint load_image_data_as_gl_texture(uint32_t *data, size_t width, size_t height) { - SDL_Surface* image_surface = - secp(SDL_CreateRGBSurfaceFrom( - data, - (int) width, - (int) height, - 32, - (int) width * 4, - 0x000000FF, - 0x0000FF00, - 0x00FF0000, - 0xFF000000)); - return image_surface; + static GLint texture_units_count = 0; + if (texture_units_count >= GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) return -1; + + GLint texture_unit = texture_units_count++; + GLuint texture; + glActiveTexture(GL_TEXTURE0 + texture_unit); + glGenTextures(1, &texture); + glBindTexture(GL_TEXTURE_2D, texture); + + 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_WRAP_S, GL_CLAMP_TO_BORDER); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + + glTexImage2D(GL_TEXTURE_2D, + 0, + GL_RGBA, + width, + height, + 0, + GL_RGBA, + GL_UNSIGNED_BYTE, + data); + return texture_unit; } -SDL_Texture *load_digits_png_file_as_texture(SDL_Renderer *renderer) +GLint tex_uni; +GLint dst_rect_uni; +GLint scr_size_uni; +GLint src_rect_uni; +GLint tex_size_uni; +GLint color_mod_uni; + +void set_texture_color_mod(GLfloat r, GLfloat g, GLfloat b) { - SDL_Surface *image_surface = load_png_file_as_surface(digits_data, digits_width, digits_height); - return secp(SDL_CreateTextureFromSurface(renderer, image_surface)); + glUniform4f(color_mod_uni, r, g, b, 1); } -#ifdef PENGER -SDL_Texture *load_penger_png_file_as_texture(SDL_Renderer *renderer) +void texture_copy(GLint texture_unit, int tex_width, int tex_height, RGFW_rect src_rect, RGFW_rect dst_rect) { - SDL_Surface *image_surface = load_png_file_as_surface(penger_data, penger_width, penger_height); - return secp(SDL_CreateTextureFromSurface(renderer, image_surface)); + glUniform1i(tex_uni, texture_unit); + glUniform4f(dst_rect_uni, dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h); + glUniform4f(src_rect_uni, src_rect.x, src_rect.y, src_rect.w, src_rect.h); + glUniform2f(tex_size_uni, tex_width, tex_height); + glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); } -#endif -void render_digit_at(SDL_Renderer *renderer, SDL_Texture *digits, size_t digit_index, - size_t wiggle_index, int *pen_x, int *pen_y, float user_scale, float fit_scale) +void render_digit_at(GLint digits_tex_unit, size_t digit_index, size_t wiggle_index, int *pen_x, int *pen_y, float user_scale, float fit_scale) { const int effective_digit_width = (int) floorf((float) CHAR_WIDTH * user_scale * fit_scale); const int effective_digit_height = (int) floorf((float) CHAR_HEIGHT * user_scale * fit_scale); - const SDL_Rect src_rect = { + const RGFW_rect src_rect = { (int) (digit_index * SPRITE_CHAR_WIDTH), (int) (wiggle_index * SPRITE_CHAR_HEIGHT), SPRITE_CHAR_WIDTH, SPRITE_CHAR_HEIGHT }; - const SDL_Rect dst_rect = { + const RGFW_rect dst_rect = { *pen_x, *pen_y, effective_digit_width, effective_digit_height }; - SDL_RenderCopy(renderer, digits, &src_rect, &dst_rect); + + texture_copy(digits_tex_unit, digits_width, digits_height, src_rect, dst_rect); + *pen_x += effective_digit_width; } #ifdef PENGER -void render_penger_at(SDL_Renderer *renderer, SDL_Texture *penger, float time, int flipped, SDL_Window *window) +void render_penger_at(GLint penger_tex_unit, int window_width, int window_height, float time, int flipped) { - int window_width, window_height; - SDL_GetWindowSize(window, &window_width, &window_height); - int sps = PENGER_STEPS_PER_SECOND; int step = (int)(time*sps)%(60*sps); //step index [0,60*sps-1] @@ -97,144 +244,169 @@ void render_penger_at(SDL_Renderer *renderer, SDL_Texture *penger, float time, i float penger_walk_width = window_width + penger_drawn_width; - const SDL_Rect src_rect = { + RGFW_rect src_rect = { (int) (penger_width / 2) * frame_index, 0, (int) penger_width / 2, (int) penger_height }; - SDL_Rect dst_rect = { + RGFW_rect dst_rect = { floorf((float)penger_walk_width * progress - penger_drawn_width), window_height - (penger_height / PENGER_SCALE), (int) (penger_width / 2) / PENGER_SCALE, (int) penger_height / PENGER_SCALE }; - SDL_RenderCopyEx(renderer, penger, &src_rect, &dst_rect, 0, NULL, flipped); + if (flipped) { + src_rect.x += src_rect.w; + src_rect.w *= -1; + } + texture_copy(penger_tex_unit, penger_width, penger_height, src_rect, dst_rect); } #endif int main(int argc, char **argv) { State state = {0}; - parse_state_from_args(&state, argc, argv); - secc(SDL_Init(SDL_INIT_VIDEO)); - - SDL_Window *window = - secp(SDL_CreateWindow( - "sowon", - 0, 0, - TEXT_WIDTH, TEXT_HEIGHT*2, - SDL_WINDOW_RESIZABLE)); - - SDL_Renderer *renderer = - secp(SDL_CreateRenderer( - window, -1, - SDL_RENDERER_PRESENTVSYNC | SDL_RENDERER_ACCELERATED)); - - secc(SDL_SetHint(SDL_HINT_RENDER_SCALE_QUALITY, "linear")); - - SDL_Texture *digits = load_digits_png_file_as_texture(renderer); + parse_state_from_args(&state, argc, argv); + RGFW_glHints *hints = RGFW_getGlobalHints_OpenGL(); + hints->profile = RGFW_glCore; + hints->major = 3; + hints->minor = 3; + RGFW_setGlobalHints_OpenGL(hints); + + RGFW_rect win_rect = {0, 0, TEXT_WIDTH, TEXT_HEIGHT*2}; + RGFW_window* win = RGFW_createWindow("sowon (RGFW)", win_rect.x, win_rect.y, win_rect.w, win_rect.h, RGFW_windowOpenGL); + + RGFW_window_makeCurrentContext_OpenGL(win); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); + + GLuint vert_shader; + if (!compile_shader_source(vert_shader_source, GL_VERTEX_SHADER, &vert_shader)) return 1; + GLuint frag_shader; + if (!compile_shader_source(frag_shader_source, GL_FRAGMENT_SHADER, &frag_shader)) return 1; + GLuint program; + if (!link_program(vert_shader, frag_shader, &program)) return 1; + glUseProgram(program); + + tex_uni = glGetUniformLocation(program, "tex"); + dst_rect_uni = glGetUniformLocation(program, "dst_rect"); + scr_size_uni = glGetUniformLocation(program, "scr_size"); + src_rect_uni = glGetUniformLocation(program, "src_rect"); + tex_size_uni = glGetUniformLocation(program, "tex_size"); + color_mod_uni = glGetUniformLocation(program, "color_mod"); + + glUniform4f(dst_rect_uni, 0, 0, 500, 500); + glUniform2f(scr_size_uni, win_rect.w, win_rect.h); + glUniform4f(src_rect_uni, 0, 0, CHAR_WIDTH, CHAR_HEIGHT); + glUniform2f(tex_size_uni, digits_width, digits_height); + + GLint digits_tex_unit = load_image_data_as_gl_texture(digits_data, digits_width, digits_height); #ifdef PENGER - SDL_Texture *penger = load_penger_png_file_as_texture(renderer); + GLint penger_tex_unit = load_image_data_as_gl_texture(penger_data, penger_width, penger_height); #endif - secc(SDL_SetTextureColorMod(digits, MAIN_COLOR_R, MAIN_COLOR_G, MAIN_COLOR_B)); - + set_texture_color_mod(MAIN_COLOR_R/255.0f, MAIN_COLOR_G/255.0f, MAIN_COLOR_B/255.0f); if (state.paused) { - secc(SDL_SetTextureColorMod(digits, PAUSE_COLOR_R, PAUSE_COLOR_G, PAUSE_COLOR_B)); + set_texture_color_mod(PAUSE_COLOR_R/255.0f, PAUSE_COLOR_G/255.0f, PAUSE_COLOR_B/255.0f); } else { - secc(SDL_SetTextureColorMod(digits, MAIN_COLOR_R, MAIN_COLOR_G, MAIN_COLOR_B)); + set_texture_color_mod(MAIN_COLOR_R/255.0f, MAIN_COLOR_G/255.0f, MAIN_COLOR_B/255.0f); } - uint64_t last_time = SDL_GetPerformanceCounter(); - while (!state.quit) { - uint64_t now = SDL_GetPerformanceCounter(); - float dt = (float)(now - last_time)/SDL_GetPerformanceFrequency(); + GLuint vao; + glGenVertexArrays(1, &vao); + glBindVertexArray(vao); + + uint64_t last_time = RGFW_getTimerValue(); + while (RGFW_window_shouldClose(win) == RGFW_FALSE) { + uint64_t now = RGFW_getTimerValue(); + float dt = (float)(now - last_time)/RGFW_getTimerFreq(); last_time = now; // INPUT BEGIN ////////////////////////////// - SDL_Event event = {0}; - while (SDL_PollEvent(&event)) { + RGFW_event event = {0}; + while (RGFW_window_checkEvent(win, &event)) { switch (event.type) { - case SDL_QUIT: { - state.quit = 1; + case RGFW_windowResized: { + glViewport(0, 0, win->w, win->h); + glUniform2f(scr_size_uni, win->w, win->h); } break; - - case SDL_KEYDOWN: { - switch (event.key.keysym.sym) { - case SDLK_SPACE: { + case RGFW_keyPressed: { + switch (event.key.value) { + case RGFW_space: { state.paused = !state.paused; if (state.paused) { - secc(SDL_SetTextureColorMod(digits, PAUSE_COLOR_R, PAUSE_COLOR_G, PAUSE_COLOR_B)); + set_texture_color_mod(PAUSE_COLOR_R/255.0f, PAUSE_COLOR_G/255.0f, PAUSE_COLOR_B/255.0f); } else { - secc(SDL_SetTextureColorMod(digits, MAIN_COLOR_R, MAIN_COLOR_G, MAIN_COLOR_B)); + set_texture_color_mod(MAIN_COLOR_R/255.0f, MAIN_COLOR_G/255.0f, MAIN_COLOR_B/255.0f); } } break; - case SDLK_KP_PLUS: - case SDLK_EQUALS: { + // TODO: add support for RGFW_kpPlus when RGFW 1.8.0 is released + // case RGFW_kpPlus: + case RGFW_equals: { state.user_scale += SCALE_FACTOR * state.user_scale; } break; - case SDLK_KP_MINUS: - case SDLK_MINUS: { + // TODO: add support for RGFW_kpMinus when RGFW 1.8.0 is released + // case RGFW_kpMinus: + case RGFW_minus: { state.user_scale -= SCALE_FACTOR * state.user_scale; } break; - case SDLK_KP_0: - case SDLK_0: { + // TODO: add support for RGFW_kp0 when RGFW 1.8.0 is released + // case RGFW_kp0: + case RGFW_0: { state.user_scale = 1.0f; } break; - case SDLK_F5: { + case RGFW_F5: { parse_state_from_args(&state, argc, argv); if (state.paused) { - secc(SDL_SetTextureColorMod(digits, PAUSE_COLOR_R, PAUSE_COLOR_G, PAUSE_COLOR_B)); + set_texture_color_mod(PAUSE_COLOR_R/255.0f, PAUSE_COLOR_G/255.0f, PAUSE_COLOR_B/255.0f); } else { - secc(SDL_SetTextureColorMod(digits, MAIN_COLOR_R, MAIN_COLOR_G, MAIN_COLOR_B)); + set_texture_color_mod(MAIN_COLOR_R/255.0f, MAIN_COLOR_G/255.0f, MAIN_COLOR_B/255.0f); } } break; - case SDLK_F11: { - Uint32 window_flags; - secc(window_flags = SDL_GetWindowFlags(window)); - if(window_flags & SDL_WINDOW_FULLSCREEN_DESKTOP) { - secc(SDL_SetWindowFullscreen(window, 0)); + case RGFW_F11: { + RGFW_windowFlags window_flags = RGFW_window_getFlags(win); // TODO: use RGFW_window_getFlags() when RGFW 1.8.0 is released + if (window_flags & RGFW_windowFullscreen) { + RGFW_window_setFlags(win, window_flags & (~RGFW_windowFullscreen)); } else { - secc(SDL_SetWindowFullscreen(window, SDL_WINDOW_FULLSCREEN_DESKTOP)); + RGFW_window_setFlags(win, window_flags | RGFW_windowFullscreen); } } break; } } break; - - case SDL_MOUSEWHEEL: { - if (SDL_GetModState() & KMOD_CTRL) { - if (event.wheel.y > 0) { + case RGFW_mouseScroll: { + if (RGFW_isKeyDown(RGFW_controlL) || RGFW_isKeyDown(RGFW_controlR)) { + if (event.scroll.y > 0) { state.user_scale += SCALE_FACTOR * state.user_scale; - } else if (event.wheel.y < 0) { + } else if (event.scroll.y < 0) { state.user_scale -= SCALE_FACTOR * state.user_scale; } } } break; - - default: {} } } // INPUT END ////////////////////////////// // RENDER BEGIN ////////////////////////////// - SDL_SetRenderDrawColor(renderer, BACKGROUND_COLOR_R, BACKGROUND_COLOR_G, BACKGROUND_COLOR_B, 255); - SDL_RenderClear(renderer); + glClearColor(BACKGROUND_COLOR_R/255.0f, BACKGROUND_COLOR_G/255.0f, BACKGROUND_COLOR_B/255.0f, 1); + glClear(GL_COLOR_BUFFER_BIT); + { const size_t t = (size_t) floorf(fmaxf(state.displayed_time, 0.0f)); // PENGER BEGIN ////////////////////////////// #ifdef PENGER - render_penger_at(renderer, penger, state.displayed_time, state.mode==MODE_COUNTDOWN, window); + render_penger_at(penger_tex_unit, win->w, win->h, state.displayed_time, state.mode==MODE_COUNTDOWN); #endif // PENGER END ////////////////////////////// @@ -242,47 +414,46 @@ int main(int argc, char **argv) // DIGITS BEGIN ////////////////////////////// int pen_x, pen_y; float fit_scale = 1.0; - int w, h; - SDL_GetWindowSize(window, &w, &h); - initial_pen(w, h, &pen_x, &pen_y, state.user_scale, &fit_scale); + initial_pen(win->w, win->h, &pen_x, &pen_y, state.user_scale, &fit_scale); // TODO: support amount of hours >99 const size_t hours = t / 60 / 60; - render_digit_at(renderer, digits, hours / 10, state.wiggle_index % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - render_digit_at(renderer, digits, hours % 10, (state.wiggle_index + 1) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - render_digit_at(renderer, digits, COLON_INDEX, state.wiggle_index % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); + render_digit_at(digits_tex_unit, hours / 10, state.wiggle_index % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); + render_digit_at(digits_tex_unit, hours % 10, (state.wiggle_index + 1) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); + render_digit_at(digits_tex_unit, COLON_INDEX, state.wiggle_index % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); const size_t minutes = t / 60 % 60; - render_digit_at(renderer, digits, minutes / 10, (state.wiggle_index + 2) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - render_digit_at(renderer, digits, minutes % 10, (state.wiggle_index + 3) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - render_digit_at(renderer, digits, COLON_INDEX, (state.wiggle_index + 1) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); + render_digit_at(digits_tex_unit, minutes / 10, (state.wiggle_index + 2) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); + render_digit_at(digits_tex_unit, minutes % 10, (state.wiggle_index + 3) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); + render_digit_at(digits_tex_unit, COLON_INDEX, (state.wiggle_index + 1) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); const size_t seconds = t % 60; - render_digit_at(renderer, digits, seconds / 10, (state.wiggle_index + 4) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - render_digit_at(renderer, digits, seconds % 10, (state.wiggle_index + 5) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); + render_digit_at(digits_tex_unit, seconds / 10, (state.wiggle_index + 4) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); + render_digit_at(digits_tex_unit, seconds % 10, (state.wiggle_index + 5) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); char title[TITLE_CAP]; - snprintf(title, sizeof(title), "%02zu:%02zu:%02zu - sowon", hours, minutes, seconds); + snprintf(title, sizeof(title), "%02zu:%02zu:%02zu - sowon (RGFW)", hours, minutes, seconds); if (strcmp(state.prev_title, title) != 0) { - SDL_SetWindowTitle(window, title); + RGFW_window_setName(win, title); } memcpy(title, state.prev_title, TITLE_CAP); // DIGITS END ////////////////////////////// } - SDL_RenderPresent(renderer); + + RGFW_window_swapBuffers_OpenGL(win); // RENDER END ////////////////////////////// // UPDATE BEGIN ////////////////////////////// state_update(&state, dt); // UPDATE END ////////////////////////////// - now = SDL_GetPerformanceCounter(); - Uint32 frame_time = (Uint32)(((now - last_time)*1000.0f)/SDL_GetPerformanceFrequency()); - Uint32 frame_cap = 1000/FPS; - if (frame_time < frame_cap) SDL_Delay(frame_cap - frame_time); + now = RGFW_getTimerValue(); + uint64_t frame_time = ((now - last_time)*1000.0f)/RGFW_getTimerFreq(); + uint64_t frame_cap = 1000/FPS; + if (frame_time < frame_cap) RGFW_sleep(frame_cap - frame_time); } - SDL_Quit(); + RGFW_window_close(win); return 0; } diff --git a/src/main_rgfw.c b/src/main_rgfw.c deleted file mode 100644 index 79f2e98..0000000 --- a/src/main_rgfw.c +++ /dev/null @@ -1,459 +0,0 @@ -#define _CRT_SECURE_NO_WARNINGS -#include -#include -#include -#include -#include - -#ifdef __APPLE__ -#define GL_SILENCE_DEPRECATION -#endif - -#ifdef _WIN32 -#define WIN32_LEAN_AND_MEAN -#define OEMRESOURCE -#include -#endif - -#ifndef __APPLE__ -#include -#else -#include -#endif - -#define RGFW_IMPLEMENTATION -#define RGFW_OPENGL -#include "RGFW.h" -typedef struct { i32 x, y, w, h; } RGFW_rect; - -#ifdef _WIN32 -void RGFW_sleep(u64 ms) { - Sleep((u32)ms); -} - -u64 RGFW_getTimerFreq(void) { - static u64 frequency = 0; - if (frequency == 0) QueryPerformanceFrequency((LARGE_INTEGER*)&frequency); - - return frequency; -} - -u64 RGFW_getTimerValue(void) { - u64 value; - QueryPerformanceCounter((LARGE_INTEGER*)&value); - return value; -} -#else -// TODO: make RGFW_getTimerFreq, RGFW_getTimerValue, RGFW_sleep compile on the rest of the platforms (Windows, MacOS) -void RGFW_sleep(u64 ms) { - struct timespec time; - time.tv_sec = 0; - time.tv_nsec = (long int)((double)ms * 1e+6); - - #ifndef RGFW_NO_UNIX_CLOCK - nanosleep(&time, NULL); - #endif -} - -u64 RGFW_getTimerFreq(void) { return 1000000000LLU; } -u64 RGFW_getTimerValue(void) { - struct timespec ts; - clock_gettime(CLOCK_REALTIME, &ts); - return (u64)ts.tv_sec * RGFW_getTimerFreq() + (u64)ts.tv_nsec; -} - -#endif // _WIN32 - -#define RGL_LOAD_IMPLEMENTATION -#include "rglLoad.h" - -#include "common.c" - -const char *vert_shader_source = - "#version 330\n" - "precision mediump float;\n" - "uniform vec2 scr_size;\n" - "uniform vec4 dst_rect;\n" - "out vec2 uv;\n" - "void main(void)\n" - "{\n" - " uv.x = (gl_VertexID & 1);\n" - " uv.y = ((gl_VertexID >> 1) & 1);\n" - " vec2 p = (dst_rect.xy + dst_rect.zw*uv)/scr_size;\n" - " p.y = 1.0 - p.y;\n" - " gl_Position = vec4(p * 2.0 - 1.0, 0.0, 1.0);\n" - "}\n"; - -const char *frag_shader_source = - "#version 330\n" - "precision mediump float;\n" - "uniform sampler2D tex;\n" - "uniform vec2 tex_size;\n" - "uniform vec4 src_rect;\n" - "uniform vec4 color_mod;\n" - "in vec2 uv;\n" - "out vec4 out_color;\n" - "void main(void) {\n" - " vec2 coord = (src_rect.xy + src_rect.zw*uv)/tex_size;\n" - " out_color = texture(tex, coord)*color_mod;\n" - "}\n"; - -const char *shader_type_as_cstr(GLuint shader) -{ - switch (shader) { - case GL_VERTEX_SHADER: - return "GL_VERTEX_SHADER"; - case GL_FRAGMENT_SHADER: - return "GL_FRAGMENT_SHADER"; - default: - return "(Unknown)"; - } -} - -bool compile_shader_source(const GLchar *source, GLenum shader_type, GLuint *shader) -{ - *shader = glCreateShader(shader_type); - glShaderSource(*shader, 1, &source, NULL); - glCompileShader(*shader); - - GLint compiled = 0; - glGetShaderiv(*shader, GL_COMPILE_STATUS, &compiled); - - if (!compiled) { - GLchar message[1024]; - GLsizei message_size = 0; - glGetShaderInfoLog(*shader, sizeof(message), &message_size, message); - fprintf(stderr, "ERROR: could not compile %s\n", shader_type_as_cstr(shader_type)); - fprintf(stderr, "%.*s\n", message_size, message); - return false; - } - - return true; -} - -bool link_program(GLuint vert_shader, GLuint frag_shader, GLuint *program) -{ - *program = glCreateProgram(); - - glAttachShader(*program, vert_shader); - glAttachShader(*program, frag_shader); - glLinkProgram(*program); - - GLint linked = 0; - glGetProgramiv(*program, GL_LINK_STATUS, &linked); - if (!linked) { - GLsizei message_size = 0; - GLchar message[1024]; - - glGetProgramInfoLog(*program, sizeof(message), &message_size, message); - fprintf(stderr, "Program Linking: %.*s\n", message_size, message); - return false; - } - - glDeleteShader(vert_shader); - glDeleteShader(frag_shader); - - return true; -} - - -GLint load_image_data_as_gl_texture(uint32_t *data, size_t width, size_t height) -{ - static GLint texture_units_count = 0; - if (texture_units_count >= GL_MAX_COMBINED_TEXTURE_IMAGE_UNITS) return -1; - - GLint texture_unit = texture_units_count++; - GLuint texture; - glActiveTexture(GL_TEXTURE0 + texture_unit); - glGenTextures(1, &texture); - glBindTexture(GL_TEXTURE_2D, texture); - - 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_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - - glTexImage2D(GL_TEXTURE_2D, - 0, - GL_RGBA, - width, - height, - 0, - GL_RGBA, - GL_UNSIGNED_BYTE, - data); - return texture_unit; -} - -GLint tex_uni; -GLint dst_rect_uni; -GLint scr_size_uni; -GLint src_rect_uni; -GLint tex_size_uni; -GLint color_mod_uni; - -void set_texture_color_mod(GLfloat r, GLfloat g, GLfloat b) -{ - glUniform4f(color_mod_uni, r, g, b, 1); -} - -void texture_copy(GLint texture_unit, int tex_width, int tex_height, RGFW_rect src_rect, RGFW_rect dst_rect) -{ - glUniform1i(tex_uni, texture_unit); - glUniform4f(dst_rect_uni, dst_rect.x, dst_rect.y, dst_rect.w, dst_rect.h); - glUniform4f(src_rect_uni, src_rect.x, src_rect.y, src_rect.w, src_rect.h); - glUniform2f(tex_size_uni, tex_width, tex_height); - glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); -} - -void render_digit_at(GLint digits_tex_unit, size_t digit_index, size_t wiggle_index, int *pen_x, int *pen_y, float user_scale, float fit_scale) -{ - const int effective_digit_width = (int) floorf((float) CHAR_WIDTH * user_scale * fit_scale); - const int effective_digit_height = (int) floorf((float) CHAR_HEIGHT * user_scale * fit_scale); - - const RGFW_rect src_rect = { - (int) (digit_index * SPRITE_CHAR_WIDTH), - (int) (wiggle_index * SPRITE_CHAR_HEIGHT), - SPRITE_CHAR_WIDTH, - SPRITE_CHAR_HEIGHT - }; - const RGFW_rect dst_rect = { - *pen_x, - *pen_y, - effective_digit_width, - effective_digit_height - }; - - texture_copy(digits_tex_unit, digits_width, digits_height, src_rect, dst_rect); - - *pen_x += effective_digit_width; -} - -#ifdef PENGER -void render_penger_at(GLint penger_tex_unit, int window_width, int window_height, float time, int flipped) -{ - int sps = PENGER_STEPS_PER_SECOND; - - int step = (int)(time*sps)%(60*sps); //step index [0,60*sps-1] - - float progress = step/(60.0*sps); // [0,1] - - int frame_index = step%2; - - float penger_drawn_width = ((float)penger_width / 2) / PENGER_SCALE; - - float penger_walk_width = window_width + penger_drawn_width; - - RGFW_rect src_rect = { - (int) (penger_width / 2) * frame_index, - 0, - (int) penger_width / 2, - (int) penger_height - }; - - RGFW_rect dst_rect = { - floorf((float)penger_walk_width * progress - penger_drawn_width), - window_height - (penger_height / PENGER_SCALE), - (int) (penger_width / 2) / PENGER_SCALE, - (int) penger_height / PENGER_SCALE - }; - - if (flipped) { - src_rect.x += src_rect.w; - src_rect.w *= -1; - } - texture_copy(penger_tex_unit, penger_width, penger_height, src_rect, dst_rect); -} -#endif - -int main(int argc, char **argv) -{ - State state = {0}; - - parse_state_from_args(&state, argc, argv); - - RGFW_glHints *hints = RGFW_getGlobalHints_OpenGL(); - hints->profile = RGFW_glCore; - hints->major = 3; - hints->minor = 3; - RGFW_setGlobalHints_OpenGL(hints); - - RGFW_rect win_rect = {0, 0, TEXT_WIDTH, TEXT_HEIGHT*2}; - RGFW_window* win = RGFW_createWindow("sowon (RGFW)", win_rect.x, win_rect.y, win_rect.w, win_rect.h, RGFW_windowOpenGL); - - RGFW_window_makeCurrentContext_OpenGL(win); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - - GLuint vert_shader; - if (!compile_shader_source(vert_shader_source, GL_VERTEX_SHADER, &vert_shader)) return 1; - GLuint frag_shader; - if (!compile_shader_source(frag_shader_source, GL_FRAGMENT_SHADER, &frag_shader)) return 1; - GLuint program; - if (!link_program(vert_shader, frag_shader, &program)) return 1; - glUseProgram(program); - - tex_uni = glGetUniformLocation(program, "tex"); - dst_rect_uni = glGetUniformLocation(program, "dst_rect"); - scr_size_uni = glGetUniformLocation(program, "scr_size"); - src_rect_uni = glGetUniformLocation(program, "src_rect"); - tex_size_uni = glGetUniformLocation(program, "tex_size"); - color_mod_uni = glGetUniformLocation(program, "color_mod"); - - glUniform4f(dst_rect_uni, 0, 0, 500, 500); - glUniform2f(scr_size_uni, win_rect.w, win_rect.h); - glUniform4f(src_rect_uni, 0, 0, CHAR_WIDTH, CHAR_HEIGHT); - glUniform2f(tex_size_uni, digits_width, digits_height); - - GLint digits_tex_unit = load_image_data_as_gl_texture(digits_data, digits_width, digits_height); - #ifdef PENGER - GLint penger_tex_unit = load_image_data_as_gl_texture(penger_data, penger_width, penger_height); - #endif - - set_texture_color_mod(MAIN_COLOR_R/255.0f, MAIN_COLOR_G/255.0f, MAIN_COLOR_B/255.0f); - if (state.paused) { - set_texture_color_mod(PAUSE_COLOR_R/255.0f, PAUSE_COLOR_G/255.0f, PAUSE_COLOR_B/255.0f); - } else { - set_texture_color_mod(MAIN_COLOR_R/255.0f, MAIN_COLOR_G/255.0f, MAIN_COLOR_B/255.0f); - } - - GLuint vao; - glGenVertexArrays(1, &vao); - glBindVertexArray(vao); - - uint64_t last_time = RGFW_getTimerValue(); - while (RGFW_window_shouldClose(win) == RGFW_FALSE) { - uint64_t now = RGFW_getTimerValue(); - float dt = (float)(now - last_time)/RGFW_getTimerFreq(); - last_time = now; - - // INPUT BEGIN ////////////////////////////// - RGFW_event event = {0}; - while (RGFW_window_checkEvent(win, &event)) { - switch (event.type) { - case RGFW_windowResized: { - glViewport(0, 0, win->w, win->h); - glUniform2f(scr_size_uni, win->w, win->h); - } break; - case RGFW_keyPressed: { - switch (event.key.value) { - case RGFW_space: { - state.paused = !state.paused; - if (state.paused) { - set_texture_color_mod(PAUSE_COLOR_R/255.0f, PAUSE_COLOR_G/255.0f, PAUSE_COLOR_B/255.0f); - } else { - set_texture_color_mod(MAIN_COLOR_R/255.0f, MAIN_COLOR_G/255.0f, MAIN_COLOR_B/255.0f); - } - } break; - - // TODO: add support for RGFW_kpPlus when RGFW 1.8.0 is released - // case RGFW_kpPlus: - case RGFW_equals: { - state.user_scale += SCALE_FACTOR * state.user_scale; - } break; - - // TODO: add support for RGFW_kpMinus when RGFW 1.8.0 is released - // case RGFW_kpMinus: - case RGFW_minus: { - state.user_scale -= SCALE_FACTOR * state.user_scale; - } break; - - // TODO: add support for RGFW_kp0 when RGFW 1.8.0 is released - // case RGFW_kp0: - case RGFW_0: { - state.user_scale = 1.0f; - } break; - - case RGFW_F5: { - parse_state_from_args(&state, argc, argv); - if (state.paused) { - set_texture_color_mod(PAUSE_COLOR_R/255.0f, PAUSE_COLOR_G/255.0f, PAUSE_COLOR_B/255.0f); - } else { - set_texture_color_mod(MAIN_COLOR_R/255.0f, MAIN_COLOR_G/255.0f, MAIN_COLOR_B/255.0f); - } - } break; - - case RGFW_F11: { - RGFW_windowFlags window_flags = RGFW_window_getFlags(win); // TODO: use RGFW_window_getFlags() when RGFW 1.8.0 is released - if (window_flags & RGFW_windowFullscreen) { - RGFW_window_setFlags(win, window_flags & (~RGFW_windowFullscreen)); - } else { - RGFW_window_setFlags(win, window_flags | RGFW_windowFullscreen); - } - } break; - } - } break; - case RGFW_mouseScroll: { - if (RGFW_isKeyDown(RGFW_controlL) || RGFW_isKeyDown(RGFW_controlR)) { - if (event.scroll.y > 0) { - state.user_scale += SCALE_FACTOR * state.user_scale; - } else if (event.scroll.y < 0) { - state.user_scale -= SCALE_FACTOR * state.user_scale; - } - } - } break; - } - } - // INPUT END ////////////////////////////// - - // RENDER BEGIN ////////////////////////////// - glClearColor(BACKGROUND_COLOR_R/255.0f, BACKGROUND_COLOR_G/255.0f, BACKGROUND_COLOR_B/255.0f, 1); - glClear(GL_COLOR_BUFFER_BIT); - - { - const size_t t = (size_t) floorf(fmaxf(state.displayed_time, 0.0f)); - // PENGER BEGIN ////////////////////////////// - - #ifdef PENGER - render_penger_at(penger_tex_unit, win->w, win->h, state.displayed_time, state.mode==MODE_COUNTDOWN); - #endif - - // PENGER END ////////////////////////////// - - // DIGITS BEGIN ////////////////////////////// - int pen_x, pen_y; - float fit_scale = 1.0; - initial_pen(win->w, win->h, &pen_x, &pen_y, state.user_scale, &fit_scale); - - // TODO: support amount of hours >99 - const size_t hours = t / 60 / 60; - render_digit_at(digits_tex_unit, hours / 10, state.wiggle_index % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - render_digit_at(digits_tex_unit, hours % 10, (state.wiggle_index + 1) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - render_digit_at(digits_tex_unit, COLON_INDEX, state.wiggle_index % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - - const size_t minutes = t / 60 % 60; - render_digit_at(digits_tex_unit, minutes / 10, (state.wiggle_index + 2) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - render_digit_at(digits_tex_unit, minutes % 10, (state.wiggle_index + 3) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - render_digit_at(digits_tex_unit, COLON_INDEX, (state.wiggle_index + 1) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - - const size_t seconds = t % 60; - render_digit_at(digits_tex_unit, seconds / 10, (state.wiggle_index + 4) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - render_digit_at(digits_tex_unit, seconds % 10, (state.wiggle_index + 5) % WIGGLE_COUNT, &pen_x, &pen_y, state.user_scale, fit_scale); - - char title[TITLE_CAP]; - snprintf(title, sizeof(title), "%02zu:%02zu:%02zu - sowon (RGFW)", hours, minutes, seconds); - if (strcmp(state.prev_title, title) != 0) { - RGFW_window_setName(win, title); - } - memcpy(title, state.prev_title, TITLE_CAP); - // DIGITS END ////////////////////////////// - } - - RGFW_window_swapBuffers_OpenGL(win); - // RENDER END ////////////////////////////// - - // UPDATE BEGIN ////////////////////////////// - state_update(&state, dt); - // UPDATE END ////////////////////////////// - - now = RGFW_getTimerValue(); - uint64_t frame_time = ((now - last_time)*1000.0f)/RGFW_getTimerFreq(); - uint64_t frame_cap = 1000/FPS; - if (frame_time < frame_cap) RGFW_sleep(frame_cap - frame_time); - } - - RGFW_window_close(win); - - return 0; -}