Example #1
0
//instance at specified point with specified orientation
//if matrix==NULL, don't modify matrix.  This will be like doing an offset   
void g3_start_instance_matrix(vms_vector *pos, vms_matrix *orient) {
	vms_vector tempv;
	vms_matrix tempm, tempm2;

	Assert(instance_depth<MAX_INSTANCE_DEPTH);

	instance_stack[instance_depth].m = View_matrix;
	instance_stack[instance_depth].p = View_position;
	instance_depth++;

	//step 1: subtract object position from view position

	vm_vec_sub(&tempv, &View_position, pos);


	if (orient) {

		//step 2: rotate view vector through object matrix

		vm_vec_rotate(&View_position, &tempv, orient);

		//step 3: rotate object matrix through view_matrix (vm = ob * vm)

		vm_copy_transpose_matrix(&tempm2, orient);

		vm_matrix_x_matrix(&tempm, &tempm2, &View_matrix);
		View_matrix = tempm;
	}
}
Example #2
0
//	Create a wing.
//	wing_type is the type of wing from the Wing_formations array to create.
//	leader_index is the index in Objects of the leader object.  This object must
//	have a position and an orientation.
//	*wingmen is a list of indices of existing ships to be added to the wing.
//	The wingmen list is terminated by -1.
//	max_size is the maximum number of ships to add to the wing
//	fill_flag is set if more ships are to be added to fill out the wing to max_size
void create_wing(int wing_type, int leader_index, int *wingmen, int max_size, int fill_flag)
{
	int			num_placed, num_vectors, cur_vec_index;
	object		*lobjp = &Objects[leader_index];
	formation	*wingp;
	object		*parent;
	int			wing_list[MAX_OBJECTS];
	matrix		rotmat;

	initialize_wings();

	Assert((wing_type >= 0) && (wing_type < MAX_WING_FORMATIONS));
	Assert(Wing_formations[wing_type].num_vectors > 0);
	Assert(Wing_formations[wing_type].num_vectors < MAX_WING_VECTORS);

	Assert(Objects[leader_index].type != OBJ_NONE);
	Assert(max_size < MAX_SHIPS_PER_WING);

	num_placed = 0;
	wingp = &Wing_formations[wing_type];
	num_vectors = wingp->num_vectors;
	cur_vec_index = 0;
	parent = lobjp;
	vm_copy_transpose_matrix(&rotmat, &lobjp->orient);

	while (num_placed < max_size) {
		vector	wvec;
		int		curobj;

		if (*wingmen == -1) {
			if (!fill_flag)
				break;
			else {
				curobj = get_free_objnum();
				Assert(curobj != -1);
				Objects[curobj].type = lobjp->type;
				Assert(Wings[cur_wing].wave_count < MAX_SHIPS_PER_WING);
// JEH		Wings[cur_wing].ship_list[Wings[cur_wing].count] = curobj;
				Wings[cur_wing].wave_count++;
			}
		} else
			curobj = *wingmen++;

		Objects[curobj] = *lobjp;
		vm_vec_rotate(&wvec, &wingp->offsets[cur_vec_index], &rotmat);
		cur_vec_index = (cur_vec_index + 1) % num_vectors;
		
		if (num_placed < num_vectors)
			parent = lobjp;
		else
			parent = &Objects[wing_list[num_placed - num_vectors]];
		
		wing_list[num_placed] = curobj;

		vm_vec_add(&Objects[curobj].pos, &parent->pos, &wvec);

		num_placed++;
	}

}
Example #3
0
//from a 2d point, compute the vector through that point
void g3_point_2_vec(vms_vector *v, short sx, short sy) {
	vms_vector tempv;
	vms_matrix tempm;

	tempv.x = fixmuldiv(fixdiv((sx << 16) - Canv_w2, Canv_w2), Matrix_scale.z, Matrix_scale.x);
	tempv.y = -fixmuldiv(fixdiv((sy << 16) - Canv_h2, Canv_h2), Matrix_scale.z, Matrix_scale.y);
	tempv.z = f1_0;

	vm_vec_normalize(&tempv);

	vm_copy_transpose_matrix(&tempm, &Unscaled_matrix);

	vm_vec_rotate(v, &tempv, &tempm);

}
Example #4
0
//	-----------------------------------------------------------------------------
//return the position & orientation of a gun on the control center object 
void calc_controlcen_gun_point(vms_vector *gun_point,vms_vector *gun_dir,object *obj,int gun_num)
{
	vms_matrix m;

	Assert(obj->type == OBJ_CNTRLCEN);
	Assert(obj->render_type==RT_POLYOBJ);

	Assert(gun_num < N_controlcen_guns);

	//instance gun position & orientation

	vm_copy_transpose_matrix(&m,&obj->orient);

	vm_vec_rotate(gun_point,&controlcen_gun_points[gun_num],&m);
	vm_vec_add2(gun_point,&obj->pos);
	vm_vec_rotate(gun_dir,&controlcen_gun_dirs[gun_num],&m);
}
Example #5
0
//given an object and a gun number, return position in 3-space of gun
//fills in gun_point
void calc_gun_point(vms_vector *gun_point,object *obj,int gun_num)
{
	polymodel *pm;
	robot_info *r;
	vms_vector pnt;
	vms_matrix m;
	int mn;				//submodel number

	Assert(obj->render_type==RT_POLYOBJ || obj->render_type==RT_MORPH);
	Assert(obj->id < N_robot_types);

	r = &Robot_info[obj->id];
	pm =&Polygon_models[r->model_num];

	if (gun_num >= r->n_guns)
	{
		mprintf((1, "Bashing gun num %d to 0.\n", gun_num));
		//Int3();
		gun_num = 0;
	}

//	Assert(gun_num < r->n_guns);

	pnt = r->gun_points[gun_num];
	mn = r->gun_submodels[gun_num];

	//instance up the tree for this gun
	while (mn != 0) {
		vms_vector tpnt;

		vm_angles_2_matrix(&m,&obj->rtype.pobj_info.anim_angles[mn]);
		vm_transpose_matrix(&m);
		vm_vec_rotate(&tpnt,&pnt,&m);

		vm_vec_add(&pnt,&tpnt,&pm->submodel_offsets[mn]);

		mn = pm->submodel_parents[mn];
	}

	//now instance for the entire object

	vm_copy_transpose_matrix(&m,&obj->orient);
	vm_vec_rotate(gun_point,&pnt,&m);
	vm_vec_add2(gun_point,&obj->pos);

}
void model_collide_preprocess_subobj(vec3d *pos, matrix *orient, polymodel *pm,  polymodel_instance *pmi, int subobj_num)
{
	submodel_instance *smi = &pmi->submodel[subobj_num];

	smi->mc_base = *pos;
	smi->mc_orient = *orient;

	int i = pm->submodel[subobj_num].first_child;

	while ( i >= 0 ) {
		angles angs = pmi->submodel[i].angs;
		bsp_info * csm = &pm->submodel[i];

		matrix tm = IDENTITY_MATRIX;

		vm_vec_unrotate(pos, &csm->offset, &smi->mc_orient );
		vm_vec_add2(pos, &smi->mc_base);

		if( vm_matrix_same(&tm, &csm->orientation)) {
			// if submodel orientation matrix is identity matrix then don't bother with matrix ops
			vm_angles_2_matrix(&tm, &angs);
		} else {
			matrix rotation_matrix = csm->orientation;
			vm_rotate_matrix_by_angles(&rotation_matrix, &angs);

			matrix inv_orientation;
			vm_copy_transpose_matrix(&inv_orientation, &csm->orientation);

			vm_matrix_x_matrix(&tm, &rotation_matrix, &inv_orientation);
		}

		vm_matrix_x_matrix(orient, &smi->mc_orient, &tm);

		model_collide_preprocess_subobj(pos, orient, pm, pmi, i);

		i = csm->next_sibling;
	}
}
Example #7
0
//called for each level to load & setup the exit sequence
load_endlevel_data(int level_num)
{
	char filename[13];
	char line[LINE_LEN],*p;
	CFILE *ifile;
	int var,segnum,sidenum;
	int exit_side, i;
	int have_binary = 0;

	endlevel_data_loaded = 0;		//not loaded yet

try_again:
	;

	if (level_num<0)		//secret level
		strcpy(filename,Secret_level_names[-level_num-1]);
	else					//normal level
		strcpy(filename,Level_names[level_num-1]);

	if (!convert_ext(filename,"END"))
		return;

	ifile = cfopen(filename,"rb");

	if (!ifile) {

		convert_ext(filename,"TXB");

		ifile = cfopen(filename,"rb");

		if (!ifile)
			if (level_num==1) {
				return;		//abort
				//Error("Cannot load file text of binary version of <%s>",filename);
			}
			else {
				level_num = 1;
				goto try_again;
			}

		have_binary = 1;
	}

	//ok...this parser is pretty simple.  It ignores comments, but
	//everything else must be in the right place

	var = 0;

	while (cfgets(line,LINE_LEN,ifile)) {

		if (have_binary) {
			for (i = 0; i < strlen(line) - 1; i++) {
				encode_rotate_left(&(line[i]));
				line[i] = line[i] ^ BITMAP_TBL_XOR;
				encode_rotate_left(&(line[i]));
			}
			p = line;
		}

		if ((p=strchr(line,';'))!=NULL)
			*p = 0;		//cut off comment

		for (p=line+strlen(line)-1;p>line && isspace(*p);*p--=0);
		for (p=line;isspace(*p);p++);

		if (!*p)		//empty line
			continue;

		switch (var) {

			case 0: {						//ground terrain
				int iff_error;
				ubyte pal[768];

				if (terrain_bm_instance.bm_data)
					free(terrain_bm_instance.bm_data);

				iff_error = iff_read_bitmap(p,&terrain_bm_instance,BM_LINEAR,pal);
				if (iff_error != IFF_NO_ERROR) {
					mprintf((1, "File %s - IFF error: %s",p,iff_errormsg(iff_error)));
					Error("File %s - IFF error: %s",p,iff_errormsg(iff_error));
				}

				terrain_bitmap = &terrain_bm_instance;
				gr_remap_bitmap_good( terrain_bitmap, pal, iff_transparent_color, -1);

				break;
			}

			case 1:							//height map

				load_terrain(p);
				break;


			case 2:

				sscanf(p,"%d,%d",&exit_point_bmx,&exit_point_bmy);
				break;

			case 3:							//exit heading

				exit_angles.h = i2f(atoi(p))/360;
				break;

			case 4: {						//planet bitmap
				int iff_error;
				ubyte pal[768];

				if (satellite_bm_instance.bm_data)
					free(satellite_bm_instance.bm_data);

				iff_error = iff_read_bitmap(p,&satellite_bm_instance,BM_LINEAR,pal);
				if (iff_error != IFF_NO_ERROR) {
					mprintf((1, "File %s - IFF error: %s",p,iff_errormsg(iff_error)));
					Error("File %s - IFF error: %s",p,iff_errormsg(iff_error));
				}

				satellite_bitmap = &satellite_bm_instance;
				gr_remap_bitmap_good( satellite_bitmap, pal, iff_transparent_color, -1);

				break;
			}

			case 5:							//earth pos
			case 7: {						//station pos
				vms_matrix tm;
				vms_angvec ta;
				int pitch,head;

				sscanf(p,"%d,%d",&head,&pitch);

				ta.h = i2f(head)/360;
				ta.p = -i2f(pitch)/360;
				ta.b = 0;

				vm_angles_2_matrix(&tm,&ta);

				if (var==5)
					satellite_pos = tm.fvec;
					//vm_vec_copy_scale(&satellite_pos,&tm.fvec,SATELLITE_DIST);
				else
					station_pos = tm.fvec;

				break;
			}

			case 6:						//planet size
				satellite_size = i2f(atoi(p));
				break;
		}

		var++;

	}

	Assert(var == NUM_VARS);


	// OK, now the data is loaded.  Initialize everything

	//find the exit sequence by searching all segments for a side with
	//children == -2

	for (segnum=0,exit_segnum=-1;exit_segnum==-1 && segnum<=Highest_segment_index;segnum++)
		for (sidenum=0;sidenum<6;sidenum++)
			if (Segments[segnum].children[sidenum] == -2) {
				exit_segnum = segnum;
				exit_side = sidenum;
				break;
			}

	Assert(exit_segnum!=-1);

	compute_segment_center(&mine_exit_point,&Segments[exit_segnum]);
	extract_orient_from_segment(&mine_exit_orient,&Segments[exit_segnum]);
	compute_center_point_on_side(&mine_side_exit_point,&Segments[exit_segnum],exit_side);

	vm_vec_scale_add(&mine_ground_exit_point,&mine_exit_point,&mine_exit_orient.uvec,-i2f(20));

	//compute orientation of surface
	{
		vms_vector tv;
		vms_matrix exit_orient,tm;

		vm_angles_2_matrix(&exit_orient,&exit_angles);
		vm_transpose_matrix(&exit_orient);
		vm_matrix_x_matrix(&surface_orient,&mine_exit_orient,&exit_orient);

		vm_copy_transpose_matrix(&tm,&surface_orient);
		vm_vec_rotate(&tv,&station_pos,&tm);
		vm_vec_scale_add(&station_pos,&mine_exit_point,&tv,STATION_DIST);

vm_vec_rotate(&tv,&satellite_pos,&tm);
vm_vec_scale_add(&satellite_pos,&mine_exit_point,&tv,SATELLITE_DIST);

vm_vector_2_matrix(&tm,&tv,&surface_orient.uvec,NULL);
vm_vec_copy_scale(&satellite_upvec,&tm.uvec,SATELLITE_HEIGHT);


	}

	cfclose(ifile);

	endlevel_data_loaded = 1;

}
// function looks at the flying controls and the current velocity to determine a goal velocity
// function determines velocity in object's reference frame and goal velocity in object's reference frame
void physics_read_flying_controls( matrix * orient, physics_info * pi, control_info * ci, float sim_time, vec3d *wash_rot)
{
	vec3d goal_vel;		// goal velocity in local coords, *not* accounting for ramping of velcity
	float ramp_time_const;		// time constant for velocity ramping

	// apply throttle, unless reverse thrusters are held down
	if (ci->forward != -1.0f)
		ci->forward += (ci->forward_cruise_percent / 100.0f);

	// give control input to cause rotation in engine wash
	extern int Wash_on;
	if ( wash_rot && Wash_on ) {
		ci->pitch += wash_rot->xyz.x;
		ci->bank += wash_rot->xyz.z;
		ci->heading += wash_rot->xyz.y;
	}

	if (ci->pitch > 1.0f ) ci->pitch = 1.0f;
	else if (ci->pitch < -1.0f ) ci->pitch = -1.0f;

	if (ci->vertical > 1.0f ) ci->vertical = 1.0f;
	else if (ci->vertical < -1.0f ) ci->vertical = -1.0f;

	if (ci->heading > 1.0f ) ci->heading = 1.0f;
	else if (ci->heading < -1.0f ) ci->heading = -1.0f;

	if (ci->sideways > 1.0f  ) ci->sideways = 1.0f;
	else if (ci->sideways < -1.0f  ) ci->sideways = -1.0f;

	if (ci->bank > 1.0f ) ci->bank = 1.0f;
	else if (ci->bank < -1.0f ) ci->bank = -1.0f;

	if ( pi->flags & PF_AFTERBURNER_ON ){
		//SparK: modifield to accept reverse burners
		if (!(pi->afterburner_max_reverse_vel > 0.0f)){
			ci->forward = 1.0f;
		}
	}

	if (ci->forward > 1.0f ) ci->forward = 1.0f;
	else if (ci->forward < -1.0f ) ci->forward = -1.0f;

	if (!Flight_controls_follow_eyepoint_orientation || (Player_obj == NULL) || (Player_obj->type != OBJ_SHIP)) {
		// Default behavior; eyepoint orientation has no effect on controls
		pi->desired_rotvel.xyz.x = ci->pitch * pi->max_rotvel.xyz.x;
		pi->desired_rotvel.xyz.y = ci->heading * pi->max_rotvel.xyz.y;
	} else {
		// Optional behavior; pitch and yaw are always relative to the eyepoint
		// orientation (excluding slew)
		vec3d tmp_vec, new_rotvel;
		matrix tmp_mat, eyemat, rotvelmat;

		ship_get_eye(&tmp_vec, &eyemat, Player_obj, false);

		vm_copy_transpose_matrix(&tmp_mat, &Player_obj->orient);
		vm_matrix_x_matrix(&rotvelmat, &tmp_mat, &eyemat);

		vm_vec_rotate(&new_rotvel, &pi->max_rotvel, &rotvelmat);
		vm_vec_unrotate(&tmp_vec, &pi->max_rotvel, &rotvelmat);
		new_rotvel.xyz.x = tmp_vec.xyz.x;

		new_rotvel.xyz.x = ci->pitch * new_rotvel.xyz.x;
		new_rotvel.xyz.y = ci->heading * new_rotvel.xyz.y;

		vm_vec_unrotate(&tmp_vec, &new_rotvel, &rotvelmat);

		pi->desired_rotvel = tmp_vec;
	}

	float	delta_bank;

#ifdef BANK_WHEN_TURN
	//	To change direction of bank, negate the whole expression.
	//	To increase magnitude of banking, decrease denominator.
	//	Adam: The following statement is all the math for banking while turning.
	delta_bank = - (ci->heading * pi->max_rotvel.xyz.y) * pi->delta_bank_const;
#else
	delta_bank = 0.0f;
#endif

	pi->desired_rotvel.xyz.z = ci->bank * pi->max_rotvel.xyz.z + delta_bank;
	pi->forward_thrust = ci->forward;
	pi->vert_thrust = ci->vertical;	//added these two in order to get side and forward thrusters
	pi->side_thrust = ci->sideways;	//to glow brighter when the ship is moving in the right direction -Bobboau

	if ( pi->flags & PF_AFTERBURNER_ON ) {
		goal_vel.xyz.x = ci->sideways*pi->afterburner_max_vel.xyz.x;
		goal_vel.xyz.y = ci->vertical*pi->afterburner_max_vel.xyz.y;
		if(ci->forward < 0.0f)
			goal_vel.xyz.z = ci->forward* pi->afterburner_max_reverse_vel;
		else
			goal_vel.xyz.z = ci->forward* pi->afterburner_max_vel.xyz.z;
	}
	else if ( pi->flags & PF_BOOSTER_ON ) {
		goal_vel.xyz.x = ci->sideways*pi->booster_max_vel.xyz.x;
		goal_vel.xyz.y = ci->vertical*pi->booster_max_vel.xyz.y;
		goal_vel.xyz.z = ci->forward* pi->booster_max_vel.xyz.z;
	}
	else {
		goal_vel.xyz.x = ci->sideways*pi->max_vel.xyz.x;
		goal_vel.xyz.y = ci->vertical*pi->max_vel.xyz.y;
		goal_vel.xyz.z = ci->forward* pi->max_vel.xyz.z;
	}

	if ( goal_vel.xyz.z < -pi->max_rear_vel && !(pi->flags & PF_AFTERBURNER_ON) )
		goal_vel.xyz.z = -pi->max_rear_vel;


	if ( pi->flags & PF_ACCELERATES )	{
		//
		// Determine *resultant* DESIRED VELOCITY (desired_vel) accounting for RAMPING of velocity
		// Use LOCAL coordinates
		// if slide_enabled, ramp velocity for x and y, otherwise set goal (0)
		//    always ramp velocity for z
		//

		// If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast.
		// Scale according to reduced_damp_time_expansion.
		float reduced_damp_ramp_time_expansion;
		if ( pi->flags & PF_REDUCED_DAMP && !timestamp_elapsed(pi->reduced_damp_decay) ) {
			float reduced_damp_fraction_time_left = timestamp_until( pi->reduced_damp_decay ) / (float) REDUCED_DAMP_TIME;
			reduced_damp_ramp_time_expansion = 1.0f + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left;
		} else {
			reduced_damp_ramp_time_expansion = 1.0f;
		}

		if (pi->flags & PF_SLIDE_ENABLED)  {
			// determine the local velocity
			// deterimine whether accelerating or decleration toward goal for x
			if ( goal_vel.xyz.x > 0.0f )  {
				if ( goal_vel.xyz.x >= pi->prev_ramp_vel.xyz.x )
					ramp_time_const = pi->slide_accel_time_const;
				else
					ramp_time_const = pi->slide_decel_time_const;
			} else if ( goal_vel.xyz.x < 0.0f ) {
				if ( goal_vel.xyz.x <= pi->prev_ramp_vel.xyz.x )
					ramp_time_const = pi->slide_accel_time_const;
				else
					ramp_time_const = pi->slide_decel_time_const;
			} else {
				ramp_time_const = pi->slide_decel_time_const;
			}
			// If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast
			if ( pi->flags & PF_REDUCED_DAMP ) {
				ramp_time_const *= reduced_damp_ramp_time_expansion;
			}
			pi->prev_ramp_vel.xyz.x = velocity_ramp(pi->prev_ramp_vel.xyz.x, goal_vel.xyz.x, ramp_time_const, sim_time);

			// deterimine whether accelerating or decleration toward goal for y
			if ( goal_vel.xyz.y > 0.0f )  {
				if ( goal_vel.xyz.y >= pi->prev_ramp_vel.xyz.y )
					ramp_time_const = pi->slide_accel_time_const;
				else
					ramp_time_const = pi->slide_decel_time_const;
			} else if ( goal_vel.xyz.y < 0.0f ) {
				if ( goal_vel.xyz.y <= pi->prev_ramp_vel.xyz.y )
					ramp_time_const = pi->slide_accel_time_const;
				else
					ramp_time_const = pi->slide_decel_time_const;
			} else {
				ramp_time_const = pi->slide_decel_time_const;
			}
			// If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast
			if ( pi->flags & PF_REDUCED_DAMP ) {
				ramp_time_const *= reduced_damp_ramp_time_expansion;
			}
			pi->prev_ramp_vel.xyz.y = velocity_ramp( pi->prev_ramp_vel.xyz.y, goal_vel.xyz.y, ramp_time_const, sim_time);
		} else  {
			// slide not enabled
			pi->prev_ramp_vel.xyz.x = 0.0f;
			pi->prev_ramp_vel.xyz.y = 0.0f;
		}

		// deterimine whether accelerating or decleration toward goal for z
		if ( goal_vel.xyz.z > 0.0f )  {
			if ( goal_vel.xyz.z >= pi->prev_ramp_vel.xyz.z )  {
				if ( pi->flags & PF_AFTERBURNER_ON )
					ramp_time_const = pi->afterburner_forward_accel_time_const;
				else if (pi->flags & PF_BOOSTER_ON)
					ramp_time_const = pi->booster_forward_accel_time_const;
				else
					ramp_time_const = pi->forward_accel_time_const;
			} else {
				ramp_time_const = pi->forward_decel_time_const;
			}
		} else if ( goal_vel.xyz.z < 0.0f ) {
			if ( pi->flags & PF_AFTERBURNER_ON )
				ramp_time_const = pi->afterburner_reverse_accel;
			else
				ramp_time_const = pi->forward_decel_time_const;
		} else {
			ramp_time_const = pi->forward_decel_time_const;
		}

		// If reduced damp in effect, then adjust ramp_velocity and desired_velocity can not change as fast
		if ( pi->flags & PF_REDUCED_DAMP ) {
			ramp_time_const *= reduced_damp_ramp_time_expansion;
		}
		pi->prev_ramp_vel.xyz.z = velocity_ramp(pi->prev_ramp_vel.xyz.z, goal_vel.xyz.z, ramp_time_const, sim_time);

		//Deternine the current dynamic glide cap, and ramp to it
		//This is outside the normal "glide" block since we want the cap to adjust whether or not the ship is in glide mode
		float dynamic_glide_cap_goal = 0.0;
		if (pi->flags & PF_AFTERBURNER_ON) {
			dynamic_glide_cap_goal = ( goal_vel.xyz.z >= 0.0f ) ? pi->afterburner_max_vel.xyz.z : pi->afterburner_max_reverse_vel;
		}
		else {
			//Use the maximum value in X, Y, and Z (including overclocking)
			dynamic_glide_cap_goal = MAX(MAX(pi->max_vel.xyz.x,pi->max_vel.xyz.y), pi->max_vel.xyz.z);
		}
		pi->cur_glide_cap = velocity_ramp(pi->cur_glide_cap, dynamic_glide_cap_goal, ramp_time_const, sim_time);


		if ( (pi->flags & PF_GLIDING) || (pi->flags & PF_FORCE_GLIDE ) ) {
			pi->desired_vel = pi->vel;

			//SUSHI: A (hopefully better) approach to dealing with accelerations in glide mode
			//Get *actual* current velocities along each axis and use those instead of ramped velocities
			vec3d local_vel;
			vm_vec_rotate(&local_vel, &pi->vel, orient);

			//Having pi->glide_cap == 0 means we're using a dynamic glide cap
			float curGlideCap = 0.0f;
			if (pi->glide_cap == 0.0f) 
				curGlideCap = pi->cur_glide_cap;
			else 
				curGlideCap = pi->glide_cap;

			//If we're near the (positive) glide cap, decay velocity where we aren't thrusting
			//This is a hack, but makes the flight feel a lot smoother
			//Don't do this if we aren't applying any thrust, we have no glide cap, or the accel multiplier is 0 (no thrust while gliding)
			float cap_decay_threshold = 0.95f;
			float cap_decay_amount = 0.2f;
			if (curGlideCap >= 0.0f && vm_vec_mag(&pi->desired_vel) >= cap_decay_threshold * curGlideCap && 
					vm_vec_mag(&goal_vel) > 0.0f &&
					pi->glide_accel_mult != 0.0f) 
			{
				if (goal_vel.xyz.x == 0.0f)
					vm_vec_scale_add2(&pi->desired_vel, &orient->vec.rvec, -cap_decay_amount * local_vel.xyz.x);
				if (goal_vel.xyz.y == 0.0f)
					vm_vec_scale_add2(&pi->desired_vel, &orient->vec.uvec, -cap_decay_amount * local_vel.xyz.y);
				if (goal_vel.xyz.z == 0.0f)
					vm_vec_scale_add2(&pi->desired_vel, &orient->vec.fvec, -cap_decay_amount * local_vel.xyz.z);
			}

			//The glide_ramp function uses (basically) the same math as the velocity ramp so that thruster power is consistent
			//Only ramp if the glide cap is positive
			float xVal = glide_ramp(local_vel.xyz.x, goal_vel.xyz.x, pi->slide_accel_time_const, pi->glide_accel_mult, sim_time);
			float yVal = glide_ramp(local_vel.xyz.y, goal_vel.xyz.y, pi->slide_accel_time_const, pi->glide_accel_mult, sim_time);
			float zVal = 0.0;
			if (pi->flags & PF_AFTERBURNER_ON) 
				zVal = glide_ramp(local_vel.xyz.z, goal_vel.xyz.z, pi->afterburner_forward_accel_time_const, pi->glide_accel_mult, sim_time);
			else {
				if (goal_vel.xyz.z >= 0.0f)
					zVal = glide_ramp(local_vel.xyz.z, goal_vel.xyz.z, pi->forward_accel_time_const, pi->glide_accel_mult, sim_time);
				else
					zVal = glide_ramp(local_vel.xyz.z, goal_vel.xyz.z, pi->forward_decel_time_const, pi->glide_accel_mult, sim_time);
			}

			//Compensate for effect of dampening: normal flight cheats here, so /we make up for it this way so glide acts the same way
			xVal *= pi->side_slip_time_const / sim_time;
			yVal *= pi->side_slip_time_const / sim_time;
			if (pi->use_newtonian_damp) zVal *= pi->side_slip_time_const / sim_time;

			vm_vec_scale_add2(&pi->desired_vel, &orient->vec.fvec, zVal);
			vm_vec_scale_add2(&pi->desired_vel, &orient->vec.rvec, xVal);
			vm_vec_scale_add2(&pi->desired_vel, &orient->vec.uvec, yVal);

			// Only do the glide cap if we have one and are actively thrusting in some direction.
			if ( curGlideCap >= 0.0f && (ci->forward != 0.0f || ci->sideways != 0.0f || ci->vertical != 0.0f) ) {
				float currentmag = vm_vec_mag(&pi->desired_vel);
				if ( currentmag > curGlideCap ) {
					vm_vec_scale( &pi->desired_vel, curGlideCap / currentmag );
				}
			}
		}
		else
		{
			// this translates local desired velocities to world velocities
			vm_vec_zero(&pi->desired_vel);
			vm_vec_scale_add2( &pi->desired_vel, &orient->vec.rvec, pi->prev_ramp_vel.xyz.x );
			vm_vec_scale_add2( &pi->desired_vel, &orient->vec.uvec, pi->prev_ramp_vel.xyz.y );
			vm_vec_scale_add2( &pi->desired_vel, &orient->vec.fvec, pi->prev_ramp_vel.xyz.z );
		}
	} else  // object does not accelerate  (PF_ACCELERATES not set)
		pi->desired_vel = pi->vel;
}
Example #9
0
//instance at specified point with specified orientation
//if matrix==NULL, don't modify matrix.  This will be like doing an offset   
//if pos==NULL, no position change
void g3_start_instance_matrix(vector *pos,matrix *orient, bool set_api)
{
	vector tempv;
	matrix tempm,tempm2;

	 Assert( G3_count == 1 );

	Assert(instance_depth<MAX_INSTANCE_DEPTH);

	instance_stack[instance_depth].m = View_matrix;
	instance_stack[instance_depth].p = View_position;
	instance_stack[instance_depth].lm = Light_matrix;
	instance_stack[instance_depth].lb = Light_base;
	instance_stack[instance_depth].om = Object_matrix;
	instance_stack[instance_depth].op = Object_position;
	instance_depth++;

	// Make sure orient is valid
	if (!orient) {
		orient = &vmd_identity_matrix;		// Assume no change in orient
	}


	if ( pos )	{
		//step 1: subtract object position from view position
		vm_vec_sub2(&View_position,pos);

		//step 2: rotate view vector through object matrix
		vm_vec_rotate(&tempv,&View_position,orient);
		View_position = tempv;

		vm_copy_transpose_matrix(&tempm2,&Object_matrix);
		vm_vec_rotate(&tempv,pos,&tempm2);
		vm_vec_add(&Object_position, &Object_position, &tempv);
//		Object_position = tempv;
	} else {
		// No movement, leave View_position alone
	}

	//step 3: rotate object matrix through view_matrix (vm = ob * vm)
	vm_copy_transpose_matrix(&tempm2,orient);

	vm_matrix_x_matrix(&tempm,&tempm2,&View_matrix);
	View_matrix = tempm;

	vm_matrix_x_matrix(&Object_matrix,orient,&instance_stack[instance_depth-1].om);
//	Object_matrix = tempm;

	// Update the lighting matrix
	matrix saved_orient = Light_matrix;
	vector saved_base = Light_base;
	
	if ( pos )	{
		vm_vec_unrotate(&Light_base,pos,&saved_orient );
		vm_vec_add2(&Light_base, &saved_base );
	} else {
		// No movement, light_base doesn't change.
	}

	vm_matrix_x_matrix(&Light_matrix,&saved_orient, orient);

	if(!Cmdline_nohtl && set_api)
		gr_start_instance_matrix(pos,orient);

}
// This function recursively checks a submodel and its children
// for a collision with a vector.
void mc_check_subobj( int mn )
{
	vec3d tempv;
	vec3d hitpt;		// used in bounding box check
	bsp_info * sm;
	int i;

	Assert( mn >= 0 );
	Assert( mn < Mc_pm->n_models );

	if ( (mn < 0) || (mn>=Mc_pm->n_models) ) return;
	
	sm = &Mc_pm->submodel[mn];
	if (sm->no_collisions) return; // don't do collisions
	if (sm->nocollide_this_only) goto NoHit; // Don't collide for this model, but keep checking others

	// Rotate the world check points into the current subobject's 
	// frame of reference.
	// After this block, Mc_p0, Mc_p1, Mc_direction, and Mc_mag are correct
	// and relative to this subobjects' frame of reference.
	vm_vec_sub(&tempv, Mc->p0, &Mc_base);
	vm_vec_rotate(&Mc_p0, &tempv, &Mc_orient);

	vm_vec_sub(&tempv, Mc->p1, &Mc_base);
	vm_vec_rotate(&Mc_p1, &tempv, &Mc_orient);
	vm_vec_sub(&Mc_direction, &Mc_p1, &Mc_p0);

	// If we are checking the root submodel, then we might want
	// to check the shield at this point
	if (Mc_pm->detail[0] == mn)	{

		// Do a quick out on the entire bounding box of the object
		if (!mc_ray_boundingbox( &Mc_pm->mins, &Mc_pm->maxs, &Mc_p0, &Mc_direction, NULL))	{
			return;
		}
			
		// Check shield if we're supposed to
		if ((Mc->flags & MC_CHECK_SHIELD) && (Mc_pm->shield.ntris > 0 )) {
			mc_check_shield();
			return;
		}

	}

	if(!(Mc->flags & MC_CHECK_MODEL)) return;
	
	Mc_submodel = mn;

	// Check if the ray intersects this subobject's bounding box 	
	if (mc_ray_boundingbox(&sm->min, &sm->max, &Mc_p0, &Mc_direction, &hitpt))	{

		// The ray interects this bounding box, so we have to check all the
		// polygons in this submodel.
		if ( Mc->flags & MC_ONLY_BOUND_BOX )	{
			float dist = vm_vec_dist( &Mc_p0, &hitpt );

			if ( dist < 0.0f ) goto NoHit; // If the ray is behind the plane there is no collision
			if ( !(Mc->flags & MC_CHECK_RAY) && (dist > Mc_mag) ) goto NoHit; // The ray isn't long enough to intersect the plane

			// If the ray hits, but a closer intersection has already been found, return
			if ( Mc->num_hits && (dist >= Mc->hit_dist ) ) goto NoHit;	

			Mc->hit_dist = dist;
			Mc->hit_point = hitpt;
			Mc->hit_submodel = Mc_submodel;
			Mc->hit_bitmap = -1;
			Mc->num_hits++;
		} else {
			if ( Cmdline_old_collision_sys ) {
				model_collide_sub(sm->bsp_data);
			} else {
				model_collide_bsp(model_get_bsp_collision_tree(sm->collision_tree_index), 0);
			}
		}
	}

NoHit:

	// If we're only checking one submodel, return
	if (Mc->flags & MC_SUBMODEL)	{
		return;
	}

	
	// If this subobject doesn't have any children, we're done checking it.
	if ( sm->num_children < 1 ) return;
	
	// Save instance (Mc_orient, Mc_base, Mc_point_base)
	matrix saved_orient = Mc_orient;
	vec3d saved_base = Mc_base;
	
	// Check all of this subobject's children
	i = sm->first_child;
	while ( i >= 0 )	{
		angles angs;
		bool blown_off;
		bool collision_checked;
		bsp_info * csm = &Mc_pm->submodel[i];
		
		if ( Mc_pmi ) {
			angs = Mc_pmi->submodel[i].angs;
			blown_off = Mc_pmi->submodel[i].blown_off;
			collision_checked = Mc_pmi->submodel[i].collision_checked;
		} else {
			angs = csm->angs;
			blown_off = csm->blown_off ? true : false;
			collision_checked = false;
		}

		// Don't check it or its children if it is destroyed
		// or if it's set to no collision
		if ( !blown_off && !collision_checked && !csm->no_collisions )	{
			if ( Mc_pmi ) {
				Mc_orient = Mc_pmi->submodel[i].mc_orient;
				Mc_base = Mc_pmi->submodel[i].mc_base;
				vm_vec_add2(&Mc_base, Mc->pos);
			} else {
				//instance for this subobject
				matrix tm = IDENTITY_MATRIX;

				vm_vec_unrotate(&Mc_base, &csm->offset, &saved_orient );
				vm_vec_add2(&Mc_base, &saved_base );

				if( vm_matrix_same(&tm, &csm->orientation)) {
					// if submodel orientation matrix is identity matrix then don't bother with matrix ops
					vm_angles_2_matrix(&tm, &angs);
				} else {
					matrix rotation_matrix = csm->orientation;
					vm_rotate_matrix_by_angles(&rotation_matrix, &angs);

					matrix inv_orientation;
					vm_copy_transpose_matrix(&inv_orientation, &csm->orientation);

					vm_matrix_x_matrix(&tm, &rotation_matrix, &inv_orientation);
				}

				vm_matrix_x_matrix(&Mc_orient, &saved_orient, &tm);
			}

			mc_check_subobj( i );
		}

		i = csm->next_sibling;
	}

}