diff options
| author | aura <nw@moneybot.cc> | 2026-03-10 01:35:50 +0100 |
|---|---|---|
| committer | aura <nw@moneybot.cc> | 2026-03-10 01:35:50 +0100 |
| commit | 8329d42d3e592f4cd42cdfa586e2325ddc76c898 (patch) | |
| tree | dec7e2a733bfc6b6384936c1f3ed067a42b59bb9 | |
| parent | 8ae8c85e9d3806cdb726e07f37e1b49484c5c48e (diff) | |
perf profiler, simplify 2d render, string struct, many small things
| -rw-r--r-- | assets/shaders/2d.fsh | 14 | ||||
| -rw-r--r-- | assets/shaders/2d.vsh | 15 | ||||
| -rw-r--r-- | assets/shaders/2d_texcoord.fsh | 19 | ||||
| -rw-r--r-- | assets/shaders/2d_texcoord.vsh | 28 | ||||
| -rw-r--r-- | src/editor/editor_gui_internal.h | 52 | ||||
| -rw-r--r-- | src/editor/editor_infobox.cpp | 4 | ||||
| -rw-r--r-- | src/editor/editor_menubar.cpp | 12 | ||||
| -rw-r--r-- | src/editor/editor_window.cpp | 6 | ||||
| -rw-r--r-- | src/game.cpp | 31 | ||||
| -rw-r--r-- | src/game.h | 5 | ||||
| -rw-r--r-- | src/game/physics/movement.cpp | 2 | ||||
| -rw-r--r-- | src/game/raycast.cpp | 2 | ||||
| -rw-r--r-- | src/game/vars.cpp | 4 | ||||
| -rw-r--r-- | src/game/world/bsp.cpp | 9 | ||||
| -rw-r--r-- | src/game/world/draw.cpp | 2 | ||||
| -rw-r--r-- | src/gui/base.cpp | 4 | ||||
| -rw-r--r-- | src/gui/view.cpp | 3 | ||||
| -rw-r--r-- | src/main.cpp | 11 | ||||
| -rw-r--r-- | src/render/gl.cpp | 25 | ||||
| -rw-r--r-- | src/render/gl.h | 2 | ||||
| -rw-r--r-- | src/render/gl_2d.cpp | 60 | ||||
| -rw-r--r-- | src/render/gl_3d.cpp | 8 | ||||
| -rw-r--r-- | src/util.h | 22 | ||||
| -rw-r--r-- | src/util/allocator.h | 37 | ||||
| -rw-r--r-- | src/util/math.h | 10 | ||||
| -rw-r--r-- | src/util/profiler.cpp | 55 | ||||
| -rw-r--r-- | src/util/profiler.h | 139 | ||||
| -rw-r--r-- | src/util/string.h | 209 | ||||
| -rw-r--r-- | src/util/time.h | 21 |
29 files changed, 616 insertions, 195 deletions
diff --git a/assets/shaders/2d.fsh b/assets/shaders/2d.fsh index 15465af..ba1fa59 100644 --- a/assets/shaders/2d.fsh +++ b/assets/shaders/2d.fsh @@ -1,7 +1,19 @@ #version 150 +uniform sampler2D g_samplers[255]; + +const uint SAMPLER_ID_NONE = 255u; + +in vec2 g_texcoord; in vec4 g_color; +flat in uint g_sampler; void main() { - gl_FragColor = g_color; + vec4 color = g_color; + if( g_sampler != SAMPLER_ID_NONE ) { + vec4 tex_color = texture2D( g_samplers[g_sampler], g_texcoord ); + color *= tex_color; + if (color.a < 0.01) discard; + } + gl_FragColor = color; } diff --git a/assets/shaders/2d.vsh b/assets/shaders/2d.vsh index 7701087..96370fc 100644 --- a/assets/shaders/2d.vsh +++ b/assets/shaders/2d.vsh @@ -1,11 +1,13 @@ #version 150 -in vec2 in_pos; -in vec2 in_texcoord; -in vec4 in_col; +in vec2 in_pos; +in vec4 in_clr; +in vec2 in_texcoord; +in float in_sampler; out vec2 g_texcoord; out vec4 g_color; +flat out uint g_sampler; uniform vec4 g_screenratio; @@ -17,7 +19,8 @@ void main() { pos[1] -= halfscreen[1]; pos[1] *= -1.0; - gl_Position = ( pos ) * g_screenratio; - g_texcoord = in_texcoord; - g_color = in_col; + g_texcoord = in_texcoord; + g_color = in_clr; + g_sampler = uint(in_sampler * 255.0 + 0.5); + gl_Position = ( pos ) * g_screenratio; } diff --git a/assets/shaders/2d_texcoord.fsh b/assets/shaders/2d_texcoord.fsh deleted file mode 100644 index 38dc69c..0000000 --- a/assets/shaders/2d_texcoord.fsh +++ /dev/null @@ -1,19 +0,0 @@ -#version 150 - -uniform sampler2D g_samplers[255]; - -const int SAMPLER_ID_NONE = 255; - -in vec2 g_texcoord; -in vec4 g_color; -flat in int g_sampler; - -void main() { - vec4 color = g_color; - if( g_sampler != SAMPLER_ID_NONE ) { - vec4 tex_color = texture2D( g_samplers[g_sampler], g_texcoord ); - color *= tex_color; - if (color.a < 0.01) discard; - } - gl_FragColor = color; -} diff --git a/assets/shaders/2d_texcoord.vsh b/assets/shaders/2d_texcoord.vsh deleted file mode 100644 index 80c7597..0000000 --- a/assets/shaders/2d_texcoord.vsh +++ /dev/null @@ -1,28 +0,0 @@ -#version 150 - -uniform sampler2D g_samplers[255]; - -in vec2 in_pos; -in vec4 in_clr; -in vec2 in_texcoord; -in float in_sampler; - -out vec2 g_texcoord; -out vec4 g_color; -flat out int g_sampler; - -uniform vec4 g_screenratio; - -void main() { - vec2 halfscreen = vec2( 1.0 / g_screenratio[0], 1.0 / g_screenratio[1] ); - - vec4 pos = vec4( in_pos.x, in_pos.y, 1, 1 ); - pos[0] -= halfscreen[0]; - pos[1] -= halfscreen[1]; - pos[1] *= -1.0; - - g_texcoord = in_texcoord; - g_color = in_clr; - g_sampler = int(in_sampler * 255.0 + 0.5); - gl_Position = ( pos ) * g_screenratio; -} diff --git a/src/editor/editor_gui_internal.h b/src/editor/editor_gui_internal.h index ff9b140..ff20a98 100644 --- a/src/editor/editor_gui_internal.h +++ b/src/editor/editor_gui_internal.h @@ -3,31 +3,31 @@ #include "editor.h" #include "../util.h" -constexpr I32 EDITOR_LAYOUT_MARGIN = 10; -constexpr I32 EDITOR_LAYOUT_TITLE_OFFSET = 15; -constexpr I32 EDITOR_LAYOUT_MENU_Y = 1; -constexpr I32 EDITOR_LAYOUT_MENU_H = 22; -constexpr I32 EDITOR_LAYOUT_NAV_Y = EDITOR_LAYOUT_MENU_Y + EDITOR_LAYOUT_MENU_H + 4; -constexpr I32 EDITOR_LAYOUT_CONTENT_Y = EDITOR_LAYOUT_NAV_Y + 28; -constexpr I32 EDITOR_LAYOUT_COLUMN_GAP = 10; -constexpr I32 EDITOR_LAYOUT_VIEW_TOOL_GAP = 17; -constexpr I32 EDITOR_LAYOUT_TOOL_BTN_TOP_GAP = 3; -constexpr I32 EDITOR_LAYOUT_TOOL_PANEL_GAP = 5; -constexpr I32 EDITOR_LAYOUT_LEFT_BOX_GAP = 10; -constexpr I32 EDITOR_LAYOUT_STATUS_H = 22; -constexpr I32 EDITOR_LAYOUT_STATUS_GAP = 6; -constexpr I32 EDITOR_LAYOUT_TOOL_PANEL_W = 300; -constexpr I32 EDITOR_LAYOUT_TOOL_PANEL_H = 150; -constexpr I32 EDITOR_LAYOUT_PROPS_DEFAULT_W = 300; -constexpr I32 EDITOR_LAYOUT_PROPS_DEFAULT_H = 300; -constexpr I32 EDITOR_LAYOUT_VIEW_DEFAULT_H = 370; -constexpr I32 EDITOR_LAYOUT_PROPS_MIN_W = 200; -constexpr I32 EDITOR_LAYOUT_PROPS_MIN_H = 120; -constexpr I32 EDITOR_LAYOUT_ASSETS_MIN_H = 120; -constexpr I32 EDITOR_LAYOUT_VIEW_MIN_H = 140; -constexpr I32 EDITOR_LAYOUT_RIGHT_MIN_W = 260; - -constexpr I32 EDITOR_TOOLBAR_DROPDOWN_W = 120; +const I32 EDITOR_LAYOUT_MARGIN = 10; +const I32 EDITOR_LAYOUT_TITLE_OFFSET = 15; +const I32 EDITOR_LAYOUT_MENU_Y = 1; +const I32 EDITOR_LAYOUT_MENU_H = 22; +const I32 EDITOR_LAYOUT_NAV_Y = EDITOR_LAYOUT_MENU_Y + EDITOR_LAYOUT_MENU_H + 4; +const I32 EDITOR_LAYOUT_CONTENT_Y = EDITOR_LAYOUT_NAV_Y + 28; +const I32 EDITOR_LAYOUT_COLUMN_GAP = 10; +const I32 EDITOR_LAYOUT_VIEW_TOOL_GAP = 17; +const I32 EDITOR_LAYOUT_TOOL_BTN_TOP_GAP = 3; +const I32 EDITOR_LAYOUT_TOOL_PANEL_GAP = 5; +const I32 EDITOR_LAYOUT_LEFT_BOX_GAP = 10; +const I32 EDITOR_LAYOUT_STATUS_H = 22; +const I32 EDITOR_LAYOUT_STATUS_GAP = 6; +const I32 EDITOR_LAYOUT_TOOL_PANEL_W = 300; +const I32 EDITOR_LAYOUT_TOOL_PANEL_H = 150; +const I32 EDITOR_LAYOUT_PROPS_DEFAULT_W = 300; +const I32 EDITOR_LAYOUT_PROPS_DEFAULT_H = 300; +const I32 EDITOR_LAYOUT_VIEW_DEFAULT_H = 370; +const I32 EDITOR_LAYOUT_PROPS_MIN_W = 200; +const I32 EDITOR_LAYOUT_PROPS_MIN_H = 120; +const I32 EDITOR_LAYOUT_ASSETS_MIN_H = 120; +const I32 EDITOR_LAYOUT_VIEW_MIN_H = 140; +const I32 EDITOR_LAYOUT_RIGHT_MIN_W = 260; + +const I32 EDITOR_TOOLBAR_DROPDOWN_W = 120; extern U8 editor_menu_hover_mask_active; extern I32 editor_menu_hover_real_x; @@ -52,4 +52,4 @@ extern void editor_create_auxiliary_panels( GAME_EDITOR* e ); extern void editor_update_toolview( GAME_EDITOR* e ); extern void editor_create_toolview_column( GAME_EDITOR* e ); extern void editor_create_game_view_column( GAME_EDITOR* e ); -extern void settool( U8 t ); +extern void editor_settool( U8 t ); diff --git a/src/editor/editor_infobox.cpp b/src/editor/editor_infobox.cpp index 8e455d9..931d9ea 100644 --- a/src/editor/editor_infobox.cpp +++ b/src/editor/editor_infobox.cpp @@ -150,9 +150,9 @@ static void gui_editor_infobox_draw_fn( void* ptr ) { ALIGN_R, FNT_JPN12, ui_clr.txt, - "fps: %.3f (%.5f ms) %dx%d", + "fps: %.0f (%.2f ms) %dx%d", gl->fps, - gl->frametime, + gl->frametime * 1000.f, gl->canvas_size[0], gl->canvas_size[1] ); diff --git a/src/editor/editor_menubar.cpp b/src/editor/editor_menubar.cpp index 5491c05..c15053f 100644 --- a/src/editor/editor_menubar.cpp +++ b/src/editor/editor_menubar.cpp @@ -267,12 +267,12 @@ static void editor_toolbar_invoke( const EDITOR_MENUBAR_ENTRY* root, const EDITO return; } if( !strcmp( root->text, "tools" ) ) { - if( !strcmp( entry->text, "none" ) ) settool( EDITOR_TOOL_NONE ); - else if( !strcmp( entry->text, "select" ) ) settool( EDITOR_TOOL_SELECT ); - else if( !strcmp( entry->text, "wall" ) ) settool( EDITOR_TOOL_WALL ); - else if( !strcmp( entry->text, "poly" ) ) settool( EDITOR_TOOL_POLY ); - else if( !strcmp( entry->text, "sprite" ) ) settool( EDITOR_TOOL_SPRITE ); - else if( !strcmp( entry->text, "ent" ) ) settool( EDITOR_TOOL_ENT ); + if( !strcmp( entry->text, "none" ) ) editor_settool( EDITOR_TOOL_NONE ); + else if( !strcmp( entry->text, "select" ) ) editor_settool( EDITOR_TOOL_SELECT ); + else if( !strcmp( entry->text, "wall" ) ) editor_settool( EDITOR_TOOL_WALL ); + else if( !strcmp( entry->text, "poly" ) ) editor_settool( EDITOR_TOOL_POLY ); + else if( !strcmp( entry->text, "sprite" ) ) editor_settool( EDITOR_TOOL_SPRITE ); + else if( !strcmp( entry->text, "ent" ) ) editor_settool( EDITOR_TOOL_ENT ); } } diff --git a/src/editor/editor_window.cpp b/src/editor/editor_window.cpp index 51ca67d..bd70418 100644 --- a/src/editor/editor_window.cpp +++ b/src/editor/editor_window.cpp @@ -108,7 +108,7 @@ void editor_update_toolview( GAME_EDITOR* e ) { gui_editor_toolview_update( egui->tool ); } -void settool( U8 t ) { +void editor_settool( U8 t ) { editor->tool.type = t; if( editor->gui.v2d ) editor->gui.v2d->poly_drag = 0; @@ -116,6 +116,10 @@ void settool( U8 t ) { editor_update_toolview( editor ); } +void settool( U8 t ) { + editor_settool( t ); +} + const char* editor_tool_name() { switch( editor->tool.type ) { case EDITOR_TOOL_SELECT: return "select"; diff --git a/src/game.cpp b/src/game.cpp index b356917..a0452db 100644 --- a/src/game.cpp +++ b/src/game.cpp @@ -1,3 +1,4 @@ +#include <stdint.h> #include <unistd.h> #include "game.h" @@ -17,6 +18,8 @@ #include "gui.h" #include "render/gl_batch.h" #include "util.h" +#include "util/profiler.h" +#include "util/time.h" CVAR* g_timescale = var_new( "g_timescale", 1.f ); @@ -27,10 +30,11 @@ GAME_DATA* game_init( GL_DATA* gl ) { memset( game, 0, sizeof(GAME_DATA) ); game->gl = gl; + profiler_init(); + VEC2 screensize = { (F32)gl->canvas_size[0], (F32)gl->canvas_size[1] }; game->shaders.gl2d = gl_2d_init( gl, screensize, "2d" ); - game->shaders.gl2d_texcoord = gl_2d_init( gl, screensize, "2d_texcoord" ); game->shaders.gl3d = gl_3d_init( gl, screensize, "3d" ); game_create_batches( game ); @@ -121,7 +125,7 @@ void game_draw( GAME_DATA* game ) { world_draw( game, objl->world, window, winsize ); } -static void game_realtime_resize_repaint( void* userdata ) { +void game_realtime_resize_repaint( void* userdata ) { GAME_DATA* game = (GAME_DATA*)userdata; if( !game || !game->gl ) return; @@ -158,15 +162,15 @@ static void game_realtime_resize_repaint( void* userdata ) { SDL_GL_SwapWindow( gl->window ); } -void game_main_loop( GAME_DATA* game ) { +U8 game_main_loop( GAME_DATA* game ) { _profiled GL_DATA* gl = game->gl; GL_SHADER_PROGRAM* gl2d = game->shaders.gl2d; if( !OK( gl_poll_events( gl ) ) ) - exit( 0 ); + return 1; if( !assets_on_frame( game ) ) - return; + return 0; gl_sync_window_size( gl ); gl_beginframe( gl ); @@ -189,18 +193,29 @@ void game_main_loop( GAME_DATA* game ) { } gui_onframe( game ); + profiler_draw_tree( game->assets.jpn12 ); + #if defined(DEBUG) && !IS_EDITOR game_draw_fpsoverlay( game ); #endif if( !OK( gl_endframe( gl ) ) ) - exit( 0 ); + return 1; + + return 0; } -void game_on_tick( GAME_DATA* game ) { +void game_on_tick( GAME_DATA* game ) { _profiled U64 tick = u_tick(); - if( tick - game->state.last_tick > (U64)(TICK_INTERVAL * 10000) * (1.f / var_getf( g_timescale )) ) { + U64 ticks = TICK_INTERVAL * TICK_RESOLUTION; + F32 ts = var_getf( g_timescale ); + if( ts != 1.f && ts > 0.f ) + ticks *= (1.f / ts); + else if( !ts ) + ticks = INT64_MAX; + + if( tick - game->state.last_tick > ticks ) { player_move( game, objl->pl ); game->state.last_tick = tick; } @@ -1,4 +1,6 @@ #pragma once +// disable new_delete_type_mismatch asan warning + #define IS_EDITOR 1 #include "game/assets.h" @@ -19,7 +21,6 @@ extern struct CVAR* g_timescale; typedef struct { GL_SHADER_PROGRAM* gl2d; - GL_SHADER_PROGRAM* gl2d_texcoord; struct GL3D* gl3d; } GAME_SHADERS; @@ -51,7 +52,7 @@ extern void ui_draw_background( GAME_DATA* game, VEC2 pos, VEC2 dim, F32 progres extern GAME_DATA* game_init( GL_DATA* gl ); extern void game_create_batches( GAME_DATA* game ); -extern void game_main_loop( GAME_DATA* game ); +extern U8 game_main_loop( GAME_DATA* game ); extern void game_on_tick( GAME_DATA* game ); extern void game_destroy( GAME_DATA* game ); diff --git a/src/game/physics/movement.cpp b/src/game/physics/movement.cpp index d689096..3979394 100644 --- a/src/game/physics/movement.cpp +++ b/src/game/physics/movement.cpp @@ -22,7 +22,7 @@ void gmove_init( GAME_DATA* game ) { gmove->game = game; } -U8 gmove_check_valid( STR<256> from ) { +U8 gmove_check_valid( ARRSTR<256> from ) { if( !gmove->game ) { dlog( "%s : game not init\n", from.data ); return 0; diff --git a/src/game/raycast.cpp b/src/game/raycast.cpp index d38eb0a..0d2dbe3 100644 --- a/src/game/raycast.cpp +++ b/src/game/raycast.cpp @@ -147,7 +147,7 @@ void ray_draw_world2d( GAME_DATA* game, WORLD* world ) { } ); if( props->tex ) - gl_textured_polygon( game->shaders.gl2d_texcoord, verts.data, verts.size, props->tex ); + gl_textured_polygon( game->shaders.gl2d, verts.data, verts.size, props->tex ); else gl_polygon( game->shaders.gl2d, verts.data, verts.size ); } diff --git a/src/game/vars.cpp b/src/game/vars.cpp index 3d1eaf4..4d48125 100644 --- a/src/game/vars.cpp +++ b/src/game/vars.cpp @@ -107,14 +107,14 @@ I32 var_call( CVAR *cmdvar, const char *cmdline ) { F32 var_getf( CVAR *var ) { switch( var->type ) { case CVAR_TYPE_FLOAT: return var->fl_v; - case CVAR_TYPE_INT: return (F32)var->fl_v; + case CVAR_TYPE_INT: return (F32)var->i_v; default: return 0.f; } } I32 var_geti( CVAR *var ) { switch( var->type ) { - case CVAR_TYPE_INT: return var->fl_v; + case CVAR_TYPE_INT: return var->i_v; case CVAR_TYPE_FLOAT: return (I32)var->fl_v; default: return 0; } diff --git a/src/game/world/bsp.cpp b/src/game/world/bsp.cpp index b55593f..c4928a3 100644 --- a/src/game/world/bsp.cpp +++ b/src/game/world/bsp.cpp @@ -853,6 +853,15 @@ BSP* bsp_build_map( WORLD_MAP* m ) { } void bsp_free( BSP* bsp ) { + for( auto& it : bsp->faces ) { + it.verts.clear(); + it.render_verts.clear(); + } + for( auto& it : bsp->leaves ) + it.edges.clear(); + for( auto& it : bsp->portals ) + it.w.points.clear(); + delete bsp; } diff --git a/src/game/world/draw.cpp b/src/game/world/draw.cpp index aad4d09..2856edd 100644 --- a/src/game/world/draw.cpp +++ b/src/game/world/draw.cpp @@ -153,7 +153,7 @@ void world_draw_sprites( } } -void world_draw( GAME_DATA* game, WORLD* world, VEC2 window, VEC2 winsize ) { +void world_draw( GAME_DATA* game, WORLD* world, VEC2 window, VEC2 winsize ) { _profiled PLAYER* pl = objl->pl; VEC2 start = { pl->pos.x, pl->pos.y }; diff --git a/src/gui/base.cpp b/src/gui/base.cpp index 5d345d8..1e8a493 100644 --- a/src/gui/base.cpp +++ b/src/gui/base.cpp @@ -38,7 +38,7 @@ void gui_end() { void gui_draw( GAME_DATA* game ) { _gui.gl2d = game->shaders.gl2d; - _gui.gl2d_font = game->shaders.gl2d_texcoord; + _gui.gl2d_font = game->shaders.gl2d; _gui.windows.each( fn( GUI_WINDOW** w ) { GUI_WINDOW* wnd = *w; @@ -58,7 +58,7 @@ void gui_input( GAME_DATA* game ) { } } -void gui_onframe( GAME_DATA* game ) { +void gui_onframe( GAME_DATA* game ) { _profiled gui_run_callbacks(); gui_input( game ); diff --git a/src/gui/view.cpp b/src/gui/view.cpp index da470e7..d053f99 100644 --- a/src/gui/view.cpp +++ b/src/gui/view.cpp @@ -1,6 +1,7 @@ #include "base.h" +#include "../util/profiler.h" -void gui_view_draw_fn( void* ptr ) { +void gui_view_draw_fn( void* ptr ) { _profiled GUI_VIEW* view = (GUI_VIEW*)ptr; I32 x = gui_relx( view ); diff --git a/src/main.cpp b/src/main.cpp index 5d70ef8..451c014 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,7 +1,6 @@ #include "game.h" #include "game/assets.h" -// disable new_delete_type_mismatch asan warning #ifndef __has_feature #define __has_feature(feature) 0 #endif @@ -16,7 +15,7 @@ I32* canvas; GAME_DATA* game; GL_DATA* gl; -void loop() { +U8 loop() { static U8 init = 0; if( !init || !gl ) { @@ -27,10 +26,10 @@ void loop() { game = game_init( gl ); init = 1; - return; + return 0; } - game_main_loop( game ); + return game_main_loop( game ); } int main(int argc, char* argv[]) { @@ -40,8 +39,8 @@ int main(int argc, char* argv[]) { canvas[0] = 800; canvas[1] = 600; - while( true ) { - loop(); + for( ;; ) { + if( loop() ) break; } game_destroy( game ); diff --git a/src/render/gl.cpp b/src/render/gl.cpp index 4e9ed9d..c1b6d19 100644 --- a/src/render/gl.cpp +++ b/src/render/gl.cpp @@ -19,11 +19,11 @@ 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 ); +void gl_apply_canvas_size( GL_DATA* gl, I32 width, I32 height ); +void gl_handle_window_size_change( GL_DATA* gl, I32 width, I32 height ); +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 ) { +void gl_query_canvas_size( GL_DATA* gl, I32* width, I32* height ) { I32 w = 0; I32 h = 0; if( gl && gl->window ) { @@ -36,7 +36,7 @@ static void gl_query_canvas_size( GL_DATA* gl, I32* width, I32* height ) { if( height ) *height = max( 1, h ); } -static void gl_constrain_window_size( I32* width, I32* height ) { +void gl_constrain_window_size( I32* width, I32* height ) { if( !width || !height ) return; @@ -61,7 +61,7 @@ static void gl_constrain_window_size( I32* width, I32* height ) { } } -static void gl_handle_window_size_change( GL_DATA* gl, I32 width, I32 height ) { +void gl_handle_window_size_change( GL_DATA* gl, I32 width, I32 height ) { if( !gl || !gl->window ) return; @@ -85,7 +85,7 @@ static void gl_handle_window_size_change( GL_DATA* gl, I32 width, I32 height ) { gl_apply_canvas_size( gl, draw_w, draw_h ); } -static I32 SDLCALL gl_event_filter( void* userdata, SDL_Event* e ) { +I32 SDLCALL gl_event_filter( void* userdata, SDL_Event* e ) { GL_DATA* gl = (GL_DATA*)userdata; if( !gl || !e ) return 1; @@ -106,7 +106,7 @@ static I32 SDLCALL gl_event_filter( void* userdata, SDL_Event* e ) { return 1; } -static void gl_apply_canvas_size( GL_DATA* gl, I32 width, I32 height ) { +void gl_apply_canvas_size( GL_DATA* gl, I32 width, I32 height ) { width = max( 1, width ); height = max( 1, height ); @@ -126,7 +126,7 @@ static void gl_apply_canvas_size( GL_DATA* gl, I32 width, I32 height ) { glUseProgram( 0 ); } -static void gl_update_screen_ratio_uniforms( GL_DATA* gl, I32 width, I32 height ) { +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 ), @@ -486,13 +486,14 @@ STAT gl_endframe( GL_DATA* gl ) { // 1000 fps max be real while( true ) { U64 diff = u_tick() - gl->last_tick; - if( diff < 10 ) + if( diff < TICK_RESOLUTION / 1000 ) usleep( 10 ); else break; } - gl->frametime = (F32)(u_tick() - gl->last_tick) / 10000.0f; - gl->fps = 1.0f / gl->frametime; + F64 delta = (F64)(u_tick() - gl->last_tick) / TICK_RESOLUTION; + gl->frametime = (F32)delta; + gl->fps = 1.f / delta; input_frame_end(); return STAT_OK; diff --git a/src/render/gl.h b/src/render/gl.h index dfb76b3..b673d47 100644 --- a/src/render/gl.h +++ b/src/render/gl.h @@ -15,7 +15,7 @@ struct VERTEX { VEC2 pos; VEC2 uv; CLR clr; - U8 sampler; + U8 sampler = 255; }; struct GL_SHADER_DEF { diff --git a/src/render/gl_2d.cpp b/src/render/gl_2d.cpp index 78af1da..b5203b2 100644 --- a/src/render/gl_2d.cpp +++ b/src/render/gl_2d.cpp @@ -1,5 +1,6 @@ #include "gl_2d.h" #include "../util.h" +#include "gl.h" GL_SHADER_PROGRAM* gl_2d_init( GL_DATA* gl, VEC2 screensize, const char* shadername ) { GL_SHADER_PROGRAM* program = gl_program_create( gl, shadername ); @@ -41,9 +42,13 @@ void gl_2d_line( GL_SHADER_PROGRAM* gl2d, VEC2 start, VEC2 end, CLR col ) { I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); - I32 color = glGetAttribLocation( gl2d->id, "in_col" ); + I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); + I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); + glEnableVertexAttribArray( sampler ); + glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); + glBindBuffer( GL_ARRAY_BUFFER, 0 ); glDrawElements( GL_LINES, 2, GL_UNSIGNED_SHORT, order ); @@ -67,12 +72,16 @@ void gl_2d_rect( GL_SHADER_PROGRAM* gl2d, VEC2 origin, VEC2 dim, CLR col ) { I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); - I32 color = glGetAttribLocation( gl2d->id, "in_col" ); + I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); + I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); + glEnableVertexAttribArray( sampler ); + glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); + glBindBuffer( GL_ARRAY_BUFFER, 0 ); - glDrawElements( GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, order ); + glDrawElements( GL_LINE_STRIP, 5, GL_UNSIGNED_SHORT, order ); } void gl_2d_textured_frect( GL_SHADER_PROGRAM* gl2d, VEC2 origin, VEC2 dim, GL_TEX2D* texture, CLR col, VEC2* uv, F32 rotation ) { @@ -106,7 +115,7 @@ void gl_2d_textured_frect( GL_SHADER_PROGRAM* gl2d, VEC2 origin, VEC2 dim, GL_TE glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_DYNAMIC_DRAW ); I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); - I32 color = glGetAttribLocation( gl2d->id, "in_col" ); + I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); @@ -152,23 +161,21 @@ void gl_2d_frect( GL_SHADER_PROGRAM* gl2d, VEC2 origin, VEC2 dim, CLR col ) { glBufferData( GL_ARRAY_BUFFER, sizeof(vertices), &vertices[0], GL_DYNAMIC_DRAW ); I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); - I32 color = glGetAttribLocation( gl2d->id, "in_col" ); + I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); - if (position >= 0) { - glEnableVertexAttribArray( position ); - glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); - } - - if (color >= 0) { - glEnableVertexAttribArray( color ); - glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); - } + glEnableVertexAttribArray( position ); + glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); + + glEnableVertexAttribArray( color ); + glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); - if (texcoord >= 0) { - glEnableVertexAttribArray( texcoord ); - glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); - } + glEnableVertexAttribArray( texcoord ); + glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); + + I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); + glEnableVertexAttribArray( sampler ); + glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); glDrawElements( GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_SHORT, order ); @@ -205,9 +212,12 @@ void gl_2d_circle( GL_SHADER_PROGRAM* gl2d, VEC2 origin, F32 radius, CLR col, U3 I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); - I32 color = glGetAttribLocation( gl2d->id, "in_col" ); + I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); + I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); + glEnableVertexAttribArray( sampler ); + glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); @@ -255,12 +265,15 @@ void gl_2d_fcircle( GL_SHADER_PROGRAM* gl2d, VEC2 origin, F32 radius, CLR col, U I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); - I32 color = glGetAttribLocation( gl2d->id, "in_col" ); + I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); glEnableVertexAttribArray( texcoord ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); + I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); + glEnableVertexAttribArray( sampler ); + glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); @@ -277,12 +290,15 @@ void gl_polygon( GL_SHADER_PROGRAM* gl2d, VERTEX* vertices, U32 vertices_count ) I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); - I32 color = glGetAttribLocation( gl2d->id, "in_col" ); + I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); glEnableVertexAttribArray( texcoord ); glVertexAttribPointer( texcoord, 2, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->uv ); + I32 sampler = glGetAttribLocation( gl2d->id, "in_sampler" ); + glEnableVertexAttribArray( sampler ); + glVertexAttribPointer( sampler, 1, GL_UNSIGNED_BYTE, 1, sizeof(VERTEX), &( (VERTEX*)nullptr)->sampler ); glBindBuffer( GL_ARRAY_BUFFER, 0 ); @@ -309,7 +325,7 @@ void gl_textured_polygon( I32 position = glGetAttribLocation( gl2d->id, "in_pos" ); glEnableVertexAttribArray( position ); glVertexAttribPointer( position, 2, GL_FLOAT, 0, sizeof(VERTEX), 0 ); - I32 color = glGetAttribLocation( gl2d->id, "in_col" ); + I32 color = glGetAttribLocation( gl2d->id, "in_clr" ); glEnableVertexAttribArray( color ); glVertexAttribPointer( color, 4, GL_FLOAT, 0, sizeof(VERTEX), &( (VERTEX*)nullptr)->clr ); I32 texcoord = glGetAttribLocation( gl2d->id, "in_texcoord" ); diff --git a/src/render/gl_3d.cpp b/src/render/gl_3d.cpp index 8449500..85e89b9 100644 --- a/src/render/gl_3d.cpp +++ b/src/render/gl_3d.cpp @@ -178,10 +178,10 @@ void build_plane( VERTEX3D* v, VEC3 pos, VEC2 size, VEC2 rot, CLR col ) { { 0.0f, 0.0f } }; - v[0] = { .pos = { vertices[0].x, vertices[0].z, vertices[0].y }, .uv = uvs[0], .clr = col, .sampler = 0 }; - v[1] = { .pos = { vertices[1].x, vertices[1].z, vertices[1].y }, .uv = uvs[1], .clr = col, .sampler = 0 }; - v[2] = { .pos = { vertices[2].x, vertices[2].z, vertices[2].y }, .uv = uvs[2], .clr = col, .sampler = 0 }; - v[3] = { .pos = { vertices[3].x, vertices[3].z, vertices[3].y }, .uv = uvs[3], .clr = col, .sampler = 0 }; + v[0] = { .pos = { vertices[0].x, vertices[0].z, vertices[0].y }, .uv = uvs[0], .clr = col }; + v[1] = { .pos = { vertices[1].x, vertices[1].z, vertices[1].y }, .uv = uvs[1], .clr = col }; + v[2] = { .pos = { vertices[2].x, vertices[2].z, vertices[2].y }, .uv = uvs[2], .clr = col }; + v[3] = { .pos = { vertices[3].x, vertices[3].z, vertices[3].y }, .uv = uvs[3], .clr = col }; } void gl_3d_plane( @@ -1,7 +1,4 @@ #pragma once -#include <SDL.h> - -#include "SDL_timer.h" #include "util/color.h" #include "util/allocator.h" #include "util/vector.h" @@ -9,23 +6,8 @@ #include "util/config.h" #include "util/screen.h" #include "util/input.h" +#include "util/time.h" #include "util/file.h" +#include "util/profiler.h" #include "util/thread.h" -inline U64 u_tick() { - return (F64)SDL_GetPerformanceCounter() * 10000 / ((F64)SDL_GetPerformanceFrequency() ); -} - -inline F32 u_time() { - return SDL_GetTicks64() / 1000.f; -} - -template < typename T > -T min( T a, T b ) { - return a < b? a : b; -} - -template < typename T > -T max( T a, T b ) { - return a > b? a : b; -} diff --git a/src/util/allocator.h b/src/util/allocator.h index 27b21c0..64bad23 100644 --- a/src/util/allocator.h +++ b/src/util/allocator.h @@ -5,10 +5,23 @@ #include <functional> #include "typedef.h" -template < typename T > +template <typename T> +struct LIST_ITERATOR { + T* ptr; + + LIST_ITERATOR( T* ptr ) : ptr( ptr ) {} + T& operator*() { return *ptr; } + T* operator->() { return ptr; } + LIST_ITERATOR& operator++() { ptr++; return *this; } + LIST_ITERATOR operator+=( U8 n ) { ptr += n; return *this; } + bool operator==( const LIST_ITERATOR& other ) { return ptr == other.ptr; } + bool operator!=( const LIST_ITERATOR& other ) { return ptr != other.ptr; } +}; + +template <typename T> using QSORT_FN = std::function< U8( T*, T* ) >; -template < typename T > +template <typename T> static U8 qsort_basic_sort( T* t1, T* t2 ) { return (*t1 > *t2); } @@ -63,6 +76,13 @@ struct LIST { size = 0; } + LIST( U32 _size, const T* data ) { + data = (T*)malloc( sizeof( T ) * _size ); + memcpy( data, data, _size * sizeof( T ) ); + size = _size; + capacity = _size; + } + LIST( const LIST<T>& other ) { if( !other.capacity || !other.size ) { capacity = 1; @@ -91,6 +111,7 @@ struct LIST { capacity = 1; size = 0; data = (T*)malloc( sizeof( T ) ); + memset( data, 0, sizeof( T ) ); return *this; } @@ -106,6 +127,10 @@ struct LIST { free( data ); } + T at( U32 index ) { + return data[index]; + } + void reserve( U32 count ) { if( capacity >= count ) return; @@ -320,4 +345,12 @@ struct LIST { ret.sort( fn ); return ret; } + + LIST_ITERATOR<T> begin() { + return LIST_ITERATOR<T>( data ); + } + + LIST_ITERATOR<T> end() { + return LIST_ITERATOR<T>( data + size ); + } }; diff --git a/src/util/math.h b/src/util/math.h index add705a..7bae125 100644 --- a/src/util/math.h +++ b/src/util/math.h @@ -57,18 +57,18 @@ inline F32 m_snap_to_grid( F32 x, F32 grid ) { } template <typename T> -inline T m_min( T a, T b ) { - return a < b ? a : b; +T min( T a, T b ) { + return a < b? a : b; } template <typename T> -inline T m_max( T a, T b ) { - return a > b ? a : b; +T max( T a, T b ) { + return a > b? a : b; } template <typename T> inline T m_clamp( T x, T a, T b ) { - return m_min( m_max( x, a ), b ); + return min( max( x, a ), b ); } extern VEC2 m_screen_transform( const VEC3& world ); diff --git a/src/util/profiler.cpp b/src/util/profiler.cpp new file mode 100644 index 0000000..86c1810 --- /dev/null +++ b/src/util/profiler.cpp @@ -0,0 +1,55 @@ +#if defined(DEBUG) || defined(PROFILER) +#include "profiler.h" +#include "../render/gl_2d_font.h" +#include "../game/vars.h" +#include "string.h" + +CVAR* prof_overlay = var_new( "prof_overlay", 0 ); +PROFILER_GLOBAL gprof; + +void __profiler_intern_draw_tree( PROFILER_LIST_ENTRY* e, GL_FONT* font, I32* x, I32* y ) { + GL_DATA* gl = gl_instance(); + static GL_SHADER_PROGRAM** gl2d = gl->programs.where( fn( GL_SHADER_PROGRAM** p ) { + return STR( (*p)->name ) == "2d" ; + } ); + + if( !gl2d ) + return; + + STR line; + if( e->parent ) { + U64 parent_dur = e->parent->duration; + U64 percent = (F64)parent_dur / e->duration * 100.f; + line = STR( "%s -> duration: %.2fms [%.0f%%]", + e->name, + (F32)e->duration / TICK_RESOLUTION * 1000.f, + percent + ); + } else { + line = STR( "%s -> duration: %.2fms", + e->name, + (F32)e->duration / TICK_RESOLUTION * 1000.f + ); + } + + gl_font_draw( font, *gl2d, VEC2{ (F32)*x + 1, (F32)*y + 1 }, line, CLR::BLACK() ); + gl_font_draw( font, *gl2d, VEC2{ (F32)*x, (F32)*y }, line, CLR::WHITE() ); + + *y += font->size + 1; + *x += 20; + for( auto& it : e->children ) + __profiler_intern_draw_tree( &it, font, x, y ); + *x -= 20; +} + +void __profiler_intern_draw_overlay( struct GL_FONT* f ) { + if( !var_geti( prof_overlay ) ) + return; + + I32 x = 50, y = 50; + for( auto& it : gprof.frames ) + __profiler_intern_draw_tree( &it, f, &x, &y ); +} + + +#endif diff --git a/src/util/profiler.h b/src/util/profiler.h new file mode 100644 index 0000000..c8eea24 --- /dev/null +++ b/src/util/profiler.h @@ -0,0 +1,139 @@ +#pragma once + +#if defined(DEBUG) || defined(PROFILER) +#include "allocator.h" +#include "time.h" +#include "thread.h" +#include "fnv.h" + +static THREAD_MUTEX __profiler_intern_mutex; + +#ifndef __func__ + #define __func__ __FUNCTION__ +#endif + +#define PROFILE( x ) \ + PROFILER_LIST_ENTRY* __profiler_intern_id = __profiler_intern_start( x ); \ + defer( { __profiler_intern_end( __profiler_intern_id ); } ) + +#define _profiled PROFILE( __func__ ); + + +struct PROFILER_LIST_ENTRY { + LIST<PROFILER_LIST_ENTRY> children; + const char* name; + U64 duration; + U64 start; + FNV1A hash; + + PROFILER_LIST_ENTRY* parent; +}; + +struct PROFILER_GLOBAL { + LIST<PROFILER_LIST_ENTRY> frames; + LIST<PROFILER_LIST_ENTRY> stack; + PROFILER_LIST_ENTRY* current = 0; +}; + +extern struct CVAR* prof_overlay; +extern PROFILER_GLOBAL gprof; + +inline PROFILER_LIST_ENTRY* __profiler_intern_is_root( FNV1A hash ) { + for( auto& it : gprof.stack ) { + if( it.hash == hash ) { + return ⁢ + } + } + return 0; +} + + +inline void __profiler_intern_clear_frame( PROFILER_LIST_ENTRY* entry ) { + entry->children.each( __profiler_intern_clear_frame ); + entry->children.clear(); +} + +inline void __profiler_intern_new_frame_child( PROFILER_LIST_ENTRY* entry ) { + for( auto& it : entry->children ) { + __profiler_intern_new_frame_child( &it ); + it.parent = entry; + } +} + +inline void __profiler_intern_new_frame( PROFILER_LIST_ENTRY* entry ) { + PROFILER_LIST_ENTRY ne = *entry; + U32 i = gprof.frames.idx_where( fn( PROFILER_LIST_ENTRY* pe ) { + return pe->hash == entry->hash; + } ); + + if( i != -1 ) { + __profiler_intern_clear_frame( &gprof.frames.data[i] ); + gprof.frames.erase( i ); + } + + PROFILER_LIST_ENTRY* pne = gprof.frames.push( ne ); + for( auto& it : pne->children ) { + it.parent = pne; + __profiler_intern_new_frame_child( &it ); + } +} + +inline PROFILER_LIST_ENTRY* __profiler_intern_start( const char* name ) { + PROFILER_LIST_ENTRY e; + FNV1A fnv = fnv1a( name ); + U64 tick = u_tick(); + PROFILER_LIST_ENTRY* ep; + + thread_mutex_lock( &__profiler_intern_mutex ); + defer( thread_mutex_unlock( &__profiler_intern_mutex ) ); + if( (ep = __profiler_intern_is_root( fnv )) != 0 ) { + __profiler_intern_new_frame( ep ); + ep->children.clear(); + ep->start = tick; + gprof.current = ep; + return ep; + } + + e.name = name; + e.children = LIST<PROFILER_LIST_ENTRY>(); + memset( e.children.data, 0, sizeof(PROFILER_LIST_ENTRY) ); + e.duration = 0; + e.start = tick; + e.children = {}; + e.parent = gprof.current; + e.hash = fnv; + + if( gprof.current ) + ep = gprof.current->children.push( e ); + else + ep = gprof.stack.push( e ); + + gprof.current = ep; + return ep; +} + +inline void __profiler_intern_end( PROFILER_LIST_ENTRY* entry ) { + U64 tick = u_tick(); + + thread_mutex_lock( &__profiler_intern_mutex ); + entry->duration = tick - entry->start; + if( gprof.current ) + gprof.current = gprof.current->parent; + thread_mutex_unlock( &__profiler_intern_mutex ); +} + +inline void __profiler_intern_init() { + thread_mutex_init( &__profiler_intern_mutex ); +} + +extern void __profiler_intern_draw_overlay( struct GL_FONT* font ); + +#define profiler_init() __profiler_intern_init() +#define profiler_draw_tree( font ) __profiler_intern_draw_overlay( font ) + +#else +#define PROFILE( x ) +#define _profiled +#define profiler_init() +#define profiler_draw_tree( x ) +#endif diff --git a/src/util/string.h b/src/util/string.h index 47da1a0..0781fca 100644 --- a/src/util/string.h +++ b/src/util/string.h @@ -1,7 +1,9 @@ #pragma once +#include <cstdio> +#include <stdarg.h> #include <string.h> -#include "typedef.h" +#include "allocator.h" constexpr U32 strlen_ct( const char* str ) { U32 len = 0; @@ -10,40 +12,215 @@ constexpr U32 strlen_ct( const char* str ) { } template <U32 N> -struct STR { +struct ARRSTR { char data[N]{ 0 }; enum { size = N }; - STR() { + ARRSTR() { memset( data, 0, N ); } - STR( const char* str ) { + ARRSTR( const char* str ) { memcpy( data, str, strlen_ct( str ) ); } - STR( const STR<N>& str ) { + ARRSTR( const ARRSTR<N>& str ) { memcpy( data, str.data, N ); } template <U32 other> - auto operator+( const STR<other>& rhs ) { - constexpr U32 l1 = strlen_ct( data ); - constexpr U32 l2 = strlen_ct( rhs.data ); + auto operator+( const ARRSTR<other>& rhs ) { + const U32 l1 = strlen_ct( data ); + const U32 l2 = strlen_ct( rhs.data ); - constexpr U32 high = N > other ? N : other; - constexpr U32 max = (l1 + l2 > high) ? l1 + l2 + 1 : high; + if( l1 + l2 >= N ) { + dlog( "STR::operator+(): string overflow" ); + abort(); + return *this; + } - STR<max> result; - memcpy( result.data, data, l1 ); - memcpy( result.data + l1, rhs.data, l2 ); - result.data[l1 + l2] = '\0'; - return result; + memcpy( data + l1, rhs.data, l2 ); + data[l1 + l2] = '\0'; + return *this; } template <U32 other> - auto concat( const STR<other>& str ) { + auto concat( const ARRSTR<other>& str ) { return *this + str; } operator char*() { return data; } }; + +template <typename CT> +struct __str : public LIST<CT> { + __str() : LIST<CT>() {} + __str( const CT* fmt, ... ) : LIST<CT>() { + va_list args; + va_start( args, fmt ); + va_list args2; + va_copy( args2, args ); + U32 c = vsnprintf( 0, 0, fmt, args ); + va_end( args ); + this->data = 0; + this->reserve( c * 2 ); + vsnprintf( this->data, c + 1, fmt, args2 ); + this->data[c] = 0; + this->size = c; + va_end( args2 ); + } + + __str( const __str<CT>& rhs ) : LIST<CT>( rhs ) { + this->data[this->size] = 0; + } + + __str<CT>& operator=( const __str<CT>& other ) { + if( this == &other ) + return *this; + + if( this->data && this->data != other.data ) + free( this->data ); + + this->data = 0; + + if( !other.capacity || !other.size ) { + this->capacity = 1; + this->size = 0; + this->data = (CT*)malloc( sizeof(CT) ); + memset( this->data, 0, sizeof(CT) ); + return *this; + } + + this->data = (CT*)malloc( other.capacity * sizeof( CT ) ); + memcpy( this->data, other.data, (other.size + 1) * sizeof( CT ) ); + this->size = other.size; + this->capacity = other.capacity; + + return *this; + } + + const bool operator==( const __str<CT>& rhs ) { return this->equals( rhs ); } + const bool operator!=( const __str<CT>& rhs ) { return !(*this == rhs); } + const bool operator==( const CT* rhs ) { return this->equals( rhs ); } + const bool operator!=( const CT* rhs ) { return !(*this == rhs); } + __str<CT> operator+( const __str<CT>& rhs ) { __str<CT> ret = *this; return ret.append( rhs ); } + __str<CT> operator+( const CT* rhs ) { __str<CT> ret = *this; return ret.append( rhs ); } + __str<CT> operator+( const CT rhs ) { __str<CT> ret = *this; ret.push( rhs ); return ret; } + __str<CT>& operator+=( const __str<CT>& rhs ) { return this->append( rhs ); } + __str<CT>& operator+=( const CT* rhs ) { return this->append( rhs ); } + __str<CT>& operator+=( const CT rhs ) { this->push( rhs ); return this; } + + operator CT*() { return this->data; } + + CT operator[]( U32 i ) { + return this->data[i]; + } + + U8 equals( const __str<CT>& rhs ) { + if( rhs.size != this->size ) + return 0; + + for( U32 i = 0; i < this->size; ++i ) { + if( this->data[i] != rhs.data[i] ) + return 0; + } + + return 1; + } + + U8 equals( const CT* rhs ) { + for( U32 i = 0; i < this->size; ++i ) { + if( !rhs[i] || this->data[i] != rhs[i] ) + return 0; + } + + return 1; + } + + __str<CT>& fmt( const char* fmt, ... ) { + va_list args; + va_start( args, fmt ); + va_list args2; + va_copy( args2, args ); + U32 c = this->size + vsnprintf( 0, 0, fmt, args ); + va_end( args ); + if( c > this->capacity ) + this->reserve( c * 2 ); + vsnprintf( this->data + this->size, c + 1, fmt, args2 ); + this->data[c] = 0; + this->size = c; + va_end( args2 ); + } + + __str<CT>& append( const CT* str ) { + U32 len; + for( len = 0; !!str[len]; ++len ); + if( this->size + len > this->capacity ) + this->reserve( this->size * 2 ); + + memcpy( this->data + this->size, str, len * sizeof(CT) ); + this->size += len; + this->data[this->size] = 0; + return *this; + } + + __str<CT>& append( const __str<CT>& str ) { + U32 len = str.len; + if( this->size + len + 1 >= this->capacity ) + this->reserve( this->size + len + 1 ); + + memcpy( this->data + this->size, str, len * sizeof(CT) ); + this->size += len; + this->data[this->size] = 0; + return *this; + } + + CT* push( const CT& item ) { + if( this->capacity <= this->size + 1 ) + this->grow(); + this->data[this->size++] = item; + this->data[this->size] = 0; + + return &this->data[this->size - 1]; + } + + U32 idx_of( const CT* str ) { + return idx_of( str, 0 ); + } + + U32 idx_of( const CT* str, U32 offset ) { + for( U32 i = offset; i < this->size; ++i ) { + U8 found = 1; + for( U32 i2 = 0; !!str[i2] && i + i2 < this->size; ++i2 ) { + if( this->data[i + i2] != str[i2] ) { + found = 0; + break; + } + } + + if( found ) + return i; + } + } + + CT* find( const CT* str ) { + for( U32 i = 0; i < this->size; ++i ) { + U8 found = 1; + for( U32 i2 = 0; !!str[i2] && i + i2 < this->size; ++i2 ) { + if( this->data[i + i2] != str[i2] ) { + found = 0; + break; + } + } + if( found ) + return this->data + i; + } + return 0; + } + + LIST_ITERATOR<CT> end() { + return LIST_ITERATOR<CT>( this->data + this->size ); + } +}; + +using STR = __str<char>; +using WSTR = __str<wchar_t>; diff --git a/src/util/time.h b/src/util/time.h new file mode 100644 index 0000000..ae696c5 --- /dev/null +++ b/src/util/time.h @@ -0,0 +1,21 @@ +#pragma once + +#include <SDL.h> +#include <SDL_timer.h> + +#include "typedef.h" + +const U32 TICK_RESOLUTION = 1000000; + +inline U64 u_tick() { + return (SDL_GetPerformanceCounter() * TICK_RESOLUTION / SDL_GetPerformanceFrequency()); +} + +inline F32 u_time() { + return (F32)((F64)u_tick() / TICK_RESOLUTION); +} + +inline F64 u_time64() { + return (F64)u_tick() / TICK_RESOLUTION; +} + |
