void model_collide_sortnorm(ubyte * p) { int frontlist = w(p+36); int backlist = w(p+40); int prelist = w(p+44); int postlist = w(p+48); int onlist = w(p+52); vec3d hitpos; if ( Mc_pm->version >= 2000 ) { if ( mc_ray_boundingbox( vp(p+56), vp(p+68), &Mc_p0, &Mc_direction, &hitpos) ) { if ( !(Mc->flags & MC_CHECK_RAY) && (vm_vec_dist(&hitpos, &Mc_p0) > Mc_mag) ) { return; } } else { return; } } if (prelist) model_collide_sub(p+prelist); if (backlist) model_collide_sub(p+backlist); if (onlist) model_collide_sub(p+onlist); if (frontlist) model_collide_sub(p+frontlist); if (postlist) model_collide_sub(p+postlist); }
// checks a vector collision against a ships shield (if it has shield points defined). void mc_check_shield() { int i; if ( Mc_pm->shield.ntris < 1 ) return; if (Mc_pm->shield_collision_tree) { mc_check_sldc(0); // see if we hit the SLDC } else { int o; for (o=0; o<8; o++ ) { model_octant * poct1 = &Mc_pm->octants[o]; if (!mc_ray_boundingbox( &poct1->min, &poct1->max, &Mc_p0, &Mc_direction, NULL )) { continue; } for (i = 0; i < poct1->nshield_tris; i++) { shield_tri * tri = poct1->shield_tris[i]; mc_shield_check_common(tri); } } }//model has shield_collsion_tree }
bool mc_check_sldc(int offset) { if (offset > Mc_pm->sldc_size-5) //no way is this big enough return false; char *type_p = (char *)(Mc_pm->shield_collision_tree+offset); // not used //int *size_p = (int *)(Mc_pm->shield_collision_tree+offset+1); // split and polygons vec3d *minbox_p = (vec3d*)(Mc_pm->shield_collision_tree+offset+5); vec3d *maxbox_p = (vec3d*)(Mc_pm->shield_collision_tree+offset+17); // split unsigned int *front_offset_p = (unsigned int*)(Mc_pm->shield_collision_tree+offset+29); unsigned int *back_offset_p = (unsigned int*)(Mc_pm->shield_collision_tree+offset+33); // polygons unsigned int *num_polygons_p = (unsigned int*)(Mc_pm->shield_collision_tree+offset+29); unsigned int *shld_polys = (unsigned int*)(Mc_pm->shield_collision_tree+offset+33); // see if it fits inside our bbox if (!mc_ray_boundingbox( minbox_p, maxbox_p, &Mc_p0, &Mc_direction, NULL )) { return false; } if (*type_p == 0) // SPLIT { return mc_check_sldc(offset+*front_offset_p) || mc_check_sldc(offset+*back_offset_p); } else { // poly list shield_tri * tri; for (unsigned int i = 0; i < *num_polygons_p; i++) { tri = &Mc_pm->shield.tris[shld_polys[i]]; mc_shield_check_common(tri); } // for (unsigned int i = 0; i < leaf->num_polygons; i++) } // shouldn't be reached return false; }
//calls the object interpreter to render an object. The object renderer //is really a seperate pipeline. returns true if drew int model_collide_sub(void *model_ptr ) { ubyte *p = (ubyte *)model_ptr; int chunk_type, chunk_size; vec3d hitpos; chunk_type = w(p); chunk_size = w(p+4); while (chunk_type != OP_EOF) { // mprintf(( "Processing chunk type %d, len=%d\n", chunk_type, chunk_size )); switch (chunk_type) { case OP_DEFPOINTS: model_collide_defpoints(p); break; case OP_FLATPOLY: model_collide_flatpoly(p); break; case OP_TMAPPOLY: model_collide_tmappoly(p); break; case OP_SORTNORM: model_collide_sortnorm(p); break; case OP_BOUNDBOX: if ( mc_ray_boundingbox( vp(p+8), vp(p+20), &Mc_p0, &Mc_direction, &hitpos ) ) { if ( !(Mc->flags & MC_CHECK_RAY) && (vm_vec_dist(&hitpos, &Mc_p0) > Mc_mag) ) { // The ray isn't long enough to intersect the bounding box return 1; } } else { return 1; } break; default: mprintf(( "Bad chunk type %d, len=%d in model_collide_sub\n", chunk_type, chunk_size )); Int3(); // Bad chunk type! return 0; } p += chunk_size; chunk_type = w(p); chunk_size = w(p+4); } return 1; }
void model_collide_bsp(bsp_collision_tree *tree, int node_index) { if ( tree->node_list == NULL || tree->n_verts <= 0) { return; } bsp_collision_node *node = &tree->node_list[node_index]; vec3d hitpos; // check the bounding box of this node. if it passes, check left and right children if ( mc_ray_boundingbox( &node->min, &node->max, &Mc_p0, &Mc_direction, &hitpos ) ) { if ( !(Mc->flags & MC_CHECK_RAY) && (vm_vec_dist(&hitpos, &Mc_p0) > Mc_mag) ) { // The ray isn't long enough to intersect the bounding box return; } if ( node->leaf >= 0 ) { model_collide_bsp_poly(tree, node->leaf); } else { if ( node->back >= 0 ) model_collide_bsp(tree, node->back); if ( node->front >= 0 ) model_collide_bsp(tree, node->front); } } }
// This function recursively checks a submodel and its children // for a collision with a vector. void mc_check_subobj( int mn ) { vec3d tempv; vec3d hitpt; // used in bounding box check bsp_info * sm; int i; Assert( mn >= 0 ); Assert( mn < Mc_pm->n_models ); if ( (mn < 0) || (mn>=Mc_pm->n_models) ) return; sm = &Mc_pm->submodel[mn]; if (sm->no_collisions) return; // don't do collisions if (sm->nocollide_this_only) goto NoHit; // Don't collide for this model, but keep checking others // Rotate the world check points into the current subobject's // frame of reference. // After this block, Mc_p0, Mc_p1, Mc_direction, and Mc_mag are correct // and relative to this subobjects' frame of reference. vm_vec_sub(&tempv, Mc->p0, &Mc_base); vm_vec_rotate(&Mc_p0, &tempv, &Mc_orient); vm_vec_sub(&tempv, Mc->p1, &Mc_base); vm_vec_rotate(&Mc_p1, &tempv, &Mc_orient); vm_vec_sub(&Mc_direction, &Mc_p1, &Mc_p0); // bail early if no ray exists if ( IS_VEC_NULL(&Mc_direction) ) { return; } if (Mc_pm->detail[0] == mn) { // Quickly bail if we aren't inside the full model bbox if (!mc_ray_boundingbox( &Mc_pm->mins, &Mc_pm->maxs, &Mc_p0, &Mc_direction, NULL)) { return; } // If we are checking the root submodel, then we might want to check // the shield at this point if ((Mc->flags & MC_CHECK_SHIELD) && (Mc_pm->shield.ntris > 0 )) { mc_check_shield(); return; } } if (!(Mc->flags & MC_CHECK_MODEL)) { return; } Mc_submodel = mn; // Check if the ray intersects this subobject's bounding box if ( mc_ray_boundingbox(&sm->min, &sm->max, &Mc_p0, &Mc_direction, &hitpt) ) { if (Mc->flags & MC_ONLY_BOUND_BOX) { float dist = vm_vec_dist( &Mc_p0, &hitpt ); // If the ray is behind the plane there is no collision if (dist < 0.0f) { goto NoHit; } // The ray isn't long enough to intersect the plane if ( !(Mc->flags & MC_CHECK_RAY) && (dist > Mc_mag) ) { goto NoHit; } // If the ray hits, but a closer intersection has already been found, return if ( Mc->num_hits && (dist >= Mc->hit_dist) ) { goto NoHit; } Mc->hit_dist = dist; Mc->hit_point = hitpt; Mc->hit_submodel = Mc_submodel; Mc->hit_bitmap = -1; Mc->num_hits++; } else { // The ray intersects this bounding box, so we have to check all the // polygons in this submodel. if ( Cmdline_old_collision_sys ) { model_collide_sub(sm->bsp_data); } else { if (Mc->lod > 0 && sm->num_details > 0) { bsp_info *lod_sm = sm; for (i = Mc->lod - 1; i >= 0; i--) { if (sm->details[i] != -1) { lod_sm = &Mc_pm->submodel[sm->details[i]]; //mprintf(("Checking %s collision for %s using %s instead\n", Mc_pm->filename, sm->name, lod_sm->name)); break; } } model_collide_bsp(model_get_bsp_collision_tree(lod_sm->collision_tree_index), 0); } else { model_collide_bsp(model_get_bsp_collision_tree(sm->collision_tree_index), 0); } } } } NoHit: // If we're only checking one submodel, return if (Mc->flags & MC_SUBMODEL) { return; } // If this subobject doesn't have any children, we're done checking it. if ( sm->num_children < 1 ) return; // Save instance (Mc_orient, Mc_base, Mc_point_base) matrix saved_orient = Mc_orient; vec3d saved_base = Mc_base; // Check all of this subobject's children i = sm->first_child; while ( i >= 0 ) { angles angs; bool blown_off; bool collision_checked; bsp_info * csm = &Mc_pm->submodel[i]; if ( Mc_pmi ) { angs = Mc_pmi->submodel[i].angs; blown_off = Mc_pmi->submodel[i].blown_off; collision_checked = Mc_pmi->submodel[i].collision_checked; } else { angs = csm->angs; blown_off = csm->blown_off ? true : false; collision_checked = false; } // Don't check it or its children if it is destroyed // or if it's set to no collision if ( !blown_off && !collision_checked && !csm->no_collisions ) { if ( Mc_pmi ) { Mc_orient = Mc_pmi->submodel[i].mc_orient; Mc_base = Mc_pmi->submodel[i].mc_base; vm_vec_add2(&Mc_base, Mc->pos); } else { //instance for this subobject matrix tm = IDENTITY_MATRIX; vm_vec_unrotate(&Mc_base, &csm->offset, &saved_orient ); vm_vec_add2(&Mc_base, &saved_base ); if( vm_matrix_same(&tm, &csm->orientation)) { // if submodel orientation matrix is identity matrix then don't bother with matrix ops vm_angles_2_matrix(&tm, &angs); } else { matrix rotation_matrix = csm->orientation; vm_rotate_matrix_by_angles(&rotation_matrix, &angs); matrix inv_orientation; vm_copy_transpose(&inv_orientation, &csm->orientation); vm_matrix_x_matrix(&tm, &rotation_matrix, &inv_orientation); } vm_matrix_x_matrix(&Mc_orient, &saved_orient, &tm); } mc_check_subobj( i ); } i = csm->next_sibling; } }