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