/*! Interpolates between camera orientations \pre p_up2, p_dir2 != NULL; *p_up2 is the target up vector; *p_dir2 is the target view direction \arg \c up1 original up vector \arg \c dir1 original view direction \arg \c p_up2 pointer to target up vector; is overwritten with interpolated up vector \arg \c p_dir2 pointer to target view direction; is overwritten with interpolated view direction \arg \c dt time step \arg \c time_constant interpolation time constant \return none \author jfpatry \date Created: 2000-08-26 \date Modified: 2000-08-26 */ void interpolate_view_frame( vector_t up1, vector_t dir1, vector_t *p_up2, vector_t *p_dir2, scalar_t dt, scalar_t time_constant ) { quaternion_t q1, q2; scalar_t alpha; vector_t x1, y1, z1; vector_t x2, y2, z2; matrixgl_t cob_mat1, inv_cob_mat1; matrixgl_t cob_mat2, inv_cob_mat2; /* Now interpolate between camera orientations */ z1 = scale_vector( -1.0, dir1 ); normalize_vector( &z1 ); y1 = project_into_plane( z1, up1 ); normalize_vector( &y1 ); x1 = cross_product( y1, z1 ); make_change_of_basis_matrix( cob_mat1, inv_cob_mat1, x1, y1, z1 ); q1 = make_quaternion_from_matrix( cob_mat1 ); z2 = scale_vector( -1.0, *p_dir2 ); normalize_vector( &z2 ); y2 = project_into_plane( z2, *p_up2 ); normalize_vector( &y2 ); x2 = cross_product( y2, z2 ); make_change_of_basis_matrix( cob_mat2, inv_cob_mat2, x2, y2, z2 ); q2 = make_quaternion_from_matrix( cob_mat2 ); alpha = min( MAX_INTERPOLATION_VALUE, 1.0 - exp( -dt / time_constant ) ); q2 = interpolate_quaternions( q1, q2, alpha ); make_matrix_from_quaternion( cob_mat2, q2 ); p_up2->x = cob_mat2[1][0]; p_up2->y = cob_mat2[1][1]; p_up2->z = cob_mat2[1][2]; p_dir2->x = -cob_mat2[2][0]; p_dir2->y = -cob_mat2[2][1]; p_dir2->z = -cob_mat2[2][2]; }
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 ); }
void draw_billboard( player_data_t *plyr, point_t center_pt, scalar_t width, scalar_t height, bool_t use_world_y_axis, point2d_t min_tex_coord, point2d_t max_tex_coord ) { point_t pt; vector_t x_vec; vector_t y_vec; vector_t z_vec; x_vec.x = plyr->view.inv_view_mat[0][0]; x_vec.y = plyr->view.inv_view_mat[0][1]; x_vec.z = plyr->view.inv_view_mat[0][2]; if ( use_world_y_axis ) { y_vec = make_vector( 0, 1, 0 ); x_vec = project_into_plane( y_vec, x_vec ); normalize_vector( &x_vec ); z_vec = cross_product( x_vec, y_vec ); } else { y_vec.x = plyr->view.inv_view_mat[1][0]; y_vec.y = plyr->view.inv_view_mat[1][1]; y_vec.z = plyr->view.inv_view_mat[1][2]; z_vec.x = plyr->view.inv_view_mat[2][0]; z_vec.y = plyr->view.inv_view_mat[2][1]; z_vec.z = plyr->view.inv_view_mat[2][2]; } #ifdef __APPLE__DISABLED__ glNormal3f( z_vec.x, z_vec.y, z_vec.z ); pt = move_point( center_pt, scale_vector( -width/2.0, x_vec ) ); pt = move_point( pt, scale_vector( -height/2.0, y_vec ) ); point_t pt2 = move_point( pt, scale_vector( width, x_vec ) ); point_t pt3 = move_point( pt2, scale_vector( height, y_vec ) ); point_t pt4 = move_point( pt3, scale_vector( -width, x_vec ) ); const GLfloat vertices2 []= { pt.x, pt.y, pt.z, pt2.x, pt2.y, pt2.z, pt3.x, pt3.y, pt3.z, pt4.x, pt4.y, pt4.z }; const GLshort texCoords2 []= { min_tex_coord.x, min_tex_coord.y, max_tex_coord.x, min_tex_coord.y, max_tex_coord.x, max_tex_coord.y, min_tex_coord.x, max_tex_coord.y, }; glEnableClientState (GL_VERTEX_ARRAY); glVertexPointer (3, GL_FLOAT , 0, vertices2); glTexCoordPointer(2, GL_SHORT, 0, texCoords2); glDrawArrays(GL_TRIANGLE_STRIP, 0, 4); #else glBegin( GL_QUADS ); { pt = move_point( center_pt, scale_vector( -width/2.0, x_vec ) ); pt = move_point( pt, scale_vector( -height/2.0, y_vec ) ); glNormal3f( z_vec.x, z_vec.y, z_vec.z ); glTexCoord2f( min_tex_coord.x, min_tex_coord.y ); glVertex3f( pt.x, pt.y, pt.z ); pt = move_point( pt, scale_vector( width, x_vec ) ); glTexCoord2f( max_tex_coord.x, min_tex_coord.y ); glVertex3f( pt.x, pt.y, pt.z ); pt = move_point( pt, scale_vector( height, y_vec ) ); glTexCoord2f( max_tex_coord.x, max_tex_coord.y ); glVertex3f( pt.x, pt.y, pt.z ); pt = move_point( pt, scale_vector( -width, x_vec ) ); glTexCoord2f( min_tex_coord.x, max_tex_coord.y ); glVertex3f( pt.x, pt.y, pt.z ); } glEnd(); #endif }