// output top and bottom vectors // fvec == forward vector (eye viewpoint basically. in world coords) // pos == world coordinate of the point we're calculating "around" // w == width of the diff between top and bottom around pos void trail_calc_facing_pts( vec3d *top, vec3d *bot, vec3d *fvec, vec3d *pos, float w ) { vec3d uvec, rvec; vm_vec_sub( &rvec, &Eye_position, pos ); if (!IS_VEC_NULL(&rvec)) vm_vec_normalize( &rvec ); vm_vec_crossprod(&uvec,fvec,&rvec); if (!IS_VEC_NULL(&uvec)) vm_vec_normalize(&uvec); vm_vec_scale_add( top, pos, &uvec, w * 0.5f ); vm_vec_scale_add( bot, pos, &uvec, -w * 0.5f ); }
// Create a grid // *forward is vector pointing forward // *right is vector pointing right // *center is center point of grid // length is length of grid // width is width of grid // square_size is size of a grid square // For example: // *forward = (0.0, 0.0, 1.0) // *right = (1.0, 0.0, 0.0) // *center = (0.0, 0.0, 0.0) // nrows = 10 // ncols = 50.0 // square_size = 10.0 // will generate a grid of squares 10 long by 5 wide. // Each grid square will be 10.0 x 10.0 units. // The center of the grid will be at the global origin. // The grid will be parallel to the xz plane (because the normal is 0,1,0). // (In fact, it will be the xz plane because it is centered on the origin.) // // Stuffs grid in *gridp. If gridp == NULL, mallocs and returns a grid. grid *create_grid(grid *gridp, vector *forward, vector *right, vector *center, int nrows, int ncols, float square_size) { int i, ncols2, nrows2, d = 1; vector dfvec, drvec, cur, cur2, tvec, uvec, save, save2; Assert(square_size > 0.0); if (double_fine_gridlines) d = 2; if (gridp == NULL) gridp = (grid *) malloc(sizeof(grid)); Assert(gridp); gridp->center = *center; gridp->square_size = square_size; // Create the plane equation. Assert(!IS_VEC_NULL(forward)); Assert(!IS_VEC_NULL(right)); vm_vec_copy_normalize(&dfvec, forward); vm_vec_copy_normalize(&drvec, right); vm_vec_cross(&uvec, &dfvec, &drvec); Assert(!IS_VEC_NULL(&uvec)); gridp->gmatrix.v.uvec = uvec; gridp->planeD = -(center->xyz.x * uvec.xyz.x + center->xyz.y * uvec.xyz.y + center->xyz.z * uvec.xyz.z); Assert(!_isnan(gridp->planeD)); gridp->gmatrix.v.fvec = dfvec; gridp->gmatrix.v.rvec = drvec; vm_vec_scale(&dfvec, square_size); vm_vec_scale(&drvec, square_size); vm_vec_scale_add(&cur, center, &dfvec, (float) -nrows * d / 2); vm_vec_scale_add2(&cur, &drvec, (float) -ncols * d / 2); vm_vec_scale_add(&cur2, center, &dfvec, (float) -nrows * 5 / 2); vm_vec_scale_add2(&cur2, &drvec, (float) -ncols * 5 / 2); save = cur; save2 = cur2; gridp->ncols = ncols; gridp->nrows = nrows; ncols2 = ncols / 2; nrows2 = nrows / 2; Assert(ncols < MAX_GRIDLINE_POINTS && nrows < MAX_GRIDLINE_POINTS); // Create the points along the edges of the grid, so we can just draw lines // between them to form the grid. for (i=0; i<=ncols*d; i++) { gridp->gpoints1[i] = cur; // small, dark gridline points vm_vec_scale_add(&tvec, &cur, &dfvec, (float) nrows * d); gridp->gpoints2[i] = tvec; vm_vec_add2(&cur, &drvec); } for (i=0; i<=ncols2; i++) { gridp->gpoints5[i] = cur2; // large, brighter gridline points vm_vec_scale_add(&tvec, &cur2, &dfvec, (float) nrows2 * 10); gridp->gpoints6[i] = tvec; vm_vec_scale_add2(&cur2, &drvec, 10.0f); } cur = save; cur2 = save2; for (i=0; i<=nrows*d; i++) { gridp->gpoints3[i] = cur; // small, dark gridline points vm_vec_scale_add(&tvec, &cur, &drvec, (float) ncols * d); gridp->gpoints4[i] = tvec; vm_vec_add2(&cur, &dfvec); } for (i=0; i<=nrows2; i++) { gridp->gpoints7[i] = cur2; // large, brighter gridline points vm_vec_scale_add(&tvec, &cur2, &drvec, (float) ncols2 * 10); gridp->gpoints8[i] = tvec; vm_vec_scale_add2(&cur2, &dfvec, 10.0f); } return gridp; }
// 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; } }