// Determine if point to lock on is in range
int hud_lock_target_in_range()
{
	vector		target_world_pos, vec_to_target;
	object		*targetp;

	if ( !hud_lock_has_homing_point() ) {
		return 0;
	}

	targetp = &Objects[Player_ai->target_objnum];

	if ( Player_ai->targeted_subsys != NULL ) {
		vm_vec_unrotate(&target_world_pos, &Player_ai->targeted_subsys->system_info->pnt, &targetp->orient);
		vm_vec_add2(&target_world_pos, &targetp->pos);
	} else {
		if ( Player->locking_subsys ) {
			vm_vec_unrotate(&target_world_pos, &Player->locking_subsys->system_info->pnt, &targetp->orient);
			vm_vec_add2(&target_world_pos, &targetp->pos);
		} else {
			Assert(Player->locking_on_center);
			target_world_pos = targetp->pos;
		}
	}

	return hud_lock_world_pos_in_range(&target_world_pos, &vec_to_target);
}
void supernova_do_particles()
{
	int idx;
	vec3d a, b, ta, tb;
	vec3d norm, sun_temp;

	// no player ship
	if((Player_obj == NULL) || (Player_ship == NULL)) {
		return;
	}

	// timestamp
	if((Supernova_particle_stamp == -1) || timestamp_elapsed(Supernova_particle_stamp)) {
		Supernova_particle_stamp = timestamp(sn_particles);

		// get particle norm
		stars_get_sun_pos(0, &sun_temp);
		vm_vec_add2(&sun_temp, &Player_obj->pos);
		vm_vec_sub(&norm, &Player_obj->pos, &sun_temp);
		vm_vec_normalize(&norm);

		particle_emitter whee;
		whee.max_life = 1.0f;
		whee.min_life = 0.6f;
		whee.max_vel = 50.0f;
		whee.min_vel = 25.0f;
		whee.normal_variance = 0.75f;
		whee.num_high = 5;
		whee.num_low = 2;
		whee.min_rad = 0.5f;
		whee.max_rad = 1.25f;

		// emit
		for(idx=0; idx<10; idx++) {
			if ( Cmdline_old_collision_sys ) {
				submodel_get_two_random_points(Ship_info[Player_ship->ship_info_index].model_num, 0, &ta, &tb);
			} else {
				submodel_get_two_random_points_better(Ship_info[Player_ship->ship_info_index].model_num, 0, &ta, &tb);
			}

			// rotate into world space
			vm_vec_unrotate(&a, &ta, &Player_obj->orient);
			vm_vec_add2(&a, &Player_obj->pos);
			whee.pos = a;
			whee.vel = norm;
			vm_vec_scale(&whee.vel, 30.0f);
			vm_vec_add2(&whee.vel, &Player_obj->phys_info.vel);
			whee.normal = norm;
			particle_emit(&whee, PARTICLE_FIRE, 0);

			vm_vec_unrotate(&b, &tb, &Player_obj->orient);
			vm_vec_add2(&b, &Player_obj->pos);
			whee.pos = b;
			particle_emit(&whee, PARTICLE_FIRE, 0);
		}
	}
}
// determine if the subsystem to lock on to has a direct line of sight
int hud_lock_on_subsys_ok()
{
	ship_subsys		*subsys;
	vector			subobj_pos;
	object			*target_objp;
	int				in_sight=0;
	
	Assert(Player_ai->target_objnum >= 0);
	target_objp	= &Objects[Player_ai->target_objnum];

	subsys = Player_ai->targeted_subsys;
	if ( !subsys ) {
		return 0;
	}

	vm_vec_unrotate(&subobj_pos, &subsys->system_info->pnt, &target_objp->orient);
	vm_vec_add2(&subobj_pos, &target_objp->pos);

	if ( Player->subsys_in_view < 0 ) {
		in_sight = ship_subsystem_in_sight(target_objp, subsys, &View_position, &subobj_pos);
	} else {
		in_sight = Player->subsys_in_view;
	}

	return in_sight;
}
// return the world pos of the sound source on a ship.  
void obj_snd_source_pos(vec3d *sound_pos, obj_snd *osp)
{
	vec3d offset_world;
	object *objp = &Objects[osp->objnum];

	// get sound pos in world coords
	vm_vec_unrotate(&offset_world, &osp->offset, &objp->orient);
	vm_vec_add(sound_pos, &objp->pos, &offset_world);
}
Exemple #5
0
/**
 * Render one triangle of a shield hit effect on one ship.
 * Each frame, the triangle needs to be rotated into global coords.
 *
 * @param trip		pointer to triangle in global array
 * @param orient	orientation of object shield is associated with
 * @param pos		center point of object
 * @param r			Red colour
 * @param g			Green colour
 * @param b			Blue colour
 */
void render_shield_triangle(gshield_tri *trip, matrix *orient, vec3d *pos, ubyte r, ubyte g, ubyte b)
{
    int		j;
    vec3d	pnt;
    vertex	*verts[3];
    vertex	points[3];

    if (trip->trinum == -1)
        return;	//	Means this is a quad, must have switched detail_level.

    for (j=0; j<3; j++ )	{
        // Rotate point into world coordinates
        vm_vec_unrotate(&pnt, &trip->verts[j].pos, orient);
        vm_vec_add2(&pnt, pos);

        // Pnt is now the x,y,z world coordinates of this vert.
        // For this example, I am just drawing a sphere at that point.

        if (!Cmdline_nohtl) g3_transfer_vertex(&points[j],&pnt);
        else g3_rotate_vertex(&points[j], &pnt);

        points[j].texture_position.u = trip->verts[j].u;
        points[j].texture_position.v = trip->verts[j].v;
        Assert((trip->verts[j].u >= 0.0f) && (trip->verts[j].u <= UV_MAX));
        Assert((trip->verts[j].v >= 0.0f) && (trip->verts[j].v <= UV_MAX));
        verts[j] = &points[j];
    }

    verts[0]->r = r;
    verts[0]->g = g;
    verts[0]->b = b;
    verts[1]->r = r;
    verts[1]->g = g;
    verts[1]->b = b;
    verts[2]->r = r;
    verts[2]->g = g;
    verts[2]->b = b;

    vec3d	norm;
    Poly_count++;
    vm_vec_perp(&norm,&verts[0]->world,&verts[1]->world,&verts[2]->world);

    int flags=TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD;
    if (!Cmdline_nohtl) flags |= TMAP_HTL_3D_UNLIT;

    if ( vm_vec_dot(&norm,&verts[1]->world ) >= 0.0 )	{
        vertex	*vertlist[3];
        vertlist[0] = verts[2];
        vertlist[1] = verts[1];
        vertlist[2] = verts[0];
        g3_draw_poly( 3, vertlist, flags);
    } else {
        g3_draw_poly( 3, verts, flags);
    }
}
//from a 2d point, compute the vector through that point.
// This can be called outside of a g3_start_frame/g3_end_frame
// pair as long g3_start_frame was previously called.
void g3_point_to_vec_delayed(vector *v,int sx,int sy)
{
	vector	tempv;

	tempv.xyz.x =  ((float)sx - Canv_w2) / Canv_w2;
	tempv.xyz.y = -((float)sy - Canv_h2) / Canv_h2;
	tempv.xyz.z = 1.0f;

	tempv.xyz.x = tempv.xyz.x * Matrix_scale.xyz.z / Matrix_scale.xyz.x;
	tempv.xyz.y = tempv.xyz.y * Matrix_scale.xyz.z / Matrix_scale.xyz.y;

	vm_vec_normalize(&tempv);
	vm_vec_unrotate(v, &tempv, &Unscaled_matrix);
}
Exemple #7
0
void render_low_detail_shield_bitmap(gshield_tri *trip, matrix *orient, vec3d *pos, ubyte r, ubyte g, ubyte b)
{
    int		j;
    vec3d	pnt;
    vertex	verts[4];

    for (j=0; j<4; j++ )	{
        // Rotate point into world coordinates
        vm_vec_unrotate(&pnt, &trip->verts[j].pos, orient);
        vm_vec_add2(&pnt, pos);

        // Pnt is now the x,y,z world coordinates of this vert.
        if(!Cmdline_nohtl) g3_transfer_vertex(&verts[j], &pnt);
        else g3_rotate_vertex(&verts[j], &pnt);
        verts[j].texture_position.u = trip->verts[j].u;
        verts[j].texture_position.v = trip->verts[j].v;
    }

    verts[0].r = r;
    verts[0].g = g;
    verts[0].b = b;
    verts[1].r = r;
    verts[1].g = g;
    verts[1].b = b;
    verts[2].r = r;
    verts[2].g = g;
    verts[2].b = b;
    verts[3].r = r;
    verts[3].g = g;
    verts[3].b = b;

    vec3d	norm;
    vm_vec_perp(&norm, &trip->verts[0].pos, &trip->verts[1].pos, &trip->verts[2].pos);
    vertex	*vertlist[4];
    if ( vm_vec_dot(&norm, &trip->verts[1].pos ) < 0.0 )	{
        vertlist[0] = &verts[3];
        vertlist[1] = &verts[2];
        vertlist[2] = &verts[1];
        vertlist[3] = &verts[0];
        g3_draw_poly( 4, vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_HTL_3D_UNLIT);
    } else {
        vertlist[0] = &verts[0];
        vertlist[1] = &verts[1];
        vertlist[2] = &verts[2];
        vertlist[3] = &verts[3];
        g3_draw_poly( 4, vertlist, TMAP_FLAG_TEXTURED | TMAP_FLAG_RGB | TMAP_FLAG_GOURAUD | TMAP_HTL_3D_UNLIT);
    }
}
Exemple #8
0
int HudGaugeRadarOrb::calcAlpha(vec3d* pt)
{
    Assert(pt);
    Assert(Player_obj);

    vec3d new_pt;
    vec3d fvec = { { { 0.0f, 0.0f, 1.0f } } };

    vm_vec_unrotate(&new_pt, pt, &Player_obj->orient);
    vm_vec_normalize(&new_pt);

    float dot = vm_vec_dot(&fvec, &new_pt);
    float angle = fabs(acosf(dot));
    int alpha = int(angle*192.0f/PI);

    return alpha;
}
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(&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;
	}
}
// 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;
}
// Adds velocity to position
// finds velocity and displacement in local coords
void physics_sim_vel(vec3d * position, physics_info * pi, float sim_time, matrix *orient)
{
	vec3d local_disp;		// displacement in this frame
	vec3d local_v_in;		// velocity in local coords at the start of this frame
	vec3d local_desired_vel;	// desired velocity in local coords
	vec3d local_v_out;		// velocity in local coords following this frame
	vec3d damp;

	//	Maybe clear the reduced_damp flag.
	//	This fixes the problem of the player getting near-instantaneous acceleration under unknown circumstances.
	//	The larger problem is probably that PF_USE_VEL is getting stuck set.
	if ((pi->flags & PF_REDUCED_DAMP) && (timestamp_elapsed(pi->reduced_damp_decay))) {
		pi->flags &= ~PF_REDUCED_DAMP;
	}

	// Set up damping constants based on special conditions
	// ie. shockwave, collision, weapon, dead
	if (pi->flags & PF_DEAD_DAMP) {
		// side_slip_time_const is already quite large and now needs to be applied in all directions
		vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, pi->side_slip_time_const );

	} else if (pi->flags & PF_REDUCED_DAMP) {
		// case of shock, weapon, collide, etc.
		if ( timestamp_elapsed(pi->reduced_damp_decay) ) {
			vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, 0.0f );
		} else {
			// damp is multiplied by fraction and not fraction^2, gives better collision separation
			float reduced_damp_fraction_time_left = timestamp_until( pi->reduced_damp_decay ) / (float) REDUCED_DAMP_TIME;
			damp.xyz.x = pi->side_slip_time_const * ( 1 + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left );
			damp.xyz.y = pi->side_slip_time_const * ( 1 + (REDUCED_DAMP_FACTOR-1) * reduced_damp_fraction_time_left );
			damp.xyz.z = pi->side_slip_time_const * reduced_damp_fraction_time_left * REDUCED_DAMP_FACTOR;
		}
	} else {
		// regular damping
		if (pi->use_newtonian_damp) {
			vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, pi->side_slip_time_const );
		} else {
			vm_vec_make( &damp, pi->side_slip_time_const, pi->side_slip_time_const, 0.0f );
		}
	}

	// Note: CANNOT maintain a *local velocity* since a rotation can occur in this frame.
	// thus the local velocity of in the next frame can be different (this would require rotate to change local vel
	// and this is not desired

	// get local components of current velocity
	vm_vec_rotate (&local_v_in, &pi->vel, orient);

	// get local components of desired velocity
	vm_vec_rotate (&local_desired_vel, &pi->desired_vel, orient);

	// find updated LOCAL velocity and position in the local x direction
	apply_physics (damp.xyz.x, local_desired_vel.xyz.x, local_v_in.xyz.x, sim_time, &local_v_out.xyz.x, &local_disp.xyz.x);

	// find updated LOCAL velocity and position in the local y direction
	apply_physics (damp.xyz.y, local_desired_vel.xyz.y, local_v_in.xyz.y, sim_time, &local_v_out.xyz.y, &local_disp.xyz.y);

	// find updated LOCAL velocity and position in the local z direction
	// for player ship, damp should normally be zero, but may be altered in a shockwave
	//  in death, shockwave,etc. we want damping time const large for all 3 axes
	// warp in test - make excessive speed drop exponentially from max allowed
	// become (0.01x in 3 sec)

	int special_warp_in = FALSE;
	float excess = local_v_in.xyz.z - pi->max_vel.xyz.z;
	if (excess > 5 && (pi->flags & PF_SPECIAL_WARP_IN)) {
		special_warp_in = TRUE;
		float exp_factor = float(exp(-sim_time / SPECIAL_WARP_T_CONST));
		local_v_out.xyz.z = pi->max_vel.xyz.z + excess * exp_factor;
		local_disp.xyz.z = (pi->max_vel.xyz.z * sim_time) + excess * (float(SPECIAL_WARP_T_CONST) * (1.0f - exp_factor));
	} else if (pi->flags & PF_SPECIAL_WARP_OUT) {
		float exp_factor = float(exp(-sim_time / SPECIAL_WARP_T_CONST));
		vec3d temp;
		vm_vec_rotate(&temp, &pi->prev_ramp_vel, orient);
		float deficeit = temp.xyz.z - local_v_in.xyz.z;
		local_v_out.xyz.z = local_v_in.xyz.z + deficeit * (1.0f - exp_factor);
		local_disp.xyz.z = (local_v_in.xyz.z * sim_time) + deficeit * (sim_time - (float(SPECIAL_WARP_T_CONST) * (1.0f - exp_factor)));
	} else {
		apply_physics (damp.xyz.z, local_desired_vel.xyz.z, local_v_in.xyz.z, sim_time, &local_v_out.xyz.z, &local_disp.xyz.z);
	}

	// maybe turn off special warp in flag
	if ((pi->flags & PF_SPECIAL_WARP_IN) && (excess < 5)) {
		pi->flags &= ~(PF_SPECIAL_WARP_IN);
	}

	// update world position from local to world coords using orient
	vec3d world_disp;
	vm_vec_unrotate (&world_disp, &local_disp, orient);
	vm_vec_add2 (position, &world_disp);

	// update world velocity
	vm_vec_unrotate(&pi->vel, &local_v_out, orient);

	if (special_warp_in) {
		vm_vec_rotate(&pi->prev_ramp_vel, &pi->vel, orient);
	}
}
/**
 * Do various updates to debris:  check if time to die, start fireballs
 * Maybe delete debris if it's very far away from player.
 *
 * @param obj			pointer to debris object
 * @param frame_time	time elapsed since last debris_move() called
 */
void debris_process_post(object * obj, float frame_time)
{
	int i, num;
	num = obj->instance;

	int objnum = OBJ_INDEX(obj);
	Assert( Debris[num].objnum == objnum );
	debris *db = &Debris[num];

	if ( db->is_hull ) {
		MONITOR_INC(NumHullDebris,1);
		radar_plot_object( obj );

		if ( timestamp_elapsed(db->sound_delay) ) {
			obj_snd_assign(objnum, SND_DEBRIS, &vmd_zero_vector, 0);
			db->sound_delay = 0;
		}
	} else {
		MONITOR_INC(NumSmallDebris,1);
	}

	if ( db->lifeleft >= 0.0f) {
		db->lifeleft -= frame_time;
		if ( db->lifeleft < 0.0f )	{
			debris_start_death_roll(obj, db);
		}
	}

	maybe_delete_debris(db);	//	Make this debris go away if it's very far away.

	// ================== DO THE ELECTRIC ARCING STUFF =====================
	if ( db->arc_frequency <= 0 )	{
		return;			// If arc_frequency <= 0, this piece has no arcs on it
	}

	if ( !timestamp_elapsed(db->fire_timeout) && timestamp_elapsed(db->next_fireball))	{		

		db->next_fireball = timestamp_rand(db->arc_frequency,db->arc_frequency*2 );
		db->arc_frequency += 100;	

		if (db->is_hull)	{

			int n, n_arcs = ((rand()>>5) % 3)+1;		// Create 1-3 sparks

			vec3d v1, v2, v3, v4;

			if ( Cmdline_old_collision_sys ) {
				submodel_get_two_random_points( db->model_num, db->submodel_num, &v1, &v2 );
				submodel_get_two_random_points( db->model_num, db->submodel_num, &v3, &v4 );
			} else {
				submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v1, &v2 );
				submodel_get_two_random_points_better( db->model_num, db->submodel_num, &v3, &v4 );
			}

			n = 0;

			int a = 100, b = 1000;
			int lifetime = (myrand()%((b)-(a)+1))+(a);

			// Create the spark effects
			for (i=0; i<MAX_DEBRIS_ARCS; i++ )	{
				if ( !timestamp_valid( db->arc_timestamp[i] ) )	{

					db->arc_timestamp[i] = timestamp(lifetime);	// live up to a second

					switch( n )	{
					case 0:
						db->arc_pts[i][0] = v1;
						db->arc_pts[i][1] = v2;
						break;
					case 1:
						db->arc_pts[i][0] = v2;
						db->arc_pts[i][1] = v3;
						break;

					case 2:
						db->arc_pts[i][0] = v2;
						db->arc_pts[i][1] = v4;
						break;

					default:
						Int3();
					}
						
					n++;
					if ( n == n_arcs )
						break;	// Don't need to create anymore
				}
			}

	
			// rotate v2 out of local coordinates into world.
			// Use v2 since it is used in every bolt.  See above switch().
			vec3d snd_pos;
			vm_vec_unrotate(&snd_pos, &v2, &obj->orient);
			vm_vec_add2(&snd_pos, &obj->pos );

			//Play a sound effect
			if ( lifetime > 750 )	{
				// 1.00 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_05), &snd_pos, &View_position, obj->radius );
			} else if ( lifetime >  500 )	{
				// 0.75 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_04), &snd_pos, &View_position, obj->radius );
			} else if ( lifetime >  250 )	{
				// 0.50 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_03), &snd_pos, &View_position, obj->radius );
			} else if ( lifetime >  100 )	{
				// 0.25 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_02), &snd_pos, &View_position, obj->radius );
			} else {
				// 0.10 second effect
				snd_play_3d( gamesnd_get_game_sound(SND_DEBRIS_ARC_01), &snd_pos, &View_position, obj->radius );
			}
		}
Exemple #13
0
void batching_add_polygon_internal(primitive_batch *batch, int texture, vec3d *pos, matrix *orient, float width, float height, color *clr)
{
    Assert(batch->get_render_info().prim_type == PRIM_TYPE_TRIS);

    //idiot-proof
    if(width == 0 || height == 0)
        return;

    Assert(pos != NULL);
    Assert(orient != NULL);

    //Let's begin.

    const int NUM_VERTICES = 4;
    vec3d p[NUM_VERTICES] = { ZERO_VECTOR };
    batch_vertex v[NUM_VERTICES];

    p[0].xyz.x = width;
    p[0].xyz.y = height;

    p[1].xyz.x = -width;
    p[1].xyz.y = height;

    p[2].xyz.x = -width;
    p[2].xyz.y = -height;

    p[3].xyz.x = width;
    p[3].xyz.y = -height;

    for(int i = 0; i < NUM_VERTICES; i++)
    {
        vec3d tmp = vmd_zero_vector;

        //Rotate correctly
        vm_vec_unrotate(&tmp, &p[i], orient);
        //Move to point in space
        vm_vec_add2(&tmp, pos);

        v[i].position = tmp;

        v[i].r = clr->red;
        v[i].g = clr->green;
        v[i].b = clr->blue;
        v[i].a = clr->alpha;
    }

    v[0].tex_coord.u = 1.0f;
    v[0].tex_coord.v = 0.0f;

    v[1].tex_coord.u = 0.0f;
    v[1].tex_coord.v = 0.0f;

    v[2].tex_coord.u = 0.0f;
    v[2].tex_coord.v = 1.0f;

    v[3].tex_coord.u = 1.0f;
    v[3].tex_coord.v = 1.0f;

    batch->add_triangle(&v[0], &v[1], &v[2]);
    batch->add_triangle(&v[0], &v[2], &v[3]);
}
/**
 * nstance 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(const vec3d *pos, const matrix *orient, bool set_api)
{
	vec3d 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_vec_unrotate(&tempv,pos,&Object_matrix);
		vm_vec_add2(&Object_position, &tempv);
	} else {
		// No movement, leave View_position alone
	}

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

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

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

	// Update the lighting matrix
	matrix saved_orient = Light_matrix;
	vec3d 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);

}
// hud_do_lock_indicator() manages missle locking, both the non-rendering calculations and the 2D HUD rendering
void hud_do_lock_indicator(float frametime)
{
	ship_weapon *swp;
	weapon_info	*wip;

	// if i'm a multiplayer observer, bail here
	if((Game_mode & GM_MULTIPLAYER) && ((Net_player->flags & NETINFO_FLAG_OBSERVER) || (Player_obj->type == OBJ_OBSERVER)) ){
		return;
	}

	Assert(Player_ai->target_objnum >= 0);

	// be sure to unset this flag, then possibly set later in this function so that
	// threat indicators work properly.
	Player_ai->ai_flags.remove(AI::AI_Flags::Seek_lock);

	if ( hud_abort_lock() ) {
		hud_lock_reset();
		return;
	}

	// if there is an EMP effect active, never update lock
	if(emp_active_local()){
		hud_lock_reset();
		return;
	}

	swp = &Player_ship->weapons;
	wip = &Weapon_info[swp->secondary_bank_weapons[swp->current_secondary_bank]];

	Lock_start_dist = wip->min_lock_time * wip->lock_pixels_per_sec;

	// if secondary weapons change, reset the lock
	if ( hud_lock_secondary_weapon_changed(swp) ) {
		hud_lock_reset();
	}
		
	Player_ai->last_secondary_index = swp->current_secondary_bank;

	object *tobjp = &Objects[Player_ai->target_objnum];
	vec3d dir_to_target;
	vm_vec_normalized_dir(&dir_to_target, &tobjp->pos, &Player_obj->pos);

	if ( !(wip->is_locked_homing()) ) {
		hud_lock_reset();
		return;		
	}

	// Allow locking on ships and bombs (only targeted weapon allowed is a bomb, so don't bother checking flags)
	if ( (Objects[Player_ai->target_objnum].type != OBJ_SHIP) && (Objects[Player_ai->target_objnum].type != OBJ_WEAPON) ) {	
		hud_lock_reset();
		return;
	}

	// Javelins must lock on engines if locking on a ship and those must be in sight
	if (wip->wi_flags[Weapon::Info_Flags::Homing_javelin] && 
		tobjp->type == OBJ_SHIP &&
		Player->locking_subsys != NULL) {
			vec3d subobj_pos;
			vm_vec_unrotate(&subobj_pos, &Player->locking_subsys->system_info->pnt, &tobjp->orient);
			vm_vec_add2(&subobj_pos, &tobjp->pos);
			int target_subsys_in_sight = ship_subsystem_in_sight(tobjp, Player->locking_subsys, &Player_obj->pos, &subobj_pos);

			if (!target_subsys_in_sight || Player->locking_subsys->system_info->type != SUBSYSTEM_ENGINE) {
				Player->locking_subsys =
					ship_get_closest_subsys_in_sight(&Ships[tobjp->instance], SUBSYSTEM_ENGINE, &Player_obj->pos);
			}
	}

	if (wip->wi_flags[Weapon::Info_Flags::Homing_javelin] && 
		tobjp->type == OBJ_SHIP &&
		Player->locking_subsys == NULL) {
			Player->locking_subsys =
				ship_get_closest_subsys_in_sight(&Ships[tobjp->instance], SUBSYSTEM_ENGINE, &Player_obj->pos);

			if (Player->locking_subsys == NULL) {
				hud_lock_reset();
				return;
			}
	}

	hud_lock_determine_lock_point(&lock_world_pos);

	if ( !hud_lock_has_homing_point() ) {
		Player->target_in_lock_cone=0;
	}

	hud_lock_check_if_target_in_lock_cone();

	// check if the target is within range of the current secondary weapon.  If it is not,
	// a lock will not be detected
	if ( !hud_lock_target_in_range() ) {
		Player->target_in_lock_cone = 0;
	}

	// If locking on a subsystem, and not in sight... can't lock
	//	Changed by MK on 4/3/98.  It was confusing me that my hornets would not lock on my target.
	//	It will now be confusing that they lock, but don't home on your subsystem, but I think that's preferable.
	//	Often you really care about destroying the target, not just the subsystem.
	/*if ( Player_ai->targeted_subsys ) {
		if ( !hud_lock_on_subsys_ok() ) {
			Player->target_in_lock_cone=0;
		}
	}*/

	if ( !Player->target_in_lock_cone ) {
		Player->locking_on_center=0;
		Player->locking_subsys_parent=-1;
		Player->locking_subsys=NULL;
	}
		
	hud_calculate_lock_position(frametime);

	if (!Players[Player_num].lock_indicator_visible)
		return;

	if (Player_ai->current_target_is_locked) {
		if ( Missile_track_loop > -1 )	{
			snd_stop(Missile_track_loop);
			Missile_track_loop = -1;

			if (wip->hud_locked_snd >= 0)
			{
				Missile_lock_loop = snd_play(&Snds[wip->hud_locked_snd]);
			}
			else
			{
				Missile_lock_loop = snd_play(&Snds[ship_get_sound(Player_obj, SND_MISSILE_LOCK)]);
			}
		}
	}
	else {
		Player_ai->ai_flags.set(AI::AI_Flags::Seek_lock);		// set this flag so multiplayer's properly track lock on other ships
		if ( Missile_lock_loop != -1 && snd_is_playing(Missile_lock_loop) ) {
			snd_stop(Missile_lock_loop);
			Missile_lock_loop = -1;
		}
	}
}
// See model.h for usage.   I don't want to put the
// usage here because you need to see the #defines and structures
// this uses while reading the help.   
int model_collide(mc_info *mc_info_obj)
{
	Mc = mc_info_obj;

	MONITOR_INC(NumFVI,1);

	Mc->num_hits = 0;				// How many collisions were found
	Mc->shield_hit_tri = -1;	// Assume we won't hit any shield polygons
	Mc->hit_bitmap = -1;
	Mc->edge_hit = 0;

	if ( (Mc->flags & MC_CHECK_SHIELD) && (Mc->flags & MC_CHECK_MODEL) )	{
		Error( LOCATION, "Checking both shield and model!\n" );
		return 0;
	}

	//Fill in some global variables that all the model collide routines need internally.
	Mc_pm = model_get(Mc->model_num);
	Mc_orient = *Mc->orient;
	Mc_base = *Mc->pos;
	Mc_mag = vm_vec_dist( Mc->p0, Mc->p1 );
	Mc_edge_time = FLT_MAX;

	if ( Mc->model_instance_num >= 0 ) {
		Mc_pmi = model_get_instance(Mc->model_instance_num);
	} else {
		Mc_pmi = NULL;
	}

	// DA 11/19/98 - disable this check for rotating submodels
	// Don't do check if for very small movement
//	if (Mc_mag < 0.01f) {
//		return 0;
//	}

	float model_radius;		// How big is the model we're checking against
	int first_submodel;		// Which submodel gets returned as hit if MC_ONLY_SPHERE specified

	if ( (Mc->flags & MC_SUBMODEL) || (Mc->flags & MC_SUBMODEL_INSTANCE) )	{
		first_submodel = Mc->submodel_num;
		model_radius = Mc_pm->submodel[first_submodel].rad;
	} else {
		first_submodel = Mc_pm->detail[0];
		model_radius = Mc_pm->rad;
	}

	if ( Mc->flags & MC_CHECK_SPHERELINE ) {
		if ( Mc->radius <= 0.0f ) {
			Warning(LOCATION, "Attempting to collide with a sphere, but the sphere's radius is <= 0.0f!\n\n(model file is %s; submodel is %d, mc_flags are %d)", Mc_pm->filename, first_submodel, Mc->flags);
			return 0;
		}

		// Do a quick check on the Bounding Sphere
		if (fvi_segment_sphere(&Mc->hit_point_world, Mc->p0, Mc->p1, Mc->pos, model_radius+Mc->radius) )	{
			if ( Mc->flags & MC_ONLY_SPHERE )	{
				Mc->hit_point = Mc->hit_point_world;
				Mc->hit_submodel = first_submodel;
				Mc->num_hits++;
				return (Mc->num_hits > 0);
			}
			// continue checking polygons.
		} else {
			return 0;
		}
	} else {
		int r;

		// Do a quick check on the Bounding Sphere
		if ( Mc->flags & MC_CHECK_RAY ) {
			r = fvi_ray_sphere(&Mc->hit_point_world, Mc->p0, Mc->p1, Mc->pos, model_radius);
		} else {
			r = fvi_segment_sphere(&Mc->hit_point_world, Mc->p0, Mc->p1, Mc->pos, model_radius);
		}
		if (r) {
			if ( Mc->flags & MC_ONLY_SPHERE ) {
				Mc->hit_point = Mc->hit_point_world;
				Mc->hit_submodel = first_submodel;
				Mc->num_hits++;
				return (Mc->num_hits > 0);
			}
			// continue checking polygons.
		} else {
			return 0;
		}

	}

	if ( Mc->flags & MC_SUBMODEL )	{
		// Check only one subobject
		mc_check_subobj( Mc->submodel_num );
		// Check submodel and any children
	} else if (Mc->flags & MC_SUBMODEL_INSTANCE) {
		mc_check_subobj(Mc->submodel_num);
	} else {
		// Check all the the highest detail model polygons and subobjects for intersections

		// Don't check it or its children if it is destroyed
		if (!Mc_pm->submodel[Mc_pm->detail[0]].blown_off)	{	
			mc_check_subobj( Mc_pm->detail[0] );
		}
	}


	//If we found a hit, then rotate it into world coordinates	
	if ( Mc->num_hits )	{
		if ( Mc->flags & MC_SUBMODEL )	{
			// If we're just checking one submodel, don't use normal instancing to find world points
			vm_vec_unrotate(&Mc->hit_point_world, &Mc->hit_point, Mc->orient);
			vm_vec_add2(&Mc->hit_point_world, Mc->pos);
		} else {
			if ( Mc_pmi ) {
				model_instance_find_world_point(&Mc->hit_point_world, &Mc->hit_point, Mc->model_instance_num, Mc->hit_submodel, Mc->orient, Mc->pos);
			} else {
				model_find_world_point(&Mc->hit_point_world, &Mc->hit_point, Mc->model_num, Mc->hit_submodel, Mc->orient, Mc->pos);
			}
		}
	}


	return Mc->num_hits;

}
// 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);

	// bail early if no ray exists
	if ( IS_VEC_NULL(&Mc_direction) ) {
		return;
	}

	if (Mc_pm->detail[0] == mn)	{
		// Quickly bail if we aren't inside the full model bbox
		if (!mc_ray_boundingbox( &Mc_pm->mins, &Mc_pm->maxs, &Mc_p0, &Mc_direction, NULL))	{
			return;
		}

		// If we are checking the root submodel, then we might want to check	
		// the shield at this point
		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) ) {
		if (Mc->flags & MC_ONLY_BOUND_BOX) {
			float dist = vm_vec_dist( &Mc_p0, &hitpt );

			// If the ray is behind the plane there is no collision
			if (dist < 0.0f) {
				goto NoHit;
			}

			// The ray isn't long enough to intersect the plane
			if ( !(Mc->flags & MC_CHECK_RAY) && (dist > Mc_mag) ) {
				goto NoHit;
			}

			// 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 {
			// The ray intersects this bounding box, so we have to check all the
			// polygons in this submodel.
			if ( Cmdline_old_collision_sys ) {
				model_collide_sub(sm->bsp_data);
			} else {
				if (Mc->lod > 0 && sm->num_details > 0) {
					bsp_info *lod_sm = sm;

					for (i = Mc->lod - 1; i >= 0; i--) {
						if (sm->details[i] != -1) {
							lod_sm = &Mc_pm->submodel[sm->details[i]];

							//mprintf(("Checking %s collision for %s using %s instead\n", Mc_pm->filename, sm->name, lod_sm->name));
							break;
						}
					}

					model_collide_bsp(model_get_bsp_collision_tree(lod_sm->collision_tree_index), 0);
				} 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(&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;
	}

}
Exemple #18
0
void ship_draw_shield( object *objp)
{
    int		model_num;
    int		i;
    vec3d	pnt;
    polymodel * pm;

    if (objp->flags & OF_NO_SHIELDS)
        return;

    Assert(objp->instance >= 0);

    model_num = Ship_info[Ships[objp->instance].ship_info_index].model_num;

    if ( Fred_running ) return;

    pm = model_get(model_num);

    if (pm->shield.ntris<1) return;

    //	Scan all the triangles in the mesh.
    for (i=0; i<pm->shield.ntris; i++ )	{
        int		j;
        vec3d	gnorm, v2f, tri_point;
        vertex prev_pnt, pnt0;
        shield_tri *tri;

        tri = &pm->shield.tris[i];

        if (i == Break_value)
            Int3();

        //	Hack! Only works for object in identity orientation.
        //	Need to rotate eye position into object's reference frame.
        //	Only draw facing triangles.
        vm_vec_rotate(&tri_point, &pm->shield.verts[tri->verts[0]].pos, &Eye_matrix);
        vm_vec_add2(&tri_point, &objp->pos);

        vm_vec_sub(&v2f, &tri_point, &Eye_position);
        vm_vec_unrotate(&gnorm, &tri->norm, &objp->orient);

        if (vm_vec_dot(&gnorm, &v2f) < 0.0f) {
            int	intensity;

            intensity = (int) (Ships[objp->instance].shield_integrity[i] * 255);

            if (intensity < 0)
                intensity = 0;
            else if (intensity > 255)
                intensity = 255;

            gr_set_color(0, 0, intensity);

            //	Process the vertices.
            //	Note this rotates each vertex each time it's needed, very dumb.
            for (j=0; j<3; j++ )	{
                vertex tmp;

                // Rotate point into world coordinates
                vm_vec_unrotate(&pnt, &pm->shield.verts[tri->verts[j]].pos, &objp->orient);
                vm_vec_add2(&pnt, &objp->pos);

                // Pnt is now the x,y,z world coordinates of this vert.
                // For this example, I am just drawing a sphere at that
                // point.
                g3_rotate_vertex(&tmp, &pnt);

                if (j)
                    g3_draw_line(&prev_pnt, &tmp);
                else
                    pnt0 = tmp;
                prev_pnt = tmp;
            }

            g3_draw_line(&pnt0, &prev_pnt);
        }
    }
}
int batch_add_polygon(int texture, int tmap_flags, vec3d *pos, matrix *orient, float width, float height, float alpha)
{
	//idiot-proof
	if(width == 0 || height == 0)
		return 0;

	Assert(pos != NULL);
	Assert(orient != NULL);

	//Let's begin.

	const int NUM_VERTICES = 4;
	vec3d p[NUM_VERTICES] = { ZERO_VECTOR };
	vertex v[NUM_VERTICES] = { vertex() };

	p[0].xyz.x = width;
	p[0].xyz.y = height;

	p[1].xyz.x = -width;
	p[1].xyz.y = height;

	p[2].xyz.x = -width;
	p[2].xyz.y = -height;

	p[3].xyz.x = width;
	p[3].xyz.y = -height;

	for(int i = 0; i < NUM_VERTICES; i++)
	{
		vec3d tmp = vmd_zero_vector;

		//Rotate correctly
		vm_vec_unrotate(&tmp, &p[i], orient);
		//Move to point in space
		vm_vec_add2(&tmp, pos);

		//Convert to vertex
		g3_transfer_vertex(&v[i], &tmp);
	}

	v[0].texture_position.u = 1.0f;
	v[0].texture_position.v = 0.0f;

	v[1].texture_position.u = 0.0f;
	v[1].texture_position.v = 0.0f;

	v[2].texture_position.u = 0.0f;
	v[2].texture_position.v = 1.0f;

	v[3].texture_position.u = 1.0f;
	v[3].texture_position.v = 1.0f;

	if (texture < 0) {
		Int3();
		return 1;
	}

	batch_item *item = NULL;

	SCP_map<int, batch_item>::iterator it = geometry_map.find(texture);

	if ( !geometry_map.empty() && it != geometry_map.end() ) {
		item = &it->second;
	} else {
		item = &geometry_map[texture];
		item->texture = texture;
	}

	Assertion( (item->laser == false), "Particle effect %s used as laser glow or laser bitmap\n", bm_get_filename(texture) );

	item->tmap_flags = tmap_flags;
	item->alpha = alpha;

	item->batch.add_allocate(1);

	item->batch.draw_quad(v);

	return 0;
}
void particle_render_all()
{
	ubyte flags;
	float pct_complete;
	float alpha;
	vertex pos;
	vec3d ts, te, temp;
	int rotate = 1;
	int framenum, cur_frame;
	bool render_batch = false;
	int tmap_flags = TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_SOFT_QUAD;

	if ( !Particles_enabled )
		return;

	MONITOR_INC( NumParticlesRend, Num_particles );	

	if ( Particles.empty() )
		return;

	for (SCP_vector<particle*>::iterator p = Particles.begin(); p != Particles.end(); ++p) {
		particle* part = *p;
		// skip back-facing particles (ripped from fullneb code)
		// Wanderer - add support for attached particles
		vec3d p_pos;
		if (part->attached_objnum >= 0) {
			vm_vec_unrotate(&p_pos, &part->pos, &Objects[part->attached_objnum].orient);
			vm_vec_add2(&p_pos, &Objects[part->attached_objnum].pos);
		} else {
			p_pos = part->pos;
		}

		if ( vm_vec_dot_to_point(&Eye_matrix.vec.fvec, &Eye_position, &p_pos) <= 0.0f ) {
			continue;
		}

		// calculate the alpha to draw at
		alpha = get_current_alpha(&p_pos);

		// if it's transparent then just skip it
		if (alpha <= 0.0f) {
			continue;
		}

		// make sure "rotate" is enabled for this particle
		rotate = 1;

		// if this is a tracer style particle, calculate tracer vectors
		if (part->tracer_length > 0.0f) {			
			ts = p_pos;
			temp = part->velocity;
			vm_vec_normalize_quick(&temp);
			vm_vec_scale_add(&te, &ts, &temp, part->tracer_length);

			// don't bother rotating
			rotate = 0;
		}

		// rotate the vertex
		if (rotate) {
			flags = g3_rotate_vertex( &pos, &p_pos );

			if ( flags ) {
				continue;
			}

			if (!Cmdline_nohtl)
				g3_transfer_vertex(&pos, &p_pos);
		}

		// pct complete for the particle
		pct_complete = part->age / part->max_life;

		// figure out which frame we should be using
		if (part->nframes > 1) {
			framenum = fl2i(pct_complete * part->nframes + 0.5);
			CLAMP(framenum, 0, part->nframes-1);

			cur_frame = part->reverse ? (part->nframes - framenum - 1) : framenum;
		} else {
			cur_frame = 0;
		}

		if (part->type == PARTICLE_DEBUG) {
			gr_set_color( 255, 0, 0 );
			g3_draw_sphere_ez( &p_pos, part->radius );
		} else {
			framenum = part->optional_data;

			Assert( cur_frame < part->nframes );

			// if this is a tracer style particle
			if (part->tracer_length > 0.0f) {
				batch_add_laser( framenum + cur_frame, &ts, part->radius, &te, part->radius );
			}
			// draw as a regular bitmap
			else {
				batch_add_bitmap( framenum + cur_frame, tmap_flags, &pos, part->particle_index % 8, part->radius, alpha );
			}

			render_batch = true;
		}
	}

	profile_begin("Batch Render");
	if (render_batch) {
		batch_render_all(Particle_buffer_object);
	}
	profile_end("Batch Render");
}
// apply the EMP effect to all relevant ships
void emp_apply(vec3d *pos, float inner_radius, float outer_radius, float emp_intensity, float emp_time, bool use_emp_time_for_capship_turrets)
{	
	float actual_intensity, actual_time;
	vec3d dist;
	float dist_mag;
	float scale_factor;
	object *target;
	ship_obj *so;
	missile_obj *mo;
	ship_subsys *moveup;
	weapon_info *wip_target;

	// all machines check to see if the blast hit a bomb. if so, shut it down (can't move anymore)	
	for( mo = GET_FIRST(&Missile_obj_list); mo != END_OF_LIST(&Missile_obj_list); mo = GET_NEXT(mo) ) {
		target = &Objects[mo->objnum];
		if(target->type != OBJ_WEAPON){
			continue;
		}

		Assert(target->instance >= 0);
		if(target->instance < 0){
			continue;
		}
		Assert(Weapons[target->instance].weapon_info_index >= 0);
		if(Weapons[target->instance].weapon_info_index < 0){
			continue;
		}
		
		// if we have a bomb weapon
		wip_target = &Weapon_info[Weapons[target->instance].weapon_info_index];
		if((wip_target->weapon_hitpoints > 0) && !(wip_target->wi_flags2 & WIF2_NO_EMP_KILL)) {
			// get the distance between the detonation and the target object
			vm_vec_sub(&dist, &target->pos, pos);
			dist_mag = vm_vec_mag(&dist);

			// if the bomb was within 1/4 of the outer radius, castrate it
			if(dist_mag <= (outer_radius * 0.25f)){
				// memset(&target->phys_info, 0, sizeof(physics_info));
				Weapons[target->instance].weapon_flags |= WF_DEAD_IN_WATER;
				mprintf(("EMP killing weapon\n"));
			}
		}	
	}

	// if I'm only a client in a multiplayer game, do nothing
	if(MULTIPLAYER_CLIENT){
		return;
	}

	// See if there are any friendly ships present, if so return without preventing msg
	for ( so = GET_FIRST(&Ship_obj_list); so != END_OF_LIST(&Ship_obj_list); so = GET_NEXT(so) ) {		
		target = &Objects[so->objnum];
		if(target->type != OBJ_SHIP){
			continue;
		}	
		
		Assert(Objects[so->objnum].instance >= 0);
		if(Objects[so->objnum].instance < 0){
			continue;
		}
		Assert(Ships[Objects[so->objnum].instance].ship_info_index >= 0);
		if(Ships[Objects[so->objnum].instance].ship_info_index < 0){
			continue;
		}

		// if the ship is a cruiser or cap ship, only apply the EMP effect to turrets
		if(Ship_info[Ships[target->instance].ship_info_index].flags & (SIF_BIG_SHIP | SIF_HUGE_SHIP)) {
			float capship_emp_time = use_emp_time_for_capship_turrets ? emp_time : MAX_TURRET_DISRUPT_TIME;
			
			moveup = &Ships[target->instance].subsys_list;
			if(moveup->next != NULL){
				moveup = moveup->next;
			}
			while(moveup != &Ships[target->instance].subsys_list){
				// if this is a turret, disrupt it
				if((moveup->system_info != NULL) && (moveup->system_info->type == SUBSYSTEM_TURRET)){
					vec3d actual_pos;					
					
					// get the distance to the subsys					
					vm_vec_unrotate(&actual_pos, &moveup->system_info->pnt, &target->orient);
					vm_vec_add2(&actual_pos, &target->pos);					
					vm_vec_sub(&dist, &actual_pos, pos);
					dist_mag = vm_vec_mag(&dist);
			
					// if for some reason, the object was outside the blast, radius
					if(dist_mag > outer_radius){			
						// next item
						moveup = moveup->next;
						continue;
					}

					// compute a scale factor for the emp effect
					scale_factor = 1.0f;
					if(dist_mag >= inner_radius){
						scale_factor = 1.0f - (dist_mag / outer_radius);
					} 

					scale_factor -= Ship_info[Ships[target->instance].ship_info_index].emp_resistance_mod;

					if (scale_factor < 0.0f) {
						moveup = moveup->next;
						continue;
					}

					// disrupt the turret
					ship_subsys_set_disrupted(moveup, (int)(capship_emp_time * scale_factor));

					mprintf(("EMP disrupting subsys %s on ship %s (%f, %f)\n", moveup->system_info->subobj_name, Ships[Objects[so->objnum].instance].ship_name, scale_factor, capship_emp_time * scale_factor));
				}
				
				// next item
				moveup = moveup->next;
			}
		}
		// otherwise coat the whole ship with the effect. mmmmmmmmm.
		else {				
			// get the distance between the detonation and the target object
			vm_vec_sub(&dist, &target->pos, pos);
			dist_mag = vm_vec_mag(&dist);

			// if for some reason, the object was outside the blast, radius
			if(dist_mag > outer_radius){			
				continue;
			}

			// compute a scale factor for the emp effect
			scale_factor = 1.0f;
			if(dist_mag >= inner_radius){
				scale_factor = 1.0f - (dist_mag / outer_radius);	
			} 

			scale_factor -= Ship_info[Ships[target->instance].ship_info_index].emp_resistance_mod;

			if (scale_factor < 0.0f) {
				continue;
			}
		
			// calculate actual EMP effect values
			actual_intensity = emp_intensity * scale_factor;
			actual_time = emp_time * scale_factor;			
			mprintf(("EMP effect s : %f, i : %f, t : %f\n", scale_factor, actual_intensity, actual_time));

			// if this effect happened to be on me, start it now
			if((target == Player_obj) && !(Game_mode & GM_STANDALONE_SERVER)){
				emp_start_local(actual_intensity, actual_time);
			} 

			// if this is a multiplayer game, notify other players of the effect
			if(Game_mode & GM_MULTIPLAYER){		
				Assert(MULTIPLAYER_MASTER);				
				send_emp_effect(target->net_signature, actual_intensity, actual_time);
			}
			
			// now be sure to start the emp effect for the ship itself
			emp_start_ship(target, actual_intensity, actual_time);
		}
	}
}
Exemple #22
0
void camera::get_info(vec3d *position, matrix *orientation)
{
	if(position == NULL && orientation == NULL)
		return;
	
	eye* eyep = NULL;
	vec3d host_normal;
	//POSITION
	if(!(flags & CAM_STATIONARY_POS) || object_host.IsValid())
	{
		c_pos = vmd_zero_vector;

		vec3d pt;
		pos_x.get(&pt.xyz.x, NULL);
		pos_y.get(&pt.xyz.y, NULL);
		pos_z.get(&pt.xyz.z, NULL);

		if(object_host.IsValid())
		{
			object *objp = object_host.objp;
			int model_num = object_get_model(objp);
			polymodel *pm = NULL;
			
			if(model_num > -1)
			{
				pm = model_get(model_num);
			}

			if(object_host_submodel < 0 || pm == NULL)
			{
				vm_vec_unrotate(&c_pos, &pt, &object_host.objp->orient);
				vm_vec_add2(&c_pos, &object_host.objp->pos);
			}
			else
			{
				eyep = get_submodel_eye(pm, object_host_submodel);
				if(eyep)
				{
					vec3d c_pos_in;
					find_submodel_instance_point_normal( &c_pos_in, &host_normal, objp, eyep->parent, &eyep->pnt, &eyep->norm);
					vm_vec_unrotate(&c_pos, &c_pos_in, &objp->orient);
					vm_vec_add2(&c_pos, &objp->pos);
				}
				else
				{
					model_find_world_point( &c_pos, &pt, pm->id, object_host_submodel, &objp->orient, &objp->pos );
				}
			}
		}
		else
		{
			c_pos = pt;
		}

		//Do custom position stuff, if needed
		if(func_custom_position != NULL && !eyep)
		{
			func_custom_position(this, &c_pos);
		}
	}

	if(position != NULL)
		*position = c_pos;

	//ORIENTATION
	if(orientation != NULL)
	{
		bool target_set = false;
		if(!(flags & CAM_STATIONARY_ORI) || object_target.IsValid() || object_host.IsValid())
		{
			if(object_target.IsValid())
			{
				object *objp = object_target.objp;
				int model_num = object_get_model(objp);
				polymodel *pm = NULL;
				vec3d target_pos = vmd_zero_vector;
				
				//See if we can get the model
				if(model_num > -1)
				{
					pm = model_get(model_num);
				}

				//If we don't have a submodel or don't have the model use object pos
				//Otherwise, find the submodel pos as it is rotated
				if(object_target_submodel < 0 || pm == NULL)
				{
					target_pos = objp->pos;
				}
				else
				{
					model_find_world_point( &target_pos, &vmd_zero_vector, pm->id, object_target_submodel, &objp->orient, &objp->pos );
				}

				vec3d targetvec;
				vm_vec_normalized_dir(&targetvec, &target_pos, &c_pos);
				vm_vector_2_matrix(&c_ori, &targetvec, NULL, NULL);
				target_set = true;
			}
			else if(object_host.IsValid())
			{
				if(eyep)
				{
					vm_vector_2_matrix(&c_ori, &host_normal, vm_vec_same(&host_normal, &object_host.objp->orient.vec.uvec)?NULL:&object_host.objp->orient.vec.uvec, NULL);
					target_set = true;
				}
				else
				{
					c_ori = object_host.objp->orient;
				}
			}
			else
			{
				c_ori = vmd_identity_matrix;
			}

			matrix mtxA = c_ori;
			matrix mtxB = IDENTITY_MATRIX;
			float pos = 0.0f;
			for(int i = 0; i < 9; i++)
			{
				ori[i].get(&pos, NULL);
				mtxB.a1d[i] = pos;
			}
			vm_matrix_x_matrix(&c_ori, &mtxA, &mtxB);

			vm_orthogonalize_matrix(&c_ori);
		}
		//Do custom orientation stuff, if needed
		if(func_custom_orientation != NULL && !target_set)
		{
			func_custom_orientation(this, &c_ori);
		}
		*orientation = c_ori;
	}
}