From 96c0065a6965bc4d93337eca9b235d252680994a Mon Sep 17 00:00:00 2001 From: hgn Date: Fri, 14 Jun 2024 20:47:44 +0100 Subject: [PATCH 01/16] move load guard here --- vg_engine.c | 10 ++++++++++ vg_engine.h | 9 ++++++++- 2 files changed, 18 insertions(+), 1 deletion(-) diff --git a/vg_engine.c b/vg_engine.c index a7e8a68..ed016be 100644 --- a/vg_engine.c +++ b/vg_engine.c @@ -119,6 +119,8 @@ void async_internal_complete( void *payload, u32 size ) } TEMP_STATUS_UNLOCK( &vg.sl_status ); + + vg.client_has_control = 1; } #ifdef VG_CUSTOM_SHADERS @@ -127,6 +129,14 @@ void vg_auto_shader_register(void); /* created from codegen */ static void _vg_load_full( void *data ) { +vg_info(" Copyright . . . -----, ,----- ,---. .---. \n" ); +vg_info(" 2021-2024 |\\ /| | / | | | | /| \n" ); +vg_info(" | \\ / | +-- / +----- +---' | / | \n" ); +vg_info(" | \\ / | | / | | \\ | / | \n" ); +vg_info(" | \\/ | | / | | \\ | / | \n" ); +vg_info(" ' ' '--' [] '----- '----- ' ' '---' " + "SOFTWARE\n" ); + vg_preload(); vg_tex2d_replace_with_error_async( &vg.tex_missing ); vg_async_stall(); diff --git a/vg_engine.h b/vg_engine.h index 936a464..54c595b 100644 --- a/vg_engine.h +++ b/vg_engine.h @@ -123,7 +123,14 @@ struct vg_engine /* Engine sync */ SDL_Window *window; SDL_GLContext gl_context; - SDL_sem *sem_loader; /* allows only one loader at a time */ + SDL_sem *sem_loader; /* allows only one loader at a time */ + + bool client_has_control; /* [T0] If 0: VG will display a loader screen + If 1: The game is responsible for + drawing everything. + This can be set back to 0 after vg_load is + complete to blinder the client + Not recommended! */ SDL_threadID thread_id_main, thread_id_loader; -- 2.25.1 From 14bf030bd48b7c40ee968d28943aea75546d3cb9 Mon Sep 17 00:00:00 2001 From: hgn Date: Fri, 14 Jun 2024 21:49:02 +0100 Subject: [PATCH 02/16] Fix some code smell --- vg_build_utils_shader.h | 1 + vg_render.h | 1 + 2 files changed, 2 insertions(+) diff --git a/vg_build_utils_shader.h b/vg_build_utils_shader.h index f83e20c..0bbb816 100644 --- a/vg_build_utils_shader.h +++ b/vg_build_utils_shader.h @@ -189,6 +189,7 @@ int vg_build_shader( char *src_vert, /* path/to/vert.vs */ if( !header ) { fprintf(stderr, "Could not open '%s'\n", path_header ); + vg_fatal_error( "IO error" ); return 0; } diff --git a/vg_render.h b/vg_render.h index 15ff12e..9e9db99 100644 --- a/vg_render.h +++ b/vg_render.h @@ -1,5 +1,6 @@ #pragma once #include "vg_engine.h" +#include "vg_framebuffer.h" struct vg_postprocess { -- 2.25.1 From ecab47672040d34a1c17f940daa37c570a14c560 Mon Sep 17 00:00:00 2001 From: hgn Date: Sun, 23 Jun 2024 14:48:33 +0100 Subject: [PATCH 03/16] ? --- vg_m.hc | 2611 ------------------------------------------------------- 1 file changed, 2611 deletions(-) delete mode 100644 vg_m.hc diff --git a/vg_m.hc b/vg_m.hc deleted file mode 100644 index bdf5343..0000000 --- a/vg_m.hc +++ /dev/null @@ -1,2611 +0,0 @@ -/* Copyright (C) 2021-2024 Harry Godden (hgn) - All Rights Reserved - * - * 0. Misc - * 1. Scalar operations - * 2. Vectors - * 2.a 2D Vectors - * 2.b 3D Vectors - * 2.c 4D Vectors - * 3. Quaternions - * 4. Matrices - * 4.a 2x2 matrices - * 4.b 3x3 matrices - * 4.c 4x3 matrices - * 4.d 4x4 matrices - * 5. Geometry - * 5.a Boxes - * 5.b Planes - * 5.c Closest points - * 5.d Raycast & Spherecasts - * 5.e Curves - * 5.f Volumes - * 5.g Inertia tensors - * 6. Statistics - * 6.a Random numbers - */ - -#pragma once - -#include "vg_stdint.h" -#include -#include - -#define VG_PIf 3.14159265358979323846264338327950288f -#define VG_TAUf 6.28318530717958647692528676655900576f - -/* - * ----------------------------------------------------------------------------- - * Section 0. Misc Operations - * ----------------------------------------------------------------------------- - */ - -/* get the f32 as the raw bits in a u32 without converting */ -static u32 vg_ftu32( f32 a ) -{ - u32 *ptr = (u32 *)(&a); - return *ptr; -} - -/* check if f32 is infinite */ -static int vg_isinff( f32 a ) -{ - return ((vg_ftu32(a)) & 0x7FFFFFFFU) == 0x7F800000U; -} - -/* check if f32 is not a number */ -static int vg_isnanf( f32 a ) -{ - return !vg_isinff(a) && ((vg_ftu32(a)) & 0x7F800000U) == 0x7F800000U; -} - -/* check if f32 is a number and is not infinite */ -static int vg_validf( f32 a ) -{ - return ((vg_ftu32(a)) & 0x7F800000U) != 0x7F800000U; -} - -static int v3_valid( v3f a ){ - for( u32 i=0; i<3; i++ ) - if( !vg_validf(a[i]) ) return 0; - return 1; -} - -/* - * ----------------------------------------------------------------------------- - * Section 1. Scalar Operations - * ----------------------------------------------------------------------------- - */ - -static inline f32 vg_minf( f32 a, f32 b ){ return a < b? a: b; } -static inline f32 vg_maxf( f32 a, f32 b ){ return a > b? a: b; } - -static inline int vg_min( int a, int b ){ return a < b? a: b; } -static inline int vg_max( int a, int b ){ return a > b? a: b; } - -static inline f32 vg_clampf( f32 a, f32 min, f32 max ) -{ - return vg_minf( max, vg_maxf( a, min ) ); -} - -static inline f32 vg_signf( f32 a ) -{ - return a < 0.0f? -1.0f: 1.0f; -} - -static inline f32 vg_fractf( f32 a ) -{ - return a - floorf( a ); -} - -static inline f64 vg_fractf64( f64 a ){ - return a - floor( a ); -} - -static f32 vg_cfrictf( f32 velocity, f32 F ) -{ - return -vg_signf(velocity) * vg_minf( F, fabsf(velocity) ); -} - -static inline f32 vg_rad( f32 deg ) -{ - return deg * VG_PIf / 180.0f; -} - -/* angle to reach b from a */ -static f32 vg_angle_diff( f32 a, f32 b ){ - f32 d = fmod(b,VG_TAUf)-fmodf(a,VG_TAUf); - if( fabsf(d) > VG_PIf ) - d = -vg_signf(d) * (VG_TAUf - fabsf(d)); - - return d; -} - -/* - * quantize float to bit count - */ -static u32 vg_quantf( f32 a, u32 bits, f32 min, f32 max ){ - u32 mask = (0x1 << bits) - 1; - return vg_clampf((a - min) * ((f32)mask/(max-min)), 0.0f, mask ); -} - -/* - * un-quantize discreet to float - */ -static f32 vg_dequantf( u32 q, u32 bits, f32 min, f32 max ){ - u32 mask = (0x1 << bits) - 1; - return min + (f32)q * ((max-min) / (f32)mask); -} - -/* https://iquilezles.org/articles/functions/ - * - * Use k to control the stretching of the function. Its maximum, which is 1, - * happens at exactly x = 1/k. - */ -static f32 vg_exp_impulse( f32 x, f32 k ){ - f32 h = k*x; - return h*expf(1.0f-h); -} - -/* - * ----------------------------------------------------------------------------- - * Section 2.a 2D Vectors - * ----------------------------------------------------------------------------- - */ - -static inline void v2_copy( v2f a, v2f d ) -{ - d[0] = a[0]; d[1] = a[1]; -} - -static inline void v2_zero( v2f a ) -{ - a[0] = 0.f; a[1] = 0.f; -} - -static inline void v2_add( v2f a, v2f b, v2f d ) -{ - d[0] = a[0]+b[0]; d[1] = a[1]+b[1]; -} - -static inline void v2_sub( v2f a, v2f b, v2f d ) -{ - d[0] = a[0]-b[0]; d[1] = a[1]-b[1]; -} - -static inline void v2_minv( v2f a, v2f b, v2f dest ) -{ - dest[0] = vg_minf(a[0], b[0]); - dest[1] = vg_minf(a[1], b[1]); -} - -static inline void v2_maxv( v2f a, v2f b, v2f dest ) -{ - dest[0] = vg_maxf(a[0], b[0]); - dest[1] = vg_maxf(a[1], b[1]); -} - -static inline f32 v2_dot( v2f a, v2f b ) -{ - return a[0] * b[0] + a[1] * b[1]; -} - -static inline f32 v2_cross( v2f a, v2f b ) -{ - return a[0]*b[1] - a[1]*b[0]; -} - -static inline void v2_abs( v2f a, v2f d ) -{ - d[0] = fabsf( a[0] ); - d[1] = fabsf( a[1] ); -} - -static inline void v2_muls( v2f a, f32 s, v2f d ) -{ - d[0] = a[0]*s; d[1] = a[1]*s; -} - -static inline void v2_divs( v2f a, f32 s, v2f d ) -{ - d[0] = a[0]/s; d[1] = a[1]/s; -} - -static inline void v2_mul( v2f a, v2f b, v2f d ) -{ - d[0] = a[0]*b[0]; - d[1] = a[1]*b[1]; -} - -static inline void v2_div( v2f a, v2f b, v2f d ) -{ - d[0] = a[0]/b[0]; d[1] = a[1]/b[1]; -} - -static inline void v2_muladd( v2f a, v2f b, v2f s, v2f d ) -{ - d[0] = a[0]+b[0]*s[0]; - d[1] = a[1]+b[1]*s[1]; -} - -static inline void v2_muladds( v2f a, v2f b, f32 s, v2f d ) -{ - d[0] = a[0]+b[0]*s; - d[1] = a[1]+b[1]*s; -} - -static inline f32 v2_length2( v2f a ) -{ - return a[0]*a[0] + a[1]*a[1]; -} - -static inline f32 v2_length( v2f a ) -{ - return sqrtf( v2_length2( a ) ); -} - -static inline f32 v2_dist2( v2f a, v2f b ) -{ - v2f delta; - v2_sub( a, b, delta ); - return v2_length2( delta ); -} - -static inline f32 v2_dist( v2f a, v2f b ) -{ - return sqrtf( v2_dist2( a, b ) ); -} - -static inline void v2_lerp( v2f a, v2f b, f32 t, v2f d ) -{ - d[0] = a[0] + t*(b[0]-a[0]); - d[1] = a[1] + t*(b[1]-a[1]); -} - -static inline void v2_normalize( v2f a ) -{ - v2_muls( a, 1.0f / v2_length( a ), a ); -} - -static void v2_normalize_clamp( v2f a ) -{ - f32 l2 = v2_length2( a ); - if( l2 > 1.0f ) - v2_muls( a, 1.0f/sqrtf(l2), a ); -} - -static inline void v2_floor( v2f a, v2f b ) -{ - b[0] = floorf( a[0] ); - b[1] = floorf( a[1] ); -} - -static inline void v2_fill( v2f a, f32 v ) -{ - a[0] = v; - a[1] = v; -} - -static inline void v2_copysign( v2f a, v2f b ) -{ - a[0] = copysignf( a[0], b[0] ); - a[1] = copysignf( a[1], b[1] ); -} - -/* integer variants - * ---------------- */ - -static inline void v2i_copy( v2i a, v2i b ) -{ - b[0] = a[0]; b[1] = a[1]; -} - -static inline int v2i_eq( v2i a, v2i b ) -{ - return ((a[0] == b[0]) && (a[1] == b[1])); -} - -static inline void v2i_add( v2i a, v2i b, v2i d ) -{ - d[0] = a[0]+b[0]; d[1] = a[1]+b[1]; -} - -static inline void v2i_sub( v2i a, v2i b, v2i d ) -{ - d[0] = a[0]-b[0]; d[1] = a[1]-b[1]; -} - -/* - * ----------------------------------------------------------------------------- - * Section 2.b 3D Vectors - * ----------------------------------------------------------------------------- - */ - -static inline void v3_copy( v3f a, v3f b ) -{ - b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; -} - -static inline void v3_zero( v3f a ) -{ - a[0] = 0.f; a[1] = 0.f; a[2] = 0.f; -} - -static inline void v3_add( v3f a, v3f b, v3f d ) -{ - d[0] = a[0]+b[0]; d[1] = a[1]+b[1]; d[2] = a[2]+b[2]; -} - -static inline void v3i_add( v3i a, v3i b, v3i d ) -{ - d[0] = a[0]+b[0]; d[1] = a[1]+b[1]; d[2] = a[2]+b[2]; -} - -static inline void v3_sub( v3f a, v3f b, v3f d ) -{ - d[0] = a[0]-b[0]; d[1] = a[1]-b[1]; d[2] = a[2]-b[2]; -} - -static inline void v3i_sub( v3i a, v3i b, v3i d ) -{ - d[0] = a[0]-b[0]; d[1] = a[1]-b[1]; d[2] = a[2]-b[2]; -} - -static inline void v3_mul( v3f a, v3f b, v3f d ) -{ - d[0] = a[0]*b[0]; d[1] = a[1]*b[1]; d[2] = a[2]*b[2]; -} - -static inline void v3_div( v3f a, v3f b, v3f d ) -{ - d[0] = b[0]!=0.0f? a[0]/b[0]: INFINITY; - d[1] = b[1]!=0.0f? a[1]/b[1]: INFINITY; - d[2] = b[2]!=0.0f? a[2]/b[2]: INFINITY; -} - -static inline void v3_muls( v3f a, f32 s, v3f d ) -{ - d[0] = a[0]*s; d[1] = a[1]*s; d[2] = a[2]*s; -} - -static inline void v3_fill( v3f a, f32 v ) -{ - a[0] = v; - a[1] = v; - a[2] = v; -} - -static inline void v3_divs( v3f a, f32 s, v3f d ) -{ - if( s == 0.0f ) - v3_fill( d, INFINITY ); - else - { - d[0] = a[0]/s; - d[1] = a[1]/s; - d[2] = a[2]/s; - } -} - -static inline void v3_muladds( v3f a, v3f b, f32 s, v3f d ) -{ - d[0] = a[0]+b[0]*s; d[1] = a[1]+b[1]*s; d[2] = a[2]+b[2]*s; -} - -static inline void v3_muladd( v2f a, v2f b, v2f s, v2f d ) -{ - d[0] = a[0]+b[0]*s[0]; - d[1] = a[1]+b[1]*s[1]; - d[2] = a[2]+b[2]*s[2]; -} - -static inline f32 v3_dot( v3f a, v3f b ) -{ - return a[0] * b[0] + a[1] * b[1] + a[2] * b[2]; -} - -static inline void v3_cross( v3f a, v3f b, v3f dest ) -{ - v3f d; - d[0] = a[1]*b[2] - a[2]*b[1]; - d[1] = a[2]*b[0] - a[0]*b[2]; - d[2] = a[0]*b[1] - a[1]*b[0]; - v3_copy( d, dest ); -} - -static inline f32 v3_length2( v3f a ) -{ - return v3_dot( a, a ); -} - -static inline f32 v3_length( v3f a ) -{ - return sqrtf( v3_length2( a ) ); -} - -static inline f32 v3_dist2( v3f a, v3f b ) -{ - v3f delta; - v3_sub( a, b, delta ); - return v3_length2( delta ); -} - -static inline f32 v3_dist( v3f a, v3f b ) -{ - return sqrtf( v3_dist2( a, b ) ); -} - -static inline void v3_normalize( v3f a ) -{ - v3_muls( a, 1.f / v3_length( a ), a ); -} - -static inline f32 vg_lerpf( f32 a, f32 b, f32 t ){ - return a + t*(b-a); -} - -static inline f64 vg_lerp( f64 a, f64 b, f64 t ) -{ - return a + t*(b-a); -} - -static inline void vg_slewf( f32 *a, f32 b, f32 speed ){ - f32 d = vg_signf( b-*a ), - c = *a + d*speed; - *a = vg_minf( b*d, c*d ) * d; -} - -static inline f32 vg_smoothstepf( f32 x ){ - return x*x*(3.0f - 2.0f*x); -} - - -/* correctly lerp around circular period -pi -> pi */ -static f32 vg_alerpf( f32 a, f32 b, f32 t ) -{ - f32 d = fmodf( b-a, VG_TAUf ), - s = fmodf( 2.0f*d, VG_TAUf ) - d; - return a + s*t; -} - -static inline void v3_lerp( v3f a, v3f b, f32 t, v3f d ) -{ - d[0] = a[0] + t*(b[0]-a[0]); - d[1] = a[1] + t*(b[1]-a[1]); - d[2] = a[2] + t*(b[2]-a[2]); -} - -static inline void v3_minv( v3f a, v3f b, v3f dest ) -{ - dest[0] = vg_minf(a[0], b[0]); - dest[1] = vg_minf(a[1], b[1]); - dest[2] = vg_minf(a[2], b[2]); -} - -static inline void v3_maxv( v3f a, v3f b, v3f dest ) -{ - dest[0] = vg_maxf(a[0], b[0]); - dest[1] = vg_maxf(a[1], b[1]); - dest[2] = vg_maxf(a[2], b[2]); -} - -static inline f32 v3_minf( v3f a ) -{ - return vg_minf( vg_minf( a[0], a[1] ), a[2] ); -} - -static inline f32 v3_maxf( v3f a ) -{ - return vg_maxf( vg_maxf( a[0], a[1] ), a[2] ); -} - -static inline void v3_floor( v3f a, v3f b ) -{ - b[0] = floorf( a[0] ); - b[1] = floorf( a[1] ); - b[2] = floorf( a[2] ); -} - -static inline void v3_ceil( v3f a, v3f b ) -{ - b[0] = ceilf( a[0] ); - b[1] = ceilf( a[1] ); - b[2] = ceilf( a[2] ); -} - -static inline void v3_negate( v3f a, v3f b ) -{ - b[0] = -a[0]; - b[1] = -a[1]; - b[2] = -a[2]; -} - -static inline void v3_rotate( v3f v, f32 angle, v3f axis, v3f d ) -{ - v3f v1, v2, k; - f32 c, s; - - c = cosf( angle ); - s = sinf( angle ); - - v3_copy( axis, k ); - v3_normalize( k ); - v3_muls( v, c, v1 ); - v3_cross( k, v, v2 ); - v3_muls( v2, s, v2 ); - v3_add( v1, v2, v1 ); - v3_muls( k, v3_dot(k, v) * (1.0f - c), v2); - v3_add( v1, v2, d ); -} - -static void v3_tangent_basis( v3f n, v3f tx, v3f ty ){ - /* Compute tangent basis (box2d) */ - if( fabsf( n[0] ) >= 0.57735027f ){ - tx[0] = n[1]; - tx[1] = -n[0]; - tx[2] = 0.0f; - } - else{ - tx[0] = 0.0f; - tx[1] = n[2]; - tx[2] = -n[1]; - } - - v3_normalize( tx ); - v3_cross( n, tx, ty ); -} - -/* - * Compute yaw and pitch based of a normalized vector representing forward - * forward: -z - * result -> (YAW,PITCH,0.0) - */ -static void v3_angles( v3f v, v3f out_angles ){ - float yaw = atan2f( v[0], -v[2] ), - pitch = atan2f( - -v[1], - sqrtf( - v[0]*v[0] + v[2]*v[2] - ) - ); - - out_angles[0] = yaw; - out_angles[1] = pitch; - out_angles[2] = 0.0f; -} - -/* - * Compute the forward vector from (YAW,PITCH,ROLL) - * forward: -z - */ -static void v3_angles_vector( v3f angles, v3f out_v ){ - out_v[0] = sinf( angles[0] ) * cosf( angles[1] ); - out_v[1] = -sinf( angles[1] ); - out_v[2] = -cosf( angles[0] ) * cosf( angles[1] ); -} - -/* - * ----------------------------------------------------------------------------- - * Section 2.c 4D Vectors - * ----------------------------------------------------------------------------- - */ - -static inline void v4_copy( v4f a, v4f b ) -{ - b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; b[3] = a[3]; -} - -static inline void v4_add( v4f a, v4f b, v4f d ) -{ - d[0] = a[0]+b[0]; - d[1] = a[1]+b[1]; - d[2] = a[2]+b[2]; - d[3] = a[3]+b[3]; -} - -static inline void v4_zero( v4f a ) -{ - a[0] = 0.f; a[1] = 0.f; a[2] = 0.f; a[3] = 0.f; -} - -static inline void v4_muls( v4f a, f32 s, v4f d ) -{ - d[0] = a[0]*s; - d[1] = a[1]*s; - d[2] = a[2]*s; - d[3] = a[3]*s; -} - -static inline void v4_muladds( v4f a, v4f b, f32 s, v4f d ) -{ - d[0] = a[0]+b[0]*s; - d[1] = a[1]+b[1]*s; - d[2] = a[2]+b[2]*s; - d[3] = a[3]+b[3]*s; -} - -static inline void v4_lerp( v4f a, v4f b, f32 t, v4f d ) -{ - d[0] = a[0] + t*(b[0]-a[0]); - d[1] = a[1] + t*(b[1]-a[1]); - d[2] = a[2] + t*(b[2]-a[2]); - d[3] = a[3] + t*(b[3]-a[3]); -} - -static inline f32 v4_dot( v4f a, v4f b ) -{ - return a[0]*b[0] + a[1]*b[1] + a[2]*b[2] + a[3]*b[3]; -} - -static inline f32 v4_length( v4f a ) -{ - return sqrtf( v4_dot(a,a) ); -} - -/* - * ----------------------------------------------------------------------------- - * Section 3 Quaternions - * ----------------------------------------------------------------------------- - */ - -static inline void q_identity( v4f q ) -{ - q[0] = 0.0f; q[1] = 0.0f; q[2] = 0.0f; q[3] = 1.0f; -} - -static inline void q_axis_angle( v4f q, v3f axis, f32 angle ) -{ - f32 a = angle*0.5f, - c = cosf(a), - s = sinf(a); - - q[0] = s*axis[0]; - q[1] = s*axis[1]; - q[2] = s*axis[2]; - q[3] = c; -} - -static inline void q_mul( v4f q, v4f q1, v4f d ) -{ - v4f t; - t[0] = q[3]*q1[0] + q[0]*q1[3] + q[1]*q1[2] - q[2]*q1[1]; - t[1] = q[3]*q1[1] - q[0]*q1[2] + q[1]*q1[3] + q[2]*q1[0]; - t[2] = q[3]*q1[2] + q[0]*q1[1] - q[1]*q1[0] + q[2]*q1[3]; - t[3] = q[3]*q1[3] - q[0]*q1[0] - q[1]*q1[1] - q[2]*q1[2]; - v4_copy( t, d ); -} - -static inline void q_normalize( v4f q ) -{ - f32 l2 = v4_dot(q,q); - if( l2 < 0.00001f ) q_identity( q ); - else { - f32 s = 1.0f/sqrtf(l2); - q[0] *= s; - q[1] *= s; - q[2] *= s; - q[3] *= s; - } -} - -static inline void q_inv( v4f q, v4f d ) -{ - f32 s = 1.0f / v4_dot(q,q); - d[0] = -q[0]*s; - d[1] = -q[1]*s; - d[2] = -q[2]*s; - d[3] = q[3]*s; -} - -static inline void q_nlerp( v4f a, v4f b, f32 t, v4f d ){ - if( v4_dot(a,b) < 0.0f ){ - v4f c; - v4_muls( b, -1.0f, c ); - v4_lerp( a, c, t, d ); - } - else - v4_lerp( a, b, t, d ); - - q_normalize( d ); -} - -static inline void q_m3x3( v4f q, m3x3f d ) -{ - f32 - l = v4_length(q), - s = l > 0.0f? 2.0f/l: 0.0f, - - xx = s*q[0]*q[0], xy = s*q[0]*q[1], wx = s*q[3]*q[0], - yy = s*q[1]*q[1], yz = s*q[1]*q[2], wy = s*q[3]*q[1], - zz = s*q[2]*q[2], xz = s*q[0]*q[2], wz = s*q[3]*q[2]; - - d[0][0] = 1.0f - yy - zz; - d[1][1] = 1.0f - xx - zz; - d[2][2] = 1.0f - xx - yy; - d[0][1] = xy + wz; - d[1][2] = yz + wx; - d[2][0] = xz + wy; - d[1][0] = xy - wz; - d[2][1] = yz - wx; - d[0][2] = xz - wy; -} - -static void q_mulv( v4f q, v3f v, v3f d ) -{ - v3f v1, v2; - - v3_muls( q, 2.0f*v3_dot(q,v), v1 ); - v3_muls( v, q[3]*q[3] - v3_dot(q,q), v2 ); - v3_add( v1, v2, v1 ); - v3_cross( q, v, v2 ); - v3_muls( v2, 2.0f*q[3], v2 ); - v3_add( v1, v2, d ); -} - -static f32 q_dist( v4f q0, v4f q1 ){ - return acosf( 2.0f * v4_dot(q0,q1) -1.0f ); -} - -/* - * ----------------------------------------------------------------------------- - * Section 4.a 2x2 matrices - * ----------------------------------------------------------------------------- - */ - -#define M2X2_INDENTIY {{1.0f, 0.0f, }, \ - {0.0f, 1.0f, }} - -#define M2X2_ZERO {{0.0f, 0.0f, }, \ - {0.0f, 0.0f, }} - -static inline void m2x2_copy( m2x2f a, m2x2f b ) -{ - v2_copy( a[0], b[0] ); - v2_copy( a[1], b[1] ); -} - -static inline void m2x2_identity( m2x2f a ) -{ - m2x2f id = M2X2_INDENTIY; - m2x2_copy( id, a ); -} - -static inline void m2x2_create_rotation( m2x2f a, f32 theta ) -{ - f32 s, c; - - s = sinf( theta ); - c = cosf( theta ); - - a[0][0] = c; - a[0][1] = -s; - a[1][0] = s; - a[1][1] = c; -} - -static inline void m2x2_mulv( m2x2f m, v2f v, v2f d ) -{ - v2f res; - - res[0] = m[0][0]*v[0] + m[1][0]*v[1]; - res[1] = m[0][1]*v[0] + m[1][1]*v[1]; - - v2_copy( res, d ); -} - -/* - * ----------------------------------------------------------------------------- - * Section 4.b 3x3 matrices - * ----------------------------------------------------------------------------- - */ - -#define M3X3_IDENTITY {{1.0f, 0.0f, 0.0f, },\ - { 0.0f, 1.0f, 0.0f, },\ - { 0.0f, 0.0f, 1.0f, }} - -#define M3X3_ZERO {{0.0f, 0.0f, 0.0f, },\ - { 0.0f, 0.0f, 0.0f, },\ - { 0.0f, 0.0f, 0.0f, }} - - -static void euler_m3x3( v3f angles, m3x3f d ) -{ - f32 cosY = cosf( angles[0] ), - sinY = sinf( angles[0] ), - cosP = cosf( angles[1] ), - sinP = sinf( angles[1] ), - cosR = cosf( angles[2] ), - sinR = sinf( angles[2] ); - - d[2][0] = -sinY * cosP; - d[2][1] = sinP; - d[2][2] = cosY * cosP; - - d[0][0] = cosY * cosR; - d[0][1] = sinR; - d[0][2] = sinY * cosR; - - v3_cross( d[0], d[2], d[1] ); -} - -static void m3x3_q( m3x3f m, v4f q ) -{ - f32 diag, r, rinv; - - diag = m[0][0] + m[1][1] + m[2][2]; - if( diag >= 0.0f ) - { - r = sqrtf( 1.0f + diag ); - rinv = 0.5f / r; - q[0] = rinv * (m[1][2] - m[2][1]); - q[1] = rinv * (m[2][0] - m[0][2]); - q[2] = rinv * (m[0][1] - m[1][0]); - q[3] = r * 0.5f; - } - else if( m[0][0] >= m[1][1] && m[0][0] >= m[2][2] ) - { - r = sqrtf( 1.0f - m[1][1] - m[2][2] + m[0][0] ); - rinv = 0.5f / r; - q[0] = r * 0.5f; - q[1] = rinv * (m[0][1] + m[1][0]); - q[2] = rinv * (m[0][2] + m[2][0]); - q[3] = rinv * (m[1][2] - m[2][1]); - } - else if( m[1][1] >= m[2][2] ) - { - r = sqrtf( 1.0f - m[0][0] - m[2][2] + m[1][1] ); - rinv = 0.5f / r; - q[0] = rinv * (m[0][1] + m[1][0]); - q[1] = r * 0.5f; - q[2] = rinv * (m[1][2] + m[2][1]); - q[3] = rinv * (m[2][0] - m[0][2]); - } - else - { - r = sqrtf( 1.0f - m[0][0] - m[1][1] + m[2][2] ); - rinv = 0.5f / r; - q[0] = rinv * (m[0][2] + m[2][0]); - q[1] = rinv * (m[1][2] + m[2][1]); - q[2] = r * 0.5f; - q[3] = rinv * (m[0][1] - m[1][0]); - } -} - -/* a X b == [b]T a == ...*/ -static void m3x3_skew_symetric( m3x3f a, v3f v ) -{ - a[0][0] = 0.0f; - a[0][1] = v[2]; - a[0][2] = -v[1]; - a[1][0] = -v[2]; - a[1][1] = 0.0f; - a[1][2] = v[0]; - a[2][0] = v[1]; - a[2][1] = -v[0]; - a[2][2] = 0.0f; -} - -/* aka kronecker product */ -static void m3x3_outer_product( m3x3f out_m, v3f a, v3f b ) -{ - out_m[0][0] = a[0]*b[0]; - out_m[0][1] = a[0]*b[1]; - out_m[0][2] = a[0]*b[2]; - out_m[1][0] = a[1]*b[0]; - out_m[1][1] = a[1]*b[1]; - out_m[1][2] = a[1]*b[2]; - out_m[2][0] = a[2]*b[0]; - out_m[2][1] = a[2]*b[1]; - out_m[2][2] = a[2]*b[2]; -} - -static void m3x3_add( m3x3f a, m3x3f b, m3x3f d ) -{ - v3_add( a[0], b[0], d[0] ); - v3_add( a[1], b[1], d[1] ); - v3_add( a[2], b[2], d[2] ); -} - -static void m3x3_sub( m3x3f a, m3x3f b, m3x3f d ) -{ - v3_sub( a[0], b[0], d[0] ); - v3_sub( a[1], b[1], d[1] ); - v3_sub( a[2], b[2], d[2] ); -} - -static inline void m3x3_copy( m3x3f a, m3x3f b ) -{ - v3_copy( a[0], b[0] ); - v3_copy( a[1], b[1] ); - v3_copy( a[2], b[2] ); -} - -static inline void m3x3_identity( m3x3f a ) -{ - m3x3f id = M3X3_IDENTITY; - m3x3_copy( id, a ); -} - -static void m3x3_diagonal( m3x3f out_a, f32 v ) -{ - m3x3_identity( out_a ); - out_a[0][0] = v; - out_a[1][1] = v; - out_a[2][2] = v; -} - -static void m3x3_setdiagonalv3( m3x3f a, v3f v ) -{ - a[0][0] = v[0]; - a[1][1] = v[1]; - a[2][2] = v[2]; -} - -static inline void m3x3_zero( m3x3f a ) -{ - m3x3f z = M3X3_ZERO; - m3x3_copy( z, a ); -} - -static inline void m3x3_inv( m3x3f src, m3x3f dest ) -{ - f32 a = src[0][0], b = src[0][1], c = src[0][2], - d = src[1][0], e = src[1][1], f = src[1][2], - g = src[2][0], h = src[2][1], i = src[2][2]; - - f32 det = 1.f / - (+a*(e*i-h*f) - -b*(d*i-f*g) - +c*(d*h-e*g)); - - dest[0][0] = (e*i-h*f)*det; - dest[0][1] = -(b*i-c*h)*det; - dest[0][2] = (b*f-c*e)*det; - dest[1][0] = -(d*i-f*g)*det; - dest[1][1] = (a*i-c*g)*det; - dest[1][2] = -(a*f-d*c)*det; - dest[2][0] = (d*h-g*e)*det; - dest[2][1] = -(a*h-g*b)*det; - dest[2][2] = (a*e-d*b)*det; -} - -static f32 m3x3_det( m3x3f m ) -{ - return m[0][0] * (m[1][1] * m[2][2] - m[2][1] * m[1][2]) - - m[0][1] * (m[1][0] * m[2][2] - m[1][2] * m[2][0]) - + m[0][2] * (m[1][0] * m[2][1] - m[1][1] * m[2][0]); -} - -static inline void m3x3_transpose( m3x3f src, m3x3f dest ) -{ - f32 a = src[0][0], b = src[0][1], c = src[0][2], - d = src[1][0], e = src[1][1], f = src[1][2], - g = src[2][0], h = src[2][1], i = src[2][2]; - - dest[0][0] = a; - dest[0][1] = d; - dest[0][2] = g; - dest[1][0] = b; - dest[1][1] = e; - dest[1][2] = h; - dest[2][0] = c; - dest[2][1] = f; - dest[2][2] = i; -} - -static inline void m3x3_mul( m3x3f a, m3x3f b, m3x3f d ) -{ - f32 a00 = a[0][0], a01 = a[0][1], a02 = a[0][2], - a10 = a[1][0], a11 = a[1][1], a12 = a[1][2], - a20 = a[2][0], a21 = a[2][1], a22 = a[2][2], - - b00 = b[0][0], b01 = b[0][1], b02 = b[0][2], - b10 = b[1][0], b11 = b[1][1], b12 = b[1][2], - b20 = b[2][0], b21 = b[2][1], b22 = b[2][2]; - - d[0][0] = a00*b00 + a10*b01 + a20*b02; - d[0][1] = a01*b00 + a11*b01 + a21*b02; - d[0][2] = a02*b00 + a12*b01 + a22*b02; - d[1][0] = a00*b10 + a10*b11 + a20*b12; - d[1][1] = a01*b10 + a11*b11 + a21*b12; - d[1][2] = a02*b10 + a12*b11 + a22*b12; - d[2][0] = a00*b20 + a10*b21 + a20*b22; - d[2][1] = a01*b20 + a11*b21 + a21*b22; - d[2][2] = a02*b20 + a12*b21 + a22*b22; -} - -static inline void m3x3_mulv( m3x3f m, v3f v, v3f d ) -{ - v3f res; - - res[0] = m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2]; - res[1] = m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2]; - res[2] = m[0][2]*v[0] + m[1][2]*v[1] + m[2][2]*v[2]; - - v3_copy( res, d ); -} - -static inline void m3x3_projection( m3x3f dst, - f32 const left, f32 const right, f32 const bottom, f32 const top ) -{ - f32 rl, tb; - - m3x3_zero( dst ); - - rl = 1.0f / (right - left); - tb = 1.0f / (top - bottom); - - dst[0][0] = 2.0f * rl; - dst[1][1] = 2.0f * tb; - dst[2][2] = 1.0f; -} - -static inline void m3x3_translate( m3x3f m, v3f v ) -{ - m[2][0] = m[0][0] * v[0] + m[1][0] * v[1] + m[2][0]; - m[2][1] = m[0][1] * v[0] + m[1][1] * v[1] + m[2][1]; - m[2][2] = m[0][2] * v[0] + m[1][2] * v[1] + m[2][2]; -} - -static inline void m3x3_scale( m3x3f m, v3f v ) -{ - v3_muls( m[0], v[0], m[0] ); - v3_muls( m[1], v[1], m[1] ); - v3_muls( m[2], v[2], m[2] ); -} - -static inline void m3x3_scalef( m3x3f m, f32 f ) -{ - v3f v; - v3_fill( v, f ); - m3x3_scale( m, v ); -} - -static inline void m3x3_rotate( m3x3f m, f32 angle ) -{ - f32 m00 = m[0][0], m10 = m[1][0], - m01 = m[0][1], m11 = m[1][1], - m02 = m[0][2], m12 = m[1][2]; - f32 c, s; - - s = sinf( angle ); - c = cosf( angle ); - - m[0][0] = m00 * c + m10 * s; - m[0][1] = m01 * c + m11 * s; - m[0][2] = m02 * c + m12 * s; - - m[1][0] = m00 * -s + m10 * c; - m[1][1] = m01 * -s + m11 * c; - m[1][2] = m02 * -s + m12 * c; -} - -/* - * ----------------------------------------------------------------------------- - * Section 4.c 4x3 matrices - * ----------------------------------------------------------------------------- - */ - -#define M4X3_IDENTITY {{1.0f, 0.0f, 0.0f, },\ - { 0.0f, 1.0f, 0.0f, },\ - { 0.0f, 0.0f, 1.0f, },\ - { 0.0f, 0.0f, 0.0f }} - -static inline void m4x3_to_3x3( m4x3f a, m3x3f b ) -{ - v3_copy( a[0], b[0] ); - v3_copy( a[1], b[1] ); - v3_copy( a[2], b[2] ); -} - -static inline void m4x3_invert_affine( m4x3f a, m4x3f b ) -{ - m3x3_transpose( a, b ); - m3x3_mulv( b, a[3], b[3] ); - v3_negate( b[3], b[3] ); -} - -static void m4x3_invert_full( m4x3f src, m4x3f dst ) -{ - f32 t2, t4, t5, - det, - a = src[0][0], b = src[0][1], c = src[0][2], - e = src[1][0], f = src[1][1], g = src[1][2], - i = src[2][0], j = src[2][1], k = src[2][2], - m = src[3][0], n = src[3][1], o = src[3][2]; - - t2 = j*o - n*k; - t4 = i*o - m*k; - t5 = i*n - m*j; - - dst[0][0] = f*k - g*j; - dst[1][0] =-(e*k - g*i); - dst[2][0] = e*j - f*i; - dst[3][0] =-(e*t2 - f*t4 + g*t5); - - dst[0][1] =-(b*k - c*j); - dst[1][1] = a*k - c*i; - dst[2][1] =-(a*j - b*i); - dst[3][1] = a*t2 - b*t4 + c*t5; - - t2 = f*o - n*g; - t4 = e*o - m*g; - t5 = e*n - m*f; - - dst[0][2] = b*g - c*f ; - dst[1][2] =-(a*g - c*e ); - dst[2][2] = a*f - b*e ; - dst[3][2] =-(a*t2 - b*t4 + c * t5); - - det = 1.0f / (a * dst[0][0] + b * dst[1][0] + c * dst[2][0]); - v3_muls( dst[0], det, dst[0] ); - v3_muls( dst[1], det, dst[1] ); - v3_muls( dst[2], det, dst[2] ); - v3_muls( dst[3], det, dst[3] ); -} - -static inline void m4x3_copy( m4x3f a, m4x3f b ) -{ - v3_copy( a[0], b[0] ); - v3_copy( a[1], b[1] ); - v3_copy( a[2], b[2] ); - v3_copy( a[3], b[3] ); -} - -static inline void m4x3_identity( m4x3f a ) -{ - m4x3f id = M4X3_IDENTITY; - m4x3_copy( id, a ); -} - -static void m4x3_mul( m4x3f a, m4x3f b, m4x3f d ) -{ - f32 - a00 = a[0][0], a01 = a[0][1], a02 = a[0][2], - a10 = a[1][0], a11 = a[1][1], a12 = a[1][2], - a20 = a[2][0], a21 = a[2][1], a22 = a[2][2], - a30 = a[3][0], a31 = a[3][1], a32 = a[3][2], - b00 = b[0][0], b01 = b[0][1], b02 = b[0][2], - b10 = b[1][0], b11 = b[1][1], b12 = b[1][2], - b20 = b[2][0], b21 = b[2][1], b22 = b[2][2], - b30 = b[3][0], b31 = b[3][1], b32 = b[3][2]; - - d[0][0] = a00*b00 + a10*b01 + a20*b02; - d[0][1] = a01*b00 + a11*b01 + a21*b02; - d[0][2] = a02*b00 + a12*b01 + a22*b02; - d[1][0] = a00*b10 + a10*b11 + a20*b12; - d[1][1] = a01*b10 + a11*b11 + a21*b12; - d[1][2] = a02*b10 + a12*b11 + a22*b12; - d[2][0] = a00*b20 + a10*b21 + a20*b22; - d[2][1] = a01*b20 + a11*b21 + a21*b22; - d[2][2] = a02*b20 + a12*b21 + a22*b22; - d[3][0] = a00*b30 + a10*b31 + a20*b32 + a30; - d[3][1] = a01*b30 + a11*b31 + a21*b32 + a31; - d[3][2] = a02*b30 + a12*b31 + a22*b32 + a32; -} - -#if 0 /* shat appf mingw wstringop-overflow */ -inline -#endif -static void m4x3_mulv( m4x3f m, v3f v, v3f d ) -{ - v3f res; - - res[0] = m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2] + m[3][0]; - res[1] = m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2] + m[3][1]; - res[2] = m[0][2]*v[0] + m[1][2]*v[1] + m[2][2]*v[2] + m[3][2]; - - v3_copy( res, d ); -} - -/* - * Transform plane ( xyz, distance ) - */ -static void m4x3_mulp( m4x3f m, v4f p, v4f d ) -{ - v3f o; - - v3_muls( p, p[3], o ); - m4x3_mulv( m, o, o ); - m3x3_mulv( m, p, d ); - - d[3] = v3_dot( o, d ); -} - -/* - * Affine transforms - */ - -static void m4x3_translate( m4x3f m, v3f v ) -{ - v3_muladds( m[3], m[0], v[0], m[3] ); - v3_muladds( m[3], m[1], v[1], m[3] ); - v3_muladds( m[3], m[2], v[2], m[3] ); -} - -static void m4x3_rotate_x( m4x3f m, f32 angle ) -{ - m4x3f t = M4X3_IDENTITY; - f32 c, s; - - c = cosf( angle ); - s = sinf( angle ); - - t[1][1] = c; - t[1][2] = s; - t[2][1] = -s; - t[2][2] = c; - - m4x3_mul( m, t, m ); -} - -static void m4x3_rotate_y( m4x3f m, f32 angle ) -{ - m4x3f t = M4X3_IDENTITY; - f32 c, s; - - c = cosf( angle ); - s = sinf( angle ); - - t[0][0] = c; - t[0][2] = -s; - t[2][0] = s; - t[2][2] = c; - - m4x3_mul( m, t, m ); -} - -static void m4x3_rotate_z( m4x3f m, f32 angle ) -{ - m4x3f t = M4X3_IDENTITY; - f32 c, s; - - c = cosf( angle ); - s = sinf( angle ); - - t[0][0] = c; - t[0][1] = s; - t[1][0] = -s; - t[1][1] = c; - - m4x3_mul( m, t, m ); -} - -static void m4x3_expand( m4x3f m, m4x4f d ) -{ - v3_copy( m[0], d[0] ); - v3_copy( m[1], d[1] ); - v3_copy( m[2], d[2] ); - v3_copy( m[3], d[3] ); - d[0][3] = 0.0f; - d[1][3] = 0.0f; - d[2][3] = 0.0f; - d[3][3] = 1.0f; -} - -static void m4x3_decompose( m4x3f m, v3f co, v4f q, v3f s ) -{ - v3_copy( m[3], co ); - s[0] = v3_length(m[0]); - s[1] = v3_length(m[1]); - s[2] = v3_length(m[2]); - - m3x3f rot; - v3_divs( m[0], s[0], rot[0] ); - v3_divs( m[1], s[1], rot[1] ); - v3_divs( m[2], s[2], rot[2] ); - - m3x3_q( rot, q ); -} - -static void m4x3_expand_aabb_point( m4x3f m, boxf box, v3f point ){ - v3f v; - m4x3_mulv( m, point, v ); - - v3_minv( box[0], v, box[0] ); - v3_maxv( box[1], v, box[1] ); -} - -static void m4x3_expand_aabb_aabb( m4x3f m, boxf boxa, boxf boxb ){ - v3f a; v3f b; - v3_copy( boxb[0], a ); - v3_copy( boxb[1], b ); - m4x3_expand_aabb_point( m, boxa, (v3f){ a[0], a[1], a[2] } ); - m4x3_expand_aabb_point( m, boxa, (v3f){ a[0], b[1], a[2] } ); - m4x3_expand_aabb_point( m, boxa, (v3f){ b[0], b[1], a[2] } ); - m4x3_expand_aabb_point( m, boxa, (v3f){ b[0], a[1], a[2] } ); - m4x3_expand_aabb_point( m, boxa, (v3f){ a[0], a[1], b[2] } ); - m4x3_expand_aabb_point( m, boxa, (v3f){ a[0], b[1], b[2] } ); - m4x3_expand_aabb_point( m, boxa, (v3f){ b[0], b[1], b[2] } ); - m4x3_expand_aabb_point( m, boxa, (v3f){ b[0], a[1], b[2] } ); -} -static inline void m4x3_lookat( m4x3f m, v3f pos, v3f target, v3f up ) -{ - v3f dir; - v3_sub( target, pos, dir ); - v3_normalize( dir ); - - v3_copy( dir, m[2] ); - - v3_cross( up, m[2], m[0] ); - v3_normalize( m[0] ); - - v3_cross( m[2], m[0], m[1] ); - v3_copy( pos, m[3] ); -} - -/* - * ----------------------------------------------------------------------------- - * Section 4.d 4x4 matrices - * ----------------------------------------------------------------------------- - */ - -#define M4X4_IDENTITY {{1.0f, 0.0f, 0.0f, 0.0f },\ - { 0.0f, 1.0f, 0.0f, 0.0f },\ - { 0.0f, 0.0f, 1.0f, 0.0f },\ - { 0.0f, 0.0f, 0.0f, 1.0f }} -#define M4X4_ZERO {{0.0f, 0.0f, 0.0f, 0.0f },\ - { 0.0f, 0.0f, 0.0f, 0.0f },\ - { 0.0f, 0.0f, 0.0f, 0.0f },\ - { 0.0f, 0.0f, 0.0f, 0.0f }} - -static void m4x4_projection( m4x4f m, f32 angle, - f32 ratio, f32 fnear, f32 ffar ) -{ - f32 scale = tanf( angle * 0.5f * VG_PIf / 180.0f ) * fnear, - r = ratio * scale, - l = -r, - t = scale, - b = -t; - - m[0][0] = 2.0f * fnear / (r - l); - m[0][1] = 0.0f; - m[0][2] = 0.0f; - m[0][3] = 0.0f; - - m[1][0] = 0.0f; - m[1][1] = 2.0f * fnear / (t - b); - m[1][2] = 0.0f; - m[1][3] = 0.0f; - - m[2][0] = (r + l) / (r - l); - m[2][1] = (t + b) / (t - b); - m[2][2] = -(ffar + fnear) / (ffar - fnear); - m[2][3] = -1.0f; - - m[3][0] = 0.0f; - m[3][1] = 0.0f; - m[3][2] = -2.0f * ffar * fnear / (ffar - fnear); - m[3][3] = 0.0f; -} - -static void m4x4_translate( m4x4f m, v3f v ) -{ - v4_muladds( m[3], m[0], v[0], m[3] ); - v4_muladds( m[3], m[1], v[1], m[3] ); - v4_muladds( m[3], m[2], v[2], m[3] ); -} - -static inline void m4x4_copy( m4x4f a, m4x4f b ) -{ - v4_copy( a[0], b[0] ); - v4_copy( a[1], b[1] ); - v4_copy( a[2], b[2] ); - v4_copy( a[3], b[3] ); -} - -static inline void m4x4_identity( m4x4f a ) -{ - m4x4f id = M4X4_IDENTITY; - m4x4_copy( id, a ); -} - -static inline void m4x4_zero( m4x4f a ) -{ - m4x4f zero = M4X4_ZERO; - m4x4_copy( zero, a ); -} - -static inline void m4x4_mul( m4x4f a, m4x4f b, m4x4f d ) -{ - f32 a00 = a[0][0], a01 = a[0][1], a02 = a[0][2], a03 = a[0][3], - a10 = a[1][0], a11 = a[1][1], a12 = a[1][2], a13 = a[1][3], - a20 = a[2][0], a21 = a[2][1], a22 = a[2][2], a23 = a[2][3], - a30 = a[3][0], a31 = a[3][1], a32 = a[3][2], a33 = a[3][3], - - b00 = b[0][0], b01 = b[0][1], b02 = b[0][2], b03 = b[0][3], - b10 = b[1][0], b11 = b[1][1], b12 = b[1][2], b13 = b[1][3], - b20 = b[2][0], b21 = b[2][1], b22 = b[2][2], b23 = b[2][3], - b30 = b[3][0], b31 = b[3][1], b32 = b[3][2], b33 = b[3][3]; - - d[0][0] = a00*b00 + a10*b01 + a20*b02 + a30*b03; - d[0][1] = a01*b00 + a11*b01 + a21*b02 + a31*b03; - d[0][2] = a02*b00 + a12*b01 + a22*b02 + a32*b03; - d[0][3] = a03*b00 + a13*b01 + a23*b02 + a33*b03; - d[1][0] = a00*b10 + a10*b11 + a20*b12 + a30*b13; - d[1][1] = a01*b10 + a11*b11 + a21*b12 + a31*b13; - d[1][2] = a02*b10 + a12*b11 + a22*b12 + a32*b13; - d[1][3] = a03*b10 + a13*b11 + a23*b12 + a33*b13; - d[2][0] = a00*b20 + a10*b21 + a20*b22 + a30*b23; - d[2][1] = a01*b20 + a11*b21 + a21*b22 + a31*b23; - d[2][2] = a02*b20 + a12*b21 + a22*b22 + a32*b23; - d[2][3] = a03*b20 + a13*b21 + a23*b22 + a33*b23; - d[3][0] = a00*b30 + a10*b31 + a20*b32 + a30*b33; - d[3][1] = a01*b30 + a11*b31 + a21*b32 + a31*b33; - d[3][2] = a02*b30 + a12*b31 + a22*b32 + a32*b33; - d[3][3] = a03*b30 + a13*b31 + a23*b32 + a33*b33; -} - -static inline void m4x4_mulv( m4x4f m, v4f v, v4f d ) -{ - v4f res; - - res[0] = m[0][0]*v[0] + m[1][0]*v[1] + m[2][0]*v[2] + m[3][0]*v[3]; - res[1] = m[0][1]*v[0] + m[1][1]*v[1] + m[2][1]*v[2] + m[3][1]*v[3]; - res[2] = m[0][2]*v[0] + m[1][2]*v[1] + m[2][2]*v[2] + m[3][2]*v[3]; - res[3] = m[0][3]*v[0] + m[1][3]*v[1] + m[2][3]*v[2] + m[3][3]*v[3]; - - v4_copy( res, d ); -} - -static inline void m4x4_inv( m4x4f a, m4x4f d ) -{ - f32 a00 = a[0][0], a01 = a[0][1], a02 = a[0][2], a03 = a[0][3], - a10 = a[1][0], a11 = a[1][1], a12 = a[1][2], a13 = a[1][3], - a20 = a[2][0], a21 = a[2][1], a22 = a[2][2], a23 = a[2][3], - a30 = a[3][0], a31 = a[3][1], a32 = a[3][2], a33 = a[3][3], - det, - t[6]; - - t[0] = a22*a33 - a32*a23; - t[1] = a21*a33 - a31*a23; - t[2] = a21*a32 - a31*a22; - t[3] = a20*a33 - a30*a23; - t[4] = a20*a32 - a30*a22; - t[5] = a20*a31 - a30*a21; - - d[0][0] = a11*t[0] - a12*t[1] + a13*t[2]; - d[1][0] =-(a10*t[0] - a12*t[3] + a13*t[4]); - d[2][0] = a10*t[1] - a11*t[3] + a13*t[5]; - d[3][0] =-(a10*t[2] - a11*t[4] + a12*t[5]); - - d[0][1] =-(a01*t[0] - a02*t[1] + a03*t[2]); - d[1][1] = a00*t[0] - a02*t[3] + a03*t[4]; - d[2][1] =-(a00*t[1] - a01*t[3] + a03*t[5]); - d[3][1] = a00*t[2] - a01*t[4] + a02*t[5]; - - t[0] = a12*a33 - a32*a13; - t[1] = a11*a33 - a31*a13; - t[2] = a11*a32 - a31*a12; - t[3] = a10*a33 - a30*a13; - t[4] = a10*a32 - a30*a12; - t[5] = a10*a31 - a30*a11; - - d[0][2] = a01*t[0] - a02*t[1] + a03*t[2]; - d[1][2] =-(a00*t[0] - a02*t[3] + a03*t[4]); - d[2][2] = a00*t[1] - a01*t[3] + a03*t[5]; - d[3][2] =-(a00*t[2] - a01*t[4] + a02*t[5]); - - t[0] = a12*a23 - a22*a13; - t[1] = a11*a23 - a21*a13; - t[2] = a11*a22 - a21*a12; - t[3] = a10*a23 - a20*a13; - t[4] = a10*a22 - a20*a12; - t[5] = a10*a21 - a20*a11; - - d[0][3] =-(a01*t[0] - a02*t[1] + a03*t[2]); - d[1][3] = a00*t[0] - a02*t[3] + a03*t[4]; - d[2][3] =-(a00*t[1] - a01*t[3] + a03*t[5]); - d[3][3] = a00*t[2] - a01*t[4] + a02*t[5]; - - det = 1.0f / (a00*d[0][0] + a01*d[1][0] + a02*d[2][0] + a03*d[3][0]); - v4_muls( d[0], det, d[0] ); - v4_muls( d[1], det, d[1] ); - v4_muls( d[2], det, d[2] ); - v4_muls( d[3], det, d[3] ); -} - -/* - * http://www.terathon.com/lengyel/Lengyel-Oblique.pdf - */ -static void m4x4_clip_projection( m4x4f mat, v4f plane ){ - v4f c = - { - (vg_signf(plane[0]) + mat[2][0]) / mat[0][0], - (vg_signf(plane[1]) + mat[2][1]) / mat[1][1], - -1.0f, - (1.0f + mat[2][2]) / mat[3][2] - }; - - v4_muls( plane, 2.0f / v4_dot(plane,c), c ); - - mat[0][2] = c[0]; - mat[1][2] = c[1]; - mat[2][2] = c[2] + 1.0f; - mat[3][2] = c[3]; -} - -/* - * Undoes the above operation - */ -static void m4x4_reset_clipping( m4x4f mat, float ffar, float fnear ){ - mat[0][2] = 0.0f; - mat[1][2] = 0.0f; - mat[2][2] = -(ffar + fnear) / (ffar - fnear); - mat[3][2] = -2.0f * ffar * fnear / (ffar - fnear); -} - -/* - * ----------------------------------------------------------------------------- - * Section 5.a Boxes - * ----------------------------------------------------------------------------- - */ - -static inline void box_addpt( boxf a, v3f pt ) -{ - v3_minv( a[0], pt, a[0] ); - v3_maxv( a[1], pt, a[1] ); -} - -static inline void box_concat( boxf a, boxf b ) -{ - v3_minv( a[0], b[0], a[0] ); - v3_maxv( a[1], b[1], a[1] ); -} - -static inline void box_copy( boxf a, boxf b ) -{ - v3_copy( a[0], b[0] ); - v3_copy( a[1], b[1] ); -} - -static inline int box_overlap( boxf a, boxf b ) -{ - return - ( a[0][0] <= b[1][0] && a[1][0] >= b[0][0] ) && - ( a[0][1] <= b[1][1] && a[1][1] >= b[0][1] ) && - ( a[0][2] <= b[1][2] && a[1][2] >= b[0][2] ) - ; -} - -static int box_within( boxf greater, boxf lesser ) -{ - v3f a, b; - v3_sub( lesser[0], greater[0], a ); - v3_sub( lesser[1], greater[1], b ); - - if( (a[0] >= 0.0f) && (a[1] >= 0.0f) && (a[2] >= 0.0f) && - (b[0] <= 0.0f) && (b[1] <= 0.0f) && (b[2] <= 0.0f) ) - { - return 1; - } - - return 0; -} - -static inline void box_init_inf( boxf box ){ - v3_fill( box[0], INFINITY ); - v3_fill( box[1], -INFINITY ); -} - -/* - * ----------------------------------------------------------------------------- - * Section 5.b Planes - * ----------------------------------------------------------------------------- - */ - -static inline void tri_to_plane( f64 a[3], f64 b[3], - f64 c[3], f64 p[4] ) -{ - f64 edge0[3]; - f64 edge1[3]; - f64 l; - - edge0[0] = b[0] - a[0]; - edge0[1] = b[1] - a[1]; - edge0[2] = b[2] - a[2]; - - edge1[0] = c[0] - a[0]; - edge1[1] = c[1] - a[1]; - edge1[2] = c[2] - a[2]; - - p[0] = edge0[1] * edge1[2] - edge0[2] * edge1[1]; - p[1] = edge0[2] * edge1[0] - edge0[0] * edge1[2]; - p[2] = edge0[0] * edge1[1] - edge0[1] * edge1[0]; - - l = sqrt(p[0] * p[0] + p[1] * p[1] + p[2] * p[2]); - p[3] = (p[0] * a[0] + p[1] * a[1] + p[2] * a[2]) / l; - - p[0] = p[0] / l; - p[1] = p[1] / l; - p[2] = p[2] / l; -} - -static int plane_intersect3( v4f a, v4f b, v4f c, v3f p ) -{ - f32 const epsilon = 1e-6f; - - v3f x; - v3_cross( a, b, x ); - f32 d = v3_dot( x, c ); - - if( (d < epsilon) && (d > -epsilon) ) return 0; - - v3f v0, v1, v2; - v3_cross( b, c, v0 ); - v3_cross( c, a, v1 ); - v3_cross( a, b, v2 ); - - v3_muls( v0, a[3], p ); - v3_muladds( p, v1, b[3], p ); - v3_muladds( p, v2, c[3], p ); - v3_divs( p, d, p ); - - return 1; -} - -static int plane_intersect2( v4f a, v4f b, v3f p, v3f n ) -{ - f32 const epsilon = 1e-6f; - - v4f c; - v3_cross( a, b, c ); - f32 d = v3_length2( c ); - - if( (d < epsilon) && (d > -epsilon) ) - return 0; - - v3f v0, v1, vx; - v3_cross( c, b, v0 ); - v3_cross( a, c, v1 ); - - v3_muls( v0, a[3], vx ); - v3_muladds( vx, v1, b[3], vx ); - v3_divs( vx, d, p ); - v3_copy( c, n ); - - return 1; -} - -static int plane_segment( v4f plane, v3f a, v3f b, v3f co ) -{ - f32 d0 = v3_dot( a, plane ) - plane[3], - d1 = v3_dot( b, plane ) - plane[3]; - - if( d0*d1 < 0.0f ) - { - f32 tot = 1.0f/( fabsf(d0)+fabsf(d1) ); - - v3_muls( a, fabsf(d1) * tot, co ); - v3_muladds( co, b, fabsf(d0) * tot, co ); - return 1; - } - - return 0; -} - -static inline f64 plane_polarity( f64 p[4], f64 a[3] ) -{ - return - (a[0] * p[0] + a[1] * p[1] + a[2] * p[2]) - -(p[0]*p[3] * p[0] + p[1]*p[3] * p[1] + p[2]*p[3] * p[2]) - ; -} - -static f32 ray_plane( v4f plane, v3f co, v3f dir ){ - f32 d = v3_dot( plane, dir ); - if( fabsf(d) > 1e-6f ){ - v3f v0; - v3_muls( plane, plane[3], v0 ); - v3_sub( v0, co, v0 ); - return v3_dot( v0, plane ) / d; - } - else return INFINITY; -} - -/* - * ----------------------------------------------------------------------------- - * Section 5.c Closest point functions - * ----------------------------------------------------------------------------- - */ - -/* - * These closest point tests were learned from Real-Time Collision Detection by - * Christer Ericson - */ -static f32 closest_segment_segment( v3f p1, v3f q1, v3f p2, v3f q2, - f32 *s, f32 *t, v3f c1, v3f c2) -{ - v3f d1,d2,r; - v3_sub( q1, p1, d1 ); - v3_sub( q2, p2, d2 ); - v3_sub( p1, p2, r ); - - f32 a = v3_length2( d1 ), - e = v3_length2( d2 ), - f = v3_dot( d2, r ); - - const f32 kEpsilon = 0.0001f; - - if( a <= kEpsilon && e <= kEpsilon ) - { - *s = 0.0f; - *t = 0.0f; - v3_copy( p1, c1 ); - v3_copy( p2, c2 ); - - v3f v0; - v3_sub( c1, c2, v0 ); - - return v3_length2( v0 ); - } - - if( a<= kEpsilon ) - { - *s = 0.0f; - *t = vg_clampf( f / e, 0.0f, 1.0f ); - } - else - { - f32 c = v3_dot( d1, r ); - if( e <= kEpsilon ) - { - *t = 0.0f; - *s = vg_clampf( -c / a, 0.0f, 1.0f ); - } - else - { - f32 b = v3_dot(d1,d2), - d = a*e-b*b; - - if( d != 0.0f ) - { - *s = vg_clampf((b*f - c*e)/d, 0.0f, 1.0f); - } - else - { - *s = 0.0f; - } - - *t = (b*(*s)+f) / e; - - if( *t < 0.0f ) - { - *t = 0.0f; - *s = vg_clampf( -c / a, 0.0f, 1.0f ); - } - else if( *t > 1.0f ) - { - *t = 1.0f; - *s = vg_clampf((b-c)/a,0.0f,1.0f); - } - } - } - - v3_muladds( p1, d1, *s, c1 ); - v3_muladds( p2, d2, *t, c2 ); - - v3f v0; - v3_sub( c1, c2, v0 ); - return v3_length2( v0 ); -} - -static int point_inside_aabb( boxf box, v3f point ) -{ - if((point[0]<=box[1][0]) && (point[1]<=box[1][1]) && (point[2]<=box[1][2]) && - (point[0]>=box[0][0]) && (point[1]>=box[0][1]) && (point[2]>=box[0][2]) ) - return 1; - else - return 0; -} - -static void closest_point_aabb( v3f p, boxf box, v3f dest ) -{ - v3_maxv( p, box[0], dest ); - v3_minv( dest, box[1], dest ); -} - -static void closest_point_obb( v3f p, boxf box, - m4x3f mtx, m4x3f inv_mtx, v3f dest ) -{ - v3f local; - m4x3_mulv( inv_mtx, p, local ); - closest_point_aabb( local, box, local ); - m4x3_mulv( mtx, local, dest ); -} - -static f32 closest_point_segment( v3f a, v3f b, v3f point, v3f dest ) -{ - v3f v0, v1; - v3_sub( b, a, v0 ); - v3_sub( point, a, v1 ); - - f32 t = v3_dot( v1, v0 ) / v3_length2(v0); - t = vg_clampf(t,0.0f,1.0f); - v3_muladds( a, v0, t, dest ); - return t; -} - -static void closest_on_triangle( v3f p, v3f tri[3], v3f dest ) -{ - v3f ab, ac, ap; - f32 d1, d2; - - /* Region outside A */ - v3_sub( tri[1], tri[0], ab ); - v3_sub( tri[2], tri[0], ac ); - v3_sub( p, tri[0], ap ); - - d1 = v3_dot(ab,ap); - d2 = v3_dot(ac,ap); - if( d1 <= 0.0f && d2 <= 0.0f ) - { - v3_copy( tri[0], dest ); - v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest ); - return; - } - - /* Region outside B */ - v3f bp; - f32 d3, d4; - - v3_sub( p, tri[1], bp ); - d3 = v3_dot( ab, bp ); - d4 = v3_dot( ac, bp ); - - if( d3 >= 0.0f && d4 <= d3 ) - { - v3_copy( tri[1], dest ); - v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest ); - return; - } - - /* Edge region of AB */ - f32 vc = d1*d4 - d3*d2; - if( vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f ) - { - f32 v = d1 / (d1-d3); - v3_muladds( tri[0], ab, v, dest ); - v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest ); - return; - } - - /* Region outside C */ - v3f cp; - f32 d5, d6; - v3_sub( p, tri[2], cp ); - d5 = v3_dot(ab, cp); - d6 = v3_dot(ac, cp); - - if( d6 >= 0.0f && d5 <= d6 ) - { - v3_copy( tri[2], dest ); - v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest ); - return; - } - - /* Region of AC */ - f32 vb = d5*d2 - d1*d6; - if( vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f ) - { - f32 w = d2 / (d2-d6); - v3_muladds( tri[0], ac, w, dest ); - v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest ); - return; - } - - /* Region of BC */ - f32 va = d3*d6 - d5*d4; - if( va <= 0.0f && (d4-d3) >= 0.0f && (d5-d6) >= 0.0f ) - { - f32 w = (d4-d3) / ((d4-d3) + (d5-d6)); - v3f bc; - v3_sub( tri[2], tri[1], bc ); - v3_muladds( tri[1], bc, w, dest ); - v3_copy( (v3f){INFINITY,INFINITY,INFINITY}, dest ); - return; - } - - /* P inside region, Q via barycentric coordinates uvw */ - f32 d = 1.0f/(va+vb+vc), - v = vb*d, - w = vc*d; - - v3_muladds( tri[0], ab, v, dest ); - v3_muladds( dest, ac, w, dest ); -} - -enum contact_type -{ - k_contact_type_default, - k_contact_type_disabled, - k_contact_type_edge -}; - -static enum contact_type closest_on_triangle_1( v3f p, v3f tri[3], v3f dest ) -{ - v3f ab, ac, ap; - f32 d1, d2; - - /* Region outside A */ - v3_sub( tri[1], tri[0], ab ); - v3_sub( tri[2], tri[0], ac ); - v3_sub( p, tri[0], ap ); - - d1 = v3_dot(ab,ap); - d2 = v3_dot(ac,ap); - if( d1 <= 0.0f && d2 <= 0.0f ) - { - v3_copy( tri[0], dest ); - return k_contact_type_default; - } - - /* Region outside B */ - v3f bp; - f32 d3, d4; - - v3_sub( p, tri[1], bp ); - d3 = v3_dot( ab, bp ); - d4 = v3_dot( ac, bp ); - - if( d3 >= 0.0f && d4 <= d3 ) - { - v3_copy( tri[1], dest ); - return k_contact_type_edge; - } - - /* Edge region of AB */ - f32 vc = d1*d4 - d3*d2; - if( vc <= 0.0f && d1 >= 0.0f && d3 <= 0.0f ) - { - f32 v = d1 / (d1-d3); - v3_muladds( tri[0], ab, v, dest ); - return k_contact_type_edge; - } - - /* Region outside C */ - v3f cp; - f32 d5, d6; - v3_sub( p, tri[2], cp ); - d5 = v3_dot(ab, cp); - d6 = v3_dot(ac, cp); - - if( d6 >= 0.0f && d5 <= d6 ) - { - v3_copy( tri[2], dest ); - return k_contact_type_edge; - } - - /* Region of AC */ - f32 vb = d5*d2 - d1*d6; - if( vb <= 0.0f && d2 >= 0.0f && d6 <= 0.0f ) - { - f32 w = d2 / (d2-d6); - v3_muladds( tri[0], ac, w, dest ); - return k_contact_type_edge; - } - - /* Region of BC */ - f32 va = d3*d6 - d5*d4; - if( va <= 0.0f && (d4-d3) >= 0.0f && (d5-d6) >= 0.0f ) - { - f32 w = (d4-d3) / ((d4-d3) + (d5-d6)); - v3f bc; - v3_sub( tri[2], tri[1], bc ); - v3_muladds( tri[1], bc, w, dest ); - return k_contact_type_edge; - } - - /* P inside region, Q via barycentric coordinates uvw */ - f32 d = 1.0f/(va+vb+vc), - v = vb*d, - w = vc*d; - - v3_muladds( tri[0], ab, v, dest ); - v3_muladds( dest, ac, w, dest ); - - return k_contact_type_default; -} - -static void closest_point_elipse( v2f p, v2f e, v2f o ) -{ - v2f pabs, ei, e2, ve, t; - - v2_abs( p, pabs ); - v2_div( (v2f){ 1.0f, 1.0f }, e, ei ); - v2_mul( e, e, e2 ); - v2_mul( ei, (v2f){ e2[0]-e2[1], e2[1]-e2[0] }, ve ); - - v2_fill( t, 0.70710678118654752f ); - - for( int i=0; i<3; i++ ){ - v2f v, u, ud, w; - - v2_mul( ve, t, v ); /* ve*t*t*t */ - v2_mul( v, t, v ); - v2_mul( v, t, v ); - - v2_sub( pabs, v, u ); - v2_normalize( u ); - - v2_mul( t, e, ud ); - v2_sub( ud, v, ud ); - - v2_muls( u, v2_length( ud ), u ); - - v2_add( v, u, w ); - v2_mul( w, ei, w ); - - v2_maxv( (v2f){0.0f,0.0f}, w, t ); - v2_normalize( t ); - } - - v2_mul( t, e, o ); - v2_copysign( o, p ); -} - -/* - * ----------------------------------------------------------------------------- - * Section 5.d Raycasts & Spherecasts - * ----------------------------------------------------------------------------- - */ - -static int ray_aabb1( boxf box, v3f co, v3f dir_inv, f32 dist ) -{ - v3f v0, v1; - f32 tmin, tmax; - - v3_sub( box[0], co, v0 ); - v3_sub( box[1], co, v1 ); - - v3_mul( v0, dir_inv, v0 ); - v3_mul( v1, dir_inv, v1 ); - - tmin = vg_minf( v0[0], v1[0] ); - tmax = vg_maxf( v0[0], v1[0] ); - tmin = vg_maxf( tmin, vg_minf( v0[1], v1[1] )); - tmax = vg_minf( tmax, vg_maxf( v0[1], v1[1] )); - tmin = vg_maxf( tmin, vg_minf( v0[2], v1[2] )); - tmax = vg_minf( tmax, vg_maxf( v0[2], v1[2] )); - - return (tmax >= tmin) && (tmin <= dist) && (tmax >= 0.0f); -} - -/* Time of intersection with ray vs triangle */ -static int ray_tri( v3f tri[3], v3f co, - v3f dir, f32 *dist, int backfaces ) -{ - f32 const kEpsilon = 0.00001f; - - v3f v0, v1, h, s, q, n; - f32 a,f,u,v,t; - - f32 *pa = tri[0], - *pb = tri[1], - *pc = tri[2]; - - v3_sub( pb, pa, v0 ); - v3_sub( pc, pa, v1 ); - v3_cross( dir, v1, h ); - v3_cross( v0, v1, n ); - - if( (v3_dot( n, dir ) > 0.0f) && !backfaces ) /* Backface culling */ - return 0; - - /* Parralel */ - a = v3_dot( v0, h ); - - if( a > -kEpsilon && a < kEpsilon ) - return 0; - - f = 1.0f/a; - v3_sub( co, pa, s ); - - u = f * v3_dot(s, h); - if( u < 0.0f || u > 1.0f ) - return 0; - - v3_cross( s, v0, q ); - v = f * v3_dot( dir, q ); - if( v < 0.0f || u+v > 1.0f ) - return 0; - - t = f * v3_dot(v1, q); - if( t > kEpsilon ) - { - *dist = t; - return 1; - } - else return 0; -} - -/* time of intersection with ray vs sphere */ -static int ray_sphere( v3f c, f32 r, - v3f co, v3f dir, f32 *t ) -{ - v3f m; - v3_sub( co, c, m ); - - f32 b = v3_dot( m, dir ), - c1 = v3_dot( m, m ) - r*r; - - /* Exit if r’s origin outside s (c > 0) and r pointing away from s (b > 0) */ - if( c1 > 0.0f && b > 0.0f ) - return 0; - - f32 discr = b*b - c1; - - /* A negative discriminant corresponds to ray missing sphere */ - if( discr < 0.0f ) - return 0; - - /* - * Ray now found to intersect sphere, compute smallest t value of - * intersection - */ - *t = -b - sqrtf( discr ); - - /* If t is negative, ray started inside sphere so clamp t to zero */ - if( *t < 0.0f ) - *t = 0.0f; - - return 1; -} - -/* - * time of intersection of ray vs cylinder - * The cylinder does not have caps but is finite - * - * Heavily adapted from regular segment vs cylinder from: - * Real-Time Collision Detection - */ -static int ray_uncapped_finite_cylinder( v3f q, v3f p, f32 r, - v3f co, v3f dir, f32 *t ) -{ - v3f d, m, n, sb; - v3_muladds( co, dir, 1.0f, sb ); - - v3_sub( q, p, d ); - v3_sub( co, p, m ); - v3_sub( sb, co, n ); - - f32 md = v3_dot( m, d ), - nd = v3_dot( n, d ), - dd = v3_dot( d, d ), - nn = v3_dot( n, n ), - mn = v3_dot( m, n ), - a = dd*nn - nd*nd, - k = v3_dot( m, m ) - r*r, - c = dd*k - md*md; - - if( fabsf(a) < 0.00001f ) - { - /* Segment runs parallel to cylinder axis */ - return 0; - } - - f32 b = dd*mn - nd*md, - discr = b*b - a*c; - - if( discr < 0.0f ) - return 0; /* No real roots; no intersection */ - - *t = (-b - sqrtf(discr)) / a; - if( *t < 0.0f ) - return 0; /* Intersection behind ray */ - - /* Check within cylinder segment */ - if( md + (*t)*nd < 0.0f ) - return 0; - - if( md + (*t)*nd > dd ) - return 0; - - /* Segment intersects cylinder between the endcaps; t is correct */ - return 1; -} - -/* - * Time of intersection of sphere and triangle. Origin must be outside the - * colliding area. This is a fairly long procedure. - */ -static int spherecast_triangle( v3f tri[3], - v3f co, v3f dir, f32 r, f32 *t, v3f n ) -{ - v3f sum[3]; - v3f v0, v1; - - v3_sub( tri[1], tri[0], v0 ); - v3_sub( tri[2], tri[0], v1 ); - v3_cross( v0, v1, n ); - v3_normalize( n ); - v3_muladds( tri[0], n, r, sum[0] ); - v3_muladds( tri[1], n, r, sum[1] ); - v3_muladds( tri[2], n, r, sum[2] ); - - int hit = 0; - f32 t_min = INFINITY, - t1; - - if( ray_tri( sum, co, dir, &t1, 0 ) ){ - t_min = vg_minf( t_min, t1 ); - hit = 1; - } - - /* - * Currently disabled; ray_sphere requires |d| = 1. it is not very important. - */ -#if 0 - for( int i=0; i<3; i++ ){ - if( ray_sphere( tri[i], r, co, dir, &t1 ) ){ - t_min = vg_minf( t_min, t1 ); - hit = 1; - } - } -#endif - - for( int i=0; i<3; i++ ){ - int i0 = i, - i1 = (i+1)%3; - - if( ray_uncapped_finite_cylinder( tri[i0], tri[i1], r, co, dir, &t1 ) ){ - if( t1 < t_min ){ - t_min = t1; - - v3f co1, ct, cx; - v3_add( dir, co, co1 ); - v3_lerp( co, co1, t_min, ct ); - - closest_point_segment( tri[i0], tri[i1], ct, cx ); - v3_sub( ct, cx, n ); - v3_normalize( n ); - } - - hit = 1; - } - } - - *t = t_min; - return hit; -} - -/* - * ----------------------------------------------------------------------------- - * Section 5.e Curves - * ----------------------------------------------------------------------------- - */ - -static void eval_bezier_time( v3f p0, v3f p1, v3f h0, v3f h1, f32 t, v3f p ) -{ - f32 tt = t*t, - ttt = tt*t; - - v3_muls( p1, ttt, p ); - v3_muladds( p, h1, 3.0f*tt -3.0f*ttt, p ); - v3_muladds( p, h0, 3.0f*ttt -6.0f*tt +3.0f*t, p ); - v3_muladds( p, p0, 3.0f*tt -ttt -3.0f*t +1.0f, p ); -} - -static void eval_bezier3( v3f p0, v3f p1, v3f p2, f32 t, v3f p ) -{ - f32 u = 1.0f-t; - - v3_muls( p0, u*u, p ); - v3_muladds( p, p1, 2.0f*u*t, p ); - v3_muladds( p, p2, t*t, p ); -} - -/* - * ----------------------------------------------------------------------------- - * Section 5.f Volumes - * ----------------------------------------------------------------------------- - */ - -static f32 vg_sphere_volume( f32 r ){ - return (4.0f/3.0f) * VG_PIf * r*r*r; -} - -static f32 vg_box_volume( boxf box ){ - v3f e; - v3_sub( box[1], box[0], e ); - return e[0]*e[1]*e[2]; -} - -static f32 vg_cylinder_volume( f32 r, f32 h ){ - return VG_PIf * r*r * h; -} - -static f32 vg_capsule_volume( f32 r, f32 h ){ - return vg_sphere_volume( r ) + vg_cylinder_volume( r, h-r*2.0f ); -} - -static void vg_sphere_bound( f32 r, boxf out_box ){ - v3_fill( out_box[0], -r ); - v3_fill( out_box[1], r ); -} - -static void vg_capsule_bound( f32 r, f32 h, boxf out_box ){ - v3_copy( (v3f){-r,-h*0.5f,r}, out_box[0] ); - v3_copy( (v3f){-r, h*0.5f,r}, out_box[1] ); -} - - -/* - * ----------------------------------------------------------------------------- - * Section 5.g Inertia Tensors - * ----------------------------------------------------------------------------- - */ - -/* - * Translate existing inertia tensor - */ -static void vg_translate_inertia( m3x3f inout_inertia, f32 mass, v3f d ){ - /* - * I = I_0 + m*[(d.d)E_3 - d(X)d] - * - * I: updated tensor - * I_0: original tensor - * m: scalar mass - * d: translation vector - * (X): outer product - * E_3: identity matrix - */ - m3x3f t, outer, scale; - m3x3_diagonal( t, v3_dot(d,d) ); - m3x3_outer_product( outer, d, d ); - m3x3_sub( t, outer, t ); - m3x3_diagonal( scale, mass ); - m3x3_mul( scale, t, t ); - m3x3_add( inout_inertia, t, inout_inertia ); -} - -/* - * Rotate existing inertia tensor - */ -static void vg_rotate_inertia( m3x3f inout_inertia, m3x3f rotation ){ - /* - * I = R I_0 R^T - * - * I: updated tensor - * I_0: original tensor - * R: rotation matrix - * R^T: tranposed rotation matrix - */ - - m3x3f Rt; - m3x3_transpose( rotation, Rt ); - m3x3_mul( rotation, inout_inertia, inout_inertia ); - m3x3_mul( inout_inertia, Rt, inout_inertia ); -} -/* - * Create inertia tensor for box - */ -static void vg_box_inertia( boxf box, f32 mass, m3x3f out_inertia ){ - v3f e, com; - v3_sub( box[1], box[0], e ); - v3_muladds( box[0], e, 0.5f, com ); - - f32 ex2 = e[0]*e[0], - ey2 = e[1]*e[1], - ez2 = e[2]*e[2], - ix = (ey2+ez2) * mass * (1.0f/12.0f), - iy = (ex2+ez2) * mass * (1.0f/12.0f), - iz = (ex2+ey2) * mass * (1.0f/12.0f); - - m3x3_identity( out_inertia ); - m3x3_setdiagonalv3( out_inertia, (v3f){ ix, iy, iz } ); - vg_translate_inertia( out_inertia, mass, com ); -} - -/* - * Create inertia tensor for sphere - */ -static void vg_sphere_inertia( f32 r, f32 mass, m3x3f out_inertia ){ - f32 ixyz = r*r * mass * (2.0f/5.0f); - - m3x3_identity( out_inertia ); - m3x3_setdiagonalv3( out_inertia, (v3f){ ixyz, ixyz, ixyz } ); -} - -/* - * Create inertia tensor for capsule - */ -static void vg_capsule_inertia( f32 r, f32 h, f32 mass, m3x3f out_inertia ){ - f32 density = mass / vg_capsule_volume( r, h ), - ch = h-r*2.0f, /* cylinder height */ - cm = VG_PIf * ch*r*r * density, /* cylinder mass */ - hm = VG_TAUf * (1.0f/3.0f) * r*r*r * density, /* hemisphere mass */ - - iy = r*r*cm * 0.5f, - ixz = iy * 0.5f + cm*ch*ch*(1.0f/12.0f), - - aux0= (hm*2.0f*r*r)/5.0f; - - iy += aux0 * 2.0f; - - f32 aux1= ch*0.5f, - aux2= aux0 + hm*(aux1*aux1 + 3.0f*(1.0f/8.0f)*ch*r); - - ixz += aux2*2.0f; - - m3x3_identity( out_inertia ); - m3x3_setdiagonalv3( out_inertia, (v3f){ ixz, iy, ixz } ); -} - -/* - * ----------------------------------------------------------------------------- - * Section 6.a PSRNG and some distributions - * ----------------------------------------------------------------------------- - */ - -/* An implementation of the MT19937 Algorithm for the Mersenne Twister - * by Evan Sultanik. Based upon the pseudocode in: M. Matsumoto and - * T. Nishimura, "Mersenne Twister: A 623-dimensionally - * equidistributed uniform pseudorandom number generator," ACM - * Transactions on Modeling and Computer Simulation Vol. 8, No. 1, - * January pp.3-30 1998. - * - * http://www.sultanik.com/Mersenne_twister - * https://github.com/ESultanik/mtwister/blob/master/mtwister.c - */ - -#define MT_UPPER_MASK 0x80000000 -#define MT_LOWER_MASK 0x7fffffff -#define MT_TEMPERING_MASK_B 0x9d2c5680 -#define MT_TEMPERING_MASK_C 0xefc60000 - -#define MT_STATE_VECTOR_LENGTH 624 - -/* changes to STATE_VECTOR_LENGTH also require changes to this */ -#define MT_STATE_VECTOR_M 397 - -typedef struct vg_rand vg_rand; -struct vg_rand { - u32 mt[MT_STATE_VECTOR_LENGTH]; - i32 index; -}; - -static void vg_rand_seed( vg_rand *rand, unsigned long seed ) { - /* set initial seeds to mt[STATE_VECTOR_LENGTH] using the generator - * from Line 25 of Table 1 in: Donald Knuth, "The Art of Computer - * Programming," Vol. 2 (2nd Ed.) pp.102. - */ - rand->mt[0] = seed & 0xffffffff; - for( rand->index=1; rand->indexindex++){ - rand->mt[rand->index] = (6069 * rand->mt[rand->index-1]) & 0xffffffff; - } -} - -/* - * Generates a pseudo-randomly generated long. - */ -static u32 vg_randu32( vg_rand *rand ) { - u32 y; - /* mag[x] = x * 0x9908b0df for x = 0,1 */ - static u32 mag[2] = {0x0, 0x9908b0df}; - if( rand->index >= MT_STATE_VECTOR_LENGTH || rand->index < 0 ){ - /* generate STATE_VECTOR_LENGTH words at a time */ - int kk; - if( rand->index >= MT_STATE_VECTOR_LENGTH+1 || rand->index < 0 ){ - vg_rand_seed( rand, 4357 ); - } - for( kk=0; kkmt[kk] & MT_UPPER_MASK) | - (rand->mt[kk+1] & MT_LOWER_MASK); - rand->mt[kk] = rand->mt[kk+MT_STATE_VECTOR_M] ^ (y>>1) ^ mag[y & 0x1]; - } - for( ; kkmt[kk] & MT_UPPER_MASK) | - (rand->mt[kk+1] & MT_LOWER_MASK); - rand->mt[kk] = - rand->mt[ kk+(MT_STATE_VECTOR_M-MT_STATE_VECTOR_LENGTH)] ^ - (y >> 1) ^ mag[y & 0x1]; - } - y = (rand->mt[MT_STATE_VECTOR_LENGTH-1] & MT_UPPER_MASK) | - (rand->mt[0] & MT_LOWER_MASK); - rand->mt[MT_STATE_VECTOR_LENGTH-1] = - rand->mt[MT_STATE_VECTOR_M-1] ^ (y >> 1) ^ mag[y & 0x1]; - rand->index = 0; - } - y = rand->mt[rand->index++]; - y ^= (y >> 11); - y ^= (y << 7) & MT_TEMPERING_MASK_B; - y ^= (y << 15) & MT_TEMPERING_MASK_C; - y ^= (y >> 18); - return y; -} - -/* - * Generates a pseudo-randomly generated f64 in the range [0..1]. - */ -static inline f64 vg_randf64( vg_rand *rand ){ - return (f64)vg_randu32(rand)/(f64)0xffffffff; -} - -static inline f64 vg_randf64_range( vg_rand *rand, f64 min, f64 max ){ - return vg_lerp( min, max, (f64)vg_randf64(rand) ); -} - -static inline void vg_rand_dir( vg_rand *rand, v3f dir ){ - dir[0] = vg_randf64(rand); - dir[1] = vg_randf64(rand); - dir[2] = vg_randf64(rand); - - /* warning: *could* be 0 length. - * very unlikely.. 1 in (2^32)^3. but its mathematically wrong. */ - - v3_muls( dir, 2.0f, dir ); - v3_sub( dir, (v3f){1.0f,1.0f,1.0f}, dir ); - - v3_normalize( dir ); -} - -static inline void vg_rand_sphere( vg_rand *rand, v3f co ){ - vg_rand_dir(rand,co); - v3_muls( co, cbrtf( vg_randf64(rand) ), co ); -} - -static void vg_rand_disc( vg_rand *rand, v2f co ){ - f32 a = vg_randf64(rand) * VG_TAUf; - co[0] = sinf(a); - co[1] = cosf(a); - v2_muls( co, sqrtf( vg_randf64(rand) ), co ); -} - -static void vg_rand_cone( vg_rand *rand, v3f out_dir, f32 angle ){ - f32 r = sqrtf(vg_randf64(rand)) * angle * 0.5f, - a = vg_randf64(rand) * VG_TAUf; - - out_dir[0] = sinf(a) * sinf(r); - out_dir[1] = cosf(a) * sinf(r); - out_dir[2] = cosf(r); -} - -static void vg_hsv_rgb( v3f hsv, v3f rgb ){ - i32 i = floorf( hsv[0]*6.0f ); - f32 v = hsv[2], - f = hsv[0] * 6.0f - (f32)i, - p = v * (1.0f-hsv[1]), - q = v * (1.0f-f*hsv[1]), - t = v * (1.0f-(1.0f-f)*hsv[1]); - - switch( i % 6 ){ - case 0: rgb[0] = v; rgb[1] = t; rgb[2] = p; break; - case 1: rgb[0] = q; rgb[1] = v; rgb[2] = p; break; - case 2: rgb[0] = p; rgb[1] = v; rgb[2] = t; break; - case 3: rgb[0] = p; rgb[1] = q; rgb[2] = v; break; - case 4: rgb[0] = t; rgb[1] = p; rgb[2] = v; break; - case 5: rgb[0] = v; rgb[1] = p; rgb[2] = q; break; - } -} - -static void vg_rgb_hsv( v3f rgb, v3f hsv ){ - f32 min = v3_minf( rgb ), - max = v3_maxf( rgb ), - range = max-min, - k_epsilon = 0.00001f; - - hsv[2] = max; - if( range < k_epsilon ){ - hsv[0] = 0.0f; - hsv[1] = 0.0f; - return; - } - - if( max > k_epsilon ){ - hsv[1] = range/max; - } - else { - hsv[0] = 0.0f; - hsv[1] = 0.0f; - return; - } - - if( rgb[0] >= max ) - hsv[0] = (rgb[1]-rgb[2])/range; - else if( max == rgb[1] ) - hsv[0] = 2.0f+(rgb[2]-rgb[0])/range; - else - hsv[0] = 4.0f+(rgb[0]-rgb[1])/range; - - hsv[0] = vg_fractf( hsv[0] * (60.0f/360.0f) ); -} -- 2.25.1 From 0ca31e13cb9edeac6c483dba1537c69f0ceb7eee Mon Sep 17 00:00:00 2001 From: hgn Date: Wed, 26 Jun 2024 15:55:49 +0100 Subject: [PATCH 04/16] terrible buffer underflow bug in vg_string --- submodules/SDL_GameControllerDB | 2 +- submodules/anyascii | 2 +- submodules/qoi | 2 +- submodules/stb | 2 +- vg_build.h | 2 +- vg_string.c | 9 +++++---- 6 files changed, 10 insertions(+), 9 deletions(-) diff --git a/submodules/SDL_GameControllerDB b/submodules/SDL_GameControllerDB index 6ed8d05..c5b4df0 160000 --- a/submodules/SDL_GameControllerDB +++ b/submodules/SDL_GameControllerDB @@ -1 +1 @@ -Subproject commit 6ed8d054340ee8a93a684e11360b66cd8a5c168e +Subproject commit c5b4df0e1061175cb11e3ebbf8045178339864a5 diff --git a/submodules/anyascii b/submodules/anyascii index 44e971c..eb5332d 160000 --- a/submodules/anyascii +++ b/submodules/anyascii @@ -1 +1 @@ -Subproject commit 44e971c774d9ec67ca6c1f16c5a476724821ab63 +Subproject commit eb5332d0b5e48d58397e6f27475a18e058330d23 diff --git a/submodules/qoi b/submodules/qoi index b8d77df..dfc056e 160000 --- a/submodules/qoi +++ b/submodules/qoi @@ -1 +1 @@ -Subproject commit b8d77df1e80b652a57f0b7270449b179a6b91f40 +Subproject commit dfc056e813c98d307238d35f7f041a725d699dfc diff --git a/submodules/stb b/submodules/stb index 8b5f1f3..5736b15 160000 --- a/submodules/stb +++ b/submodules/stb @@ -1 +1 @@ -Subproject commit 8b5f1f37b5b75829fc72d38e7b5d4bcbf8a26d55 +Subproject commit 5736b15f7ea0ffb08dd38af21067c314d6a3aae9 diff --git a/vg_build.h b/vg_build.h index be9f098..5fce6f0 100644 --- a/vg_build.h +++ b/vg_build.h @@ -444,7 +444,7 @@ vg_make_app( struct vg_project *proj, vg_strcatf( &components, "%s ", sources ); struct vg_compiler_env denv = *env; - denv.optimization = 3; + //denv.optimization = 3; /* external dependencies */ struct compile_result depencies = diff --git a/vg_string.c b/vg_string.c index f6c7344..61df5fe 100644 --- a/vg_string.c +++ b/vg_string.c @@ -74,9 +74,9 @@ static i32 vg_str_dynamic_grow( vg_str *str ) } } -static void _vg_strcatch( vg_str *str, char c ) +static bool _vg_strcatch( vg_str *str, char c ) { - if( str->i == -1 ) return; + if( str->i == -1 ) return 0; i32 max = vg_str_storage( str ); if( str->i == max ) @@ -87,11 +87,12 @@ static void _vg_strcatch( vg_str *str, char c ) { str->i = -1; str->buffer[ max-1 ] = '\0'; - return; + return 0; } } str->buffer[ str->i ++ ] = c; + return 1; } void vg_strcat( vg_str *str, const char *append ) @@ -102,7 +103,7 @@ void vg_strcat( vg_str *str, const char *append ) append:; char c = append[ i ++ ]; - _vg_strcatch( str, c ); + if( !_vg_strcatch( str, c ) ) return; if( c == '\0' ) { -- 2.25.1 From 3601b23a521f38f3311fde52e94a3a70a150df9d Mon Sep 17 00:00:00 2001 From: hgn Date: Wed, 4 Sep 2024 20:53:51 +0100 Subject: [PATCH 05/16] memory info --- vg_engine.c | 7 +++++++ vg_m.h | 13 +++++++++++-- vg_mem.c | 27 ++++++++++++++++++++++++--- vg_mem.h | 2 +- vg_render.c | 4 +--- 5 files changed, 44 insertions(+), 9 deletions(-) diff --git a/vg_engine.c b/vg_engine.c index ed016be..ddcda8f 100644 --- a/vg_engine.c +++ b/vg_engine.c @@ -739,6 +739,12 @@ static void _vg_terminate(void) exit(0); } +static int cmd_log_memory( int argc, const char *argv[] ) +{ + vg_mem_log( vg_mem.rtmemory, 0, "rtmemory" ); + return 0; +} + static int cmd_vg_settings_toggle( int argc, const char *argv[] ); void vg_enter( int argc, char *argv[], const char *window_name ) { @@ -762,6 +768,7 @@ void vg_enter( int argc, char *argv[], const char *window_name ) vg_console_load_autos(); vg_console_reg_cmd( "vg_settings", cmd_vg_settings_toggle, NULL ); + vg_console_reg_cmd( "vg_rtmemory", cmd_log_memory, NULL ); _vg_init_window( window_name ); vg_async_init(); diff --git a/vg_m.h b/vg_m.h index 4af60c8..dae258c 100644 --- a/vg_m.h +++ b/vg_m.h @@ -1567,6 +1567,16 @@ static inline int box_overlap( boxf a, boxf b ) ; } +static int box_within_pt( boxf box, v3f pt ) +{ + if( (pt[0] >= box[0][0]) && (pt[1] >= box[0][1]) && (pt[2] >= box[0][2]) && + (pt[0] <= box[1][0]) && (pt[1] <= box[1][1]) && (pt[2] <= box[1][2]) ) + { + return 1; + } + else return 0; +} + static int box_within( boxf greater, boxf lesser ) { v3f a, b; @@ -1578,8 +1588,7 @@ static int box_within( boxf greater, boxf lesser ) { return 1; } - - return 0; + else return 0; } static inline void box_init_inf( boxf box ){ diff --git a/vg_mem.c b/vg_mem.c index 8fa1057..863b2a5 100644 --- a/vg_mem.c +++ b/vg_mem.c @@ -49,8 +49,14 @@ void *_vg_linear_alloc( void *buffer, u32 size, const char *constr_name ) } if( alloc->flags & VG_MEMORY_SYSTEM ) + { if( (alloc->allocation_count + 1) > VG_MAX_ALLOCATIONS ) + { + vg_error( "Alloc (%p) allocation count is at the limit of" + " %u allocations.\n", alloc, VG_MAX_ALLOCATIONS ); vg_fatal_error( "Max linear allocations reached" ); + } + } void *data; @@ -109,6 +115,7 @@ void *vg_linear_resize( void *buffer, void *data, u32 newsize ) vg_fatal_error( "realloc failed" ); alloc->alloc_table[ alloc->allocation_count-1 ].data = data; + alloc->alloc_table[ alloc->allocation_count-1 ].size = newsize; alloc->last_alloc = data; return data; } @@ -308,16 +315,29 @@ void vg_alloc_quota(void) "Scratch buffer" ); } +static void vg_mem_print_size( u32 bytes, char buf[32] ) +{ + if( bytes > 1024*1024 ) + snprintf( buf, 32, "%umb", bytes/(1024*1024) ); + else if( bytes > 1024 ) + snprintf( buf, 32, "%ukb", bytes/1024 ); + else + snprintf( buf, 32, "%ub", bytes ); +} + void vg_mem_log( void *lin_alloc, int depth, const char *name ) { if( vg_mem.use_libc_malloc ){ vg_linear_allocator *alloc = vg_linear_header( lin_alloc ); u32 s = alloc->size; - f32 p = ((float)alloc->cur / (float)alloc->size) * 100.0f; + f32 p = ((float)alloc->cur / (float)s) * 100.0f; for( int i=0; iflags & VG_MEMORY_SYSTEM ){ for( u32 i=0; iallocation_count; i++ ){ @@ -325,7 +345,8 @@ void vg_mem_log( void *lin_alloc, int depth, const char *name ) if( meta->type == k_allocation_type_block ){ for( int i=0; iname, meta->size ); + vg_mem_print_size( meta->size, asize ); + printf( "B(%s): %s\n", meta->name, asize ); } else{ vg_mem_log( meta->data, depth +1, meta->name ); diff --git a/vg_mem.h b/vg_mem.h index 6fde883..94042a9 100644 --- a/vg_mem.h +++ b/vg_mem.h @@ -1,6 +1,6 @@ #pragma once -#define VG_MAX_ALLOCATIONS 128 +#define VG_MAX_ALLOCATIONS 256 typedef struct vg_linear_allocator vg_linear_allocator; typedef struct vg_allocation_meta vg_allocation_meta; diff --git a/vg_render.c b/vg_render.c index 3274721..a1fc499 100644 --- a/vg_render.c +++ b/vg_render.c @@ -143,10 +143,8 @@ void vg_postprocess_to_screen( vg_framebuffer *fb ) glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glViewport( 0,0, vg.window_x, vg.window_y ); - glEnable(GL_BLEND); + glDisable(GL_BLEND); glDisable(GL_DEPTH_TEST); - glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA); - glBlendEquation(GL_FUNC_ADD); v2f inverse; vg_framebuffer_inverse_ratio( fb, inverse ); -- 2.25.1 From f45e6edd22f03528d9f0351761460ddc00b7908a Mon Sep 17 00:00:00 2001 From: hgn Date: Fri, 6 Sep 2024 03:02:08 +0100 Subject: [PATCH 06/16] adjust fatal errors --- vg_async.c | 19 +-- vg_audio.c | 89 ++++++++------ vg_audio_dsp.c | 5 +- vg_build.h | 23 +++- vg_build_utils_shader.h | 10 +- vg_bvh.c | 2 +- vg_console.c | 38 +++--- vg_engine.c | 156 ++++++++++++------------ vg_engine.h | 8 +- vg_framebuffer.c | 30 +++-- vg_input.c | 10 +- vg_io.c | 44 ++++--- vg_io.h | 2 +- vg_lines.c | 7 +- vg_loader.c | 40 ++++--- vg_loader.h | 3 +- vg_log.c | 40 ++----- vg_log.h | 3 - vg_mem.c | 84 ++++++------- vg_mem.h | 2 +- vg_mem_pool.c | 8 +- vg_msg.c | 2 +- vg_opengl.c | 38 ++++++ vg_opengl.h | 2 + vg_platform.h | 13 +- vg_profiler.c | 2 +- vg_rigidbody.c | 8 +- vg_rigidbody_collision.c | 2 +- vg_rigidbody_view.c | 2 - vg_shader.c | 242 +++++++++++++++++++++----------------- vg_shader.h | 3 +- vg_steam.c | 5 +- vg_string.c | 9 +- vg_tex.c | 6 +- vg_tool.c | 10 +- vg_tool.h | 1 - vg_ui/imgui.c | 8 +- vg_ui/imgui_impl_opengl.c | 18 +-- 38 files changed, 547 insertions(+), 447 deletions(-) create mode 100644 vg_opengl.c diff --git a/vg_async.c b/vg_async.c index 7916282..9a3da53 100644 --- a/vg_async.c +++ b/vg_async.c @@ -18,16 +18,19 @@ vg_async_item *vg_async_alloc( u32 size ) remaining = vg_linear_remaining( vg_async.buffer ), capacity = vg_linear_get_capacity( vg_async.buffer ); - if( total_allocation > capacity ){ + if( total_allocation > capacity ) + { SDL_AtomicUnlock( &vg_async.sl_index ); - vg_error( "Requested: %umb. Buffer size: %umb\n", + vg_fatal_condition(); + vg_info( "async alloc invalid size\n" ); + vg_info( "Requested: %umb. Buffer size: %umb\n", (total_allocation/1024)/1024, (capacity/1024)/1024 ); - - vg_fatal_error( "async alloc invalid size\n" ); + vg_fatal_exit(); } - if( total_allocation > remaining ){ + if( total_allocation > remaining ) + { SDL_AtomicUnlock( &vg_async.sl_index ); SDL_SemWait( vg_async.sem_wait_for_flush ); SDL_AtomicLock( &vg_async.sl_index ); @@ -65,14 +68,14 @@ vg_async_item *vg_async_alloc( u32 size ) */ void vg_async_stall(void) { - vg_assert_thread(k_thread_purpose_loader); + VG_ASSERT( vg_thread_purpose() == k_thread_purpose_loader ); SDL_SemWait( vg_async.sem_wait_for_flush ); } void vg_async_dispatch( vg_async_item *item, void (*runner)( void *payload, u32 size ) ) { - vg_assert_thread(k_thread_purpose_loader); + VG_ASSERT( vg_thread_purpose() == k_thread_purpose_loader ); if( SDL_SemValue(vg_async.sem_wait_for_flush) ) SDL_SemWait(vg_async.sem_wait_for_flush); @@ -84,7 +87,7 @@ void vg_async_dispatch( vg_async_item *item, void vg_async_call( void (*runner)( void *payload, u32 size ), void *payload, u32 size ) { - vg_assert_thread(k_thread_purpose_loader); + VG_ASSERT( vg_thread_purpose() == k_thread_purpose_loader ); vg_async_item *call = vg_async_alloc(0); call->payload = payload; call->size = size; diff --git a/vg_audio.c b/vg_audio.c index 99b4382..e7bc7e5 100644 --- a/vg_audio.c +++ b/vg_audio.c @@ -631,22 +631,22 @@ static void audio_channel_mix( audio_channel *ch, float *buffer ) if( !vg_validf( framevol_l ) || !vg_validf( framevol_r ) || - !vg_validf( frame_samplerate ) ){ - vg_fatal_error( "Invalid sampling conditions.\n" - "This crash is to protect your ears.\n" - " channel: %p (%s)\n" - " sample_rate: %f\n" - " volume: L%f R%f\n" - " listener: %.2f %.2f %.2f [%.2f %.2f %.2f]\n", - ch, ch->name, frame_samplerate, - framevol_l, framevol_r, - vg_audio.internal_listener_pos[0], - vg_audio.internal_listener_pos[1], - vg_audio.internal_listener_pos[2], - vg_audio.internal_listener_ears[0], - vg_audio.internal_listener_ears[1], - vg_audio.internal_listener_ears[2] - ); + !vg_validf( frame_samplerate ) ) + { + vg_fatal_condition(); + vg_info( "Invalid sampling conditions.\n" + "This crash is to protect your ears.\n" ); + vg_info( " channel: %p (%s)\n", ch, ch->name ); + vg_info( " sample_rate: %f\n", frame_samplerate ); + vg_info( " volume: L%f R%f\n", framevol_l, framevol_r ); + vg_info( " listener: %.2f %.2f %.2f [%.2f %.2f %.2f]\n", + vg_audio.internal_listener_pos[0], + vg_audio.internal_listener_pos[1], + vg_audio.internal_listener_pos[2], + vg_audio.internal_listener_ears[0], + vg_audio.internal_listener_ears[1], + vg_audio.internal_listener_ears[2] ); + vg_fatal_exit(); } } @@ -983,9 +983,11 @@ void audio_clip_load( audio_clip *clip, void *lin_alloc ) * NULL when we get the clip */ - if( format == k_audio_format_vorbis ){ - if( !clip->path ){ - vg_fatal_error( "No path specified, embeded vorbis unsupported" ); + if( format == k_audio_format_vorbis ) + { + if( !clip->path ) + { + vg_error( "No path specified, embeded vorbis unsupported\n" ); } audio_lock(); @@ -993,17 +995,22 @@ void audio_clip_load( audio_clip *clip, void *lin_alloc ) audio_unlock(); if( !clip->data ) - vg_fatal_error( "Audio failed to load" ); + { + vg_error( "Audio failed to load\n" ); + } float mb = (float)(clip->size) / (1024.0f*1024.0f); vg_info( "Loaded audio clip '%s' (%.1fmb)\n", clip->path, mb ); } - else if( format == k_audio_format_stereo ){ - vg_fatal_error( "Unsupported format (Stereo uncompressed)" ); + else if( format == k_audio_format_stereo ) + { + vg_error( "Unsupported format (Stereo uncompressed)\n" ); } - else if( format == k_audio_format_bird ){ - if( !clip->data ){ - vg_fatal_error( "No data, external birdsynth unsupported" ); + else if( format == k_audio_format_bird ) + { + if( !clip->data ) + { + vg_error( "No data, external birdsynth unsupported\n" ); } u32 total_size = clip->size + sizeof(struct synth_bird); @@ -1011,7 +1018,9 @@ void audio_clip_load( audio_clip *clip, void *lin_alloc ) total_size = vg_align8( total_size ); if( total_size > AUDIO_DECODE_SIZE ) - vg_fatal_error( "Bird coding too long\n" ); + { + vg_error( "Bird coding too long, and exceeds maximum decode size\n" ); + } struct synth_bird *bird = vg_linear_alloc( lin_alloc, total_size ); memcpy( &bird->settings, clip->data, clip->size ); @@ -1021,9 +1030,11 @@ void audio_clip_load( audio_clip *clip, void *lin_alloc ) vg_info( "Loaded bird synthesis pattern (%u bytes)\n", total_size ); } - else{ - if( !clip->path ){ - vg_fatal_error( "No path specified, embeded mono unsupported" ); + else + { + if( !clip->path ) + { + vg_error( "No path specified, embeded mono unsupported\n" ); } vg_linear_clear( vg_mem.scratch ); @@ -1040,10 +1051,13 @@ void audio_clip_load( audio_clip *clip, void *lin_alloc ) stb_vorbis *decoder = stb_vorbis_open_memory( filedata, fsize, &err, &alloc ); - if( !decoder ){ - vg_error( "stb_vorbis_open_memory failed on '%s' (%d)\n", + if( !decoder ) + { + vg_fatal_condition(); + vg_info( "Vorbis decode error\n" ); + vg_info( "stb_vorbis_open_memory failed on '%s' (%d)\n", clip->path, err ); - vg_fatal_error( "Vorbis decode error" ); + vg_fatal_exit(); } /* only mono is supported in uncompressed */ @@ -1059,13 +1073,9 @@ void audio_clip_load( audio_clip *clip, void *lin_alloc ) decoder, clip->data, length_samples ); if( read_samples != length_samples ) - vg_fatal_error( "Decode error" ); - -#if 0 - float mb = (float)(data_size) / (1024.0f*1024.0f); - vg_info( "Loaded audio clip '%s' (%.1fmb) %u samples\n", clip->path, mb, - length_samples ); -#endif + { + vg_error( "Decode error, read_samples did not match length_samples\n" ); + } } } @@ -1081,6 +1091,7 @@ static void audio_require_clip_loaded( audio_clip *clip ) return; audio_unlock(); + vg_fatal_error( "Must load audio clip before playing! \n" ); } diff --git a/vg_audio_dsp.c b/vg_audio_dsp.c index 3714e32..e362b3e 100644 --- a/vg_audio_dsp.c +++ b/vg_audio_dsp.c @@ -9,7 +9,10 @@ float *dsp_allocate( u32 samples ) samples = vg_align4( samples ); if( vg_dsp.allocations + samples > (1024*1024)/4 ) - vg_fatal_error( "too much dsp" ); + { + vg_fatal_error( "Ran out of memory in the DSP buffer\n" + " Request was %u samples\n", samples ); + } float *buf = &vg_dsp.buffer[ vg_dsp.allocations ]; vg_dsp.allocations += samples; diff --git a/vg_build.h b/vg_build.h index 5fce6f0..9a1d861 100644 --- a/vg_build.h +++ b/vg_build.h @@ -224,14 +224,26 @@ vg_compiler_run( struct vg_project *project, { /* check for problems in configuration */ if( env->libc != k_libc_version_native ) + { if( env->compiler != k_compiler_zigcc ) - vg_fatal_error( + { + vg_fatal_condition(); + vg_info( "Cannot specify libc version using the '%s' compiler.\n", compiler_names[ env->compiler ] ); + vg_fatal_exit(); + } + } if( env->compiler == k_compiler_clang ) + { if( env->platform != k_platform_linux ) - vg_fatal_error( "Cannot compile for '%s' using the '%s' compiler;" ); + { + vg_fatal_condition(); + vg_info( "Cannot compile for '%s' using the '%s' compiler;" ); + vg_fatal_exit(); + } + } vg_str cmd = {0}; vg_strcat( &cmd, "ccache " ); @@ -509,7 +521,12 @@ vg_make_app( struct vg_project *proj, appname, k_obj_type_exe ); } else - vg_fatal_error( "Programming error" ); + { + vg_fatal_condition(); + vg_info( "No compile procedure set for platform '%s'\n", + platform_names[env->platform] ); + vg_fatal_exit(); + } return (struct compile_result){}; } diff --git a/vg_build_utils_shader.h b/vg_build_utils_shader.h index 0bbb816..235c67c 100644 --- a/vg_build_utils_shader.h +++ b/vg_build_utils_shader.h @@ -187,11 +187,7 @@ int vg_build_shader( char *src_vert, /* path/to/vert.vs */ FILE *header = fopen( path_header, "w" ); if( !header ) - { - fprintf(stderr, "Could not open '%s'\n", path_header ); - vg_fatal_error( "IO error" ); - return 0; - } + vg_fatal_error( "Could not open '%s'\n", path_header ); fprintf( header, "#pragma once\n" ); fprintf( header, "#include \"vg/vg_engine.h\"\n" ); @@ -206,7 +202,6 @@ int vg_build_shader( char *src_vert, /* path/to/vert.vs */ { fclose( header ); vg_fatal_error( "Failed to assemble vertex source code" ); - return 0; } vg_strcatf( c_body, "\n .fs = \n" ); @@ -214,7 +209,6 @@ int vg_build_shader( char *src_vert, /* path/to/vert.vs */ { fclose( header ); vg_fatal_error( "Failed to assemble fragment source code" ); - return 0; } vg_strcatf( c_body, "\n};\n\n" ); @@ -254,7 +248,7 @@ int vg_build_shader( char *src_vert, /* path/to/vert.vs */ if( uf->array ) continue; - for( int j=0; jdepth+1 >= vg_list_size(it->stack) ){ + if( it->depth+1 >= VG_ARRAY_LEN(it->stack) ){ vg_error( "Maximum stack reached!\n" ); return 0; } diff --git a/vg_console.c b/vg_console.c index 0f7387d..00d8e5f 100644 --- a/vg_console.c +++ b/vg_console.c @@ -10,11 +10,8 @@ struct vg_console vg_console; void vg_console_reg_var( const char *alias, void *ptr, enum vg_var_dtype type, u32 flags ) { - if( vg_thread_purpose() == k_thread_purpose_main ) - vg_fatal_error( "FIXME: Cannot register VAR from main thread" ); - - if( vg_console.var_count > vg_list_size(vg_console.vars) ) - vg_fatal_error( "Too many vars registered" ); + VG_ASSERT( vg_thread_purpose() != k_thread_purpose_main ); + VG_ASSERT( vg_console.var_count < VG_ARRAY_LEN(vg_console.vars) ); vg_var *var = &vg_console.vars[ vg_console.var_count ++ ]; var->name = alias; @@ -29,11 +26,8 @@ void vg_console_reg_cmd( const char *alias, int (*function)(int argc, const char *argv[]), void (*poll_suggest)(int argc, const char *argv[]) ) { - if( vg_thread_purpose() == k_thread_purpose_main ) - vg_fatal_error( "FIXME: Cannot register CMD from main thread" ); - - if( vg_console.function_count > vg_list_size(vg_console.functions) ) - vg_fatal_error( "Too many functions registered" ); + VG_ASSERT( vg_thread_purpose() != k_thread_purpose_main ); + VG_ASSERT( vg_console.function_count < VG_ARRAY_LEN(vg_console.functions) ); vg_cmd *cmd = &vg_console.functions[ vg_console.function_count ++ ]; @@ -345,10 +339,10 @@ void console_suggest_score_text( const char *str, const char *input, best_pos = j; /* insert if good score */ - if( best_pos < vg_list_size( vg_console.suggestions ) ) + if( best_pos < VG_ARRAY_LEN( vg_console.suggestions ) ) { int start = VG_MIN( vg_console.suggestion_count, - vg_list_size( vg_console.suggestions )-1 ); + VG_ARRAY_LEN( vg_console.suggestions )-1 ); for( int j=start; j>best_pos; j -- ) vg_console.suggestions[j] = vg_console.suggestions[j-1]; @@ -357,7 +351,7 @@ void console_suggest_score_text( const char *str, const char *input, vg_console.suggestions[ best_pos ].lev_score = score; if( vg_console.suggestion_count < - vg_list_size( vg_console.suggestions ) ) + VG_ARRAY_LEN( vg_console.suggestions ) ) vg_console.suggestion_count ++; } } @@ -452,7 +446,7 @@ static void _console_fetch_suggestion( ui_context *ctx ) { strncpy( target, vg_console.suggestions[ vg_console.suggestion_select ].str, - vg_list_size( vg_console.input )-1 ); + VG_ARRAY_LEN( vg_console.input )-1 ); _ui_textbox_move_cursor( ctx, &ctx->textbox.cursor_user, @@ -515,7 +509,7 @@ static void console_history_get( char* buf, int entry_num ) int offset = VG_MIN( entry_num, vg_console.history_count -1 ), pick = (vg_console.history_last - offset) % - vg_list_size( vg_console.history ); + VG_ARRAY_LEN( vg_console.history ); strcpy( buf, vg_console.history[ pick ] ); } @@ -532,7 +526,7 @@ static void _vg_console_on_up( ui_context *ctx, char *buf, u32 len ) vg_console.history_pos+1, VG_MIN ( - vg_list_size( vg_console.history ), + VG_ARRAY_LEN( vg_console.history ), vg_console.history_count - 1 ) ) @@ -542,7 +536,7 @@ static void _vg_console_on_up( ui_context *ctx, char *buf, u32 len ) _ui_textbox_move_cursor( ctx, &ctx->textbox.cursor_user, &ctx->textbox.cursor_pos, - vg_list_size(vg_console.input)-1, 1 ); + VG_ARRAY_LEN(vg_console.input)-1, 1 ); } } @@ -556,7 +550,7 @@ static void _vg_console_on_down( ui_context *ctx, char *buf, u32 len ) _ui_textbox_move_cursor( ctx, &ctx->textbox.cursor_user, &ctx->textbox.cursor_pos, - vg_list_size(vg_console.input)-1, 1 ); + VG_ARRAY_LEN(vg_console.input)-1, 1 ); } } @@ -573,9 +567,9 @@ static void _vg_console_on_enter( ui_context *ctx, char *buf, u32 len ) vg_console.history[ vg_console.history_last ]) ) { vg_console.history_last = ( vg_console.history_last + 1) % - vg_list_size(vg_console.history ); + VG_ARRAY_LEN(vg_console.history ); vg_console.history_count = - VG_MIN( vg_list_size( vg_console.history ), + VG_MIN( VG_ARRAY_LEN( vg_console.history ), vg_console.history_count + 1 ); strcpy( vg_console.history[ vg_console.history_last ], vg_console.input ); @@ -673,7 +667,7 @@ void vg_console_draw( ui_context *ctx ) { ptr --; - if( ptr < 0 ) ptr = vg_list_size( vg_log.log )-1; + if( ptr < 0 ) ptr = VG_ARRAY_LEN( vg_log.log )-1; ui_text( ctx, rect_line, vg_log.log[ptr], 1, k_ui_align_left, 0 ); rect_line[1] -= fh; @@ -691,7 +685,7 @@ void vg_console_draw( ui_context *ctx ) .enter = _vg_console_on_enter, }; ui_textbox( ctx, rect_input, NULL, - vg_console.input, vg_list_size(vg_console.input), 1, + vg_console.input, VG_ARRAY_LEN(vg_console.input), 1, UI_TEXTBOX_AUTOFOCUS, &callbacks ); /* diff --git a/vg_engine.c b/vg_engine.c index ddcda8f..2470b49 100644 --- a/vg_engine.c +++ b/vg_engine.c @@ -12,42 +12,34 @@ struct vg_engine vg = #include "vg/vg_ui/imgui_impl_opengl.c" #include "vg/vg_default_font.gc" -#define TEMP_STATUS_LOCK SDL_AtomicLock -#define TEMP_STATUS_UNLOCK SDL_AtomicUnlock -#define TEMP_SEM_POST(X) SDL_SemPost( X ) -#define TEMP_SEM_WAIT(X) SDL_SemWait( X ) -#define TEMP_SEM_GET(X) SDL_SemValue( X ) - enum engine_status _vg_engine_status(void) { - TEMP_STATUS_LOCK( &vg.sl_status ); + SDL_AtomicLock( &vg.sl_status ); enum engine_status status = vg.engine_status; - TEMP_STATUS_UNLOCK( &vg.sl_status ); + SDL_AtomicUnlock( &vg.sl_status ); return status; } enum vg_thread_purpose vg_thread_purpose(void) { - TEMP_STATUS_LOCK( &vg.sl_status ); - if( vg.thread_id_main == SDL_GetThreadID(NULL) ) + SDL_AtomicLock( &vg.sl_status ); + + SDL_threadID id = SDL_GetThreadID(NULL); + if( vg.thread_id_main == id ) { - TEMP_STATUS_UNLOCK( &vg.sl_status ); + SDL_AtomicUnlock( &vg.sl_status ); return k_thread_purpose_main; } - else + else if( vg.thread_id_loader == id ) { - TEMP_STATUS_UNLOCK( &vg.sl_status ); + SDL_AtomicUnlock( &vg.sl_status ); return k_thread_purpose_loader; } -} - -static void vg_assert_thread( enum vg_thread_purpose required ) -{ - enum vg_thread_purpose purpose = vg_thread_purpose(); - - if( purpose != required ){ - vg_fatal_error( "thread_purpose must be %u not %u\n", required, purpose ); + else + { + SDL_AtomicUnlock( &vg.sl_status ); + return k_thread_purpose_nothing; } } @@ -77,20 +69,6 @@ static struct vg_profile vg_prof_update = {.name="update()"}, vg_prof_render = {.name="render()"}, vg_prof_swap = {.name="swap"}; -void vg_checkgl( const char *src_info ) -{ - int fail = 0; - - GLenum err; - while( (err = glGetError()) != GL_NO_ERROR ){ - vg_error( "(%s) OpenGL Error: #%d\n", src_info, err ); - fail = 1; - } - - if( fail ) - vg_fatal_error( "OpenGL Error" ); -} - static void async_vg_bake_shaders( void *payload, u32 size ) { vg_shaders_compile(); @@ -106,11 +84,11 @@ void async_internal_complete( void *payload, u32 size ) { vg_success( "Internal async setup complete\n" ); - TEMP_STATUS_LOCK( &vg.sl_status ); + SDL_AtomicLock( &vg.sl_status ); if( vg.engine_status == k_engine_status_crashed ) { - TEMP_STATUS_UNLOCK( &vg.sl_status ); + SDL_AtomicUnlock( &vg.sl_status ); return; } else @@ -118,9 +96,7 @@ void async_internal_complete( void *payload, u32 size ) vg.engine_status = k_engine_status_running; } - TEMP_STATUS_UNLOCK( &vg.sl_status ); - - vg.client_has_control = 1; + SDL_AtomicUnlock( &vg.sl_status ); } #ifdef VG_CUSTOM_SHADERS @@ -455,13 +431,8 @@ static int vg_framefilter( double dt ){ return 0; } -static int _vg_crashscreen(void) +static void _vg_crashscreen(void) { -#if 0 - if( vg_getkey( SDLK_ESCAPE ) ) - return 1; -#endif - glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glEnable(GL_BLEND); glDisable(GL_DEPTH_TEST); @@ -472,11 +443,22 @@ static int _vg_crashscreen(void) glClear( GL_COLOR_BUFFER_BIT ); glViewport( 0,0, vg.window_x, vg.window_y ); -#if 0 - _vg_render_log(); -#endif + ui_prerender( &vg_ui.ctx ); + vg_ui_set_screen( vg.window_x, vg.window_y ); + ui_update_mouse( &vg_ui.ctx, + (ui_px[2]){ vg.mouse_pos[0], vg.mouse_pos[1] }, vg.mouse_state ); - return 0; + vg_framebuffer_ui( &vg_ui.ctx ); + + vg_console.enabled = 1; + ui_ignore_input_frames( &vg_ui.ctx, 10 ); + vg_gui( &vg_ui.ctx ); + ui_ignore_input_frames( &vg_ui.ctx, 0 ); + ui_capture_mouse( &vg_ui.ctx, 1 ); + vg_console_draw( &vg_ui.ctx ); + + ui_postrender( &vg_ui.ctx, vg.time_frame_delta ); + vg_ui_post_update(); } static void _vg_gameloop(void) @@ -521,8 +503,7 @@ static void _vg_gameloop(void) if( status == k_engine_status_crashed ) { - if( _vg_crashscreen() ) - break; + _vg_crashscreen(); } else { @@ -726,16 +707,16 @@ static void _vg_terminate(void) /* Shutdown */ vg_console_write_persistent(); - TEMP_STATUS_LOCK( &vg.sl_status ); + SDL_AtomicLock( &vg.sl_status ); vg.engine_status = k_engine_status_none; - TEMP_STATUS_UNLOCK( &vg.sl_status ); + SDL_AtomicUnlock( &vg.sl_status ); - vg_loader_free(); - - vg_success( "If you see this it means everything went.. \"well\".....\n" ); + vg_loader_atexit(); SDL_GL_DeleteContext( vg.gl_context ); SDL_Quit(); + + vg_success( "The program has terminated 'correctly'\n" ); exit(0); } @@ -778,28 +759,45 @@ void vg_enter( int argc, char *argv[], const char *window_name ) /* Opengl-required systems */ vg_ui_init(); - vg_loader_init(); vg.engine_status = k_engine_status_load_internal; + vg_loader_step( vg_loader_init, vg_loader_free ); _vg_opengl_sync_init(); - vg_loader_start( _vg_load_full, NULL ); + vg_loader_start( _vg_load_full, NULL ); _vg_gameloop(); _vg_terminate(); } -void vg_fatal_error( const char *fmt, ... ) +#ifndef _WIN32 + #include +#endif + +void vg_fatal_exit(void) { - va_list args; - va_start( args, fmt ); - _vg_logx_va( stderr, NULL, "fatal", KRED, fmt, args ); - va_end( args ); + /* append backtrace */ +#if !defined(_WIN32) + void *array[20]; + char **strings; + int size, i; + + size = backtrace( array, 20 ); + strings = backtrace_symbols( array, size ); + + if( strings != NULL ) + { + vg_info( "\n\n---------------- gnu backtrace -------------\n" ); - vg_print_backtrace(); + for( int i=0; i @@ -125,13 +126,6 @@ struct vg_engine SDL_GLContext gl_context; SDL_sem *sem_loader; /* allows only one loader at a time */ - bool client_has_control; /* [T0] If 0: VG will display a loader screen - If 1: The game is responsible for - drawing everything. - This can be set back to 0 after vg_load is - complete to blinder the client - Not recommended! */ - SDL_threadID thread_id_main, thread_id_loader; diff --git a/vg_framebuffer.c b/vg_framebuffer.c index 8a70b61..253c3a5 100644 --- a/vg_framebuffer.c +++ b/vg_framebuffer.c @@ -74,8 +74,10 @@ void vg_framebuffer_bind_texture( vg_framebuffer *fb, int attachment, int slot ) if( (at->purpose != k_framebuffer_attachment_type_texture) && (at->purpose != k_framebuffer_attachment_type_texture_depth) ) { - vg_fatal_error( "illegal operation: bind non-texture framebuffer" - " attachment to texture slot" ); + vg_fatal_condition(); + vg_info( "illegal operation: bind non-texture framebuffer" + " attachment to texture slot" ); + vg_fatal_exit(); } glActiveTexture( GL_TEXTURE0 + slot ); @@ -99,7 +101,7 @@ static const char *render_fb_attachment_str( GLenum e ) FB_FORMAT_STR(GL_DEPTH_STENCIL_ATTACHMENT) }; - for( int i=0; iattachments = vg_linear_alloc( alloc, @@ -311,17 +317,17 @@ static void async_framebuffer_create( void *payload, u32 size ) } else { + vg_fatal_condition(); if( result == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT ) - vg_error( " status: Incomplete attachment" ); + vg_info( " status: Incomplete attachment" ); else if( result == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT ) - vg_error( " status: Missing attachment" ); + vg_info( " status: Missing attachment" ); else if( result == GL_FRAMEBUFFER_UNSUPPORTED ) - vg_error( " status: Unsupported framebuffer format" ); + vg_info( " status: Unsupported framebuffer format" ); else - vg_error( " status: Generic Error" ); - + vg_info( " status: Generic Error" ); vg_info( "}\n" ); - vg_fatal_error( "Incomplete framebuffer (see logs)" ); + vg_fatal_exit(); } } diff --git a/vg_input.c b/vg_input.c index d4e51bc..ee0df5f 100644 --- a/vg_input.c +++ b/vg_input.c @@ -394,7 +394,7 @@ next_code:; else if( op == vg_gui_visible ) pc ++; else - vg_fatal_error( "unknown op\n" ); + vg_fatal_error( "unknown op (%u)\n", op ); goto next_code; } @@ -406,10 +406,10 @@ const char *controller_button_str( SDL_GameControllerButton button ) { static const char *controller_glyphs[ SDL_CONTROLLER_BUTTON_MAX ][2] = { /* xbox/generic playstation */ - [ SDL_CONTROLLER_BUTTON_A ] = { KGRN "\x06\x02\x85",KBLU "\x06\x02\x82" }, - [ SDL_CONTROLLER_BUTTON_B ] = { KRED "\x06\x02\x86",KRED "\x06\x02\x81" }, - [ SDL_CONTROLLER_BUTTON_X ] = { KBLU "\x06\x02\x83",KMAG "\x06\x02\x7f" }, - [ SDL_CONTROLLER_BUTTON_Y ] = { KYEL "\x06\x02\x84",KGRN "\x06\x02\x80" }, + [ SDL_CONTROLLER_BUTTON_A ] = { KGRN "\x06\x02\x85",KBLU "\x06\x02\x82" }, + [ SDL_CONTROLLER_BUTTON_B ] = { KRED "\x06\x02\x86",KRED "\x06\x02\x81" }, + [ SDL_CONTROLLER_BUTTON_X ] = { KBLU "\x06\x02\x83",KMAG "\x06\x02\x7f" }, + [ SDL_CONTROLLER_BUTTON_Y ] = { KYEL "\x06\x02\x84",KGRN "\x06\x02\x80" }, [ SDL_CONTROLLER_BUTTON_LEFTSTICK ] = { "\x87","\x87" }, [ SDL_CONTROLLER_BUTTON_RIGHTSTICK ] = { "\x8b","\x8b" }, [ SDL_CONTROLLER_BUTTON_LEFTSHOULDER ] = { "\x91","\x91" }, diff --git a/vg_io.c b/vg_io.c index 76e8ca3..b100992 100644 --- a/vg_io.c +++ b/vg_io.c @@ -108,17 +108,16 @@ void vg_dir_close( vg_dir *dir ) dir->index = 0; } -void vg_file_print_invalid( FILE *fp ) +void vg_file_error_info( FILE *fp ) { - if( feof( fp )) { + if( feof( fp )) + { vg_error( "mdl_open: header too short\n" ); } - else{ - if( ferror( fp )) - vg_error( "mdl_open: %s\n", strerror(errno) ); - else - vg_error( "mdl_open: unkown failure\n" ); - + else + { + if( ferror( fp )) vg_info( "fopen: %s\n", strerror(errno) ); + else vg_info( "fopen: unkown failure\n" ); } } @@ -128,13 +127,15 @@ void vg_file_print_invalid( FILE *fp ) void *vg_file_read( void *lin_alloc, const char *path, u32 *size ) { FILE *f = fopen( path, "rb" ); - if( f ){ + if( f ) + { void *buffer = lin_alloc? vg_linear_alloc( lin_alloc, 0 ): NULL; u64 current = 0; /* read in chunks */ - for( u32 i=0; 1; i++ ){ + for( u32 i=0; 1; i++ ) + { if( lin_alloc ) buffer = vg_linear_extend( lin_alloc,buffer,VG_FILE_IO_CHUNK_SIZE ); else @@ -143,18 +144,27 @@ void *vg_file_read( void *lin_alloc, const char *path, u32 *size ) u64 l = fread( buffer + current, 1, VG_FILE_IO_CHUNK_SIZE, f ); current += l; - if( l != VG_FILE_IO_CHUNK_SIZE ){ - if( feof( f ) ){ + if( l != VG_FILE_IO_CHUNK_SIZE ) + { + if( feof( f ) ) + { break; } - else{ - if( ferror( f ) ){ + else + { + if( ferror( f ) ) + { fclose(f); - vg_fatal_error( "read error" ); + vg_fatal_condition(); + vg_info( "Read error\n" ); + vg_fatal_exit(); } - else{ + else + { fclose(f); - vg_fatal_error( "unknown error codition" ); + vg_fatal_condition(); + vg_info( "Unknown error condition\n" ); + vg_fatal_exit(); } } } diff --git a/vg_io.h b/vg_io.h index fefb6bf..0991f0e 100644 --- a/vg_io.h +++ b/vg_io.h @@ -35,7 +35,6 @@ int vg_dirskip( vg_dir *dir ); int vg_dir_next_entry( vg_dir *dir ); enum vg_entry_type vg_dir_entry_type( vg_dir *dir ); void vg_dir_close( vg_dir *dir ); -void vg_file_print_invalid( FILE *fp ); /* * File I/O @@ -50,3 +49,4 @@ char *vg_file_read_text( void *lin_alloc, const char *path, u32 *sz ); int vg_asset_write( const char *path, void *data, i64 size ); int vg_file_copy( const char *src, const char *dst, void *lin_alloc ); const char *vg_path_filename( const char *path ); +void vg_file_error_info( FILE *fp ); diff --git a/vg_lines.c b/vg_lines.c index 6315482..94f8b68 100644 --- a/vg_lines.c +++ b/vg_lines.c @@ -57,7 +57,6 @@ static void async_vg_lines_init( void *payload, u32 payload_size ) glBufferData( GL_ARRAY_BUFFER, VG_LINES_BUFFER_SIZE, NULL, GL_DYNAMIC_DRAW ); glBindVertexArray( vg_lines.vao ); - VG_CHECK_GL_ERR(); /* Pointers */ glVertexAttribPointer( @@ -79,8 +78,6 @@ static void async_vg_lines_init( void *payload, u32 payload_size ) (void*)(offsetof( struct vg_lines_vert, colour )) ); glEnableVertexAttribArray( 1 ); - - VG_CHECK_GL_ERR(); } void vg_lines_init(void) @@ -187,7 +184,7 @@ void vg_line_boxf( boxf box, u32 colour ) {4,5},{5,7},{7,6},{6,4}, {4,0},{5,1},{6,2},{7,3}}; - vg_line_mesh( verts, indices, vg_list_size(indices), colour ); + vg_line_mesh( verts, indices, VG_ARRAY_LEN(indices), colour ); } void vg_line_boxf_transformed( m4x3f m, boxf box, u32 colour ) @@ -205,7 +202,7 @@ void vg_line_boxf_transformed( m4x3f m, boxf box, u32 colour ) {4,5},{5,7},{7,6},{6,4}, {4,0},{5,1},{6,2},{7,3}}; - vg_line_mesh( verts, indices, vg_list_size(indices), colour ); + vg_line_mesh( verts, indices, VG_ARRAY_LEN(indices), colour ); } void vg_line_cross(v3f pos,u32 colour, float scale) diff --git a/vg_loader.c b/vg_loader.c index 4859f75..f16d2c4 100644 --- a/vg_loader.c +++ b/vg_loader.c @@ -78,18 +78,18 @@ void vg_loader_init(void) glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, sizeof(float)*2, (void*)0 ); glEnableVertexAttribArray( 0 ); - VG_CHECK_GL_ERR(); - - if( !vg_shader_compile( &_shader_loader ) ) - vg_fatal_error( "failed to compile shader" ); + vg_compile_shader( &_shader_loader ); } -static void vg_loader_free(void) +void vg_loader_free(void) { - vg_info( "vg_loader_free\n" ); glDeleteVertexArrays( 1, &vg_loader.vao ); glDeleteBuffers( 1, &vg_loader.vbo ); +} +void vg_loader_atexit(void) +{ + vg_info( "Shutdown steps\n" ); for( int i=0; i -#endif - struct vg_log vg_log; static void _vg_log_append_line( const char *str ) { - if( vg_log.log_line_count < vg_list_size( vg_log.log ) ) + if( vg_log.log_line_count < VG_ARRAY_LEN( vg_log.log ) ) vg_log.log_line_count ++; char *dest = vg_log.log[ vg_log.log_line_current ++ ]; - vg_strncpy( str, dest, vg_list_size(vg_log.log[0]), k_strncpy_allow_cutoff ); + vg_strncpy( str, dest, VG_ARRAY_LEN(vg_log.log[0]), k_strncpy_allow_cutoff ); - if( vg_log.log_line_current >= vg_list_size( vg_log.log ) ) + if( vg_log.log_line_current >= VG_ARRAY_LEN( vg_log.log ) ) vg_log.log_line_current = 0; } @@ -40,12 +36,12 @@ void _vg_logx_va( FILE *file, char buffer[4096]; - vsnprintf( buffer, vg_list_size(buffer), fmt, args ); + vsnprintf( buffer, VG_ARRAY_LEN(buffer), fmt, args ); const char *line = buffer; char logline[96]; - for( u32 i=0; icur + size) > alloc->size ) - { vg_fatal_error( "linear allocator overflow (%u + %u > %u)\n", - alloc->cur, size, alloc->size ); - } + alloc->cur, size, alloc->size ); if( alloc->flags & VG_MEMORY_SYSTEM ) { if( (alloc->allocation_count + 1) > VG_MAX_ALLOCATIONS ) { - vg_error( "Alloc (%p) allocation count is at the limit of" - " %u allocations.\n", alloc, VG_MAX_ALLOCATIONS ); - vg_fatal_error( "Max linear allocations reached" ); + vg_fatal_condition(); + vg_info( "Linear allocators marked as 'SYSTEMS', have a hard limit of " + "%u allocations.\n\n" + "The limit was exceeded by the following request:\n", + VG_MAX_ALLOCATIONS ); + vg_info( " Name: %s\n", constr_name ); + vg_info( " Size: %u bytes\n", size ); + vg_fatal_exit(); } } void *data; - if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) ){ + if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) ) + { data = malloc( size ); vg_allocation_meta *meta = &alloc->alloc_table[ alloc->allocation_count ]; @@ -69,24 +73,21 @@ void *_vg_linear_alloc( void *buffer, u32 size, const char *constr_name ) meta->size = size; meta->name = constr_name; } - else{ + else data = buffer + alloc->cur; - } u8 *bytes = data; - for( u32 i=0; iallocation_count ++; alloc->last_alloc = data; alloc->last_alloc_size = size; alloc->cur += size; - if( ((u64)data) % 8 ){ - vg_fatal_error( "unaligned" ); - } - + if( ((u64)data) % 8 ) + vg_fatal_error( "Resultant allocation was unaligned, most likely memory " + "corruption or programmer error\n" ); return data; } @@ -100,28 +101,29 @@ void *vg_linear_resize( void *buffer, void *data, u32 newsize ) newsize = vg_align8( newsize ); if( alloc->last_alloc != data ) - vg_fatal_error( "This block has been fixed!" ); + vg_fatal_error( "Tried to resize allocation in linear allocator which " + "has allocated other things after this block.\n" ); if( (alloc->cur - alloc->last_alloc_size + newsize) > alloc->size ) - vg_fatal_error( "Cannot resize, overflow" ); + vg_fatal_error( "Tried to resize allocation to new size which would " + "overflow the allocator\n" ); alloc->cur -= alloc->last_alloc_size; alloc->cur += newsize; alloc->last_alloc_size = newsize; - if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) ){ + if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) ) + { data = realloc( data, newsize ); if( !data ) - vg_fatal_error( "realloc failed" ); + vg_fatal_error( "We are libc mode, and realloc failed" ); alloc->alloc_table[ alloc->allocation_count-1 ].data = data; alloc->alloc_table[ alloc->allocation_count-1 ].size = newsize; alloc->last_alloc = data; return data; } - else{ - return data; - } + else return data; } /* its possible to delete just the last item */ @@ -129,12 +131,12 @@ void vg_linear_del( void *buffer, void *data ) { vg_linear_allocator *alloc = vg_linear_header( buffer ); - if( alloc->last_alloc != data ){ - vg_fatal_error( "This block has been fixed! Last alloc: %p, this: %p\n", - alloc->last_alloc, data ); - } + if( alloc->last_alloc != data ) + vg_fatal_error( "This block has been fixed and cannot be deleted.\n" + "Last alloc: %p, this: %p\n", alloc->last_alloc, data ); - if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) ){ + if( vg_mem.use_libc_malloc && (alloc->flags & VG_MEMORY_SYSTEM) ) + { vg_allocation_meta *meta = &alloc->alloc_table[alloc->allocation_count-1]; if( meta->type == k_allocation_type_linear ) vg_fatal_error( "Cannot free a linear allocator in this conext" ); @@ -229,25 +231,27 @@ void vg_linear_clear( void *buffer ) void *_vg_create_linear_allocator( void *lin_alloc, u32 size, u16 flags, const char *constr_name) { - if( sizeof( vg_linear_allocator ) != 32 ) - vg_fatal_error( "Programming error" ); + VG_ASSERT( sizeof( vg_linear_allocator ) == 32 ); vg_linear_allocator *header; u32 block_size = size + sizeof(vg_linear_allocator); /* Creating it inside an existing one */ - if( lin_alloc ){ + if( lin_alloc ) + { vg_linear_allocator *alloc = vg_linear_header( lin_alloc ); if( alloc->cur + block_size > alloc->size ) - vg_fatal_error( "Out of memory" ); + vg_fatal_error( "Out of memory (%u + %u > %u)\n", + alloc->cur, block_size, alloc->size ); if( alloc->allocation_count + 1 > VG_MAX_ALLOCATIONS ) - vg_fatal_error( "Max allocations in linear allocator" ); + vg_fatal_error( "Exceeded max allocations in linear allocator (%u)\n", + VG_MAX_ALLOCATIONS ); if( (flags && VG_MEMORY_SYSTEM) && (alloc->flags & VG_MEMORY_REALTIME) ) - vg_fatal_error( "Cannot declare realtime allocator inside systems" - " allocator" ); + vg_fatal_error( "Cannot declare realtime allocator inside systems " + "allocator"); if( vg_mem.use_libc_malloc ){ vg_allocation_meta *meta = @@ -263,9 +267,7 @@ void *_vg_create_linear_allocator( void *lin_alloc, u32 size, meta->size = size; meta->name = constr_name; } - else{ - header = lin_alloc + alloc->cur; - } + else header = lin_alloc + alloc->cur; alloc->cur += block_size; alloc->last_alloc = header; @@ -286,12 +288,12 @@ void *_vg_create_linear_allocator( void *lin_alloc, u32 size, header->size = size; header->flags = flags; - if( vg_mem.use_libc_malloc && (flags & VG_MEMORY_SYSTEM) ){ + if( vg_mem.use_libc_malloc && (flags & VG_MEMORY_SYSTEM) ) + { u32 table_size = sizeof(vg_allocation_meta)*VG_MAX_ALLOCATIONS; header->alloc_table = malloc( table_size ); } - else - header->alloc_table = NULL; + else header->alloc_table = NULL; return header+1; } diff --git a/vg_mem.h b/vg_mem.h index 94042a9..6fde883 100644 --- a/vg_mem.h +++ b/vg_mem.h @@ -1,6 +1,6 @@ #pragma once -#define VG_MAX_ALLOCATIONS 256 +#define VG_MAX_ALLOCATIONS 128 typedef struct vg_linear_allocator vg_linear_allocator; typedef struct vg_allocation_meta vg_allocation_meta; diff --git a/vg_mem_pool.c b/vg_mem_pool.c index 1fe3302..0a830a2 100644 --- a/vg_mem_pool.c +++ b/vg_mem_pool.c @@ -69,12 +69,11 @@ void vg_pool_watch( vg_pool *pool, u16 id ) { vg_pool_node *node = vg_pool_nodeptr( pool, id ); - if( !node->ref_count ){ + if( !node->ref_count ) vg_pool_unlink( pool, id ); - } if( node->ref_count == 0xffff ) - vg_fatal_error( "pool watch missmatch (limit is 128)\n" ); + vg_fatal_error( "Pool watch missmatch (limit is 128)\n" ); node->ref_count ++; } @@ -88,7 +87,8 @@ void vg_pool_unwatch( vg_pool *pool, u16 id ) vg_fatal_error( "pool unwatch missmatch (no watchers)\n" ); node->ref_count --; - if( !node->ref_count ){ + if( !node->ref_count ) + { vg_pool_node *head = vg_pool_nodeptr( pool, pool->head ), *tail = vg_pool_nodeptr( pool, pool->tail ); diff --git a/vg_msg.c b/vg_msg.c index 16ce1d8..facd66b 100644 --- a/vg_msg.c +++ b/vg_msg.c @@ -119,7 +119,7 @@ u32 vg_msg_cmd_bytecount( u8 code ) u8 vg_msg_count_bits( u32 count ) { - if( count > 16 ) vg_fatal_error( "Too large\n" ); + VG_ASSERT( count <= 16 ); return ((count-1)<<2); } diff --git a/vg_opengl.c b/vg_opengl.c new file mode 100644 index 0000000..8e4e55a --- /dev/null +++ b/vg_opengl.c @@ -0,0 +1,38 @@ +#include "vg/vg_opengl.h" + +static const char *gl_error_names[] = +{ + "GL_INVALID_ENUM", + "GL_INVALID_VALUE", + "GL_INVALID_OPERATION", + "GL_STACK_OVERFLOW", + "GL_STACK_UNDERFLOW", + "GL_OUT_OF_MEMORY", + "GL_INVALID_FRAMEBUFFER_OPERATION" +}; + +void vg_opengl_log_errors(void) +{ + u32 err_count = 0; + GLenum err; + while( (err = glGetError()) != GL_NO_ERROR ) + { + if( !err_count ) + vg_info( "OpenGL error buffer:\n" ); + + u32 err_i = err - 0x0500; + if( err_i < VG_ARRAY_LEN(gl_error_names) ) + { + vg_info( " %u %s\n", err, gl_error_names[ err_i ] ); + } + else + { + vg_info( "%u (unknown code)\n", err ); + } + + err_count ++; + } + + if( !err_count ) + vg_info( "OpenGL error buffer is empty.\n" ); +} diff --git a/vg_opengl.h b/vg_opengl.h index 3656719..a59c1f0 100644 --- a/vg_opengl.h +++ b/vg_opengl.h @@ -1 +1,3 @@ #include "dep/glad/glad.h" + +void vg_opengl_log_errors(void); diff --git a/vg_platform.h b/vg_platform.h index b846b06..e9bf50b 100644 --- a/vg_platform.h +++ b/vg_platform.h @@ -28,15 +28,16 @@ typedef v3f m4x3f[4]; typedef v4f m4x4f[4]; typedef v3f boxf[2]; -/* anything compiled against VG shall implement this function somewhere. */ +/* anything compiled against VG shall implement vg_fatal_exit() somewhere. */ +void vg_fatal_condition(void); +void vg_fatal_exit(void); void vg_fatal_error( const char *fmt, ... ); #define VG_ASSERT( ITEM, ... ) \ - if( !( ITEM ) ) { \ - vg_fatal_error( "Assertion failed: " VG_LOG_MCSTR(ITEM) "\n" \ - VG_LOG_WHERE ); \ - } + if( !( ITEM ) ) { \ + vg_fatal_error( "Assertion failed: " VG_LOG_MCSTR(ITEM) "\n" VG_LOG_WHERE );\ + } #define VG_MIN( A, B ) ((A)<(B)?(A):(B)) #define VG_MAX( A, B ) ((A)>(B)?(A):(B)) -#define vg_list_size( A ) (sizeof(A)/sizeof(A[0])) +#define VG_ARRAY_LEN( A ) (sizeof(A)/sizeof(A[0])) diff --git a/vg_profiler.c b/vg_profiler.c index 79e0723..4785743 100644 --- a/vg_profiler.c +++ b/vg_profiler.c @@ -52,7 +52,7 @@ void vg_profile_drawn( ui_context *ctx, struct vg_profile **profiles, u32 count, ui_fill( ctx, panel, 0xa0000000 ); - if( count > 8 ) vg_fatal_error( "Too many profiles\n" ); + VG_ASSERT( count <= 8 ); f64 avgs[8]; u32 colours[8]; diff --git a/vg_rigidbody.c b/vg_rigidbody.c index bcfebc5..322f42a 100644 --- a/vg_rigidbody.c +++ b/vg_rigidbody.c @@ -89,11 +89,11 @@ void rb_extrapolate( rigidbody *rb, v3f co, v4f q ) void rb_iter( rigidbody *rb ) { - if( !vg_validf( rb->v[0] ) || - !vg_validf( rb->v[1] ) || - !vg_validf( rb->v[2] ) ) + if( !vg_validf(rb->v[0]) || !vg_validf(rb->v[1]) || !vg_validf(rb->v[2]) ) { - vg_fatal_error( "NaN velocity" ); + vg_fatal_error( + "Aborting the program because velocity has invalid value in one " + "or more components: %f %f %f\n", rb->v[0],rb->v[1],rb->v[2] ); } v3f gravity = { 0.0f, -9.8f, 0.0f }; diff --git a/vg_rigidbody_collision.c b/vg_rigidbody_collision.c index 1c1d058..2989a46 100644 --- a/vg_rigidbody_collision.c +++ b/vg_rigidbody_collision.c @@ -495,7 +495,7 @@ int rb_capsule__triangle( m4x3f mtxA, rb_capsule *c, v3f tri[3], rb_ct *buf ) int rb_global_has_space( void ) { - if( rb_contact_count + 16 > vg_list_size(rb_contact_buffer) ) + if( rb_contact_count + 16 > VG_ARRAY_LEN(rb_contact_buffer) ) return 0; return 1; diff --git a/vg_rigidbody_view.c b/vg_rigidbody_view.c index 962148f..f16f3c6 100644 --- a/vg_rigidbody_view.c +++ b/vg_rigidbody_view.c @@ -134,8 +134,6 @@ static void async_vg_rb_view_init( void *payload, u32 payload_size ) glVertexAttribPointer( 1, 3, GL_FLOAT, GL_FALSE, stride, (void *)offsetof(rb_view_vert, n) ); glEnableVertexAttribArray( 1 ); - - VG_CHECK_GL_ERR(); } void vg_rb_view_init(void) diff --git a/vg_shader.c b/vg_shader.c index b17c64a..ace5c17 100644 --- a/vg_shader.c +++ b/vg_shader.c @@ -21,13 +21,21 @@ struct vg_shaders } static vg_shaders; -static GLuint vg_shader_subshader( const char *src, GLint gliShaderType ) +/* + * Compile OpenGL subshader from GLSL source. Type is subshader type. + * If critical is set to 1, the program will fatal exit on compile failure. + */ +static GLuint vg_compile_opengl_subshader( GLint type, + const char *src, bool critical ) { - GLint shader = glCreateShader( gliShaderType ); + GLuint shader = glCreateShader( type ); - if( shader == GL_NONE ) + if( shader == 0 ) { - vg_error( "Could not 'glCreateShader()'\n" ); + vg_fatal_condition(); + vg_info( "glCreateShader returned 0.\n" ); + vg_opengl_log_errors(); + vg_fatal_exit(); return 0; } @@ -37,113 +45,139 @@ static GLuint vg_shader_subshader( const char *src, GLint gliShaderType ) GLint status; glGetShaderiv( shader, GL_COMPILE_STATUS, &status ); - if( status != GL_TRUE ) - { + if( status == GL_TRUE ) + { + return shader; + } + else + { + if( critical ) vg_fatal_condition(); + GLchar info[1024]; GLsizei len; + glGetShaderInfoLog( shader, sizeof(info), &len, info ); - glGetShaderInfoLog( shader, sizeof(info), &len, info ); - vg_error( "Error info:\n%s\n", info ); - return 0; - } + const char *type_str = "?"; + + if( type == GL_VERTEX_SHADER ) type_str = "GL_VERTEX_SHADER"; + else if( type == GL_FRAGMENT_SHADER ) type_str = "GL_FRAGMENT_SHADER"; + + vg_info( "%s subshader compile error:\n\n%s\n", type_str, info ); - return shader; + if( critical ) vg_fatal_exit(); + return 0; + } } -int vg_shader_compile( struct vg_shader *shader ) +/* + * Final compilation by linking, if critical is 1, a fatal exit will occur on + * link failure + */ +static int vg_link_opengl_program( GLuint program, bool critical ) { - GLuint program, vert, frag; - - /* If we are compiling this again, we obviously need to try to take the src - * from the disk instead. - * - * Only do this if we have filenames set on the shader, so engine shaders - * dont have to do it (text.. etc). - */ - - int use_source_files = 0; - if( shader->compiled ){ - if( shader->vs.orig_file && shader->fs.orig_file ){ - use_source_files = 1; - } - else { - vg_warn( "No source files for shader '%s'\n", shader->name ); - return 1; - } - } + glLinkProgram( program ); + + GLint success; + glGetProgramiv( program, GL_LINK_STATUS, &success ); - vg_info( "Compile shader '%s'\n", shader->name ); - - if( use_source_files ){ - char error[260]; - char path[260]; - - strcpy( path, "../../" ); - strcat( path, shader->vs.orig_file ); - char *vertex_src = stb_include_file( path, "", "../../shaders", error ); - - strcpy( path, "../../" ); - strcat( path, shader->fs.orig_file ); - char *fragment_src = stb_include_file( path, "", "../../shaders", error ); - - if( !vertex_src || !fragment_src ){ - const char *errstr = "Could not find shader source files (%s)\n"; - if( shader->compiled ){ - vg_warn( errstr, shader->vs.orig_file ); - free( vertex_src ); - free( fragment_src ); - return 1; - } - else{ - vg_error( errstr, shader->vs.orig_file ); - free( vertex_src ); - free( fragment_src ); - return 0; - } - } - - vert = vg_shader_subshader( vertex_src, GL_VERTEX_SHADER ); - frag = vg_shader_subshader( fragment_src, GL_FRAGMENT_SHADER ); - - free( vertex_src ); - free( fragment_src ); - } - else{ - vert = vg_shader_subshader( shader->vs.static_src, GL_VERTEX_SHADER ); - frag = vg_shader_subshader( shader->fs.static_src, GL_FRAGMENT_SHADER ); - } - - if( !vert || !frag ) + if( success ) return 1; + else + { + if( critical ) vg_fatal_condition(); + + char info[ 512 ]; + glGetProgramInfoLog( program, sizeof(info), NULL, info ); + vg_info( "Shader program link error:\n\n%s\n", info ); + + if( critical ) vg_fatal_exit(); return 0; - - program = glCreateProgram(); + } +} + +/* + * Compile vg_shader from static source code. Will fatal exit if there is a + * compile error + */ +void vg_compile_shader( struct vg_shader *shader ) +{ + VG_ASSERT( shader->compiled == 0 ); + + const char *vs = shader->vs.static_src, + *fs = shader->fs.static_src; + + GLuint vert = vg_compile_opengl_subshader( GL_VERTEX_SHADER, vs, 1 ), + frag = vg_compile_opengl_subshader( GL_FRAGMENT_SHADER, fs, 1 ), + program = glCreateProgram(); glAttachShader( program, vert ); glAttachShader( program, frag ); - glLinkProgram( program ); + + vg_link_opengl_program( program, 1 ); glDeleteShader( vert ); glDeleteShader( frag ); - - /* Check for link errors */ - char infoLog[ 512 ]; - int success_link = 1; - - glGetProgramiv( program, GL_LINK_STATUS, &success_link ); - if( !success_link ) - { - glGetProgramInfoLog( program, 512, NULL, infoLog ); - vg_error( "Link failed: %s\n", infoLog ); - glDeleteProgram( program ); - return 0; - } - - if( shader->compiled ) - glDeleteProgram( shader->id ); - + shader->id = program; - shader->compiled = 1; - return 1; + shader->compiled = 1; +} + +/* + * Recompile vg_shader from its original source files. This won't work in the + * shipped version of the engine. + */ +void vg_recompile_shader( struct vg_shader *shader ) +{ + VG_ASSERT( shader->compiled == 1 ); + + char error[260]; + char path[260]; + + strcpy( path, "../../" ); + strcat( path, shader->vs.orig_file ); + char *vs = stb_include_file( path, "", "../../shaders", error ); + + strcpy( path, "../../" ); + strcat( path, shader->fs.orig_file ); + char *fs = stb_include_file( path, "", "../../shaders", error ); + + if( !vs || !fs ) + { + vg_warn( "Could not recompile shader due to missing source files:\n" ); + + if( !vs ) vg_info( " Vertex: %s\n", shader->vs.orig_file ); + if( !fs ) vg_info( " Fragment: %s\n", shader->fs.orig_file ); + free( vs ); + free( fs ); + return; + } + + GLuint vert = vg_compile_opengl_subshader( GL_VERTEX_SHADER, vs, 0 ), + frag = vg_compile_opengl_subshader( GL_FRAGMENT_SHADER, fs, 0 ); + + free( vs ); + free( fs ); + + if( !vert || !frag ) return; + + GLuint program = glCreateProgram(); + + glAttachShader( program, vert ); + glAttachShader( program, frag ); + + if( vg_link_opengl_program( program, 0 ) ) + { + /* replace existing */ + glDeleteProgram( shader->id ); + shader->id = program; + } + else + { + /* womp womp */ + glDeleteProgram( program ); + } + + glDeleteShader( vert ); + glDeleteShader( frag ); } void vg_free_shader( struct vg_shader *shader ) @@ -151,6 +185,7 @@ void vg_free_shader( struct vg_shader *shader ) if( shader->compiled ) { glDeleteProgram( shader->id ); + shader->id = 0; shader->compiled = 0; } } @@ -163,25 +198,21 @@ void vg_shaders_compile(void) { vg_info( "Compiling shaders\n" ); - for( int i=0; icompiled = 0; - shader->id = 0; /* TODO: make this an error shader */ + shader->id = 0; /* TODO: make this an error shader */ vg_shaders.shaders[ vg_shaders.count ++ ] = shader; } diff --git a/vg_shader.h b/vg_shader.h index 1ea106c..9fff67d 100644 --- a/vg_shader.h +++ b/vg_shader.h @@ -18,5 +18,6 @@ struct vg_shader void vg_shaders_compile(void); int vg_shaders_live_recompile(int argc, const char *argv[]); void vg_shader_register( struct vg_shader *shader ); -int vg_shader_compile( struct vg_shader *shader ); +void vg_compile_shader( struct vg_shader *shader ); +void vg_recompile_shader( struct vg_shader *shader ); void vg_free_shader( struct vg_shader *shader ); diff --git a/vg_steam.c b/vg_steam.c index a021cb1..3c51338 100644 --- a/vg_steam.c +++ b/vg_steam.c @@ -6,7 +6,8 @@ struct vg_steam vg_steam; vg_steam_async_call *vg_alloc_async_steam_api_call(void) { - if( vg_steam.call_count == vg_list_size(vg_steam.calls) ){ + if( vg_steam.call_count == VG_ARRAY_LEN(vg_steam.calls) ) + { vg_fatal_error( "Maximum concurrent API calls exceeded (%u)\n", vg_steam.call_count ); } @@ -17,7 +18,7 @@ vg_steam_async_call *vg_alloc_async_steam_api_call(void) void steam_register_callback( u32 id, void (*p_handler)( CallbackMsg_t *msg ) ) { if( vg_steam.callback_handler_count == - vg_list_size(vg_steam.callback_handlers) ) + VG_ARRAY_LEN(vg_steam.callback_handlers) ) { vg_fatal_error( "Too many steam callback handlers registered (%u)\n", vg_steam.callback_handler_count ); diff --git a/vg_string.c b/vg_string.c index 61df5fe..34b98f7 100644 --- a/vg_string.c +++ b/vg_string.c @@ -24,7 +24,7 @@ i32 vg_str_storage( vg_str *str ) */ void vg_strnull( vg_str *str, char *buffer, i32 len ) { - if( len == -1 ) vg_fatal_error( "waaaa" ); + VG_ASSERT( len >= 0 ); str->buffer = buffer; if( buffer ) @@ -204,7 +204,10 @@ u32 vg_strncpy( const char *src, char *dst, u32 len, } else if( behaviour == k_strncpy_overflow_fatal ) { - vg_fatal_error( "Strncpy dest exceeded buffer length\n" ); + vg_fatal_condition(); + vg_info( "vg_strncpy to buffer with maximum length '%u' exceeded" + " the end of the buffer.\n", len ); + vg_fatal_exit(); } } } @@ -215,7 +218,7 @@ u32 vg_strncpy( const char *src, char *dst, u32 len, static void _vg_strcatf_va( vg_str *str, const char *fmt, va_list args ) { char buffer[4096]; - vsnprintf( buffer, vg_list_size(buffer), fmt, args ); + vsnprintf( buffer, VG_ARRAY_LEN(buffer), fmt, args ); vg_strcat( str, buffer ); } diff --git a/vg_tex.c b/vg_tex.c index 8791dd8..17db5f2 100644 --- a/vg_tex.c +++ b/vg_tex.c @@ -83,9 +83,7 @@ struct texture_load_info{ static void async_vg_tex2d_upload( void *payload, u32 size ) { - if( vg_thread_purpose() != k_thread_purpose_main ){ - vg_fatal_error( "Catastrophic programming error.\n" ); - } + VG_ASSERT( vg_thread_purpose() == k_thread_purpose_main ); struct texture_load_info *info = payload; @@ -277,7 +275,7 @@ void vg_tex2d_load_qoi_async( const u8 *bytes, u32 size, void vg_tex2d_load_qoi_async_file( const char *path, u32 flags, GLuint *dest ) { if( vg_thread_purpose() != k_thread_purpose_loader ) - vg_fatal_error( "wrong thread\n" ); + vg_fatal_error( "Called aync texture load from wrong thread (main)\n" ); vg_linear_clear( vg_mem.scratch ); diff --git a/vg_tool.c b/vg_tool.c index 8ac0832..ce45fa3 100644 --- a/vg_tool.c +++ b/vg_tool.c @@ -9,11 +9,19 @@ #include "vg_mem_queue.c" #include "vg_io.c" +void vg_fatal_exit(void) +{ + exit(1); +} + void vg_fatal_error( const char *fmt, ... ) { + vg_fatal_condition(); + va_list args; va_start( args, fmt ); _vg_logx_va( stderr, NULL, "fatal", KRED, fmt, args ); va_end( args ); - exit(1); + + vg_fatal_exit(); } diff --git a/vg_tool.h b/vg_tool.h index aa7a850..0449370 100644 --- a/vg_tool.h +++ b/vg_tool.h @@ -1,3 +1,2 @@ #pragma once #include "vg_log.h" -void vg_fatal_error( const char *fmt, ... ); diff --git a/vg_ui/imgui.c b/vg_ui/imgui.c index 30ccef2..0b63730 100644 --- a/vg_ui/imgui.c +++ b/vg_ui/imgui.c @@ -59,7 +59,7 @@ ui_vert *ui_fill_rect( ui_context *ctx, ui_rect rect, u32 colour, ui_px uv[4] ) u16 start = ctx->cur_vert; u32 mesh[] = { 0,2,1, 0,3,2 }; - for( u32 i=0; icur_indice += 6; @@ -115,7 +115,7 @@ void ui_outline( ui_context *ctx, mask = UI_TOP|UI_LEFT|UI_BOTTOM|UI_RIGHT; u32 c = 0; - for( u32 i=0; iarea[0]-256,0,256,ctx->area[1]}, swatch; - const char *names[vg_list_size(ctx->scheme)] = { + const char *names[VG_ARRAY_LEN(ctx->scheme)] = { [k_ui_bg] = "k_ui_bg", "k_ui_bg+1", "k_ui_bg+2", "k_ui_bg+3", "k_ui_bg+4", "k_ui_bg+5", "k_ui_bg+6", "k_ui_bg+7", @@ -1947,7 +1947,7 @@ void ui_dev_colourview( ui_context *ctx ) ui_rect col[2]; ui_split_ratio( window, k_ui_axis_v, 0.5f, 0, col[0], col[1] ); - for( int i=0; ischeme); i++ ) + for( int i=0; ischeme); i++ ) { int which = (i/8)%2; diff --git a/vg_ui/imgui_impl_opengl.c b/vg_ui/imgui_impl_opengl.c index 236789d..9c4dc32 100644 --- a/vg_ui/imgui_impl_opengl.c +++ b/vg_ui/imgui_impl_opengl.c @@ -331,7 +331,11 @@ void ui_impl_render_batch( ui_context *ctx, ui_batch *batch, glUniform1f( glGetUniformLocation(_shader_ui_hsv.id,"uHue"), inf->hue ); } else - vg_fatal_error( "Invalid UI shader (%d)\n", shader ); + { + vg_fatal_condition(); + vg_info( "Invalid UI shader (%d)\n", shader ); + vg_fatal_exit(); + } glDrawElements( GL_TRIANGLES, batch->indice_count, GL_UNSIGNED_SHORT, (void *)((size_t)batch->indice_offset) ); @@ -411,7 +415,7 @@ void vg_ui_handle_sdl_key( ui_context *ctx, SDL_Keysym ev ) if( ev.mod & KMOD_ALT ) mod |= KMOD_ALT; - for( int i=0; iw, sheet->h, 0, GL_RED, GL_UNSIGNED_BYTE, image ); - VG_CHECK_GL_ERR(); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE ); glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); -- 2.25.1 From d0f65909290fd4981f2d0b6ad3389daf88777ac5 Mon Sep 17 00:00:00 2001 From: hgn Date: Fri, 6 Sep 2024 04:29:38 +0100 Subject: [PATCH 07/16] clean logger function --- vg_console.c | 1 - vg_engine.c | 6 ++--- vg_log.c | 73 +++++++++++++++++++++++++--------------------------- vg_log.h | 2 +- 4 files changed, 39 insertions(+), 43 deletions(-) diff --git a/vg_console.c b/vg_console.c index 00d8e5f..b1f320a 100644 --- a/vg_console.c +++ b/vg_console.c @@ -676,7 +676,6 @@ void vg_console_draw( ui_context *ctx ) /* * Input area */ - struct ui_textbox_callbacks callbacks = { .up = _vg_console_on_up, diff --git a/vg_engine.c b/vg_engine.c index 2470b49..37293b0 100644 --- a/vg_engine.c +++ b/vg_engine.c @@ -439,7 +439,7 @@ static void _vg_crashscreen(void) glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA); glBlendEquation(GL_FUNC_ADD); - glClearColor( 0.15f + sinf(vg.time_real)*0.1f, 0.0f, 0.0f,1.0f ); + glClearColor( 0.15f,0.0f,0.0f,1.0f ); glClear( GL_COLOR_BUFFER_BIT ); glViewport( 0,0, vg.window_x, vg.window_y ); @@ -786,10 +786,10 @@ void vg_fatal_exit(void) if( strings != NULL ) { - vg_info( "\n\n---------------- gnu backtrace -------------\n" ); + vg_error( "\n---------------- gnu backtrace -------------\n" ); for( int i=0; i= 90 ) + { + line[ line_length ++ ] = '\n'; + line[ line_length ] = '\0'; + flush = 1; + marker = '.'; + } - snprintf( logline, 96, "%s%7s" KNRM "|%s %s", - colour, line_prefix, colour, line ); - _vg_log_append_line( logline ); + if( c == '\n' ) + { + line[ line_length ] = '\0'; + flush = 1; + } - if( location ){ + if( flush || c == '\0' ) + { + if( location ) + { #ifdef VG_ENGINE - const char *thread_colours[] = { - KGRN, KMAG, KCYN, KYEL, KBLU - }; - + const char *thread_colours[] = { KGRN, KMAG, KCYN, KYEL, KBLU }; const char *colour = thread_colours[ (vg_thread_purpose() % VG_ARRAY_LEN( thread_colours ))]; - fprintf( file, "%s[%u]"KNRM"%.32s", - colour, vg_thread_purpose(), line_location ); + fprintf( file, "%s%u|"KNRM"%.32s", + colour, vg_thread_purpose(), location ); #else - fprintf( file, KNRM "%.32s", line_location ); + fprintf( file, KNRM "%.32s", location ); #endif } - fputs( logline, file ); - fputc( '\n', file ); - fputs( KNRM, file ); - - if( c == '\0' ) break; - if( buffer[i+1] == '\0' ) break; - line = buffer+i+1; + _vg_log_append_line( line ); + fputs( line, file ); + line_length = snprintf( line, 90, "%s " KNRM "%c%s ", + colour, marker, colour ); } + + if( c == '\0' ) break; + if( buffer[i+1] == '\0' ) break; } #ifdef VG_ENGINE diff --git a/vg_log.h b/vg_log.h index 89b86dc..ebfa59d 100644 --- a/vg_log.h +++ b/vg_log.h @@ -5,7 +5,7 @@ #define VG_LOG_MCSTR(S) VG_LOG_MCSTR2(S) #define VG_LOG_MCSTR2(S) #S -#define VG_LOG_WHERE "@" __FILE__ ":" VG_LOG_MCSTR(__LINE__)\ +#define VG_LOG_WHERE __FILE__ ":" VG_LOG_MCSTR(__LINE__)\ " " #define vg_success( ... ) \ -- 2.25.1 From 5095d97989f2e37258b2dd72e9ad3f2a38b03e58 Mon Sep 17 00:00:00 2001 From: hgn Date: Tue, 10 Sep 2024 12:01:42 +0100 Subject: [PATCH 08/16] up max allocations --- vg_mem.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vg_mem.h b/vg_mem.h index 6fde883..94042a9 100644 --- a/vg_mem.h +++ b/vg_mem.h @@ -1,6 +1,6 @@ #pragma once -#define VG_MAX_ALLOCATIONS 128 +#define VG_MAX_ALLOCATIONS 256 typedef struct vg_linear_allocator vg_linear_allocator; typedef struct vg_allocation_meta vg_allocation_meta; -- 2.25.1 From 9f68c9a8d889b9fa51a4cb1cca345831e95b4bf9 Mon Sep 17 00:00:00 2001 From: hgn Date: Wed, 25 Sep 2024 12:28:52 +0100 Subject: [PATCH 09/16] add basic memory viewer --- vg_engine.c | 13 +++- vg_mem.c | 22 +++++- vg_mem_view.c | 196 ++++++++++++++++++++++++++++++++++++++++++++++++++ vg_mem_view.h | 5 ++ 4 files changed, 232 insertions(+), 4 deletions(-) create mode 100644 vg_mem_view.c create mode 100644 vg_mem_view.h diff --git a/vg_engine.c b/vg_engine.c index 37293b0..db025c8 100644 --- a/vg_engine.c +++ b/vg_engine.c @@ -50,6 +50,7 @@ static void _vg_opengl_sync_init(void) #include "vg_console.h" #include "vg_profiler.h" +#include "vg_mem_view.h" #ifndef VG_NO_AUDIO #include "vg_audio.h" #endif @@ -128,6 +129,7 @@ vg_info(" ' ' '--' [] '----- '----- ' ' '---' " vg_loader_step( vg_audio_init, vg_audio_free ); #endif vg_loader_step( vg_profiler_init, NULL ); + vg_loader_step( vg_mem_view_init, NULL ); /* client */ #ifdef VG_CUSTOM_SHADERS @@ -314,7 +316,7 @@ static void _vg_gameloop_render(void) audio_debug_ui( &vg_ui.ctx, vg.pv ); #endif - /* profiling */ + /* profiling TODO MOVE TO OWN FILE */ if( vg_profiler ){ int frame_target = vg.display_refresh_rate; if( vg.fps_limit > 0 ) frame_target = vg.fps_limit; @@ -346,6 +348,14 @@ static void _vg_gameloop_render(void) ui_text( &vg_ui.ctx, (ui_rect){258,4,900,900},perf,1,0,k_ui_align_left); } + + if( vg_mem_view && vg_loader_availible() ) + { + vg_mem_view_ui( &vg_ui.ctx, (ui_rect){400,32, + vg.window_x-400,vg.window_y-64}, + vg_mem.rtmemory, 0, "rtmemory" ); + } + ui_postrender( &vg_ui.ctx, vg.time_frame_delta ); vg_ui_post_update(); } @@ -1336,6 +1346,7 @@ __attribute__((used)) int AmdPowerXpressRequestHighPerformance = 1; #include "vg_framebuffer.c" #include "vg_render.c" #include "vg_opengl.c" +#include "vg_mem_view.c" #ifdef VG_CUSTOM_SHADERS #include "shaders/impl.c" diff --git a/vg_mem.c b/vg_mem.c index 1b55b09..0e07918 100644 --- a/vg_mem.c +++ b/vg_mem.c @@ -126,6 +126,22 @@ void *vg_linear_resize( void *buffer, void *data, u32 newsize ) else return data; } +void vg_libc_del_recursive( void *buffer ) +{ + vg_linear_allocator *alloc = vg_linear_header( buffer ); + for( u32 i=0; iallocation_count; i ++ ) + { + vg_allocation_meta *meta = &alloc->alloc_table[i]; + if( meta->type == k_allocation_type_linear ) + vg_libc_del_recursive( meta->data ); + else + free( meta->data ); + } + + free( alloc->alloc_table ); + free( alloc ); +} + /* its possible to delete just the last item */ void vg_linear_del( void *buffer, void *data ) { @@ -139,9 +155,9 @@ void vg_linear_del( void *buffer, void *data ) { vg_allocation_meta *meta = &alloc->alloc_table[alloc->allocation_count-1]; if( meta->type == k_allocation_type_linear ) - vg_fatal_error( "Cannot free a linear allocator in this conext" ); - - free( data ); + vg_libc_del_recursive( meta->data ); + else + free( data ); } alloc->allocation_count --; diff --git a/vg_mem_view.c b/vg_mem_view.c new file mode 100644 index 0000000..92af16d --- /dev/null +++ b/vg_mem_view.c @@ -0,0 +1,196 @@ +#include "vg_ui/imgui.h" + +int vg_mem_view = 0; + +void squarey_layout( ui_rect rect, f32 *areas, u32 area_count, + void (*cb)( u32, ui_rect, void* ), void *cb_user ) +{ + f32 area_total = 0.0f; + for( u32 i=0; iindices[idx]; + vg_allocation_meta *meta = &inf->alloc->alloc_table[idx]; + + if( meta->type == k_allocation_type_block ) + { + ui_fill( inf->ui_ctx, tmp, 0x80000000 | (~0xff000000&(idx*0x45d9f3b)) ); + + if( tmp[2] > 20 && tmp[3] > 16 ) + ui_text( inf->ui_ctx, tmp, meta->name, 1, k_ui_align_left, 0 ); + } + else + { + vg_mem_view_ui( inf->ui_ctx, tmp, meta->data, 0, meta->name ); + } + + return; + + + char buf[32]; + vg_mem_print_size( meta->size, buf ); + ui_text( inf->ui_ctx, tmp, buf, 1, k_ui_align_middle_center, 0 ); +} + +vg_linear_allocator *_CB_values; +int _CB_vg_mem_sort( const void *a, const void *b ) +{ + i32 ia = *((const i32 *)a), ib = *((const i32 *)b); + f32 fa = _CB_values->alloc_table[ ia ].size, + fb = _CB_values->alloc_table[ ib ].size; + return (fa < fb) - (fa > fb); +} + +void vg_mem_view_ui( ui_context *ctx, ui_rect rect, + void *lin_alloc, int depth, const char *name ) +{ + f32 sizes[ VG_MAX_ALLOCATIONS ]; + i32 indices[ VG_MAX_ALLOCATIONS ]; + + if( vg_mem.use_libc_malloc ) + { + vg_linear_allocator *alloc = vg_linear_header( lin_alloc ); + struct vg_mem_draw_inf inf = + { + .ui_ctx = ctx, + .alloc = alloc, + .indices = indices, + }; + + if( alloc->allocation_count ) + { + if( alloc->cur < alloc->size ) + { + u32 short_side = rect[3] < rect[2]? 1: 0; + f32 p = 1.0f-((f32)alloc->cur / (f32)alloc->size); + ui_px h = (f32)rect[2+short_side^0x1] * p*p; + ui_rect out_box = {rect[0], rect[1]}; + out_box[ 2+short_side^0x1 ] = h; + out_box[ 2+short_side ] = rect[ 2+short_side ]; + + ui_fill( ctx, out_box, 0x80303030 ); + + rect[ short_side^0x1 ] += h; + rect[ 2+short_side^0x1 ] -= h; + } + + if( alloc->flags & VG_MEMORY_SYSTEM ) + { + for( i32 i=0; iallocation_count; i ++ ) + indices[i] = i; + + u32 count = alloc->allocation_count; + _CB_values = alloc; + qsort( indices, count, sizeof(i32), _CB_vg_mem_sort ); + + for( u32 i=0; iallocation_count; i++ ) + { + i32 indice = indices[i]; + + vg_allocation_meta *meta = &alloc->alloc_table[indice]; + sizes[i] = sqrtf(meta->size); + } + + squarey_layout( rect, sizes, count, vg_mem_draw_cb, &inf ); + } + else + { + //printf( " (UNTRACKED)\n" ); + } + } + else + { + ui_fill( ctx, rect, 0x80101010 ); + ui_text( ctx, rect, name, 1, k_ui_align_left, 0 ); + } + } + else + { + //vg_error( "allocations are not tracked (turn on libc mode)\n" ); + } +} + +void vg_mem_view_init(void) +{ + VG_VAR_I32( vg_mem_view, flags=VG_VAR_PERSISTENT ); +} diff --git a/vg_mem_view.h b/vg_mem_view.h new file mode 100644 index 0000000..8792257 --- /dev/null +++ b/vg_mem_view.h @@ -0,0 +1,5 @@ +#pragma once +#include "vg_ui/imgui.h" +extern int vg_mem_view; +void vg_mem_view_init(void); +void vg_mem_view_ui( ui_context *ctx, ui_rect rect, void *lin_alloc, int depth, const char *name ); -- 2.25.1 From dc86dfa60b77884d157313f3be097dbe4db47d11 Mon Sep 17 00:00:00 2001 From: hgn Date: Thu, 26 Sep 2024 00:28:52 +0100 Subject: [PATCH 10/16] magi&memory view --- vg_console.c | 10 +- vg_console.h | 1 + vg_engine.c | 14 ++- vg_magi.c | 190 +++++++++++++++++++++++++++++ vg_magi.h | 44 +++++++ vg_mem_view.c | 243 +++++++++++++++++++++++++++++++++++--- vg_mem_view.h | 1 - vg_ui/imgui.c | 13 +- vg_ui/imgui.h | 12 +- vg_ui/imgui_impl_opengl.c | 106 ++++++++++------- 10 files changed, 550 insertions(+), 84 deletions(-) create mode 100644 vg_magi.c create mode 100644 vg_magi.h diff --git a/vg_console.c b/vg_console.c index b1f320a..a57c1a2 100644 --- a/vg_console.c +++ b/vg_console.c @@ -584,6 +584,8 @@ static void _vg_console_on_enter( ui_context *ctx, char *buf, u32 len ) vg_console.input[0] = '\0'; console_update_suggestions( ctx ); } + + vg_console.auto_focus = 1; } int vg_console_exec( int argc, const char *argv[] ) @@ -608,6 +610,7 @@ int vg_console_exec( int argc, const char *argv[] ) if( line[0] != 0x00 ) { + strcpy( vg_console.input, line ); vg_execute_console_input( line, silent ); } } @@ -619,6 +622,7 @@ int vg_console_exec( int argc, const char *argv[] ) vg_error( "Could not open '%s'\n", path ); } + vg_console.input[0] = '\0'; return 0; } @@ -683,9 +687,13 @@ void vg_console_draw( ui_context *ctx ) .change = _vg_console_on_update, .enter = _vg_console_on_enter, }; + + u32 flags = 0; + if( vg_console.auto_focus ) flags |= UI_TEXTBOX_AUTOFOCUS; ui_textbox( ctx, rect_input, NULL, vg_console.input, VG_ARRAY_LEN(vg_console.input), 1, - UI_TEXTBOX_AUTOFOCUS, &callbacks ); + flags, &callbacks ); + vg_console.auto_focus = 0; /* * suggestions diff --git a/vg_console.h b/vg_console.h index 27c11b8..046b811 100644 --- a/vg_console.h +++ b/vg_console.h @@ -62,6 +62,7 @@ struct vg_console int history_last, history_pos, history_count; i32 enabled, cheats; + bool auto_focus; } extern vg_console; diff --git a/vg_engine.c b/vg_engine.c index db025c8..9b0c1bf 100644 --- a/vg_engine.c +++ b/vg_engine.c @@ -50,6 +50,7 @@ static void _vg_opengl_sync_init(void) #include "vg_console.h" #include "vg_profiler.h" +#include "vg_magi.h" #include "vg_mem_view.h" #ifndef VG_NO_AUDIO #include "vg_audio.h" @@ -86,18 +87,16 @@ void async_internal_complete( void *payload, u32 size ) vg_success( "Internal async setup complete\n" ); SDL_AtomicLock( &vg.sl_status ); - if( vg.engine_status == k_engine_status_crashed ) { SDL_AtomicUnlock( &vg.sl_status ); return; } else - { vg.engine_status = k_engine_status_running; - } - SDL_AtomicUnlock( &vg.sl_status ); + + vg_magi_restore(); } #ifdef VG_CUSTOM_SHADERS @@ -181,6 +180,7 @@ static void _vg_process_events(void) { if( event.key.keysym.scancode == SDL_SCANCODE_GRAVE ) { + vg_console.auto_focus = 1; vg_console.enabled = 1; } else @@ -349,12 +349,15 @@ static void _vg_gameloop_render(void) (ui_rect){258,4,900,900},perf,1,0,k_ui_align_left); } +#if 0 if( vg_mem_view && vg_loader_availible() ) { vg_mem_view_ui( &vg_ui.ctx, (ui_rect){400,32, vg.window_x-400,vg.window_y-64}, vg_mem.rtmemory, 0, "rtmemory" ); } +#endif + _vg_magi_render( &vg_ui.ctx ); ui_postrender( &vg_ui.ctx, vg.time_frame_delta ); vg_ui_post_update(); @@ -715,6 +718,7 @@ static void _vg_init_window( const char *window_name ) static void _vg_terminate(void) { /* Shutdown */ + vg_magi_save(); vg_console_write_persistent(); SDL_AtomicLock( &vg.sl_status ); @@ -745,6 +749,7 @@ void vg_enter( int argc, char *argv[], const char *window_name ) /* Systems init */ vg_alloc_quota(); vg_console_init(); + vg_magi_init(); vg_console_reg_var( "vg_fps_limit", &vg.fps_limit, k_var_dtype_i32, VG_VAR_PERSISTENT ); @@ -1338,6 +1343,7 @@ __attribute__((used)) int AmdPowerXpressRequestHighPerformance = 1; #include "vg_perlin.c" #include "vg_string.c" #include "vg_profiler.c" +#include "vg_magi.c" #include "vg_rigidbody_collision.c" #include "vg_rigidbody_constraints.c" #include "vg_rigidbody.c" diff --git a/vg_magi.c b/vg_magi.c new file mode 100644 index 0000000..b068ee5 --- /dev/null +++ b/vg_magi.c @@ -0,0 +1,190 @@ +#include "vg_magi.h" +#include "vg_console.h" + +struct vg_magi _vg_magi; + +struct vg_magi_panel *_vg_magi_open( ui_px w, ui_px h, u32 flags ) +{ + VG_ASSERT( _vg_magi.panel_count < VG_MAGI_MAX_PANELS ); + struct vg_magi_panel *panel = &_vg_magi.panels[ _vg_magi.panel_count ++ ]; + panel->rect[0] = 32; + panel->rect[1] = 32; + panel->rect[2] = w; + panel->rect[3] = h; + panel->title = ""; + panel->data = NULL; + panel->minimized = 0; + panel->flags = flags; + panel->ui_cb = NULL; + panel->close_cb = NULL; + + if( flags & VG_MAGI_PERSISTENT ) + strcpy( panel->cmd, vg_console.input ); + + return panel; +} + +void _vg_magi_render( ui_context *ctx ) +{ + if( _vg_magi.panel_count == 0 ) return; + + u32 highlight = 0xffffffff, + top = _vg_magi.panel_count-1; + + if( _vg_magi.mode == k_magi_mode_none ) + { + for( u32 i=0; i<_vg_magi.panel_count; i ++ ) + { + struct vg_magi_panel *panel = &_vg_magi.panels[ i ]; + if( ui_inside_rect( panel->rect, ctx->mouse ) ) + highlight = i; + } + + /* bring to top */ + if( (highlight < top) && ui_click_down( ctx, UI_MOUSE_ANY ) ) + { + struct vg_magi_panel temp = _vg_magi.panels[ highlight ]; + + for( i32 i=0, j=0; i<_vg_magi.panel_count; i ++ ) + if( i != highlight ) + _vg_magi.panels[ j ++ ] = _vg_magi.panels[ i ]; + + _vg_magi.panels[ top ] = temp; + highlight = top; + } + } + else + { + highlight = top; + struct vg_magi_panel *ptop = &_vg_magi.panels[ top ]; + + if( _vg_magi.mode == k_magi_mode_drag ) + { + ptop->rect[0] = _vg_magi.drag_original[0] + ctx->mouse_delta[0]; + ptop->rect[1] = _vg_magi.drag_original[1] + ctx->mouse_delta[1]; + } + else if( _vg_magi.mode == k_magi_mode_resize ) + { + ptop->rect[2] = _vg_magi.drag_original[2] + ctx->mouse_delta[0]; + ptop->rect[3] = _vg_magi.drag_original[3] + ctx->mouse_delta[1]; + + if( ptop->rect[2] < ptop->min_w ) ptop->rect[2] = ptop->min_w; + if( ptop->rect[3] < ptop->min_h ) ptop->rect[3] = ptop->min_h; + } + + if( ui_click_up( ctx, UI_MOUSE_ANY ) ) + _vg_magi.mode = k_magi_mode_none; + } + + for( i32 i=0; i<_vg_magi.panel_count; i ++ ) + { + struct vg_magi_panel *panel = &_vg_magi.panels[ i ]; + + ui_rect title, rect; + ui_split( panel->rect, k_ui_axis_h, 28, 0, title, rect ); + ui_fill( ctx, title, ui_opacity( ui_colour( ctx, k_ui_bg+7 ), 0.9f ) ); + + if( panel->flags & VG_MAGI_PERSISTENT ) + { + ui_text( ctx, title, panel->cmd, 1, k_ui_align_middle_center, + ui_colourcont( ctx, k_ui_bg+7 ) ); + } + else + { + ui_text( ctx, title, panel->title, 1, k_ui_align_middle_center, + ui_colourcont( ctx, k_ui_bg+7 ) ); + } + + ui_fill( ctx, rect, ui_opacity( ui_colour( ctx, k_ui_bg+1 ), 0.7f ) ); + + if( i == highlight ) + { + /* TODO: enable interaction */ + + if( ui_click_down( ctx, UI_MOUSE_MIDDLE ) ) + { + if( panel->flags & VG_MAGI_MOVEABLE ) + { + _vg_magi.mode = k_magi_mode_drag; + rect_copy( panel->rect, _vg_magi.drag_original ); + } + } + else if( ui_click_down( ctx, UI_MOUSE_RIGHT ) ) + { + if( panel->flags & VG_MAGI_RESIZEABLE ) + { + _vg_magi.mode = k_magi_mode_resize; + rect_copy( panel->rect, _vg_magi.drag_original ); + } + } + + ui_outline( ctx, panel->rect, 1, ui_colour( ctx, k_ui_bg+7 ), 0 ); + } + else + { + /* TODO: disable interaction */ + } + + panel->ui_cb( ctx, rect, panel ); + } +} + +void vg_magi_restore(void) +{ + vg_console_exec( 2, (const char *[]){ "magi.conf", "silent" } ); +} + +void vg_magi_save(void) +{ + FILE *fp = fopen( "cfg/magi.conf", "w" ); + + if( !fp ) + { + vg_error( "Cannot open cfg/magi.conf\n" ); + return; + } + + for( u32 i=0; i<_vg_magi.panel_count; i ++ ) + { + struct vg_magi_panel *magi = &_vg_magi.panels[i]; + + if( magi->flags & VG_MAGI_PERSISTENT ) + { + fprintf( fp, "%s\n", magi->cmd ); + fprintf( fp, "magi_pos %d %d %d %d\n", + magi->rect[0], magi->rect[1], magi->rect[2], magi->rect[3] ); + } + } + + fclose( fp ); +} + +static int cmd_vg_magi_dim( int argc, const char *argv[] ) +{ + if( !_vg_magi.panel_count ) + { + vg_error( "No active panels to apply that to.\n" ); + return 0; + } + + if( argc == 0 ) + { + vg_error( "Usage: magi_pos x y w h\n" ); + return 0; + } + + struct vg_magi_panel *magi = &_vg_magi.panels[ _vg_magi.panel_count-1 ]; + for( int i=0; i<4; i ++ ) + { + if( argc >= i+1 ) + magi->rect[i] = atoi( argv[i] ); + else break; + } + + return 1; +} + +void vg_magi_init(void) +{ + vg_console_reg_cmd( "magi_pos", cmd_vg_magi_dim, NULL ); +} diff --git a/vg_magi.h b/vg_magi.h new file mode 100644 index 0000000..34c5f4a --- /dev/null +++ b/vg_magi.h @@ -0,0 +1,44 @@ +#pragma once +#define VG_MAGI_MAX_PANELS 8 + +#define VG_MAGI_RESIZEABLE 0x1 +#define VG_MAGI_MOVEABLE 0x2 +#define VG_MAGI_PERSISTENT 0x4 +#define VG_MAGI_ALL (VG_MAGI_RESIZEABLE|VG_MAGI_MOVEABLE|VG_MAGI_PERSISTENT) + +struct vg_magi +{ + struct vg_magi_panel + { + bool minimized; + const char *title; + ui_rect rect; + u32 flags; + void *data; + + char cmd[96]; /* used for persistence */ + ui_px min_w, min_h; + + void(*ui_cb)( ui_context *ctx, ui_rect rect, struct vg_magi_panel *magi ); + void(*close_cb)( struct vg_magi_panel *me ); + } + panels[ VG_MAGI_MAX_PANELS ]; + u32 panel_count; + + enum magi_mode + { + k_magi_mode_none, + k_magi_mode_drag, + k_magi_mode_resize + } + mode; + ui_rect drag_original; + ui_px drag_start[2]; +} +extern _vg_magi; + +struct vg_magi_panel *_vg_magi_open( ui_px w, ui_px h, u32 flags ); +void _vg_magi_render( ui_context *ctx ); +void vg_magi_init(void); +void vg_magi_save(void); +void vg_magi_restore(void); diff --git a/vg_mem_view.c b/vg_mem_view.c index 92af16d..d326b5d 100644 --- a/vg_mem_view.c +++ b/vg_mem_view.c @@ -71,15 +71,26 @@ L_LOOP: goto L_LOOP_ADJUST; } +struct vg_mem_view_result +{ + vg_allocation_meta *target; + ui_rect target_rect; + u32 colour; +}; + struct vg_mem_draw_inf { ui_context *ui_ctx; vg_linear_allocator *alloc; i32 *indices; + u32 root_colour; + + struct vg_mem_view_result *result; }; -void vg_mem_view_ui( ui_context *ctx, ui_rect rect, - void *lin_alloc, int depth, const char *name ); +static void vg_mem_view_ui( ui_context *ctx, ui_rect rect, + void *lin_alloc, const char *name, u32 root_colour, + struct vg_mem_view_result *result ); static void vg_mem_draw_cb( u32 idx, ui_rect rect, void *user ) { @@ -92,24 +103,27 @@ static void vg_mem_draw_cb( u32 idx, ui_rect rect, void *user ) idx = inf->indices[idx]; vg_allocation_meta *meta = &inf->alloc->alloc_table[idx]; + u32 colour; + if( inf->root_colour ) colour = inf->root_colour; + else colour = ~0xff000000&((idx+5)*0x45d9f3b); + if( meta->type == k_allocation_type_block ) { - ui_fill( inf->ui_ctx, tmp, 0x80000000 | (~0xff000000&(idx*0x45d9f3b)) ); - - if( tmp[2] > 20 && tmp[3] > 16 ) - ui_text( inf->ui_ctx, tmp, meta->name, 1, k_ui_align_left, 0 ); + ui_fill( inf->ui_ctx, tmp, 0x80000000 | colour ); + ui_outline( inf->ui_ctx, tmp, -1, 0xff000000 | colour, 0 ); } else + vg_mem_view_ui( inf->ui_ctx, tmp, meta->data, meta->name, colour, NULL ); + + if( inf->result ) { - vg_mem_view_ui( inf->ui_ctx, tmp, meta->data, 0, meta->name ); + if( ui_inside_rect( rect, inf->ui_ctx->mouse ) ) + { + inf->result->target = meta; + inf->result->colour = colour; + rect_copy( rect, inf->result->target_rect ); + } } - - return; - - - char buf[32]; - vg_mem_print_size( meta->size, buf ); - ui_text( inf->ui_ctx, tmp, buf, 1, k_ui_align_middle_center, 0 ); } vg_linear_allocator *_CB_values; @@ -121,8 +135,9 @@ int _CB_vg_mem_sort( const void *a, const void *b ) return (fa < fb) - (fa > fb); } -void vg_mem_view_ui( ui_context *ctx, ui_rect rect, - void *lin_alloc, int depth, const char *name ) +static void vg_mem_view_ui( ui_context *ctx, ui_rect rect, + void *lin_alloc, const char *name, u32 root_colour, + struct vg_mem_view_result *result ) { f32 sizes[ VG_MAX_ALLOCATIONS ]; i32 indices[ VG_MAX_ALLOCATIONS ]; @@ -135,6 +150,8 @@ void vg_mem_view_ui( ui_context *ctx, ui_rect rect, .ui_ctx = ctx, .alloc = alloc, .indices = indices, + .result = result, + .root_colour = root_colour }; if( alloc->allocation_count ) @@ -148,7 +165,11 @@ void vg_mem_view_ui( ui_context *ctx, ui_rect rect, out_box[ 2+short_side^0x1 ] = h; out_box[ 2+short_side ] = rect[ 2+short_side ]; - ui_fill( ctx, out_box, 0x80303030 ); + ui_fill( ctx, out_box, 0x80000000 ); + + char asize[32]; + vg_mem_print_size( alloc->size-alloc->cur, asize ); + ui_text( ctx, out_box, asize, 1, k_ui_align_middle_center, 0 ); rect[ short_side^0x1 ] += h; rect[ 2+short_side^0x1 ] -= h; @@ -181,7 +202,7 @@ void vg_mem_view_ui( ui_context *ctx, ui_rect rect, else { ui_fill( ctx, rect, 0x80101010 ); - ui_text( ctx, rect, name, 1, k_ui_align_left, 0 ); + //ui_text( ctx, rect, name, 1, k_ui_align_left, 0 ); } } else @@ -190,7 +211,191 @@ void vg_mem_view_ui( ui_context *ctx, ui_rect rect, } } +static struct +{ + const char *name; + void **buffer; +} +_vg_mem_named_buffers[] = +{ + { "rtmemory", &vg_mem.rtmemory }, + { "scratch", &vg_mem.scratch } +}; + +struct mem_view_data +{ + void *main_buffer[8], + *inspecting; + v4f inspect_colour; + + const char *walk[8]; + + u32 depth; + + f32 vis_data[256*256]; + GLuint tex; +}; + +static void cb_vg_mem_view( ui_context *ctx, ui_rect rect, + struct vg_magi_panel *magi ) +{ + struct mem_view_data *mv = magi->data; + struct vg_mem_view_result result = { .target=NULL }; + + ui_rect left; + ui_split( rect, k_ui_axis_v, 256+16, 2, left, rect ); + ui_fill( ctx, left, ui_opacity( ui_colour( ctx,k_ui_bg+1 ), 0.8f ) ); + + for( u32 i=0; idepth+1; i ++ ) + ui_info( ctx, left, mv->walk[ i ] ); + + if( mv->depth ) + if( ui_button( ctx, left, "up" ) == 1 ) + mv->depth --; + + vg_mem_view_ui( ctx, rect, mv->main_buffer[ mv->depth ], "", 0, &result ); + + if( result.target ) + { + ui_outline( ctx, result.target_rect, 1, ui_colour( ctx,k_ui_bg+7 ), 0 ); + ui_info( ctx, left, result.target->name ); + + char buf[32]; + vg_mem_print_size( result.target->size, buf ); + ui_info( ctx, left, buf ); + + if( mv->inspecting != result.target->data ) + { + if( result.target->type == k_allocation_type_block ) + { + for( u32 i=0; i<256*256; i++ ) mv->vis_data[i] = 0.0f; + f32 max_freq = 0.0f; + + const u8 *src = result.target->data; + for( u32 i=0; isize-1; i ++ ) + { + u8 x = src[i], y = src[i+1]; + u32 offset = y*256 + x; + + mv->vis_data[ offset ] += 1.0f; + max_freq = vg_maxf( mv->vis_data[ offset ], max_freq ); + } + + f32 median = 0.0f; + for( u32 i=0; i<256*256; i++ ) median += mv->vis_data[i]; + median /= 256.0f*256.0f; + + f32 inv_max = 1.0f/logf(1.0f+median*2.0f); + for( u32 i=0; i<256*256; i++ ) + { + f32 v = logf(mv->vis_data[i]) * inv_max; + mv->vis_data[i] = v; + } + + glBindTexture( GL_TEXTURE_2D, mv->tex ); + glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 256, 256, + GL_RED, GL_FLOAT, mv->vis_data ); + } + + mv->inspecting = result.target->data; + + f32 nrm = 1.6f / 255.0f; + mv->inspect_colour[0] = (f32)((result.colour ) & 0xff) * nrm; + mv->inspect_colour[1] = (f32)((result.colour>>8 ) & 0xff) * nrm; + mv->inspect_colour[2] = (f32)((result.colour>>16) & 0xff) * nrm; + mv->inspect_colour[3] = 1.0f; + } + + if( result.target->type == k_allocation_type_block ) + ui_info( ctx, left, "Leaf" ); + else + ui_info( ctx, left, "Linear Allocator (expand)" ); + + if( result.target->type == k_allocation_type_block ) + { + ui_rect freq_box = { left[0]+8, left[1], 256,256 }; + + ui_flush( ctx, k_ui_shader_colour, NULL ); + ui_fill_rect( ctx, freq_box, 0xffffffff, (ui_px[4]){ 0,256,256,0 } ); + struct ui_batch_shader_data_image inf = { .resource = &mv->tex }; + v4_copy( mv->inspect_colour, vg_ui.colour ); + ui_flush( ctx, k_ui_shader_grad, &inf ); + v4_copy( (v4f){1,1,1,1}, vg_ui.colour ); + } + + if( result.target->type == k_allocation_type_linear ) + { + if( ui_click_down( ctx, UI_MOUSE_LEFT ) ) + { + mv->main_buffer[ mv->depth+1 ] = result.target->data; + mv->walk[ mv->depth+1 ] = result.target->name; + mv->inspecting = NULL; + mv->depth ++; + } + } + } +} + +static void cb_mem_view_close( struct vg_magi_panel *me ) +{ + struct mem_view_data *mv = me->data; + glDeleteTextures( 1, &mv->tex ); + free( me->data ); +} + +static int cmd_vg_mem_view( int argc, const char *argv[] ) +{ + if( argc == 1 ) + { + for( u32 i=0; ititle = "Memory outliner"; + + struct mem_view_data *mv = malloc(sizeof(struct mem_view_data)); + mv->main_buffer[0] = *_vg_mem_named_buffers[i].buffer; + mv->walk[0] = _vg_mem_named_buffers[i].name; + mv->depth = 0; + mv->inspecting = NULL; + + glGenTextures( 1, &mv->tex ); + glBindTexture( GL_TEXTURE_2D, mv->tex ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_R32F, 256,256, 0, + GL_RED, GL_FLOAT, NULL ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); + + magi->data = mv; + magi->ui_cb = cb_vg_mem_view; + magi->close_cb = cb_mem_view_close; + magi->min_w = w; + magi->min_h = h; + return 1; + } + } + + vg_error( "No named buffer '%s'\n", argv[0] ); + } + else + vg_error( "Usage: vg_mem_view \n" ); + + return 0; +} + +static void cmd_vg_mem_view_poll( int argc, const char *argv[] ) +{ + const char *term = argv[ argc-1 ]; + + if( argc == 1 ) + for( u32 i=0; imouse_state[1] = ctx->mouse_state[0]; ctx->mouse_state[0] = mouse_state; - ctx->mouse_delta[0] = mouse[0]-ctx->mouse[0]; - ctx->mouse_delta[1] = mouse[1]-ctx->mouse[1]; + ctx->mouse_delta[0] = mouse[0]-ctx->mouse_click[0]; + ctx->mouse_delta[1] = mouse[1]-ctx->mouse_click[1]; if( !ctx->mouse_pos_overriden ) { @@ -256,9 +256,7 @@ void ui_update_mouse( ui_context *ctx, ui_px mouse[2], i32 mouse_state ) return; } - if( ui_click_down(ctx, UI_MOUSE_LEFT)|| - ui_click_down(ctx, UI_MOUSE_MIDDLE)|| - ui_click_down(ctx, UI_MOUSE_RIGHT) ) + if( ui_click_down(ctx, UI_MOUSE_ANY) ) { ctx->mouse_click[0] = ctx->mouse[0]; ctx->mouse_click[1] = ctx->mouse[1]; @@ -926,12 +924,11 @@ static void ui_enum_post( ui_context *ctx ) drawer[3] *= ctx->_enum.option_count; int close = 0; - int clickany= ui_click_up(ctx, UI_MOUSE_LEFT|UI_MOUSE_RIGHT|UI_MOUSE_MIDDLE), + int clickany= ui_click_up( ctx, UI_MOUSE_ANY ), hover = ui_inside_rect( drawer, ctx->mouse ); - if( clickany && !hover ){ + if( clickany && !hover ) return; - } /* HACK */ ctx->focused_control_type = k_ui_control_none; diff --git a/vg_ui/imgui.h b/vg_ui/imgui.h index 32e636a..8672cf4 100644 --- a/vg_ui/imgui.h +++ b/vg_ui/imgui.h @@ -42,6 +42,7 @@ enum ui_shader k_ui_shader_colour, k_ui_shader_image, k_ui_shader_hsv, + k_ui_shader_grad }; typedef u32 ui_scheme[8*4]; @@ -76,15 +77,10 @@ enum ui_scheme_colour #define UI_MODAL_WARN 0x3 #define UI_MODAL_TYPE_BITS 0x3 -#if 0 -#define UI_MOUSE_LEFT (SDL_BUTTON(SDL_BUTTON_LEFT)) -#define UI_MOUSE_RIGHT (SDL_BUTTON(SDL_BUTTON_RIGHT)) -#define UI_MOUSE_MIDDLE (SDL_BUTTON(SDL_BUTTON_MIDDLE)) -#else #define UI_MOUSE_LEFT 1 -#define UI_MOUSE_RIGHT 2 -#define UI_MOUSE_MIDDLE 4 -#endif +#define UI_MOUSE_MIDDLE 2 +#define UI_MOUSE_RIGHT 4 +#define UI_MOUSE_ANY (UI_MOUSE_LEFT|UI_MOUSE_RIGHT|UI_MOUSE_MIDDLE) #define UI_TOP 0x1 #define UI_LEFT 0x2 diff --git a/vg_ui/imgui_impl_opengl.c b/vg_ui/imgui_impl_opengl.c index 9c4dc32..18edb3e 100644 --- a/vg_ui/imgui_impl_opengl.c +++ b/vg_ui/imgui_impl_opengl.c @@ -53,48 +53,6 @@ struct vg_ui vg_ui = .bg_inverse_ratio = {1,1}, }; -#if 0 -static vg_shader _shader_ui = -{ - .vs.static_src = - "layout (location=0) in vec2 a_co;" - "layout (location=1) in vec2 a_uv;" - "layout (location=2) in vec4 a_colour;" - "uniform mat3 uPv;" - "uniform vec2 uInverseFontSheet;" - "" - "out vec2 aTexCoords;" - "out vec4 aColour;" - "" - "void main(){" - "gl_Position = vec4( uPv * vec3( a_co, 1.0 ), 1.0 );" - "aTexCoords = a_uv * uInverseFontSheet;" - "aColour = a_colour;" - "}", - .fs.static_src = - "uniform sampler2D uTexGlyphs;" - "uniform lowp vec4 uColour;" - "out lowp vec4 FragColor;" - "" - "in highp vec2 aTexCoords;" - "in lowp vec4 aColour;" - "" - "void main(){" - "lowp vec4 avg = vec4(0.0);" - - "if( aColour.a == 0.0 ){" - "avg = aColour;" - "avg.a = texture( uTexGlyphs, aTexCoords ).r;" - "}" - "else{" - "avg = aColour;" - "}" - - "FragColor = avg * uColour;" - "}" -}; -#else - static struct vg_shader _shader_ui ={ .name = "[vg] ui - transparent", .vs = { @@ -209,6 +167,50 @@ static struct vg_shader _shader_ui_image = { } }; +static struct vg_shader _shader_ui_image_grad = { + .name = "[vg] ui_image (gradient)", + .vs = + { + .orig_file = NULL, + .static_src = + "layout (location=0) in vec2 a_co;" + "layout (location=1) in vec2 a_uv;" + "layout (location=2) in vec4 a_colour;" + "uniform mat3 uPv;" + + "out vec2 aTexCoords;" + "out vec4 aColour;" + "out vec2 aWsp;" + + "void main()" + "{" + "gl_Position = vec4( uPv * vec3( a_co, 1.0 ), 1.0 );" + "aTexCoords = a_uv * 0.00390625;" + "aColour = a_colour;" + + "aWsp = a_co;" + "}", + }, + .fs = + { + .orig_file = NULL, + .static_src = + "uniform sampler2D uTexImage;" + "uniform vec4 uColour;" + "out vec4 FragColor;" + + "in vec2 aTexCoords;" + "in vec4 aColour;" + "in vec2 aWsp;" + + "void main()" + "{" + "vec4 colour = texture( uTexImage, aTexCoords );" + "FragColor = vec4(vec3(colour.r)*uColour.rgb,1.0);" + "}" + } +}; + static struct vg_shader _shader_ui_hsv = { .name = "[vg] ui_hsv", .vs = { @@ -253,7 +255,6 @@ static struct vg_shader _shader_ui_hsv = { "}" } }; -#endif void vg_ui_set_screen( i32 width, i32 height ) { @@ -322,6 +323,23 @@ void ui_impl_render_batch( ui_context *ctx, ui_batch *batch, glActiveTexture( GL_TEXTURE0 ); glBindTexture( GL_TEXTURE_2D, *image ); } + else if( shader == k_ui_shader_grad ) + { + glUseProgram( _shader_ui_image_grad.id ); + glUniformMatrix3fv( + glGetUniformLocation( _shader_ui_image_grad.id, "uPv" ), 1, + GL_FALSE, (float *)vg_ui.pv ); + glUniform1i( + glGetUniformLocation(_shader_ui_image_grad.id,"uTexImage"), 0 ); + glUniform4fv( glGetUniformLocation( _shader_ui_image.id, "uColour" ), 1, + vg_ui.colour ); + + struct ui_batch_shader_data_image *inf = shader_data; + GLuint *image = inf->resource; + + glActiveTexture( GL_TEXTURE0 ); + glBindTexture( GL_TEXTURE_2D, *image ); + } else if( shader == k_ui_shader_hsv ) { struct ui_batch_shader_data_hsv *inf = shader_data; @@ -448,6 +466,7 @@ void vg_ui_init(void) vg_compile_shader( &_shader_ui ); vg_compile_shader( &_shader_ui_hsv ); vg_compile_shader( &_shader_ui_image ); + vg_compile_shader( &_shader_ui_image_grad ); u32 verts = 30000, indices = 20000; ui_init( &vg_ui.ctx, @@ -550,6 +569,7 @@ void ui_free(void) vg_free_shader( &_shader_ui ); vg_free_shader( &_shader_ui_hsv ); vg_free_shader( &_shader_ui_image ); + vg_free_shader( &_shader_ui_image_grad ); free( vg_ui.ctx.indice_buffer ); free( vg_ui.ctx.vertex_buffer ); } -- 2.25.1 From cce18a1c398bdea256da085aeec9a6ea1d1c1919 Mon Sep 17 00:00:00 2001 From: hgn Date: Thu, 26 Sep 2024 00:54:03 +0100 Subject: [PATCH 11/16] better back-tree walking --- vg_mem_view.c | 39 ++++++++++++++++++++++++++++++++++----- 1 file changed, 34 insertions(+), 5 deletions(-) diff --git a/vg_mem_view.c b/vg_mem_view.c index d326b5d..9f882f6 100644 --- a/vg_mem_view.c +++ b/vg_mem_view.c @@ -246,12 +246,41 @@ static void cb_vg_mem_view( ui_context *ctx, ui_rect rect, ui_split( rect, k_ui_axis_v, 256+16, 2, left, rect ); ui_fill( ctx, left, ui_opacity( ui_colour( ctx,k_ui_bg+1 ), 0.8f ) ); - for( u32 i=0; idepth+1; i ++ ) - ui_info( ctx, left, mv->walk[ i ] ); + /* Tree back-tracker */ + { + ui_rect bib = { left[0],left[1],left[2],24 }; + u32 new_depth = mv->depth; + for( u32 i=0; idepth+1; i ++ ) + { + if( i != mv->depth ) + { + if( ui_button_text( ctx, bib, mv->walk[ i ], 1 ) == 1 ) + { + new_depth = i; + } + } + else + { + ui_fill( ctx, bib, ui_colour( ctx, k_ui_bg ) ); + ui_text( ctx, bib, mv->walk[i], 1, k_ui_align_middle_center, 0 ); + } + + bib[0] += 8; + bib[2] -= 8; + bib[1] += 24; + } + mv->depth = new_depth; + ui_px v = (mv->depth+1)*24; + left[1] += v; + left[3] -= v; + } - if( mv->depth ) - if( ui_button( ctx, left, "up" ) == 1 ) - mv->depth --; + if( vg_mem.use_libc_malloc == 0 ) + { + ui_text( ctx, rect, "Run with --use-libc-malloc to view memory", + 1, k_ui_align_middle_center, 0 ); + return; + } vg_mem_view_ui( ctx, rect, mv->main_buffer[ mv->depth ], "", 0, &result ); -- 2.25.1 From 680f9d088cff050075f87e8bb290a7ad9a697db0 Mon Sep 17 00:00:00 2001 From: hgn Date: Thu, 26 Sep 2024 22:38:25 +0100 Subject: [PATCH 12/16] move profilers & audio inspector to magi --- vg_audio.c | 260 ++++++++++++++++++++++++++++--------------------- vg_audio.h | 12 +-- vg_audio_dsp.c | 27 +---- vg_audio_dsp.h | 4 - vg_engine.c | 70 +++++-------- vg_magi.c | 101 +++++++++++++++++-- vg_magi.h | 5 + vg_mem_view.c | 24 +++-- vg_profiler.c | 70 ++++++++++--- vg_profiler.h | 18 +++- 10 files changed, 355 insertions(+), 236 deletions(-) diff --git a/vg_audio.c b/vg_audio.c index e7bc7e5..b3e79be 100644 --- a/vg_audio.c +++ b/vg_audio.c @@ -26,6 +26,28 @@ static struct vg_profile vg_prof_audio_mix, vg_prof_audio_dsp; + +static f64 _vg_audio_budget() +{ + audio_lock(); + f64 ms = ((double)vg_audio.samples_last / 44100.0) * 1000.0; + audio_unlock(); + + return ms; +} + +struct vg_profile_set static _vg_prof_audio = +{ + .name = "audio", + .count = 3, + .get_budget = _vg_audio_budget, + .list = + { + &vg_prof_audio_decode, &vg_prof_audio_mix, &vg_prof_audio_dsp + } +}; + + /* * These functions are called from the main thread and used to prevent bad * access. TODO: They should be no-ops in release builds. @@ -104,42 +126,6 @@ void vg_audio_device_init(void) } } -void vg_audio_register(void) -{ - vg_console_reg_var( "debug_audio", &vg_audio.debug_ui, - k_var_dtype_i32, VG_VAR_CHEAT ); - vg_console_reg_var( "debug_dsp", &vg_audio.debug_dsp, - k_var_dtype_i32, VG_VAR_CHEAT ); - vg_console_reg_var( "volume", &vg_audio.external_global_volume, - k_var_dtype_f32, VG_VAR_PERSISTENT ); - vg_console_reg_var( "vg_audio_device", &vg_audio.device_choice, - k_var_dtype_str, VG_VAR_PERSISTENT ); - vg_console_reg_var( "vg_dsp", &vg_audio.dsp_enabled, - k_var_dtype_i32, VG_VAR_PERSISTENT ); -} - -void vg_audio_init(void) -{ - /* allocate memory */ - /* 32mb fixed */ - vg_audio.audio_pool = - vg_create_linear_allocator( vg_mem.rtmemory, 1024*1024*32, - VG_MEMORY_SYSTEM ); - - /* fixed */ - u32 decode_size = AUDIO_DECODE_SIZE * AUDIO_CHANNELS; - vg_audio.decode_buffer = vg_linear_alloc( vg_mem.rtmemory, decode_size ); - - vg_dsp_init(); - vg_audio_device_init(); -} - -void vg_audio_free(void) -{ - vg_dsp_free(); - SDL_CloseAudioDevice( vg_audio.sdl_output_device ); -} - /* * thread 1 */ @@ -715,7 +701,8 @@ static void audio_channel_mix( audio_channel *ch, float *buffer ) vg_profile_end( &_vg_prof_audio_mix ); } -static void audio_mixer_callback( void *user, u8 *stream, int byte_count ){ +static void audio_mixer_callback( void *user, u8 *stream, int byte_count ) +{ /* * Copy data and move edit flags to commit flags * ------------------------------------------------------------- */ @@ -728,13 +715,15 @@ static void audio_mixer_callback( void *user, u8 *stream, int byte_count ){ vg_audio.internal_listener_velocity ); vg_audio.internal_global_volume = vg_audio.external_global_volume; - for( int i=0; iallocated ) continue; - if( ch->activity == k_channel_activity_alive ){ + if( ch->activity == k_channel_activity_alive ) + { if( (ch->cursor >= ch->source_length) && !(ch->flags & AUDIO_FLAG_LOOP) ) { @@ -756,7 +745,8 @@ static void audio_mixer_callback( void *user, u8 *stream, int byte_count ){ } /* process new channels */ - if( ch->activity == k_channel_activity_reset ){ + if( ch->activity == k_channel_activity_reset ) + { ch->_ = ch->editable_state; ch->cursor = 0; ch->source_length = 0; @@ -769,23 +759,25 @@ static void audio_mixer_callback( void *user, u8 *stream, int byte_count ){ ch->editable_state.relinquished = ch->_.relinquished; - if( ch->editble_state_write_mask & AUDIO_EDIT_VOLUME ){ + if( ch->editble_state_write_mask & AUDIO_EDIT_VOLUME ) + { ch->_.volume = ch->editable_state.volume; ch->_.volume_target = ch->editable_state.volume; } - else{ + else ch->editable_state.volume = ch->_.volume; - } - if( ch->editble_state_write_mask & AUDIO_EDIT_VOLUME_SLOPE ){ + if( ch->editble_state_write_mask & AUDIO_EDIT_VOLUME_SLOPE ) + { ch->volume_movement_start = ch->_.volume; ch->volume_movement = 0; ch->_.volume_target = ch->editable_state.volume_target; ch->_.volume_rate = ch->editable_state.volume_rate; } - else{ + else + { ch->editable_state.volume_target = ch->_.volume_target; ch->editable_state.volume_rate = ch->_.volume_rate; } @@ -797,7 +789,8 @@ static void audio_mixer_callback( void *user, u8 *stream, int byte_count ){ ch->editable_state.sampling_rate = ch->_.sampling_rate; - if( ch->editble_state_write_mask & AUDIO_EDIT_LFO_ATTACHMENT ){ + if( ch->editble_state_write_mask & AUDIO_EDIT_LFO_ATTACHMENT ) + { ch->_.lfo = ch->editable_state.lfo; ch->_.lfo_amount = ch->editable_state.lfo_amount; } @@ -819,13 +812,16 @@ static void audio_mixer_callback( void *user, u8 *stream, int byte_count ){ ch->editble_state_write_mask = 0x00; } - for( int i=0; ieditble_state_write_mask & AUDIO_EDIT_LFO_WAVE ){ + if( lfo->editble_state_write_mask & AUDIO_EDIT_LFO_WAVE ) + { lfo->_.wave_type = lfo->editable_state.wave_type; - if( lfo->_.wave_type == k_lfo_polynomial_bipolar ){ + if( lfo->_.wave_type == k_lfo_polynomial_bipolar ) + { lfo->_.polynomial_coefficient = lfo->editable_state.polynomial_coefficient; lfo->sqrt_polynomial_coefficient = @@ -833,15 +829,18 @@ static void audio_mixer_callback( void *user, u8 *stream, int byte_count ){ } } - if( lfo->editble_state_write_mask & AUDIO_EDIT_LFO_PERIOD ){ - if( lfo->_.period ){ + if( lfo->editble_state_write_mask & AUDIO_EDIT_LFO_PERIOD ) + { + if( lfo->_.period ) + { float t = lfo->time; t/= (float)lfo->_.period; lfo->_.period = lfo->editable_state.period; lfo->time = lfo->_.period * t; } - else{ + else + { lfo->time = 0; lfo->_.period = lfo->editable_state.period; } @@ -856,10 +855,12 @@ static void audio_mixer_callback( void *user, u8 *stream, int byte_count ){ /* * Process spawns * ------------------------------------------------------------- */ - for( int i=0; iactivity == k_channel_activity_wake ){ + if( ch->activity == k_channel_activity_wake ) + { if( audio_channel_load_source( ch ) ) ch->activity = k_channel_activity_alive; else @@ -948,14 +949,14 @@ static void audio_mixer_callback( void *user, u8 *stream, int byte_count ){ vg_profile_increment( &_vg_prof_audio_mix ); vg_profile_increment( &_vg_prof_dsp ); - vg_prof_audio_mix = _vg_prof_audio_mix; - vg_prof_audio_decode = _vg_prof_audio_decode; - vg_prof_audio_dsp = _vg_prof_dsp; - - vg_audio.samples_last = frame_count; + if( vg_audio.inspector_open ) + { + vg_prof_audio_mix = _vg_prof_audio_mix; + vg_prof_audio_decode = _vg_prof_audio_decode; + vg_prof_audio_dsp = _vg_prof_dsp; - if( vg_audio.debug_dsp ) - vg_dsp_update_texture(); + vg_audio.samples_last = frame_count; + } audio_unlock(); } @@ -1098,55 +1099,22 @@ static void audio_require_clip_loaded( audio_clip *clip ) /* * Debugging */ +struct vg_audio_view_data +{ + i32 view_3d; +}; -void audio_debug_ui( ui_context *ctx, -#ifdef VG_3D - m4x4f -#else - m3x3f -#endif - mtx_pv ){ +static void cb_vg_audio_view( ui_context *ctx, ui_rect rect, + struct vg_magi_panel *magi ) +{ + struct vg_audio_view_data *vd = magi->data; - if( !vg_audio.debug_ui ) - return; + ui_rect left, panel; + ui_split( rect, k_ui_axis_v, 256, 2, left, panel ); + ui_checkbox( ctx, left, "3D labels", &vd->view_3d ); audio_lock(); - - glBindTexture( GL_TEXTURE_2D, vg_dsp.view_texture ); - glTexSubImage2D( GL_TEXTURE_2D, 0, 0, 0, 256, 256, - GL_RGBA, GL_UNSIGNED_BYTE, - vg_dsp.view_texture_buffer ); - - /* - * Profiler - * ----------------------------------------------------------------------- - */ - - float budget = ((double)vg_audio.samples_last / 44100.0) * 1000.0; - vg_profile_drawn( ctx, - (struct vg_profile *[]){ &vg_prof_audio_decode, - &vg_prof_audio_mix, - &vg_prof_audio_dsp}, 3, - budget, (ui_rect){ 4, VG_PROFILE_SAMPLE_COUNT*2 + 8, - 512, 0 }, 0, 0 ); - - char perf[128]; - - /* Draw UI */ - ui_rect window = { - 0, - 0, - 800, - AUDIO_CHANNELS * 18 - }; - - if( vg_audio.debug_dsp ) - { - ui_rect view_thing = { 4, vg.window_y-512-4, 512, 512 }; - ui_image( ctx, view_thing, &vg_dsp.view_texture ); - } - ui_rect overlap_buffer[ AUDIO_CHANNELS ]; u32 overlap_length = 0; @@ -1156,11 +1124,15 @@ void audio_debug_ui( ui_context *ctx, audio_channel *ch = &vg_audio.channels[i]; ui_rect row; - ui_split( window, k_ui_axis_h, 18, 1, row, window ); + ui_split( panel, k_ui_axis_h, 18, 1, row, panel ); + + bool show_row = ui_clip( rect, row, row ); if( !ch->allocated ) { - ui_fill( ctx, row, 0x50333333 ); + if( show_row ) + ui_fill( ctx, row, 0x50333333 ); + continue; } @@ -1206,17 +1178,20 @@ void audio_debug_ui( ui_context *ctx, ch->editable_state.volume, ch->name ); - ui_fill( ctx, row, 0xa0000000 | ch->colour ); - ui_text( ctx, row, perf, 1, k_ui_align_middle_left, 0 ); + if( show_row ) + { + ui_fill( ctx, row, 0xa0000000 | ch->colour ); + ui_text( ctx, row, perf, 1, k_ui_align_middle_left, 0 ); + } #ifdef VG_3D - if( AUDIO_FLAG_SPACIAL_3D ) + if( vd->view_3d && (ch->flags & AUDIO_FLAG_SPACIAL_3D) ) { v4f wpos; v3_copy( ch->editable_state.spacial_falloff, wpos ); wpos[3] = 1.0f; - m4x4_mulv( mtx_pv, wpos, wpos ); + m4x4_mulv( vg.pv, wpos, wpos ); if( wpos[3] > 0.0f ) { @@ -1258,3 +1233,66 @@ void audio_debug_ui( ui_context *ctx, audio_unlock(); } + +static void cb_vg_audio_close( struct vg_magi_panel *me ) +{ + vg_audio.inspector_open = 0; + free( me->data ); +} + +static int cmd_vg_audio( int argc, const char *argv[] ) +{ + if( vg_audio.inspector_open ) + { + vg_error( "Only 1 audio inspector at a time.\n" ); + return 0; + } + + vg_audio.inspector_open = 1; + ui_px w = 800, h=8*18; + struct vg_magi_panel *magi = _vg_magi_open( w,h, VG_MAGI_ALL ); + magi->title = "Audio inspector"; + + struct vg_audio_view_data *vd = malloc(sizeof(struct vg_audio_view_data)); + vd->view_3d = 0; + + magi->data = vd; + magi->ui_cb = cb_vg_audio_view; + magi->close_cb = cb_vg_audio_close; + return 1; +} + +void vg_audio_register(void) +{ + vg_console_reg_cmd( "vg_audio", cmd_vg_audio, NULL ); + vg_console_reg_var( "volume", &vg_audio.external_global_volume, + k_var_dtype_f32, VG_VAR_PERSISTENT ); + vg_console_reg_var( "vg_audio_device", &vg_audio.device_choice, + k_var_dtype_str, VG_VAR_PERSISTENT ); + vg_console_reg_var( "vg_dsp", &vg_audio.dsp_enabled, + k_var_dtype_i32, VG_VAR_PERSISTENT ); +} + +void vg_audio_init(void) +{ + _vg_profile_reg_set( &_vg_prof_audio ); + + /* allocate memory */ + /* 32mb fixed */ + vg_audio.audio_pool = + vg_create_linear_allocator( vg_mem.rtmemory, 1024*1024*32, + VG_MEMORY_SYSTEM ); + + /* fixed */ + u32 decode_size = AUDIO_DECODE_SIZE * AUDIO_CHANNELS; + vg_audio.decode_buffer = vg_linear_alloc( vg_mem.rtmemory, decode_size ); + + vg_dsp_init(); + vg_audio_device_init(); +} + +void vg_audio_free(void) +{ + SDL_CloseAudioDevice( vg_audio.sdl_output_device ); +} + diff --git a/vg_audio.h b/vg_audio.h index a579487..f660cbb 100644 --- a/vg_audio.h +++ b/vg_audio.h @@ -174,7 +174,8 @@ struct vg_audio_system } channels[ AUDIO_CHANNELS ]; - int debug_ui, debug_ui_3d, debug_dsp, dsp_enabled; + bool inspector_open; + int dsp_enabled; v3f internal_listener_pos, internal_listener_ears, @@ -223,12 +224,3 @@ int audio_oneshot( audio_clip *clip, f32 volume, f32 pan ); void audio_set_lfo_wave( int id, enum lfo_wave_type type, f32 coefficient ); void audio_set_lfo_frequency( int id, float freq ); int audio_channel_load_source( audio_channel *ch ); - -void audio_debug_ui( ui_context *ctx, - -#ifdef VG_3D - m4x4f -#else - m3x3f -#endif - mtx_pv ); diff --git a/vg_audio_dsp.c b/vg_audio_dsp.c index e362b3e..cd49883 100644 --- a/vg_audio_dsp.c +++ b/vg_audio_dsp.c @@ -131,22 +131,10 @@ static struct dsp_lpf __echos_lpf[8]; #endif static struct dsp_schroeder __diffusion_chain[8]; -static void async_vg_dsp_alloc_texture( void *payload, u32 size ) +void vg_dsp_init( void ) { - glGenTextures( 1, &vg_dsp.view_texture ); - glBindTexture( GL_TEXTURE_2D, vg_dsp.view_texture ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGBA, 256, 256, 0, - GL_RGBA, GL_UNSIGNED_BYTE, vg_dsp.view_texture_buffer ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST ); -} - -void vg_dsp_init( void ){ vg_rand_seed( &vg_dsp.rand, 461 ); vg_dsp.buffer = vg_linear_alloc( vg_mem.rtmemory, 1024*1024*1 ); - vg_dsp.view_texture_buffer = vg_linear_alloc( vg_mem.rtmemory, 512*512 ); - - vg_async_call( async_vg_dsp_alloc_texture, NULL, 0 ); /* temporary global design */ dsp_init_lpf( &__lpf_mud_free, 125.0f ); @@ -286,16 +274,3 @@ void dsp_update_tunings(void) vg_dsp.echo_tunings[i] *= volumes[i]; } } - -void vg_dsp_free( void ) -{ - glDeleteTextures( 1, &vg_dsp.view_texture ); -} - -void vg_dsp_update_texture( void ) -{ - for( int i=0; i<512*512; i++ ){ - float v = vg_clampf( vg_dsp.buffer[i] * 0.5f + 0.5f, 0.0f, 1.0f ); - vg_dsp.view_texture_buffer[i] = v * 255.0f; - } -} diff --git a/vg_audio_dsp.h b/vg_audio_dsp.h index e3239eb..4a1e9ae 100644 --- a/vg_audio_dsp.h +++ b/vg_audio_dsp.h @@ -11,9 +11,6 @@ struct vg_dsp float *buffer; u32 allocations; - u8 *view_texture_buffer; - GLuint view_texture; - float echo_distances[14], echo_tunings[8], reverb_wet_mix, @@ -51,7 +48,6 @@ void vg_dsp_init( void ); void vg_dsp_free( void ); void dsp_update_tunings(void); void vg_dsp_process( float *stereo_in, float *stereo_out ); -void vg_dsp_update_texture( void ); f32 dsp_biquad_process( struct dsp_biquad *bq, f32 xn ); void dsp_init_biquad_butterworth_lpf( struct dsp_biquad *bq, f32 fc ); diff --git a/vg_engine.c b/vg_engine.c index 9b0c1bf..920bdd8 100644 --- a/vg_engine.c +++ b/vg_engine.c @@ -71,6 +71,24 @@ static struct vg_profile vg_prof_update = {.name="update()"}, vg_prof_render = {.name="render()"}, vg_prof_swap = {.name="swap"}; +static f64 _vg_gameloop_budget() +{ + int frame_target = vg.display_refresh_rate; + if( vg.fps_limit > 0 ) frame_target = vg.fps_limit; + return (1.0/(f64)frame_target)*1000.0; +} + +struct vg_profile_set static _vg_prof_gameloop = +{ + .name = "gameloop", + .get_budget = _vg_gameloop_budget, + .count = 3, + .list = + { + &vg_prof_update, &vg_prof_render, &vg_prof_swap + } +}; + static void async_vg_bake_shaders( void *payload, u32 size ) { vg_shaders_compile(); @@ -124,6 +142,8 @@ vg_info(" ' ' '--' [] '----- '----- ' ' '---' " vg_loader_step( vg_input_init, vg_input_free ); vg_loader_step( vg_lines_init, NULL ); vg_loader_step( vg_rb_view_init, NULL ); + _vg_profile_reg_set( &_vg_prof_gameloop ); + #ifndef VG_NO_AUDIO vg_loader_step( vg_audio_init, vg_audio_free ); #endif @@ -310,53 +330,7 @@ static void _vg_gameloop_render(void) if( vg.settings_open ) vg_settings_gui( &vg_ui.ctx ); - - /* vg tools */ -#ifndef VG_NO_AUDIO - audio_debug_ui( &vg_ui.ctx, vg.pv ); -#endif - - /* profiling TODO MOVE TO OWN FILE */ - if( vg_profiler ){ - int frame_target = vg.display_refresh_rate; - if( vg.fps_limit > 0 ) frame_target = vg.fps_limit; - vg_profile_drawn( - &vg_ui.ctx, - (struct vg_profile *[]){ - &vg_prof_update,&vg_prof_render,&vg_prof_swap}, 3, - (1.0f/(float)frame_target)*1000.0f, - (ui_rect){ 4, 4, 250, 0 }, 0, 0 - ); - char perf[256]; - - snprintf( perf, 255, - "x: %d y: %d\n" - "refresh: %d (%.1fms)\n" - "samples: %d\n" - "iterations: %d (acc: %.3fms%%)\n" - "time: real(%.2f) delta(%.2f) rate(%.2f)\n" - " extrap(%.2f) frame(%.2f) spin( "PRINTF_U64" )\n", - vg.window_x, vg.window_y, - frame_target, (1.0f/(float)frame_target)*1000.0f, - vg.samples, - vg.fixed_iterations, - (vg.time_fixed_accumulator/VG_TIMESTEP_FIXED)*100.0f, - vg.time_real, vg.time_delta, vg.time_rate, - vg.time_fixed_extrapolate, vg.time_frame_delta, - vg.time_spinning ); - - ui_text( &vg_ui.ctx, - (ui_rect){258,4,900,900},perf,1,0,k_ui_align_left); - } - -#if 0 - if( vg_mem_view && vg_loader_availible() ) - { - vg_mem_view_ui( &vg_ui.ctx, (ui_rect){400,32, - vg.window_x-400,vg.window_y-64}, - vg_mem.rtmemory, 0, "rtmemory" ); - } -#endif + _vg_magi_render( &vg_ui.ctx ); ui_postrender( &vg_ui.ctx, vg.time_frame_delta ); @@ -1152,7 +1126,7 @@ static void vg_settings_audio_apply(void) { struct ui_enum_opt *selected = NULL, *oi; - for( int i=0; iflags = flags; panel->ui_cb = NULL; panel->close_cb = NULL; + panel->min_w = w; + panel->min_h = h; if( flags & VG_MAGI_PERSISTENT ) strcpy( panel->cmd, vg_console.input ); @@ -65,17 +67,41 @@ void _vg_magi_render( ui_context *ctx ) } else if( _vg_magi.mode == k_magi_mode_resize ) { - ptop->rect[2] = _vg_magi.drag_original[2] + ctx->mouse_delta[0]; - ptop->rect[3] = _vg_magi.drag_original[3] + ctx->mouse_delta[1]; + ui_px dx = ctx->mouse_delta[0]; + if( _vg_magi.drag_left ) dx = -dx; - if( ptop->rect[2] < ptop->min_w ) ptop->rect[2] = ptop->min_w; - if( ptop->rect[3] < ptop->min_h ) ptop->rect[3] = ptop->min_h; + ptop->rect[2] = _vg_magi.drag_original[2] + dx; + if( ptop->rect[2] < ptop->min_w ) + { + ptop->rect[2] = ptop->min_w; + dx = ptop->min_w - _vg_magi.drag_original[2]; + } + + if( _vg_magi.drag_left ) + ptop->rect[0] = _vg_magi.drag_original[0] - dx; + + if( !ptop->minimized ) + { + ui_px dy = ctx->mouse_delta[1]; + if( _vg_magi.drag_top ) dy = -dy; + + ptop->rect[3] = _vg_magi.drag_original[3] + dy; + if( ptop->rect[3] < ptop->min_h ) + { + ptop->rect[3] = ptop->min_h; + dy = ptop->min_h - _vg_magi.drag_original[3]; + } + + if( _vg_magi.drag_top ) + ptop->rect[1] = _vg_magi.drag_original[1] - dy; + } } if( ui_click_up( ctx, UI_MOUSE_ANY ) ) _vg_magi.mode = k_magi_mode_none; } + i32 j=0; for( i32 i=0; i<_vg_magi.panel_count; i ++ ) { struct vg_magi_panel *panel = &_vg_magi.panels[ i ]; @@ -84,6 +110,14 @@ void _vg_magi_render( ui_context *ctx ) ui_split( panel->rect, k_ui_axis_h, 28, 0, title, rect ); ui_fill( ctx, title, ui_opacity( ui_colour( ctx, k_ui_bg+7 ), 0.9f ) ); + ui_rect min_button, quit_button; + ui_split( title, k_ui_axis_v, title[2]-title[3], 2, title, quit_button ); + int should_close = ui_button_text( ctx, quit_button, "X", 1 ); + + ui_split( title, k_ui_axis_v, title[2]-title[3], 2, title, min_button ); + int should_min = ui_button_text( ctx, min_button, + panel->minimized? "+": "-", 1 ); + if( panel->flags & VG_MAGI_PERSISTENT ) { ui_text( ctx, title, panel->cmd, 1, k_ui_align_middle_center, @@ -114,6 +148,14 @@ void _vg_magi_render( ui_context *ctx ) if( panel->flags & VG_MAGI_RESIZEABLE ) { _vg_magi.mode = k_magi_mode_resize; + _vg_magi.drag_top = 0; + _vg_magi.drag_left = 0; + + if( ctx->mouse[0] < panel->rect[0]+panel->rect[2]/2 ) + _vg_magi.drag_left = 1; + if( ctx->mouse[1] < panel->rect[1]+panel->rect[3]/2 ) + _vg_magi.drag_top = 1; + rect_copy( panel->rect, _vg_magi.drag_original ); } } @@ -125,8 +167,38 @@ void _vg_magi_render( ui_context *ctx ) /* TODO: disable interaction */ } - panel->ui_cb( ctx, rect, panel ); + if( !panel->minimized ) + panel->ui_cb( ctx, rect, panel ); + + if( should_close == 1 ) + { + if( panel->close_cb ) + panel->close_cb( panel ); + + continue; + } + + if( should_min == 1 ) + { + panel->minimized ^= 0x1; + if( panel->minimized ) + { + panel->sh = panel->rect[3]; + panel->rect[3] = 32; + } + else + { + panel->rect[3] = panel->sh; + } + } + + if( j != i ) + _vg_magi.panels[ j ] = _vg_magi.panels[ i ]; + + j ++; } + + _vg_magi.panel_count = j; } void vg_magi_restore(void) @@ -151,8 +223,10 @@ void vg_magi_save(void) if( magi->flags & VG_MAGI_PERSISTENT ) { fprintf( fp, "%s\n", magi->cmd ); - fprintf( fp, "magi_pos %d %d %d %d\n", - magi->rect[0], magi->rect[1], magi->rect[2], magi->rect[3] ); + fprintf( fp, "magi_pos %d %d %d %d %d\n", + magi->rect[0], magi->rect[1], magi->rect[2], + magi->minimized? magi->sh: magi->rect[3], + (i32)magi->minimized ); } } @@ -169,16 +243,23 @@ static int cmd_vg_magi_dim( int argc, const char *argv[] ) if( argc == 0 ) { - vg_error( "Usage: magi_pos x y w h\n" ); + vg_error( "Usage: magi_pos x y w h \n" ); return 0; } struct vg_magi_panel *magi = &_vg_magi.panels[ _vg_magi.panel_count-1 ]; for( int i=0; i<4; i ++ ) - { if( argc >= i+1 ) magi->rect[i] = atoi( argv[i] ); - else break; + + if( argc >= 5 ) + { + magi->minimized = atoi( argv[4] ); + if( magi->minimized ) + { + magi->sh = magi->rect[3]; + magi->rect[3] = 32; + } } return 1; diff --git a/vg_magi.h b/vg_magi.h index 34c5f4a..3d480a0 100644 --- a/vg_magi.h +++ b/vg_magi.h @@ -13,6 +13,8 @@ struct vg_magi bool minimized; const char *title; ui_rect rect; + ui_px sh; + u32 flags; void *data; @@ -32,6 +34,9 @@ struct vg_magi k_magi_mode_resize } mode; + + bool drag_top, drag_left; + ui_rect drag_original; ui_px drag_start[2]; } diff --git a/vg_mem_view.c b/vg_mem_view.c index 9f882f6..c36913e 100644 --- a/vg_mem_view.c +++ b/vg_mem_view.c @@ -211,17 +211,6 @@ static void vg_mem_view_ui( ui_context *ctx, ui_rect rect, } } -static struct -{ - const char *name; - void **buffer; -} -_vg_mem_named_buffers[] = -{ - { "rtmemory", &vg_mem.rtmemory }, - { "scratch", &vg_mem.scratch } -}; - struct mem_view_data { void *main_buffer[8], @@ -372,6 +361,17 @@ static void cb_mem_view_close( struct vg_magi_panel *me ) free( me->data ); } +static struct +{ + const char *name; + void **buffer; +} +_vg_mem_named_buffers[] = +{ + { "rtmemory", &vg_mem.rtmemory }, + { "scratch", &vg_mem.scratch } +}; + static int cmd_vg_mem_view( int argc, const char *argv[] ) { if( argc == 1 ) @@ -401,8 +401,6 @@ static int cmd_vg_mem_view( int argc, const char *argv[] ) magi->data = mv; magi->ui_cb = cb_vg_mem_view; magi->close_cb = cb_mem_view_close; - magi->min_w = w; - magi->min_h = h; return 1; } } diff --git a/vg_profiler.c b/vg_profiler.c index 4785743..a4f2cca 100644 --- a/vg_profiler.c +++ b/vg_profiler.c @@ -3,7 +3,7 @@ #include "vg_engine.h" #include "vg_ui/imgui.h" -int vg_profiler = 0; +struct _vg_profiler _vg_profiler; void vg_profile_begin( struct vg_profile *profile ) { @@ -28,13 +28,13 @@ void vg_profile_end( struct vg_profile *profile ) u64 time_end = SDL_GetPerformanceCounter(), delta = time_end - profile->start; - if( profile->mode == k_profile_mode_frame ){ + if( profile->mode == k_profile_mode_frame ) + { profile->samples[ profile->buffer_current ] = delta; vg_profile_increment( profile ); } - else{ + else profile->samples[ profile->buffer_current ] += delta; - } } void vg_profile_drawn( ui_context *ctx, struct vg_profile **profiles, u32 count, @@ -97,11 +97,10 @@ void vg_profile_drawn( ui_context *ctx, struct vg_profile **profiles, u32 count, snprintf( infbuf, 64, "accuracy: %.7fms", rate_mul ); ui_text( ctx, - (ui_rect){ panel[0] + 4, - panel[1] + panel[3] - 14, 500, 30 }, + (ui_rect){ panel[0], panel[1], panel[2]-4, 24 }, infbuf, 1, - k_ui_align_left, 0 ); + k_ui_align_right, 0 ); for( int i=0; iname ); ui_text( ctx, - (ui_rect){ panel[0] + 4, - panel[1] + panel[3] + 4 + i*14, - panel[2]-8, 14 }, - infbuf, 1, k_ui_align_left, 0 ); + (ui_rect){ panel[0], panel[1] + 24 + i*14, + panel[2]-4, 14 }, + infbuf, 1, k_ui_align_right, 0 ); + } +} + +void _vg_profile_reg_set( struct vg_profile_set *set ) +{ + VG_ASSERT(_vg_profiler.named_count < VG_ARRAY_LEN(_vg_profiler.named_sets)); + _vg_profiler.named_sets[ _vg_profiler.named_count ++ ] = set; +} + +static void cb_vg_profiler( ui_context *ctx, ui_rect rect, + struct vg_magi_panel *magi ) +{ + struct vg_profile_set *ps = magi->data; + vg_profile_drawn( ctx, ps->list, ps->count, ps->get_budget(), rect, 0, 0 ); +} + +static int cmd_vg_profile( int argc, const char *argv[] ) +{ + if( argc == 1 ) + { + for( u32 i=0; i<_vg_profiler.named_count; i ++ ) + { + struct vg_profile_set *ps = _vg_profiler.named_sets[i]; + if( !strcmp( argv[0], ps->name ) ) + { + ui_px w = 256, h = VG_PROFILE_SAMPLE_COUNT * 2; + struct vg_magi_panel *magi = + _vg_magi_open( w,h, VG_MAGI_MOVEABLE|VG_MAGI_PERSISTENT ); + magi->title = "Profiler"; + magi->data = ps; + magi->ui_cb = cb_vg_profiler; + magi->close_cb = NULL; + return 1; + } + } } + else + vg_error( "Usage: vg_profile \n" ); + + return 0; +} + +static void cmd_vg_profile_poll( int argc, const char *argv[] ) +{ + const char *term = argv[ argc-1 ]; + + if( argc == 1 ) + for( u32 i=0; i<_vg_profiler.named_count; i ++ ) + console_suggest_score_text( _vg_profiler.named_sets[i]->name,term,0 ); } void vg_profiler_init(void) { - VG_VAR_I32( vg_profiler, flags=VG_VAR_PERSISTENT ); + vg_console_reg_cmd( "vg_profile", cmd_vg_profile, cmd_vg_profile_poll ); } diff --git a/vg_profiler.h b/vg_profiler.h index 4cad16b..d2a7f36 100644 --- a/vg_profiler.h +++ b/vg_profiler.h @@ -3,8 +3,6 @@ #include "vg_ui/imgui.h" #define VG_PROFILE_SAMPLE_COUNT 128 -extern int vg_profiler; - struct vg_profile { const char *name; @@ -22,6 +20,20 @@ struct vg_profile u64 start; }; +struct _vg_profiler +{ + struct vg_profile_set + { + const char *name; + u32 count; + f64 (*get_budget)(void); + struct vg_profile *list[]; + } + *named_sets[ 8 ]; + u32 named_count; +} +extern _vg_profiler; + void vg_profile_begin( struct vg_profile *profile ); void vg_profile_increment( struct vg_profile *profile ); void vg_profile_end( struct vg_profile *profile ); @@ -29,3 +41,5 @@ void vg_profile_drawn( ui_context *ctx, struct vg_profile **profiles, u32 count, f64 budget, ui_rect panel, int dir, i32 normalize ); void vg_profiler_init(void); + +void _vg_profile_reg_set( struct vg_profile_set *set ); -- 2.25.1 From ee976ace83ec1f6a9408bdaebb90754834863d16 Mon Sep 17 00:00:00 2001 From: hgn Date: Mon, 30 Sep 2024 17:42:37 +0100 Subject: [PATCH 13/16] keep panels relative to corners --- vg_engine.c | 3 +++ vg_magi.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++--- vg_magi.h | 3 +++ 3 files changed, 66 insertions(+), 3 deletions(-) diff --git a/vg_engine.c b/vg_engine.c index 920bdd8..98a4344 100644 --- a/vg_engine.c +++ b/vg_engine.c @@ -244,6 +244,9 @@ static void _vg_process_events(void) } else { + + i32 delta[2] = { w - vg.window_x, h - vg.window_y }; + _vg_magi_area_change( delta ); vg.window_x = w; vg.window_y = h; diff --git a/vg_magi.c b/vg_magi.c index 6d1abb5..15ad090 100644 --- a/vg_magi.c +++ b/vg_magi.c @@ -19,6 +19,7 @@ struct vg_magi_panel *_vg_magi_open( ui_px w, ui_px h, u32 flags ) panel->close_cb = NULL; panel->min_w = w; panel->min_h = h; + panel->corner = 0; if( flags & VG_MAGI_PERSISTENT ) strcpy( panel->cmd, vg_console.input ); @@ -26,6 +27,26 @@ struct vg_magi_panel *_vg_magi_open( ui_px w, ui_px h, u32 flags ) return panel; } +void _vg_magi_area_change( i32 d[2] ) +{ + for( u32 i=0; i<_vg_magi.panel_count; i ++ ) + { + struct vg_magi_panel *panel = &_vg_magi.panels[ i ]; + if( panel->corner & 0x1 ) + panel->rect[0] += d[0]; + if( panel->corner & 0x2 ) + panel->rect[1] += d[1]; + } +} + +static void vg_magi_getcorner( ui_rect rect, u32 id, ui_px corner[2] ) +{ + corner[0] = rect[0]; + corner[1] = rect[1]; + if( id&0x1 ) corner[0] += rect[2]; + if( id&0x2 ) corner[1] += rect[3]; +} + void _vg_magi_render( ui_context *ctx ) { if( _vg_magi.panel_count == 0 ) return; @@ -64,6 +85,26 @@ void _vg_magi_render( ui_context *ctx ) { ptop->rect[0] = _vg_magi.drag_original[0] + ctx->mouse_delta[0]; ptop->rect[1] = _vg_magi.drag_original[1] + ctx->mouse_delta[1]; + + ui_rect vp = { 0,0, ctx->area[0],ctx->area[1] }; + + f32 min2 = 9999999.9f; + for( u32 i=0; i<4; i ++ ) + { + ui_px c0[2], c1[2]; + vg_magi_getcorner( vp, i, c0 ); + vg_magi_getcorner( ptop->rect, i, c1 ); + + f32 dx = c0[0]-c1[0], + dy = c0[1]-c1[1], + d2 = dx*dx + dy*dy; + + if( d2 < min2 ) + { + min2 = d2; + ptop->corner = i; + } + } } else if( _vg_magi.mode == k_magi_mode_resize ) { @@ -222,11 +263,17 @@ void vg_magi_save(void) if( magi->flags & VG_MAGI_PERSISTENT ) { + ui_rect vp = {0,0,vg.window_x,vg.window_y}; + ui_px c[2], p[2]; + vg_magi_getcorner( vp, magi->corner, c ); + p[0] = magi->rect[0] - c[0]; + p[1] = magi->rect[1] - c[1]; + fprintf( fp, "%s\n", magi->cmd ); - fprintf( fp, "magi_pos %d %d %d %d %d\n", - magi->rect[0], magi->rect[1], magi->rect[2], + fprintf( fp, "magi_pos %d %d %d %d %d %d\n", + p[0], p[1], magi->rect[2], magi->minimized? magi->sh: magi->rect[3], - (i32)magi->minimized ); + (i32)magi->minimized, magi->corner ); } } @@ -262,6 +309,16 @@ static int cmd_vg_magi_dim( int argc, const char *argv[] ) } } + if( argc >= 6 ) + { + ui_rect vp = {0,0,vg.window_x,vg.window_y}; + ui_px c[2]; + magi->corner = atoi( argv[5] ); + vg_magi_getcorner( vp, magi->corner, c ); + magi->rect[0] += c[0]; + magi->rect[1] += c[1]; + } + return 1; } diff --git a/vg_magi.h b/vg_magi.h index 3d480a0..0290914 100644 --- a/vg_magi.h +++ b/vg_magi.h @@ -15,6 +15,8 @@ struct vg_magi ui_rect rect; ui_px sh; + u32 corner; /* which corner of screen relative to? TL, TR, BL, BR */ + u32 flags; void *data; @@ -47,3 +49,4 @@ void _vg_magi_render( ui_context *ctx ); void vg_magi_init(void); void vg_magi_save(void); void vg_magi_restore(void); +void _vg_magi_area_change( i32 d[2] ); -- 2.25.1 From 3f99a0570f6c12bf4c676dd11448ce7c842d08da Mon Sep 17 00:00:00 2001 From: hgn Date: Thu, 12 Dec 2024 16:34:51 +0000 Subject: [PATCH 14/16] Make sure that launch options be documented (with --help) --- vg_engine.c | 16 +++++--- vg_opt.c | 105 +++++++++++++++++++++++++++++++++++++++++++++++++--- vg_opt.h | 15 +++++--- 3 files changed, 119 insertions(+), 17 deletions(-) diff --git a/vg_engine.c b/vg_engine.c index 98a4344..b07193d 100644 --- a/vg_engine.c +++ b/vg_engine.c @@ -524,22 +524,28 @@ static void _vg_process_launch_opts_internal( int argc, char *argv[] ) char *arg; while( vg_argp( argc, argv ) ) { - if( (arg = vg_opt_arg( 'w' )) ) + if( (arg = vg_opt_arg( 'w', "Render output width" )) ) vg.window_x = atoi( arg ); - if( (arg = vg_opt_arg( 'h' )) ) + if( (arg = vg_opt_arg( 'h', "Render output height" )) ) vg.window_y = atoi( arg ); - if( (arg = vg_long_opt_arg( "samples" )) ) + if( (arg = vg_long_opt_arg( "samples", "Rendering samples per pixel" )) ) vg.samples = VG_MAX( 0, VG_MIN( 8, atoi( arg ) ) ); - if( vg_long_opt( "use-libc-malloc" ) ) + if( vg_long_opt( "use-libc-malloc", "Use standard libc allocator" ) ) vg_mem.use_libc_malloc = 1; - if( vg_long_opt( "high-performance" ) ) + if( vg_long_opt( "high-performance", "Turn graphics to lowest quality" ) ) vg.quality_profile = k_quality_profile_low; vg_launch_opt(); + + if( vg_long_opt( "help", "Helps you" ) ) + { + _vg_print_options(); + exit(0); + } } } diff --git a/vg_opt.c b/vg_opt.c index ba0f9c4..80b3146 100644 --- a/vg_opt.c +++ b/vg_opt.c @@ -13,6 +13,7 @@ * short options | -a value * multi-set options | -ab value * + * long gnu flag | --long-opt * long gnu options | --long-value=test * standard agument | regular_thing */ @@ -23,6 +24,88 @@ static int vg_argc = 0; static int vg_consume_next = 0; static char **vg_argv; +enum vg_opt_type +{ + k_vg_opt_type_standard, + k_vg_opt_type_flag, + k_vg_opt_type_arg, + k_vg_opt_type_long_flag, + k_vg_opt_type_long_arg +}; + +struct _vg_opt_reg +{ + const char *alias, *desc; + char alias_c; + u8 type; +} +static _vg_all_opts[32]; +static u32 _vg_opt_count = 0; + +static void _vg_opt_observe( const char *alias, char alias_c, const char *desc, + enum vg_opt_type type ) +{ + for( u32 i=0; i<_vg_opt_count; i ++ ) + { + struct _vg_opt_reg *reg = &_vg_all_opts[i]; + if( (type == k_vg_opt_type_flag || type == k_vg_opt_type_arg) + && reg->alias_c == alias_c ) + { + return; + } + + if( (type == k_vg_opt_type_long_flag || type == k_vg_opt_type_long_arg) + && reg->alias == alias ) + { + return; + } + + if( (type == k_vg_opt_type_standard) + && (reg->alias == NULL && reg->alias_c == 0) ) + { + return; + } + } + + if( _vg_opt_count < VG_ARRAY_LEN( _vg_all_opts ) ) + { + struct _vg_opt_reg *reg = &_vg_all_opts[ _vg_opt_count ++ ]; + reg->alias = alias; + reg->alias_c = alias_c; + reg->desc = desc; + reg->type = type; + } +} + +void _vg_print_options(void) +{ + for( u32 i=0; i<_vg_opt_count; i ++ ) + { + struct _vg_opt_reg *reg = &_vg_all_opts[i]; + + if( reg->type == k_vg_opt_type_flag ) + printf( "-%c %s\n", reg->alias_c, reg->desc ); + + if( reg->type == k_vg_opt_type_arg ) + printf( "-%c %s\n", reg->alias_c, reg->desc ); + + if( reg->type == k_vg_opt_type_long_flag ) + printf( "--%-21s %s\n", reg->alias, reg->desc ); + + if( reg->type == k_vg_opt_type_long_arg ) + { + char temp[32]; + snprintf( temp, 32, "--%s=", reg->alias ); + printf( "%-23s %s\n", temp, reg->desc ); + } + + if( reg->type == k_vg_opt_type_standard ) + { + printf( " %s\n", reg->desc ); + } + } +} + /* Will return 0 if exhausted */ int vg_argp( int argc, char *argv[] ) { @@ -70,8 +153,10 @@ int vg_argp( int argc, char *argv[] ) } /* Example: see if -c is set */ -int vg_opt( char c ) +int vg_opt( char c, const char *desc ) { + _vg_opt_observe( NULL, c, desc, k_vg_opt_type_flag ); + char *carg = vg_argv[ vg_argi ]; if( carg[0] == '-' ) @@ -91,9 +176,11 @@ int vg_opt( char c ) } /* Example: get -c *value* */ -char *vg_opt_arg( char c ) +char *vg_opt_arg( char c, const char *desc ) { - if( vg_opt( c ) ) + _vg_opt_observe( NULL, c, desc, k_vg_opt_type_arg ); + + if( vg_opt( c, NULL ) ) { if( vg_argi < vg_argc-1 ) { @@ -112,8 +199,10 @@ char *vg_opt_arg( char c ) } /* Example see if --big is set */ -int vg_long_opt( char *name ) +int vg_long_opt( char *name, const char *desc ) { + _vg_opt_observe( name, 0, desc, k_vg_opt_type_long_flag ); + char *carg = vg_argv[ vg_argi ]; if( carg[0] == '-' ) @@ -132,8 +221,10 @@ int vg_long_opt( char *name ) } /* Example: get --big=value */ -char *vg_long_opt_arg( char *name ) +char *vg_long_opt_arg( char *name, const char *desc ) { + _vg_opt_observe( name, 0, desc, k_vg_opt_type_long_arg ); + char *carg = vg_argv[ vg_argi ]; if( carg[0] == '-' ) @@ -173,8 +264,10 @@ char *vg_long_opt_arg( char *name ) } /* Example: get regular_thing */ -char *vg_arg(void) +char *vg_arg( const char *desc ) { + _vg_opt_observe( NULL, 0, desc, k_vg_opt_type_standard ); + char *carg = vg_argv[ vg_argi ]; if( carg[0] != '-' ) diff --git a/vg_opt.h b/vg_opt.h index 6f2d879..0dac45c 100644 --- a/vg_opt.h +++ b/vg_opt.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2021-2024 Mt.ZERO Software, Harry Godden - All Rights Reserved + * Copyright (C) 2021-2024 Mt.ZERO Software - All Rights Reserved */ #pragma once @@ -8,16 +8,19 @@ int vg_argp( int argc, char *argv[] ); /* Example: see if -c is set */ -int vg_opt( char c ); +int vg_opt( char c, const char *desc ); /* Example: get -c *value* */ -char *vg_opt_arg( char c ); +char *vg_opt_arg( char c, const char *desc ); /* Example see if --big is set */ -int vg_long_opt( char *name ); +int vg_long_opt( char *name, const char *desc ); /* Example: get --big=value */ -char *vg_long_opt_arg( char *name ); +char *vg_long_opt_arg( char *name, const char *desc ); /* Example: get regular_thing */ -char *vg_arg(void); +char *vg_arg( const char *desc ); + +/* You should probably bind this to --help (and call it last!) */ +void _vg_print_options(void); -- 2.25.1 From 58fffa5507995a5bded3fa695bc4521068a2b281 Mon Sep 17 00:00:00 2001 From: hgn Date: Fri, 13 Dec 2024 01:53:01 +0000 Subject: [PATCH 15/16] add roll to camera calculation --- vg_camera.c | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/vg_camera.c b/vg_camera.c index 8cd261f..3828645 100644 --- a/vg_camera.c +++ b/vg_camera.c @@ -40,11 +40,13 @@ void vg_m4x3_transform_camera( m4x3f m, vg_camera *cam ) */ void vg_camera_update_transform( vg_camera *cam ) { - v4f qyaw, qpitch, qcam; + v4f qyaw, qpitch, qroll, qcam; q_axis_angle( qyaw, (v3f){ 0.0f, 1.0f, 0.0f }, -cam->angles[0] ); q_axis_angle( qpitch, (v3f){ 1.0f, 0.0f, 0.0f }, -cam->angles[1] ); + q_axis_angle( qroll, (v3f){ 0.0f, 0.0f, 1.0f }, -cam->angles[2] ); q_mul( qyaw, qpitch, qcam ); + q_mul( qcam, qroll, qcam ); q_m3x3( qcam, cam->transform ); v3_copy( cam->pos, cam->transform[3] ); } -- 2.25.1 From b2d1c177bedd117abe9419b7a6ccbf7f890d3663 Mon Sep 17 00:00:00 2001 From: hgn Date: Fri, 13 Dec 2024 02:37:46 +0000 Subject: [PATCH 16/16] move explicit bezier to vg --- vg_m.h | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/vg_m.h b/vg_m.h index dae258c..5ab6a22 100644 --- a/vg_m.h +++ b/vg_m.h @@ -2303,6 +2303,56 @@ static void eval_bezier3( v3f p0, v3f p1, v3f p2, f32 t, v3f p ) v3_muladds( p, p2, t*t, p ); } +static f32 explicit_bezier( f32 A[2], f32 B[2], f32 C[2], f32 D[2], f32 x ) +{ + f32 dAxDx = D[0]-A[0], + unitBx = (B[0] - A[0]) / dAxDx, + unitCx = (C[0] - A[0]) / dAxDx, + + /* cubic coefficients */ + a = 3.0f*unitBx - 3.0f*unitCx + 1.0f, + b = -6.0f*unitBx + 3.0f*unitCx, + c = 3.0f*unitBx, + d = -(x - A[0]) / dAxDx, + + t0 = 0.0f, + Ft0 = d, + t1 = 1.0f, + Ft1 = a+b+c+d, + tc, Ftcx; + + /* Illinois method to find root */ + for( u32 j=0; j<8; j ++ ) + { + tc = t1 - Ft1*(t1-t0)/(Ft1-Ft0); + Ftcx = tc*tc*tc*a + tc*tc*b + tc*c + d; + + if( fabsf(Ftcx) < 0.00001f ) + break; + + if( Ft1*Ftcx < 0.0f ) + { + t0 = t1; + Ft0 = Ft1; + } + else + Ft0 *= 0.5f; + + t1 = tc; + Ft1 = Ftcx; + } + + /* Evaluate parametric bezier */ + f32 t2 = tc*tc, + t3 = tc*tc*tc; + + return D[1] * t3 + + C[1] * (-3.0f*t3 + 3.0f*t2) + + B[1] * ( 3.0f*t3 - 6.0f*t2 + 3.0f*tc) + + A[1] * (-1.0f*t3 + 3.0f*t2 - 3.0f*tc + 1.0f); +} + + /* * ----------------------------------------------------------------------------- * Section 5.f Volumes -- 2.25.1