void opengl_post_lightshafts()
{
	opengl_shader_set_current(gr_opengl_maybe_create_shader(SDR_TYPE_POST_PROCESS_LIGHTSHAFTS, 0));

	float x, y;

	// should we even be here?
	if ( !Game_subspace_effect && ls_on && !ls_force_off ) {
		int n_lights = light_get_global_count();

		for ( int idx = 0; idx<n_lights; idx++ ) {
			vec3d light_dir;
			vec3d local_light_dir;
			light_get_global_dir(&light_dir, idx);
			vm_vec_rotate(&local_light_dir, &light_dir, &Eye_matrix);

			if ( !stars_sun_has_glare(idx) ) {
				continue;
			}

			float dot;
			if ( (dot = vm_vec_dot(&light_dir, &Eye_matrix.vec.fvec)) > 0.7f ) {

				x = asinf(vm_vec_dot(&light_dir, &Eye_matrix.vec.rvec)) / PI*1.5f + 0.5f; //cant get the coordinates right but this works for the limited glare fov
				y = asinf(vm_vec_dot(&light_dir, &Eye_matrix.vec.uvec)) / PI*1.5f*gr_screen.clip_aspect + 0.5f;
				Current_shader->program->Uniforms.setUniform2f("sun_pos", x, y);
				Current_shader->program->Uniforms.setUniformi("scene", 0);
				Current_shader->program->Uniforms.setUniformi("cockpit", 1);
				Current_shader->program->Uniforms.setUniformf("density", ls_density);
				Current_shader->program->Uniforms.setUniformf("falloff", ls_falloff);
				Current_shader->program->Uniforms.setUniformf("weight", ls_weight);
				Current_shader->program->Uniforms.setUniformf("intensity", Sun_spot * ls_intensity);
				Current_shader->program->Uniforms.setUniformf("cp_intensity", Sun_spot * ls_cpintensity);

				GL_state.Texture.SetActiveUnit(0);
				GL_state.Texture.SetTarget(GL_TEXTURE_2D);
				GL_state.Texture.Enable(Scene_depth_texture);
				GL_state.Texture.SetActiveUnit(1);
				GL_state.Texture.SetTarget(GL_TEXTURE_2D);
				GL_state.Texture.Enable(Cockpit_depth_texture);
				GL_state.Blend(GL_TRUE);
				GL_state.SetAlphaBlendMode(ALPHA_BLEND_ADDITIVE);

				opengl_draw_textured_quad(-1.0f, -1.0f, 0.0f, 0.0f, 1.0f, 1.0f, Scene_texture_u_scale, Scene_texture_u_scale);

				GL_state.Blend(GL_FALSE);
				break;
			}
		}
	}

	if ( zbuffer_saved ) {
		zbuffer_saved = false;
		gr_zbuffer_set(GR_ZBUFF_FULL);
		glClear(GL_DEPTH_BUFFER_BIT);
		gr_zbuffer_set(GR_ZBUFF_NONE);
		glFramebufferTexture2D(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, GL_TEXTURE_2D, Scene_depth_texture, 0);
	}
}
Example #2
0
// Try and find a new locking point
void hud_lock_get_new_lock_pos(object *target_objp, vector *lock_world_pos)
{
	ship			*target_shipp=NULL;
	int			lock_in_range=0;
	float			best_lock_dot=-1.0f, lock_dot=-1.0f;
	ship_subsys	*ss;
	vector		subsys_world_pos, vec_to_lock;

	if ( target_objp->type == OBJ_SHIP ) {
		target_shipp = &Ships[target_objp->instance];
	}

	// if a large ship, lock to pos closest to center and within range
	if ( (target_shipp) && (Ship_info[target_shipp->ship_info_index].flags & (SIF_BIG_SHIP|SIF_HUGE_SHIP)) ) {
		// check all the subsystems and the center of the ship
		
		// assume best lock pos is the center of the ship
		*lock_world_pos=target_objp->pos;
		Player->locking_on_center=1;
		Player->locking_subsys=NULL;
		Player->locking_subsys_parent=-1;
		lock_in_range = hud_lock_world_pos_in_range(lock_world_pos, &vec_to_lock);
		vm_vec_normalize(&vec_to_lock);
		if ( lock_in_range ) {
			best_lock_dot=vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_lock);
		} 
		// take center if reasonable dot
		if ( best_lock_dot > 0.95 ) {
			return;
		}

		// iterate through subsystems to see if we can get a better choice
		ss = GET_FIRST(&target_shipp->subsys_list);
		while ( ss != END_OF_LIST( &target_shipp->subsys_list ) ) {

			// get world pos of subsystem
			get_subsystem_world_pos(target_objp, ss, &subsys_world_pos);

			if ( hud_lock_world_pos_in_range(&subsys_world_pos, &vec_to_lock) ) {
				vm_vec_normalize(&vec_to_lock);
				lock_dot=vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_lock);
				if ( lock_dot > best_lock_dot ) {
					best_lock_dot=lock_dot;
					Player->locking_on_center=0;
					Player->locking_subsys=ss;
					Player->locking_subsys_parent=Player_ai->target_objnum;
					*lock_world_pos=subsys_world_pos;
				}
			}
			ss = GET_NEXT( ss );
		}
	} else {
		// if small ship (or weapon), just go for the center
		*lock_world_pos = target_objp->pos;
		Player->locking_on_center=1;
		Player->locking_subsys=NULL;
		Player->locking_subsys_parent=-1;
	}
}
Example #3
0
//	-----------------------------------------------------------------------------
//	Look at control center guns, find best one to fire at *objp.
//	Return best gun number (one whose direction dotted with vector to player is largest).
//	If best gun has negative dot, return -1, meaning no gun is good.
int calc_best_gun(int num_guns, vms_vector *gun_pos, vms_vector *gun_dir, vms_vector *objpos)
{
	int	i;
	fix	best_dot;
	int	best_gun;

	best_dot = -F1_0*2;
	best_gun = -1;

	for (i=0; i<num_guns; i++) {
		fix			dot;
		vms_vector	gun_vec;

		vm_vec_sub(&gun_vec, objpos, &gun_pos[i]);
		vm_vec_normalize_quick(&gun_vec);
		dot = vm_vec_dot(&gun_dir[i], &gun_vec);

		if (dot > best_dot) {
			best_dot = dot;
			best_gun = i;
		}
	}

	Assert(best_gun != -1);		// Contact Mike.  This is impossible.  Or maybe you're getting an unnormalized vector somewhere.

	if (best_dot < 0)
		return -1;
	else
		return best_gun;

}
void HudGaugeRadarDradis::plotBlip(blip* b, vec3d *pos, float *alpha)
{
	*pos = b->position;
	vm_vec_normalize(pos);

	if (ship_is_tagged(b->objp)) {
		*alpha = 1.0f;
		return;
	}

	float fade_multi = 1.5f;
	
	if (b->objp->type == OBJ_SHIP) {
		if (Ships[b->objp->instance].flags[Ship::Ship_Flags::Stealth]) {
			fade_multi *= 2.0f;
		}
	}
	
	b->time_since_update += flFrametime;
	// If the blip has been pinged by the local x-axis sweep, update
	if (std::abs(vm_vec_dot(&sweep_normal_x, pos)) < 0.01f) {
		b->time_since_update = 0.0f;
	}

	*alpha = ((sweep_duration - b->time_since_update)/sweep_duration)*fade_multi/2.0f;
	
	if (*alpha < 0.0f) {
		*alpha = 0.0f;
	}
}
//	-----------------------------------------------------------------------------------------------------------
// Simulate a physics object for this frame.  Used by the editor.  The difference between
// this function and physics_sim() is that this one uses a heading change to rotate around
// the universal Y axis, rather than the local orientation's Y axis.  Banking is also ignored.
void physics_sim_editor(vec3d *position, matrix * orient, physics_info * pi, float sim_time )
{
	physics_sim_vel(position, pi, sim_time, orient);
	physics_sim_rot_editor(orient, pi, sim_time);
	pi->speed = vm_vec_mag_quick(&pi->vel);
	pi->fspeed = vm_vec_dot(&orient->vec.fvec, &pi->vel);		// instead of vector magnitude -- use only forward vector since we are only interested in forward velocity
}
bool mc_shield_check_common(shield_tri	*tri)
{
	vec3d * points[3];
	vec3d hitpoint;
	 
	float dist;
	float sphere_check_closest_shield_dist = FLT_MAX;

	// Check to see if Mc_pmly is facing away from ray.  If so, don't bother
	// checking it.
	if (vm_vec_dot(&Mc_direction,&tri->norm) > 0.0f)	{
		return false;
	}
	// get the vertices in the form the next function wants them
	for (int j = 0; j < 3; j++ )
		points[j] = &Mc_pm->shield.verts[tri->verts[j]].pos;

	if (!(Mc->flags & MC_CHECK_SPHERELINE) ) {	// Don't do this test for sphere colliding against shields
		// Find the intersection of this ray with the plane that the Mc_pmly
		// lies in
		dist = fvi_ray_plane(NULL, points[0],&tri->norm,&Mc_p0,&Mc_direction,0.0f);

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

		// Find the hit Mc_pmint
		vm_vec_scale_add( &hitpoint, &Mc_p0, &Mc_direction, dist );
	
		// Check to see if the Mc_pmint of intersection is on the plane.  If so, this
		// also finds the uv's where the ray hit.
		if ( fvi_point_face(&hitpoint, 3, points, &tri->norm, NULL,NULL,NULL ) )	{
			Mc->hit_dist = dist;
			Mc->shield_hit_tri = (int)(tri - Mc_pm->shield.tris);
			Mc->hit_point = hitpoint;
			Mc->hit_normal = tri->norm;
			Mc->hit_submodel = -1;
			Mc->num_hits++;
			return true;		// We hit, so we're done
		}
	} else {		// Sphere check against shield
					// This needs to look at *all* shield tris and not just return after the first hit

		// HACK HACK!! The 10000.0 is the face radius, I didn't know this,
		// so I'm assume 10000 would be as big as ever.
		mc_check_sphereline_face(3, points, points[0], 10000.0f, &tri->norm, NULL, 0, NULL, NULL);
		if (Mc->num_hits && Mc->hit_dist < sphere_check_closest_shield_dist) {

			// same behavior whether face or edge
			// normal, edge_hit, hit_point all updated thru sphereline_face
			sphere_check_closest_shield_dist = Mc->hit_dist;
			Mc->shield_hit_tri = (int)(tri - Mc_pm->shield.tris);
			Mc->hit_submodel = -1;
			Mc->num_hits++;
			return true;		// We hit, so we're done
		}
	} // Mc->flags & MC_CHECK_SPHERELINE else

	return false;
}
static void mc_check_face(int nv, vec3d **verts, vec3d *plane_pnt, float face_rad, vec3d *plane_norm, uv_pair *uvl_list, int ntmap, ubyte *poly, bsp_collision_leaf* bsp_leaf)
{
	vec3d	hit_point;
	float		dist;
	float		u, v;

	// Check to see if poly is facing away from ray.  If so, don't bother
	// checking it.
	if (vm_vec_dot(&Mc_direction,plane_norm) > 0.0f)	{
		return;
	}

	// Find the intersection of this ray with the plane that the poly
	dist = fvi_ray_plane(NULL, plane_pnt, plane_norm, &Mc_p0, &Mc_direction, 0.0f);

	if ( dist < 0.0f ) return; // If the ray is behind the plane there is no collision
	if ( !(Mc->flags & MC_CHECK_RAY) && (dist > 1.0f) ) return; // 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 ) ) return;	

	// Find the hit point
	vm_vec_scale_add( &hit_point, &Mc_p0, &Mc_direction, dist );
	
	// Check to see if the point of intersection is on the plane.  If so, this
	// also finds the uv's where the ray hit.
	if ( fvi_point_face(&hit_point, nv, verts, plane_norm, &u,&v, uvl_list ) )	{
		Mc->hit_dist = dist;

		Mc->hit_point = hit_point;
		Mc->hit_submodel = Mc_submodel;

		Mc->hit_normal = *plane_norm;

		if ( uvl_list )	{
			Mc->hit_u = u;
			Mc->hit_v = v;
			if ( ntmap < 0 ) {
				Mc->hit_bitmap = -1;
			} else {
				Mc->hit_bitmap = Mc_pm->maps[ntmap].textures[TM_BASE_TYPE].GetTexture();			
			}
		}
		
		if(ntmap >= 0){
			Mc->t_poly = poly;
			Mc->f_poly = NULL;
		} else {
			Mc->t_poly = NULL;
			Mc->f_poly = poly;
		}

		Mc->bsp_leaf = bsp_leaf;

//		mprintf(( "Bing!\n" ));

		Mc->num_hits++;
	}
}
Example #8
0
File: draw.c Project: jihnsius/d2r
//returns true if a plane is facing the viewer. takes the unrotated surface 
//normal of the plane, and a point on it.  The normal need not be normalized
bool g3_check_normal_facing(vms_vector *v,vms_vector *norm)
{
	vms_vector tempv;

	vm_vec_sub(&tempv,&View_position,v);

	return (vm_vec_dot(&tempv,norm) > 0);
}
Example #9
0
/**
 * Given a shield triangle, compute the uv coordinates at its vertices given
 * the center point of the explosion texture, distance to center of shield and
 * right and up vectors.
 *
 * For small distances (relative to radius), coordinates can be computed using
 * distance. For larger values, should compute angle.
 */
void rs_compute_uvs(shield_tri *stp, shield_vertex *verts, vec3d *tcp, float radius, vec3d *rightv, vec3d *upv)
{
    int	i;
    shield_vertex *sv;

    for (i=0; i<3; i++) {
        vec3d	v2cp;

        sv = &verts[stp->verts[i]];

        vm_vec_sub(&v2cp, &sv->pos, tcp);
        sv->u = vm_vec_dot(&v2cp, rightv) * Shield_scale + 0.5f;
        sv->v = - vm_vec_dot(&v2cp, upv) * Shield_scale + 0.5f;

        CLAMP(sv->u, 0.0f, UV_MAX);
        CLAMP(sv->v, 0.0f, UV_MAX);
    }
}
Example #10
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);
    }
}
Example #11
0
/**
 * Returns TRUE if point is behind user plane
 */
int g3_point_behind_user_plane( const vec3d *pnt )
{
	if ( G3_user_clip ) {
		vec3d tmp;
		vm_vec_sub( &tmp, pnt, &G3_user_clip_point );
		if ( vm_vec_dot( &tmp, &G3_user_clip_normal ) <= 0.0f )	{
			return 1;
		}
	}

	return 0;
}
void opengl_shader_set_default_material(bool textured, bool alpha, vec4 *clr, float color_scale, uint32_t array_index, const material::clip_plane& clip_plane)
{
	Current_shader->program->Uniforms.setUniformi("baseMap", 0);

	if ( textured ) {
		Current_shader->program->Uniforms.setUniformi("noTexturing", 0);
		Current_shader->program->Uniforms.setUniformi("baseMapIndex", array_index);
	} else {
		Current_shader->program->Uniforms.setUniformi("noTexturing", 1);
		// array_index is probably not valid here
		Current_shader->program->Uniforms.setUniformi("baseMapIndex", 0);
	}

	if ( alpha ) {
		Current_shader->program->Uniforms.setUniformi("alphaTexture", 1);
	} else {
		Current_shader->program->Uniforms.setUniformi("alphaTexture", 0);
	}

	if ( High_dynamic_range ) {
		Current_shader->program->Uniforms.setUniformi("srgb", 1);
		Current_shader->program->Uniforms.setUniformf("intensity", color_scale);
	} else {
		Current_shader->program->Uniforms.setUniformi("srgb", 0);
		Current_shader->program->Uniforms.setUniformf("intensity", 1.0f);
	}

	Current_shader->program->Uniforms.setUniformf("alphaThreshold", GL_alpha_threshold);

	if ( clr != NULL ) {
		Current_shader->program->Uniforms.setUniform4f("color", *clr);
	} else {
		Current_shader->program->Uniforms.setUniform4f("color", 1.0f, 1.0f, 1.0f, 1.0f);
	}

	if (clip_plane.enabled) {
		Current_shader->program->Uniforms.setUniformi("clipEnabled", 1);

		vec4 clip_equation;
		clip_equation.xyzw.x = clip_plane.normal.xyz.x;
		clip_equation.xyzw.y = clip_plane.normal.xyz.y;
		clip_equation.xyzw.z = clip_plane.normal.xyz.z;
		clip_equation.xyzw.w = -vm_vec_dot(&clip_plane.normal, &clip_plane.position);

		Current_shader->program->Uniforms.setUniform4f("clipEquation", clip_equation);
		Current_shader->program->Uniforms.setUniformMatrix4f("modelMatrix", gr_model_matrix_stack.get_transform());
	} else {
		Current_shader->program->Uniforms.setUniformi("clipEnabled", 0);
	}

	Current_shader->program->Uniforms.setUniformMatrix4f("modelViewMatrix", gr_model_view_matrix);
	Current_shader->program->Uniforms.setUniformMatrix4f("projMatrix", gr_projection_matrix);
}
Example #13
0
// Determine if locking point is in the locking cone
void hud_lock_check_if_target_in_lock_cone()
{
	float	dot;
	vec3d	vec_to_target;

	vm_vec_normalized_dir(&vec_to_target, &lock_world_pos, &Player_obj->pos);
	dot = vm_vec_dot(&Player_obj->orient.vec.fvec, &vec_to_target);

	if ( dot > 0.85) {
		Player->target_in_lock_cone = 1;
	} else {
		Player->target_in_lock_cone = 0;
	}
}
Example #14
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);
    }
}
//	-----------------------------------------------------------------------------------------------------------
// Simulate a physics object for this frame
void physics_sim(vec3d* position, matrix* orient, physics_info* pi, float sim_time)
{
	// check flag which tells us whether or not to do velocity translation
	if (pi->flags & PF_CONST_VEL) {
		vm_vec_scale_add2(position, &pi->vel, sim_time);
	}
	else
	{
		physics_sim_vel(position, pi, sim_time, orient);
		physics_sim_rot(orient, pi, sim_time);

		pi->speed = vm_vec_mag(&pi->vel);							//	Note, cannot use quick version, causes cumulative error, increasing speed.
		pi->fspeed = vm_vec_dot(&orient->vec.fvec, &pi->vel);		// instead of vector magnitude -- use only forward vector since we are only interested in forward velocity
	}

}
Example #16
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 warpin_batch_draw_face( int texture, vertex *v1, vertex *v2, vertex *v3 )
{
	vec3d norm;
	vertex vertlist[3];

	vm_vec_perp(&norm,&v1->world, &v2->world, &v3->world);
	if ( vm_vec_dot(&norm, &v1->world ) >= 0.0 ) {
		vertlist[0] = *v3;
		vertlist[1] = *v2;
		vertlist[2] = *v1;
	} else {
		vertlist[0] = *v1;
		vertlist[1] = *v2;
		vertlist[2] = *v3;
	}

	batch_add_tri(texture, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT | TMAP_FLAG_EMISSIVE, vertlist, 1.0f);
}
Example #18
0
File: draw.c Project: jihnsius/d2r
bool do_facing_check(vms_vector *norm,g3s_point **vertlist,vms_vector *p)
{
	if (norm) {		//have normal

		Assert(norm->x || norm->y || norm->z);

		return g3_check_normal_facing(p,norm);
	}
	else {	//normal not specified, so must compute

		vms_vector tempv;

		//get three points (rotated) and compute normal

		vm_vec_perp(&tempv,&vertlist[0]->p3_vec,&vertlist[1]->p3_vec,&vertlist[2]->p3_vec);

		return (vm_vec_dot(&tempv,&vertlist[1]->p3_vec) < 0);
	}
}
void draw_face( vertex *v1, vertex *v2, vertex *v3 )
{
	vec3d norm;
	vertex *vertlist[3];

	vm_vec_perp(&norm,&v1->world, &v2->world, &v3->world);
	if ( vm_vec_dot(&norm, &v1->world ) >= 0.0 ) {
		vertlist[0] = v3;
		vertlist[1] = v2;
		vertlist[2] = v1;
	} else {
		vertlist[0] = v1;
		vertlist[1] = v2;
		vertlist[2] = v3;
	}

	g3_draw_poly( 3, vertlist, TMAP_FLAG_TEXTURED | TMAP_HTL_3D_UNLIT );

}
Example #20
0
//clips an edge against one plane.
vertex *clip_edge(int plane_flag,vertex *on_pnt,vertex *off_pnt, uint flags)
{
	float ratio;
	vertex *tmp;

	tmp = get_temp_point();

	if ( plane_flag & CC_OFF_USER )	{

		// Clip with user-defined plane
		vector w, ray_direction;
		float num,den;

		vm_vec_sub(&ray_direction,(vector *)&off_pnt->x,(vector *)&on_pnt->x);
			
		vm_vec_sub(&w,(vector *)&on_pnt->x,&G3_user_clip_point);
	
		den = -vm_vec_dot(&G3_user_clip_normal,&ray_direction);
		if ( den == 0.0f ) {	// Ray & plane are parallel, so there is no intersection
			Int3();	// Get John
			ratio = 1.0f;
		} else {
			num =  vm_vec_dot(&G3_user_clip_normal,&w);
	
			ratio = num / den;
		}

		tmp->x = on_pnt->x + (off_pnt->x-on_pnt->x) * ratio;
		tmp->y = on_pnt->y + (off_pnt->y-on_pnt->y) * ratio;
		tmp->z = on_pnt->z + (off_pnt->z-on_pnt->z) * ratio;

	} else {
		float a,b,kn,kd;

		//compute clipping value k = (xs-zs) / (xs-xe-zs+ze)
		//use x or y as appropriate, and negate x/y value as appropriate

		if (plane_flag & (CC_OFF_RIGHT | CC_OFF_LEFT)) {
			a = on_pnt->x;
			b = off_pnt->x;
		}
		else {
			a = on_pnt->y;
			b = off_pnt->y;
		}

		if (plane_flag & (CC_OFF_LEFT | CC_OFF_BOT)) {
			a = -a;
			b = -b;
		}

		kn = a - on_pnt->z;						//xs-zs
		kd = kn - b + off_pnt->z;				//xs-zs-xe+ze

		ratio = kn / kd;

		tmp->x = on_pnt->x + (off_pnt->x-on_pnt->x) * ratio;
		tmp->y = on_pnt->y + (off_pnt->y-on_pnt->y) * ratio;

		if (plane_flag & (CC_OFF_TOP|CC_OFF_BOT))	{
			tmp->z = tmp->y;
		} else {
			tmp->z = tmp->x;
		}

		if (plane_flag & (CC_OFF_LEFT|CC_OFF_BOT))
			tmp->z = -tmp->z;

	}

	if (flags & TMAP_FLAG_TEXTURED) {
		tmp->u = on_pnt->u + (off_pnt->u-on_pnt->u) * ratio;
		tmp->v = on_pnt->v + (off_pnt->v-on_pnt->v) * ratio;

		tmp->env_u = on_pnt->env_u + (off_pnt->env_u-on_pnt->env_u) * ratio;
		tmp->env_v = on_pnt->env_v + (off_pnt->env_v-on_pnt->env_v) * ratio;
	}

	if (flags & TMAP_FLAG_GOURAUD ) {
		if (flags & TMAP_FLAG_RAMP) {

			float on_b, off_b;

			on_b = i2fl(on_pnt->b);
			off_b = i2fl(off_pnt->b);

			tmp->b = ubyte(fl2i(on_b + (off_b-on_b) * ratio));
		}
		if (flags & TMAP_FLAG_RGB) {
			float on_r, on_b, on_g, onspec_r, onspec_g, onspec_b;
			float off_r, off_b, off_g, offspec_r, offspec_g, offspec_b;

			on_r = i2fl(on_pnt->r);
			off_r = i2fl(off_pnt->r);

			on_g = i2fl(on_pnt->g);
			off_g = i2fl(off_pnt->g);

			on_b = i2fl(on_pnt->b);
			off_b = i2fl(off_pnt->b);


			onspec_r = i2fl(on_pnt->spec_r);
			offspec_r = i2fl(off_pnt->spec_r);

			onspec_g = i2fl(on_pnt->spec_g);
			offspec_g = i2fl(off_pnt->spec_g);

			onspec_b = i2fl(on_pnt->spec_b);
			offspec_b = i2fl(off_pnt->spec_b);


			tmp->r = ubyte(fl2i(on_r + (off_r-on_r) * ratio));
			tmp->g = ubyte(fl2i(on_g + (off_g-on_g) * ratio));
			tmp->b = ubyte(fl2i(on_b + (off_b-on_b) * ratio));

			tmp->spec_r = ubyte(fl2i(onspec_r + (offspec_r-onspec_r) * ratio));
			tmp->spec_g = ubyte(fl2i(onspec_g + (offspec_g-onspec_g) * ratio));
			tmp->spec_b = ubyte(fl2i(onspec_b + (offspec_b-onspec_b) * ratio));
		}
	}
	else
	{
		tmp->spec_r=tmp->spec_g=tmp->spec_b=0;
	}

	if (flags & TMAP_FLAG_ALPHA) {

		float on_a, off_a;

		on_a = i2fl(on_pnt->a);
		off_a = i2fl(off_pnt->a);

		tmp->a = ubyte(fl2i(on_a + (off_a-on_a) * ratio));
	}

	g3_code_vertex(tmp);

	return tmp;	
}
Example #21
0
//alternate interpreter for morphing object
bool g3_draw_morphing_model(ubyte *p,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,g3s_lrgb model_light,vms_vector *new_points)
{
	fix *glow_values = NULL;

	glow_num = -1;		//glow off by default

	while (w(p) != OP_EOF)

		switch (w(p)) {

			case OP_DEFPOINTS: {
				int n = w(p+2);

				rotate_point_list(Interp_point_list,new_points,n);
				p += n*sizeof(struct vms_vector) + 4;

				break;
			}

			case OP_DEFP_START: {
				int n = w(p+2);
				int s = w(p+4);

				rotate_point_list(&Interp_point_list[s],new_points,n);
				p += n*sizeof(struct vms_vector) + 8;

				break;
			}

			case OP_FLATPOLY: {
				int nv = w(p+2);
				int i,ntris;

				gr_setcolor(w(p+28));
				
				for (i=0;i<2;i++)
					point_list[i] = Interp_point_list + wp(p+30)[i];

				for (ntris=nv-2;ntris;ntris--) {

					point_list[2] = Interp_point_list + wp(p+30)[i++];

					g3_check_and_draw_poly(3,point_list,NULL,NULL);

					point_list[1] = point_list[2];

				}

				p += 30 + ((nv&~1)+1)*2;
					
				break;
			}

			case OP_TMAPPOLY: {
				int nv = w(p+2);
				g3s_uvl *uvl_list;
				g3s_lrgb light, *lrgb_list;
				g3s_uvl morph_uvls[3];
				int i,ntris;

				MALLOC(lrgb_list, g3s_lrgb, nv);

				//calculate light from surface normal
				if (glow_num < 0) //no glow
				{
					light.r = light.g = light.b = -vm_vec_dot(&View_matrix.fvec,vp(p+16));
					light.r = f1_0/4 + (light.r*3)/4;
					light.r = fixmul(light.r,model_light.r);
					light.g = f1_0/4 + (light.g*3)/4;
					light.g = fixmul(light.g,model_light.g);
					light.b = f1_0/4 + (light.b*3)/4;
					light.b = fixmul(light.b,model_light.b);
				}
				else //yes glow
				{
					light.r = light.g = light.b = glow_values[glow_num];
					glow_num = -1;
				}

				//now poke light into l values
				uvl_list = (g3s_uvl *) (p+30+((nv&~1)+1)*2);

				for (i=0;i<nv;i++)
				{
					lrgb_list[i].r = light.r;
					lrgb_list[i].g = light.g;
					lrgb_list[i].b = light.b;
				}

				for (i=0;i<3;i++)
					morph_uvls[i].l = (light.r+light.g+light.b)/3;

				for (i=0;i<2;i++) {
					point_list[i] = Interp_point_list + wp(p+30)[i];

					morph_uvls[i].u = uvl_list[i].u;
					morph_uvls[i].v = uvl_list[i].v;
				}

				for (ntris=nv-2;ntris;ntris--) {

					point_list[2] = Interp_point_list + wp(p+30)[i];
					morph_uvls[2].u = uvl_list[i].u;
					morph_uvls[2].v = uvl_list[i].v;
					i++;

					g3_check_and_draw_tmap(3,point_list,uvl_list,lrgb_list,model_bitmaps[w(p+28)],NULL,NULL);

					point_list[1] = point_list[2];
					morph_uvls[1].u = morph_uvls[2].u;
					morph_uvls[1].v = morph_uvls[2].v;

				}

				p += 30 + ((nv&~1)+1)*2 + nv*12;
				d_free(lrgb_list);

				break;
			}

			case OP_SORTNORM:

				if (g3_check_normal_facing(vp(p+16),vp(p+4)) > 0) {		//facing

					//draw back then front

					g3_draw_morphing_model(p+w(p+30),model_bitmaps,anim_angles,model_light,new_points);
					g3_draw_morphing_model(p+w(p+28),model_bitmaps,anim_angles,model_light,new_points);

				}
				else {			//not facing.  draw front then back

					g3_draw_morphing_model(p+w(p+28),model_bitmaps,anim_angles,model_light,new_points);
					g3_draw_morphing_model(p+w(p+30),model_bitmaps,anim_angles,model_light,new_points);
				}

				p += 32;

				break;


			case OP_RODBM: {
				g3s_point rod_bot_p,rod_top_p;
				g3s_lrgb rodbm_light = { f1_0, f1_0, f1_0 };

				g3_rotate_point(&rod_bot_p,vp(p+20));
				g3_rotate_point(&rod_top_p,vp(p+4));

				g3_draw_rod_tmap(model_bitmaps[w(p+2)],&rod_bot_p,w(p+16),&rod_top_p,w(p+32),rodbm_light);

				p+=36;
				break;
			}

			case OP_SUBCALL: {
				vms_angvec *a;

				if (anim_angles)
					a = &anim_angles[w(p+2)];
				else
					a = &zero_angles;

				g3_start_instance_angles(vp(p+4),a);

				g3_draw_polygon_model(p+w(p+16),model_bitmaps,anim_angles,model_light,glow_values);

				g3_done_instance();

				p += 20;

				break;

			}

			case OP_GLOW:

				if (glow_values)
					glow_num = w(p+2);
				p += 4;
				break;
		}

	return 1;
}
Example #22
0
//calls the object interpreter to render an object.  The object renderer
//is really a seperate pipeline. returns true if drew
bool g3_draw_polygon_model(ubyte *p,grs_bitmap **model_bitmaps,vms_angvec *anim_angles,g3s_lrgb model_light,fix *glow_values)
{

	glow_num = -1;		//glow off by default

	while (w(p) != OP_EOF)

		switch (w(p)) {

			case OP_DEFPOINTS: {
				int n = w(p+2);

				rotate_point_list(Interp_point_list,vp(p+4),n);
				p += n*sizeof(struct vms_vector) + 4;

				break;
			}

			case OP_DEFP_START: {
				int n = w(p+2);
				int s = w(p+4);

				rotate_point_list(&Interp_point_list[s],vp(p+8),n);
				p += n*sizeof(struct vms_vector) + 8;

				break;
			}

			case OP_FLATPOLY: {
				int nv = w(p+2);

				Assert( nv < MAX_POINTS_PER_POLY );
				if (g3_check_normal_facing(vp(p+4),vp(p+16)) > 0) {
					int i;
#ifdef FADE_FLATPOLY
					short c;
					unsigned char cc;
					int l;
#endif

//					DPH: Now we treat this color as 15bpp
//					gr_setcolor(w(p+28));
					
#ifndef FADE_FLATPOLY
					gr_setcolor(gr_find_closest_color_15bpp(w(p + 28)));
#else
					//l = (32 * model_light) >> 16;
					l = f2i(fixmul(i2f(32), (model_light.r+model_light.g+model_light.b)/3));
					if (l<0) l = 0;
					else if (l>32) l = 32;
					cc = gr_find_closest_color_15bpp(w(p+28));
					c = gr_fade_table[(l<<8)|cc];
					gr_setcolor(c);
#endif

					for (i=0;i<nv;i++)
						point_list[i] = Interp_point_list + wp(p+30)[i];

					g3_draw_poly(nv,point_list);
				}

				p += 30 + ((nv&~1)+1)*2;
					
				break;
			}

			case OP_TMAPPOLY: {
				int nv = w(p+2);
				g3s_uvl *uvl_list;

				Assert( nv < MAX_POINTS_PER_POLY );
				if (g3_check_normal_facing(vp(p+4),vp(p+16)) > 0) {
					int i;
					g3s_lrgb light, *lrgb_list;

					MALLOC(lrgb_list, g3s_lrgb, nv);
					//calculate light from surface normal
					if (glow_num < 0) //no glow
					{
						light.r = light.g = light.b = -vm_vec_dot(&View_matrix.fvec,vp(p+16));
						light.r = f1_0/4 + (light.r*3)/4;
						light.r = fixmul(light.r,model_light.r);
						light.g = f1_0/4 + (light.g*3)/4;
						light.g = fixmul(light.g,model_light.g);
						light.b = f1_0/4 + (light.b*3)/4;
						light.b = fixmul(light.b,model_light.b);
					}
					else //yes glow
					{
						light.r = light.g = light.b = glow_values[glow_num];
						glow_num = -1;
					}

					//now poke light into l values
					uvl_list = (g3s_uvl *) (p+30+((nv&~1)+1)*2);

					for (i=0;i<nv;i++)
					{
						uvl_list[i].l = (light.r+light.g+light.b)/3;
						lrgb_list[i].r = light.r;
						lrgb_list[i].g = light.g;
						lrgb_list[i].b = light.b;
					}

					for (i=0;i<nv;i++)
						point_list[i] = Interp_point_list + wp(p+30)[i];

					g3_draw_tmap(nv,point_list,uvl_list,lrgb_list,model_bitmaps[w(p+28)]);
					d_free(lrgb_list);
				}

				p += 30 + ((nv&~1)+1)*2 + nv*12;
					
				break;
			}

			case OP_SORTNORM:

				if (g3_check_normal_facing(vp(p+16),vp(p+4)) > 0) {		//facing

					//draw back then front

					g3_draw_polygon_model(p+w(p+30),model_bitmaps,anim_angles,model_light,glow_values);
					g3_draw_polygon_model(p+w(p+28),model_bitmaps,anim_angles,model_light,glow_values);

				}
				else {			//not facing.  draw front then back

					g3_draw_polygon_model(p+w(p+28),model_bitmaps,anim_angles,model_light,glow_values);
					g3_draw_polygon_model(p+w(p+30),model_bitmaps,anim_angles,model_light,glow_values);
				}

				p += 32;

				break;


			case OP_RODBM: {
				g3s_point rod_bot_p,rod_top_p;
				g3s_lrgb rodbm_light = { f1_0, f1_0, f1_0 };

				g3_rotate_point(&rod_bot_p,vp(p+20));
				g3_rotate_point(&rod_top_p,vp(p+4));

				g3_draw_rod_tmap(model_bitmaps[w(p+2)],&rod_bot_p,w(p+16),&rod_top_p,w(p+32),rodbm_light);

				p+=36;
				break;
			}

			case OP_SUBCALL: {
				vms_angvec *a;

				if (anim_angles)
					a = &anim_angles[w(p+2)];
				else
					a = &zero_angles;

				g3_start_instance_angles(vp(p+4),a);

				g3_draw_polygon_model(p+w(p+16),model_bitmaps,anim_angles,model_light,glow_values);

				g3_done_instance();

				p += 20;

				break;

			}

			case OP_GLOW:

				if (glow_values)
					glow_num = w(p+2);
				p += 4;
				break;

			default:
				Error("invalid polygon model\n");
		}
	return 1;
}
void obj_collide_pair(object *A, object *B)
{
	uint ctype;
	int (*check_collision)( obj_pair *pair );
	int swapped = 0;	
	
	check_collision = NULL;

	if ( A==B ) return;		// Don't check collisions with yourself

	if ( !(A->flags&OF_COLLIDES) ) return;		// This object doesn't collide with anything
	if ( !(B->flags&OF_COLLIDES) ) return;		// This object doesn't collide with anything
	
	// Make sure you're not checking a parent with it's kid or vicy-versy
//	if ( A->parent_sig == B->signature && !(A->type == OBJ_SHIP && B->type == OBJ_DEBRIS) ) return;
//	if ( B->parent_sig == A->signature && !(A->type == OBJ_DEBRIS && B->type == OBJ_SHIP) ) return;
	if ( reject_obj_pair_on_parent(A,B) ) {
		return;
	}

	Assert( A->type < 127 );
	Assert( B->type < 127 );

	ctype = COLLISION_OF(A->type,B->type);
	switch( ctype )	{
	case COLLISION_OF(OBJ_WEAPON,OBJ_SHIP):
		swapped = 1;
		check_collision = collide_ship_weapon;
		break;
	case COLLISION_OF(OBJ_SHIP, OBJ_WEAPON):
		check_collision = collide_ship_weapon;
		break;
	case COLLISION_OF(OBJ_DEBRIS, OBJ_WEAPON):
		check_collision = collide_debris_weapon;
		break;
	case COLLISION_OF(OBJ_WEAPON, OBJ_DEBRIS):
		swapped = 1;
		check_collision = collide_debris_weapon;
		break;
	case COLLISION_OF(OBJ_DEBRIS, OBJ_SHIP):
		check_collision = collide_debris_ship;		
		break;
	case COLLISION_OF(OBJ_SHIP, OBJ_DEBRIS):
		check_collision = collide_debris_ship;
		swapped = 1;
		break;
	case COLLISION_OF(OBJ_ASTEROID, OBJ_WEAPON):
		// Only check collision's with player weapons
//		if ( Objects[B->parent].flags & OF_PLAYER_SHIP ) {
			check_collision = collide_asteroid_weapon;
//		}
		break;
	case COLLISION_OF(OBJ_WEAPON, OBJ_ASTEROID):
		swapped = 1;
		// Only check collision's with player weapons
//		if ( Objects[A->parent].flags & OF_PLAYER_SHIP ) {
			check_collision = collide_asteroid_weapon;
//		}
		break;
	case COLLISION_OF(OBJ_ASTEROID, OBJ_SHIP):
		// Only check collisions with player ships
//		if ( B->flags & OF_PLAYER_SHIP )	{
			check_collision = collide_asteroid_ship;
//		}
		break;
	case COLLISION_OF(OBJ_SHIP, OBJ_ASTEROID):
		// Only check collisions with player ships
//		if ( A->flags & OF_PLAYER_SHIP )	{
			check_collision = collide_asteroid_ship;
//		}
		swapped = 1;
		break;
	case COLLISION_OF(OBJ_SHIP,OBJ_SHIP):
		check_collision = collide_ship_ship;
		break;	
	
	case COLLISION_OF(OBJ_SHIP, OBJ_BEAM):
		if(beam_collide_early_out(B, A)){
			return;
		}
		swapped = 1;
		check_collision = beam_collide_ship;
		break;

	case COLLISION_OF(OBJ_BEAM, OBJ_SHIP):
		if(beam_collide_early_out(A, B)){
			return;
		}
		check_collision = beam_collide_ship;
		break;

	case COLLISION_OF(OBJ_ASTEROID, OBJ_BEAM):
		if(beam_collide_early_out(B, A)) {
			return;
		}
		swapped = 1;
		check_collision = beam_collide_asteroid;
		break;

	case COLLISION_OF(OBJ_BEAM, OBJ_ASTEROID):
		if(beam_collide_early_out(A, B)){
			return;
		}
		check_collision = beam_collide_asteroid;
		break;
	case COLLISION_OF(OBJ_DEBRIS, OBJ_BEAM):
		if(beam_collide_early_out(B, A)) {
			return;
		}
		swapped = 1;
		check_collision = beam_collide_debris;
		break;
	case COLLISION_OF(OBJ_BEAM, OBJ_DEBRIS):
		if(beam_collide_early_out(A, B)){
			return;
		}
		check_collision = beam_collide_debris;
		break;
	case COLLISION_OF(OBJ_WEAPON, OBJ_BEAM):
		if(beam_collide_early_out(B, A)) {
			return;
		}
		swapped = 1;
		check_collision = beam_collide_missile;
		break;

	case COLLISION_OF(OBJ_BEAM, OBJ_WEAPON):
		if(beam_collide_early_out(A, B)){
			return;
		}		
		check_collision = beam_collide_missile;
		break;

	case COLLISION_OF(OBJ_WEAPON, OBJ_WEAPON): {
		weapon_info *awip, *bwip;
		awip = &Weapon_info[Weapons[A->instance].weapon_info_index];
		bwip = &Weapon_info[Weapons[B->instance].weapon_info_index];

		if ((awip->weapon_hitpoints > 0) || (bwip->weapon_hitpoints > 0)) {
			if (bwip->weapon_hitpoints == 0) {
				check_collision = collide_weapon_weapon;
				swapped=1;
			} else {
				check_collision = collide_weapon_weapon;
			}
		}

		break;
	}

	default:
		return;
	}

	if ( !check_collision ) return;

	// Swap them if needed
	if ( swapped )	{
		object *tmp = A;
		A = B;
		B = tmp;
	}

	collider_pair *collision_info = NULL;
	bool valid = false;
	uint key = (OBJ_INDEX(A) << 12) + OBJ_INDEX(B);

	collision_info = &Collision_cached_pairs[key];

	if ( collision_info->initialized ) {
		// make sure we're referring to the correct objects in case the original pair was deleted
		if ( collision_info->signature_a == collision_info->a->signature && 
			collision_info->signature_b == collision_info->b->signature ) {
			valid = true;
		} else {
			collision_info->a = A;
			collision_info->b = B;
			collision_info->signature_a = A->signature;
			collision_info->signature_b = B->signature;
			collision_info->next_check_time = timestamp(0);
		}
	} else {
		collision_info->a = A;
		collision_info->b = B;
		collision_info->signature_a = A->signature;
		collision_info->signature_b = B->signature;
		collision_info->initialized = true;
		collision_info->next_check_time = timestamp(0);
	}

	if ( valid &&  A->type != OBJ_BEAM ) {
		// if this signature is valid, make the necessary checks to see if we need to collide check
		if ( collision_info->next_check_time == -1 ) {
			return;
		} else {
			if ( !timestamp_elapsed(collision_info->next_check_time) ) {
				return;
			}
		}
	} else {
		//if ( A->type == OBJ_BEAM ) {
			//if(beam_collide_early_out(A, B)){
				//collision_info->next_check_time = -1;
				//return;
			//}
		//}

		// only check debris:weapon collisions for player
		if (check_collision == collide_debris_weapon) {
			// weapon is B
			if ( !(Weapon_info[Weapons[B->instance].weapon_info_index].wi_flags & WIF_TURNS) ) {
				// check for dumbfire weapon
				// check if debris is behind laser
				float vdot;
				if (Weapon_info[Weapons[B->instance].weapon_info_index].subtype == WP_LASER) {
					vec3d velocity_rel_weapon;
					vm_vec_sub(&velocity_rel_weapon, &B->phys_info.vel, &A->phys_info.vel);
					vdot = -vm_vec_dot(&velocity_rel_weapon, &B->orient.vec.fvec);
				} else {
					vdot = vm_vec_dot( &A->phys_info.vel, &B->phys_info.vel);
				}
				if ( vdot <= 0.0f )	{
					// They're heading in opposite directions...
					// check their positions
					vec3d weapon2other;
					vm_vec_sub( &weapon2other, &A->pos, &B->pos );
					float pdot = vm_vec_dot( &B->orient.vec.fvec, &weapon2other );
					if ( pdot <= -A->radius )	{
						// The other object is behind the weapon by more than
						// its radius, so it will never hit...
						collision_info->next_check_time = -1;
						return;
					}
				}

				// check dist vs. dist moved during weapon lifetime
				vec3d delta_v;
				vm_vec_sub(&delta_v, &B->phys_info.vel, &A->phys_info.vel);
				if (vm_vec_dist_squared(&A->pos, &B->pos) > (vm_vec_mag_squared(&delta_v)*Weapons[B->instance].lifeleft*Weapons[B->instance].lifeleft)) {
					collision_info->next_check_time = -1;
					return;
				}

				// for nonplayer ships, only create collision pair if close enough
				if ( (B->parent >= 0) && !(Objects[B->parent].flags & OF_PLAYER_SHIP) && (vm_vec_dist(&B->pos, &A->pos) < (4.0f*A->radius + 200.0f)) ) {
					collision_info->next_check_time = -1;
					return;
				}
			}
		}

		// don't check same team laser:ship collisions on small ships if not player
		if (check_collision == collide_ship_weapon) {
			// weapon is B
			if ( (B->parent >= 0)
				&& !(Objects[B->parent].flags & OF_PLAYER_SHIP)
				&& (Ships[Objects[B->parent].instance].team == Ships[A->instance].team) 
				&& (Ship_info[Ships[A->instance].ship_info_index].flags & SIF_SMALL_SHIP) 
				&& (Weapon_info[Weapons[B->instance].weapon_info_index].subtype == WP_LASER) ) {
				collision_info->next_check_time = -1;
				return;
			}
		}
	}

	obj_pair new_pair;	

	new_pair.a = A;
	new_pair.b = B;
	new_pair.check_collision = check_collision;
	new_pair.next_check_time = collision_info->next_check_time;

	if ( check_collision(&new_pair) ) {
		// don't have to check ever again
		collision_info->next_check_time = -1;
	} else {
		collision_info->next_check_time = new_pair.next_check_time;
	}
}
Example #24
0
void do_object_physics( object * obj )
{
	vms_angvec rotang;
	vms_vector frame_vec;	//movement in this frame
	vms_vector new_pos,ipos;		//position after this frame
	int iseg;
	int hit;
	vms_matrix rotmat,new_pm;
	int count=0;
	short joy_x,joy_y,btns;
	int joyx_moved,joyy_moved;
	fix speed;
	vms_vector *desired_upvec;
	fixang delta_ang,roll_ang;
	vms_vector forvec = {0,0,f1_0};
	vms_matrix temp_matrix;

	//check keys

	rotang.pitch = ROT_SPEED * (key_down_time(KEY_UP) - key_down_time(KEY_DOWN));
	rotang.head  = ROT_SPEED * (key_down_time(KEY_RIGHT) - key_down_time(KEY_LEFT));
	rotang.bank = 0;

	//check for joystick movement

	joy_get_pos(&joy_x,&joy_y);
	btns=joy_get_btns();

	joyx_moved = (abs(joy_x - _old_joy_x)>JOY_NULL);
	joyy_moved = (abs(joy_y - _old_joy_y)>JOY_NULL);

	if (abs(joy_x) < JOY_NULL) joy_x = 0;
	if (abs(joy_y) < JOY_NULL) joy_y = 0;

	if (!rotang.pitch) rotang.pitch = fixmul(-joy_y * 128,FrameTime);
	if (!rotang.head) rotang.head = fixmul(joy_x * 128,FrameTime);
	
	if (joyx_moved) _old_joy_x = joy_x;
	if (joyy_moved) _old_joy_y = joy_y;

	speed = ((btns&2) || keyd_pressed[KEY_A])?SLOW_SPEED*3:(keyd_pressed[KEY_Z]?SLOW_SPEED/2:SLOW_SPEED);

	//now build matrices, do rotations, etc., etc.

	vm_angles_2_matrix(&rotmat,&rotang);
	vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
	obj->orient = new_pm;

	//move player

	vm_vec_copy_scale(&obj->velocity,&obj->orient.fvec,speed);
	vm_vec_copy_scale(&frame_vec,&obj->velocity,FrameTime);

	do {
		fix wall_part;
		vms_vector tvec;

		count++;

		vm_vec_add(&new_pos,&obj->pos,&frame_vec);

		hit = find_vector_intersection(&ipos,&iseg,&obj->pos,obj->seg_id,&new_pos,obj->size,-1);

		obj->seg_id = iseg;
		obj->pos = ipos;

		//-FIXJOHN-if (hit==HIT_OBJECT) ExplodeObject(hit_objnum);

		if (hit==HIT_WALL) {
			vm_vec_sub(&frame_vec,&new_pos,&obj->pos);	//part through wall
			wall_part = vm_vec_dot(wall_norm,&frame_vec);
			vm_vec_copy_scale(&tvec,wall_norm,wall_part);
			if ((wall_part == 0) || (vm_vec_mag(&tvec) < 5)) Int3();
			vm_vec_sub2(&frame_vec,&tvec);
		}

	} while (hit == HIT_WALL);

	Assert(check_point_in_seg(&obj->pos,obj->seg_id,0).centermask==0);

	//now bank player according to segment orientation

	desired_upvec = &Segments[obj->seg_id].sides[3].faces[0].normal;

	if (labs(vm_vec_dot(desired_upvec,&obj->orient.fvec)) < f1_0/2) {

		vm_vector_2_matrix(&temp_matrix,&obj->orient.fvec,desired_upvec,NULL);

		delta_ang = vm_vec_delta_ang(&obj->orient.uvec,&temp_matrix.uvec,&obj->orient.fvec);

		if (rotang.head) delta_ang += (rotang.head<0)?TURNROLL_ANG:-TURNROLL_ANG;

		if (abs(delta_ang) > DAMP_ANG) {

			roll_ang = fixmul(FrameTime,ROLL_RATE);

			if (abs(delta_ang) < roll_ang) roll_ang = delta_ang;
			else if (delta_ang<0) roll_ang = -roll_ang;

			vm_vec_ang_2_matrix(&rotmat,&forvec,roll_ang);

			vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
			obj->orient = new_pm;
		}
	}

}
Example #25
0
void do_physics_align_object( object * obj )
{
	vms_vector desired_upvec;
	fixang delta_ang,roll_ang;
	//vms_vector forvec = {0,0,f1_0};
	vms_matrix temp_matrix;
	fix d,largest_d=-f1_0;
	int i,best_side;

        best_side=0;
	// bank player according to segment orientation

	//find side of segment that player is most alligned with

	for (i=0;i<6;i++) {
#ifdef COMPACT_SEGS
			vms_vector _tv1;
			get_side_normal( &Segments[obj->segnum], i, 0, &_tv1 );
			d = vm_vec_dot(&_tv1,&obj->orient.uvec);
#else
			d = vm_vec_dot(&Segments[obj->segnum].sides[i].normals[0],&obj->orient.uvec);
#endif

		if (d > largest_d) {largest_d = d; best_side=i;}
	}

	if (floor_levelling) {

		// old way: used floor's normal as upvec
#ifdef COMPACT_SEGS
			get_side_normal(&Segments[obj->segnum], 3, 0, &desired_upvec );			
#else
			desired_upvec = Segments[obj->segnum].sides[3].normals[0];
#endif

	}
	else  // new player leveling code: use normal of side closest to our up vec
		if (get_num_faces(&Segments[obj->segnum].sides[best_side])==2) {
#ifdef COMPACT_SEGS
				vms_vector normals[2];
				get_side_normals(&Segments[obj->segnum], best_side, &normals[0], &normals[1] );			

				desired_upvec.x = (normals[0].x + normals[1].x) / 2;
				desired_upvec.y = (normals[0].y + normals[1].y) / 2;
				desired_upvec.z = (normals[0].z + normals[1].z) / 2;

				vm_vec_normalize(&desired_upvec);
#else
				side *s = &Segments[obj->segnum].sides[best_side];
				desired_upvec.x = (s->normals[0].x + s->normals[1].x) / 2;
				desired_upvec.y = (s->normals[0].y + s->normals[1].y) / 2;
				desired_upvec.z = (s->normals[0].z + s->normals[1].z) / 2;
		
				vm_vec_normalize(&desired_upvec);
#endif
		}
		else
#ifdef COMPACT_SEGS
				get_side_normal(&Segments[obj->segnum], best_side, 0, &desired_upvec );			
#else
				desired_upvec = Segments[obj->segnum].sides[best_side].normals[0];
#endif

	if (labs(vm_vec_dot(&desired_upvec,&obj->orient.fvec)) < f1_0/2) {
		vms_angvec tangles;
		
		vm_vector_2_matrix(&temp_matrix,&obj->orient.fvec,&desired_upvec,NULL);

		delta_ang = vm_vec_delta_ang(&obj->orient.uvec,&temp_matrix.uvec,&obj->orient.fvec);

		delta_ang += obj->mtype.phys_info.turnroll;

		if (abs(delta_ang) > DAMP_ANG) {
			vms_matrix rotmat, new_pm;

			roll_ang = fixmul(FrameTime,ROLL_RATE);

			if (abs(delta_ang) < roll_ang) roll_ang = delta_ang;
			else if (delta_ang<0) roll_ang = -roll_ang;

			tangles.p = tangles.h = 0;  tangles.b = roll_ang;
			vm_angles_2_matrix(&rotmat,&tangles);

			vm_matrix_x_matrix(&new_pm,&obj->orient,&rotmat);
			obj->orient = new_pm;
		}
		else floor_levelling=0;
	}

}
Example #26
0
do_endlevel_flythrough(int n)
{
	object *obj;
	segment *pseg;
	int old_player_seg;

	flydata = &fly_objects[n];
	obj = flydata->obj;
	
	old_player_seg = obj->segnum;

	//move the player for this frame

	if (!flydata->first_time) {

		vm_vec_scale_add2(&obj->pos,&flydata->step,FrameTime);
		angvec_add2_scale(&flydata->angles,&flydata->angstep,FrameTime);

		vm_angles_2_matrix(&obj->orient,&flydata->angles);
	}

	//check new player seg

	update_object_seg(obj);
	pseg = &Segments[obj->segnum];

	if (flydata->first_time || obj->segnum != old_player_seg) {		//moved into new seg
		vms_vector curcenter,nextcenter;
		fix step_size,seg_time;
		short entry_side,exit_side;	//what sides we entry and leave through
		vms_vector dest_point;		//where we are heading (center of exit_side)
		vms_angvec dest_angles;		//where we want to be pointing
		vms_matrix dest_orient;
		int up_side;

		//find new exit side

		if (!flydata->first_time) {

			entry_side = matt_find_connect_side(obj->segnum,old_player_seg);
			exit_side = Side_opposite[entry_side];
		}

		if (flydata->first_time || entry_side==-1 || pseg->children[exit_side]==-1)
			exit_side = find_exit_side(obj);

		{										//find closest side to align to
			fix d,largest_d=-f1_0;
			int i;

			for (i=0;i<6;i++) {
				#ifdef COMPACT_SEGS
				vms_vector v1;
				get_side_normal(pseg, i, 0, &v1 );
				d = vm_vec_dot(&v1,&flydata->obj->orient.uvec);
				#else
				d = vm_vec_dot(&pseg->sides[i].normals[0],&flydata->obj->orient.uvec);
				#endif
				if (d > largest_d) {largest_d = d; up_side=i;}
			}

		}

		//update target point & angles

		compute_center_point_on_side(&dest_point,pseg,exit_side);

		//update target point and movement points

		//offset object sideways
		if (flydata->offset_frac) {
			int s0=-1,s1,i;
			vms_vector s0p,s1p;
			fix dist;

			for (i=0;i<6;i++)
				if (i!=entry_side && i!=exit_side && i!=up_side && i!=Side_opposite[up_side])
					if (s0==-1)
						s0 = i;
					else
						s1 = i;

			compute_center_point_on_side(&s0p,pseg,s0);
			compute_center_point_on_side(&s1p,pseg,s1);
			dist = fixmul(vm_vec_dist(&s0p,&s1p),flydata->offset_frac);

			if (dist-flydata->offset_dist > MAX_SLIDE_PER_SEGMENT)
				dist = flydata->offset_dist + MAX_SLIDE_PER_SEGMENT;

			flydata->offset_dist = dist;

			vm_vec_scale_add2(&dest_point,&obj->orient.rvec,dist);

		}

		vm_vec_sub(&flydata->step,&dest_point,&obj->pos);
		step_size = vm_vec_normalize_quick(&flydata->step);
		vm_vec_scale(&flydata->step,flydata->speed);

		compute_segment_center(&curcenter,pseg);
		compute_segment_center(&nextcenter,&Segments[pseg->children[exit_side]]);
		vm_vec_sub(&flydata->headvec,&nextcenter,&curcenter);

		#ifdef COMPACT_SEGS	
		{
			vms_vector _v1;
			get_side_normal(pseg, up_side, 0, &_v1 );
			vm_vector_2_matrix(&dest_orient,&flydata->headvec,&_v1,NULL);
		}
		#else
		vm_vector_2_matrix(&dest_orient,&flydata->headvec,&pseg->sides[up_side].normals[0],NULL);
		#endif
		vm_extract_angles_matrix(&dest_angles,&dest_orient);

		if (flydata->first_time)
			vm_extract_angles_matrix(&flydata->angles,&obj->orient);

		seg_time = fixdiv(step_size,flydata->speed);	//how long through seg

		if (seg_time) {
			flydata->angstep.x = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.p,dest_angles.p),seg_time)));
			flydata->angstep.z = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.b,dest_angles.b),seg_time)));
			flydata->angstep.y = max(-MAX_ANGSTEP,min(MAX_ANGSTEP,fixdiv(delta_ang(flydata->angles.h,dest_angles.h),seg_time)));

		}
		else {
			flydata->angles = dest_angles;
			flydata->angstep.x = flydata->angstep.y = flydata->angstep.z = 0;
		}
	}

	flydata->first_time=0;
}
Example #27
0
do_endlevel_frame()
{
	static fix timer;
	vms_vector save_last_pos;
	static fix explosion_wait1=0;
	static fix explosion_wait2=0;
	static fix bank_rate;
	static fix ext_expl_halflife;

	save_last_pos = ConsoleObject->last_pos;	//don't let move code change this
	object_move_all();
	ConsoleObject->last_pos = save_last_pos;

	if (ext_expl_playing) {

		external_explosion.lifeleft -= FrameTime;
		do_explosion_sequence(&external_explosion);

		if (external_explosion.lifeleft < ext_expl_halflife)
			mine_destroyed = 1;

		if (external_explosion.flags & OF_SHOULD_BE_DEAD)
			ext_expl_playing = 0;
	}

	if (cur_fly_speed != desired_fly_speed) {
		fix delta = desired_fly_speed - cur_fly_speed;
		fix frame_accel = fixmul(FrameTime,FLY_ACCEL);

		if (abs(delta) < frame_accel)
			cur_fly_speed = desired_fly_speed;
		else
			if (delta > 0)
				cur_fly_speed += frame_accel;
			else
				cur_fly_speed -= frame_accel;
	}

	//do big explosions
	if (!outside_mine) {

		if (Endlevel_sequence==EL_OUTSIDE) {
			vms_vector tvec;

			vm_vec_sub(&tvec,&ConsoleObject->pos,&mine_side_exit_point);

			if (vm_vec_dot(&tvec,&mine_exit_orient.fvec) > 0) {
				object *tobj;

				outside_mine = 1;

				tobj = object_create_explosion(exit_segnum,&mine_side_exit_point,i2f(50),VCLIP_BIG_PLAYER_EXPLOSION);

				if (tobj) {
					external_explosion = *tobj;

					tobj->flags |= OF_SHOULD_BE_DEAD;

					flash_scale = 0;	//kill lights in mine

					ext_expl_halflife = tobj->lifeleft;

					ext_expl_playing = 1;
				}
	
				digi_link_sound_to_pos( SOUND_BIG_ENDLEVEL_EXPLOSION, exit_segnum, 0, &mine_side_exit_point, 0, i2f(3)/4 );
			}
		}

		//do explosions chasing player
		if ((explosion_wait1-=FrameTime) < 0) {
			vms_vector tpnt;
			int segnum;
			object *expl;
			static int sound_count;

			vm_vec_scale_add(&tpnt,&ConsoleObject->pos,&ConsoleObject->orient.fvec,-ConsoleObject->size*5);
			vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.rvec,(rand()-RAND_MAX/2)*15);
			vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.uvec,(rand()-RAND_MAX/2)*15);

			segnum = find_point_seg(&tpnt,ConsoleObject->segnum);

			if (segnum != -1) {
				expl = object_create_explosion(segnum,&tpnt,i2f(20),VCLIP_BIG_PLAYER_EXPLOSION);
				if (rand()<10000 || ++sound_count==7) {		//pseudo-random
					digi_link_sound_to_pos( SOUND_TUNNEL_EXPLOSION, segnum, 0, &tpnt, 0, F1_0 );
					sound_count=0;
				}
			}

			explosion_wait1 = 0x2000 + rand()/4;

		}
	}

	//do little explosions on walls
	if (Endlevel_sequence >= EL_FLYTHROUGH && Endlevel_sequence < EL_OUTSIDE)
		if ((explosion_wait2-=FrameTime) < 0) {
			vms_vector tpnt;
			fvi_query fq;
			fvi_info hit_data;

			//create little explosion on wall

			vm_vec_copy_scale(&tpnt,&ConsoleObject->orient.rvec,(rand()-RAND_MAX/2)*100);
			vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.uvec,(rand()-RAND_MAX/2)*100);
			vm_vec_add2(&tpnt,&ConsoleObject->pos);

			if (Endlevel_sequence == EL_FLYTHROUGH)
				vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.fvec,rand()*200);
			else
				vm_vec_scale_add2(&tpnt,&ConsoleObject->orient.fvec,rand()*60);

			//find hit point on wall

			fq.p0 = &ConsoleObject->pos;
			fq.p1 = &tpnt;
			fq.startseg = ConsoleObject->segnum;
			fq.rad = 0;
			fq.thisobjnum = 0;
			fq.ignore_obj_list = NULL;
			fq.flags = 0;

			find_vector_intersection(&fq,&hit_data);

			if (hit_data.hit_type==HIT_WALL && hit_data.hit_seg!=-1)
				object_create_explosion(hit_data.hit_seg,&hit_data.hit_pnt,i2f(3)+rand()*6,VCLIP_SMALL_EXPLOSION);

			explosion_wait2 = (0xa00 + rand()/8)/2;
		}

	switch (Endlevel_sequence) {

		case EL_OFF: return;

		case EL_FLYTHROUGH: {

			do_endlevel_flythrough(0);

			if (ConsoleObject->segnum == transition_segnum) {
				int objnum;

				Endlevel_sequence = EL_LOOKBACK;

				objnum = obj_create(OBJ_CAMERA, 0, 
					ConsoleObject->segnum,&ConsoleObject->pos,&ConsoleObject->orient,0,
					CT_NONE,MT_NONE,RT_NONE);

				if (objnum == -1) {				//can't get object, so abort
					mprintf((1, "Can't get object for endlevel sequence.  Aborting endlevel sequence.\n"));
					stop_endlevel_sequence();
					return;
				}

				Viewer = endlevel_camera = &Objects[objnum];

				select_cockpit(CM_LETTERBOX);

				fly_objects[1] = fly_objects[0];
				fly_objects[1].obj = endlevel_camera;
				fly_objects[1].speed = (5*cur_fly_speed)/4;
				fly_objects[1].offset_frac = 0x4000;

				vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,i2f(7));

				timer=0x20000;
			}

			break;
		}


		case EL_LOOKBACK: {

			do_endlevel_flythrough(0);
			do_endlevel_flythrough(1);

			if (timer>0) {

				timer -= FrameTime;

				if (timer < 0)		//reduce speed
					fly_objects[1].speed = fly_objects[0].speed;
			}

			if (endlevel_camera->segnum == exit_segnum) {
				vms_angvec cam_angles,exit_seg_angles;

				Endlevel_sequence = EL_OUTSIDE;

				timer = i2f(2);

				vm_vec_negate(&endlevel_camera->orient.fvec);
				vm_vec_negate(&endlevel_camera->orient.rvec);

				vm_extract_angles_matrix(&cam_angles,&endlevel_camera->orient);
				vm_extract_angles_matrix(&exit_seg_angles,&mine_exit_orient);
				bank_rate = (-exit_seg_angles.b - cam_angles.b)/2;

				ConsoleObject->control_type = endlevel_camera->control_type = CT_NONE;

				//_MARK_("Starting outside");//Commented out by KRB

#ifdef SLEW_ON
 slew_obj = endlevel_camera;
#endif
			}
				
			break;
		}

		case EL_OUTSIDE: {
			#ifndef SLEW_ON
			vms_angvec cam_angles;
			#endif

			vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed));
#ifndef SLEW_ON
			vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,fixmul(FrameTime,-2*cur_fly_speed));
			vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.uvec,fixmul(FrameTime,-cur_fly_speed/10));

			vm_extract_angles_matrix(&cam_angles,&endlevel_camera->orient);
			cam_angles.b += fixmul(bank_rate,FrameTime);
			vm_angles_2_matrix(&endlevel_camera->orient,&cam_angles);
#endif

			timer -= FrameTime;

			if (timer < 0) {

				Endlevel_sequence = EL_STOPPED;

				vm_extract_angles_matrix(&player_angles,&ConsoleObject->orient);

				timer = i2f(3);

			}

			break;
		}

		case EL_STOPPED: {

			get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos);
			chase_angles(&player_angles,&player_dest_angles);
			vm_angles_2_matrix(&ConsoleObject->orient,&player_angles);

			vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed));

			timer -= FrameTime;

			if (timer < 0) {

				#ifdef SLEW_ON
				slew_obj = endlevel_camera;
				_do_slew_movement(endlevel_camera,1,1);
				timer += FrameTime;		//make time stop
				break;
				#else

				#ifdef SHORT_SEQUENCE

				stop_endlevel_sequence();

				#else
				Endlevel_sequence = EL_PANNING;

				vm_extract_angles_matrix(&camera_cur_angles,&endlevel_camera->orient);


				timer = i2f(3);

				if (Game_mode & GM_MULTI) { // try to skip part of the seq if multiplayer
					stop_endlevel_sequence();
					return;
				}

				//mprintf((0,"Switching to pan...\n"));
				#endif		//SHORT_SEQUENCE
				#endif		//SLEW_ON

			}
			break;
		}

		#ifndef SHORT_SEQUENCE
		case EL_PANNING: {
			#ifndef SLEW_ON
			int mask;
			#endif

			get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos);
			chase_angles(&player_angles,&player_dest_angles);
			vm_angles_2_matrix(&ConsoleObject->orient,&player_angles);
			vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed));

			#ifdef SLEW_ON
			_do_slew_movement(endlevel_camera,1,1);
			#else

			get_angs_to_object(&camera_desired_angles,&ConsoleObject->pos,&endlevel_camera->pos);
			mask = chase_angles(&camera_cur_angles,&camera_desired_angles);
			vm_angles_2_matrix(&endlevel_camera->orient,&camera_cur_angles);

			if ((mask&5) == 5) {

				vms_vector tvec;

				Endlevel_sequence = EL_CHASING;

				//_MARK_("Done outside");//Commented out -KRB

				vm_vec_normalized_dir_quick(&tvec,&station_pos,&ConsoleObject->pos);
				vm_vector_2_matrix(&ConsoleObject->orient,&tvec,&surface_orient.uvec,NULL);

				desired_fly_speed *= 2;

				//mprintf((0,"Switching to chase...\n"));

			}
			#endif

			break;
		}

		case EL_CHASING: {
			fix d,speed_scale;

			#ifdef SLEW_ON
			_do_slew_movement(endlevel_camera,1,1);
			#endif

			get_angs_to_object(&camera_desired_angles,&ConsoleObject->pos,&endlevel_camera->pos);
			chase_angles(&camera_cur_angles,&camera_desired_angles);

			#ifndef SLEW_ON
			vm_angles_2_matrix(&endlevel_camera->orient,&camera_cur_angles);
			#endif

			d = vm_vec_dist_quick(&ConsoleObject->pos,&endlevel_camera->pos);

			speed_scale = fixdiv(d,i2f(0x20));
			if (d<f1_0) d=f1_0;

			get_angs_to_object(&player_dest_angles,&station_pos,&ConsoleObject->pos);
			chase_angles(&player_angles,&player_dest_angles);
			vm_angles_2_matrix(&ConsoleObject->orient,&player_angles);

			vm_vec_scale_add2(&ConsoleObject->pos,&ConsoleObject->orient.fvec,fixmul(FrameTime,cur_fly_speed));
			#ifndef SLEW_ON
			vm_vec_scale_add2(&endlevel_camera->pos,&endlevel_camera->orient.fvec,fixmul(FrameTime,fixmul(speed_scale,cur_fly_speed)));

			if (vm_vec_dist(&ConsoleObject->pos,&station_pos) < i2f(10))
				stop_endlevel_sequence();
			#endif

			break;

		}
		#endif		//ifdef SHORT_SEQUENCE
	}
}
// Returns TRUE if the weapon will never hit the other object.
// If it can it predicts how long until these two objects need
// to be checked and fills the time in in current_pair.
int weapon_will_never_hit( object *obj_weapon, object *other, obj_pair * current_pair )
{

	Assert( obj_weapon->type == OBJ_WEAPON );
	weapon *wp = &Weapons[obj_weapon->instance];
	weapon_info *wip = &Weapon_info[wp->weapon_info_index];

//	mprintf(( "Frame: %d,  Weapon=%d, Other=%d, pair=$%08x\n", G3_frame_count, OBJ_INDEX(weapon), OBJ_INDEX(other), current_pair ));
	

	// Do some checks for weapons that don't turn
	if ( !(wip->wi_flags & WIF_TURNS) )	{

		// This first check is to see if a weapon is behind an object, and they
		// are heading in opposite directions.   If so, we don't need to ever check	
		// them again.   This is only valid for weapons that don't turn. 

		float vdot;
		if (wip->subtype == WP_LASER) {
			vec3d velocity_rel_weapon;
			vm_vec_sub(&velocity_rel_weapon, &obj_weapon->phys_info.vel, &other->phys_info.vel);
			vdot = -vm_vec_dot(&velocity_rel_weapon, &obj_weapon->orient.vec.fvec);
		} else {
			vdot = vm_vec_dot( &other->phys_info.vel, &obj_weapon->phys_info.vel);
		}
		if ( vdot <= 0.0f )	{
			// They're heading in opposite directions...
			// check their positions
			vec3d weapon2other;
			vm_vec_sub( &weapon2other, &other->pos, &obj_weapon->pos );
			float pdot = vm_vec_dot( &obj_weapon->orient.vec.fvec, &weapon2other );
			if ( pdot <= -other->radius )	{
				// The other object is behind the weapon by more than
				// its radius, so it will never hit...
				return 1;
			}
		}

		// FUTURE ENHANCEMENT IDEAS 

		// Given a laser does it hit a slow or not moving object
		// in its life or the next n seconds?  We'd actually need to check the 
		// model for this.
				
	}


	// This check doesn't care about orient, only looks at the maximum speed
	// of the two objects, so it knows that in the next n seconds, they can't
	// go further than some distance, so don't bother checking collisions for 
	// that time.   This is very rough, but is so general that it works for
	// everything and immidiately gets rid of a lot of cases.
	
	if ( current_pair )	{
		// Find the time it will take before these get within each others distances.
		// tmp->next_check_time = timestamp(500);
		//vector	max_vel;			//maximum foward velocity in x,y,z

		float max_vel_weapon, max_vel_other;

		//SUSHI: Fix bug where additive weapon velocity screws up collisions
		//Assumes that weapons which don't home don't change speed, which is currently the case.
		if (!(wip->wi_flags & WIF_TURNS))
			max_vel_weapon = obj_weapon->phys_info.speed;
		else if (wp->lssm_stage==5)
			max_vel_weapon = wip->lssm_stage5_vel;
		else
			max_vel_weapon = wp->weapon_max_vel;

		max_vel_other = other->phys_info.max_vel.xyz.z;
		if (max_vel_other < 10.0f) {
			if ( vm_vec_mag_squared( &other->phys_info.vel ) > 100 ) {
				// bump up velocity from collision
				max_vel_other = vm_vec_mag( &other->phys_info.vel ) + 10.0f;
			} else {
				max_vel_other = 10.0f;		// object may move from collision
			}
		}

		// check weapon that does not turn against sphere expanding at ship maxvel
		// compare (weeapon) ray with expanding sphere (ship) to find earliest possible collision time
		// look for two time solutions to Xw = Xs, where Xw = Xw0 + Vwt*t  Xs = Xs + Vs*(t+dt), where Vs*dt = radius of ship 
		// Since direction of Vs is unknown, solve for (Vs*t) and find norm of both sides
		if ( !(wip->wi_flags & WIF_TURNS) ) {
			vec3d delta_x, laser_vel;
			float a,b,c, delta_x_dot_vl, delta_t;
			float root1, root2, root, earliest_time;

			if (max_vel_weapon == max_vel_other) {
				// this will give us NAN using the below formula, so check every frame
				current_pair->next_check_time = timestamp(0);
				return 0;
			}

			vm_vec_sub( &delta_x, &obj_weapon->pos, &other->pos );
			laser_vel = obj_weapon->phys_info.vel;
			// vm_vec_copy_scale( &laser_vel, &weapon->orient.vec.fvec, max_vel_weapon );
			delta_t = (other->radius + 10.0f) / max_vel_other;		// time to get from center to radius of other obj
			delta_x_dot_vl = vm_vec_dotprod( &delta_x, &laser_vel );

			a = max_vel_weapon*max_vel_weapon - max_vel_other*max_vel_other;
			b = 2.0f * (delta_x_dot_vl - max_vel_other*max_vel_other*delta_t);
			c = vm_vec_mag_squared( &delta_x ) - max_vel_other*max_vel_other*delta_t*delta_t;

			float discriminant = b*b - 4.0f*a*c;
			if ( discriminant < 0) {
				// never hit
				return 1;
			} else {
				root = fl_sqrt( discriminant );
				root1 = (-b + root) / (2.0f * a) * 1000.0f;	// get time in ms
				root2 = (-b - root) / (2.0f * a) * 1000.0f;	// get time in ms
			}

			// standard algorithm
			if (max_vel_weapon > max_vel_other) {
				// find earliest positive time
				if ( root1 > root2 ) {
					float temp = root1;
					root1 = root2;
					root2 = temp;
				}

				if (root1 > 0) {
					earliest_time = root1;
				} else if (root2 > 0) {
					// root1 < 0 and root2 > 0, so we're inside sphere and next check should be next frame
					current_pair->next_check_time = timestamp(0);	// check next time
					return 0;
				} else {
					// both times negative, so never collides
					return 1;
				}
			}
			// need to modify it for weapons that are slower than ships
			else {
				if (root2 > 0) {
					earliest_time = root2;
				} else {
					current_pair->next_check_time = timestamp(0);
					return 0;
				}
			}



			// check if possible collision occurs after weapon expires
			if ( earliest_time > 1000*wp->lifeleft )
				return 1;

			// Allow one worst case frametime to elapse (~5 fps)
			earliest_time -= 200.0f;

			if (earliest_time > 100) {
				current_pair->next_check_time = timestamp( fl2i(earliest_time) );
				return 0;
			} else {
				current_pair->next_check_time = timestamp(0);	// check next time
				return 0;
			}

		} else {

			float dist, max_vel, time;

			max_vel = max_vel_weapon + max_vel_other;

			// suggest that fudge factor for other radius be changed to other_radius + const (~10)
			dist = vm_vec_dist( &other->pos, &obj_weapon->pos ) - (other->radius + 10.0f);
			if ( dist > 0.0f )	{
				time = (dist*1000.0f) / max_vel;
				int time_ms = fl2i(time);

				// check if possible collision occurs after weapon expires
				if ( time_ms > 1000*wp->lifeleft )
					return 1;

				time_ms -= 200;	// Allow at least one worst case frametime to elapse (~5 fps)
						
				if ( time_ms > 100 )	{		// If it takes longer than 1/10th of a second, then delay it
					current_pair->next_check_time = timestamp(time_ms);
					//mprintf(( "Delaying %d ms\n", time_ms ));
					return 0;
				}
			}
			current_pair->next_check_time = timestamp(0);	// check next time

		}
	}

	return 0;
}
// Adds the pair to the pair list
void obj_add_pair( object *A, object *B, int check_time, int add_to_end )
{
	uint ctype;
	int (*check_collision)( obj_pair *pair );
	int swapped = 0;	
	
	check_collision = NULL;

	if ( Num_pairs_allocated == 0 ) return;		// don't have anything to add the pair too

	if ( A==B ) return;		// Don't check collisions with yourself

	if ( !(A->flags&OF_COLLIDES) ) return;		// This object doesn't collide with anything
	if ( !(B->flags&OF_COLLIDES) ) return;		// This object doesn't collide with anything
	
	// Make sure you're not checking a parent with it's kid or vicy-versy
//	if ( A->parent_sig == B->signature && !(A->type == OBJ_SHIP && B->type == OBJ_DEBRIS) ) return;
//	if ( B->parent_sig == A->signature && !(A->type == OBJ_DEBRIS && B->type == OBJ_SHIP) ) return;
	if ( reject_obj_pair_on_parent(A,B) ) {
		return;
	}

	Assert( A->type < 127 );
	Assert( B->type < 127 );

	ctype = COLLISION_OF(A->type,B->type);
	switch( ctype )	{
	case COLLISION_OF(OBJ_WEAPON,OBJ_SHIP):
		swapped = 1;
		check_collision = collide_ship_weapon;
		break;
	case COLLISION_OF(OBJ_SHIP, OBJ_WEAPON):
		check_collision = collide_ship_weapon;
		break;
	case COLLISION_OF(OBJ_DEBRIS, OBJ_WEAPON):
		check_collision = collide_debris_weapon;
		break;
	case COLLISION_OF(OBJ_WEAPON, OBJ_DEBRIS):
		swapped = 1;
		check_collision = collide_debris_weapon;
		break;
	case COLLISION_OF(OBJ_DEBRIS, OBJ_SHIP):
		check_collision = collide_debris_ship;		
		break;
	case COLLISION_OF(OBJ_SHIP, OBJ_DEBRIS):
		check_collision = collide_debris_ship;
		swapped = 1;
		break;
	case COLLISION_OF(OBJ_ASTEROID, OBJ_WEAPON):
		// Only check collision's with player weapons
//		if ( Objects[B->parent].flags & OF_PLAYER_SHIP ) {
			check_collision = collide_asteroid_weapon;
//		}
		break;
	case COLLISION_OF(OBJ_WEAPON, OBJ_ASTEROID):
		swapped = 1;
		// Only check collision's with player weapons
//		if ( Objects[A->parent].flags & OF_PLAYER_SHIP ) {
			check_collision = collide_asteroid_weapon;
//		}
		break;
	case COLLISION_OF(OBJ_ASTEROID, OBJ_SHIP):
		// Only check collisions with player ships
//		if ( B->flags & OF_PLAYER_SHIP )	{
			check_collision = collide_asteroid_ship;
//		}
		break;
	case COLLISION_OF(OBJ_SHIP, OBJ_ASTEROID):
		// Only check collisions with player ships
//		if ( A->flags & OF_PLAYER_SHIP )	{
			check_collision = collide_asteroid_ship;
//		}
		swapped = 1;
		break;
	case COLLISION_OF(OBJ_SHIP,OBJ_SHIP):
		check_collision = collide_ship_ship;
		break;	
	
	case COLLISION_OF(OBJ_BEAM, OBJ_SHIP):
		if(beam_collide_early_out(A, B)){
			return;
		}
		check_collision = beam_collide_ship;
		break;

	case COLLISION_OF(OBJ_BEAM, OBJ_ASTEROID):
		if(beam_collide_early_out(A, B)){
			return;
		}
		check_collision = beam_collide_asteroid;
		break;

	case COLLISION_OF(OBJ_BEAM, OBJ_DEBRIS):
		if(beam_collide_early_out(A, B)){
			return;
		}
		check_collision = beam_collide_debris;
		break;

	case COLLISION_OF(OBJ_BEAM, OBJ_WEAPON):
		if(beam_collide_early_out(A, B)){
			return;
		}		
		check_collision = beam_collide_missile;
		break;

	case COLLISION_OF(OBJ_WEAPON, OBJ_WEAPON): {
		weapon_info *awip, *bwip;
		awip = &Weapon_info[Weapons[A->instance].weapon_info_index];
		bwip = &Weapon_info[Weapons[B->instance].weapon_info_index];

		if ((awip->weapon_hitpoints > 0) || (bwip->weapon_hitpoints > 0)) {
			if (bwip->weapon_hitpoints == 0) {
				check_collision = collide_weapon_weapon;
				swapped=1;
			} else {
				check_collision = collide_weapon_weapon;
			}
		}
/*

		if (awip->subtype != WP_LASER || bwip->subtype != WP_LASER) {
			if (awip->subtype == WP_LASER) {
				if ( bwip->wi_flags & WIF_BOMB ) {
					check_collision = collide_weapon_weapon;
				}
			} else if (bwip->subtype == WP_LASER) {
				if ( awip->wi_flags & WIF_BOMB ) {
					check_collision = collide_weapon_weapon;
					swapped=1;			
				}
			} else {
				if ( (awip->wi_flags&WIF_BOMB) || (bwip->wi_flags&WIF_BOMB) ) {
					check_collision = collide_weapon_weapon;
				}
			}
		}
*/
/*
		int	atype, btype;

		atype = Weapon_info[Weapons[A->instance].weapon_info_index].subtype;
		btype = Weapon_info[Weapons[B->instance].weapon_info_index].subtype;

		if ((atype == WP_LASER) && (btype == WP_MISSILE))
			check_collision = collide_weapon_weapon;
		else if ((atype == WP_MISSILE) && (btype == WP_LASER)) {
			check_collision = collide_weapon_weapon;
			swapped = 1;
		} else if ((atype == WP_MISSILE) && (btype == WP_MISSILE))
			check_collision = collide_weapon_weapon;
*/

		break;
	}

	default:
		return;
	}

	// Swap them if needed
	if ( swapped )	{
		object *tmp = A;
		A = B;
		B = tmp;
	}

	// if there are any more obj_pair checks
	// we should then add function int maybe_not_add_obj_pair()
	// MWA -- 4/1/98 -- I'd do it, but I don't want to bust anything, so I'm doing my stuff here instead :-)
	//if ( MULTIPLAYER_CLIENT && !(Netgame.debug_flags & NETD_FLAG_CLIENT_NODAMAGE)){
		// multiplayer clients will only do ship/ship collisions, and their own ship to boot
	//	if ( check_collision != collide_ship_ship ){
	//		return;
	//	}

	//	if ( (A != Player_obj) && (B != Player_obj) ){
	//		return;
	//	}
	//}	

	// only check debris:weapon collisions for player
	if (check_collision == collide_debris_weapon) {
		// weapon is B
		if ( !(Weapon_info[Weapons[B->instance].weapon_info_index].wi_flags & WIF_TURNS) ) {
		// check for dumbfire weapon
			// check if debris is behind laser
			float vdot;
			if (Weapon_info[Weapons[B->instance].weapon_info_index].subtype == WP_LASER) {
				vec3d velocity_rel_weapon;
				vm_vec_sub(&velocity_rel_weapon, &B->phys_info.vel, &A->phys_info.vel);
				vdot = -vm_vec_dot(&velocity_rel_weapon, &B->orient.vec.fvec);
			} else {
				vdot = vm_vec_dot( &A->phys_info.vel, &B->phys_info.vel);
			}
			if ( vdot <= 0.0f )	{
				// They're heading in opposite directions...
				// check their positions
				vec3d weapon2other;
				vm_vec_sub( &weapon2other, &A->pos, &B->pos );
				float pdot = vm_vec_dot( &B->orient.vec.fvec, &weapon2other );
				if ( pdot <= -A->radius )	{
					// The other object is behind the weapon by more than
					// its radius, so it will never hit...
					return;
				}
			}

			// check dist vs. dist moved during weapon lifetime
			vec3d delta_v;
			vm_vec_sub(&delta_v, &B->phys_info.vel, &A->phys_info.vel);
			if (vm_vec_dist_squared(&A->pos, &B->pos) > (vm_vec_mag_squared(&delta_v)*Weapons[B->instance].lifeleft*Weapons[B->instance].lifeleft)) {
				return;
			}

			// for nonplayer ships, only create collision pair if close enough
			if ( (B->parent >= 0) && !(Objects[B->parent].flags & OF_PLAYER_SHIP) && (vm_vec_dist(&B->pos, &A->pos) < (4.0f*A->radius + 200.0f)) )
				return;
		}
	}

	// don't check same team laser:ship collisions on small ships if not player
	if (check_collision == collide_ship_weapon) {
		// weapon is B
		if ( (B->parent >= 0)
			&& !(Objects[B->parent].flags & OF_PLAYER_SHIP)
			&& (Ships[Objects[B->parent].instance].team == Ships[A->instance].team) 
			&& (Ship_info[Ships[A->instance].ship_info_index].flags & SIF_SMALL_SHIP) 
			&& (Weapon_info[Weapons[B->instance].weapon_info_index].subtype == WP_LASER) ) {
			pairs_not_created++;
			return;
		}
	}

	if ( !check_collision ) return;
	Pairs_created++;

	// At this point, we have determined that collisions between
	// these two should be checked, so add the pair to the
	// collision pair list.

	if ( pair_free_list.next == NULL )	{
		nprintf(( "collision", "Out of object pairs!! Not all collisions will work!\n" ));
		return;
	}

	Num_pairs++;
/*	if (Num_pairs > Num_pairs_hwm) {
		Num_pairs_hwm = Num_pairs;
		//nprintf(("AI", "Num_pairs high water mark = %i\n", Num_pairs_hwm));
	}
*/

	if ( Num_pairs >= (Num_pairs_allocated - 20) ) {
		int i;

		Assert( Obj_pairs != NULL );

		int old_pair_count = Num_pairs_allocated;
		obj_pair *old_pairs_ptr = Obj_pairs;

		// determine where we need to update the "previous" ptrs to
		int prev_free_mark = (pair_free_list.next - old_pairs_ptr);
		int prev_used_mark = (pair_used_list.next - old_pairs_ptr);

		Obj_pairs = (obj_pair*) vm_realloc_q( Obj_pairs, sizeof(obj_pair) * (Num_pairs_allocated + PAIRS_BUMP) );

		// allow us to fail here and only if we don't do we setup the new pairs

		if (Obj_pairs == NULL) {
			// failed, just go back to the way we were and use only the pairs we have already
			Obj_pairs = old_pairs_ptr;
		} else {
			Num_pairs_allocated += PAIRS_BUMP;

			Assert( Obj_pairs != NULL );

			// have to reset all of the "next" ptrs for the old set and handle the new set
			for (i = 0; i < Num_pairs_allocated; i++) {
				if (i >= old_pair_count) {
					memset( &Obj_pairs[i], 0, sizeof(obj_pair) );
					Obj_pairs[i].next = &Obj_pairs[i+1];
				} else {
					if (Obj_pairs[i].next != NULL) {
						// the "next" ptr will end up going backwards for used pairs so we have
						// to allow for that with this craziness...
						int next_mark = (Obj_pairs[i].next - old_pairs_ptr);
						Obj_pairs[i].next = &Obj_pairs[next_mark];
					}

					// catch that last NULL from the previously allocated set
					if ( i == (old_pair_count-1) ) {
						Obj_pairs[i].next = &Obj_pairs[i+1];
					}
				}
			}

			Obj_pairs[Num_pairs_allocated-1].next = NULL;

			// reset the "previous" ptrs
			pair_free_list.next = &Obj_pairs[prev_free_mark];
			pair_used_list.next = &Obj_pairs[prev_used_mark];
		}
	}

	// get a new obj_pair from the free list
	obj_pair * new_pair = pair_free_list.next;
	pair_free_list.next = new_pair->next;

	if ( add_to_end ) {
		obj_pair *last, *tmp;

		last = tmp = pair_used_list.next;
		while( tmp != NULL )	{
			if ( tmp->next == NULL )
				last = tmp;

			tmp = tmp->next;
		}

		if ( last == NULL )
			last = &pair_used_list;
			
		last->next = new_pair;
		Assert(new_pair != NULL);
		new_pair->next = NULL;
	}
	else {
		new_pair->next = pair_used_list.next;
		pair_used_list.next = new_pair;
	}

	A->num_pairs++;
	B->num_pairs++;
	
	new_pair->a = A;
	new_pair->b = B;
	new_pair->check_collision = check_collision;

	if ( check_time == -1 ){
		new_pair->next_check_time = timestamp(0);	// 0 means instantly time out
	} else {
		new_pair->next_check_time = check_time;
	}

}
Example #30
0
//	-----------------------------------------------------------------------------------------------------------
//Simulate a physics object for this frame
void do_physics_sim(object *obj)
{
	int ignore_obj_list[MAX_IGNORE_OBJS],n_ignore_objs;
	int iseg;
	int try_again;
	int fate=0;
	vms_vector frame_vec;			//movement in this frame
	vms_vector new_pos,ipos;		//position after this frame
	int count=0;
	int objnum;
	int WallHitSeg, WallHitSide;
	fvi_info hit_info;
	fvi_query fq;
	vms_vector save_pos;
	int save_seg;
	fix drag;
	fix sim_time;
	vms_vector start_pos;
	int obj_stopped=0;
	fix moved_time; 			//how long objected moved before hit something
	physics_info *pi;
	int orig_segnum = obj->segnum;
	fix PhysTime = (FrameTime<F1_0/30?F1_0/30:FrameTime);

	Assert(obj->movement_type == MT_PHYSICS);

#ifndef NDEBUG
	if (Dont_move_ai_objects)
		if (obj->control_type == CT_AI)
			return;
#endif

	pi = &obj->mtype.phys_info;

	do_physics_sim_rot(obj);

	if (!(pi->velocity.x || pi->velocity.y || pi->velocity.z || pi->thrust.x || pi->thrust.y || pi->thrust.z))
		return;

	objnum = obj-Objects;

	n_phys_segs = 0;

	/* As this engine was not designed for that high FPS as we intend, we use F1_0/30 max. for sim_time to ensure
	   scaling and dot products stay accurate and reliable. The object position intended for this frame will be scaled down later,
	   after the main collision-loop is done.
	   This won't make collision results be equal in all FPS settings, but hopefully more accurate, the higher our FPS are.
	*/
	sim_time = PhysTime; //FrameTime;

	//debug_obj = obj;

#ifdef EXTRA_DEBUG
	//check for correct object segment 
        if(!get_seg_masks(&obj->pos,obj->segnum,0,__FILE__,__LINE__).centermask==0) {
		//Int3();  Removed by Rob 10/5/94
		if (!update_object_seg(obj)) {
			if (!(Game_mode & GM_MULTI))
				Int3();
			compute_segment_center(&obj->pos,&Segments[obj->segnum]);
			obj->pos.x += objnum;
		}
	}
#endif

	start_pos = obj->pos;

	n_ignore_objs = 0;

	Assert(obj->mtype.phys_info.brakes==0);		//brakes not used anymore?

		//if uses thrust, cannot have zero drag
        Assert(!(obj->mtype.phys_info.flags&PF_USES_THRUST) || obj->mtype.phys_info.drag!=0);

	//do thrust & drag
	// NOTE: this always must be dependent on FrameTime, if sim_time differs!
	if ((drag = obj->mtype.phys_info.drag) != 0) {

		int count;
		vms_vector accel;
		fix r,k,have_accel;

		count = FrameTime / FT;
		r = FrameTime % FT;
		k = fixdiv(r,FT);

		if (obj->mtype.phys_info.flags & PF_USES_THRUST) {

			vm_vec_copy_scale(&accel,&obj->mtype.phys_info.thrust,fixdiv(f1_0,obj->mtype.phys_info.mass));
			have_accel = (accel.x || accel.y || accel.z);

			while (count--) {
				if (have_accel)
					vm_vec_add2(&obj->mtype.phys_info.velocity,&accel);

				vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-drag);
			}

			//do linear scale on remaining bit of time

			vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&accel,k);
			if (drag)
				vm_vec_scale(&obj->mtype.phys_info.velocity,f1_0-fixmul(k,drag));
		}
		else if (drag)
		{
			fix total_drag=f1_0;

			while (count--)
				total_drag = fixmul(total_drag,f1_0-drag);

			//do linear scale on remaining bit of time

			total_drag = fixmul(total_drag,f1_0-fixmul(k,drag));

			vm_vec_scale(&obj->mtype.phys_info.velocity,total_drag);
		}
	}

	do {
		try_again = 0;

		//Move the object
		vm_vec_copy_scale(&frame_vec, &obj->mtype.phys_info.velocity, sim_time);

		if ( (frame_vec.x==0) && (frame_vec.y==0) && (frame_vec.z==0) )	
			break;

		count++;

		//	If retry count is getting large, then we are trying to do something stupid.
		if (count > 8) break; // in original code this was 3 for all non-player objects. still leave us some limit in case fvi goes apeshit.

		vm_vec_add(&new_pos,&obj->pos,&frame_vec);

		ignore_obj_list[n_ignore_objs] = -1;

		fq.p0						= &obj->pos;
		fq.startseg				= obj->segnum;
		fq.p1						= &new_pos;
		fq.rad					= obj->size;
		fq.thisobjnum			= objnum;
		fq.ignore_obj_list	= ignore_obj_list;
		fq.flags					= FQ_CHECK_OBJS;

		if (obj->type == OBJ_WEAPON)
			fq.flags |= FQ_TRANSPOINT;

		if (obj->type == OBJ_PLAYER)
			fq.flags |= FQ_GET_SEGLIST;

		fate = find_vector_intersection(&fq,&hit_info);
		//	Matt: Mike's hack.
		if (fate == HIT_OBJECT) {
			object	*objp = &Objects[hit_info.hit_object];

			if (((objp->type == OBJ_WEAPON) && (objp->id == PROXIMITY_ID)) || objp->type == OBJ_POWERUP) // do not increase count for powerups since they *should* not change our movement
				count--;
		}

#ifndef NDEBUG
		if (fate == HIT_BAD_P0) {
			Int3();
		}
#endif

		if (obj->type == OBJ_PLAYER) {
			int i;

			if (n_phys_segs && phys_seglist[n_phys_segs-1]==hit_info.seglist[0])
				n_phys_segs--;

			for (i=0;(i<hit_info.n_segs) && (n_phys_segs<MAX_FVI_SEGS-1);  )
				phys_seglist[n_phys_segs++] = hit_info.seglist[i++];
		}

		ipos = hit_info.hit_pnt;
		iseg = hit_info.hit_seg;
		WallHitSide = hit_info.hit_side;
		WallHitSeg = hit_info.hit_side_seg;

		if (iseg==-1) {		//some sort of horrible error
			if (obj->type == OBJ_WEAPON)
				obj->flags |= OF_SHOULD_BE_DEAD;
			break;
		}

		Assert(!((fate==HIT_WALL) && ((WallHitSeg == -1) || (WallHitSeg > Highest_segment_index))));

		//if(!get_seg_masks(&hit_info.hit_pnt,hit_info.hit_seg,0).centermask==0)
		//	Int3();

		save_pos = obj->pos;			//save the object's position
		save_seg = obj->segnum;

		// update object's position and segment number
		obj->pos = ipos;

		if ( iseg != obj->segnum )
			obj_relink(objnum, iseg );

		//if start point not in segment, move object to center of segment
                if (get_seg_masks(&obj->pos,obj->segnum,0,__FILE__,__LINE__).centermask!=0) {
			int n;

			if ((n=find_object_seg(obj))==-1) {
				//Int3();
				if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) {
					obj->pos = obj->last_pos;
					obj_relink(objnum, n );
				}
				else {
					compute_segment_center(&obj->pos,&Segments[obj->segnum]);
					obj->pos.x += objnum;
				}
				if (obj->type == OBJ_WEAPON)
					obj->flags |= OF_SHOULD_BE_DEAD;
			}
			return;
		}

		//calulate new sim time
		{
			//vms_vector moved_vec;
			vms_vector moved_vec_n;
			fix attempted_dist,actual_dist;

			actual_dist = vm_vec_normalized_dir(&moved_vec_n,&obj->pos,&save_pos);

			if (fate==HIT_WALL && vm_vec_dot(&moved_vec_n,&frame_vec) < 0) {		//moved backwards

				//don't change position or sim_time

				obj->pos = save_pos;
		
				//iseg = obj->segnum;		//don't change segment

				obj_relink(objnum, save_seg );

				moved_time = 0;
			}
			else {
				fix old_sim_time;

				attempted_dist = vm_vec_mag(&frame_vec);

				old_sim_time = sim_time;

				sim_time = fixmuldiv(sim_time,attempted_dist-actual_dist,attempted_dist);

				moved_time = old_sim_time - sim_time;

				if (sim_time < 0 || sim_time>old_sim_time) {
					sim_time = old_sim_time;
					//WHY DOES THIS HAPPEN??

					moved_time = 0;
				}
			}
		}


		switch( fate )		{

			case HIT_WALL:		{
				vms_vector moved_v;
				fix hit_speed=0, wall_part=0;

				// Find hit speed	

				vm_vec_sub(&moved_v,&obj->pos,&save_pos);

				wall_part = vm_vec_dot(&moved_v,&hit_info.hit_wallnorm);

				if ((wall_part != 0 && moved_time>0 && (hit_speed=-fixdiv(wall_part,moved_time))>0) || obj->type == OBJ_WEAPON || obj->type == OBJ_DEBRIS)
					collide_object_with_wall( obj, hit_speed, WallHitSeg, WallHitSide, &hit_info.hit_pnt );
				if (obj->type == OBJ_PLAYER)
					scrape_player_on_wall(obj, WallHitSeg, WallHitSide, &hit_info.hit_pnt );

				Assert( WallHitSeg > -1 );				
				Assert( WallHitSide > -1 );				

				if ( !(obj->flags&OF_SHOULD_BE_DEAD) )	{


					Assert(! (obj->mtype.phys_info.flags & PF_STICK && obj->mtype.phys_info.flags & PF_BOUNCE));	//can't be bounce and stick

					if (obj->mtype.phys_info.flags & PF_STICK) {		//stop moving

						add_stuck_object(obj, WallHitSeg, WallHitSide);

						vm_vec_zero(&obj->mtype.phys_info.velocity);
						obj_stopped = 1;
						try_again = 0;
					}
					else {					// Slide object along wall

						//We're constrained by wall, so subtract wall part from 
						//velocity vector

						wall_part = vm_vec_dot(&hit_info.hit_wallnorm,&obj->mtype.phys_info.velocity);

						// if wall_part, make sure the value is sane enough to get usable velocity computed
						if (wall_part < 0 && wall_part > -f1_0) wall_part = -f1_0;
						if (wall_part > 0 && wall_part < f1_0) wall_part = f1_0;

						if (obj->mtype.phys_info.flags & PF_BOUNCE)		//bounce off wall
							wall_part *= 2;	//Subtract out wall part twice to achieve bounce

						vm_vec_scale_add2(&obj->mtype.phys_info.velocity,&hit_info.hit_wallnorm,-wall_part);

						try_again = 1;
					}
				}

				break;
			}

			case HIT_OBJECT:		{
				vms_vector old_vel;

				// Mark the hit object so that on a retry the fvi code
				// ignores this object.

				Assert(hit_info.hit_object != -1);
				//	Calculcate the hit point between the two objects.
				{	vms_vector	*ppos0, *ppos1, pos_hit;
					fix			size0, size1;
					ppos0 = &Objects[hit_info.hit_object].pos;
					ppos1 = &obj->pos;
					size0 = Objects[hit_info.hit_object].size;
					size1 = obj->size;
					Assert(size0+size1 != 0);	// Error, both sizes are 0, so how did they collide, anyway?!?
					//vm_vec_scale(vm_vec_sub(&pos_hit, ppos1, ppos0), fixdiv(size0, size0 + size1));
					//vm_vec_add2(&pos_hit, ppos0);
					vm_vec_sub(&pos_hit, ppos1, ppos0);
					vm_vec_scale_add(&pos_hit,ppos0,&pos_hit,fixdiv(size0, size0 + size1));

					old_vel = obj->mtype.phys_info.velocity;

					collide_two_objects( obj, &Objects[hit_info.hit_object], &pos_hit);

				}

				// Let object continue its movement
				if ( !(obj->flags&OF_SHOULD_BE_DEAD)  )	{
					//obj->pos = save_pos;

					if (obj->mtype.phys_info.flags&PF_PERSISTENT || (old_vel.x == obj->mtype.phys_info.velocity.x && old_vel.y == obj->mtype.phys_info.velocity.y && old_vel.z == obj->mtype.phys_info.velocity.z)) {
						//if (Objects[hit_info.hit_object].type == OBJ_POWERUP)
							ignore_obj_list[n_ignore_objs++] = hit_info.hit_object;
						try_again = 1;
					}
				}

				break;
			}	
			case HIT_NONE:		
				break;

#ifndef NDEBUG
			case HIT_BAD_P0:
				Int3();		// Unexpected collision type: start point not in specified segment.
				break;
			default:
				// Unknown collision type returned from find_vector_intersection!!
				Int3();
				break;
#endif
		}
	} while ( try_again );

	//	Pass retry count info to AI.
	if (obj->control_type == CT_AI) {
		if (count > 0) {
			Ai_local_info[objnum].retry_count = count-1;
			Total_retries += count-1;
			Total_sims++;
		}
	}

	// As sim_time may not base on FrameTime, scale actual object position to get accurate movement
	if (PhysTime/FrameTime > 0)
	{
		vms_vector md;
		vm_vec_sub(&md, &obj->pos, &start_pos);
		vm_vec_scale(&md, F1_0/((float)PhysTime/FrameTime));
		vm_vec_add(&obj->pos,&start_pos, &md);
		//check for and update correct object segment
		if(!get_seg_masks(&obj->pos, obj->segnum, 0, __FILE__, __LINE__).centermask == 0)
		{
			if (!update_object_seg(obj)) {
				if (!(Game_mode & GM_MULTI))
					Int3();
				compute_segment_center(&obj->pos,&Segments[obj->segnum]);
				obj->pos.x += objnum;
			}
		}
	}

	// After collision with objects and walls, set velocity from actual movement
	if (!obj_stopped
		&& ((obj->type == OBJ_PLAYER) || (obj->type == OBJ_ROBOT) || (obj->type == OBJ_DEBRIS)) 
		&& ((fate == HIT_WALL) || (fate == HIT_OBJECT) || (fate == HIT_BAD_P0))
		)
	{	
		vms_vector moved_vec;
		vm_vec_sub(&moved_vec,&obj->pos,&start_pos);
		vm_vec_copy_scale(&obj->mtype.phys_info.velocity,&moved_vec,fixdiv(f1_0,FrameTime));
	}

	fix_illegal_wall_intersection(obj, &start_pos);

	//Assert(check_point_in_seg(&obj->pos,obj->segnum,0).centermask==0);

	//if (obj->control_type == CT_FLYING)
	if (obj->mtype.phys_info.flags & PF_LEVELLING)
		do_physics_align_object( obj );


	//hack to keep player from going through closed doors
	if (obj->type==OBJ_PLAYER && obj->segnum!=orig_segnum && (!cheats.ghostphysics) ) {
		int sidenum;

		sidenum = find_connect_side(&Segments[obj->segnum],&Segments[orig_segnum]);

		if (sidenum != -1) {

			if (! (WALL_IS_DOORWAY(&Segments[orig_segnum],sidenum) & WID_FLY_FLAG)) {
				side *s;
				int vertnum,num_faces,i;
				fix dist;
				int vertex_list[6];

				//bump object back

				s = &Segments[orig_segnum].sides[sidenum];

                                create_abs_vertex_lists( &num_faces, vertex_list, orig_segnum, sidenum, __FILE__,__LINE__);

				//let's pretend this wall is not triangulated
				vertnum = vertex_list[0];
				for (i=1;i<4;i++)
					if (vertex_list[i] < vertnum)
						vertnum = vertex_list[i];

#ifdef COMPACT_SEGS
					{
						vms_vector _vn;
						get_side_normal(&Segments[orig_segnum], sidenum, 0, &_vn );
						dist = vm_dist_to_plane(&start_pos, &_vn, &Vertices[vertnum]);
						vm_vec_scale_add(&obj->pos,&start_pos,&_vn,obj->size-dist);
					}
#else
					dist = vm_dist_to_plane(&start_pos, &s->normals[0], &Vertices[vertnum]);
					vm_vec_scale_add(&obj->pos,&start_pos,&s->normals[0],obj->size-dist);
#endif
				update_object_seg(obj);

			}
		}
	}

//--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL 	#ifndef NDEBUG
	//if end point not in segment, move object to last pos, or segment center
        if (get_seg_masks(&obj->pos,obj->segnum,0,__FILE__,__LINE__).centermask!=0) {
		if (find_object_seg(obj)==-1) {
			int n;

			//Int3();
			if (obj->type==OBJ_PLAYER && (n=find_point_seg(&obj->last_pos,obj->segnum))!=-1) {
				obj->pos = obj->last_pos;
				obj_relink(objnum, n );
			}
			else {
				compute_segment_center(&obj->pos,&Segments[obj->segnum]);
				obj->pos.x += objnum;
			}
			if (obj->type == OBJ_WEAPON)
				obj->flags |= OF_SHOULD_BE_DEAD;
		}
	}
//--WE ALWYS WANT THIS IN, MATT AND MIKE DECISION ON 12/10/94, TWO MONTHS AFTER FINAL 	#endif
}