1 #ifndef PLAYER_INTERFACE_H
2 #define PLAYER_INTERFACE_H
7 #include "player_ragdoll.h"
8 #include "player_model.h"
11 typedef struct player_device player_device
;
12 typedef struct player_interface player_interface
;
13 typedef struct player_attachment player_attachment
;
14 typedef mdl_keyframe player_pose
[32];
16 #define PLAYER_DEVICE_API VG_STATIC
18 struct player_interface
23 struct player_attachment
25 player_device
*device
;
28 /* animation driven */
32 camera cam_1st
, cam_3rd
;
39 k_camera_mode_firstperson
,
40 k_camera_mode_thirdperson
43 float camera_type_blend
;
45 teleport_gate
*gate_waiting
;
48 float device_blend_time
;
50 struct input_binding
*input_js1h
,
68 struct player_avatar
*playeravatar
;
70 struct player_ragdoll ragdoll
;
73 /* FIXME: eventually store animation state here when we have more than 1
74 * player. since currently its written into the avatar
76 * struct avatar_anim_state anim_state;
81 vg_tex2d tex_characters
= { .path
= "textures/ch_gradient.qoi" };
85 void (* bind
) ( player_interface
*player
, player_attachment
*at
);
90 void (* pre_update
) ( player_interface
*player
, player_attachment
*at
);
91 void (* update
) ( player_interface
*player
, player_attachment
*at
);
92 void (* post_update
)( player_interface
*player
, player_attachment
*at
);
96 * Get current pose, and root transform
98 void (* pose
) ( player_interface
*player
, player_attachment
*at
,
99 player_pose pose
, v3f root_co
, v4f root_q
);
103 * Use this to fill out animation state
105 void (* animate
) ( player_interface
*player
, player_attachment
*at
);
107 /* Get current camera, required fields to be filled are:
112 * They may be blended with other systems
114 void (* post_animate
) ( player_interface
*player
, player_attachment
*at
);
117 This is called when a player is forced back to a spawnpoint.
119 void (* reset
) ( player_interface
*player
, player_attachment
*at
,
120 struct respawn_point
*spawn
);
123 * make calls into player_debugtext( .. ) in this function
125 void (* debug_ui
) ( player_interface
*player
, player_attachment
*at
);
129 * Called when going through a gate, it should modify any direction and
130 * position sensitive things, as well as store context here. it may be
133 void (* gate_transport
)( player_interface
*player
, player_attachment
*at
,
134 teleport_gate
*gate
);
138 * Load the state previously saved when gate_transport was called
140 void (* load_state
) ( player_interface
*player
, player_attachment
*at
);
146 void (* store_state
)( player_interface
*player
, player_attachment
*at
);
147 void (* attatch
) ( player_interface
*player
, player_attachment
*at
,
153 VG_STATIC
void player_interface_create_player( player_interface
*inst
)
155 static int only_once
= 0;
156 assert( only_once
== 0 );
159 inst
->input_js1h
= vg_create_named_input( "steer-h", k_input_type_axis
);
160 inst
->input_js1v
= vg_create_named_input( "steer-v", k_input_type_axis
);
161 inst
->input_grab
= vg_create_named_input( "grab", k_input_type_axis_norm
);
162 inst
->input_js2h
= vg_create_named_input( "grab-h", k_input_type_axis
);
163 inst
->input_js2v
= vg_create_named_input( "grab-v", k_input_type_axis
);
164 inst
->input_jump
= vg_create_named_input( "jump", k_input_type_button
);
165 inst
->input_push
= vg_create_named_input( "push", k_input_type_button
);
166 inst
->input_walk
= vg_create_named_input( "walk", k_input_type_button
);
167 inst
->input_walkh
= vg_create_named_input( "walk-h", k_input_type_axis
);
168 inst
->input_walkv
= vg_create_named_input( "walk-v", k_input_type_axis
);
169 inst
->input_use
= vg_create_named_input( "use", k_input_type_button
);
170 inst
->input_reset
= vg_create_named_input( "reset", k_input_type_button
);
171 inst
->input_camera
=vg_create_named_input( "camera", k_input_type_button
);
173 const char *default_cfg
[] =
175 "bind steer-h gp-ls-h",
179 "bind steer-v gp-ls-v",
185 "bind grab-h gp-rs-h",
186 "bind grab-v gp-rs-v",
197 "bind walk-h gp-ls-h",
198 "bind walk-v -gp-ls-v",
212 for( int i
=0; i
<vg_list_size(default_cfg
); i
++ )
213 vg_execute_console_input(default_cfg
[i
]);
215 v3_zero( inst
->rb
.co
);
216 v3_zero( inst
->rb
.w
);
217 v3_zero( inst
->rb
.v
);
218 q_identity( inst
->rb
.q
);
219 m4x3_identity( inst
->rb
.to_world
);
220 m4x3_identity( inst
->rb
.to_local
);
223 VG_STATIC
void player_use_avatar( player_interface
*player
,
224 struct player_avatar
*av
)
226 player
->playeravatar
= av
;
227 player_setup_ragdoll_from_avatar( &player
->ragdoll
, av
);
230 VG_STATIC
void player_use_mesh( player_interface
*player
, glmesh
*mesh
)
232 player
->playermesh
= mesh
;
235 /* FIXME: Seperate concepts for binding and equip.
237 VG_STATIC
void player_use_device( player_interface
*player
, player_device
*dev
,
240 player
->dev
.device
= dev
;
241 player
->dev
.storage
= storage
;
243 player
->dev
.device
->bind( player
, &player
->dev
);
246 VG_STATIC
void player_pre_update( player_interface
*player
)
248 assert( player
->dev
.device
);
250 if( vg_input_button_down( player
->input_camera
) )
252 if( player
->camera_mode
== k_camera_mode_firstperson
)
253 player
->camera_mode
= k_camera_mode_thirdperson
;
255 player
->camera_mode
= k_camera_mode_firstperson
;
259 v3_copy( player
->rb
.co
, player
->prev_position
);
262 if( player
->dev
.device
->pre_update
)
263 player
->dev
.device
->pre_update( player
, &player
->dev
);
266 VG_STATIC
void player_update( player_interface
*player
)
268 assert( player
->dev
.device
);
270 if( player
->dev
.device
->update
)
271 player
->dev
.device
->update( player
, &player
->dev
);
274 VG_STATIC
void player_apply_transport_to_cam( m4x3f transport
)
276 /* FIXME: Applies to main_camera directly! */
278 /* Pre-emptively edit the camera matrices so that the motion vectors
282 m4x3_invert_affine( transport
, transport_i
);
283 m4x3_expand( transport_i
, transport_4
);
284 m4x4_mul( main_camera
.mtx
.pv
, transport_4
, main_camera
.mtx
.pv
);
285 m4x4_mul( main_camera
.mtx
.v
, transport_4
, main_camera
.mtx
.v
);
289 * Applies gate transport to a player_interface
292 void player_pass_gate( player_interface
*player
, teleport_gate
*gate
)
294 player
->gate_waiting
= gate
;
297 VG_STATIC
void player_post_update( player_interface
*player
)
299 assert( player
->dev
.device
);
301 if( player
->dev
.device
->post_update
)
302 player
->dev
.device
->post_update( player
, &player
->dev
);
305 VG_STATIC
void player_pre_render( player_interface
*player
)
307 player
->dev
.device
->animate( player
, &player
->dev
);
309 /* TODO: eventually, blending code goes here */
312 q_m3x3( player
->dev
.pose_root_q
, transform
);
313 v3_copy( player
->dev
.pose_root_co
, transform
[3] );
315 struct skeleton
*sk
= &player
->playeravatar
->sk
;
317 skeleton_apply_pose( sk
, player
->dev
.pose
, k_anim_apply_defer_ik
);
318 skeleton_apply_ik_pass( sk
);
319 skeleton_apply_pose( sk
, player
->dev
.pose
, k_anim_apply_deffered_only
);
320 skeleton_apply_inverses( sk
);
321 skeleton_apply_transform( sk
, transform
);
322 skeleton_debug( sk
);
325 if( player
->dev
.device
->pose
)
327 player
->dev
.device
->pose( player
, &player
->dev
, pose
, transform
);
329 struct skeleton
*sk
= &player
->playeravatar
->sk
;
331 skeleton_apply_pose( sk
, pose
, k_anim_apply_defer_ik
);
332 skeleton_apply_ik_pass( sk
);
333 skeleton_apply_pose( sk
, pose
, k_anim_apply_deffered_only
);
334 skeleton_apply_inverses( sk
);
335 skeleton_apply_transform( sk
, transform
);
336 skeleton_debug( sk
);
340 player
->dev
.device
->post_animate( player
, &player
->dev
);
342 /* TODO: eventually, blending code goes here */
344 float camera_blend_target
= 1.0f
;
345 if( player
->camera_mode
== k_camera_mode_firstperson
)
346 camera_blend_target
= 0.0f
;
348 player
->camera_type_blend
= vg_lerpf( player
->camera_type_blend
,
350 5.0f
* vg
.frame_delta
);
352 float t
= player
->camera_type_blend
;
353 camera_lerp( &player
->dev
.cam_1st
, &player
->dev
.cam_3rd
, t
, &player
->cam
);
355 if( player
->gate_waiting
)
357 /* construct plane equation for reciever gate */
359 v3_copy( player
->gate_waiting
->recv_to_world
[2], plane
);
360 plane
[3] = v3_dot( plane
, player
->gate_waiting
->recv_to_world
[3] );
362 /* check camera polarity */
363 if( v3_dot( player
->cam
.pos
, plane
) < plane
[3] )
365 vg_success( "Plane cleared\n" );
366 player_apply_transport_to_cam( player
->gate_waiting
->transport
);
367 player
->gate_waiting
= NULL
;
371 /* de-transform camera and player back */
373 m4x3_invert_affine( player
->gate_waiting
->transport
, inverse
);
374 m4x3_mulv( inverse
, player
->cam
.pos
, player
->cam
.pos
);
376 /* TODO: Find robust method for this */
377 v3f fwd_dir
= { cosf(player
->cam
.angles
[0]),
379 sinf(player
->cam
.angles
[0])};
380 m3x3_mulv( inverse
, fwd_dir
, fwd_dir
);
381 player
->cam
.angles
[0] = atan2f( fwd_dir
[2], fwd_dir
[0] );
383 skeleton_apply_transform( sk
, inverse
);
388 v3_copy( player
->dev
.cam_1st
.pos
, player
->cam
.pos
);
389 v3_copy( player
->dev
.cam_1st
.angles
, player
->cam
.angles
);
390 player
->cam
.fov
= player
->dev
.cam_1st
.fov
;
394 VG_STATIC
void player_render( camera
*cam
, player_interface
*player
)
396 shader_viewchar_use();
397 vg_tex2d_bind( &tex_characters
, 0 );
398 shader_viewchar_uTexMain( 0 );
399 shader_viewchar_uCamera( cam
->transform
[3] );
400 shader_viewchar_uPv( cam
->mtx
.pv
);
401 shader_link_standard_ub( _shader_viewchar
.id
, 2 );
402 glUniformMatrix4x3fv( _uniform_viewchar_uTransforms
,
403 player
->playeravatar
->sk
.bone_count
,
405 (float *)player
->playeravatar
->sk
.final_mtx
);
407 mesh_bind( player
->playermesh
);
408 mesh_draw( player
->playermesh
);
411 VG_STATIC
void player_debugtext( int size
, const char *fmt
, ... )
416 va_start( args
, fmt
);
417 vsnprintf( buffer
, 1024, fmt
, args
);
420 ui_text( vg_uictx
.cursor
, buffer
, size
, k_text_align_right
);
421 vg_uictx
.cursor
[1] += 14*size
;
424 VG_STATIC
void player_ui( player_interface
*player
)
426 /* TODO: if debugger enabled */
428 if( player
->dev
.device
->debug_ui
)
430 vg_uictx
.cursor
[0] = vg
.window_x
- 200;
431 vg_uictx
.cursor
[1] = 0;
432 vg_uictx
.cursor
[2] = 200;
433 vg_uictx
.cursor
[3] = 200;
435 struct ui_vert
*b
= ui_fill_rect( vg_uictx
.cursor
, 0x70000000 );
437 vg_uictx
.cursor
[0] = vg
.window_x
;
438 player
->dev
.device
->debug_ui( player
, &player
->dev
);
440 b
[2].co
[1] = vg_uictx
.cursor
[1];
441 b
[3].co
[1] = vg_uictx
.cursor
[1];
445 VG_STATIC
void player_spawn( player_interface
*player
,
446 struct respawn_point
*rp
)
448 v3_copy( rp
->co
, player
->rb
.co
);
450 v3_copy( rp
->co
, player
->prev_position
);
452 v3_zero( player
->rb
.v
);
453 v3_zero( player
->rb
.w
);
454 q_identity( player
->rb
.q
);
455 rb_update_transform( &player
->rb
);
457 if( player
->dev
.device
->reset
)
458 player
->dev
.device
->reset( player
, &player
->dev
, rp
);
462 VG_STATIC
void player_kill( player_interface
*player
)
468 * Apply per render-frame mouse look from player to angles
471 void player_look( player_interface
*player
, v3f angles
)
474 v2_muladds( angles
, vg
.mouse_delta
, 0.0025f
, angles
);
476 if( vg_input
.controller_should_use_trackpad_look
)
478 static v2f last_input
;
480 static v2f vel_smooth
;
482 v2f input
= { player
->input_js2h
->axis
.value
,
483 player
->input_js2v
->axis
.value
};
485 if( (v2_length2(last_input
) > 0.001f
) && (v2_length2(input
) > 0.001f
) )
487 v2_sub( input
, last_input
, vel
);
488 v2_muls( vel
, 1.0f
/vg
.time_delta
, vel
);
495 v2_lerp( vel_smooth
, vel
, vg
.time_delta
*8.0f
, vel_smooth
);
497 v2_muladds( angles
, vel_smooth
, vg
.time_delta
, angles
);
498 v2_copy( input
, last_input
);
502 angles
[0] += player
->input_js2h
->axis
.value
* vg
.time_delta
* 4.0f
;
503 angles
[1] += player
->input_js2v
->axis
.value
* vg
.time_delta
* 4.0f
;
506 angles
[1] = vg_clampf( angles
[1], -VG_PIf
*0.5f
, VG_PIf
*0.5f
);
509 #endif /* PLAYER_INTERFACE_H */