From 99376ce8eaf30125fb08dd5dc8b534800580fe47 Mon Sep 17 00:00:00 2001 From: hgn Date: Sat, 12 Aug 2023 15:49:42 +0100 Subject: [PATCH] challenge effects --- blender_export.py | 2 +- build.c | 2 +- ent_challenge.c | 33 ++++++++++++- ent_objective.c | 29 +++++------ entity.h | 3 +- font.h | 7 --- maps_src/mp_spawn/main.mdl | Bin 13230368 -> 13234440 bytes menu.h | 3 +- player.c | 5 +- shaders/scene_fxglow.h | 10 +++- shaders/scene_fxglow.vs | 31 ++++++++++++ skaterift.c | 2 +- world.c | 9 ++++ world.h | 10 ++-- world_render.c | 99 ++++++++++++++++++++++++++++--------- 15 files changed, 181 insertions(+), 64 deletions(-) create mode 100644 shaders/scene_fxglow.vs diff --git a/blender_export.py b/blender_export.py index 1b1c4fb..50f46c3 100644 --- a/blender_export.py +++ b/blender_export.py @@ -2148,7 +2148,7 @@ class SR_SCENE_SETTINGS(bpy.types.PropertyGroup): #{ use_hidden: bpy.props.BoolProperty( name="use hidden", default=False ) export_dir: bpy.props.StringProperty( name="Export Dir", subtype='DIR_PATH' ) - gizmos: bpy.props.BoolProperty( name="Draw Gizmos", default=True ) + gizmos: bpy.props.BoolProperty( name="Draw Gizmos", default=False ) panel: bpy.props.EnumProperty( name='Panel', diff --git a/build.c b/build.c index 811317d..a0a253f 100644 --- a/build.c +++ b/build.c @@ -190,7 +190,7 @@ void build_shaders(void) /* Scene */ _S( "scene_standard", "scene.vs", "scene_standard.fs" ); _S( "scene_standard_alphatest", "scene.vs", "scene_standard_alphatest.fs" ); - _S( "scene_fxglow", "scene.vs", "scene_fxglow.fs" ); + _S( "scene_fxglow", "scene_fxglow.vs", "scene_fxglow.fs" ); _S( "scene_vertex_blend", "scene.vs", "scene_vertex_blend.fs" ); _S( "scene_terrain", "scene.vs", "scene_terrain.fs" ); _S( "scene_route", "scene.vs", "scene_route.fs" ); diff --git a/ent_challenge.c b/ent_challenge.c index 515aeb0..bed8587 100644 --- a/ent_challenge.c +++ b/ent_challenge.c @@ -3,12 +3,13 @@ #include "entity.h" #include "input.h" +#include "gui.h" VG_STATIC void ent_challenge_call( world_instance *world, ent_call *call ){ u32 index = mdl_entity_id_id( call->id ); ent_challenge *challenge = mdl_arritm( &world->ent_challenge, index ); - if( call->function == 0 ){ /* challenge() */ + if( call->function == 0 ){ /* unlock() */ if( !challenge->status ){ vg_info( "challenge( '%s' )\n", mdl_pstr( &world->meta, challenge->pstr_alias) ); @@ -21,7 +22,11 @@ VG_STATIC void ent_challenge_call( world_instance *world, ent_call *call ){ challenge->status = 1; } else if( call->function == 1 ){ /* view() */ - world_entity_focus( call->id ); + if( (localplayer.subsystem == k_player_subsystem_walk) && + (world_static.challenge_target == NULL) ){ + world_static.challenge_target = NULL; + world_entity_focus( call->id ); + } } else { vg_print_backtrace(); @@ -53,7 +58,31 @@ VG_STATIC void ent_challenge_preupdate( ent_challenge *challenge ){ world_static.focus_cam.farz = localplayer.cam.farz; } + gui_helper_action( button_display_string( k_srbind_maccept ), "start" ); + gui_helper_action( button_display_string( k_srbind_mback ), "exit" ); + + if( mdl_entity_id_type( challenge->first ) == k_ent_objective ){ + if( button_down( k_srbind_maccept ) ){ + u32 index = mdl_entity_id_id( challenge->first ); + world_static.challenge_target = mdl_arritm( &world->ent_objective, + index ); + world_static.challenge_timer = 0.0f; + world_entity_unfocus(); + + u32 next = challenge->first; + while( mdl_entity_id_type(next) == k_ent_objective ){ + u32 index = mdl_entity_id_id( next ); + ent_objective *objective = mdl_arritm(&world->ent_objective,index); + objective->flags &= ~k_ent_objective_passed; + next = objective->id_next; + v3_fill( objective->transform.s, 1.0f ); + } + return; + } + } + if( button_down( k_srbind_mback ) ){ + world_static.challenge_target = NULL; world_entity_unfocus(); return; } diff --git a/ent_objective.c b/ent_objective.c index 330e60f..68a3dd0 100644 --- a/ent_objective.c +++ b/ent_objective.c @@ -8,11 +8,12 @@ VG_STATIC void ent_objective_pass( world_instance *world, ent_objective *objective ){ if( objective->id_next ){ - world->challenge_timer += objective->filter; + world_static.challenge_timer += objective->filter; u32 index = mdl_entity_id_id( objective->id_next ); ent_objective *next = mdl_arritm( &world->ent_objective, index ); - world->challenge_target = next; + world_static.challenge_target = next; + objective->flags |= k_ent_objective_passed; if( next->filter & k_ent_objective_filter_passthrough ) ent_objective_pass( world, next ); @@ -21,8 +22,8 @@ VG_STATIC void ent_objective_pass( world_instance *world, } else { vg_success( "NYU Film school graduate SUCKAH\n" ); - world->challenge_target = NULL; - world->challenge_timer = 0.0f; + world_static.challenge_target = NULL; + world_static.challenge_timer = 0.0f; if( objective->id_win ){ ent_call call; @@ -72,29 +73,21 @@ VG_STATIC void ent_objective_call( world_instance *world, ent_call *call ){ ent_objective *objective = mdl_arritm( &world->ent_objective, index ); if( call->function == 0 ){ - if( objective->flags & k_ent_objective_hidden ) return; + if( objective->flags & (k_ent_objective_hidden| + k_ent_objective_passed)) return; - if( world->challenge_target ){ - if( (world->challenge_target == objective) && + if( world_static.challenge_target ){ + if( (world_static.challenge_target == objective) && ent_objective_check_filter( objective )){ ent_objective_pass( world, objective ); } else { vg_error( "womp womp\n" ); - world->challenge_target = NULL; - world->challenge_timer = 0.0f; + world_static.challenge_target = NULL; + world_static.challenge_timer = 0.0f; } } } -#if 0 - else if( call->function == 1 ){ - if( objective->flags & k_ent_objective_hidden ) return; - - vg_info( "begin the challenge\n" ); - world->challenge_timer = 0.0f; - ent_objective_pass( world, objective ); - } -#endif else if( call->function == 2 ){ objective->flags &= ~k_ent_objective_hidden; diff --git a/entity.h b/entity.h index 6faa7d9..5ac85d8 100644 --- a/entity.h +++ b/entity.h @@ -425,7 +425,8 @@ enum ent_objective_filter{ }; enum ent_objective_flag { - k_ent_objective_hidden = 0x1 + k_ent_objective_hidden = 0x1, + k_ent_objective_passed = 0x2 }; struct ent_objective{ diff --git a/font.h b/font.h index 76e63c8..4361e93 100644 --- a/font.h +++ b/font.h @@ -169,13 +169,6 @@ void font3d_begin( const char *text, shader_model_font_uMdl( transform ); } else if( render->shader == k_font_shader_world ){ - - - vg_info( "-----\n" ); - for( int i=0; i<4; i++ ){ - vg_info( PRINTF_v4f( prev_mtx[i] ) ); - } - shader_scene_font_uPvmPrev( prev_mtx ); shader_scene_font_uMdl( transform ); } diff --git a/maps_src/mp_spawn/main.mdl b/maps_src/mp_spawn/main.mdl index caf82eec3d24dd3f8c889ce4b4c15058d6f2d762..acbcb5130344d26b6c5ee22cf2b5219322a11bd7 100644 GIT binary patch delta 23922 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 delta 18619 zcmbW9d0bT0|Nj}7VI9^PRslgq76lg=6=WGJEGyfw(kv?mlTa|ha!c|9scEJ%=&_IG z29|4TV3;D@J2N0h+(E@$K*2S|1yo#UzVCCH_p#68_ur4XuXCUGocH^j_c{08HwT+X z3ord@zs~rp{jzH^nPG{oZ_v(M8yhDZ8=EFjMt0tW&pye^0F-`48Dz3vviA)^P|h$U z$a)3U&9)x9t_Q@RW^>3>qWRditjsQ$Cq0neQ~bW!p>EVwhsvYq$r5Du>!s zt6ko-PbN;xOqc9J&e+%l19@26rsYh}%b1Xzqi1tEYq($=U<;?mwgD+NXKif6AUm5u z&@e?mdBT?&({Lg-gK}2d*lo0zMqzE4+4{_M>#B^f+hx;ozU*zg3vSAWmp}2y&HDr# zw`?gJwdHfdo*aVa%y_Y_GW+E{^gs2&c5Rojs^Lt+kbV z7@j}<&b6wT(|vWr zNMN)YlFjS+)(9dq6-s64dv8@m ze3_%GuP{_e5mdaNsR*={#a2wuQsm2AEt8E&i97Ojn#HlOWY4Wt_!0jpibUmB`Jm)6 zO>=d}bla1A{ANs1%u&d$ko(gV6I`21jwO5DpQF1g{B2!nG9y=^bQzhyC;9558M=EL zJ|IW$%KgcvT*V>Rl*hDcLt>Whm5PRa*5FpYe16gXp1DL$S0uS^ zj2T&~H#DYIpRQ_k+wR~M1v?6K)$=2>xnr7W5mlOlYbUfpvyA{W8kXmm8E{4=5?Wy<{z zt%oglpEXL zt9tn2OkK?V9s7G`Ib#PbxGDbCDs|Ni-K8Qs>$AEEs$DBj#Z(>j`%+{_z`gbWyu@_4HIRX{X|*O!+AIL{<2A;kpN_ z!mKxC#_w=b#`lWQ9bD13=b@khq+Jlbyr7tSCThp!>jJUPccyDG=0|R zx{MT8nB=?|u*8oB6tL`=whS z<7*-IsdClI^5JBv+`*r`9BQvp^u4-fc+WFgF(cGI+QD_|lDO)(9fs)MomgQ_6BTul z_N8`;d%-_jGeO0|X!}F<%1XL+e|$WwlfLrLo>zHBoW0W3>5=39*U#qb)Z^C-w=T)1 zIC~GpG+5@ZEB43PlYy?Ci_RxkR(z%#Hs=I9(9&;-8R-yn*)ormb@DN~{MVgyJzZ`} zhnV}lC<1*?^yw|8-Up!y}{z^&JHq064Yt1zz|-lt5x z{aQPRzsknxYSwHdYguZGoCE=etIwtA|MQV<>3g$q@b@R#tL-X3eyb+|E(9y(_NkXs zUU+VT&TaI|DMUC5&)A=n?6Z_P<(|oh>hpEmBa5x8Ix5qCvTJ$Z^28*#iSB#5anenh zFjmr=yA$`pT|06lA#J(KH!4 zSTW$8ZXr4jal1qioMb$@$;XPUl{w9Zc4}Oo}lBW*n2p9>-eQ^Z_}clnn_^i z8WXx?--Zcub-Uiag8r+f*sB$;Z=Oi9J}q_3?nG!%^2nNe-RU_+IDXd@`^n0N40Y8v z+lK1$W(>66f`!@kQ=I~vhU!xG54Pq#;+F%a&PNg|&poHoxun0PBZD&F3EP|lcSgN> z;l7b{nC^r&7Sm)?j{SIIdo%iU!4i27m^F27v~HVnJ~rEoca6C}#K`((ufnEl^0(uoR8uS|IbpoyT*K$Ae3pwB^Bpvj;qplnbMXe#In&@@mkC=WCp z^d;yk&Ya$pt+!Y&^MrYp#OjhK!u=hLGwWiKnp?Nffj)lgT4nX0sR14 z3R+h2$Z7e4or(t^EKV*Z-|k)B--^2d?Vy&l?p+=ufok9K7;EFmecWz3pwwIf%@Q;` zvr|-ZyCHy5b9$xK&H!NT4_^MB#tv)@+YeUn`x(eP2n7gb2(1XJDy#7e2)PI)2n`5! z)mGy;gmeT0f(fAmAxyw{5DE~=5LyvbBF2M|i%^2lfM93Dco5PN3;xo(J5Rn&zE8%SfTYob-#)|L&+szCo`mJyz;Ps?lwfijAOM!RN&u{O zC$Z74(b^aXU~SB3w0at_(e$kGJ~oD(w0gb+fbpH=q3(W$m!F~cDd?J|u@_ERS0xvr z1fc=J?zGh=4j~=EfM7!CKnQEHdcA{CfKZ0eil91UHGTmh7oh~90m1Gsj0Yhd!GK^w z=s*ZNi}4^7Ae14rBB;(`JP5f6B?t`&cIPo3gmeT0f(fAmA?yOigHV7_hR}+jYQ}gF zauG@p8W8MSFdl?-1OtKzp#vf8BF2MIfKZ0eilDlL@gU?Plpr)9*tKFj2gbswTs~8VL0YVuaP(D2Moansru zchlOK4q#19E1=PeHE7p?c44=;-I!a}P70t-8lj8<%RH?Js&;G53kbOgB?t`&cDJp@ zaR})M1_TpA2SV5#tJgaS1qfvbtq7{S7!N`&LJ2|xg55og2O%B7fM7!CKnUx=cn}H@ z$`D!+RGkBdo?tu(=?De{6G8_<*i(!Lp#Y%_ zp%p>ZjqxDlB9tIBAlUtb@gSrl7!XVd9SC6-j0d3rp$wtb3M*7a(hIlZ1?xH2dM>e^ z8+y*fPG*HTgmeT0f(fAmAo3OSW?YU8AKLXT8Vd7Mf)HFAMU=Gp9~Y8W;3U<5bA0 zoKqVowGus2Ipr~uz1ERJN;x%hlDlH7mXn@SF(cE|t`uVC)X7QXhOKFw3OSW?YU8AK zM~_rad7Mf)HFA=Bpof-|o>MU=Gp9~Y8c+01<5bA0oKqVowHJD%a?0aW%Bhi)T!kK5 zPI^wojNrdw>WG>Thn^TO-Bkjm2+z2r1q9Pz%G?j9;Z@Hjhy5@=%MAL=Tywe z%&C);#ut6lI2Cd#=hVhY?S~$zobou8a%$ux_eT#cCq1WPPG(M>oHPOGo5rb-Q#q$L zPU>Fhk;*BLQz@rLPVzwX&~nmqD&}P7)X7N`guZE<3OSW?YU891MvqiZd7Mf)HFA>o zMh`6~J*Q$$W=@@)G$H7l#;K4~Ij1&G>QMAZ<&?*%lv5)oc^~x9a?*1u=49s7$w?E2 zzG<8aIhAv2%RLH5EQyV9B1bU=$ z%HveZsgaXB5^qh)0nK^ZG(nO(e8mB@|<(%3$sr#WvDyKY7rJNc$$@`;+mXn@S zF()&pPEML=^iAVb$f=xD8z*%PdZcp7<5bG2k&}D?dT2T6ITdp~Ck>g1#ug1%{-3OSW?YU89HiXN$)@;H@pYUCszh8|i@dQQch%$zzo zY2wj0jZ-0~a!zfW)CuU3$|;XiDW^tG^5N*A<)r6S%*o8DlanS9ebYDr(#ZKPMw@IDd?NVsgP4Sr#4P%9eTi*Fxburb~1UKN;x%h zl8-<;EhjyvVoqjGot!k!p>G-dQQcRq`kM9 zQzs`)Dz>I^D&$no$cF9P+c>F5VqGeyJVrhHdtTSbN&X^wXc#`55t?Wz9>zD^sO{9+h zcd7r?%9r}ta{a57EtfQZYfuYH#utGMpkmMp&`J;itpfcB`Y&iT=qJ$6pf#Yipmm`2 zpbelBP$_65=oiqhpiQ97pe>-SplzV-px;0{Ks!OZK)-{^K;@v_pg%wrpgo{JL3=^_ zK$W2Vpej%`NC1f-Bgh0YgK9vvpaY<~ijwg(%|HL~jaJK(zuTg+a)g|$>?|RBwvZ!c zWs6xNsJpxSV6+$^hKRk?qN6Y_B_TE@JV0=B7$an4WK7DiJigk}oo#u1{o+$7E_GX= zx2Hlrba=U&6;Gj4%adDIyR)(_Puj0Nh2lCiv|oSfoju#~^!AOXj+Q64Z*&X(8uI;@ zbYo;_fU~#YX6Ix(%<|;s6)?Sd1)OeP?(Ua4k#+u$BOC0WA!N!|)bF)NZD${^pJ{n? z<@^)N<0}^)=dgGHueCge;^LDW2nC$r;zrw(xonz`vshS9V4ke&$E>{ighlvRAPry9 z{fZE8(O*s0&!B2qIN3Xc2Kzj^c>0m$(WR!Y99SaDw@C!qxekL z|07MNrK{!SLrYh4<0DJgg@!Im*ZC8V^bGH_$_G$D^P`qi53(%~)qUpm0E#o@ty$E^ z@9~xM57{z25VIkstIcq6wfVjfNaoL?i|r!<#RzW?(t9@5*t*A)muJ&K!ChyMbXdC1 z9qr7@VPgSbXy}Ad8i1M`iD5Pk4agQOk6O=kK=D^6!@oLmSkRrKD>*Zp9*9s13c-d2 z0VbE4n90S{9pOH{LI&%jLkFkx$2&sE={YoL)Wg&CuH|9V!F!g6XX@`}Sswm%_#PYk z+|j#PSMoo4JyzUxAuoMR%N%W7#tAZE=n&#OmnL~U zXfWT&u{=0gdpj#X8}1buJC_CqJv@8#_FU-t+_5{XXlD~Wen(*CZ5y(3F5MLsrHx_{ zKs(q5SRS4|a)%YSy@W(T7ioc*;rcYa?LqSLX;|w0V^z1ZEDw&0?Un~8M1~C}z((_} ztnAqn1j~a{b?tMR!%bG)%30-x9I}(w0w8y&KFf+Xa8GAi+M-+4AsI z-L0|UegJwqS$iwf&od)|4FQ+O#aov9$Ew?X^%)tN`Z1RKhyMIKC(CmG$iACU?EgF4 z^59t24QBFp4(UCQ2D(E$f5U4mz_=%CZ@7`y=g~$t2MDv~hAqU{Xug?9;{QW~#}5#o zhsv8inHd>r8J133e$&!fS9ZhFd0^MyjIQTo<$sg~1q^q1-?bcO4I>@he;pi;R$YTZ ztFE)+8pKcyl~4j6uf9HD0;&8DZIx-rx&j&?(~;@|+BdGlyzPpm!~EOT9C$lf(t$B| zU$Jx^+|Wl%fkcSV%|e?p6QNX1OQ) zdfCz;Zfdi17`I%`wse@bw!tgfVcrhaHNUl4I%{@Z&d!2mfV3vSWPWc;U{h)n$(V2H z5$6G-7N+@oTV@PNm`{UcA!Ph~+9&YdzIB%@_bS)7TJG)N08~{1R8@K@XBIqEKhLKj zfgQ%Jm)K~nthfXtnzpq{R3~QB~6NK{gxnVvglr^~M&XPSBF1g|zOu zNHH@yl-Yvw{tYde6K#hItjCK3!ZOBM?(X?-bB5(^#j1;zyMK@teI{I#8!lwQQmd*HhZ+u7nf*`{?vuK)`?}dr1JP+4vnzQ`{HCg-}Jv1aClleAV?v@o@$h6$~eOWUU zOD|+(Snljxa!#<^+4aMD%iZ6Xp38!A8DQD+b6Mp3MKsVm`!mbk-7C*!ix9=i^8$JnMzGx8R@gKVW(_bO8n(}G$}-Lp*}&46P5nsx5*i{)A|EcH2VZF4IP;XH z{g+v%S#i?R{_AXZIr}6$T(>uUeF}QnH20*C0I!z?#yhEyPSEYvQUmrjT4(k~k!C0N=we$|i#<%~wi)Pb=u z;LOGdseUFYSW3%X)y%X3%97~~GBSD@^?&Zxx+y1w&+;=Z?dx)m=UCd;PdzbQ0jDpH zv*LtkY2Uzb!xtx@{|(cQ%UF2=+NK@%^A!99S5mf&Zi$i&7ZjPofJ^~8T07+gE3=M+ z$C}SiWRA1k`uVe?P)s@|=8zwj(;#&Qv}7G+#W7)MtZlMw?672VWI5gc=FsG!rf4xl z$P_HMewqkgKTSNA31tT0YCXf%pB~Bd`3%nKhgsDTFAbQk)*sFWEBz5>de~p%ugTE_ zi&4RY$n_$6ZSbvCA07g$RUg({ZvFV-At*kohwC3dIwWRI2?#X?xCg-1gn9um)Ep4% zL!66gpv;~0FQyA#QMrlWJ06BxH6DCdjjx9=$OnLAT)pKc8B3vf{~#-*%Y(C^1uCKW zpyk%evD8-x7JZebU^7vypv}=YSB$B%+*~>404so2q#f`R;56od2<5wVt|F|f^&sk% zbj=`p)|^(yn%_Af=q)#k->S_rhO%>w5b6^N4aILmcg1hlM2bO?Ch}+{-4Pxg>H`O~ zTW%WOFtNf6{TSY;iLZ%?7h>$7v%0Wa=~3BMXTu2 zu$x7rtHH5ov{Z<(Lb4DmL?p*1N3f3&D<%tM{Eu|08<V2l_k^0gHHm}7#6iZMl6~y()Hk5EZ-CfW2J%9+7#aey&lfRG>#NH7k7QY7_1(+bvH#wIrUcOlH= z7v?8~!BYz)lI?5g8ZT(rRl}Nhy85}+*up`w*V07+P_sj@9cH#22Bm1rEPfki0*ofX z>*#dPXjZdbj5dcx3!y@E=mAo;j{fTDBQ4QZ(Wk}*l6Q@d3;B9I{e$(kMQYh>BMcF3 zh6px8Y~U;ou^}IBpj*A6{a2}dQ}2Gg`yJ>l^fUD~l7S_3iEnQ<&_-7L;?!H+TP-@N z>zvdzxXT@u;<3(bb7W%SQU z!eAk3F#CwCFei!R^3kK`8Km1^WCwp0)VPUuwWMMz4U@%_=B@O#fOzJ$Twmmq&4ZZ#CI3{l|A*}O4BYBqr~8- z;3#8ol)w&hbr;QMH@?6etTF`)DkDe;R*|W{(*m|y^Vov?Cs}l?Np>_PJDQ1q8U0a} z%xb@>gBQP6!u(i~94n*m_(n)`of{DduYE+I5MhQgLJTCYmeXHYKKNP)^sI-!V?2$4 z#Bn#B&2HpuqrI328&>HfB-+D~XiqlprdvIrbrvLs+QdQT#6gLJ&XK8q&^K6EGaw-Z z^fd+;`s%(5Xbh{K}UM_`93dKl^0OLwuhDUcm%qpfKon&k?C828b+?8auXQ75xh z;Ul{ExClO!d|F8}ncL@ri(unov=Lm)HZD-wxCo@Zl5TNFc) zNw?s$ej=oen%;1b-c@udyT=oS-fE$@pf>iLNL>~El|6kK@VlyLwBG3ySx`-5-BYB; zD_ux2#ifXGDdbc&oz9~BRDf(@jx+XT4lyoLB-sKjVRQeah4c~WD7LHzf)t5#qL%|}`N%;`axf=3n35cfNyNuU*SjaN`VVU$fk>Hy95K=b5l}V0`}W}Q zdxOKxto?&<)8O#t!QrjF!p*&;H*j1plSePI+(aj{^%*NA4=I0`AcuHB79kol-OAeD zhtvUSWw?>$4+Weci?o~REH?M|jKc>W9zIYQPUhB7f3`~RO6xa9bHHCC`fHAm${MO= zFHoAl;3j~qC&6EYOE=k^{ALotGVJdRw%MKVT=u z8|{R6N(v9q>1^5FIzyc6Xum;#Z+0JHc5n3Y?Q_hxPn&O_bH07dzJ0oU`DU!=|bP1dDXaN$9(VA<9ihu%HM(H+o zBVQfb-#oOxFjVX>LfR2PWb8ruhbuI_QrBM$G4~fj4wA@vn$BL?mqqv|j1X^Ah<80H zt*6fqgSt_oxASdp=cC@v-QCUJ&P^km>^)-55d!)42wlz+MhZ(kBFj6Fe8_;KbOBqBWFb)W zgya)whU60{0E(pXC@oe=cP`1(1Y43?kYMjwLlzvPGu@=AuvAnB$w?#u$7wFhJi`-> zgV-T`gv1)M^*H_1eUKDo!l1r`Xx~9~eM!^_`l55+V=T=0zV!j5-~TY9e!b=pUCz;h8;Y{f!*B)Y=?C}W-}SkFf5uJIz=b36^=1l zvzizxvb-jSnn~Jey2V|()37b7^$D%<39Ti)n&|SrJv*cRKHaxnd|F(5YF&ITxcD4* z@wwr`N9y;0+-{=2J`HTBDA*(Q946Q^8EuA;@H4Q%f|f{Oh^gO@1N~Sj^dnc#P(x@x z-bn-_DPM&5R@d}an|rhLS3~~zi@xS{lJ(rzx`%QS)HO~d>?~aq=EU7K+&#>g5+|g@ znNx%~paaBmmd1XH93o54(Q)cX?j0&d1|5nFiVUhFp66*FZ|M~e5rRZ7 zIE+E?&oo{_5PADN-PD(l)0+|e6;L!f*g;5gNP>JRFfhVF5--rzF-g4tptDJXZzc`y zJ^?zKH25g<3LFfXvL<|RIPAy52iKC`&2*t}ICp`)mpQzbDV%M?4wA#o^j+C`(!Yg9 z1bHwUX{G!H4~2&jawyB9Y)9r{BJ*45PEQ5z#_y=KFC$|v(u`iL_7EG}m$&;2G{J`K zh=$y{2>&K5ts?wYR5aR~E8*~UnIj@>DnM} zpmHk6e zvNNf=M%PGB1#6XtcNY7H^bdhTgiI~;hl4D=PK$#=m<9Whtejxm=xvsgH{|ac^8O8) z!~2nbt2heY&fd;aA$kkWHQvtT=?z*G*waaOw`AlXIM?cW_L{KW6p8t7I={CLP1yMq zi`ZVrwwniZT0y6+BlB<4SAG6%)68rX2enb>iQ_FADJ>A&UKlUd#5SY-cKx zski86>A^)ic9#0F6M{|BPBj=x6@192?R2+HMdmr~QhQ%z-Px)f&Fl~yRgO@IWb$ol zkU267e@|(NWsWr25$2fe_%xYS$JjSn*nhcU>=z^b3VVt5^r8U!X(nlFtrZi7Kp1ze N|BZ+JUx93F{ttn$tk?hm diff --git a/menu.h b/menu.h index 44feffd..59c01f6 100644 --- a/menu.h +++ b/menu.h @@ -215,8 +215,7 @@ static void menu_trigger_item( ent_menuitem *item ) menu_close(); } else if( MDL_CONST_PSTREQ( &menu.model, q, "reset_home" ) ){ - world_static.active_instance = 0; - world_static.active_trigger_volume_count = 0; + world_set_active_instance( 0 ); localplayer.viewable_world = world_current_instance(); localplayer_cmd_respawn( 1, (const char *[]){"start"} ); menu_close(); diff --git a/player.c b/player.c index 12f8cbd..f5176eb 100644 --- a/player.c +++ b/player.c @@ -165,7 +165,7 @@ void player__pass_gate( player_instance *player, ent_gate *gate ) m4x3_mulv( gate->transport, player->cam.pos, player->cam.pos ); if( gate->flags & k_ent_gate_nonlocal ) - world_static.active_instance = gate->target; + world_set_active_instance( gate->target ); audio_lock(); audio_oneshot( &audio_gate_pass, 1.0f, 0.0f ); @@ -282,6 +282,9 @@ PLAYER_API void player__spawn( player_instance *player, ent_spawn *rp ){ player->immobile = 0; player->gate_waiting = NULL; world_static.last_use = 0.0; + world_static.focused_entity = 0; + world_static.challenge_target = NULL; + world_static.challenge_timer = 0.0f; world_entity_unfocus(); if( _player_reset[ player->subsystem ] ) diff --git a/shaders/scene_fxglow.h b/shaders/scene_fxglow.h index 8225145..a86f520 100644 --- a/shaders/scene_fxglow.h +++ b/shaders/scene_fxglow.h @@ -7,7 +7,7 @@ static struct vg_shader _shader_scene_fxglow = { .link = shader_scene_fxglow_link, .vs = { -.orig_file = "shaders/scene.vs", +.orig_file = "shaders/scene_fxglow.vs", .static_src = "layout (location=0) in vec3 a_co;\n" "layout (location=1) in vec4 a_norm;\n" @@ -36,6 +36,7 @@ static struct vg_shader _shader_scene_fxglow = { "uniform mat4x3 uMdl;\n" "uniform mat4 uPv;\n" "uniform mat4 uPvmPrev;\n" +"uniform vec2 uUvOffset;\n" "\n" "out vec2 aUv;\n" "out vec4 aNorm;\n" @@ -52,7 +53,7 @@ static struct vg_shader _shader_scene_fxglow = { "\n" " gl_Position = vproj0;\n" "\n" -" aUv = a_uv;\n" +" aUv = a_uv + uUvOffset;\n" " aNorm = vec4( mat3(uMdl) * a_norm.xyz, a_norm.w );\n" " aCo = a_co;\n" " aWorldCo = world_pos0;\n" @@ -444,6 +445,7 @@ static struct vg_shader _shader_scene_fxglow = { static GLuint _uniform_scene_fxglow_uMdl; static GLuint _uniform_scene_fxglow_uPv; static GLuint _uniform_scene_fxglow_uPvmPrev; +static GLuint _uniform_scene_fxglow_uUvOffset; static GLuint _uniform_scene_fxglow_uTexMain; static GLuint _uniform_scene_fxglow_uCamera; static GLuint _uniform_scene_fxglow_g_world_depth; @@ -458,6 +460,9 @@ static void shader_scene_fxglow_uPv(m4x4f m){ static void shader_scene_fxglow_uPvmPrev(m4x4f m){ glUniformMatrix4fv(_uniform_scene_fxglow_uPvmPrev,1,GL_FALSE,(float*)m); } +static void shader_scene_fxglow_uUvOffset(v2f v){ + glUniform2fv(_uniform_scene_fxglow_uUvOffset,1,v); +} static void shader_scene_fxglow_uTexMain(int i){ glUniform1i(_uniform_scene_fxglow_uTexMain,i); } @@ -475,6 +480,7 @@ static void shader_scene_fxglow_link(void){ _uniform_scene_fxglow_uMdl = glGetUniformLocation( _shader_scene_fxglow.id, "uMdl" ); _uniform_scene_fxglow_uPv = glGetUniformLocation( _shader_scene_fxglow.id, "uPv" ); _uniform_scene_fxglow_uPvmPrev = glGetUniformLocation( _shader_scene_fxglow.id, "uPvmPrev" ); + _uniform_scene_fxglow_uUvOffset = glGetUniformLocation( _shader_scene_fxglow.id, "uUvOffset" ); _uniform_scene_fxglow_uTexMain = glGetUniformLocation( _shader_scene_fxglow.id, "uTexMain" ); _uniform_scene_fxglow_uCamera = glGetUniformLocation( _shader_scene_fxglow.id, "uCamera" ); _uniform_scene_fxglow_g_world_depth = glGetUniformLocation( _shader_scene_fxglow.id, "g_world_depth" ); diff --git a/shaders/scene_fxglow.vs b/shaders/scene_fxglow.vs new file mode 100644 index 0000000..10c820a --- /dev/null +++ b/shaders/scene_fxglow.vs @@ -0,0 +1,31 @@ +layout (location=0) in vec3 a_co; +layout (location=1) in vec4 a_norm; +layout (location=2) in vec2 a_uv; + +#include "motion_vectors_vs.glsl" + +uniform mat4x3 uMdl; +uniform mat4 uPv; +uniform mat4 uPvmPrev; +uniform vec2 uUvOffset; + +out vec2 aUv; +out vec4 aNorm; +out vec3 aCo; +out vec3 aWorldCo; + +void main() +{ + vec3 world_pos0 = uMdl * vec4( a_co, 1.0 ); + vec4 vproj0 = uPv * vec4( world_pos0, 1.0 ); + vec4 vproj1 = uPvmPrev * vec4( a_co, 1.0 ); + + vs_motion_out( vproj0, vproj1 ); + + gl_Position = vproj0; + + aUv = a_uv + uUvOffset; + aNorm = vec4( mat3(uMdl) * a_norm.xyz, a_norm.w ); + aCo = a_co; + aWorldCo = world_pos0; +} diff --git a/skaterift.c b/skaterift.c index e56a43a..9b90548 100644 --- a/skaterift.c +++ b/skaterift.c @@ -143,7 +143,7 @@ static void skaterift_restore_state(void){ }; skaterift_world_load_thread( &args ); - world_static.active_instance = vg_msg_seekkvu32( &world, "index", 0 ); + world_set_active_instance( vg_msg_seekkvu32( &world, "index", 0 ) ); world_static.active_trigger_volume_count = 0; localplayer.viewable_world = world_current_instance(); } diff --git a/world.c b/world.c index c3b5516..019e572 100644 --- a/world.c +++ b/world.c @@ -26,6 +26,15 @@ static void world_init(void) VG_MEMORY_SYSTEM ); } +static void world_set_active_instance( u32 index ){ + world_static.challenge_target = NULL; + world_static.challenge_timer = 0.0f; + world_static.focused_entity = 0; + world_static.focus_strength = 0.0f; + world_static.active_trigger_volume_count = 0; + world_static.active_instance = index; +} + static void skaterift_world_get_save_path( enum world_purpose which, char buf[128] ){ addon_reg *reg; diff --git a/world.h b/world.h index 63bfa9c..d35f064 100644 --- a/world.h +++ b/world.h @@ -194,9 +194,6 @@ struct world_instance { u32 cubemap_cooldown, cubemap_side; rb_object rb_geo; - - ent_objective *challenge_target; - f32 challenge_timer; }; struct world_static { @@ -214,12 +211,14 @@ struct world_static { world_instance instances[4]; i32 active_instance; - - /* TODO: FOCUSED_INSTANCE */ u32 focused_entity; /* like skateshop, challenge.. */ f32 focus_strength; camera focus_cam; + /* challenges */ + ent_objective *challenge_target; + f32 challenge_timer; + addon_reg *addon_hub, *addon_client; @@ -234,5 +233,6 @@ static world_static; static void world_init(void); static world_instance *world_current_instance(void); +static void world_set_active_instance( u32 index ); #endif /* WORLD_H */ diff --git a/world_render.c b/world_render.c index 35730ac..1272879 100644 --- a/world_render.c +++ b/world_render.c @@ -414,31 +414,68 @@ VG_STATIC void world_render_challenges( world_instance *world, struct world_pass *pass, v3f pos, int layer_depth ){ if( !world ) return; + if( skaterift.activity == k_skaterift_replay ) return; /* sort lists */ - const f32 radius = 40.0f; - bh_iter it; - bh_iter_init_range( 0, &it, pos, radius+10.0f ); - i32 idx; + f32 radius = 40.0f; u32 objective_list[ 32 ], challenge_list[ 16 ]; + v2f objective_uv_offsets[ 32 ]; + u32 objective_count = 0, challenge_count = 0; - while( bh_next( world->entity_bh, &it, &idx ) ){ - u32 id = world->entity_list[ idx ], - type = mdl_entity_id_type( id ), - index = mdl_entity_id_id( id ); + ent_challenge *active_challenge = NULL; + int running = 0; + if( mdl_entity_id_type( world_static.focused_entity ) == k_ent_challenge ){ + if( (skaterift.activity == k_skaterift_default) && + world_static.challenge_target ){ + running = 1; + } - if( type == k_ent_objective ) { - if( objective_count < vg_list_size(objective_list) ) - objective_list[ objective_count ++ ] = index; + if( !((skaterift.activity != k_skaterift_ent_focus) && + !world_static.challenge_target) ){ + world_instance *challenge_world = world_current_instance(); + u32 index = mdl_entity_id_id( world_static.focused_entity ); + active_challenge = mdl_arritm(&challenge_world->ent_challenge, index); } - else if( type == k_ent_challenge ){ - if( challenge_count < vg_list_size(challenge_list) ) - challenge_list[ challenge_count ++ ] = index; + } + + if( active_challenge ){ + shader_scene_fxglow_uUvOffset( (v2f){ 8.0f/256.0f, 0.0f } ); + challenge_list[ challenge_count ++ ] = world_static.focused_entity; + + u32 next = active_challenge->first; + while( mdl_entity_id_type(next) == k_ent_objective ){ + u32 index = mdl_entity_id_id( next ); + objective_list[ objective_count ++ ] = index; + + ent_objective *objective = mdl_arritm( &world->ent_objective, index ); + next = objective->id_next; + } + + radius = 10000.0f; + } + else { + shader_scene_fxglow_uUvOffset( (v2f){ 0.0f, 0.0f } ); + bh_iter it; + bh_iter_init_range( 0, &it, pos, radius+10.0f ); + i32 idx; + while( bh_next( world->entity_bh, &it, &idx ) ){ + u32 id = world->entity_list[ idx ], + type = mdl_entity_id_type( id ), + index = mdl_entity_id_id( id ); + + if( type == k_ent_objective ) { + if( objective_count < vg_list_size(objective_list) ) + objective_list[ objective_count ++ ] = index; + } + else if( type == k_ent_challenge ){ + if( challenge_count < vg_list_size(challenge_list) ) + challenge_list[ challenge_count ++ ] = index; + } } } @@ -449,15 +486,31 @@ void world_render_challenges( world_instance *world, struct world_pass *pass, for( u32 i=0; ient_objective, index ); - if( objective->flags & k_ent_objective_hidden ) continue; + if( (objective->flags & k_ent_objective_hidden) && + !active_challenge ) continue; - f32 dist = v3_dist( objective->transform.co, pos ) * (1.0f/radius), - scale = vg_smoothstepf( vg_clampf( 5.0f-dist*5.0f, 0.0f,1.0f ) ); + f32 scale = 1.0f; - v3_fill( objective->transform.s, scale ); + if( running ){ + u32 passed = objective->flags & k_ent_objective_passed; + f32 target = passed? 0.0f: 1.0f; + vg_slewf(&objective->transform.s[0], target, vg.time_frame_delta*4.0f); + scale = vg_smoothstepf( objective->transform.s[0] ); + + if( (objective == world_static.challenge_target) || passed ) + shader_scene_fxglow_uUvOffset( (v2f){ 16.0f/256.0f, 0.0f } ); + else + shader_scene_fxglow_uUvOffset( (v2f){ 8.0f/256.0f, 0.0f } ); + } + else { + f32 dist = v3_dist( objective->transform.co, pos ) * (1.0f/radius); + scale = vg_smoothstepf( vg_clampf( 5.0f-dist*5.0f, 0.0f,1.0f ) ); + } m4x3f mmdl; - mdl_transform_m4x3( &objective->transform, mmdl ); + q_m3x3( objective->transform.q, mmdl ); + m3x3_scalef( mmdl, scale ); + v3_copy( objective->transform.co, mmdl[3] ); shader_scene_fxglow_uMdl( mmdl ); for( u32 j=0; jsubmesh_count; j++ ){ @@ -466,10 +519,8 @@ void world_render_challenges( world_instance *world, struct world_pass *pass, if( sm->material_id != last_material ){ last_material = sm->material_id; - pass->fn_bind_textures( world, &world->surfaces[sm->material_id] ); } - mdl_draw_submesh( sm ); } } @@ -505,7 +556,6 @@ void world_render_challenges( world_instance *world, struct world_pass *pass, for( u32 i=0; ient_challenge); i++ ){ ent_challenge *challenge = mdl_arritm( &world->ent_challenge, i ); - vg_line_point( challenge->transform.co, 0.2f, VG__GREEN ); if( challenge->status ) count ++; } @@ -519,6 +569,8 @@ void world_render_challenges( world_instance *world, struct world_pass *pass, m4x3f mlocal; m3x3_identity( mlocal ); mlocal[3][0] = -w*0.5f; + mlocal[3][1] = 0.0f; + mlocal[3][2] = 0.0f; for( u32 i=0; imtx.pv ); @@ -806,7 +859,7 @@ VG_STATIC void render_world( world_instance *world, camera *cam, glBlendEquation(GL_FUNC_ADD); shader_blitcolour_use(); - shader_blitcolour_uColour( (v4f){ 0.5f, 0.5f, 0.5f, greyout*0.5f } ); + shader_blitcolour_uColour( (v4f){ 0.5f, 0.5f, 0.5f, greyout*0.56f } ); render_fsquad(); glDisable(GL_BLEND); -- 2.25.1