From: hgn Date: Thu, 6 Oct 2022 04:32:19 +0000 (+0100) Subject: medium sized dollop X-Git-Url: https://harrygodden.com/git/?a=commitdiff_plain;h=c2d67378dd5c82de50b8fbbbe222ec6be2da4eee;hp=1740c935bfdacc65c5c7e4bb95fba1ada1f7118a;p=carveJwlIkooP6JGAAIwe30JlM.git medium sized dollop --- diff --git a/.lsan_suppress.txt b/.lsan_suppress.txt new file mode 100644 index 0000000..ac3baee --- /dev/null +++ b/.lsan_suppress.txt @@ -0,0 +1,7 @@ +leak:libGL.so +leak:libGLX_nvidia.so +leak:__interceptor_malloc +leak:__interceptor_calloc +leak:__interceptor_realloc +leak:__interceptor_posix_memalign +leak:libnvidia-glcore.so diff --git a/audio.h b/audio.h index 25f3aa8..f6baa20 100644 --- a/audio.h +++ b/audio.h @@ -120,7 +120,7 @@ audio_player audio_player_gate = .name = "Gate" }; -static void audio_init(void) +static int audio_init(void) { audio_player_init( &audio_player0 ); audio_player_init( &audio_player1 ); @@ -160,7 +160,7 @@ static void audio_init(void) audio_player_set_flags( &ambient_sprites[2], AUDIO_FLAG_SPACIAL_3D ); audio_player_set_flags( &ambient_sprites[3], AUDIO_FLAG_SPACIAL_3D ); audio_player_set_vol( &ambient_player, 1.0f ); - audio_player_set_vol( &audio_player_gate, 5.0f ); + audio_player_set_vol( &audio_player_gate, 0.0f ); audio_player_set_vol( &audio_player_extra, 1.0f ); audio_player_playclip( &audio_player0, &audio_board[0] ); @@ -187,10 +187,14 @@ static void audio_init(void) .opt_f32 = { .clamp = 0 }, .persistent = 1 }); + + return 1; } -static void audio_free(void) +static void audio_free(void*_) { + /* TODO! */ + vg_warn( "UNIMPLEMENTED: audio_free()\n" ); } static void audio_sample_occlusion( v3f origin ) @@ -202,6 +206,7 @@ static void audio_sample_occlusion( v3f origin ) int lv = 0; v3f last; + v3_zero(last); for( int i=0; iorigins[ child ], ch->origins[ parent ], - ch->offsets[ child ] ); -} - -static int character_load( struct character *ch, const char *name ) -{ - char buf[64]; - - snprintf( buf, sizeof(buf)-1, "models/%s.mdl", name ); - mdl_header *src = mdl_load( buf ); - - if( !src ) - return 0; - - int error_count = 0; - - for( int i=0; iparts[i], 0, sizeof(mdl_submesh) ); - v3_zero( ch->origins[i] ); - - if( !pnode ) - { - vg_warn( "Character file does not contain an '_%s' part.\n", - character_part_strings[i] ); - error_count ++; - continue; - } - - mdl_submesh *sm = mdl_node_submesh( src, pnode, 0 ); - - if( !sm ) - { - vg_warn( "Character file's '_%s' part has no mesh.\n", - character_part_strings[i] ); - error_count ++; - continue; - } - - ch->parts[i] = *sm; - v3_copy( pnode->co, ch->origins[i] ); - } - - mdl_unpack_glmesh( src, &ch->mesh ); - - if( !error_count ) - vg_success( "Loaded character file '%s' with no errors\n", name ); - - /* Create the offsets */ - character_offset( ch, k_chpart_body0, k_chpart_body1 ); - character_offset( ch, k_chpart_body1, k_chpart_neck ); - character_offset( ch, k_chpart_neck, k_chpart_head ); - - character_offset( ch, k_chpart_body1, k_chpart_arm_l0 ); - character_offset( ch, k_chpart_arm_l0, k_chpart_arm_l1 ); - character_offset( ch, k_chpart_arm_l1, k_chpart_hand_l ); - - character_offset( ch, k_chpart_body1, k_chpart_arm_r0 ); - character_offset( ch, k_chpart_arm_r0, k_chpart_arm_r1 ); - character_offset( ch, k_chpart_arm_r1, k_chpart_hand_r ); - - character_offset( ch, k_chpart_body0, k_chpart_leg_l0 ); - character_offset( ch, k_chpart_leg_l0, k_chpart_leg_l1 ); - character_offset( ch, k_chpart_leg_l1, k_chpart_foot_l ); - - character_offset( ch, k_chpart_body0, k_chpart_leg_r0 ); - character_offset( ch, k_chpart_leg_r0, k_chpart_leg_r1 ); - character_offset( ch, k_chpart_leg_r1, k_chpart_foot_r ); - - character_offset( ch, k_chpart_board, k_chpart_wb ); - character_offset( ch, k_chpart_board, k_chpart_wf ); - - ch->ik_arm_l.l1 = v3_length( ch->offsets[ k_chpart_arm_l1 ] ); - ch->ik_arm_l.l2 = v3_length( ch->offsets[ k_chpart_hand_l ] ); - ch->ik_arm_r.l1 = v3_length( ch->offsets[ k_chpart_arm_r1 ] ); - ch->ik_arm_r.l2 = v3_length( ch->offsets[ k_chpart_hand_r ] ); - - ch->ik_leg_l.l1 = v3_length( ch->offsets[ k_chpart_leg_l1 ] ); - ch->ik_leg_l.l2 = v3_length( ch->offsets[ k_chpart_foot_l ] ); - ch->ik_leg_r.l1 = v3_length( ch->offsets[ k_chpart_leg_r1 ] ); - ch->ik_leg_r.l2 = v3_length( ch->offsets[ k_chpart_foot_r ] ); - - ch->ik_body.l1 = v3_length( ch->offsets[ k_chpart_body1 ] ); - ch->ik_body.l2 = v3_length( ch->offsets[ k_chpart_neck ] ); - - free( src ); - return 1; -} - -static void align_to_board( struct character *ch, enum character_part id ) -{ - /* Calculate rotation between board and feet */ - m4x3f *mats = ch->matrices; - - v3f foot_pos, foot_fwd, foot_target, board_norm, board_origin; - v3_copy( mats[id][3], foot_pos ); - m3x3_mulv( mats[id], (v3f){1.0f,0.0f,0.0f}, foot_fwd ); - v3_add( foot_fwd, foot_pos, foot_target ); - - m3x3_mulv( mats[k_chpart_board], (v3f){0.0f,1.0f,0.0f}, board_norm ); - m4x3_mulv( mats[k_chpart_board], (v3f){0.0f,0.13f,0.0f}, board_origin ); - - vg_line( foot_pos, foot_target, 0xff00ff00 ); - - v3f v0; - v3_sub( board_origin, foot_target, v0 ); - float t = v3_dot( v0, board_norm ) / board_norm[1]; - foot_target[1] += t; - vg_line( foot_pos, foot_target, 0xff00ffff ); - - v3_sub( foot_target, foot_pos, foot_target ); - v3_normalize( foot_target ); - float ang = acosf( v3_dot( foot_target, foot_fwd ) ); - - v4f qcorrection; m3x3f correction; - q_axis_angle( qcorrection, (v3f){0.0f,0.0f,1.0f}, -ang ); - q_m3x3( qcorrection, correction ); - m3x3_mul( mats[id], correction, mats[id] ); -} - -static void character_eval( struct character *ch ) -{ - m4x3f *mats = ch->matrices; - v3f *offs = ch->offsets; - - ik_basic( &ch->ik_body, mats[k_chpart_body0], mats[k_chpart_body1], - k_ikY, k_ikX ); - - m3x3f temp; - v4f body_rotation; - /* TODO: Do this directly via m3x3 */ - - q_axis_angle( body_rotation, (v3f){0.0f,1.0f,0.0f}, ch->rhip ); - q_m3x3( body_rotation, temp ); - m3x3_mul( mats[k_chpart_body0], temp, mats[k_chpart_body0] ); - - q_axis_angle( body_rotation, (v3f){0.0f,1.0f,0.0f}, ch->rcollar ); - q_m3x3( body_rotation, temp ); - m3x3_mul( mats[k_chpart_body1], temp, mats[k_chpart_body1] ); - - /* Setup aux */ - m4x3_mulv( mats[k_chpart_body0], offs[k_chpart_leg_l0], ch->ik_leg_l.base ); - m4x3_mulv( mats[k_chpart_body0], offs[k_chpart_leg_r0], ch->ik_leg_r.base ); - m4x3_mulv( mats[k_chpart_body1], offs[k_chpart_arm_l0], ch->ik_arm_l.base ); - m4x3_mulv( mats[k_chpart_body1], offs[k_chpart_arm_r0], ch->ik_arm_r.base ); - - /* IK for arms and legs */ - ik_basic( &ch->ik_arm_l, mats[k_chpart_arm_l0], mats[k_chpart_arm_l1], - k_ikZ, k_ikY ); - ik_basic( &ch->ik_arm_r, mats[k_chpart_arm_r0], mats[k_chpart_arm_r1], - k_iknZ, k_ikY ); - ik_basic( &ch->ik_leg_l, mats[k_chpart_leg_l0], mats[k_chpart_leg_l1], - k_ikY, k_iknX ); - ik_basic( &ch->ik_leg_r, mats[k_chpart_leg_r0], mats[k_chpart_leg_r1], - k_ikY, k_iknX ); - - /* Hands */ - m3x3_copy( mats[k_chpart_arm_l1], mats[k_chpart_hand_l] ); - m3x3_copy( mats[k_chpart_arm_r1], mats[k_chpart_hand_r] ); - m4x3_mulv( mats[k_chpart_arm_l1], offs[k_chpart_hand_l], - mats[k_chpart_hand_l][3] ); - m4x3_mulv( mats[k_chpart_arm_r1], offs[k_chpart_hand_r], - mats[k_chpart_hand_r][3] ); - - /* Neck / Head */ - m3x3_copy( mats[k_chpart_body1], mats[k_chpart_neck] ); - m4x3_mulv( mats[k_chpart_body1], offs[k_chpart_neck], - mats[k_chpart_neck][3] ); - -#if 1 - v4f qhead; - q_axis_angle( qhead, (v3f){ 0.0f,1.0f,0.0f }, ch->rhead ); - q_m3x3( qhead, mats[k_chpart_head] ); - m4x3_mulv( mats[k_chpart_neck], offs[k_chpart_head], mats[k_chpart_head][3]); - m3x3_mul( mats[k_chpart_neck], mats[k_chpart_head], mats[k_chpart_head] ); -#else - m4x3_mulv( mats[k_chpart_neck], offs[k_chpart_head], mats[k_chpart_head][3]); - m3x3_copy( mats[k_chpart_neck], mats[k_chpart_head] ); -#endif - - /* Feet */ - m3x3_copy( mats[k_chpart_leg_l1], mats[k_chpart_foot_l] ); - m3x3_copy( mats[k_chpart_leg_r1], mats[k_chpart_foot_r] ); - m4x3_mulv( mats[k_chpart_leg_l1], offs[k_chpart_foot_l], - mats[k_chpart_foot_l][3] ); - m4x3_mulv( mats[k_chpart_leg_r1], offs[k_chpart_foot_r], - mats[k_chpart_foot_r][3] ); - - align_to_board( ch, k_chpart_foot_l ); - align_to_board( ch, k_chpart_foot_r ); - - for( int i=0; imroot, ch->matrices[i], ch->matrices[i] ); -} - -#define B3D_CO( X, Y, Z ) (v3f){ X, Z, -Y } - -typedef struct character_pose character_pose; -struct character_pose -{ - v3f b0, b1, p, fr, fl, pl, pr, hl, hr, apl, apr, cam; -}; - -static character_pose pose_aero = -{ - .b0 = {0.0721f, 0.8167f, 0.1365f}, - .b1 = {-0.0773f, 1.1559f, -0.1699f}, - .p = {0.0421f, 1.1430f, 0.2803f}, - .fr = {0.0535f, 0.1312f, -0.3647f}, - .fl = {-0.0605f, 0.1464f, 0.2917f}, - .pl = {-0.1704f, 0.6889f, -0.4017f}, - .pr = {0.0672f, 0.7598f, -0.5963f}, - .hl = {-0.2153f, 0.7195f, -0.1345f}, - .hr = {0.1974f, 0.7940f, -0.3522f}, - .apl = {-0.2008f, 0.9546f, 0.3687f}, - .apr = {0.3133f, 0.9299f, 0.0181f}, - .cam = {-0.3394f, 1.2661f, 0.2936f} -}; - -static character_pose pose_slide = -{ - .b0 = {0.6732f, 0.5565f, -0.0000f}, - .b1 = {0.8116f, 1.0547f, 0.0613f}, - .p = {1.0404f, 0.7907f, 0.0186f}, - .fr = {-0.0030f, 0.1366f, -0.4461f}, - .fl = {-0.0030f, 0.1366f, 0.3480f}, - .pl = {-0.0887f, 0.8229f, 0.3826f}, - .pr = {-0.0887f, 0.8229f, -0.4621f}, - .hl = {0.7749f, 0.5545f, 0.5310f}, - .hr = {0.5844f, 1.2445f, -0.5456f}, - .apl = {1.0999f, 0.5390f, 0.2398f}, - .apr = {0.9816f, 0.9536f, -0.5463f}, - .cam = {0.9888f, 1.4037f, 0.6081f} -}; - -static character_pose pose_slide1 = -{ - .b0 = {-0.2385f, 0.6403f, 0.1368f}, - .b1 = {-0.5151f, 1.1351f, 0.1380f}, - .p = {-0.1158f, 1.2118f, 0.3895f}, - .fr = {-0.0030f, 0.1323f, -0.3190f}, - .fl = {-0.0030f, 0.1323f, 0.5797f}, - .pl = {-0.6568f, 0.4305f, 0.2069f}, - .pr = {-0.6850f, 0.2740f, -0.2969f}, - .hl = {-0.7029f, 0.6132f, 0.2972f}, - .hr = {-0.2572f, 1.0104f, -0.4770f}, - .apl = {-0.4808f, 0.8480f, 0.3731f}, - .apr = {-0.0836f, 1.0480f, -0.1201f}, - .cam = {-1.0508f, 1.0769f, 0.0528f} -}; - -static character_pose pose_aero_reverse = -{ - .b0 = {0.0616f, 0.8167f, -0.1415f}, - .b1 = {0.0148f, 1.1559f, 0.1861f}, - .p = {0.0558f, 1.1430f, -0.2779f}, - .fr = {0.0535f, 0.1312f, -0.3647f}, - .fl = {0.0730f, 0.1464f, 0.2917f}, - .pl = {-0.2073f, 0.6889f, 0.3839f}, - .pr = {-0.3584f, 0.4069f, 0.1032f}, - .hl = {0.1567f, 0.7195f, 0.1997f}, - .hr = {-0.3055f, 0.7940f, 0.2639f}, - .apl = {0.3143f, 0.9546f, -0.2784f}, - .apr = {-0.2885f, 0.9299f, -0.1236f}, - .cam = {-0.3394f, 1.2661f, -0.2936f} -}; - -static character_pose pose_stand = -{ - .b0 = {0.1877f, 1.0663f, 0.0063f}, - .b1 = {0.0499f, 1.5564f, -0.0584f}, - .p = {0.5982f, 1.2810f, 0.0842f}, - .fr = {0.0535f, 0.1312f, -0.3647f}, - .fl = {0.0354f, 0.1464f, 0.2917f}, - .pl = {-0.4325f, 0.6889f, 0.1823f}, - .pr = {-0.4794f, 0.7598f, -0.3610f}, - .hl = {0.0498f, 1.0058f, 0.2317f}, - .hr = {0.0188f, 0.9786f, -0.2725f}, - .apl = {0.2898f, 1.3453f, 0.2303f}, - .apr = {0.5273f, 1.2876f, -0.1848f}, - .cam = {-0.3477f, 1.5884f, -0.0019f} -}; - -static character_pose pose_stand_reverse = -{ - .b0 = {0.1624f, 1.0688f, -0.0632f}, - .b1 = {0.0499f, 1.5564f, -0.0013f}, - .p = {0.5423f, 1.2810f, -0.2368f}, - .fr = {0.0535f, 0.1312f, -0.3647f}, - .fl = {0.0354f, 0.1464f, 0.2917f}, - .pl = {-0.4325f, 0.6889f, 0.4591f}, - .pr = {-0.4794f, 0.7598f, -0.0842f}, - .hl = {0.0498f, 1.0058f, 0.2317f}, - .hr = {0.0188f, 0.9786f, -0.2725f}, - .apl = {0.2898f, 1.3453f, 0.0695f}, - .apr = {0.4715f, 1.2876f, -0.4982f}, - .cam = {-0.3477f, 1.5884f, -0.0730f} -}; - -static character_pose pose_fly = -{ - .b0 = {0.2995f, 0.6819f, -0.1369f}, - .b1 = {0.1618f, 1.1720f, -0.2016f}, - .p = {0.7477f, 0.9173f, -0.1885f}, - .fr = {0.0535f, 0.1312f, -0.3647f}, - .fl = {0.0354f, 0.1464f, 0.2917f}, - .pl = {-0.2930f, 0.4849f, 0.5307f}, - .pr = {-0.4754f, 0.4124f, -0.4874f}, - .hl = {0.2650f, 1.1897f, 0.4626f}, - .hr = {0.2494f, 1.2059f, -0.7985f}, - .apl = {0.5165f, 1.0990f, 0.1655f}, - .apr = {0.6759f, 1.0661f, -0.6014f}, - .cam = {-0.2727f, 1.2606f, 0.3564f} -}; - -static -void character_pose_blend( struct character *ch, character_pose *pose, float q ) -{ - v3_muladds( ch->ik_body.base, pose->b0, q, ch->ik_body.base ); - v3_muladds( ch->ik_body.end, pose->b1, q, ch->ik_body.end ); - v3_muladds( ch->ik_body.pole, pose->p, q, ch->ik_body.pole ); - v3_muladds( ch->ik_leg_l.end, pose->fl, q, ch->ik_leg_l.end ); - v3_muladds( ch->ik_leg_l.pole, pose->pl, q, ch->ik_leg_l.pole ); - v3_muladds( ch->ik_leg_r.end, pose->fr, q, ch->ik_leg_r.end ); - v3_muladds( ch->ik_leg_r.pole, pose->pr, q, ch->ik_leg_r.pole ); - v3_muladds( ch->ik_arm_l.pole, pose->apl, q, ch->ik_arm_l.pole ); - v3_muladds( ch->ik_arm_r.pole, pose->apr, q, ch->ik_arm_r.pole ); - v3_muladds( ch->ik_arm_l.end, pose->hl, q, ch->ik_arm_l.end ); - v3_muladds( ch->ik_arm_r.end, pose->hr, q, ch->ik_arm_r.end ); - v3_muladds( ch->cam_pos, pose->cam, q, ch->cam_pos ); -} - -#if 1 -static -void character_final_pose( struct character *ch, v3f cog, - character_pose *pose, float q ) -{ - character_pose npose; - float dip = vg_clampf(cog[1], -1.0f, 0.3f) * 0.5f, - tilt = vg_clampf(cog[2], -1.0f, 1.0f) * 0.3f; - - v4f rz; m4x3f tr; - q_axis_angle( rz, (v3f){0.0f,0.0f,1.0f}, -cog[0]*0.3f ); - q_m3x3( rz, tr ); - m3x3_identity( tr ); - //v3_copy( (v3f){0.0f,dip,tilt}, tr[3] ); - v3_copy( cog, tr[3] ); - - v3_muladd( pose->b0, tr[3], (v3f){0.85f,1.0f,1.0f}, npose.b0 ); - //m4x3_mulv( tr, pose->b0, npose.b0 ); - m4x3_mulv( tr, pose->b1, npose.b1 ); - m4x3_mulv( tr, pose->p, npose.p ); - m4x3_mulv( tr, pose->pl, npose.pl ); - m4x3_mulv( tr, pose->pr, npose.pr ); - m4x3_mulv( tr, pose->hl, npose.hl ); - m4x3_mulv( tr, pose->hr, npose.hr ); - m4x3_mulv( tr, pose->apl, npose.apl ); - m4x3_mulv( tr, pose->apr, npose.apr ); - - v3_copy( pose->fr, npose.fr ); - v3_copy( pose->fl, npose.fl ); - v3_copy( pose->cam, npose.cam ); - - character_pose_blend( ch, &npose, q ); -} -#else -static -void character_final_pose( struct character *ch, v4f rot, - character_pose *pose, float q ) -{ - character_pose npose; - - m4x3f tr; - q_m3x3( rot, tr ); - v3_zero( tr[3] ); - - m4x3_mulv( tr, pose->b0, npose.b0 ); - m4x3_mulv( tr, pose->b1, npose.b1 ); - m4x3_mulv( tr, pose->p, npose.p ); - m4x3_mulv( tr, pose->pl, npose.pl ); - m4x3_mulv( tr, pose->pr, npose.pr ); - m4x3_mulv( tr, pose->hl, npose.hl ); - m4x3_mulv( tr, pose->hr, npose.hr ); - m4x3_mulv( tr, pose->apl, npose.apl ); - m4x3_mulv( tr, pose->apr, npose.apr ); - - v3_copy( pose->fr, npose.fr ); - v3_copy( pose->fl, npose.fl ); - v3_copy( pose->cam, npose.cam ); - - character_pose_blend( ch, &npose, q ); -} -#endif - -static void character_yaw_upper( struct character *ch, float yaw ) -{ - m3x3f r; - v4f q; - - q_axis_angle( q, (v3f){0.0f,1.0f,0.0f}, yaw ); - q_m3x3( q, r ); - - m3x3_mulv( r, ch->ik_body.pole, ch->ik_body.pole ); - m3x3_mulv( r, ch->ik_body.end, ch->ik_body.end ); -} - -static void zero_ik_basic( struct ik_basic *ik ) -{ - v3_zero( ik->base ); - v3_zero( ik->end ); - v3_zero( ik->pole ); -} - -static void character_pose_reset( struct character *ch ) -{ - zero_ik_basic( &ch->ik_body ); - zero_ik_basic( &ch->ik_leg_l ); - zero_ik_basic( &ch->ik_leg_r ); - zero_ik_basic( &ch->ik_arm_l ); - zero_ik_basic( &ch->ik_arm_r ); - v3_zero( ch->cam_pos ); -} - -static void character_testpose( struct character *ch, float t ) -{ - /* Body */ - float *hips = ch->ik_body.base, - *collar = ch->ik_body.end, - *pole = ch->ik_body.pole; - - hips[0] = cosf(t*1.325f)*0.25f; - hips[1] = (sinf(t)*0.2f+0.6f) * ch->origins[ k_chpart_body0 ][1]; - hips[2] = 0.0f; - - collar[0] = hips[0]; - collar[1] = hips[1] + (ch->ik_body.l1+ch->ik_body.l2)*(sinf(t)*0.05f+0.94f); - collar[2] = hips[2] + cosf(t*0.42f)*0.01f; - - v3_add( hips, collar, pole ); - v3_muls( pole, 0.5f, pole ); - v3_add( pole, (v3f){ 1.0f, 0.0f, 0.0f }, pole ); - - /* Legs */ - float *footl = ch->ik_leg_l.end, - *footr = ch->ik_leg_r.end, - *polel = ch->ik_leg_l.pole, - *poler = ch->ik_leg_r.pole; - - footl[0] = sinf(t*0.563f); - footl[1] = 0.0f; - footl[2] = 0.0f; - - footr[0] = 0.0f; - footr[1] = 0.0f; - footr[2] = cosf(t*0.672f); - - v3_add( hips, footl, polel ); - v3_muls( polel, 0.4f, polel ); - v3_add( polel, (v3f){ -1.0f,0.0f,0.0f }, polel ); - - v3_add( hips, footr, poler ); - v3_muls( poler, 0.4f, poler ); - v3_add( poler, (v3f){ -1.0f,0.0f,0.0f }, poler ); - - /* Arms */ - float *arml = ch->ik_arm_l.end, - *armr = ch->ik_arm_r.end; - polel = ch->ik_arm_l.pole; - poler = ch->ik_arm_r.pole; - - v3_copy( (v3f){ 0.0f, 0.0f, 1.0f }, arml ); - v3_copy( (v3f){ 0.0f, 0.0f,-1.0f }, armr ); - v3_copy( (v3f){ 1.0f, 1.0f, 0.5f }, polel ); - v3_copy( (v3f){ 1.0f, 1.0f,-0.5f }, poler ); - - /* Other */ - ch->rhip = sinf(t*0.2f); - ch->rcollar = sinf(t*0.35325f); - q_identity( ch->qhead ); - - m4x3_identity( ch->matrices[k_chpart_board] ); - m4x3_identity( ch->matrices[k_chpart_wb] ); - m4x3_identity( ch->matrices[k_chpart_wf] ); -} - -static void character_draw( struct character *ch, float temp, m4x3f camera ) -{ - shader_character_use(); - shader_character_uPv( vg_pv ); - - vg_tex2d_bind( &tex_pallet, 0 ); - shader_character_uTexMain( 0 ); - shader_character_uOpacity( temp ); - shader_character_uCamera( camera[3] ); - shader_link_standard_ub( _shader_character.id, 2 ); - - glEnable( GL_CULL_FACE ); - glCullFace( GL_BACK ); - - mesh_bind( &ch->mesh ); - - for( int i=4; imatrices[i] ); - mdl_draw_submesh( &ch->parts[i] ); - } - - for( int i=0; i<2; i++ ) - { - if( ch->shoes[i] ) - { - shader_character_uMdl( ch->matrices[i] ); - mdl_draw_submesh( &ch->parts[i] ); - } - else - { - shader_character_uMdl( ch->matrices[i+2] ); - mdl_draw_submesh( &ch->parts[i] ); - shader_character_uMdl( ch->matrices[i] ); - mdl_draw_submesh( &ch->parts[i+2] ); - } - } -} - -/* - * Ragdoll Stuff - */ - -static void character_rd_box( struct character *ch, enum character_part id, - v3f dims ) -{ - v3_muls( dims, -0.5f, ch->ragdoll[id].bbx[0] ); - v3_muls( dims, 0.5f, ch->ragdoll[id].bbx[1] ); -} - -struct rd_joint -{ - enum character_part ia, ib; - v3f lca, lcb; - - struct rd_joint_axis - { - v3f va, vb; - float spring, ang; - } - min, maj; -}; - -static const float k_human_major = 0.5f, - k_human_minor = 0.5f, - k_human_major_max = 0.4f, - k_human_minor_max = 0.1f; - -#define HUMAN_VERTICAL_DEFAULT \ -.min = { \ - .va = {1.0f,0.0f,0.0f}, .vb = {1.0f,0.0f,0.0f}, \ - .spring = k_human_minor, .ang = k_human_minor_max \ -}, \ -.maj = { \ - .va = {0.0f,1.0f,0.0f}, .vb = {0.0f,1.0f,0.0f}, \ - .spring = k_human_major, .ang = k_human_major_max \ -} - -#define HUMAN_ARM_LEFT \ -.min = { \ - .va = {1.0f,0.0f,0.0f}, .vb = {1.0f,0.0f,0.0f}, \ - .spring = k_human_minor, .ang = k_human_minor_max \ -}, \ -.maj = { \ - .va = {0.0f,0.0f,1.0f}, .vb = {0.0f,0.0f,1.0f}, \ - .spring = k_human_major, .ang = k_human_major_max \ -} - -#define HUMAN_ARM_RIGHT \ -.min = { \ - .va = {1.0f,0.0f,0.0f}, .vb = {1.0f,0.0f,0.0f}, \ - .spring = k_human_minor, .ang = k_human_minor_max \ -}, \ -.maj = { \ - .va = {0.0f,0.0f,-1.0f}, .vb = {0.0f,0.0f,-1.0f}, \ - .spring = k_human_major, .ang = k_human_major_max \ -} - -static struct rd_joint rd_joints[] = -{ - { .ia = k_chpart_leg_l1, .ib = k_chpart_foot_l, HUMAN_VERTICAL_DEFAULT }, - { .ia = k_chpart_leg_r1, .ib = k_chpart_foot_r, HUMAN_VERTICAL_DEFAULT }, - - { .ia = k_chpart_body0, .ib = k_chpart_body1, HUMAN_VERTICAL_DEFAULT }, - { .ia = k_chpart_body1, .ib = k_chpart_neck, HUMAN_VERTICAL_DEFAULT }, - { .ia = k_chpart_neck, .ib = k_chpart_head, HUMAN_VERTICAL_DEFAULT }, - { .ia = k_chpart_body0, .ib = k_chpart_leg_l0, HUMAN_VERTICAL_DEFAULT }, - { .ia = k_chpart_leg_l0, .ib = k_chpart_leg_l1, HUMAN_VERTICAL_DEFAULT }, - { .ia = k_chpart_body0, .ib = k_chpart_leg_r0, HUMAN_VERTICAL_DEFAULT }, - { .ia = k_chpart_leg_r0, .ib = k_chpart_leg_r1, HUMAN_VERTICAL_DEFAULT }, - - { .ia = k_chpart_body1, .ib = k_chpart_arm_l0, HUMAN_ARM_LEFT }, - { .ia = k_chpart_arm_l0, .ib = k_chpart_arm_l1, HUMAN_ARM_LEFT }, - { .ia = k_chpart_arm_l1, .ib = k_chpart_hand_l, HUMAN_ARM_LEFT }, - - { .ia = k_chpart_body1, .ib = k_chpart_arm_r0, HUMAN_ARM_RIGHT }, - { .ia = k_chpart_arm_r0, .ib = k_chpart_arm_r1, HUMAN_ARM_RIGHT }, - { .ia = k_chpart_arm_r1, .ib = k_chpart_hand_r, HUMAN_ARM_RIGHT } -}; - -/* Ragdoll should be in rest pose when calling this function */ -static void character_init_ragdoll_joints( struct character *ch ) -{ - for( int i=0; iorigins[joint->ib]; - v3_sub( hinge, ch->ragdoll[joint->ia].co, joint->lca ); - v3_sub( hinge, ch->ragdoll[joint->ib].co, joint->lcb ); - } - - for( int i=0; iorigins[i]; - v3_sub( ch->ragdoll[i].co, pivot, ch->ragdoll[i].delta ); - } -} - -static void character_init_ragdoll( struct character *ch ) -{ - v3f *offs = ch->offsets; - rigidbody *rbs = ch->ragdoll; - - /* CHest */ - float chest_width = fabsf(offs[k_chpart_arm_r0][2])*2.0f, - chest_depth = chest_width * 0.571f, - chest_height = offs[k_chpart_neck][1]; - v3f chest_dims = { chest_depth, chest_height, chest_width }; - character_rd_box( ch, k_chpart_body1, chest_dims ); - - v3_copy( ch->origins[k_chpart_body1], rbs[k_chpart_body1].co ); - rbs[k_chpart_body1].co[1] += chest_height*0.5f; - - /* Torso */ - v3f torso_dims = { chest_depth, - offs[k_chpart_body1][1]-offs[k_chpart_leg_l0][1], - chest_width*0.85f }; - v3_copy( ch->origins[k_chpart_body0], rbs[k_chpart_body0].co ); - character_rd_box( ch, k_chpart_body0, torso_dims ); - - /* Neck */ - v3f neck_dims = { chest_depth*0.5f, - offs[k_chpart_head][1], - chest_depth*0.5f }; - v3_copy( ch->origins[k_chpart_neck], rbs[k_chpart_neck].co ); - rbs[k_chpart_neck].co[1] += neck_dims[1]*0.5f; - character_rd_box( ch, k_chpart_neck, neck_dims ); - - /* Head */ - v3f head_dims = { chest_width*0.5f, chest_width*0.5f, chest_width*0.5f }; - v3_copy( ch->origins[k_chpart_head], rbs[k_chpart_head].co ); - rbs[k_chpart_head].co[1] += head_dims[1]*0.5f; - character_rd_box( ch, k_chpart_head, head_dims ); - - /* ARms */ - v3f ua_dims = { 0.0f, 0.0f, fabsf(offs[k_chpart_arm_l1][2]) }; - ua_dims[1] = 0.38f*ua_dims[2]; - ua_dims[0] = 0.38f*ua_dims[2]; - v3f la_dims = { ua_dims[0], ua_dims[1], fabsf(offs[k_chpart_hand_l][2]) }; - v3f hand_dims = { ua_dims[1], ua_dims[1]*0.5f, ua_dims[1] }; - - character_rd_box( ch, k_chpart_arm_l0, ua_dims ); - character_rd_box( ch, k_chpart_arm_r0, ua_dims ); - character_rd_box( ch, k_chpart_arm_l1, la_dims ); - character_rd_box( ch, k_chpart_arm_r1, la_dims ); - character_rd_box( ch, k_chpart_hand_l, hand_dims ); - character_rd_box( ch, k_chpart_hand_r, hand_dims ); - - v3_copy( ch->origins[k_chpart_arm_l0], rbs[k_chpart_arm_l0].co ); - rbs[k_chpart_arm_l0].co[2] += ua_dims[2] * 0.5f; - v3_copy( ch->origins[k_chpart_arm_l1], rbs[k_chpart_arm_l1].co ); - rbs[k_chpart_arm_l1].co[2] += la_dims[2] * 0.5f; - v3_copy( ch->origins[k_chpart_hand_l], rbs[k_chpart_hand_l].co ); - rbs[k_chpart_hand_l].co[2] += hand_dims[2] * 0.5f; - - v3_copy( ch->origins[k_chpart_arm_r0], rbs[k_chpart_arm_r0].co ); - rbs[k_chpart_arm_r0].co[2] -= ua_dims[2] * 0.5f; - v3_copy( ch->origins[k_chpart_arm_r1], rbs[k_chpart_arm_r1].co ); - rbs[k_chpart_arm_r1].co[2] -= la_dims[2] * 0.5f; - v3_copy( ch->origins[k_chpart_hand_r], rbs[k_chpart_hand_r].co ); - rbs[k_chpart_hand_r].co[2] -= hand_dims[2] * 0.5f; - - /* LEgs */ - v3f ul_dims = { 0.0f, fabsf(offs[k_chpart_leg_l1][1]), 0.0f }; - ul_dims[0] = 0.38f*ul_dims[1]; - ul_dims[2] = 0.38f*ul_dims[1]; - v3f ll_dims = { ul_dims[0], fabsf(offs[k_chpart_foot_l][1]), ul_dims[2] }; - v3f foot_dims = { 2.0f*ul_dims[0], ul_dims[0], ul_dims[0] }; - - character_rd_box( ch, k_chpart_leg_l0, ul_dims ); - character_rd_box( ch, k_chpart_leg_r0, ul_dims ); - character_rd_box( ch, k_chpart_leg_l1, ll_dims ); - character_rd_box( ch, k_chpart_leg_r1, ll_dims ); - character_rd_box( ch, k_chpart_foot_l, foot_dims ); - character_rd_box( ch, k_chpart_foot_r, foot_dims ); - - v3_copy( ch->origins[k_chpart_leg_l0], rbs[k_chpart_leg_l0].co ); - rbs[k_chpart_leg_l0].co[1] -= ul_dims[1] * 0.5f; - v3_copy( ch->origins[k_chpart_leg_l1], rbs[k_chpart_leg_l1].co ); - rbs[k_chpart_leg_l1].co[1] -= ll_dims[1] * 0.5f; - v3_copy( ch->origins[k_chpart_foot_l], rbs[k_chpart_foot_l].co ); - rbs[k_chpart_foot_l].co[1] -= foot_dims[1] * 0.5f; - rbs[k_chpart_foot_l].co[0] -= foot_dims[0] * 0.5f; - - v3_copy( ch->origins[k_chpart_leg_r0], rbs[k_chpart_leg_r0].co ); - rbs[k_chpart_leg_r0].co[1] -= ul_dims[1] * 0.5f; - v3_copy( ch->origins[k_chpart_leg_r1], rbs[k_chpart_leg_r1].co ); - rbs[k_chpart_leg_r1].co[1] -= ll_dims[1] * 0.5f; - v3_copy( ch->origins[k_chpart_foot_r], rbs[k_chpart_foot_r].co ); - rbs[k_chpart_foot_r].co[1] -= foot_dims[1] * 0.5f; - rbs[k_chpart_foot_r].co[0] -= foot_dims[0] * 0.5f; - - character_rd_box( ch, k_chpart_sock_l, foot_dims ); - character_rd_box( ch, k_chpart_sock_r, foot_dims ); - v3_copy( rbs[k_chpart_foot_l].co, rbs[k_chpart_sock_l].co ); - v3_copy( rbs[k_chpart_foot_r].co, rbs[k_chpart_sock_r].co ); - - box_copy( (boxf){{-0.2f,-0.2f,-0.7f},{0.2f,0.2f,0.7f}}, - rbs[k_chpart_board].bbx ); - - for( int i=0; iragdoll[i] ); - - character_init_ragdoll_joints( ch ); -} - -static void character_ragdoll_go( struct character *ch, v3f pos ) -{ - character_init_ragdoll( ch ); - for( int i=0; iragdoll[i].co, ch->ragdoll[i].co ); -} - -static void character_ragdoll_copypose( struct character *ch, v3f v ) -{ - for( int i=0; iragdoll[i]; - - m4x3_mulv( ch->matrices[i], rb->delta, rb->co ); - m3x3_q( ch->matrices[i], rb->q ); - v3_copy( v, rb->v ); - v3_zero( rb->w ); - - rb_update_transform( rb ); - } - - float vel = v3_length(v); - - ch->shoes[0] = 1; - ch->shoes[1] = 1; -} - -static void character_mimic_ragdoll( struct character *ch ) -{ - for( int i=0; iragdoll[i]; - v3f *mat = ch->matrices[i]; - - m3x3_copy( rb->to_world, mat ); - v3f inv_delta; - v3_negate( rb->delta, inv_delta ); - m4x3_mulv( rb->to_world, inv_delta, mat[3] ); - } - - /* Attach wheels to board */ - m3x3_copy( ch->matrices[k_chpart_board], ch->matrices[k_chpart_wb] ); - m3x3_copy( ch->matrices[k_chpart_board], ch->matrices[k_chpart_wf] ); - m4x3_mulv( ch->matrices[k_chpart_board], ch->offsets[k_chpart_wb], - ch->matrices[k_chpart_wb][3] ); - m4x3_mulv( ch->matrices[k_chpart_board], ch->offsets[k_chpart_wf], - ch->matrices[k_chpart_wf][3] ); -} - -static void character_debug_ragdoll( struct character *ch ) -{ - rb_debug( &ch->ragdoll[k_chpart_body0], 0xffffffff ); - rb_debug( &ch->ragdoll[k_chpart_body1], 0xffffffff ); - rb_debug( &ch->ragdoll[k_chpart_neck], 0xff00ff00 ); - rb_debug( &ch->ragdoll[k_chpart_head], 0xff00ff00 ); - - rb_debug( &ch->ragdoll[k_chpart_arm_l0], 0xffffa500 ); - rb_debug( &ch->ragdoll[k_chpart_arm_l1], 0xffffa500 ); - rb_debug( &ch->ragdoll[k_chpart_hand_l], 0xffffa500 ); - - rb_debug( &ch->ragdoll[k_chpart_arm_r0], 0xff00a5ff ); - rb_debug( &ch->ragdoll[k_chpart_arm_r1], 0xff00a5ff ); - rb_debug( &ch->ragdoll[k_chpart_hand_r], 0xff00a5ff ); - - rb_debug( &ch->ragdoll[k_chpart_leg_l0], 0xffffa500 ); - rb_debug( &ch->ragdoll[k_chpart_leg_l1], 0xffffa500 ); - rb_debug( &ch->ragdoll[k_chpart_foot_l], 0xffffa500 ); - rb_debug( &ch->ragdoll[k_chpart_leg_r0], 0xff00a5ff ); - rb_debug( &ch->ragdoll[k_chpart_leg_r1], 0xff00a5ff ); - rb_debug( &ch->ragdoll[k_chpart_foot_r], 0xff00a5ff ); -} - -static void character_ragdoll_iter( struct character *ch ) -{ - rb_solver_reset(); - - for( int i=0; iragdoll[i], &world.rb_geo ); - } - - rb_presolve_contacts( rb_contact_buffer, rb_contact_count ); - - v3f rv; - - float shoe_vel[2] = {0.0f,0.0f}; - for( int i=0; i<2; i++ ) - if( ch->shoes[i] ) - shoe_vel[i] = v3_length( ch->ragdoll[i].v ); - - /* This used to be 20 iterations */ - for( int i=0; i<10; i++ ) - { - float const k_springfactor = 1.0f/20.0f; - - rb_solve_contacts( rb_contact_buffer, rb_contact_count ); - - for( int j=0; jragdoll[joint->ia], - *rbb = &ch->ragdoll[joint->ib]; - - rb_constraint_position( rba, joint->lca, rbb, joint->lcb ); - rb_constraint_angle( rba, joint->maj.va, rbb, joint->maj.vb, - joint->maj.ang, - joint->maj.spring * k_springfactor ); - - rb_constraint_angle( rba, joint->min.va, rbb, joint->min.vb, - joint->min.ang, - joint->min.spring * k_springfactor ); - } - } - - for( int j=0; jragdoll[joint->ia], - *rbb = &ch->ragdoll[joint->ib]; - rb_angle_limit_force( rba, joint->min.va, rbb, joint->min.vb, - joint->min.ang ); - rb_angle_limit_force( rba, joint->maj.va, rbb, joint->maj.vb, - joint->maj.ang ); - } - - for( int i=0; iragdoll[i] ); - - for( int i=0; i<2; i++ ) - { - if( ch->shoes[i] ) - { - float a = v3_length( ch->ragdoll[i].v ) - shoe_vel[i]; - - if( a > 2.0f ) - { - ch->shoes[i] = 0; - - rigidbody *src = &ch->ragdoll[k_chpart_foot_l]; - rigidbody *dst = &ch->ragdoll[k_chpart_sock_l]; - - v3_copy( src->co, dst->co ); - v3_copy( src->v, dst->v ); - v3_copy( src->q, dst->q ); - v3_copy( src->w, dst->w ); - } - } - } - - for( int i=0; iragdoll[i] ); -} - -#endif diff --git a/common.h b/common.h index e4015a8..fa22207 100644 --- a/common.h +++ b/common.h @@ -49,4 +49,5 @@ static void eval_bezier_time( v3f p0, v3f p1, v3f h0, v3f h1, float t, v3f p ) static int network_scores_updated = 0; + #endif /* COMMON_H */ diff --git a/gate.h b/gate.h deleted file mode 100644 index fec2826..0000000 --- a/gate.h +++ /dev/null @@ -1,260 +0,0 @@ -#ifndef GATE_H -#define GATE_H - -#include "common.h" -#include "model.h" -#include "render.h" -#include "shaders/gate.h" -#include "shaders/gatelq.h" -#include "world_water.h" - -typedef struct teleport_gate teleport_gate; - -static struct -{ - struct framebuffer fb; - glmesh mdl; - - int high_qual; /* If in high performance mode, we don't use RT's, and - instead use stencil buffers. - There is therefore no heat warp effect. */ -} -grender = -{ - .high_qual = 0, - .fb = { - .format = GL_RGB, - .div = 1 - } -}; - -struct teleport_gate -{ - v3f co[2]; - v4f q[2]; - v2f dims; - - m4x3f to_world, recv_to_world, transport; -}; - -static void gate_transform_update( teleport_gate *gate ) -{ - m4x3f to_local; - - q_m3x3( gate->q[0], gate->to_world ); - v3_copy( gate->co[0], gate->to_world[3] ); - - m4x3_invert_affine( gate->to_world, to_local ); - - q_m3x3( gate->q[1], gate->recv_to_world ); - v3_copy( gate->co[1], gate->recv_to_world[3] ); - m4x3_mul( gate->recv_to_world, to_local, gate->transport ); -} - -static void gate_register(void) -{ - shader_gate_register(); - shader_gatelq_register(); -} - -static void gate_init(void) -{ - fb_init( &grender.fb ); - - mdl_header *mgate = mdl_load( "models/rs_gate.mdl" ); - mdl_unpack_glmesh( mgate, &grender.mdl ); - free( mgate ); -} - -static void gate_fb_resize(void) -{ - fb_resize( &grender.fb ); -} - -static int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera ) -{ - v3f viewdir, gatedir; - m3x3_mulv( camera, (v3f){0.0f,0.0f,-1.0f}, viewdir ); - m3x3_mulv( gate->to_world, (v3f){0.0f,0.0f,-1.0f}, gatedir ); - - v3f v0; - v3_sub( viewpos, gate->co[0], v0 ); - if( v3_dot(v0, gatedir) >= 0.0f ) - return 0; - - if( v3_dist( viewpos, gate->co[0] ) > 100.0f ) - return 0; - - v3f a,b,c,d; - - float sx = gate->dims[0], - sy = gate->dims[1]; - m4x3_mulv( gate->to_world, (v3f){-sx,-sy,0.0f}, a ); - m4x3_mulv( gate->to_world, (v3f){ sx,-sy,0.0f}, b ); - m4x3_mulv( gate->to_world, (v3f){ sx, sy,0.0f}, c ); - m4x3_mulv( gate->to_world, (v3f){-sx, sy,0.0f}, d ); - - vg_line( a,b, 0xffffa000 ); - vg_line( b,c, 0xffffa000 ); - vg_line( c,d, 0xffffa000 ); - vg_line( d,a, 0xffffa000 ); - - vg_line2( gate->co[0], gate->co[1], 0xff0000ff, 0x00000000 ); - - m4x3f cam_new; - m4x3_mul( gate->transport, camera, cam_new ); - - vg_line_pt3( cam_new[3], 0.3f, 0xff00ff00 ); - - m4x3f gate_xform; - m4x3_copy( gate->to_world, gate_xform ); - m4x3_scalev( gate_xform, (v3f){ gate->dims[0], gate->dims[1], 1.0f } ); - - m4x3f inverse; - m4x3_invert_affine( cam_new, inverse ); - - m4x4f view; - m4x3_expand( inverse, view ); - - v4f surface; - m3x3_mulv( gate->recv_to_world, (v3f){0.0f,0.0f,-1.0f}, surface ); - surface[3] = v3_dot( surface, gate->co[1] ); - - m4x4f projection; - pipeline_projection( projection, 0.1f, 900.0f ); - - m4x3_mulp( inverse, surface, surface ); - surface[3] = -fabsf(surface[3]); - plane_clip_projection( projection, surface ); - - m4x4_mul( projection, view, projection ); - - if( grender.high_qual ) - { - fb_use( &grender.fb ); - glClearColor( 0.11f, 0.35f, 0.37f, 1.0f ); - glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); - } - else - { - shader_gatelq_use(); - shader_gatelq_uPv( vg_pv ); - shader_gatelq_uMdl( gate_xform ); - shader_gatelq_uCam( viewpos ); - shader_gatelq_uTime( vg_time*0.25f ); - shader_gatelq_uInvRes( (v2f){ - 1.0f / (float)vg_window_x, - 1.0f / (float)vg_window_y }); - - glEnable( GL_STENCIL_TEST ); - glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE ); - glStencilFunc( GL_ALWAYS, 1, 0xFF ); - glStencilMask( 0xFF ); - - mesh_bind( &grender.mdl ); - mesh_draw( &grender.mdl ); - - glClear( GL_DEPTH_BUFFER_BIT ); - glStencilFunc( GL_EQUAL, 1, 0xFF ); - glStencilMask( 0x00 ); - } - - render_world( projection, cam_new ); - - if( grender.high_qual ) - { - /* - * TODO: Need to find a way to draw a stencil buffer into the water - * rendering - */ - - render_water_texture( cam_new ); - fb_use( &grender.fb ); - - render_water_surface( projection, cam_new ); - fb_use( NULL ); - - shader_gate_use(); - - shader_gate_uPv( vg_pv ); - shader_gate_uMdl( gate_xform ); - - fb_bindtex( &grender.fb, 0 ); - - shader_gate_uCam( viewpos ); - shader_gate_uTexMain( 0 ); - shader_gate_uTexWater( 1 ); - shader_gate_uTime( vg_time*0.25f ); - shader_gate_uInvRes( (v2f){ - 1.0f / (float)vg_window_x, - 1.0f / (float)vg_window_y }); - - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); - glBlendEquation(GL_FUNC_ADD); - - mesh_bind( &grender.mdl ); - mesh_draw( &grender.mdl ); - - glDisable(GL_BLEND); - } - else - { - glDisable( GL_STENCIL_TEST ); - - render_water_texture( cam_new ); - fb_use( NULL ); - glEnable( GL_STENCIL_TEST ); - - render_water_surface( projection, cam_new ); - - glStencilMask( 0xFF ); - glStencilFunc( GL_ALWAYS, 1, 0xFF ); - glDisable( GL_STENCIL_TEST ); - } - - return 1; -} - -static int gate_intersect( teleport_gate *gate, v3f pos, v3f last ) -{ - v4f surface; - m3x3_mulv( gate->to_world, (v3f){0.0f,0.0f,-1.0f}, surface ); - surface[3] = v3_dot( surface, gate->co[0] ); - - v3f v0, c, delta, p0; - v3_sub( pos, last, v0 ); - float l = v3_length( v0 ); - v3_divs( v0, l, v0 ); - - v3_muls( surface, surface[3], c ); - v3_sub( c, last, delta ); - - float d = v3_dot(surface, v0); - - if( d > 0.00001f ) - { - float t = v3_dot(delta, surface) / d; - if( t >= 0.0f && t <= l ) - { - v3f local, rel; - v3_muladds( last, v0, t, local ); - v3_sub( gate->co[0], local, rel ); - - v3f vup, vside; - m3x3_mulv( gate->to_world, (v3f){0.0f,1.0f,0.0f}, vup ); - m3x3_mulv( gate->to_world, (v3f){1.0f,0.0f,0.0f}, vside ); - - v2f xy = { v3_dot( rel, vside ), v3_dot( rel, vup ) }; - - if( fabsf(xy[0]) <= gate->dims[0] && fabsf(xy[1]) <= gate->dims[1] ) - { - return 1; - } - } - } - - return 0; -} - -#endif diff --git a/highscores.h b/highscores.h index 2c077b1..78db2ad 100644 --- a/highscores.h +++ b/highscores.h @@ -243,7 +243,7 @@ static int highscores_init( u32 pool_size, u32 playerinfo_pool_size ) } else { - vg_log( "No existing database found (.aadb)\n" ); + vg_low( "No existing database found (.aadb)\n" ); vg_info( "Initializing database nodes\n" ); memset( &sys->dbheader, 0, sizeof(highscore_database) ); @@ -315,7 +315,7 @@ static aatree_ptr highscores_push_record( highscore_record *record ) struct highscore_system *sys = &highscore_system; /* TODO: Verify steam ID */ - vg_log( "Inserting record into database for track %hu\n",record->trackid ); + vg_low( "Inserting record into database for track %hu\n",record->trackid ); if( record->trackid >= vg_list_size(sys->dbheader.tracks) ) { @@ -339,11 +339,11 @@ static aatree_ptr highscores_push_record( highscore_record *record ) if( crecord->time < record->time || (crecord->time == record->time && crecord->points > record->points)) { - vg_log( "Not overwriting better score\n" ); + vg_low( "Not overwriting better score\n" ); return existing; } - vg_log( "Freeing existing record for player %lu\n", record->playerid ); + vg_low( "Freeing existing record for player %lu\n", record->playerid ); table->root_playerid = aatree_del( &sys->aainfo_playerid, existing ); table->root_datetime = aatree_del( &sys->aainfo_datetime, existing ); table->root_points = aatree_del( &sys->aainfo_points, existing ); @@ -389,7 +389,7 @@ static aatree_ptr highscore_set_user_nickname( u64 steamid, char nick[10] ) name[i] = nick[i]; name[10] = '\0'; - vg_log( "Updating %lu's nickname -> %s\n", steamid, name ); + vg_low( "Updating %lu's nickname -> %s\n", steamid, name ); struct highscore_system *sys = &highscore_system; diff --git a/main.c b/main.c index e967bcf..fb53847 100644 --- a/main.c +++ b/main.c @@ -1,146 +1,47 @@ /* - * Copyright 2021-2022 (C) Mount0 Software, Harry Godden - All Rights Reserved + * ============================================================================= * - * module.h structure definitions - * module_submodule.h implementation - * module_submodule_2.h + * Copyright . . . -----, ,----- ,---. .---. + * 2021-2022 |\ /| | / | | | | /| + * | \ / | +-- / +----- +---' | / | + * | \ / | | / | | \ | / | + * | \/ | | / | | \ | / | + * ' ' '--' [] '----- '----- ' ' '---' SOFTWARE + * + * ============================================================================= + * + * register: shader register & init scheduling + * init: initialization + * update: logic + * render: graphics + * free: resource free + * */ -#include "common.h" - -/* Resources */ -vg_tex2d tex_norwey = { .path = "textures/norway_foliage.qoi" }; -vg_tex2d tex_grid = { .path = "textures/grid.qoi" }; -vg_tex2d tex_sky = { .path = "textures/sky.qoi" }; -vg_tex2d tex_gradients = { .path = "textures/gradients.qoi", - .flags = VG_TEXTURE_CLAMP }; -vg_tex2d tex_cement = { .path = "textures/cement512.qoi" }; -vg_tex2d tex_water = { .path = "textures/water.qoi" }; - -/* Convars */ -static int debugview = 0; -static int sv_debugcam = 0; -static int lightedit = 0; -static int sv_scene = 0; -static int cl_ui = 1; - -/* Components */ #define SR_NETWORKED - -/* uncomment this to run the game without any graphics being drawn */ -//#define SR_NETWORK_TEST - +#define VG_3D +#include "common.h" #include "steam.h" -#include "network.h" - -#include "model.h" -//#include "road.h" -#include "scene.h" -//#include "ik.h" -#include "audio.h" -//#include "terrain.h" -//#include "character.h" -#include "ragdoll.h" -#include "rigidbody.h" #include "render.h" +#include "audio.h" #include "world.h" #include "player.h" -#include "shaders/blit.h" -#include "shaders/standard.h" -#include "shaders/unlit.h" - -#include "physics_test.h" -#include "anim_test.h" - -#include "gate.h" - -void vg_register(void) -{ - shader_blit_register(); - shader_standard_register(); - shader_vblend_register(); - shader_unlit_register(); - - player_register(); - world_register(); - gate_register(); -} - -static void init_other(void) -{ - player_init(); - render_init(); - gate_init(); - world_init(); - audio_init(); -} - -vg_tex2d *texture_list[] = -{ - &tex_norwey, - &tex_gradients, - &tex_grid, - &tex_sky, - &tex_cement, - &tex_water, - &tex_water_surf -}; +static int cl_ui = 1; int main( int argc, char *argv[] ) { - highscores_init( 2000, 50 ); - vg_init( argc, argv, "Voyager Game Engine" ); + vg_enter( argc, argv, "Voyager Game Engine" ); } -static int playermodel( int argc, char const *argv[] ) +static void highscores_save_at_exit(void*_) { - if( argc < 1 ) return 0; - - glmesh old_mesh = player.mdl.mesh; - - if( player_load_model( argv[0] ) ) - mesh_free( &old_mesh ); - - return 1; + highscores_serialize_all(); + highscores_free(); } -void vg_start(void) +int vg_preload(void) { - steam_init(); - - vg_convar_push( (struct vg_convar){ - .name = "fc", - .data = &freecam, - .data_type = k_convar_dtype_i32, - .opt_i32 = { .min=0, .max=1, .clamp=1 }, - .persistent = 1 - }); - - vg_convar_push( (struct vg_convar){ - .name = "grid", - .data = &walk_grid_iterations, - .data_type = k_convar_dtype_i32, - .opt_i32 = { .min=0, .max=1, .clamp=0 }, - .persistent = 1 - }); - - vg_convar_push( (struct vg_convar){ - .name = "fcs", - .data = &fc_speed, - .data_type = k_convar_dtype_f32, - .opt_f32 = { .clamp = 0 }, - .persistent = 1 - }); - - vg_convar_push( (struct vg_convar){ - .name = "ledit", - .data = &lightedit, - .data_type = k_convar_dtype_i32, - .opt_i32 = { .min=0, .max=1, .clamp=1 }, - .persistent = 1 - }); - vg_convar_push( (struct vg_convar){ .name = "cl_ui", .data = &cl_ui, @@ -149,141 +50,76 @@ void vg_start(void) .persistent = 1 }); - vg_convar_push( (struct vg_convar){ - .name = "walk_speed", - .data = &k_walkspeed, - .data_type = k_convar_dtype_f32, - .opt_f32 = { .clamp = 0 }, - .persistent = 1 - }); +vg_info(" Copyright . . . -----, ,----- ,---. .---. " ); +vg_info(" 2021-2022 |\\ /| | / | | | | /| " ); +vg_info(" | \\ / | +-- / +----- +---' | / | " ); +vg_info(" | \\ / | | / | | \\ | / | " ); +vg_info(" | \\/ | | / | | \\ | / | " ); +vg_info(" ' ' '--' [] '----- '----- ' ' '---' " + "SOFTWARE" ); - vg_convar_push( (struct vg_convar){ - .name = "run_speed", - .data = &k_runspeed, - .data_type = k_convar_dtype_f32, - .opt_f32 = { .clamp = 0 }, - .persistent = 1 - }); + highscores_init( 2000, 50 ); + if( !vg_loader_highwater( highscores_save_at_exit, NULL ) ) return 0; - vg_convar_push( (struct vg_convar){ - .name = "walk_accel", - .data = &k_walk_accel, - .data_type = k_convar_dtype_f32, - .opt_f32 = { .clamp = 0 }, - .persistent = 1 - }); + vg_sleep_ms(200); - vg_convar_push( (struct vg_convar){ - .name = "rd_floaty", - .data = &k_ragdoll_floatyiness, - .data_type = k_convar_dtype_f32, - .opt_f32 = { .clamp = 0 }, - .persistent = 1 - }); + if( !steam_init() ) return 0; + if( !vg_loader_highwater( steam_end, NULL ) ) return 0; - vg_convar_push( (struct vg_convar){ - .name = "rd_floatd", - .data = &k_ragdoll_floatydrag, - .data_type = k_convar_dtype_f32, - .opt_f32 = { .clamp = 0 }, - .persistent = 1 - }); + if( !network_init() ) return 0; + if( !vg_loader_highwater( network_end, NULL ) ) return 0; - vg_convar_push( (struct vg_convar){ - .name = "dt", - .data = &ktimestep, - .data_type = k_convar_dtype_f32, - .opt_f32 = { .clamp = 0 }, - .persistent = 0 - }); + return 1; +} - vg_convar_push( (struct vg_convar){ - .name = "debugcam", - .data = &sv_debugcam, - .data_type = k_convar_dtype_i32, - .opt_i32 = { .min=0, .max=1, .clamp=0 }, - .persistent = 1 - }); +int vg_load(void) +{ + if( !render_init() ) return 0; + if( !vg_loader_highwater( render_free, NULL ) ) return 0; - vg_convar_push( (struct vg_convar){ - .name = "debugview", - .data = &debugview, - .data_type = k_convar_dtype_i32, - .opt_i32 = { .min=0, .max=1, .clamp=0 }, - .persistent = 1 - }); + if( !world_init() ) return 0; - vg_function_push( (struct vg_cmd){ - .name = "reset", - .function = reset_player - }); + if( !player_init() ) return 0; + if( !vg_loader_highwater( player_model_free, NULL ) ) return 0; - vg_tex2d_init( texture_list, vg_list_size( texture_list ) ); - - init_other(); - /* - * If we're in physics test mode we dont need to load anything else, this - * parameter is dev only. TODO: dev only cvars that don't ship with the game - * when building in release mode. - */ - if( sv_scene == 0 ) - { - player_load_model( "ch_new" ); + if( !vg_bake_shaders() ) return 0; - world_load(); - reset_player( 1, (const char *[]){ "start" } ); - rb_init( &player.phys.rb ); + if( !audio_init() ) return 0; + if( !vg_loader_highwater( audio_free, NULL ) ) return 0; - network_init(); - } - else if( sv_scene == 1 ) - { - physics_test_start(); - } - else if( sv_scene == 2 ) - { - anim_test_start(); - } + /* FInal step */ + world_load(); + vg_console_load_autos(); + + return 1; } -void vg_free(void) +static void vg_start(void) { - network_end(); - vg_tex2d_free( texture_list, vg_list_size(texture_list) ); - /* TODO: THE REST OF THE GOD DAMN FREEING STUFF */ - steam_end(); + player_load_model( "ch_new" ); + reset_player( 1, (const char *[]){ "start" } ); +} - highscores_serialize_all(); - highscores_free(); +static void draw_origin_axis(void) +{ + vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 ); + vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 ); + vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff ); } -void vg_update(void) +void vg_update( int loaded ) { steam_update(); - if( sv_scene == 0 ) + if( loaded ) { + draw_origin_axis(); network_update(); player_update(); world_update( player.phys.rb.co ); - //traffic_visualize( world.traffic, world.traffic_count ); - // - /* TEMP */ - if( glfwGetKey( vg_window, GLFW_KEY_J )) - { - v3_copy( player.camera_pos, world.mr_ball.co ); - } - } - else if( sv_scene == 1 ) - { - physics_test_update(); - } - else if( sv_scene == 2 ) - { - anim_test_update(); } } @@ -294,18 +130,14 @@ static void vg_framebuffer_resize( int w, int h ) water_fb_resize(); } -static void draw_origin_axis(void) -{ - vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 1.0f, 0.0f, 0.0f }, 0xffff0000 ); - vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 1.0f, 0.0f }, 0xff00ff00 ); - vg_line( (v3f){ 0.0f, 0.0f, 0.0f }, (v3f){ 0.0f, 0.0f, 1.0f }, 0xff0000ff ); -} - static void render_main_game(void) { + /* TODO Breakup this & Gen */ +#if 0 float speed = freecam? 0.0f: v3_length( player.phys.rb.v ); v3f shake = { vg_randf()-0.5f, vg_randf()-0.5f, vg_randf()-0.5f }; v3_muls( shake, speed*0.01f, shake ); +#endif m4x4f world_4x4; m4x3_expand( player.camera_inverse, world_4x4 ); @@ -333,7 +165,6 @@ static void render_main_game(void) glBindFramebuffer( GL_FRAMEBUFFER, 0 ); render_water_surface( vg_pv, player.camera ); - vg_tex2d_bind( &tex_water, 1 ); /*TODO: ?*/ render_world_gates( vg_pv, player.phys.rb.co, player.camera ); /* Copy the RGB of what we have into the background buffer */ @@ -378,91 +209,30 @@ static void render_main_game(void) glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background ); render_fsquad(); - glDisable(GL_BLEND); - - /* Other shite */ - glDisable( GL_DEPTH_TEST ); - vg_lines_drawall( (float *)vg_pv ); - glViewport( 0,0, vg_window_x, vg_window_y ); } -void vg_render(void) +void vg_render(void) { glBindFramebuffer( GL_FRAMEBUFFER, 0 ); glViewport( 0,0, vg_window_x, vg_window_y ); - glDisable( GL_DEPTH_TEST ); + glClearColor( 0.11f, 0.35f, 0.37f, 1.0f ); glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT | GL_STENCIL_BUFFER_BIT ); -#ifndef SR_NETWORK_TEST - draw_origin_axis(); - - if( sv_scene == 0 ) - { - render_main_game(); - } - else if( sv_scene == 1 ) - { - physics_test_render(); - } - else if( sv_scene == 2 ) - { - anim_test_render( &tex_characters ); - } -#endif -} - -static void run_light_widget( struct light_widget *lw ) -{ - struct ui_checkbox c1 = { .data=&lw->enabled }; - - ui_checkbox( &ui_global_ctx, &c1 ); - - if( lw->enabled ) - { - struct ui_slider_vector - colour = { .min=0.0f, .max=2.0f, .len=3, .data=lw->colour }, - dir = { .min=-VG_PIf, .max=VG_PIf, .len=2, .data=lw->dir }; - - ui_slider_vector( &ui_global_ctx, &colour ); - ui_global_ctx.cursor[1] += 4; - ui_slider_vector( &ui_global_ctx, &dir ); - } -} - -static void run_debug_info(void) -{ - char buf[40]; + render_main_game(); - snprintf( buf, 40, "%.2fm/s", v3_length( player.phys.rb.v ) ); - gui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left ); - snprintf( buf, 40, "%.2f %.2f %.2f m/s", - player.phys.a[0], player.phys.a[1], player.phys.a[2] ); - gui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left ); - - snprintf( buf, 40, "pos %.2f %.2f %.2f", - player.phys.rb.co[0], player.phys.rb.co[1], player.phys.rb.co[2] ); - gui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left ); - - if( vg_gamepad_ready ) - { - for( int i=0; i<6; i++ ) - { - snprintf( buf, 40, "%.2f", vg_gamepad.axes[i] ); - gui_text( (ui_px [2]){ 0, (i+3)*20 }, buf, 1, k_text_align_left ); - } - } - else - { - gui_text( (ui_px [2]){ 0, 60 }, - "Gamepad not ready", 1, k_text_align_left ); - } + /* Other shite */ + glDisable(GL_BLEND); + glDisable( GL_DEPTH_TEST ); + vg_lines_drawall( (float *)vg_pv ); + glViewport( 0,0, vg_window_x, vg_window_y ); } void vg_ui(void) { +#if 0 if( lightedit ) { ui_global_ctx.cursor[0] = 10; @@ -497,6 +267,7 @@ void vg_ui(void) render_update_lighting_ub(); } +#endif //glPolygonMode( GL_FRONT_AND_BACK, GL_LINE ); if( cl_ui ) @@ -506,37 +277,58 @@ void vg_ui(void) //glPolygonMode( GL_FRONT_AND_BACK, GL_FILL ); audio_debug_soundscapes(); - world_audio_debug(); +} + +void vg_free(void) +{ +} #if 0 - static double last_b_press = 0.0; +static void run_light_widget( struct light_widget *lw ) +{ + struct ui_checkbox c1 = { .data=&lw->enabled }; - double localtime = vg_time - last_b_press; + ui_checkbox( &ui_global_ctx, &c1 ); + + if( lw->enabled ) + { + struct ui_slider_vector + colour = { .min=0.0f, .max=2.0f, .len=3, .data=lw->colour }, + dir = { .min=-VG_PIf, .max=VG_PIf, .len=2, .data=lw->dir }; - world_routes_ui_updatetime( 0, localtime ); - world_routes_ui_draw( 0, (v4f){ 1.0f,0.0f,1.0f,1.0f}, 9.0f ); + ui_slider_vector( &ui_global_ctx, &colour ); + ui_global_ctx.cursor[1] += 4; + ui_slider_vector( &ui_global_ctx, &dir ); + } +} +#endif - if( glfwGetKey(vg_window,GLFW_KEY_B) ) - world_routes_ui_notch( 0, localtime ); +static void run_debug_info(void) +{ + char buf[40]; + + snprintf( buf, 40, "%.2fm/s", v3_length( player.phys.rb.v ) ); + gui_text( (ui_px [2]){ 0, 0 }, buf, 1, k_text_align_left ); + + snprintf( buf, 40, "%.2f %.2f %.2f m/s", + player.phys.a[0], player.phys.a[1], player.phys.a[2] ); + gui_text( (ui_px [2]){ 0, 20 }, buf, 1, k_text_align_left ); - if( vg_time-last_b_press > 1.0 ) - if( glfwGetKey(vg_window,GLFW_KEY_N) ) - { - last_b_press = vg_time; - world_routes_ui_newseg( 0 ); - } + snprintf( buf, 40, "pos %.2f %.2f %.2f", + player.phys.rb.co[0], player.phys.rb.co[1], player.phys.rb.co[2] ); + gui_text( (ui_px [2]){ 0, 40 }, buf, 1, k_text_align_left ); - static double last_m_press; - if( vg_time-last_m_press > 1.0 ) - if( glfwGetKey( vg_window, GLFW_KEY_M) ) + if( vg.gamepad_ready ) + { + for( int i=0; i<6; i++ ) { - last_m_press = vg_time; - - vg_info( "start: %u\n",world.routes.routes[0].ui.segment_count ); - for( int i=0; iindice_count = indice_count; + return 1; } static void mesh_bind( glmesh *mesh ) @@ -465,13 +470,15 @@ static void mdl_node_transform( mdl_node *pnode, m4x3f transform ) v3_copy( pnode->co, transform[3] ); } -static void mdl_unpack_submesh( mdl_header *mdl, glmesh *mesh, mdl_submesh *sm ) +__attribute__((warn_unused_result)) +static int mdl_unpack_submesh( mdl_header *mdl, glmesh *mesh, mdl_submesh *sm ) { - mesh_upload( mesh, mdl_submesh_vertices( mdl, sm ), sm->vertex_count, - mdl_submesh_indices( mdl, sm ), sm->indice_count ); + return mesh_upload( mesh, mdl_submesh_vertices( mdl, sm ), sm->vertex_count, + mdl_submesh_indices( mdl, sm ), sm->indice_count ); } -static void mdl_unpack_glmesh( mdl_header *mdl, glmesh *mesh ) +__attribute__((warn_unused_result)) +static int mdl_unpack_glmesh( mdl_header *mdl, glmesh *mesh ) { u32 offset = mdl_submesh_from_id( mdl, 0 )->vertex_count; @@ -489,8 +496,8 @@ static void mdl_unpack_glmesh( mdl_header *mdl, glmesh *mesh ) mdl_vert *vertex_base = mdl_baseptr( mdl, mdl->vertex_offset ); u32 *indice_base = mdl_baseptr( mdl, mdl->indice_offset ); - mesh_upload( mesh, vertex_base, mdl->vertex_count, - indice_base, mdl->indice_count ); + return mesh_upload( mesh, vertex_base, mdl->vertex_count, + indice_base, mdl->indice_count ); } static void mdl_draw_submesh( mdl_submesh *sm ) diff --git a/models_src/mp_dev.mdl b/models_src/mp_dev.mdl index d6d132e..fc7c735 100644 Binary files a/models_src/mp_dev.mdl and b/models_src/mp_dev.mdl differ diff --git a/network.h b/network.h index a9b5c8f..42bee34 100644 --- a/network.h +++ b/network.h @@ -12,13 +12,13 @@ #define SR_USE_LOCALHOST /* Call it at start; Connects us to the gameserver */ -static void network_init(void); +static int network_init(void); /* Run this from main loop */ static void network_update(void); /* Call it at shutdown */ -static void network_end(void); +static void network_end(void*_); /* * Can buffer up a bunch of these by calling many times, they will be @@ -320,7 +320,7 @@ static void network_update(void) } else { - vg_log( "Not making remote connection; app ticket not gotten\n" ); + vg_low( "Not making remote connection; app ticket not gotten\n" ); } } @@ -334,7 +334,7 @@ static void network_update(void) } } -static void network_init(void) +static int network_init(void) { if( steam_ready ) { @@ -342,9 +342,11 @@ static void network_init(void) on_server_connect_status ); request_auth_ticket(); } + + return 1; } -static void network_end(void) +static void network_end(void*_) { /* TODO: Fire off any buffered highscores that need to be setn */ if( cremote_state == k_ESteamNetworkingConnectionState_Connected || @@ -357,9 +359,9 @@ static void network_end(void) #else /* SR_NETWORKED */ -static void network_init(void){} +static int network_init(void){ return 1; } static void network_update(void){} -static void network_end(void){} +static void network_end(void*_){} #endif /* SR_NETWORKED */ #endif /* NETWORK_H */ diff --git a/player.h b/player.h index fa9335c..0a226af 100644 --- a/player.h +++ b/player.h @@ -177,17 +177,58 @@ static void player_restore_frame(void); * ----------------------------------------------------------------------------- */ -static void player_register(void) /* 0 */ +static int player_init(void) /* 1 */ { - player_model_register(); -} - -static void player_init(void) /* 1 */ -{ - player_model_init(); - + rb_init( &player.phys.rb ); rb_init( &player.collide_front ); rb_init( &player.collide_back ); + + vg_convar_push( (struct vg_convar){ + .name = "walk_speed", + .data = &k_walkspeed, + .data_type = k_convar_dtype_f32, + .opt_f32 = { .clamp = 0 }, + .persistent = 1 + }); + + vg_convar_push( (struct vg_convar){ + .name = "run_speed", + .data = &k_runspeed, + .data_type = k_convar_dtype_f32, + .opt_f32 = { .clamp = 0 }, + .persistent = 1 + }); + + vg_convar_push( (struct vg_convar){ + .name = "walk_accel", + .data = &k_walk_accel, + .data_type = k_convar_dtype_f32, + .opt_f32 = { .clamp = 0 }, + .persistent = 1 + }); + + vg_convar_push( (struct vg_convar){ + .name = "fc", + .data = &freecam, + .data_type = k_convar_dtype_i32, + .opt_i32 = { .min=0, .max=1, .clamp=1 }, + .persistent = 1 + }); + + vg_convar_push( (struct vg_convar){ + .name = "fcs", + .data = &fc_speed, + .data_type = k_convar_dtype_f32, + .opt_f32 = { .clamp = 0 }, + .persistent = 1 + }); + + vg_function_push( (struct vg_cmd){ + .name = "reset", + .function = reset_player + }); + + return player_model_init(); } static void player_update(void) /* 2 */ diff --git a/player_animation.h b/player_animation.h index 33dc3bf..02b4d25 100644 --- a/player_animation.h +++ b/player_animation.h @@ -154,7 +154,7 @@ static void player_animate(void) /* trick setup */ float jump_start_frame = 14.0f/30.0f; - player.fjump = vg_lerpf( player.fjump, phys->jump, 0.08f ); + player.fjump = vg_lerpf( player.fjump, phys->jump, 0.14f ); float setup_frame = phys->jump * jump_start_frame, setup_blend = vg_minf( player.fjump, 1.0f ); diff --git a/player_audio.h b/player_audio.h index 5402b7a..3071af3 100644 --- a/player_audio.h +++ b/player_audio.h @@ -1,3 +1,12 @@ +/* + * Copyright 2021-2022 (C) Mount0 Software, Harry Godden - All Rights Reserved + * ----------------------------------------------------------------------------- + * + * Player audio + * + * ----------------------------------------------------------------------------- + */ + #ifndef PLAYER_AUDIO_H #define PLAYER_AUDIO_H @@ -48,6 +57,7 @@ static void player_audio(void) audio_player_set_position( &audio_player1, phys->rb.co ); audio_player_set_position( &audio_player2, phys->rb.co ); audio_player_set_position( &audio_player_gate, world.render_gate_pos ); + audio_player_set_vol( &audio_player_gate, 5.0f ); v3_sub( phys->rb.co, player.camera[3], delta ); v3_normalize( delta ); diff --git a/player_model.h b/player_model.h index a2379fc..e0693b1 100644 --- a/player_model.h +++ b/player_model.h @@ -11,17 +11,25 @@ vg_tex2d tex_characters = { .path = "textures/ch_gradient.qoi" }; -static void player_model_register(void) +static int player_model_init(void) { shader_viewchar_register(); + + if( vg_acquire_thread_sync(1) ) + { + vg_tex2d_init( (vg_tex2d *[]){ &tex_characters }, 1 ); + vg_release_thread_sync(1); + return 1; + } + else + return 0; } -static void player_model_init(void) +static void player_model_free(void *_) { - vg_tex2d_init( (vg_tex2d *[]){ &tex_characters }, 1 ); + vg_tex2d_free( (vg_tex2d *[]){ &tex_characters }, 1 ); } - /* * Load model from file (.mdl) */ @@ -37,7 +45,9 @@ static int player_load_model( const char *name ) struct player_model *mdl = &player.mdl; - mdl_unpack_glmesh( src, &mdl->mesh ); + if( !mdl_unpack_glmesh( src, &mdl->mesh ) ) + goto il_free_err; + skeleton_setup( &mdl->sk, src ); /* diff --git a/render.h b/render.h index f77f106..6a5b56d 100644 --- a/render.h +++ b/render.h @@ -1,6 +1,11 @@ #include "common.h" #include "model.h" +#include "shaders/blit.h" +#include "shaders/standard.h" +#include "shaders/vblend.h" +#include "shaders/unlit.h" + static void render_water_texture( m4x3f camera ); static void render_water_surface( m4x4f pv, m4x3f camera ); static void render_world( m4x4f projection, m4x3f camera ); @@ -10,6 +15,15 @@ static void render_world_depth( m4x4f projection, m4x3f camera ); #ifndef RENDER_H #define RENDER_H +struct framebuffer +{ + GLuint fb, colour, rb; + int div; + GLuint format; + + int allocated; +}; + static struct pipeline { float fov; @@ -48,6 +62,8 @@ static struct pipeline GLuint fb_depthmap, rgb_depthmap; GLuint ubo_world_lighting, ubo_world; + + int ready; } gpipeline = { @@ -155,26 +171,9 @@ static void render_update_lighting_ub(void) &gpipeline.ub_world_lighting ); } -static void render_alloc_ub(void) -{ - glGenBuffers( 1, &gpipeline.ubo_world_lighting ); - glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting ); - glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting), - NULL, GL_DYNAMIC_DRAW ); - - render_update_lighting_ub(); - glBindBufferBase( GL_UNIFORM_BUFFER, 0, gpipeline.ubo_world_lighting ); -} - /* * Framebuffers */ -struct framebuffer -{ - GLuint fb, colour, rb; - int div; - GLuint format; -}; static void fb_use( struct framebuffer *fb ) { @@ -190,7 +189,8 @@ static void fb_use( struct framebuffer *fb ) } } -static void fb_init( struct framebuffer *fb ) +__attribute__((warn_unused_result)) +static int fb_init( struct framebuffer *fb ) { i32 ix = vg_window_x / fb->div, iy = vg_window_y / fb->div; @@ -214,6 +214,23 @@ static void fb_init( struct framebuffer *fb ) glFramebufferRenderbuffer( GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb->rb ); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + + if( VG_CHECK_GL_ERR() ) + { + fb->allocated = 0; + vg_error( "Error while creating standard framebuffer\n" ); + return 0; + } + + fb->allocated = 1; + return 1; +} + +static void fb_free( struct framebuffer *fb ) +{ + glDeleteTextures( 1, &fb->colour ); + glDeleteFramebuffers( 1, &fb->fb ); } static void fb_bindtex( struct framebuffer *fb, int texture ) @@ -224,6 +241,9 @@ static void fb_bindtex( struct framebuffer *fb, int texture ) static void fb_resize( struct framebuffer *fb ) { + if( !fb->allocated ) + return; + i32 ix = vg_window_x / fb->div, iy = vg_window_y / fb->div; @@ -237,69 +257,134 @@ static void fb_resize( struct framebuffer *fb ) static void render_fb_resize(void) { - glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg_window_x, vg_window_y, 0, - GL_RGB, GL_UNSIGNED_BYTE, NULL ); + if( gpipeline.ready ) + { + glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg_window_x, vg_window_y, 0, + GL_RGB, GL_UNSIGNED_BYTE, NULL ); + } } /* * Vg */ -static void render_init(void) +static int render_init(void) { - glGenFramebuffers( 1, &gpipeline.fb_background ); - glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_background ); + shader_blit_register(); + shader_standard_register(); + shader_vblend_register(); + shader_unlit_register(); - glGenTextures( 1, &gpipeline.rgb_background ); - glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg_window_x, vg_window_y, - 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); + if( vg_acquire_thread_sync(1) ) + { + vg_info( "Allocating framebuffers\n" ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - gpipeline.rgb_background, 0); + glGenFramebuffers( 1, &gpipeline.fb_background ); + glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_background ); - /* - * World depth map, maybe this should be moved to world.h - * TODO: review - */ - glGenFramebuffers( 1, &gpipeline.fb_depthmap ); - glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap ); + glGenTextures( 1, &gpipeline.rgb_background ); + glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_background ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_RGB, vg_window_x, vg_window_y, + 0, GL_RGB, GL_UNSIGNED_BYTE, NULL); - glGenTextures( 1, &gpipeline.rgb_depthmap ); - glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_depthmap ); - glTexImage2D( GL_TEXTURE_2D, 0, GL_R32F, 1024, 1024, 0, - GL_RED, GL_FLOAT, NULL ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); - glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); - vg_tex2d_clamp(); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + gpipeline.rgb_background, 0); - glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, - GL_TEXTURE_2D, - gpipeline.rgb_depthmap, 0); + if( VG_CHECK_GL_ERR() ) + { + vg_error( "Error while creating back buffer\n" ); + vg_release_thread_sync(1); + return 0; + } - float quad[] = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, - 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f }; + /* + * World depth map, maybe this should be moved to world.h + * TODO: review + */ + glGenFramebuffers( 1, &gpipeline.fb_depthmap ); + glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap ); + + glGenTextures( 1, &gpipeline.rgb_depthmap ); + glBindTexture( GL_TEXTURE_2D, gpipeline.rgb_depthmap ); + glTexImage2D( GL_TEXTURE_2D, 0, GL_R32F, 1024, 1024, 0, + GL_RED, GL_FLOAT, NULL ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR ); + glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR ); + vg_tex2d_clamp(); + + glFramebufferTexture2D( GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, + GL_TEXTURE_2D, + gpipeline.rgb_depthmap, 0); + + if( VG_CHECK_GL_ERR() ) + { + vg_error( "Error while creating world depth buffer\n" ); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + vg_release_thread_sync(1); + return 0; + } - glGenVertexArrays( 1, &gpipeline.fsquad.vao ); - glGenBuffers( 1, &gpipeline.fsquad.vbo ); - glBindVertexArray( gpipeline.fsquad.vao ); - glBindBuffer( GL_ARRAY_BUFFER, gpipeline.fsquad.vbo ); - glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW ); - glBindVertexArray( gpipeline.fsquad.vao ); - glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, - sizeof(float)*2, (void*)0 ); - glEnableVertexAttribArray( 0 ); - VG_CHECK_GL(); + float quad[] = { 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, + 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f }; - render_alloc_ub(); + glGenVertexArrays( 1, &gpipeline.fsquad.vao ); + glGenBuffers( 1, &gpipeline.fsquad.vbo ); + glBindVertexArray( gpipeline.fsquad.vao ); + glBindBuffer( GL_ARRAY_BUFFER, gpipeline.fsquad.vbo ); + glBufferData( GL_ARRAY_BUFFER, sizeof(quad), quad, GL_STATIC_DRAW ); + glBindVertexArray( gpipeline.fsquad.vao ); + glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, + sizeof(float)*2, (void*)0 ); + glEnableVertexAttribArray( 0 ); + + if( VG_CHECK_GL_ERR() ) + { + vg_error( "Error while creating fsquad\n" ); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + vg_release_thread_sync(1); + return 0; + } + + glGenBuffers( 1, &gpipeline.ubo_world_lighting ); + glBindBuffer( GL_UNIFORM_BUFFER, gpipeline.ubo_world_lighting ); + glBufferData( GL_UNIFORM_BUFFER, sizeof(struct ub_world_lighting), + NULL, GL_DYNAMIC_DRAW ); + + render_update_lighting_ub(); + glBindBufferBase( GL_UNIFORM_BUFFER, 0, gpipeline.ubo_world_lighting ); + + if( VG_CHECK_GL_ERR() ) + { + vg_error( "Error while creating world uniform buffers\n" ); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + vg_release_thread_sync(1); + return 0; + } + + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + vg_success( "Done\n" ); + + gpipeline.ready = 1; + vg_release_thread_sync(1); + return 1; + } + else + return 0; } -static void render_free(void) +static void render_free(void *_) { - /* TODO: ... */ + glDeleteVertexArrays( 1, &gpipeline.fsquad.vao ); + glDeleteBuffers( 1, &gpipeline.fsquad.vbo ); + + glDeleteFramebuffers( 1, &gpipeline.fb_background ); + glDeleteFramebuffers( 1, &gpipeline.fb_depthmap ); + + glDeleteTextures( 1, &gpipeline.rgb_background ); + glDeleteTextures( 1, &gpipeline.rgb_depthmap ); } /* diff --git a/rigidbody.h b/rigidbody.h index 026d867..29e8cea 100644 --- a/rigidbody.h +++ b/rigidbody.h @@ -338,17 +338,12 @@ static void rb_init( rigidbody *rb ) v3f dims; v3_sub( rb->bbx[1], rb->bbx[0], dims ); volume = dims[0]*dims[1]*dims[2]; - - if( !rb->is_world ) - vg_info( "Box volume: %f\n", volume ); } else if( rb->type == k_rb_shape_sphere ) { volume = sphere_volume( rb->inf.sphere.radius ); v3_fill( rb->bbx[0], -rb->inf.sphere.radius ); v3_fill( rb->bbx[1], rb->inf.sphere.radius ); - - vg_info( "Sphere volume: %f\n", volume ); } else if( rb->type == k_rb_shape_capsule ) { diff --git a/scene.h b/scene.h index 8754d00..acfc56b 100644 --- a/scene.h +++ b/scene.h @@ -84,25 +84,6 @@ static void scene_init( scene *pscene ) #endif } -static void *buffer_reserve( void *buffer, u32 count, u32 *cap, u32 amount, - size_t emsize ) -{ - if( count+amount > *cap ) - { - *cap = VG_MAX( (*cap)*2, (*cap)+amount ); - - return realloc( buffer, (*cap) * emsize ); - } - - return buffer; -} - -static void *buffer_fix( void *buffer, u32 count, u32 *cap, size_t emsize ) -{ - *cap = count; - return realloc( buffer, (*cap) * emsize ); -} - /* * Append a model into the scene with a given transform */ @@ -199,15 +180,21 @@ static void scene_fix( scene *pscene ) &pscene->indice_cap, sizeof( mdl_vert )); } -static void scene_upload( scene *pscene ) +__attribute__((warn_unused_result)) +static int scene_upload( scene *pscene ) { - mesh_upload( &pscene->mesh, + if( ! mesh_upload( &pscene->mesh, pscene->verts, pscene->vertex_count, - pscene->indices, pscene->indice_count ); + pscene->indices, pscene->indice_count ) ) + { + return 0; + } vg_info( "Scene upload\n" ); vg_info( " indices:%u\n", pscene->indice_count ); vg_info( " verts:%u\n", pscene->vertex_count ); + + return 1; } static void scene_bind( scene *pscene ) @@ -232,10 +219,6 @@ static void scene_free( scene *pscene ) /* TODO: bvh */ } -static void scene_register(void) -{ -} - /* * BVH implementation */ diff --git a/shaders.sh b/shaders.sh index e958679..9130269 100755 --- a/shaders.sh +++ b/shaders.sh @@ -11,21 +11,20 @@ shader(){ } shader blit blit.vs blit.fs -shader fscolour blit.vs colour.fs -shader terrain standard.vs terrain.fs -shader vblend standard.vs vblend.fs -shader alphatest standard.vs std_alphatest.fs shader standard standard.vs standard.fs +shader vblend standard.vs vblend.fs shader unlit standard.vs unlit.fs -shader character character.vs character.fs -shader gate gate.vs gate.fs -shader gatelq gate.vs gate_lq.fs -shader water standard.vs water.fs +shader terrain standard.vs terrain.fs shader sky standard.vs sky.fs shader planeinf standard.vs planeinf.fs shader gpos standard.vs gpos.fs -shader route standard.vs route.fs +shader fscolour blit.vs colour.fs +shader alphatest standard.vs std_alphatest.fs shader scoretext scoretext.vs vblend.fs +shader water standard.vs water.fs +shader gate gate.vs gate.fs +shader gatelq gate.vs gate_lq.fs +shader route standard.vs route.fs shader routeui routeui.vs routeui.fs shader viewchar standard_skinned.vs viewchar.fs diff --git a/skeleton.h b/skeleton.h index d74e660..abbef4e 100644 --- a/skeleton.h +++ b/skeleton.h @@ -533,7 +533,7 @@ static int skeleton_setup( struct skeleton *skele, mdl_header *mdl ) skele->anims[i].rate = anim->rate; skele->anims[i].length = anim->length; - strncpy( skele->anims[i].name, mdl_pstr(mdl, anim->pstr_name), 32 ); + strncpy( skele->anims[i].name, mdl_pstr(mdl, anim->pstr_name), 31 ); u32 total_keyframes = (skele->bone_count-1)*anim->length; size_t block_size = sizeof(mdl_keyframe) * total_keyframes; diff --git a/steam.h b/steam.h index 57af429..c0fb789 100644 --- a/steam.h +++ b/steam.h @@ -2,6 +2,7 @@ #define STEAM_H #include "vg/vg_steam.h" +#include "vg/vg_steam_utils.h" #include "vg/vg_steam_networking.h" #include "vg/vg_steam_auth.h" #include "vg/vg_steam_http.h" @@ -17,30 +18,49 @@ * nothing. */ +static void recv_steam_warning( int severity, const char *msg ) +{ + if( severity == 0 ) + vg_low( "%s\n", msg ); + else + vg_info( "%s\n", msg ); +} + static int steam_ready = 0; static void *hSteamNetworkingSockets, *hSteamUser; static HSteamPipe hSteamClientPipe; -static void steam_init(void) +static int steam_init(void) { #ifdef SR_NETWORKED + vg_info( "Initializing steamworks\n" ); + if( !SteamAPI_Init() ) { + printf("\n"); vg_error( "Steamworks failed to initialize\n" ); - return; + return 1; } + steam_ready = 1; SteamAPI_ManualDispatch_Init(); - vg_success( "Steamworks API running\n" ); /* Connect interfaces */ hSteamClientPipe = SteamAPI_GetHSteamPipe(); hSteamNetworkingSockets = SteamAPI_SteamNetworkingSockets_SteamAPI(); hSteamUser = SteamAPI_SteamUser(); + + ISteamUtils *utils = SteamAPI_SteamUtils(); + SteamAPI_ISteamUtils_SetWarningMessageHook( utils, recv_steam_warning ); + + printf("\n"); + vg_success( "\nSteamworks API running\n" ); #endif + + return 1; } static void steam_update(void) @@ -49,7 +69,7 @@ static void steam_update(void) steamworks_event_loop( hSteamClientPipe ); } -static void steam_end(void) +static void steam_end(void *nothing) { if( steam_ready ) { diff --git a/world.h b/world.h index 8779df9..8c5837d 100644 --- a/world.h +++ b/world.h @@ -5,13 +5,14 @@ static int ray_world( v3f pos, v3f dir, ray_hit *hit ); #ifndef WORLD_H #define WORLD_H +#include "vg/vg_loader.h" + #include "network.h" #include "network_msg.h" #include "scene.h" #include "terrain.h" #include "render.h" #include "rigidbody.h" -#include "gate.h" #include "bvh.h" #include "lighting.h" #include "model.h" @@ -111,7 +112,15 @@ static struct gworld struct route_gate { - teleport_gate gate; + struct teleport_gate + { + v3f co[2]; + v4f q[2]; + v2f dims; + + m4x3f to_world, recv_to_world, transport; + } + gate; u32 node_id; @@ -183,8 +192,6 @@ static struct gworld glmesh cars; mdl_submesh car_holden; - rigidbody mr_ball; - /* Load time */ struct instance_cache @@ -215,17 +222,18 @@ static int ray_world( v3f pos, v3f dir, ray_hit *hit ); */ #include "world_routes.h" #include "world_sfd.h" -#include "world_audio.h" #include "world_render.h" #include "world_water.h" #include "world_gen.h" +#include "world_gate.h" /* * ----------------------------------------------------------------------------- * Events * ----------------------------------------------------------------------------- */ -static void world_register(void) + +static int world_init(void) { shader_terrain_register(); shader_sky_register(); @@ -234,43 +242,80 @@ static void world_register(void) shader_fscolour_register(); shader_alphatest_register(); - world_routes_register(); - world_sfd_register(); - world_water_register(); -} - -static void world_free(void) -{ - /* TODO.. */ - - world_sfd_free(); -} + vg_info( "Loading world resources\n" ); - -static void world_init(void) -{ mdl_header *mcars = mdl_load( "models/rs_cars.mdl" ); - mdl_unpack_glmesh( mcars, &world.cars ); mdl_node *nholden = mdl_node_from_name( mcars, "holden" ); world.car_holden = *mdl_node_submesh( mcars, nholden, 0 ); - free(mcars); - mdl_header *msky = mdl_load("models/rs_skydome.mdl"); - mdl_unpack_glmesh( msky, &world.skydome ); - mdl_node *nlower = mdl_node_from_name( msky, "dome_lower" ), *nupper = mdl_node_from_name( msky, "dome_upper" ); world.dome_lower = *mdl_node_submesh( msky, nlower, 0 ); world.dome_upper = *mdl_node_submesh( msky, nupper, 0 ); + + /* TODO: cleanup resource acquisition */ + if( !mcars || !msky ) + { + free( mcars ); + free( msky ); + return 0; + } + + if( vg_acquire_thread_sync(1) ) + { + if( !mdl_unpack_glmesh( mcars, &world.cars ) ) + { + free( mcars ); + free( msky ); + vg_release_thread_sync(1); + return 0; + } + + if( !mdl_unpack_glmesh( msky, &world.skydome ) ) + { + mesh_free( &world.cars ); + free( mcars ); + free( msky ); + vg_release_thread_sync(1); + return 0; + } + + vg_release_thread_sync(1); + } + else + { + free(mcars); + free(msky); + return 0; + } + + free(mcars); free(msky); + vg_info( "Loading other world systems\n" ); + + if( !vg_loader_highwater( (void *)mesh_free, &world.cars ) ) return 0; + if( !vg_loader_highwater( (void *)mesh_free, &world.skydome ) ) return 0; /* Other systems */ - world_render_init(); - world_sfd_init(); - world_audio_init(); + + if( !world_render_init() ) return 0; + if( !vg_loader_highwater( world_render_free, NULL ) ) return 0; + + if( !world_sfd_init() ) return 0; + if( !vg_loader_highwater( world_sfd_free, NULL ) ) return 0; + + if( !world_water_init() ) return 0; + if( !vg_loader_highwater( world_water_free, NULL ) ) return 0; + + if( !world_gates_init() ) return 0; + if( !vg_loader_highwater( world_gates_free, NULL ) ) return 0; + + if( !world_routes_init() ) return 0; + if( !vg_loader_highwater( world_routes_free, NULL ) ) return 0; + return 1; } static void world_update( v3f pos ) diff --git a/world_audio.h b/world_audio.h deleted file mode 100644 index 2de8bf2..0000000 --- a/world_audio.h +++ /dev/null @@ -1,117 +0,0 @@ -#ifndef WORLD_AUDIO_H -#define WORLD_AUDIO_H - -#include "common.h" -#include "vg/vg_audio.h" -#include "audio.h" - -#if 0 -audio_pack audio_birds = -{ - .sources = "sound/bird0.ogg\0" - "sound/bird1.ogg\0" - "sound/bird2.ogg\0", - .name = "Birds", - .source_mode = k_audio_source_compressed -}; -#endif - -static float k_audio_random_freq = 1.0f/10.0f, - k_audio_random_hz = 1.0f; - -static double world_audio_last_tick = 0.0; - -static struct world_ambient_layer -{ - audio_player sys; - v3f pos; -} -world_ambient_layers[8]; - -static void world_audio_init(void) -{ -#if 0 - audio_pack_init( &audio_birds ); - - vg_convar_push( (struct vg_convar){ - .name = "aud_random_freq", - .data = &k_audio_random_freq, - .data_type = k_convar_dtype_f32, - .opt_f32 = { .clamp = 0 }, - .persistent = 1 - }); - - for( int i=0; isys; - sys->_vol = 1.0f; - sys->ch = 1; - sys->name = "ambient"; - sys->flags = SFX_FLAG_PERSISTENT; - } -#endif -} - -static void world_audio_spawn_random( v3f around ) -{ -#if 0 - for( int i=0; isys.is_playing ) - { - sfx_set_playrnd( &audio_birds, &layer->sys, 0, 3 ); - - v3f chance; - vg_rand_sphere( chance ); - v3_muladds( around, chance, 100.0f, layer->pos ); - - return; - } - } -#endif -} - -static void world_audio_update( v3f around, v3f ears ) -{ -#if 0 - if( world_audio_last_tick + (double)k_audio_random_hz < vg_time ) - { - world_audio_last_tick = vg_time; - - float chance = vg_randf(); - if( chance < k_audio_random_freq ) - { - world_audio_spawn_random( around ); - } - } - - /* Spacialize */ - for( int i=0; isys.is_playing ) - audio_player_spacialize(&layer->sys, layer->pos, around, ears, 30.0f); - } -#endif -} - -static void world_audio_debug(void) -{ -#if 0 - for( int i=0; isys.is_playing ) - { - vg_line_pt3( layer->pos, 1.0f, 0xffff00ff ); - } - } -#endif -} - -#endif /* WORLD_AUDIO_H */ diff --git a/world_gate.h b/world_gate.h new file mode 100644 index 0000000..8434fb1 --- /dev/null +++ b/world_gate.h @@ -0,0 +1,277 @@ +#ifndef WORLD_GATE_H +#define WORLD_GATE_H + +#include "common.h" +#include "model.h" +#include "render.h" +#include "shaders/gate.h" +#include "shaders/gatelq.h" +#include "world_water.h" + +typedef struct teleport_gate teleport_gate; + +static struct +{ + struct framebuffer fb; + glmesh mdl; + + int high_qual; /* If in high performance mode, we don't use RT's, and + instead use stencil buffers. + There is therefore no heat warp effect. */ +} +grender = +{ + .high_qual = 0, + .fb = { + .format = GL_RGB, + .div = 1 + } +}; + +static void gate_transform_update( teleport_gate *gate ) +{ + m4x3f to_local; + + q_m3x3( gate->q[0], gate->to_world ); + v3_copy( gate->co[0], gate->to_world[3] ); + + m4x3_invert_affine( gate->to_world, to_local ); + + q_m3x3( gate->q[1], gate->recv_to_world ); + v3_copy( gate->co[1], gate->recv_to_world[3] ); + m4x3_mul( gate->recv_to_world, to_local, gate->transport ); +} + +static int world_gates_init(void) +{ + vg_info( "world_gates_init\n" ); + shader_gate_register(); + shader_gatelq_register(); + + mdl_header *mgate = mdl_load( "models/rs_gate.mdl" ); + + if( vg_acquire_thread_sync(1) ) + { + if( !fb_init( &grender.fb ) ) + { + free( mgate ); + vg_release_thread_sync(1); + return 0; + } + + if( !mdl_unpack_glmesh( mgate, &grender.mdl ) ) + { + free( mgate ); + fb_free( &grender.fb ); + vg_release_thread_sync(1); + return 0; + } + + vg_release_thread_sync(1); + } + else + { + free( mgate ); + return 0; + } + + return 1; +} + +static void world_gates_free(void*_) +{ + fb_free( &grender.fb ); +} + +static void gate_fb_resize(void) +{ + fb_resize( &grender.fb ); +} + +static int render_gate( teleport_gate *gate, v3f viewpos, m4x3f camera ) +{ + v3f viewdir, gatedir; + m3x3_mulv( camera, (v3f){0.0f,0.0f,-1.0f}, viewdir ); + m3x3_mulv( gate->to_world, (v3f){0.0f,0.0f,-1.0f}, gatedir ); + + v3f v0; + v3_sub( viewpos, gate->co[0], v0 ); + if( v3_dot(v0, gatedir) >= 0.0f ) + return 0; + + if( v3_dist( viewpos, gate->co[0] ) > 100.0f ) + return 0; + + v3f a,b,c,d; + + float sx = gate->dims[0], + sy = gate->dims[1]; + m4x3_mulv( gate->to_world, (v3f){-sx,-sy,0.0f}, a ); + m4x3_mulv( gate->to_world, (v3f){ sx,-sy,0.0f}, b ); + m4x3_mulv( gate->to_world, (v3f){ sx, sy,0.0f}, c ); + m4x3_mulv( gate->to_world, (v3f){-sx, sy,0.0f}, d ); + + vg_line( a,b, 0xffffa000 ); + vg_line( b,c, 0xffffa000 ); + vg_line( c,d, 0xffffa000 ); + vg_line( d,a, 0xffffa000 ); + + vg_line2( gate->co[0], gate->co[1], 0xff0000ff, 0x00000000 ); + + m4x3f cam_new; + m4x3_mul( gate->transport, camera, cam_new ); + + vg_line_pt3( cam_new[3], 0.3f, 0xff00ff00 ); + + m4x3f gate_xform; + m4x3_copy( gate->to_world, gate_xform ); + m4x3_scalev( gate_xform, (v3f){ gate->dims[0], gate->dims[1], 1.0f } ); + + m4x3f inverse; + m4x3_invert_affine( cam_new, inverse ); + + m4x4f view; + m4x3_expand( inverse, view ); + + v4f surface; + m3x3_mulv( gate->recv_to_world, (v3f){0.0f,0.0f,-1.0f}, surface ); + surface[3] = v3_dot( surface, gate->co[1] ); + + m4x4f projection; + pipeline_projection( projection, 0.1f, 900.0f ); + + m4x3_mulp( inverse, surface, surface ); + surface[3] = -fabsf(surface[3]); + plane_clip_projection( projection, surface ); + + m4x4_mul( projection, view, projection ); + + if( grender.high_qual ) + { + fb_use( &grender.fb ); + glClearColor( 0.11f, 0.35f, 0.37f, 1.0f ); + glClear( GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT ); + } + else + { + shader_gatelq_use(); + shader_gatelq_uPv( vg_pv ); + shader_gatelq_uMdl( gate_xform ); + shader_gatelq_uCam( viewpos ); + shader_gatelq_uTime( vg_time*0.25f ); + shader_gatelq_uInvRes( (v2f){ + 1.0f / (float)vg_window_x, + 1.0f / (float)vg_window_y }); + + glEnable( GL_STENCIL_TEST ); + glStencilOp( GL_KEEP, GL_KEEP, GL_REPLACE ); + glStencilFunc( GL_ALWAYS, 1, 0xFF ); + glStencilMask( 0xFF ); + + mesh_bind( &grender.mdl ); + mesh_draw( &grender.mdl ); + + glClear( GL_DEPTH_BUFFER_BIT ); + glStencilFunc( GL_EQUAL, 1, 0xFF ); + glStencilMask( 0x00 ); + } + + render_world( projection, cam_new ); + + if( grender.high_qual ) + { + /* + * TODO: Need to find a way to draw a stencil buffer into the water + * rendering + */ + + render_water_texture( cam_new ); + fb_use( &grender.fb ); + + render_water_surface( projection, cam_new ); + fb_use( NULL ); + + shader_gate_use(); + + shader_gate_uPv( vg_pv ); + shader_gate_uMdl( gate_xform ); + + fb_bindtex( &grender.fb, 0 ); + + shader_gate_uCam( viewpos ); + shader_gate_uTexMain( 0 ); + shader_gate_uTexWater( 1 ); + shader_gate_uTime( vg_time*0.25f ); + shader_gate_uInvRes( (v2f){ + 1.0f / (float)vg_window_x, + 1.0f / (float)vg_window_y }); + + glEnable(GL_BLEND); + glBlendFunc(GL_SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA); + glBlendEquation(GL_FUNC_ADD); + + mesh_bind( &grender.mdl ); + mesh_draw( &grender.mdl ); + + glDisable(GL_BLEND); + } + else + { + glDisable( GL_STENCIL_TEST ); + + render_water_texture( cam_new ); + fb_use( NULL ); + glEnable( GL_STENCIL_TEST ); + + render_water_surface( projection, cam_new ); + + glStencilMask( 0xFF ); + glStencilFunc( GL_ALWAYS, 1, 0xFF ); + glDisable( GL_STENCIL_TEST ); + } + + return 1; +} + +static int gate_intersect( teleport_gate *gate, v3f pos, v3f last ) +{ + v4f surface; + m3x3_mulv( gate->to_world, (v3f){0.0f,0.0f,-1.0f}, surface ); + surface[3] = v3_dot( surface, gate->co[0] ); + + v3f v0, c, delta, p0; + v3_sub( pos, last, v0 ); + float l = v3_length( v0 ); + v3_divs( v0, l, v0 ); + + v3_muls( surface, surface[3], c ); + v3_sub( c, last, delta ); + + float d = v3_dot(surface, v0); + + if( d > 0.00001f ) + { + float t = v3_dot(delta, surface) / d; + if( t >= 0.0f && t <= l ) + { + v3f local, rel; + v3_muladds( last, v0, t, local ); + v3_sub( gate->co[0], local, rel ); + + v3f vup, vside; + m3x3_mulv( gate->to_world, (v3f){0.0f,1.0f,0.0f}, vup ); + m3x3_mulv( gate->to_world, (v3f){1.0f,0.0f,0.0f}, vside ); + + v2f xy = { v3_dot( rel, vside ), v3_dot( rel, vup ) }; + + if( fabsf(xy[0]) <= gate->dims[0] && fabsf(xy[1]) <= gate->dims[1] ) + { + return 1; + } + } + } + + return 0; +} + +#endif /* WORLD_GATE_H */ diff --git a/world_gen.h b/world_gen.h index 74907c6..d9037c9 100644 --- a/world_gen.h +++ b/world_gen.h @@ -86,12 +86,14 @@ static void world_apply_procedural_foliage(void) } } } + free( mfoliage ); } static void world_load(void) { mdl_header *mworld = mdl_load( "models/mp_dev.mdl" ); + vg_info( "Loading world: models/mp_dev.mdl\n" ); world.spawn_count = 0; world.traffic_count = 0; @@ -127,10 +129,17 @@ static void world_load(void) if( sm ) { - glmesh surf; - mdl_unpack_submesh( mworld, &surf, sm ); - world_water_init(); - water_set_surface( &surf, pnode->co[1] ); + + if( vg_acquire_thread_sync(1) ) + { + glmesh surf; + if( mdl_unpack_submesh( mworld, &surf, sm ) ) + { + water_set_surface( &surf, pnode->co[1] ); + } + + vg_release_thread_sync(1); + } } } else if( pnode->classtype == k_classtype_car_path ) @@ -261,7 +270,16 @@ static void world_load(void) world_add_all_if_material( midentity, &world.geo,mworld,mat_vertex_blend); scene_copy_slice( &world.geo, &world.sm_geo_vb ); - scene_upload( &world.geo ); + if( vg_acquire_thread_sync(1) ) + { + if( !scene_upload( &world.geo ) ) + { + + } + + vg_release_thread_sync(1); + } + scene_bh_create( &world.geo ); @@ -279,7 +297,73 @@ static void world_load(void) world_add_all_if_material( midentity, &world.foliage, mworld, mat_graffiti ); scene_copy_slice( &world.foliage, &world.sm_graffiti ); - scene_upload( &world.foliage ); + + if( vg_acquire_thread_sync(1) ) + { + if( !scene_upload( &world.foliage ) ) + { + + } + + /* + * Rendering the depth map + */ + m4x4f ortho; + m4x3f camera; + + v3f extent; + v3_sub( world.geo.bbx[1], world.geo.bbx[0], extent ); + + float fl = world.geo.bbx[0][0], + fr = world.geo.bbx[1][0], + fb = world.geo.bbx[0][2], + ft = world.geo.bbx[1][2], + rl = 1.0f / (fr-fl), + tb = 1.0f / (ft-fb); + + m4x4_zero( ortho ); + ortho[0][0] = 2.0f * rl; + ortho[2][1] = 2.0f * tb; + ortho[3][0] = (fr + fl) * -rl; + ortho[3][1] = (ft + fb) * -tb; + ortho[3][3] = 1.0f; + m4x3_identity( camera ); + + glViewport( 0, 0, 1024, 1024 ); + glDisable(GL_DEPTH_TEST); + glBindFramebuffer( GL_FRAMEBUFFER, gpipeline.fb_depthmap ); + shader_fscolour_use(); + shader_fscolour_uColour( (v4f){-9999.0f,-9999.0f,-9999.0f,-9999.0f} ); + render_fsquad(); + + glEnable(GL_BLEND); + glBlendFunc(GL_ONE, GL_ONE); + glBlendEquation(GL_MAX); + render_world_depth( ortho, camera ); + glDisable(GL_BLEND); + glEnable(GL_DEPTH_TEST); + glBindFramebuffer( GL_FRAMEBUFFER, 0 ); + + + /* + * TODO: World settings entity + */ + struct ub_world_lighting *winfo = &gpipeline.ub_world_lighting; + v4_copy( wrender.plane, winfo->g_water_plane ); + + v4f bounds; + bounds[0] = world.geo.bbx[0][0]; + bounds[1] = world.geo.bbx[0][2]; + bounds[2] = 1.0f/ (world.geo.bbx[1][0]-world.geo.bbx[0][0]); + bounds[3] = 1.0f/ (world.geo.bbx[1][2]-world.geo.bbx[0][2]); + v4_copy( bounds, winfo->g_depth_bounds ); + + winfo->g_water_fog = 0.04f; + render_update_lighting_ub(); + + vg_release_thread_sync(1); + } + world_routes_loadfrom( mworld ); for( int i=0; ig_water_plane ); - - v4f bounds; - bounds[0] = world.geo.bbx[0][0]; - bounds[1] = world.geo.bbx[0][2]; - bounds[2] = 1.0f/ (world.geo.bbx[1][0]-world.geo.bbx[0][0]); - bounds[3] = 1.0f/ (world.geo.bbx[1][2]-world.geo.bbx[0][2]); - v4_copy( bounds, winfo->g_depth_bounds ); - - winfo->g_water_fog = 0.04f; - render_update_lighting_ub(); - - - world.mr_ball.type = k_rb_shape_sphere; - world.mr_ball.inf.sphere.radius = 2.0f; - v3_copy( (v3f){ 0.0f, 110.0f, 0.0f }, world.mr_ball.co ); - - q_identity(world.mr_ball.q); - rb_init( &world.mr_ball ); + scene_free_offline_buffers( &world.foliage ); /* * Setup scene collider diff --git a/world_render.h b/world_render.h index 3662bb1..65494a5 100644 --- a/world_render.h +++ b/world_render.h @@ -15,9 +15,27 @@ vg_tex2d tex_alphatest = { .path = "textures/alphatest.qoi", vg_tex2d tex_graffiti = { .path = "textures/graffitibox.qoi", .flags = VG_TEXTURE_NEAREST }; -static void world_render_init(void) +static int world_render_init(void) { - vg_tex2d_init( (vg_tex2d *[]){ &tex_terrain_colours, + vg_info( "Loading default world textures\n" ); + + if( vg_acquire_thread_sync(1) ) + { + vg_tex2d_init( (vg_tex2d *[]){ &tex_terrain_colours, + &tex_terrain_noise, + &tex_alphatest, + &tex_graffiti }, 4 ); + + vg_release_thread_sync(1); + return 1; + } + + return 0; +} + +static void world_render_free(void*_) +{ + vg_tex2d_free( (vg_tex2d *[]){ &tex_terrain_colours, &tex_terrain_noise, &tex_alphatest, &tex_graffiti }, 4 ); diff --git a/world_routes.h b/world_routes.h index 2b85f87..141cbc0 100644 --- a/world_routes.h +++ b/world_routes.h @@ -3,6 +3,7 @@ #include "world.h" #include "world_info.h" +#include "world_gate.h" #include "shaders/vblend.h" #include "shaders/route.h" @@ -728,8 +729,10 @@ static void world_id_fixup( u32 *uid, mdl_header *mdl ) /* * Create the strips of colour that run through the world along course paths */ -static void world_routes_gen_meshes(void) +static int world_routes_gen_meshes(void) { + vg_info( "Generating route meshes\n" ); + struct subworld_routes *r = &world.routes; scene_init( &r->scene_lines ); @@ -853,13 +856,58 @@ static void world_routes_gen_meshes(void) scene_copy_slice( &r->scene_lines, &route->sm ); } - scene_upload( &r->scene_lines ); + if( vg_acquire_thread_sync(1) ) + { + if( !scene_upload( &r->scene_lines ) ) + { + vg_release_thread_sync(1); + return 0; + } + + /* UI buffers */ + + for( int i=0; iroute_count; i++ ) + { + /* OpenGL strips */ + struct route *route = &r->routes[i]; + + glGenVertexArrays( 1, &route->ui.vao ); + glGenBuffers( 1, &route->ui.vbo ); + glGenBuffers( 1, &route->ui.ebo ); + glBindVertexArray( route->ui.vao ); + + size_t stride = sizeof(v2f); + + glBindBuffer( GL_ARRAY_BUFFER, route->ui.vbo ); + glBufferData( GL_ARRAY_BUFFER, k_route_ui_max_verts*stride, + NULL, GL_DYNAMIC_DRAW ); + glBindVertexArray( route->ui.vao ); + glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, route->ui.ebo ); + glBufferData( GL_ELEMENT_ARRAY_BUFFER, + k_route_ui_max_indices*sizeof(u16), NULL, + GL_DYNAMIC_DRAW ); + + glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, stride, (void *)0 ); + glEnableVertexAttribArray( 0 ); + VG_CHECK_GL_ERR(); + } + + vg_release_thread_sync(1); + } + else + { + return 0; + } + scene_free_offline_buffers( &r->scene_lines ); + return 1; } static void world_routes_loadfrom( mdl_header *mdl ) { + vg_info( "Initializing routes\n" ); + struct subworld_routes *r = &world.routes; r->nodes = NULL; r->node_count = 0; @@ -989,27 +1037,6 @@ static void world_routes_loadfrom( mdl_header *mdl ) route->factive = 0.0f; mdl_node_transform( pnode, route->scoreboard_transform ); - /* OpenGL strips */ - glGenVertexArrays( 1, &route->ui.vao ); - glGenBuffers( 1, &route->ui.vbo ); - glGenBuffers( 1, &route->ui.ebo ); - glBindVertexArray( route->ui.vao ); - - size_t stride = sizeof(v2f); - - glBindBuffer( GL_ARRAY_BUFFER, route->ui.vbo ); - glBufferData( GL_ARRAY_BUFFER, k_route_ui_max_verts*stride, - NULL, GL_DYNAMIC_DRAW ); - glBindVertexArray( route->ui.vao ); - glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, route->ui.ebo ); - glBufferData( GL_ELEMENT_ARRAY_BUFFER, - k_route_ui_max_indices*sizeof(u16), NULL, - GL_DYNAMIC_DRAW ); - - glVertexAttribPointer( 0, 2, GL_FLOAT, GL_FALSE, stride, (void *)0 ); - glEnableVertexAttribArray( 0 ); - VG_CHECK_GL(); - route->ui.indices_head = k_route_ui_max_indices - 9; route->ui.vertex_head = k_route_ui_max_verts - 200; route->ui.segment_start = 0; @@ -1069,16 +1096,18 @@ static void world_routes_loadfrom( mdl_header *mdl ) * ----------------------------------------------------------------------------- */ -static void world_routes_register(void) +static int world_routes_init(void) { struct subworld_routes *r = &world.routes; r->current_run_version = 2; shader_route_register(); shader_routeui_register(); + + return 1; } -static void world_routes_free(void) +static void world_routes_free(void*_) { struct subworld_routes *r = &world.routes; diff --git a/world_sfd.h b/world_sfd.h index c6fa66b..05f191d 100644 --- a/world_sfd.h +++ b/world_sfd.h @@ -153,8 +153,11 @@ static int world_sfd_test( int argc, const char *argv[] ) return 0; } -static void world_sfd_init(void) +static int world_sfd_init(void) { + vg_info( "world_sfd_init\n" ); + shader_scoretext_register(); + struct subworld_sfd *sfd = &world.sfd; vg_function_push( (struct vg_cmd){ @@ -163,15 +166,12 @@ static void world_sfd_init(void) }); mdl_header *mboard = mdl_load( "models/rs_scoretext.mdl" ); - scene_init( &sfd->mesh ); - mdl_node *pn_card = mdl_node_from_name( mboard, "score_card" ); - mdl_submesh *card = mdl_submesh_from_id( mboard, pn_card->submesh_start ); - mdl_node *pn_backer = mdl_node_from_name( mboard, "backer" ); mdl_submesh *backer = mdl_submesh_from_id( mboard, pn_backer->submesh_start); - mdl_unpack_submesh( mboard, &sfd->temp, backer ); + mdl_node *pn_card = mdl_node_from_name( mboard, "score_card" ); + mdl_submesh *card = mdl_submesh_from_id( mboard, pn_card->submesh_start ); m4x3f identity; m4x3_identity( identity ); @@ -192,22 +192,39 @@ static void world_sfd_init(void) } } - scene_upload( &sfd->mesh ); - scene_free_offline_buffers( &sfd->mesh ); + if( vg_acquire_thread_sync(1) ) + { + vg_tex2d_init( (vg_tex2d *[]){ &tex_scoretext }, 1 ); + if( !scene_upload( &sfd->mesh ) ) + { + vg_release_thread_sync(1); + return 0; + } - free( mboard ); - vg_tex2d_init( (vg_tex2d *[]){ &tex_scoretext }, 1 ); + if( !mdl_unpack_submesh( mboard, &sfd->temp, backer ) ) + { + vg_release_thread_sync(1); + return 0; + } + + vg_release_thread_sync(1); + } + else + { + free( mboard ); + return 0; + } + scene_free_offline_buffers( &sfd->mesh ); sfd_new( &sfd->tester, 27, 13 ); + free( mboard ); + return 1; } -static void world_sfd_register(void) -{ - shader_scoretext_register(); -} -static void world_sfd_free(void) +static void world_sfd_free(void *_) { + mesh_free( &world.sfd.mesh.mesh ); vg_tex2d_free( (vg_tex2d *[]){ &tex_scoretext }, 1 ); } diff --git a/world_water.h b/world_water.h index 85f4b5d..11d9594 100644 --- a/world_water.h +++ b/world_water.h @@ -26,18 +26,35 @@ wrender = .fbdepth = { .format = GL_RGBA, .div = 4 } }; -static void world_water_register(void) +static int world_water_init(void) { + vg_info( "world_water_init\n" ); shader_water_register(); + + if( vg_acquire_thread_sync(1) ) + { + if( !fb_init( &wrender.fbreflect ) || + !fb_init( &wrender.fbdepth ) ) + { + vg_release_thread_sync(1); + return 0; + } + + vg_tex2d_init( (vg_tex2d *[]){&tex_water_surf}, 1 ); + + vg_success( "done\n" ); + vg_release_thread_sync(1); + return 1; + } + else + return 0; } -static void world_water_init(void) +static void world_water_free(void *_) { - /* TODO: probably dont do this every time */ - wrender.enabled = 1; - - fb_init( &wrender.fbreflect ); - fb_init( &wrender.fbdepth ); + vg_tex2d_free( (vg_tex2d *[]){&tex_water_surf}, 1 ); + fb_free( &wrender.fbreflect ); + fb_free( &wrender.fbdepth ); } static void water_fb_resize(void) @@ -53,6 +70,7 @@ static void water_set_surface( glmesh *surf, float height ) { wrender.mdl = *surf; wrender.height = height; + wrender.enabled = 1; v4_copy( (v4f){ 0.0f, 1.0f, 0.0f, height }, wrender.plane ); }