#include "model.h"
#include "camera.h"
#include "rigidbody.h"
+#include "player_ragdoll.h"
+#include "player_model.h"
#include "world.h"
typedef struct player_device player_device;
typedef struct player_attachment player_attachment;
typedef mdl_keyframe player_pose[32];
+#define PLAYER_DEVICE_API VG_STATIC
+
struct player_interface
{
rigidbody rb;
{
player_device *device;
void *storage;
+
+ /* animation driven */
+ player_pose pose;
+ v3f pose_root_co;
+ v4f pose_root_q;
+ camera cam_1st, cam_3rd;
}
- dev;
+ dev,
+ dev_previous;
+
+ enum camera_mode
+ {
+ k_camera_mode_firstperson,
+ k_camera_mode_thirdperson
+ }
+ camera_mode;
+
+ float camera_type_blend;
+
+ /* TODO: have an automated system for crossing the thirdperson camera
+ * across portal boundaries. if it fails the check with the gate plane, then
+ * transform root_co and root_q, as well as final camera, BACK across the
+ * division, using the inverse of the transport matrix
+ */
+
+ int device_blend;
+ float device_blend_time;
struct input_binding *input_js1h,
*input_js1v,
*input_walkv,
*input_use,
*input_reset,
- *input_grab;
+ *input_grab,
+ *input_camera;
+
+#if 0
+ v3f prev_position;
+#endif
+
+ struct player_avatar *playeravatar;
+ glmesh *playermesh;
+ struct player_ragdoll ragdoll;
+
+
+ /* FIXME: eventually store animation state here when we have more than 1
+ * player. since currently its written into the avatar
+ *
+ * struct avatar_anim_state anim_state;
+ */
};
+/* FIXME: yo */
+vg_tex2d tex_characters = { .path = "textures/ch_gradient.qoi" };
+
struct player_device
{
+ void (* bind ) ( player_interface *player, player_attachment *at );
+
+ /*
+ * Regular updates
+ */
void (* pre_update) ( player_interface *player, player_attachment *at );
void (* update) ( player_interface *player, player_attachment *at );
void (* post_update)( player_interface *player, player_attachment *at );
- void (* pose) ( player_interface *player, player_attachment *at,
- player_pose pose );
- void (* get_camera) ( player_interface *player, player_attachment *at,
- camera *cam );
-
- void (* attatch ) ( player_interface *player, player_attachment *at,
- void *storage );
+#if 0
+ /*
+ * Get current pose, and root transform
+ */
+ void (* pose) ( player_interface *player, player_attachment *at,
+ player_pose pose, v3f root_co, v4f root_q );
+#endif
+ /*
+ * Use this to fill out animation state
+ */
+ void (* animate) ( player_interface *player, player_attachment *at );
+
+ /* Get current camera, required fields to be filled are:
+ * fov
+ * pos
+ * angles
+ *
+ * They may be blended with other systems
+ */
+ void (* post_animate) ( player_interface *player, player_attachment *at );
+
+ /*
+ This is called when a player is forced back to a spawnpoint.
+ */
void (* reset ) ( player_interface *player, player_attachment *at,
struct respawn_point *spawn );
- void (* store_state)( player_interface *player, player_attachment *at );
- void (* load_state) ( player_interface *player, player_attachment *at );
+ /*
+ * make calls into player_debugtext( .. ) in this function
+ */
void (* debug_ui) ( player_interface *player, player_attachment *at );
+
+#if 0
+ /*
+ * Called when going through a gate, it should modify any direction and
+ * position sensitive things, as well as store context here. it may be
+ * restored later.
+ */
+ void (* gate_transport)( player_interface *player, player_attachment *at,
+ teleport_gate *gate );
+#endif
+
+ /*
+ * Load the state previously saved when gate_transport was called
+ */
+ void (* load_state) ( player_interface *player, player_attachment *at );
+
+
+
+
+#if 0
+ void (* store_state)( player_interface *player, player_attachment *at );
+ void (* attatch ) ( player_interface *player, player_attachment *at,
+ void *storage );
+#endif
+
};
VG_STATIC void player_interface_create_player( player_interface *inst )
inst->input_walkv= vg_create_named_input( "walk-v", k_input_type_axis );
inst->input_use = vg_create_named_input( "use", k_input_type_button );
inst->input_reset= vg_create_named_input( "reset", k_input_type_button );
+ inst->input_camera=vg_create_named_input( "camera", k_input_type_button );
const char *default_cfg[] =
{
"bind use gp-y",
"bind use e",
+ "bind camera c"
};
for( int i=0; i<vg_list_size(default_cfg); i++ )
m4x3_identity( inst->rb.to_local );
}
+VG_STATIC void player_use_avatar( player_interface *player,
+ struct player_avatar *av )
+{
+ player->playeravatar = av;
+ player_setup_ragdoll_from_avatar( &player->ragdoll, av );
+}
+
+VG_STATIC void player_use_mesh( player_interface *player, glmesh *mesh )
+{
+ player->playermesh = mesh;
+}
+
+/* FIXME: Seperate concepts for binding and equip.
+ */
VG_STATIC void player_use_device( player_interface *player, player_device *dev,
void *storage )
{
player->dev.device = dev;
player->dev.storage = storage;
+
+ player->dev.device->bind( player, &player->dev );
}
VG_STATIC void player_pre_update( player_interface *player )
{
assert( player->dev.device );
+ if( vg_input_button_down( player->input_camera ) )
+ {
+ if( player->camera_mode == k_camera_mode_firstperson )
+ player->camera_mode = k_camera_mode_thirdperson;
+ else
+ player->camera_mode = k_camera_mode_firstperson;
+ }
+
+#if 0
+ v3_copy( player->rb.co, player->prev_position );
+#endif
+
if( player->dev.device->pre_update )
player->dev.device->pre_update( player, &player->dev );
}
player->dev.device->update( player, &player->dev );
}
+VG_STATIC void player_apply_transport_to_cam( m4x3f transport )
+{
+ /* FIXME: Applies to main_camera directly! */
+
+ /* Pre-emptively edit the camera matrices so that the motion vectors
+ * are correct */
+ m4x3f transport_i;
+ m4x4f transport_4;
+ m4x3_invert_affine( transport, transport_i );
+ m4x3_expand( transport_i, transport_4 );
+ m4x4_mul( main_camera.mtx.pv, transport_4, main_camera.mtx.pv );
+ m4x4_mul( main_camera.mtx.v, transport_4, main_camera.mtx.v );
+}
+
+/*
+ * Applies gate transport to a player_interface
+ */
+PLAYER_DEVICE_API
+void player_pass_gate( player_interface *player, teleport_gate *gate )
+{
+
+}
+
VG_STATIC void player_post_update( player_interface *player )
{
assert( player->dev.device );
if( player->dev.device->post_update )
player->dev.device->post_update( player, &player->dev );
-
- if( player->dev.device->get_camera )
- player->dev.device->get_camera( player, &player->dev, &player->cam );
-#if 0
- camera_update_transform( &player->cam );
- camera_update_view( &player->cam );
- camera_update_projection( &player->cam );
- camera_finalize( &player->cam );
-#endif
}
-#if 0
VG_STATIC void player_pre_render( player_interface *player )
{
- assert( player->dev.device );
+ player->dev.device->animate( player, &player->dev );
- if( player->dev.device->pre_render )
- player->dev.device->pre_render( player );
-}
+ /* TODO: eventually, blending code goes here */
+
+ m4x3f transform;
+ q_m3x3( player->dev.pose_root_q, transform );
+ v3_copy( player->dev.pose_root_co, transform[3] );
+
+ struct skeleton *sk = &player->playeravatar->sk;
+
+ skeleton_apply_pose( sk, player->dev.pose, k_anim_apply_defer_ik );
+ skeleton_apply_ik_pass( sk );
+ skeleton_apply_pose( sk, player->dev.pose, k_anim_apply_deffered_only );
+ skeleton_apply_inverses( sk );
+ skeleton_apply_transform( sk, transform );
+ skeleton_debug( sk );
+
+#if 0
+ if( player->dev.device->pose )
+ {
+ player->dev.device->pose( player, &player->dev, pose, transform );
+
+ struct skeleton *sk = &player->playeravatar->sk;
+
+ skeleton_apply_pose( sk, pose, k_anim_apply_defer_ik );
+ skeleton_apply_ik_pass( sk );
+ skeleton_apply_pose( sk, pose, k_anim_apply_deffered_only );
+ skeleton_apply_inverses( sk );
+ skeleton_apply_transform( sk, transform );
+ skeleton_debug( sk );
+ }
#endif
+ player->dev.device->post_animate( player, &player->dev );
+
+ /* TODO: eventually, blending code goes here */
+
+ float camera_blend_target = 1.0f;
+ if( player->camera_mode == k_camera_mode_firstperson )
+ camera_blend_target = 0.0f;
+
+ player->camera_type_blend = vg_lerpf( player->camera_type_blend,
+ camera_blend_target,
+ 5.0f * vg.frame_delta );
+
+ float t = player->camera_type_blend;
+ camera_lerp( &player->dev.cam_1st, &player->dev.cam_3rd, t, &player->cam );
+
+
+#if 0
+ v3_copy( player->dev.cam_1st.pos, player->cam.pos );
+ v3_copy( player->dev.cam_1st.angles, player->cam.angles );
+ player->cam.fov = player->dev.cam_1st.fov;
+#endif
+}
+
+VG_STATIC void player_render( camera *cam, player_interface *player )
+{
+ shader_viewchar_use();
+ vg_tex2d_bind( &tex_characters, 0 );
+ shader_viewchar_uTexMain( 0 );
+ shader_viewchar_uCamera( cam->transform[3] );
+ shader_viewchar_uPv( cam->mtx.pv );
+ shader_link_standard_ub( _shader_viewchar.id, 2 );
+ glUniformMatrix4x3fv( _uniform_viewchar_uTransforms,
+ player->playeravatar->sk.bone_count,
+ 0,
+ (float *)player->playeravatar->sk.final_mtx );
+
+ mesh_bind( player->playermesh );
+ mesh_draw( player->playermesh );
+}
+
VG_STATIC void player_debugtext( int size, const char *fmt, ... )
{
char buffer[ 1024 ];
{
vg_uictx.cursor[0] = vg.window_x - 200;
vg_uictx.cursor[1] = 0;
- vg_uictx.cursor[2] = 0;
+ vg_uictx.cursor[2] = 200;
vg_uictx.cursor[3] = 200;
struct ui_vert *b = ui_fill_rect( vg_uictx.cursor, 0x70000000 );
+ vg_uictx.cursor[0] = vg.window_x;
player->dev.device->debug_ui( player, &player->dev );
b[2].co[1] = vg_uictx.cursor[1];
struct respawn_point *rp )
{
v3_copy( rp->co, player->rb.co );
+#if 0
+ v3_copy( rp->co, player->prev_position );
+#endif
v3_zero( player->rb.v );
v3_zero( player->rb.w );
q_identity( player->rb.q );
+ rb_update_transform( &player->rb );
+
+ if( player->dev.device->reset )
+ player->dev.device->reset( player, &player->dev, rp );
+}
+
+
+VG_STATIC void player_kill( player_interface *player )
+{
+
}
/*
* Apply per render-frame mouse look from player to angles
*/
-VG_STATIC void player_look( player_interface *player, v3f angles )
+PLAYER_DEVICE_API
+void player_look( player_interface *player, v3f angles )
{
angles[2] = 0.0f;
v2_muladds( angles, vg.mouse_delta, 0.0025f, angles );