summaryrefslogtreecommitdiff
path: root/src/render/gl.cpp
diff options
context:
space:
mode:
authoraura <nw@moneybot.cc>2026-03-04 00:51:18 +0100
committeraura <nw@moneybot.cc>2026-03-04 00:51:18 +0100
commit890bea19359649695df1b618a41ce580cf3dfbda (patch)
tree8bc10ae4e613b0ad57fae9a68cec38c7d59cf067 /src/render/gl.cpp
parent61aea7311c2e1af78fd9da544499f2198f2da1dd (diff)
parentbe91342733fd56d1e7bafe72e82a8ac4dc67b79d (diff)
Merge branch 'ui-rework'
Diffstat (limited to 'src/render/gl.cpp')
-rw-r--r--src/render/gl.cpp237
1 files changed, 187 insertions, 50 deletions
diff --git a/src/render/gl.cpp b/src/render/gl.cpp
index e44a165..d18cd53 100644
--- a/src/render/gl.cpp
+++ b/src/render/gl.cpp
@@ -8,6 +8,10 @@
#include "../util.h"
I32 SAMPLER_INDICES[255];
+const I32 GL_WINDOW_MIN_W = 800;
+const I32 GL_WINDOW_MIN_H = 600;
+const I32 GL_WINDOW_ASPECT_W = 4;
+const I32 GL_WINDOW_ASPECT_H = 3;
GL_DATA* gl_inst;
@@ -15,6 +19,128 @@ GL_DATA* gl_instance() {
return gl_inst;
}
+static void gl_apply_canvas_size( GL_DATA* gl, I32 width, I32 height );
+static void gl_handle_window_size_change( GL_DATA* gl, I32 width, I32 height );
+static void gl_update_screen_ratio_uniforms( GL_DATA* gl, I32 width, I32 height );
+
+static void gl_query_canvas_size( GL_DATA* gl, I32* width, I32* height ) {
+ I32 w = 0;
+ I32 h = 0;
+ if( gl && gl->window ) {
+ SDL_GL_GetDrawableSize( gl->window, &w, &h );
+ if( w <= 0 || h <= 0 )
+ SDL_GetWindowSize( gl->window, &w, &h );
+ }
+
+ if( width ) *width = max( 1, w );
+ if( height ) *height = max( 1, h );
+}
+
+static void gl_constrain_window_size( I32* width, I32* height ) {
+ if( !width || !height )
+ return;
+
+ I32 in_w = max( GL_WINDOW_MIN_W, *width );
+ I32 in_h = max( GL_WINDOW_MIN_H, *height );
+
+ I32 keep_w_h = (I32)( ( (I64)in_w * GL_WINDOW_ASPECT_H + GL_WINDOW_ASPECT_W / 2 ) / GL_WINDOW_ASPECT_W );
+ keep_w_h = max( GL_WINDOW_MIN_H, keep_w_h );
+
+ I32 keep_h_w = (I32)( ( (I64)in_h * GL_WINDOW_ASPECT_W + GL_WINDOW_ASPECT_H / 2 ) / GL_WINDOW_ASPECT_H );
+ keep_h_w = max( GL_WINDOW_MIN_W, keep_h_w );
+
+ I32 d_keep_w = abs( keep_w_h - in_h );
+ I32 d_keep_h = abs( keep_h_w - in_w );
+
+ if( d_keep_w <= d_keep_h ) {
+ *width = in_w;
+ *height = keep_w_h;
+ } else {
+ *width = keep_h_w;
+ *height = in_h;
+ }
+}
+
+static void gl_handle_window_size_change( GL_DATA* gl, I32 width, I32 height ) {
+ if( !gl || !gl->window )
+ return;
+
+ I32 target_w = width;
+ I32 target_h = height;
+ if( target_w <= 0 || target_h <= 0 )
+ SDL_GetWindowSize( gl->window, &target_w, &target_h );
+
+ gl_constrain_window_size( &target_w, &target_h );
+
+ I32 wnd_w, wnd_h;
+ SDL_GetWindowSize( gl->window, &wnd_w, &wnd_h );
+ if( ( target_w != wnd_w || target_h != wnd_h ) && !gl->window_constraint_active ) {
+ gl->window_constraint_active = 1;
+ SDL_SetWindowSize( gl->window, target_w, target_h );
+ gl->window_constraint_active = 0;
+ }
+
+ I32 draw_w, draw_h;
+ gl_query_canvas_size( gl, &draw_w, &draw_h );
+ gl_apply_canvas_size( gl, draw_w, draw_h );
+}
+
+static I32 SDLCALL gl_event_filter( void* userdata, SDL_Event* e ) {
+ GL_DATA* gl = (GL_DATA*)userdata;
+ if( !gl || !e )
+ return 1;
+
+ if( e->type == SDL_WINDOWEVENT ) {
+ if( e->window.event == SDL_WINDOWEVENT_SIZE_CHANGED
+ || e->window.event == SDL_WINDOWEVENT_RESIZED ) {
+ gl_handle_window_size_change( gl, e->window.data1, e->window.data2 );
+
+ if( gl->resize_repaint_cb && !gl->resize_repaint_active ) {
+ gl->resize_repaint_active = 1;
+ gl->resize_repaint_cb( gl->resize_repaint_userdata );
+ gl->resize_repaint_active = 0;
+ }
+ }
+ }
+
+ return 1;
+}
+
+static void gl_apply_canvas_size( GL_DATA* gl, I32 width, I32 height ) {
+ width = max( 1, width );
+ height = max( 1, height );
+
+ gl->canvas_size[0] = width;
+ gl->canvas_size[1] = height;
+ if( canvas ) {
+ canvas[0] = width;
+ canvas[1] = height;
+ }
+
+ gl->clip_start = { 0.f, 0.f };
+ gl->clip_dim = { (F32)width, (F32)height };
+
+ gl_update_screen_ratio_uniforms( gl, width, height );
+
+ glViewport( 0, 0, width, height );
+ glUseProgram( 0 );
+}
+
+static void gl_update_screen_ratio_uniforms( GL_DATA* gl, I32 width, I32 height ) {
+ F32 screen_ratio[] = {
+ 2.f / (F32)max( 1, width ),
+ 2.f / (F32)max( 1, height ),
+ 1.f,
+ 1.f
+ };
+
+ gl->programs.each( fn( GL_SHADER_PROGRAM** it ) {
+ glUseProgram( (*it)->id );
+ I32 ratio_location = glGetUniformLocation( (*it)->id, "g_screenratio" );
+ glUniform4fv( ratio_location, 1, &screen_ratio[0] );
+ } );
+}
+
GL_DATA* gl_create( I32* _canvas ) {
if( gl_inst ) {
dlog( "gl_create() : fatal: gl instance already exists\n" );
@@ -24,6 +150,10 @@ GL_DATA* gl_create( I32* _canvas ) {
if( !font_mutex.align )
thread_mutex_init( &font_mutex );
+ SDL_SetHint( SDL_HINT_WINDOWS_ENABLE_MESSAGELOOP, "1" );
+ SDL_SetHint( SDL_HINT_WINDOWS_DPI_SCALING, "0" );
+ SDL_SetHint( SDL_HINT_VIDEO_HIGHDPI_DISABLED, "1" );
+
if( !!SDL_Init( SDL_INIT_VIDEO | SDL_VIDEO_OPENGL ) ) {
dlog( "gl_create() could not init SDL: %s\n", SDL_GetError() );
return 0;
@@ -40,14 +170,18 @@ GL_DATA* gl_create( I32* _canvas ) {
SDL_GL_SetAttribute( SDL_GL_BLUE_SIZE, 8 );
SDL_GL_SetAttribute( SDL_GL_ALPHA_SIZE, 8 );
+ I32 start_w = _canvas[0];
+ I32 start_h = _canvas[1];
+ gl_constrain_window_size( &start_w, &start_h );
+
GL_DATA* gl = new GL_DATA;
gl->window = SDL_CreateWindow(
"game",
SDL_WINDOWPOS_CENTERED,
SDL_WINDOWPOS_CENTERED,
- _canvas[0],
- _canvas[1],
- SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN
+ start_w,
+ start_h,
+ SDL_WINDOW_OPENGL | SDL_WINDOW_SHOWN | SDL_WINDOW_RESIZABLE
);
if( !gl->window ) {
@@ -56,6 +190,8 @@ GL_DATA* gl_create( I32* _canvas ) {
return 0;
}
+ SDL_SetWindowMinimumSize( gl->window, GL_WINDOW_MIN_W, GL_WINDOW_MIN_H );
+
gl->ctx = SDL_GL_CreateContext( gl->window );
if( !gl->ctx ) {
dlog( "gl_init() could not create context: %s\n", SDL_GetError() );
@@ -85,10 +221,8 @@ GL_DATA* gl_create( I32* _canvas ) {
SAMPLER_INDICES[i] = i;
gl->programs.clear();
- memcpy( gl->canvas_size, _canvas, sizeof(I32) * 2 );
- gl->clip_start = { 0, 0 };
- gl->clip_dim = { (F32)gl->canvas_size[0], (F32)gl->canvas_size[1] };
- glViewport( 0, 0, gl->canvas_size[0], gl->canvas_size[1] );
+ gl_handle_window_size_change( gl, start_w, start_h );
+ SDL_SetEventFilter( gl_event_filter, gl );
gl_inst = gl;
return gl;
@@ -105,6 +239,8 @@ void gl_gen_buffers( GL_DATA* gl ) {
}
void gl_destroy( GL_DATA *gl ) {
+ SDL_SetEventFilter( 0, 0 );
+
gl->programs.each( fn( GL_SHADER_PROGRAM** it ) { gl_program_destroy( gl, *it ); } );
gl->fonts.each( fn( GL_FONT** it ) { gl_font_destroy( gl, *it ); } );
gl->textures.each( fn( GL_TEX2D** it ) { gl_texture_destroy( gl, *it ); } );
@@ -120,27 +256,31 @@ void gl_destroy( GL_DATA *gl ) {
void gl_update_window( GL_DATA* gl, I32* size ) {
if( !gl->window )
return;
- SDL_SetWindowSize( gl->window, size[0], size[1] );
+
+ I32 width = size ? size[0] : 0;
+ I32 height = size ? size[1] : 0;
+ gl_constrain_window_size( &width, &height );
+ SDL_SetWindowSize( gl->window, width, height );
SDL_SetWindowPosition( gl->window, SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED );
+ gl_handle_window_size_change( gl, width, height );
+}
- gl->canvas_size[0] = size[0];
- gl->canvas_size[1] = size[1];
+void gl_sync_window_size( GL_DATA* gl ) {
+ if( !gl || !gl->window )
+ return;
- gl->programs.each( fn( GL_SHADER_PROGRAM** it ) {
- F32 screen_ratio[] = {
- 2.f / (F32)gl->canvas_size[0],
- 2.f / (F32)gl->canvas_size[1],
- 1.f,
- 1.f
- };
+ SDL_PumpEvents();
+ I32 w, h;
+ SDL_GetWindowSize( gl->window, &w, &h );
+ gl_handle_window_size_change( gl, w, h );
+}
- glUseProgram( (*it)->id );
- I32 ratio_location = glGetUniformLocation( (*it)->id, "g_screenratio" );
- glUniform4fv( ratio_location, 1, &screen_ratio[0] );
- } );
+void gl_set_resize_repaint_callback( GL_DATA* gl, GL_RESIZE_REPAINT_CB cb, void* userdata ) {
+ if( !gl )
+ return;
- glViewport( 0, 0, gl->canvas_size[0], gl->canvas_size[1] );
- glUseProgram( 0 );
+ gl->resize_repaint_cb = cb;
+ gl->resize_repaint_userdata = userdata;
}
STAT gl_shader_compile( GL_DATA* gl, GL_SHADER_DEF* shader ) {
@@ -318,6 +458,29 @@ STAT gl_beginframe( GL_DATA* gl ) {
return STAT_OK;
}
+STAT gl_poll_events( GL_DATA* gl ) {
+ SDL_Event e;
+ while( SDL_PollEvent( &e ) ) {
+ input_on_event( &e );
+
+ switch( e.type ) {
+ case SDL_QUIT:
+ return STAT_BREAK;
+ case SDL_WINDOWEVENT: {
+ if( e.window.event == SDL_WINDOWEVENT_SIZE_CHANGED
+ || e.window.event == SDL_WINDOWEVENT_RESIZED ) {
+ gl_handle_window_size_change( gl, e.window.data1, e.window.data2 );
+ }
+ } break;
+ case SDL_KEYDOWN:
+ return e.key.keysym.sym == SDLK_ESCAPE ? STAT_BREAK : STAT_OK;
+ default: break;
+ }
+ }
+
+ return STAT_OK;
+}
+
STAT gl_endframe( GL_DATA* gl ) {
SDL_GL_SwapWindow( gl->window );
@@ -333,20 +496,6 @@ STAT gl_endframe( GL_DATA* gl ) {
gl->fps = 1.0f / gl->frametime;
input_frame_end();
-
- SDL_Event e;
- while( SDL_PollEvent( &e ) ) {
- input_on_event( &e );
-
- switch( e.type ) {
- case SDL_QUIT:
- return STAT_BREAK;
- case SDL_KEYDOWN:
- return e.key.keysym.sym == SDLK_ESCAPE ? STAT_BREAK : STAT_OK;
- default: break;
- }
- }
-
return STAT_OK;
}
@@ -372,19 +521,7 @@ void gl_reset_clip( GL_DATA* gl ) {
void gl_set_viewport( GL_DATA* gl, VEC2 start, VEC2 dim ) {
I32 vpy = (I32)gl->canvas_size[1] - start.y - dim.y;
glViewport( (I32)start.x, vpy, (I32)dim.x, (I32)dim.y );
-
- gl->programs.each( fn( GL_SHADER_PROGRAM** it ) {
- F32 screen_ratio[] = {
- 2.f / (F32)dim.x,
- 2.f / (F32)dim.y,
- 1.f,
- 1.f
- };
-
- glUseProgram( (*it)->id );
- I32 ratio_location = glGetUniformLocation( (*it)->id, "g_screenratio" );
- glUniform4fv( ratio_location, 1, &screen_ratio[0] );
- } );
+ gl_update_screen_ratio_uniforms( gl, (I32)dim.x, (I32)dim.y );
gl->viewport_start = start;
gl->viewport_dim = dim;