update helpers/location to 'frosted' ui
[carveJwlIkooP6JGAAIwe30JlM.git] / ent_npc.c
1 #include "vg/vg_mem.h"
2 #include "ent_npc.h"
3 #include "shaders/model_character_view.h"
4 #include "input.h"
5 #include "player.h"
6 #include "gui.h"
7
8 struct npc npc_gumpa, npc_slowmo, npc_volc_flight;
9 static struct skeleton_anim *gumpa_idle;
10 static struct skeleton_anim *slowmo_momentum, *slowmo_slide, *slowmo_rewind,
11 *anim_tutorial_cam;
12 static float slowmo_opacity = 0.0f;
13 static f64 volc_start_preview = 0.0;
14
15 void npc_load_model( struct npc *npc, const char *path )
16 {
17 vg_linear_clear( vg_mem.scratch );
18
19 mdl_context *meta = &npc->meta;
20 mdl_open( meta, path, vg_mem.rtmemory );
21 mdl_load_metadata_block( meta, vg_mem.rtmemory );
22 mdl_load_animation_block( meta, vg_mem.rtmemory );
23
24 struct skeleton *sk = &npc->skeleton;
25 skeleton_setup( sk, vg_mem.rtmemory, meta );
26
27 u32 mtx_size = sizeof(m4x3f)*sk->bone_count;
28 npc->final_mtx = vg_linear_alloc( vg_mem.rtmemory, mtx_size );
29
30 if( mdl_arrcount( &meta->textures ) )
31 {
32 mdl_texture *tex0 = mdl_arritm( &meta->textures, 0 );
33 void *data = vg_linear_alloc( vg_mem.scratch, tex0->file.pack_size );
34 mdl_fread_pack_file( meta, &tex0->file, data );
35
36 vg_tex2d_load_qoi_async( data, tex0->file.pack_size,
37 VG_TEX2D_NEAREST|VG_TEX2D_CLAMP,
38 &npc->texture );
39 }
40 else
41 {
42 npc->texture = vg.tex_missing;
43 }
44
45 mdl_async_load_glmesh( meta, &npc->mesh, NULL );
46 mdl_close( meta );
47 }
48
49 void npc_init(void)
50 {
51 npc_load_model( &npc_gumpa, "models/gumpa.mdl" );
52 gumpa_idle = skeleton_get_anim( &npc_gumpa.skeleton, "gumpa_idle" );
53
54 npc_load_model( &npc_slowmo, "models/slowmos.mdl" );
55 slowmo_momentum =
56 skeleton_get_anim( &npc_slowmo.skeleton, "slowmo_momentum" );
57 slowmo_slide = skeleton_get_anim( &npc_slowmo.skeleton, "slowmo_slide" );
58 slowmo_rewind = skeleton_get_anim( &npc_slowmo.skeleton, "slowmo_rewind" );
59
60 npc_load_model( &npc_volc_flight, "models/volc_flight.mdl" );
61 anim_tutorial_cam =
62 skeleton_get_anim( &npc_volc_flight.skeleton, "tutorial" );
63 }
64
65 static struct npc *npc_resolve( u32 id )
66 {
67 if( id == 1 ) return &npc_gumpa;
68 else if( id == 2 ) return &npc_slowmo;
69 else if( id == 3 ) return &npc_volc_flight;
70 else return NULL;
71 }
72
73 static entity_call_result npc_slowmo_call( ent_npc *npc, ent_call *call )
74 {
75 if( call->function == 0 )
76 {
77 gui_helper_clear();
78 vg_str text;
79
80 if( npc->context == 2 )
81 {
82 if( gui_new_helper( input_axis_list[k_sraxis_grab], &text ))
83 vg_strcat( &text, "Crouch (store energy)" );
84 if( gui_new_helper( input_joy_list[k_srjoystick_steer], &text ))
85 vg_strcat( &text, "Slide" );
86 }
87 else if( npc->context == 1 )
88 {
89 if( gui_new_helper( input_axis_list[k_sraxis_grab], &text ))
90 vg_strcat( &text, "Crouch (store energy)" );
91 }
92 else if( npc->context == 3 )
93 {
94 if( gui_new_helper( input_button_list[k_srbind_reset], &text ))
95 vg_strcat( &text, "Rewind time" );
96 if( gui_new_helper( input_button_list[k_srbind_replay_resume], &text ))
97 vg_strcat( &text, "Resume" );
98 }
99 return k_entity_call_result_OK;
100 }
101 else if( call->function == -1 )
102 {
103 world_entity_clear_focus();
104 gui_helper_clear();
105 return k_entity_call_result_OK;
106 }
107 else
108 return k_entity_call_result_unhandled;
109 }
110
111 entity_call_result ent_npc_call( world_instance *world, ent_call *call )
112 {
113 u32 index = mdl_entity_id_id( call->id );
114 ent_npc *npc = mdl_arritm( &world->ent_npc, index );
115
116 if( npc->id == 2 )
117 {
118 return npc_slowmo_call( npc, call );
119 }
120 else if( npc->id == 3 )
121 {
122 if( call->function == 0 )
123 {
124 world_entity_set_focus( call->id );
125 gui_helper_clear();
126 vg_str text;
127 if( gui_new_helper( input_button_list[k_srbind_maccept], &text ))
128 vg_strcat( &text, "Preview course" );
129 return k_entity_call_result_OK;
130 }
131 else if( call->function == -1 )
132 {
133 world_entity_clear_focus();
134 gui_helper_clear();
135 return k_entity_call_result_OK;
136 }
137 else
138 return k_entity_call_result_unhandled;
139 }
140 else if( npc->id == 4 )
141 {
142 if( call->function == 0 )
143 {
144 gui_helper_clear();
145 vg_str text;
146 if( gui_new_helper( input_button_list[k_srbind_camera], &text ))
147 vg_strcat( &text, "First/Thirdperson" );
148 return k_entity_call_result_OK;
149 }
150 else if( call->function == -1 )
151 {
152 gui_helper_clear();
153 return k_entity_call_result_OK;
154 }
155 else
156 return k_entity_call_result_unhandled;
157 }
158 else
159 {
160 if( call->function == 0 )
161 {
162 world_entity_set_focus( call->id );
163 gui_helper_clear();
164 vg_str text;
165 if( gui_new_helper( input_button_list[k_srbind_maccept], &text ))
166 vg_strcat( &text, "Talk to ???" );
167 return k_entity_call_result_OK;
168 }
169 else if( call->function == -1 )
170 {
171 world_entity_clear_focus();
172 gui_helper_clear();
173 return k_entity_call_result_OK;
174 }
175 else
176 return k_entity_call_result_unhandled;
177 }
178 }
179
180 void ent_npc_preupdate( ent_focus_context *ctx )
181 {
182 world_instance *world = ctx->world;
183 ent_npc *ent = mdl_arritm( &world->ent_npc, ctx->index );
184
185 if( !ctx->active )
186 {
187 if( button_down(k_srbind_maccept) )
188 {
189 world_entity_focus_modal();
190 gui_helper_clear();
191 vg_str text;
192 if( gui_new_helper( input_button_list[k_srbind_mback], &text ))
193 vg_strcat( &text, "leave" );
194
195 volc_start_preview = vg.time;
196 }
197
198 return;
199 }
200
201 if( ent->id == 3 )
202 {
203 player_pose pose;
204 struct skeleton *sk = &npc_volc_flight.skeleton;
205
206 f64 t = (vg.time - volc_start_preview) * 0.5;
207 skeleton_sample_anim_clamped( sk, anim_tutorial_cam, t, pose.keyframes );
208
209 ent_camera *cam = mdl_arritm( &world->ent_camera,
210 mdl_entity_id_id(ent->camera) );
211 v3_copy( pose.keyframes[0].co, cam->transform.co );
212
213 v4f qp;
214 q_axis_angle( qp, (v3f){1,0,0}, VG_TAUf*0.25f );
215 q_mul( pose.keyframes[0].q, qp, cam->transform.q );
216 q_normalize( cam->transform.q );
217
218 v3_add( ent->transform.co, cam->transform.co, cam->transform.co );
219 }
220
221 world_entity_focus_camera( world, ent->camera );
222
223 if( button_down( k_srbind_mback ) )
224 {
225 world_entity_exit_modal();
226 world_entity_clear_focus();
227 gui_helper_clear();
228 }
229 }
230
231 void npc_update( ent_npc *ent )
232 {
233 if( ent->id == 3 ) return;
234 if( ent->id == 4 ) return;
235
236 struct npc *npc_def = npc_resolve( ent->id );
237 VG_ASSERT( npc_def );
238
239 player_pose pose;
240 struct skeleton *sk = &npc_def->skeleton;
241 pose.type = k_player_pose_type_ik;
242 pose.board.lean = 0.0f;
243
244 if( ent->id == 1 )
245 {
246 skeleton_sample_anim( sk, gumpa_idle, vg.time, pose.keyframes );
247 }
248 else if( ent->id == 2 )
249 {
250 struct skeleton_anim *anim = NULL;
251 if( ent->context == 1 ) anim = slowmo_momentum;
252 else if( ent->context == 2 ) anim = slowmo_slide;
253 else if( ent->context == 3 ) anim = slowmo_rewind;
254
255 VG_ASSERT( anim );
256
257 f32 t = vg.time*0.5f,
258 animtime = fmodf( t*anim->rate, anim->length ),
259 lt = animtime / (f32)anim->length;
260 skeleton_sample_anim( sk, anim, t, pose.keyframes );
261 slowmo_opacity = vg_clampf(fabsf(lt-0.5f)*9.0f-3.0f,0,1);
262 }
263
264 v3_copy( ent->transform.co, pose.root_co );
265 v4_copy( ent->transform.q, pose.root_q );
266 apply_full_skeleton_pose( &npc_def->skeleton, &pose, npc_def->final_mtx );
267 }
268
269 void npc_render( ent_npc *ent, world_instance *world, vg_camera *cam )
270 {
271 if( ent->id == 3 ) return;
272 if( ent->id == 4 ) return;
273
274 struct npc *npc_def = npc_resolve( ent->id );
275 VG_ASSERT( npc_def );
276
277 shader_model_character_view_use();
278
279 glActiveTexture( GL_TEXTURE0 );
280 glBindTexture( GL_TEXTURE_2D, npc_def->texture );
281 shader_model_character_view_uTexMain( 0 );
282 shader_model_character_view_uCamera( cam->transform[3] );
283 shader_model_character_view_uPv( cam->mtx.pv );
284
285 if( ent->id == 2 )
286 {
287 shader_model_character_view_uDepthMode( 2 );
288 shader_model_character_view_uDitherCutoff( slowmo_opacity );
289 }
290 else
291 {
292 shader_model_character_view_uDepthMode( 0 );
293 }
294
295 WORLD_BIND_LIGHT_BUFFERS_UB0_TEX234( world, model_character_view );
296
297 glUniformMatrix4x3fv( _uniform_model_character_view_uTransforms,
298 npc_def->skeleton.bone_count,
299 0,
300 (const GLfloat *)npc_def->final_mtx );
301
302 mesh_bind( &npc_def->mesh );
303 mesh_draw( &npc_def->mesh );
304 }