From 413ef78504278d37080b9b59a652e4bbd5e2a0fc Mon Sep 17 00:00:00 2001 From: kasull Date: Sun, 1 Mar 2026 20:18:08 -0500 Subject: editor ui rework add responsive editor relayout for window resize rework header with back/save, view mode buttons, and 2d view type selector add clipped, scrollable assets and contextual tool panels simplify tool button wiring and repeated layout logic simplify 2d top-down editor internals and shared grid update hooks --- src/render/gl.cpp | 237 ++++++++++++++++++++++++++++++++++++++++++------------ 1 file changed, 187 insertions(+), 50 deletions(-) (limited to 'src/render/gl.cpp') 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; -- cgit v1.2.3