/* * Tcl callback to allow reading of game configuration variables from Tcl. */ static int get_param_cb ( ClientData cd, Tcl_Interp *ip, int argc, const char *argv[]) { int i; int num_params; struct param *parm; if ( argc != 2 ) { Tcl_AppendResult(ip, argv[0], ": invalid number of arguments\n", "Usage: ", argv[0], " <parameter name>", (char *)0 ); return TCL_ERROR; } /* Search for parameter */ parm = NULL; num_params = sizeof(Params)/sizeof(struct param); for (i=0; i<num_params; i++) { parm = (struct param*)&Params + i; if ( strcmp( parm->name, argv[1] ) == 0 ) { break; } } /* If can't find parameter, report error */ if ( parm == NULL || i == num_params ) { Tcl_AppendResult(ip, argv[0], ": invalid parameter `", argv[1], "'", (char *)0 ); return TCL_ERROR; } /* Get value of parameter */ switch ( parm->type ) { case PARAM_STRING: fetch_param_string( parm ); Tcl_SetObjResult( ip, Tcl_NewStringObj( parm->val.string_val, -1 ) ); break; case PARAM_CHAR: fetch_param_char( parm ); Tcl_SetObjResult( ip, Tcl_NewStringObj( &parm->val.char_val, 1 ) ); break; case PARAM_INT: fetch_param_int( parm ); Tcl_SetObjResult( ip, Tcl_NewIntObj( parm->val.int_val ) ); break; case PARAM_BOOL: fetch_param_bool( parm ); Tcl_SetObjResult( ip, Tcl_NewBooleanObj( parm->val.bool_val ) ); break; default: code_not_reached(); } return TCL_OK; }
/*! Compares the positions of two races in a cup \return pos(race2)-pos(race1) \author jfpatry \date Created: 2000-09-24 \date Modified: 2000-09-24 */ int compare_race_positions( cup_data_t *cup_data, list_elem_t race1, list_elem_t race2 ) { int incr = 1; list_elem_t cur_elem = NULL; bool_t found1 = False; bool_t found2 = False; int diff; check_assertion( race1 != NULL, "race is null" ); check_assertion( race2 != NULL, "race is null" ); check_assertion( cup_data != NULL, "null data" ); check_assertion( cup_data->race_list != NULL, "null list" ); diff = 0; cur_elem = get_list_head( cup_data->race_list ); while( 1 ) { if ( cur_elem == NULL ) { check_assertion( 0, "race1 or race2 aren't races in the cup" ); } if ( cur_elem == race1 ) { if ( found2 ) { return diff; } found1 = True; incr = 1; } if ( cur_elem == race2 ) { if ( found1 ) { return diff; } found2 = True; incr = -1; } cur_elem = get_next_list_elem( cup_data->race_list, cur_elem ); if ( found1 || found2 ) { diff += incr; } } code_not_reached(); }
void print_gl_info() { char *extensions; char *p, *oldp; int i; GLint int_val; GLfloat float_val; GLboolean boolean_val; fprintf( stderr, " vendor: %s\n", glGetString( GL_VENDOR ) ); fprintf( stderr, " renderer: %s\n", glGetString( GL_RENDERER ) ); fprintf( stderr, " version: %s\n", glGetString( GL_VERSION ) ); extensions = string_copy( (char*) glGetString( GL_EXTENSIONS ) ); fprintf( stderr, " extensions:\n" ); oldp = extensions; while ( (p=strchr(oldp,' ')) ) { *p='\0'; fprintf( stderr, " %s\n", oldp ); oldp = p+1; } if ( *oldp ) { fprintf( stderr, " %s\n", oldp ); } free( extensions ); for ( i=0; i<sizeof(gl_values)/sizeof(gl_values[0]); i++) { fprintf( stderr, " %s: ", gl_values[i].name ); switch( gl_values[i].type ) { #ifndef __APPLE__ case GL_INT: glGetIntegerv( gl_values[i].value, &int_val ); fprintf( stderr, "%d", int_val ); break; #else case GL_FIXED: glGetIntegerv( gl_values[i].value, &int_val ); fprintf( stderr, "%d", int_val ); break; #endif case GL_FLOAT: glGetFloatv( gl_values[i].value, &float_val ); fprintf( stderr, "%f", float_val ); break; case GL_UNSIGNED_BYTE: glGetBooleanv( gl_values[i].value, &boolean_val ); fprintf( stderr, "%d", boolean_val ); break; default: code_not_reached(); } fprintf( stderr, "\n" ); } fprintf( stderr, "\n" ); }
void set_gl_options( RenderMode mode ) { /* Must set the following options: Enable/Disable: GL_TEXTURE_2D GL_DEPTH_TEST GL_CULL_FACE GL_LIGHTING GL_NORMALIZE GL_ALPHA_TEST GL_BLEND GL_STENCIL_TEST GL_TEXTURE_GEN_S GL_TEXTURE_GEN_T GL_COLOR_MATERIAL Other Functions: glDepthMask glShadeModel glDepthFunc */ /* * Modify defaults based on rendering mode * * This could could be improved if it stored state and avoided * redundant state changes, which are costly (or so I've heard)... */ switch( mode ) { case GUI: glEnable( GL_TEXTURE_2D ); glDisable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glDisable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); glDisable( GL_FOG ); break; case GAUGE_BARS: glEnable( GL_TEXTURE_2D ); glDisable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glDisable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glEnable( GL_TEXTURE_GEN_S ); glEnable( GL_TEXTURE_GEN_T ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); break; case TEXFONT: glEnable( GL_TEXTURE_2D ); glDisable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glDisable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); break; case TEXT: glDisable( GL_TEXTURE_2D ); glDisable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glDisable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); break; case SPLASH_SCREEN: glDisable( GL_TEXTURE_2D ); glDisable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glDisable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); break; case COURSE: glEnable( GL_TEXTURE_2D ); glEnable( GL_DEPTH_TEST ); glEnable( GL_CULL_FACE ); glEnable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glEnable( GL_TEXTURE_GEN_S ); glEnable( GL_TEXTURE_GEN_T ); glEnable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LEQUAL ); glTexGeni( GL_S, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); glTexGeni( GL_T, GL_TEXTURE_GEN_MODE, GL_OBJECT_LINEAR ); break; case TREES: glEnable( GL_TEXTURE_2D ); glEnable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glEnable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glEnable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); glAlphaFunc( GL_GEQUAL, 0.5 ); break; case PARTICLES: glEnable( GL_TEXTURE_2D ); glEnable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glDisable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glEnable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); glAlphaFunc( GL_GEQUAL, 0.5 ); break; case PARTICLE_SHADOWS: glDisable( GL_TEXTURE_2D ); glEnable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glDisable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); break; case SKY: glEnable( GL_TEXTURE_2D ); glDisable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glDisable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_FALSE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); break; case FOG_PLANE: glDisable( GL_TEXTURE_2D ); glEnable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glDisable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); break; case TUX: glDisable( GL_TEXTURE_2D ); glEnable( GL_DEPTH_TEST ); glEnable( GL_CULL_FACE ); glEnable( GL_LIGHTING ); glEnable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); break; case TUX_SHADOW: #ifdef USE_STENCIL_BUFFER glDisable( GL_TEXTURE_2D ); glEnable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glDisable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glEnable( GL_STENCIL_TEST ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_FALSE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); glStencilFunc( GL_EQUAL, 0, ~0 ); glStencilOp( GL_KEEP, GL_KEEP, GL_INCR ); #else glDisable( GL_TEXTURE_2D ); glEnable( GL_DEPTH_TEST ); glEnable( GL_CULL_FACE ); glDisable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); #endif break; case TRACK_MARKS: glEnable( GL_TEXTURE_2D ); glEnable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glEnable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glDisable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_COLOR_MATERIAL ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDepthMask( GL_FALSE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LEQUAL ); break; case OVERLAYS: glEnable( GL_TEXTURE_2D ); glDisable( GL_DEPTH_TEST ); glDisable( GL_CULL_FACE ); glDisable( GL_LIGHTING ); glDisable( GL_NORMALIZE ); glEnable( GL_ALPHA_TEST ); glEnable( GL_BLEND ); glDisable( GL_STENCIL_TEST ); glDisable( GL_TEXTURE_GEN_S ); glDisable( GL_TEXTURE_GEN_T ); glDisable( GL_COLOR_MATERIAL ); glDepthMask( GL_TRUE ); glShadeModel( GL_SMOOTH ); glDepthFunc( GL_LESS ); glAlphaFunc( GL_GEQUAL, 0.5 ); break; default: code_not_reached(); } }
void write_config_file() { FILE *config_stream; char config_file[BUFF_LEN]; char config_dir[BUFF_LEN]; struct param *parm; int i; #ifdef __APPLE__ // Don't save the config file on iphone, no use for it. return; #endif if ( get_config_file_name( config_file, sizeof( config_file ) ) != 0 ) { return; } if ( get_config_dir_name( config_dir, sizeof( config_dir ) ) != 0 ) { return; } if ( !dir_exists( config_dir ) ) { #if defined(WIN32) && !defined(__CYGWIN__) if (mkdir( config_dir ) != 0) { return; } #else if (mkdir( config_dir, 0775) != 0) { return; } #endif } config_stream = fopen( config_file, "w" ); if ( config_stream == NULL ) { print_warning( CRITICAL_WARNING, "couldn't open %s for writing: %s", config_file, strerror(errno) ); return; } fprintf( config_stream, "# Tux Racer " VERSION " configuration file\n" "#\n" ); for (i=0; i<sizeof(Params)/sizeof(struct param); i++) { parm = (struct param*)&Params + i; //FIXME : dans la version simulateur, on ne veut as qu'il enregistre le data_dir car il change à chaque fois et sinon c'est la merde if (!strcmp(parm->name,"data_dir")) continue; // Don't save the resolution if (!strcmp(parm->name,"x_resolution")) continue; if (!strcmp(parm->name,"y_resolution")) continue; if ( parm->comment != NULL ) { fprintf( config_stream, "\n# %s\n#\n%s\n#\n", parm->name, parm->comment ); } switch ( parm->type ) { case PARAM_STRING: fetch_param_string( parm ); fprintf( config_stream, "set %s \"%s\"\n", parm->name, parm->val.string_val ); break; case PARAM_CHAR: fetch_param_char( parm ); fprintf( config_stream, "set %s %c\n", parm->name, parm->val.char_val ); break; case PARAM_INT: fetch_param_int( parm ); fprintf( config_stream, "set %s %d\n", parm->name, parm->val.int_val ); break; case PARAM_BOOL: fetch_param_bool( parm ); fprintf( config_stream, "set %s %s\n", parm->name, parm->val.bool_val ? "true" : "false" ); break; default: code_not_reached(); } } if ( fclose( config_stream ) != 0 ) { perror( "fclose" ); } }
/* * Tcl callback to allow setting of game configuration variables from Tcl. */ static int set_param_cb ( ClientData cd, Tcl_Interp *ip, int argc, const char *argv[]) { int i; int tmp_int; int num_params; struct param *parm; if ( argc != 3 ) { Tcl_AppendResult(ip, argv[0], ": invalid number of arguments\n", "Usage: ", argv[0], " <parameter name> <value>", (char *)0 ); return TCL_ERROR; } /* Search for parameter */ parm = NULL; num_params = sizeof(Params)/sizeof(struct param); for (i=0; i<num_params; i++) { parm = (struct param*)&Params + i; if ( strcmp( parm->name, argv[1] ) == 0 ) { break; } } /* If can't find parameter, report error */ if ( parm == NULL || i == num_params ) { Tcl_AppendResult(ip, argv[0], ": invalid parameter `", argv[1], "'", (char *)0 ); return TCL_ERROR; } /* Set value of parameter */ switch ( parm->type ) { case PARAM_STRING: set_param_string( parm, argv[2] ); break; case PARAM_CHAR: if ( strlen( argv[2] ) > 1 ) { Tcl_AppendResult(ip, "\n", argv[0], ": value for `", argv[1], "' must be a single character", (char *)0 ); return TCL_ERROR; } set_param_char( parm, argv[2][0] ); break; case PARAM_INT: if ( Tcl_GetInt( ip, argv[2], &tmp_int ) != TCL_OK ) { Tcl_AppendResult(ip, "\n", argv[0], ": value for `", argv[1], "' must be an integer", (char *)0 ); return TCL_ERROR; } set_param_int( parm, tmp_int ); break; case PARAM_BOOL: if ( Tcl_GetBoolean( ip, argv[2], &tmp_int ) != TCL_OK ) { Tcl_AppendResult(ip, "\n", argv[0], ": value for `", argv[1], "' must be a boolean", (char *)0 ); return TCL_ERROR; } check_assertion( tmp_int == 0 || tmp_int == 1, "invalid boolean value" ); set_param_bool( parm, (bool_t) tmp_int ); break; default: code_not_reached(); } return TCL_OK; }
void update_view( player_data_t *plyr, scalar_t dt ) { point_t view_pt; vector_t view_dir, up_dir, vel_dir, view_vec; scalar_t ycoord; scalar_t course_angle; vector_t axis; matrixgl_t rot_mat; vector_t y_vec; vector_t mz_vec; vector_t vel_proj; quaternion_t rot_quat; scalar_t speed; vector_t vel_cpy; scalar_t time_constant_mult; vel_cpy = plyr->vel; speed = normalize_vector( &vel_cpy ); time_constant_mult = 1.0 / min( 1.0, max( 0.0, ( speed - NO_INTERPOLATION_SPEED ) / ( BASELINE_INTERPOLATION_SPEED - NO_INTERPOLATION_SPEED ))); up_dir = make_vector( 0, 1, 0 ); vel_dir = plyr->vel; normalize_vector( &vel_dir ); course_angle = get_course_angle(); switch( plyr->view.mode ) { case TUXEYE: { scalar_t f = 2; vector_t v = plyr->plane_nml; scalar_t n = 1.; view_pt = plyr->pos; view_pt.x += v.x / n * 0.3; view_pt.y += v.y / n * 0.3; view_pt.y += 0.1; view_pt.z += v.z / n * 0.3; if(plyr->control.flip_factor || plyr->control.barrel_roll_factor) { matrixgl_t mat1, mat; vector_t right; scalar_t n = sqrt(plyr->viewdir_for_tuxeye.x * plyr->viewdir_for_tuxeye.x + plyr->viewdir_for_tuxeye.y * plyr->viewdir_for_tuxeye.y + plyr->viewdir_for_tuxeye.z * plyr->viewdir_for_tuxeye.z); plyr->viewdir_for_tuxeye.x /= n; plyr->viewdir_for_tuxeye.y /= n; plyr->viewdir_for_tuxeye.z /= n; n = sqrt(plyr->updir_for_tuxeye.x * plyr->updir_for_tuxeye.x + plyr->updir_for_tuxeye.y * plyr->updir_for_tuxeye.y + plyr->updir_for_tuxeye.z * plyr->updir_for_tuxeye.z); plyr->updir_for_tuxeye.x /= n; plyr->updir_for_tuxeye.y /= n; plyr->updir_for_tuxeye.z /= n; right = cross_product(plyr->updir_for_tuxeye, plyr->viewdir_for_tuxeye); make_rotation_about_vector_matrix( mat1, right, jump_from_time(plyr->control.flip_factor) * 360 ); make_rotation_about_vector_matrix( mat, plyr->viewdir_for_tuxeye, jump_from_time(plyr->control.barrel_roll_factor) * 360 ); multiply_matrices(mat, mat1, mat); view_dir = transform_vector(mat, plyr->viewdir_for_tuxeye); up_dir = transform_vector(mat, plyr->updir_for_tuxeye); } else { view_dir = plyr->direction; view_dir.y += 0.1; view_dir.x = (plyr->view.dir.x * f + view_dir.x) / (f + 1); view_dir.y = (plyr->view.dir.y * f + view_dir.y) / (f + 1); view_dir.z = (plyr->view.dir.z * f + view_dir.z) / (f + 1); plyr->viewdir_for_tuxeye = view_dir; up_dir = plyr->plane_nml; up_dir.x = (plyr->view.up.x * f + up_dir.x) / (f + 1); up_dir.y = (plyr->view.up.y * f + up_dir.y) / (f + 1); up_dir.z = (plyr->view.up.z * f + up_dir.z) / (f + 1); plyr->updir_for_tuxeye = up_dir; } break; } case BEHIND: { /* Camera-on-a-string mode */ /* Construct vector from player to camera */ view_vec = make_vector( 0, sin( ANGLES_TO_RADIANS( course_angle - CAMERA_ANGLE_ABOVE_SLOPE + PLAYER_ANGLE_IN_CAMERA ) ), cos( ANGLES_TO_RADIANS( course_angle - CAMERA_ANGLE_ABOVE_SLOPE + PLAYER_ANGLE_IN_CAMERA ) ) ); view_vec = scale_vector( CAMERA_DISTANCE, view_vec ); y_vec = make_vector( 0.0, 1.0, 0.0 ); mz_vec = make_vector( 0.0, 0.0, -1.0 ); vel_proj = project_into_plane( y_vec, vel_dir ); normalize_vector( &vel_proj ); /* Rotate view_vec so that it places the camera behind player */ rot_quat = make_rotation_quaternion( mz_vec, vel_proj ); view_vec = rotate_vector( rot_quat, view_vec ); /* Construct view point */ view_pt = move_point( plyr->pos, view_vec ); /* Make sure view point is above terrain */ ycoord = find_y_coord( view_pt.x, view_pt.z ); if ( view_pt.y < ycoord + MIN_CAMERA_HEIGHT ) { view_pt.y = ycoord + MIN_CAMERA_HEIGHT; } /* Interpolate view point */ if ( plyr->view.initialized ) { /* Interpolate twice to get a second-order filter */ int i; for (i=0; i<2; i++) { view_pt = interpolate_view_pos( plyr->pos, plyr->pos, MAX_CAMERA_PITCH, plyr->view.pos, view_pt, CAMERA_DISTANCE, dt, BEHIND_ORBIT_TIME_CONSTANT * time_constant_mult ); } } /* Make sure interpolated view point is above terrain */ ycoord = find_y_coord( view_pt.x, view_pt.z ); if ( view_pt.y < ycoord + ABSOLUTE_MIN_CAMERA_HEIGHT ) { view_pt.y = ycoord + ABSOLUTE_MIN_CAMERA_HEIGHT; } /* Construct view direction */ view_vec = subtract_points( view_pt, plyr->pos ); axis = cross_product( y_vec, view_vec ); normalize_vector( &axis ); make_rotation_about_vector_matrix( rot_mat, axis, PLAYER_ANGLE_IN_CAMERA ); view_dir = scale_vector( -1.0, transform_vector( rot_mat, view_vec ) ); /* Interpolate orientation of camera */ if ( plyr->view.initialized ) { /* Interpolate twice to get a second-order filter */ int i; for (i=0; i<2; i++) { interpolate_view_frame( plyr->view.up, plyr->view.dir, &up_dir, &view_dir, dt, BEHIND_ORIENT_TIME_CONSTANT ); up_dir = make_vector( 0.0, 1.0, 0.0 ); } } break; } case FOLLOW: { /* Camera follows player (above and behind) */ up_dir = make_vector( 0, 1, 0 ); /* Construct vector from player to camera */ view_vec = make_vector( 0, sin( ANGLES_TO_RADIANS( course_angle - CAMERA_ANGLE_ABOVE_SLOPE + PLAYER_ANGLE_IN_CAMERA ) ), cos( ANGLES_TO_RADIANS( course_angle - CAMERA_ANGLE_ABOVE_SLOPE + PLAYER_ANGLE_IN_CAMERA ) ) ); view_vec = scale_vector( CAMERA_DISTANCE, view_vec ); y_vec = make_vector( 0.0, 1.0, 0.0 ); mz_vec = make_vector( 0.0, 0.0, -1.0 ); vel_proj = project_into_plane( y_vec, vel_dir ); normalize_vector( &vel_proj ); /* Rotate view_vec so that it places the camera behind player */ rot_quat = make_rotation_quaternion( mz_vec, vel_proj ); view_vec = rotate_vector( rot_quat, view_vec ); /* Construct view point */ view_pt = move_point( plyr->pos, view_vec ); /* Make sure view point is above terrain */ ycoord = find_y_coord( view_pt.x, view_pt.z ); if ( view_pt.y < ycoord + MIN_CAMERA_HEIGHT ) { view_pt.y = ycoord + MIN_CAMERA_HEIGHT; } /* Interpolate view point */ if ( plyr->view.initialized ) { /* Interpolate twice to get a second-order filter */ int i; for ( i=0; i<2; i++ ) { view_pt = interpolate_view_pos( plyr->view.plyr_pos, plyr->pos, MAX_CAMERA_PITCH, plyr->view.pos, view_pt, CAMERA_DISTANCE, dt, FOLLOW_ORBIT_TIME_CONSTANT * time_constant_mult ); } } /* Make sure interpolate view point is above terrain */ ycoord = find_y_coord( view_pt.x, view_pt.z ); if ( view_pt.y < ycoord + ABSOLUTE_MIN_CAMERA_HEIGHT ) { view_pt.y = ycoord + ABSOLUTE_MIN_CAMERA_HEIGHT; } /* Construct view direction */ view_vec = subtract_points( view_pt, plyr->pos ); axis = cross_product( y_vec, view_vec ); normalize_vector( &axis ); make_rotation_about_vector_matrix( rot_mat, axis, PLAYER_ANGLE_IN_CAMERA ); view_dir = scale_vector( -1.0, transform_vector( rot_mat, view_vec ) ); /* Interpolate orientation of camera */ if ( plyr->view.initialized ) { /* Interpolate twice to get a second-order filter */ int i; for ( i=0; i<2; i++ ) { interpolate_view_frame( plyr->view.up, plyr->view.dir, &up_dir, &view_dir, dt, FOLLOW_ORIENT_TIME_CONSTANT ); up_dir = make_vector( 0.0, 1.0, 0.0 ); } } break; } case ABOVE: { /* Camera always uphill of player */ up_dir = make_vector( 0, 1, 0 ); /* Construct vector from player to camera */ view_vec = make_vector( 0, sin( ANGLES_TO_RADIANS( course_angle - CAMERA_ANGLE_ABOVE_SLOPE+ PLAYER_ANGLE_IN_CAMERA ) ), cos( ANGLES_TO_RADIANS( course_angle - CAMERA_ANGLE_ABOVE_SLOPE+ PLAYER_ANGLE_IN_CAMERA ) ) ); view_vec = scale_vector( CAMERA_DISTANCE, view_vec ); /* Construct view point */ view_pt = move_point( plyr->pos, view_vec ); /* Make sure view point is above terrain */ ycoord = find_y_coord( view_pt.x, view_pt.z ); if ( view_pt.y < ycoord + MIN_CAMERA_HEIGHT ) { view_pt.y = ycoord + MIN_CAMERA_HEIGHT; } /* Construct view direction */ view_vec = subtract_points( view_pt, plyr->pos ); make_rotation_matrix( rot_mat, PLAYER_ANGLE_IN_CAMERA, 'x' ); view_dir = scale_vector( -1.0, transform_vector( rot_mat, view_vec ) ); break; } default: code_not_reached(); } /* Create view matrix */ plyr->view.pos = view_pt; plyr->view.dir = view_dir; plyr->view.up = up_dir; plyr->view.plyr_pos = plyr->pos; plyr->view.initialized = True; setup_view_matrix( plyr ); }