summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoraura <nw@moneybot.cc>2026-03-10 01:35:50 +0100
committeraura <nw@moneybot.cc>2026-03-10 01:35:50 +0100
commit8329d42d3e592f4cd42cdfa586e2325ddc76c898 (patch)
treedec7e2a733bfc6b6384936c1f3ed067a42b59bb9
parent8ae8c85e9d3806cdb726e07f37e1b49484c5c48e (diff)
perf profiler, simplify 2d render, string struct, many small things
-rw-r--r--assets/shaders/2d.fsh14
-rw-r--r--assets/shaders/2d.vsh15
-rw-r--r--assets/shaders/2d_texcoord.fsh19
-rw-r--r--assets/shaders/2d_texcoord.vsh28
-rw-r--r--src/editor/editor_gui_internal.h52
-rw-r--r--src/editor/editor_infobox.cpp4
-rw-r--r--src/editor/editor_menubar.cpp12
-rw-r--r--src/editor/editor_window.cpp6
-rw-r--r--src/game.cpp31
-rw-r--r--src/game.h5
-rw-r--r--src/game/physics/movement.cpp2
-rw-r--r--src/game/raycast.cpp2
-rw-r--r--src/game/vars.cpp4
-rw-r--r--src/game/world/bsp.cpp9
-rw-r--r--src/game/world/draw.cpp2
-rw-r--r--src/gui/base.cpp4
-rw-r--r--src/gui/view.cpp3
-rw-r--r--src/main.cpp11
-rw-r--r--src/render/gl.cpp25
-rw-r--r--src/render/gl.h2
-rw-r--r--src/render/gl_2d.cpp60
-rw-r--r--src/render/gl_3d.cpp8
-rw-r--r--src/util.h22
-rw-r--r--src/util/allocator.h37
-rw-r--r--src/util/math.h10
-rw-r--r--src/util/profiler.cpp55
-rw-r--r--src/util/profiler.h139
-rw-r--r--src/util/string.h209
-rw-r--r--src/util/time.h21
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;
}
diff --git a/src/game.h b/src/game.h
index 829f983..f0e1957 100644
--- a/src/game.h
+++ b/src/game.h
@@ -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(
diff --git a/src/util.h b/src/util.h
index 32fdb7e..d0e391f 100644
--- a/src/util.h
+++ b/src/util.h
@@ -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 &it;
+ }
+ }
+ 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;
+}
+