X-Git-Url: https://harrygodden.com/git/?a=blobdiff_plain;f=player.h;h=8a0b17d28552f3992c99874bd746d4987f59da95;hb=0a33f65eecb5e75cddaefa08d3a5eb1a301d0479;hp=1edbc6ba08981fce86b63c8904294429ac6e95e8;hpb=a1741ec4aed057cbafff2d6bc9e5cf8a15ae322b;p=carveJwlIkooP6JGAAIwe30JlM.git diff --git a/player.h b/player.h index 1edbc6b..8a0b17d 100644 --- a/player.h +++ b/player.h @@ -1,47 +1,208 @@ +#ifndef PLAYER_H +#define PLAYER_H + +#include "player_api.h" + +#include "player_common.h" +#include "player_walk.h" +#include "player_skate.h" +#include "player_dead.h" + +struct player_instance +{ + /* transform definition */ + rigidbody rb; + v3f angles; + + v4f qbasis; + m3x3f basis, invbasis, basis_gate; + world_instance *viewable_world; + + /* + * Camera management + * --------------------------- + */ + camera cam; /* output final camera */ + + enum camera_mode + { + k_cam_firstperson = 0, + k_cam_thirdperson = 1 + } + camera_mode; + float camera_type_blend; + + + v3f fpv_offset, /* expressed relative to rigidbody */ + tpv_offset, + fpv_viewpoint, /* expressed relative to neck bone inverse final */ + fpv_offset_smooth, + fpv_viewpoint_smooth, + tpv_offset_smooth, + tpv_lpf, + cam_velocity_smooth; + + float cam_velocity_influence, + cam_velocity_coefficient, + cam_velocity_constant, + cam_velocity_coefficient_smooth, + cam_velocity_constant_smooth, + cam_velocity_influence_smooth, + cam_land_punch, + cam_land_punch_v; + + ent_gate *gate_waiting; + + /* + * Input + * -------------------------------- + */ + struct input_binding *input_js1h, + *input_js1v, + *input_js2h, + *input_js2v, + *input_jump, + *input_push, + *input_trick0, + *input_trick1, + *input_trick2, + *input_walk, + *input_walkh, + *input_walkv, + *input_use, + *input_reset, + *input_grab, + *input_camera; + + /* + * Animation + * -------------------------------------------------- + */ + + struct player_avatar *playeravatar; + glmesh *playermesh; + struct player_ragdoll ragdoll; + vg_tex2d *playertex; + + player_pose holdout_pose; + float holdout_time; + + /* + * Subsystems + * ------------------------------------------------- + */ + + enum player_subsystem + { + k_player_subsystem_walk = 0, + k_player_subsystem_skate = 1, + k_player_subsystem_dead = 2 + } + subsystem; + + struct player_skate _skate; + struct player_walk _walk; + struct player_dead _dead; +}; + +/* + * Gameloop tables + * --------------------------------------------------------- + */ + +VG_STATIC +void (*_player_bind[])( player_instance *player ) = +{ + player__walk_bind, + player__skate_bind, + NULL +}; + +VG_STATIC +void (*_player_reset[])( player_instance *player, ent_spawn *rp ) = +{ + player__walk_reset, + player__skate_reset, + NULL +}; + +VG_STATIC +void (*_player_pre_update[])( player_instance *player ) = +{ + player__walk_pre_update, + player__skate_pre_update, + NULL +}; + +VG_STATIC +void( *_player_update[])( player_instance *player ) = +{ + player__walk_update, + player__skate_update, + player__dead_update, +}; + +VG_STATIC +void( *_player_post_update[])( player_instance *player ) = +{ + player__walk_post_update, + player__skate_post_update, + NULL +}; + +VG_STATIC +void( *_player_im_gui[])( player_instance *player ) = +{ + player__walk_im_gui, + player__skate_im_gui, + NULL +}; + +VG_STATIC +void( *_player_animate[])( player_instance *player, player_animation *dest ) = +{ + player__walk_animate, + player__skate_animate, + player__dead_animate +}; + +VG_STATIC +void( *_player_post_animate[])( player_instance *player ) = +{ + player__walk_post_animate, + player__skate_post_animate, + player__dead_post_animate +}; + +/* implementation */ + +#include "player.c" +#include "player_common.c" +#include "player_walk.c" +#include "player_skate.c" +#include "player_dead.c" + +#endif /* PLAYER_H */ + + +#if 0 /* - * Copyright (C) 2021-2022 Mt.ZERO Software, Harry Godden - All Rights Reserved + * Copyright (C) 2021-2023 Mt.ZERO Software, Harry Godden - All Rights Reserved */ +#define PLAYER_H #ifndef PLAYER_H #define PLAYER_H #define PLAYER_REWIND_FRAMES 60*4 +#include "conf.h" #include "audio.h" #include "common.h" #include "world.h" #include "skeleton.h" #include "bvh.h" -VG_STATIC float - k_walkspeed = 12.0f, /* no longer used */ - k_runspeed = 20.0f, - k_board_radius = 0.3f, - k_board_length = 0.45f, - k_board_allowance = 0.04f, - //k_friction_lat = 8.8f, - k_friction_lat = 12.0f, - k_friction_resistance = 0.01f, - k_max_push_speed = 16.0f, - k_push_accel = 10.0f, - k_push_cycle_rate = 8.0f, - k_steer_ground = 2.5f, - k_steer_air = 3.6f, - k_steer_air_lerp = 0.3f, - k_pump_force = 0.0f, - k_downforce = 5.0f, - k_walk_downforce = 8.0f, - k_jump_charge_speed = (1.0f/1.0f), - k_jump_force = 5.0f, - k_pitch_limit = 1.5f, - k_look_speed = 2.0f, - k_walk_accel = 150.0f, - k_walk_friction = 8.0f; - -VG_STATIC int cl_playermdl_id = 0; -VG_STATIC int freecam = 0; -VG_STATIC int walk_grid_iterations = 1; -VG_STATIC float fc_speed = 10.0f; /* * ----------------------------------------------------------------------------- @@ -51,30 +212,20 @@ VG_STATIC float fc_speed = 10.0f; VG_STATIC struct gplayer { - /* Physics */ - rigidbody collide_front, collide_back; + rigidbody rb, rb_frame; + v3f co, angles; /* used as transfer between controllers */ - struct player_phys + enum player_controller { - rigidbody rb, rb_gate_frame; - float iY, siY; /* Yaw inertia */ - - v3f a, v_last, m, bob, vl; - - /* Utility */ - float vswitch, slip, slip_last, - reverse; - - float grab, jump, pushing, push_time; - v2f grab_mouse_delta; - - double start_push; - int in_air, on_board, jump_charge, jump_dir; - - m3x3f vr,vr_pstep; + k_player_controller_walk, + k_player_controller_skate, + k_player_controller_ragdoll, + k_player_controller_mountain_skate, + k_player_controller_snowboard, + k_player_controller_drive } - phys, - phys_gate_frame; + controller, + controller_frame; m4x3f visual_transform, inv_visual_transform; @@ -82,10 +233,6 @@ VG_STATIC struct gplayer int is_dead, death_tick_allowance, rewinding; int rewind_sound_wait; - v3f land_target; - v3f land_target_log[22]; - u32 land_target_colours[22]; - int land_log_count; v3f handl_target, handr_target, handl, handr; @@ -105,16 +252,13 @@ VG_STATIC struct gplayer *input_grab; /* Camera */ - float air_blend; float air_time; - v3f camera_pos, smooth_localcam; - v2f angles; struct rewind_frame { v3f pos; - v2f ang; + v3f ang; } *rewind_buffer; u32 rewind_incrementer, @@ -136,7 +280,11 @@ VG_STATIC struct gplayer walk_timer, fjump, fonboard, - frun; + frun, + fgrind; + + v3f board_offset; + v4f board_rotation; float walk; int step_phase; @@ -164,33 +312,53 @@ VG_STATIC struct gplayer id_ik_hand_r, id_ik_elbow_l, id_ik_elbow_r, - id_head; + id_head, + id_ik_foot_l, + id_ik_foot_r, + id_board; v3f cam_pos; struct ragdoll_part { u32 bone_id; - v3f offset; + //v3f offset; + + /* Collider transform relative to bone */ + m4x3f collider_mtx, + inv_collider_mtx; u32 use_limits; v3f limits[2]; rigidbody rb; u32 parent; + u32 colour; } ragdoll[32]; u32 ragdoll_count; + rb_constr_pos position_constraints[32]; + u32 position_constraints_count; + + rb_constr_swingtwist cone_constraints[32]; + u32 cone_constraints_count; + int shoes[2]; } mdl; } -player = +player__OLD + +#if 0 += { .collide_front = { .type = k_rb_shape_sphere, .inf.sphere.radius = 0.3f }, .collide_back = { .type = k_rb_shape_sphere, .inf.sphere.radius = 0.3f } -}; +} +#endif + +; /* * API @@ -208,145 +376,86 @@ VG_STATIC void player_save_rewind_frame(void); VG_STATIC void player_mouseview(void); #include "player_physics.h" +#include "player_physics_skate.h" +#include "player_physics_walk.h" #include "player_ragdoll.h" #include "player_model.h" #include "player_animation.h" #include "player_audio.h" +/* + * player_physics__ + * + * + * + */ + /* * ----------------------------------------------------------------------------- * Events * ----------------------------------------------------------------------------- */ +VG_STATIC int kill_player( int argc, char const *argv[] ); +VG_STATIC int reset_player( int argc, char const *argv[] ); +VG_STATIC void reset_player_poll( int argc, char const *argv[] ); -VG_STATIC void player_init(void) /* 1 */ +VG_STATIC void player_init(void) /* 1 */ { - player.input_js1h = vg_create_named_input( "steer-h", k_input_type_axis ); - player.input_js1v = vg_create_named_input( "steer-v", k_input_type_axis ); - player.input_grab = vg_create_named_input( "grab", k_input_type_axis_norm ); - player.input_js2h = vg_create_named_input( "grab-h", k_input_type_axis ); - player.input_js2v = vg_create_named_input( "grab-v", k_input_type_axis ); - player.input_jump = vg_create_named_input( "jump", k_input_type_button ); - player.input_push = vg_create_named_input( "push", k_input_type_button ); - player.input_walk = vg_create_named_input( "walk", k_input_type_button ); - - player.input_walkh = vg_create_named_input( "walk-h", - k_input_type_axis ); - player.input_walkv = vg_create_named_input( "walk-v", - k_input_type_axis ); - - - player.input_switch_mode = vg_create_named_input( "switch-mode", - k_input_type_button ); - player.input_reset = vg_create_named_input( "reset", k_input_type_button ); - - const char *default_cfg[] = - { - "bind steer-h gp-ls-h", - "bind -steer-h a", - "bind +steer-h d", + rb_init( &player.rb ); - "bind steer-v gp-ls-v", - "bind -steer-v w", - "bind +steer-v s", + VG_VAR_F32( k_walkspeed ); + VG_VAR_F32( k_stopspeed ); + VG_VAR_F32( k_airspeed ); + VG_VAR_F32( k_walk_friction ); + VG_VAR_F32( k_walk_air_accel ); + VG_VAR_F32( k_walk_accel ); - "bind grab gp-rt", - "bind +grab shift", - "bind grab-h gp-rs-h", - "bind grab-v gp-rs-v", + VG_VAR_I32( freecam ); + VG_VAR_I32( cl_thirdperson ); + VG_VAR_F32_PERSISTENT( fc_speed ); - "bind jump space", - "bind jump gp-a", + VG_VAR_F32( k_ragdoll_limit_scale ); + VG_VAR_I32( k_ragdoll_div ); + VG_VAR_I32( k_ragdoll_debug_collider ); + VG_VAR_I32( k_ragdoll_debug_constraints ); - "bind push gp-b", - "bind push w", + VG_VAR_F32( k_friction_lat ); - "bind walk shift", - "bind walk gp-ls", - - "bind walk-h gp-ls-h", - "bind walk-v -gp-ls-v", - "bind +walk-h d", - "bind -walk-h a", - "bind +walk-v w", - "bind -walk-v s", - - "bind reset gp-lb", - "bind reset r", - - "bind switch-mode gp-y", - "bind switch-mode e", - }; - - for( int i=0; icog, 0.10f, 0xffffffff ); + vg_line_pt3( phys->cog, 0.09f, 0xffffffff ); + vg_line_pt3( phys->cog, 0.08f, 0xffffffff ); + vg_line( phys->cog, phys->rb.co, 0xff000000 ); + + v3f spring_end; + v3f throw_end, p0, p1; + v3_muladds( phys->rb.co, phys->rb.up, 1.0f, spring_end ); + v3_muladds( spring_end, phys->throw_v, 1.0f, throw_end ); + v3_muladds( spring_end, player.debug_mmcollect_lat, 1.0f, p0 ); + v3_muladds( spring_end, player.debug_mmcollect_vert, 1.0f, p1 ); + vg_line( spring_end, throw_end, VG__RED ); + vg_line( spring_end, p0, VG__GREEN ); + vg_line( spring_end, p1, VG__BLUE ); +#endif + + if( player.rewinding ) + return; + + if( vg_input_button_down( player.input_reset ) && !menu_enabled() ) { - if( player.is_dead ) + double delta = world.time - world.last_use; + + if( (delta <= RESET_MAX_TIME) && (world.last_use != 0.0) ) { - reset_player( 0, NULL ); + player.rewinding = 1; + player.rewind_sound_wait = 1; + player.rewind_time = (float)player.rewind_length - 0.0001f; + player_save_rewind_frame(); audio_lock(); - audio_play_oneshot( &audio_ui[0], 1.0f ); + audio_play_oneshot( &audio_rewind[0], 1.0f ); audio_unlock(); - } - else - { - double delta = world.time - world.last_use; - - if( (delta <= RESET_MAX_TIME) && (world.last_use != 0.0) ) - { - player.rewinding = 1; - player.rewind_sound_wait = 1; - player.rewind_time = (float)player.rewind_length - 0.0001f; - player_save_rewind_frame(); - audio_lock(); - audio_play_oneshot( &audio_rewind[0], 1.0f ); - audio_unlock(); - /* based on analytical testing. DONT CHANGE! - * - * time taken: y = (x^(4/5)) * 74.5 - * inverse : x = (2/149)^(4/5) * y^(4/5) - */ + /* based on analytical testing. DONT CHANGE! + * + * time taken: y = (x^(4/5)) * 74.5 + * inverse : x = (2/149)^(4/5) * y^(4/5) + */ - float constant = powf( 2.0f/149.0f, 4.0f/5.0f ), - curve = powf( player.rewind_total_length, 4.0f/5.0f ); - - player.rewind_predicted_time = constant * curve; - player.diag_rewind_start = vg.time; - player.diag_rewind_time = player.rewind_time; + float constant = powf( 2.0f/149.0f, 4.0f/5.0f ), + curve = powf( player.rewind_total_length, 4.0f/5.0f ); + + player.rewind_predicted_time = constant * curve; + player.diag_rewind_start = vg.time; + player.diag_rewind_time = player.rewind_time; - player.is_dead = 0; - player.death_tick_allowance = 30; - player_restore_frame(); + player.is_dead = 0; + player.death_tick_allowance = 30; + player_restore_frame(); - if( !phys->on_board ) - { - player.angles[0] = atan2f( -phys->rb.forward[2], - -phys->rb.forward[0] ); - } + if( player.controller == k_player_controller_walk ) + { + player.angles[0] = atan2f( -player.rb.forward[2], + -player.rb.forward[0] ); + } - player.mdl.shoes[0] = 1; - player.mdl.shoes[1] = 1; + player.mdl.shoes[0] = 1; + player.mdl.shoes[1] = 1; - world_routes_notify_reset(); + world_routes_notify_reset(); - /* apply 1 frame of movement */ - player_do_motion(); + /* apply 1 frame of movement */ + player_do_motion(); + } + else + { + if( player.is_dead ) + { + reset_player( 0, NULL ); } else { @@ -487,29 +634,34 @@ VG_STATIC void player_update_pre(void) } } - if( vg_input_button_down( player.input_switch_mode ) ) + if( vg_input_button_down( player.input_switch_mode ) && !menu_enabled() ) { - phys->on_board ^= 0x1; - audio_lock(); - if( phys->on_board ) + +#if 0 + if( phys->controller == k_player_controller_walk ) { + phys->controller = k_player_controller_skate; + v3_muladds( phys->rb.v, phys->rb.forward, 0.2f, phys->rb.v ); audio_play_oneshot( &audio_lands[6], 1.0f ); } - else + else if( phys->controller == k_player_controller_skate ) { + phys->controller = k_player_controller_walk; + audio_play_oneshot( &audio_lands[5], 1.0f ); } +#endif audio_unlock(); } - if( !phys->on_board ) + if( player.controller == k_player_controller_walk ) player_mouseview(); } -VG_STATIC void player_update_fixed(void) /* 2 */ +VG_STATIC void player_update_fixed(void) /* 2 */ { if( player.rewinding ) return; @@ -517,8 +669,6 @@ VG_STATIC void player_update_fixed(void) /* 2 if( player.death_tick_allowance ) player.death_tick_allowance --; - struct player_phys *phys = &player.phys; - if( player.is_dead ) { player_ragdoll_iter(); @@ -538,10 +688,23 @@ VG_STATIC void player_update_fixed(void) /* 2 VG_STATIC void player_update_post(void) { - for( int i=0; ilog_length - 1; j ++ ) + vg_line( p->log[j], p->log[j+1], p->colour ); + + vg_line_cross( p->log[p->log_length-1], p->colour, 0.25f ); + v3f p1; + v3_add( p->log[p->log_length-1], p->n, p1 ); + vg_line( p->log[p->log_length-1], p1, 0xffffffff ); + } +#endif + +#if 0 if( player.is_dead ) { player_debug_ragdoll(); @@ -554,17 +717,23 @@ VG_STATIC void player_update_post(void) player_animate(); if( !freecam ) - player_animate_camera(); + { + if( cl_thirdperson ) + player_animate_camera_thirdperson(); + else + player_animate_camera(); + } } if( freecam ) +#endif player_freecam(); - /* CAMERA POSITIONING: LAYER 0 */ - v2_copy( player.angles, camera_angles ); - v3_copy( player.camera_pos, camera_pos ); + v2_copy( player.angles, main_camera.angles ); + v3_copy( player.camera_pos, main_camera.pos ); +#if 0 if( player.rewinding ) { if( player.rewind_time <= 0.0f ) @@ -654,8 +823,6 @@ VG_STATIC void player_update_post(void) player.rewind_sound_wait = 0; } } - - } int i0 = floorf( player.rewind_time ), @@ -674,17 +841,20 @@ VG_STATIC void player_update_post(void) float blend = (4.0f-player.rewind_time) * 0.25f, c = vg_clampf( blend, 0.0f, 1.0f ); - camera_angles[0] = vg_alerpf(override_angles[0], player.angles[0], c); - camera_angles[1] = vg_lerpf (override_angles[1], player.angles[1], c); - v3_lerp( override_pos, player.camera_pos, c, camera_pos ); + main_camera.angles[0] = + vg_alerpf(override_angles[0], player.angles[0], c); + main_camera.angles[1] = + vg_lerpf (override_angles[1], player.angles[1], c); + v3_lerp( override_pos, player.camera_pos, c, main_camera.pos ); } } +#endif - camera_update(); + camera_update_transform( &main_camera ); player_audio(); } -VG_STATIC void draw_player( m4x3f cam ) +VG_STATIC void draw_player( camera *cam ) { if( player.is_dead ) player_model_copy_ragdoll(); @@ -692,8 +862,8 @@ VG_STATIC void draw_player( m4x3f cam ) shader_viewchar_use(); vg_tex2d_bind( &tex_characters, 0 ); shader_viewchar_uTexMain( 0 ); - shader_viewchar_uCamera( cam[3] ); - shader_viewchar_uPv( vg.pv ); + 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.mdl.sk.bone_count, @@ -704,6 +874,123 @@ VG_STATIC void draw_player( m4x3f cam ) mesh_draw( &player.mdl.player_meshes[cl_playermdl_id] ); } +VG_STATIC void player_do_motion(void) +{ + if( world.water.enabled ) + { + if( (player.rb.co[1] < 0.0f) && !player.is_dead ) + { + audio_lock(); + audio_player_set_flags( &audio_player_extra, AUDIO_FLAG_SPACIAL_3D ); + audio_player_set_position( &audio_player_extra, player.rb.co ); + audio_player_set_vol( &audio_player_extra, 20.0f ); + audio_player_playclip( &audio_player_extra, &audio_splash ); + audio_unlock(); + + player_kill(); + } + } + + v3f prevco; + v3_copy( player.rb.co, prevco ); + + if( player.controller == k_player_controller_skate ) + { +#if 0 + player_skate_update(); +#endif + } + else + player_walk_physics( &player_walky ); + + + /* Real angular velocity integration */ +#if 0 + v3_lerp( phys->rb.w, (v3f){0.0f,0.0f,0.0f}, 0.125f*0.5f, phys->rb.w ); + if( v3_length2( phys->rb.w ) > 0.0f ) + { + v4f rotation; + v3f axis; + v3_copy( phys->rb.w, axis ); + + float mag = v3_length( axis ); + v3_divs( axis, mag, axis ); + q_axis_angle( rotation, axis, mag*k_rb_delta ); + q_mul( rotation, phys->rb.q, phys->rb.q ); + } + + /* Faux angular velocity */ + v4f rotate; + + float lerpq = (player_skate.activity == k_skate_activity_air)? 0.04f: 0.3f; + phys->siY = vg_lerpf( phys->siY, phys->iY, lerpq ); + + q_axis_angle( rotate, phys->rb.up, phys->siY ); + q_mul( rotate, phys->rb.q, phys->rb.q ); + phys->iY = 0.0f; +#endif + + /* + * Gate intersection, by tracing a line over the gate planes + */ +#if 0 + for( int i=0; igate; + + if( gate_intersect( gate, phys->rb.co, prevco ) ) + { + m4x3_mulv( gate->transport, phys->rb.co, phys->rb.co ); + m4x3_mulv( gate->transport, phys->cog, phys->cog ); + m3x3_mulv( gate->transport, phys->cog_v, phys->cog_v ); + m3x3_mulv( gate->transport, phys->rb.v, phys->rb.v ); + m3x3_mulv( gate->transport, phys->vl, phys->vl ); + m3x3_mulv( gate->transport, phys->v_last, phys->v_last ); + m3x3_mulv( gate->transport, phys->m, phys->m ); + m3x3_mulv( gate->transport, phys->bob, phys->bob ); + + /* Pre-emptively edit the camera matrices so that the motion vectors + * are correct */ + m4x3f transport_i; + m4x4f transport_4; + m4x3_invert_affine( gate->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 ); + + v4f transport_rotation; + m3x3_q( gate->transport, transport_rotation ); + q_mul( transport_rotation, phys->rb.q, phys->rb.q ); + + world_routes_activate_gate( i ); + + if( phys->controller == k_player_controller_walk ) + { + v3f fwd_dir = {cosf(player.angles[0]), + 0.0f, + sinf(player.angles[0])}; + m3x3_mulv( gate->transport, fwd_dir, fwd_dir ); + + player.angles[0] = atan2f( fwd_dir[2], fwd_dir[0] ); + } + + player.rewind_length = 0; + player.rewind_total_length = 0.0f; + player.rewind_incrementer = 10000; + player_save_frame(); + + audio_lock(); + audio_play_oneshot( &audio_gate_pass, 1.0f ); + audio_unlock(); + break; + } + } +#endif + + rb_update_transform( &player.rb ); +} + /* * ----------------------------------------------------------------------------- * API implementation @@ -712,7 +999,7 @@ VG_STATIC void draw_player( m4x3f cam ) VG_STATIC float *player_get_pos(void) { - return player.phys.rb.co; + return player.rb.co; } VG_STATIC void player_kill(void) @@ -720,8 +1007,7 @@ VG_STATIC void player_kill(void) if( player.death_tick_allowance == 0 ) { player.is_dead = 1; - player_ragdoll_copy_model( player.phys.rb.v ); - world_routes_clear(); + player_ragdoll_copy_model( player.rb.v ); } } @@ -731,4 +1017,19 @@ VG_STATIC float *player_cam_pos(void) } +VG_STATIC void player_save_frame(void) +{ + player.controller_frame = player.controller; + + /* TODO ->save() */ +} + +VG_STATIC void player_restore_frame(void) +{ + player.controller = player.controller_frame; + + /* TODO ->load() */ +} + #endif /* PLAYER_H */ +#endif