FS2_Open
Open source remastering of the Freespace 2 engine
modelcollide.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (C) Volition, Inc. 1999. All rights reserved.
3  *
4  * All source code herein is the property of Volition, Inc. You may not sell
5  * or otherwise commercially exploit the source or things you created based on the
6  * source.
7  *
8 */
9 
10 
11 
12 
13 #define MODEL_LIB
14 
15 #include "cmdline/cmdline.h"
16 #include "graphics/tmapper.h"
17 #include "math/fvi.h"
18 #include "math/vecmat.h"
19 #include "model/model.h"
20 #include "model/modelsinc.h"
21 
22 
23 
24 #define TOL 1E-4
25 #define DIST_TOL 1.0
26 
27 // Some global variables that get set by model_collide and are used internally for
28 // checking a collision rather than passing a bunch of parameters around. These are
29 // not persistant between calls to model_collide
30 
31 static mc_info *Mc; // The mc_info passed into model_collide
32 
33 static polymodel *Mc_pm; // The polygon model we're checking
34 static int Mc_submodel; // The current submodel we're checking
35 
36 static polymodel_instance *Mc_pmi;
37 
38 static matrix Mc_orient; // A matrix to rotate a world point into the current
39  // submodel's frame of reference.
40 static vec3d Mc_base; // A point used along with Mc_orient.
41 
42 static vec3d Mc_p0; // The ray origin rotated into the current submodel's frame of reference
43 static vec3d Mc_p1; // The ray end rotated into the current submodel's frame of reference
44 static float Mc_mag; // The length of the ray
45 static vec3d Mc_direction; // A vector from the ray's origin to its end, in the current submodel's frame of reference
46 
47 static vec3d **Mc_point_list = NULL; // A pointer to the current submodel's vertex list
48 
49 static float Mc_edge_time;
50 
51 
53 {
54  if (Mc_point_list != NULL) {
55  vm_free(Mc_point_list);
56  Mc_point_list = NULL;
57  }
58 }
59 
60 // allocate the point list
61 // NOTE: SHOULD ONLY EVER BE CALLED FROM model_allocate_interp_data()!!!
63 {
64  Assert( n_points > 0 );
65 
66  if (Mc_point_list != NULL) {
67  vm_free(Mc_point_list);
68  Mc_point_list = NULL;
69  }
70 
71  Mc_point_list = (vec3d**) vm_malloc( sizeof(vec3d *) * n_points );
72 
73  Verify( Mc_point_list != NULL );
74 }
75 
76 // Returns non-zero if vector from p0 to pdir
77 // intersects the bounding box.
78 // hitpos could be NULL, so don't fill it if it is.
79 int mc_ray_boundingbox( vec3d *min, vec3d *max, vec3d * p0, vec3d *pdir, vec3d *hitpos )
80 {
81 
82  vec3d tmp_hitpos;
83  if ( hitpos == NULL ) {
84  hitpos = &tmp_hitpos;
85  }
86 
87 
88  if ( Mc->flags & MC_CHECK_SPHERELINE ) {
89 
90  // In the case of a sphere, just increase the size of the box by the radius
91  // of the sphere in all directions.
92 
93  vec3d sphere_mod_min, sphere_mod_max;
94 
95  sphere_mod_min.xyz.x = min->xyz.x - Mc->radius;
96  sphere_mod_max.xyz.x = max->xyz.x + Mc->radius;
97  sphere_mod_min.xyz.y = min->xyz.y - Mc->radius;
98  sphere_mod_max.xyz.y = max->xyz.y + Mc->radius;
99  sphere_mod_min.xyz.z = min->xyz.z - Mc->radius;
100  sphere_mod_max.xyz.z = max->xyz.z + Mc->radius;
101 
102  return fvi_ray_boundingbox( &sphere_mod_min, &sphere_mod_max, p0, pdir, hitpos );
103  } else {
104  return fvi_ray_boundingbox( min, max, p0, pdir, hitpos );
105  }
106 }
107 
108 
109 
110 // -----
111 // mc_check_face
112 // nv -- number of vertices
113 // verts -- actual vertices
114 // plane_pnt -- A point on the plane. Could probably use the first vertex.
115 // plane_norm -- normal of the plane
116 // uvl_list -- list of uv coords for the poly.
117 // ntmap -- The tmap index into the model's textures array.
118 //
119 // detects whether or not a vector has collided with a polygon. vector points stored in global
120 // Mc_p0 and Mc_p1. Results stored in global mc_info * Mc.
121 
122 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)
123 {
124  vec3d hit_point;
125  float dist;
126  float u, v;
127 
128  // Check to see if poly is facing away from ray. If so, don't bother
129  // checking it.
130  if (vm_vec_dot(&Mc_direction,plane_norm) > 0.0f) {
131  return;
132  }
133 
134  // Find the intersection of this ray with the plane that the poly
135  dist = fvi_ray_plane(NULL, plane_pnt, plane_norm, &Mc_p0, &Mc_direction, 0.0f);
136 
137  if ( dist < 0.0f ) return; // If the ray is behind the plane there is no collision
138  if ( !(Mc->flags & MC_CHECK_RAY) && (dist > 1.0f) ) return; // The ray isn't long enough to intersect the plane
139 
140  // If the ray hits, but a closer intersection has already been found, return
141  if ( Mc->num_hits && (dist >= Mc->hit_dist ) ) return;
142 
143  // Find the hit point
144  vm_vec_scale_add( &hit_point, &Mc_p0, &Mc_direction, dist );
145 
146  // Check to see if the point of intersection is on the plane. If so, this
147  // also finds the uv's where the ray hit.
148  if ( fvi_point_face(&hit_point, nv, verts, plane_norm, &u,&v, uvl_list ) ) {
149  Mc->hit_dist = dist;
150 
151  Mc->hit_point = hit_point;
152  Mc->hit_submodel = Mc_submodel;
153 
154  Mc->hit_normal = *plane_norm;
155 
156  if ( uvl_list ) {
157  Mc->hit_u = u;
158  Mc->hit_v = v;
159  if ( ntmap < 0 ) {
160  Mc->hit_bitmap = -1;
161  } else {
162  Mc->hit_bitmap = Mc_pm->maps[ntmap].textures[TM_BASE_TYPE].GetTexture();
163  }
164  }
165 
166  if(ntmap >= 0){
167  Mc->t_poly = poly;
168  Mc->f_poly = NULL;
169  } else {
170  Mc->t_poly = NULL;
171  Mc->f_poly = poly;
172  }
173 
174  Mc->bsp_leaf = bsp_leaf;
175 
176 // mprintf(( "Bing!\n" ));
177 
178  Mc->num_hits++;
179  }
180 }
181 
182 // ----------------------------------------------------------------------------------------------------------
183 // check face with spheres
184 //
185 // inputs: nv => number of vertices
186 // verts => array of vertices
187 // plane_pnt => center point in plane (about which radius is measured)
188 // face_rad => radius of face
189 // plane_norm => normal of face
190 static void mc_check_sphereline_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)
191 {
192  vec3d hit_point;
193  float u, v;
194  float delta_t; // time sphere takes to cross from one side of plane to the other
195  float face_t; // time at which face touches plane
196  // NOTE all times are normalized so that t = 1.0 at the end of the frame
197  int check_face = 1; // assume we'll check the face.
198  int check_edges = 1; // assume we'll check the edges.
199 
200  // Check to see if poly is facing away from ray. If so, don't bother
201  // checking it.
202 
203  if (vm_vec_dot(&Mc_direction,plane_norm) > 0.0f) {
204  return;
205  }
206 
207  // Find the intersection of this sphere with the plane of the poly
208  if ( !fvi_sphere_plane( &hit_point, &Mc_p0, &Mc_direction, Mc->radius, plane_norm, plane_pnt, &face_t, &delta_t ) ) {
209  return;
210  }
211 
212  // If the ray is behind the plane there is no collision
213  if (face_t > 1.0f) {
214  check_face = 0;
215  check_edges = 0;
216  } else if (face_t < 0.0f) {
217  check_face = 0;
218 
219  // check whether sphere can hit edge in allowed time range
220  if ( (face_t + delta_t) < 0.0f)
221  check_edges = 0;
222  }
223 
224  // If the ray hits, but a closer intersection has already been found, don't check face
225  if ( Mc->num_hits && (face_t >= Mc->hit_dist ) ) {
226  check_face = 0; // The ray isn't long enough to intersect the plane
227  }
228 
229 
230  //vec3d temp_sphere;
231  //vec3d temp_dir;
232  //float temp_dist;
233  // DA 11/5/97 Above is used to test distance between hit_point and sphere_hit_point.
234  // This can be as large as 0.003 on a unit sphere. I suspect that with larger spheres,
235  // both the relative and absolute error decrease, but this should still be checked for the
236  // case of larger spheres (about 5-10 units). The error also depends on the geometry of the
237  // object we're colliding against, but I think to a lesser degree.
238 
239  if ( check_face ) {
240  // Find the time of the sphere surface touches the plane
241  // If this is within the collision window, check to see if we hit a face
242  if ( fvi_point_face(&hit_point, nv, verts, plane_norm, &u, &v, uvl_list) ) {
243 
244  Mc->hit_dist = face_t;
245  Mc->hit_point = hit_point;
246  Mc->hit_normal = *plane_norm;
247  Mc->hit_submodel = Mc_submodel;
248  Mc->edge_hit = 0;
249 
250  if ( uvl_list ) {
251  Mc->hit_u = u;
252  Mc->hit_v = v;
253  if ( ntmap < 0 ) {
254  Mc->hit_bitmap = -1;
255  } else {
256  Mc->hit_bitmap = Mc_pm->maps[ntmap].textures[TM_BASE_TYPE].GetTexture();
257  }
258  }
259 
260  if(ntmap >= 0){
261  Mc->t_poly = poly;
262  Mc->f_poly = NULL;
263  } else {
264  Mc->t_poly = NULL;
265  Mc->f_poly = poly;
266  }
267 
268  Mc->bsp_leaf = bsp_leaf;
269 
270  Mc->num_hits++;
271  check_edges = 0;
272  /*
273  vm_vec_scale_add( &temp_sphere, &Mc_p0, &Mc_direction, Mc->hit_dist );
274  temp_dist = vm_vec_dist( &temp_sphere, &hit_point );
275  if ( (temp_dist - DIST_TOL > Mc->radius) || (temp_dist + DIST_TOL < Mc->radius) ) {
276  // get Andsager
277  //mprintf(("Estimated radius error: Estimate %f, actual %f Mc->radius\n", temp_dist, Mc->radius));
278  }
279  vm_vec_sub( &temp_dir, &hit_point, &temp_sphere );
280  // Assert( vm_vec_dot( &temp_dir, &Mc_direction ) > 0 );
281  */
282  }
283  }
284 
285 
286  if ( check_edges ) {
287  // Either (face_t) is out of range or we miss the face
288  // Check for sphere hitting edge
289 
290  // If checking shields, we *still* need to check edges
291 
292  // this is where we need another test to cull checking for edges
293  // PUT TEST HERE
294 
295  // check each edge to see if we hit, find the closest edge
296  // Mc->hit_dist stores the best edge time of *all* faces
297  float sphere_time;
298  if ( fvi_polyedge_sphereline(&hit_point, &Mc_p0, &Mc_direction, Mc->radius, nv, verts, &sphere_time)) {
299  Assert( sphere_time >= 0.0f );
300  /*
301  vm_vec_scale_add( &temp_sphere, &Mc_p0, &Mc_direction, sphere_time );
302  temp_dist = vm_vec_dist( &temp_sphere, &hit_point );
303  if ( (temp_dist - DIST_TOL > Mc->radius) || (temp_dist + DIST_TOL < Mc->radius) ) {
304  // get Andsager
305  //mprintf(("Estimated radius error: Estimate %f, actual %f Mc->radius\n", temp_dist, Mc->radius));
306  }
307  vm_vec_sub( &temp_dir, &hit_point, &temp_sphere );
308 // Assert( vm_vec_dot( &temp_dir, &Mc_direction ) > 0 );
309  */
310 
311  if ( (Mc->num_hits==0) || (sphere_time < Mc->hit_dist) ) {
312  // This is closer than best so far
313  Mc->hit_dist = sphere_time;
314  Mc->hit_point = hit_point;
315  Mc->hit_submodel = Mc_submodel;
316  Mc->edge_hit = 1;
317  if ( ntmap < 0 ) {
318  Mc->hit_bitmap = -1;
319  } else {
320  Mc->hit_bitmap = Mc_pm->maps[ntmap].textures[TM_BASE_TYPE].GetTexture();
321  }
322 
323  if(ntmap >= 0){
324  Mc->t_poly = poly;
325  Mc->f_poly = NULL;
326  } else {
327  Mc->t_poly = NULL;
328  Mc->f_poly = poly;
329  }
330 
331  Mc->num_hits++;
332 
333  // nprintf(("Physics", "edge sphere time: %f, normal: (%f, %f, %f) hit_point: (%f, %f, %f)\n", sphere_time,
334  // Mc->hit_normal.xyz.x, Mc->hit_normal.xyz.y, Mc->hit_normal.xyz.z,
335  // hit_point.xyz.x, hit_point.xyz.y, hit_point.xyz.z));
336  } else { // Not best so far
337  Assert(Mc->num_hits>0);
338  Mc->num_hits++;
339  }
340  }
341  }
342 }
343 
344 
345 // Point list
346 // +0 int id
347 // +4 int size
348 // +8 int n_verts
349 // +12 int n_norms
350 // +16 int offset from start of chunk to vertex data
351 // +20 n_verts*char norm_counts
352 // +offset vertex data. Each vertex n is a point followed by norm_counts[n] normals.
354 {
355  int n;
356  int nverts = w(p+8);
357  int offset = w(p+16);
358 
359  ubyte * normcount = p+20;
360  vec3d *src = vp(p+offset);
361 
362  Assert( Mc_point_list != NULL );
363 
364  for (n=0; n<nverts; n++ ) {
365  Mc_point_list[n] = src;
366 
367  src += normcount[n]+1;
368  }
369 }
370 
372 {
373  int n;
374  int nverts = w(p+8);
375  int offset = w(p+16);
376 
377  ubyte * normcount = p+20;
378  vec3d *src = vp(p+offset);
379 
381 
382  Assert( Mc_point_list != NULL );
383 
384  for (n=0; n<nverts; n++ ) {
385  Mc_point_list[n] = src;
386 
387  src += normcount[n]+1;
388  }
389 
390  return nverts;
391 }
392 
393 // Flat Poly
394 // +0 int id
395 // +4 int size
396 // +8 vec3d normal
397 // +20 vec3d center
398 // +32 float radius
399 // +36 int nverts
400 // +40 byte red
401 // +41 byte green
402 // +42 byte blue
403 // +43 byte pad
404 // +44 nverts*int vertlist
406 {
407  int i;
408  int nv;
410  short *verts;
411 
412  nv = w(p+36);
413 
414  if ( nv <= 0 )
415  return;
416 
417  if ( nv > TMAP_MAX_VERTS ) {
418  Int3();
419  return;
420  }
421 
422  verts = (short *)(p+44);
423 
424  for (i=0;i<nv;i++) {
425  points[i] = Mc_point_list[verts[i*2]];
426  }
427 
428  if ( Mc->flags & MC_CHECK_SPHERELINE ) {
429  mc_check_sphereline_face(nv, points, vp(p+20), fl(p+32), vp(p+8), NULL, -1, p, NULL);
430  } else {
431  mc_check_face(nv, points, vp(p+20), fl(p+32), vp(p+8), NULL, -1, p, NULL);
432  }
433 }
434 
435 
436 // Textured Poly
437 // +0 int id
438 // +4 int size
439 // +8 vec3d normal
440 // +20 vec3d normal_point
441 // +32 int tmp = 0
442 // +36 int nverts
443 // +40 int tmap_num
444 // +44 nverts*(model_tmap_vert) vertlist (n,u,v)
446 {
447  int i;
448  int nv;
449  uv_pair uvlist[TMAP_MAX_VERTS];
451  model_tmap_vert *verts;
452 
453  nv = w(p+36);
454 
455  if ( nv <= 0 )
456  return;
457 
458  if ( nv > TMAP_MAX_VERTS ) {
459  Int3();
460  return;
461  }
462 
463  int tmap_num = w(p+40);
464  Assert(tmap_num >= 0 && tmap_num < MAX_MODEL_TEXTURES); // Goober5000
465 
466  if ( (!(Mc->flags & MC_CHECK_INVISIBLE_FACES)) && (Mc_pm->maps[tmap_num].textures[TM_BASE_TYPE].GetTexture() < 0) ) {
467  // Don't check invisible polygons.
468  //SUSHI: Unless $collide_invisible is set.
469  if (!(Mc_pm->submodel[Mc_submodel].collide_invisible))
470  return;
471  }
472 
473  verts = (model_tmap_vert *)(p+44);
474 
475  for (i=0;i<nv;i++) {
476  points[i] = Mc_point_list[verts[i].vertnum];
477  uvlist[i].u = verts[i].u;
478  uvlist[i].v = verts[i].v;
479  }
480 
481  if ( Mc->flags & MC_CHECK_SPHERELINE ) {
482  mc_check_sphereline_face(nv, points, vp(p+20), fl(p+32), vp(p+8), uvlist, tmap_num, p, NULL);
483  } else {
484  mc_check_face(nv, points, vp(p+20), fl(p+32), vp(p+8), uvlist, tmap_num, p, NULL);
485  }
486 }
487 
488 
489 // Sortnorms
490 // +0 int id
491 // +4 int size
492 // +8 vec3d normal
493 // +20 vec3d center
494 // +32 float radius
495 // 36 int front offset
496 // 40 int back offset
497 // 44 int prelist offset
498 // 48 int postlist offset
499 // 52 int online offset
500 
501 int model_collide_sub( void *model_ptr );
502 
504 {
505  int frontlist = w(p+36);
506  int backlist = w(p+40);
507  int prelist = w(p+44);
508  int postlist = w(p+48);
509  int onlist = w(p+52);
510  vec3d hitpos;
511 
512  if ( Mc_pm->version >= 2000 ) {
513  if ( mc_ray_boundingbox( vp(p+56), vp(p+68), &Mc_p0, &Mc_direction, &hitpos) ) {
514  if ( !(Mc->flags & MC_CHECK_RAY) && (vm_vec_dist(&hitpos, &Mc_p0) > Mc_mag) ) {
515  return;
516  }
517  } else {
518  return;
519  }
520  }
521 
522  if (prelist) model_collide_sub(p+prelist);
523  if (backlist) model_collide_sub(p+backlist);
524  if (onlist) model_collide_sub(p+onlist);
525  if (frontlist) model_collide_sub(p+frontlist);
526  if (postlist) model_collide_sub(p+postlist);
527 }
528 
529 //calls the object interpreter to render an object. The object renderer
530 //is really a seperate pipeline. returns true if drew
531 int model_collide_sub(void *model_ptr )
532 {
533  ubyte *p = (ubyte *)model_ptr;
534  int chunk_type, chunk_size;
535  vec3d hitpos;
536 
537  chunk_type = w(p);
538  chunk_size = w(p+4);
539 
540  while (chunk_type != OP_EOF) {
541 
542 // mprintf(( "Processing chunk type %d, len=%d\n", chunk_type, chunk_size ));
543 
544  switch (chunk_type) {
545  case OP_DEFPOINTS: model_collide_defpoints(p); break;
546  case OP_FLATPOLY: model_collide_flatpoly(p); break;
547  case OP_TMAPPOLY: model_collide_tmappoly(p); break;
548  case OP_SORTNORM: model_collide_sortnorm(p); break;
549  case OP_BOUNDBOX:
550  if ( mc_ray_boundingbox( vp(p+8), vp(p+20), &Mc_p0, &Mc_direction, &hitpos ) ) {
551  if ( !(Mc->flags & MC_CHECK_RAY) && (vm_vec_dist(&hitpos, &Mc_p0) > Mc_mag) ) {
552  // The ray isn't long enough to intersect the bounding box
553  return 1;
554  }
555  } else {
556  return 1;
557  }
558  break;
559  default:
560  mprintf(( "Bad chunk type %d, len=%d in model_collide_sub\n", chunk_type, chunk_size ));
561  Int3(); // Bad chunk type!
562  return 0;
563  }
564  p += chunk_size;
565  chunk_type = w(p);
566  chunk_size = w(p+4);
567  }
568  return 1;
569 }
570 
571 void model_collide_bsp_poly(bsp_collision_tree *tree, int leaf_index)
572 {
573  int i;
574  int tested_leaf = leaf_index;
575  uv_pair uvlist[TMAP_MAX_VERTS];
577 
578  while ( tested_leaf >= 0 ) {
579  bsp_collision_leaf *leaf = &tree->leaf_list[tested_leaf];
580 
581  bool flat_poly = false;
582  int vert_start = leaf->vert_start;
583  int nv = leaf->num_verts;
584 
585  if ( leaf->tmap_num < MAX_MODEL_TEXTURES ) {
586  if ( (!(Mc->flags & MC_CHECK_INVISIBLE_FACES)) && (Mc_pm->maps[leaf->tmap_num].textures[TM_BASE_TYPE].GetTexture() < 0) ) {
587  // Don't check invisible polygons.
588  //SUSHI: Unless $collide_invisible is set.
589  if (!(Mc_pm->submodel[Mc_submodel].collide_invisible))
590  return;
591  }
592  } else {
593  flat_poly = true;
594  }
595 
596  int vert_num;
597  for ( i = 0; i < nv; ++i ) {
598  vert_num = tree->vert_list[vert_start+i].vertnum;
599  points[i] = &tree->point_list[vert_num];
600 
601  uvlist[i].u = tree->vert_list[vert_start+i].u;
602  uvlist[i].v = tree->vert_list[vert_start+i].v;
603  }
604 
605  if ( flat_poly ) {
606  if ( Mc->flags & MC_CHECK_SPHERELINE ) {
607  mc_check_sphereline_face(nv, points, &leaf->plane_pnt, leaf->face_rad, &leaf->plane_norm, NULL, -1, NULL, leaf);
608  } else {
609  mc_check_face(nv, points, &leaf->plane_pnt, leaf->face_rad, &leaf->plane_norm, NULL, -1, NULL, leaf);
610  }
611  } else {
612  if ( Mc->flags & MC_CHECK_SPHERELINE ) {
613  mc_check_sphereline_face(nv, points, &leaf->plane_pnt, leaf->face_rad, &leaf->plane_norm, uvlist, leaf->tmap_num, NULL, leaf);
614  } else {
615  mc_check_face(nv, points, &leaf->plane_pnt, leaf->face_rad, &leaf->plane_norm, uvlist, leaf->tmap_num, NULL, leaf);
616  }
617  }
618 
619  tested_leaf = leaf->next;
620  }
621 }
622 
623 void model_collide_bsp(bsp_collision_tree *tree, int node_index)
624 {
625  if ( tree->node_list == NULL || tree->n_verts <= 0) {
626  return;
627  }
628 
629  bsp_collision_node *node = &tree->node_list[node_index];
630  vec3d hitpos;
631 
632  // check the bounding box of this node. if it passes, check left and right children
633  if ( mc_ray_boundingbox( &node->min, &node->max, &Mc_p0, &Mc_direction, &hitpos ) ) {
634  if ( !(Mc->flags & MC_CHECK_RAY) && (vm_vec_dist(&hitpos, &Mc_p0) > Mc_mag) ) {
635  // The ray isn't long enough to intersect the bounding box
636  return;
637  }
638 
639  if ( node->leaf >= 0 ) {
640  model_collide_bsp_poly(tree, node->leaf);
641  } else {
642  if ( node->back >= 0 ) model_collide_bsp(tree, node->back);
643  if ( node->front >= 0 ) model_collide_bsp(tree, node->front);
644  }
645  }
646 }
647 
649 {
650  ubyte *p = (ubyte *)model_ptr;
651 
652  int i;
653  int nv;
654  model_tmap_vert *verts;
655 
656  nv = w(p+36);
657 
658  if ( nv < 0 ) return;
659 
660  if ( nv > TMAP_MAX_VERTS ) {
661  Int3();
662  return;
663  }
664 
665  int tmap_num = w(p+40);
666 
667  Assert(tmap_num >= 0 && tmap_num < MAX_MODEL_TEXTURES);
668 
669  verts = (model_tmap_vert *)(p+44);
670 
671  leaf->tmap_num = (ubyte)tmap_num;
672  leaf->num_verts = (ubyte)nv;
673  leaf->vert_start = vert_buffer->size();
674 
675  vec3d *plane_pnt = vp(p+20);
676  float face_rad = fl(p+32);
677  vec3d *plane_norm = vp(p+8);
678 
679  leaf->plane_pnt = *plane_pnt;
680  leaf->face_rad = face_rad;
681  leaf->plane_norm = *plane_norm;
682 
683  for ( i = 0; i < nv; ++i ) {
684  vert_buffer->push_back(verts[i]);
685  }
686 }
687 
689 {
690  ubyte *p = (ubyte *)model_ptr;
691 
692  int i;
693  int nv;
694  short *verts;
695 
696  nv = w(p+36);
697 
698  if ( nv < 0 ) return;
699 
700  if ( nv > TMAP_MAX_VERTS ) {
701  Int3();
702  return;
703  }
704 
705  verts = (short *)(p+44);
706 
707  leaf->tmap_num = 255;
708  leaf->num_verts = (ubyte)nv;
709  leaf->vert_start = vert_buffer->size();
710 
711  vec3d *plane_pnt = vp(p+20);
712  float face_rad = fl(p+32);
713  vec3d *plane_norm = vp(p+8);
714 
715  leaf->plane_pnt = *plane_pnt;
716  leaf->face_rad = face_rad;
717  leaf->plane_norm = *plane_norm;
718 
719  model_tmap_vert vert;
720 
721  for ( i = 0; i < nv; ++i ) {
722  vert.vertnum = verts[i*2];
723  vert.normnum = 0;
724  vert.u = 0.0f;
725  vert.v = 0.0f;
726 
727  vert_buffer->push_back(vert);
728  }
729 }
730 
731 void model_collide_parse_bsp(bsp_collision_tree *tree, void *model_ptr, int version)
732 {
733  ubyte *p = (ubyte *)model_ptr;
734  ubyte *next_p;
735 
736  int chunk_type = w(p);
737  int chunk_size = w(p+4);
738 
739  int next_chunk_type;
740  int next_chunk_size;
741 
742  Assert(chunk_type == OP_DEFPOINTS);
743 
744  int n_verts = model_collide_parse_bsp_defpoints(p);
745 
746  if ( n_verts <= 0) {
747  tree->point_list = NULL;
748  tree->n_verts = 0;
749 
750  tree->n_nodes = 0;
751  tree->node_list = NULL;
752 
753  tree->n_leaves = 0;
754  tree->leaf_list = NULL;
755 
756  // finally copy the vert list.
757  tree->vert_list = NULL;
758 
759  return;
760  }
761 
762  p += chunk_size;
763 
764  bsp_collision_node new_node;
765  bsp_collision_leaf new_leaf;
766 
767  SCP_vector<bsp_collision_node> node_buffer;
768  SCP_vector<bsp_collision_leaf> leaf_buffer;
769  SCP_vector<model_tmap_vert> vert_buffer;
770 
771  SCP_map<size_t, ubyte*> bsp_datap;
772 
773  node_buffer.push_back(new_node);
774 
775  size_t i = 0;
776  vec3d *min;
777  vec3d *max;
778 
779  bsp_datap[i] = p;
780 
781  while ( i < node_buffer.size() ) {
782  p = bsp_datap[i];
783 
784  chunk_type = w(p);
785  chunk_size = w(p+4);
786 
787  switch ( chunk_type ) {
788  case OP_SORTNORM:
789  if ( version >= 2000 ) {
790  min = vp(p+56);
791  max = vp(p+68);
792 
793  node_buffer[i].min = *min;
794  node_buffer[i].max = *max;
795  }
796 
797  node_buffer[i].leaf = -1;
798  node_buffer[i].front = -1;
799  node_buffer[i].back = -1;
800 
801  if ( w(p+36) ) {
802  next_chunk_type = w(p+w(p+36));
803 
804  if ( next_chunk_type != OP_EOF ) {
805  node_buffer.push_back(new_node);
806  node_buffer[i].front = (node_buffer.size() - 1);
807  bsp_datap[node_buffer[i].front] = p+w(p+36);
808  }
809  }
810 
811  if ( w(p+40) ) {
812  next_chunk_type = w(p+w(p+40));
813 
814  if ( next_chunk_type != OP_EOF ) {
815  node_buffer.push_back(new_node);
816  node_buffer[i].back = (node_buffer.size() - 1);
817  bsp_datap[node_buffer[i].back] = p+w(p+40);
818  }
819  }
820 
821  next_p = p + chunk_size;
822  next_chunk_type = w(next_p);
823 
824  Assert( next_chunk_type == OP_EOF );
825 
826  ++i;
827  break;
828  case OP_BOUNDBOX:
829  min = vp(p+8);
830  max = vp(p+20);
831 
832  node_buffer[i].min = *min;
833  node_buffer[i].max = *max;
834 
835  node_buffer[i].front = -1;
836  node_buffer[i].back = -1;
837  node_buffer[i].leaf = -1;
838 
839  next_p = p + chunk_size;
840  next_chunk_type = w(next_p);
841  next_chunk_size = w(next_p+4);
842 
843  if ( next_chunk_type != OP_EOF && (next_chunk_type == OP_TMAPPOLY || next_chunk_type == OP_FLATPOLY ) ) {
844  new_leaf.next = -1;
845 
846  node_buffer[i].leaf = leaf_buffer.size(); // get index of where our poly list starts in the leaf buffer
847 
848  while ( next_chunk_type != OP_EOF ) {
849  if ( next_chunk_type == OP_TMAPPOLY ) {
850 
851  model_collide_parse_bsp_tmappoly(&new_leaf, &vert_buffer, next_p);
852 
853  leaf_buffer.push_back(new_leaf);
854 
855  leaf_buffer.back().next = leaf_buffer.size();
856  } else if ( next_chunk_type == OP_FLATPOLY ) {
857  model_collide_parse_bsp_flatpoly(&new_leaf, &vert_buffer, next_p);
858 
859  leaf_buffer.push_back(new_leaf);
860 
861  leaf_buffer.back().next = leaf_buffer.size();
862  } else {
863  Int3();
864  }
865 
866  next_p += next_chunk_size;
867  next_chunk_type = w(next_p);
868  next_chunk_size = w(next_p+4);
869  }
870 
871  leaf_buffer.back().next = -1;
872  }
873 
874  Assert(next_chunk_type == OP_EOF);
875 
876  ++i;
877  break;
878  }
879  }
880 
881  // copy point list
882  Assert(n_verts != -1);
883 
884  tree->point_list = (vec3d*)vm_malloc(sizeof(vec3d) * n_verts);
885 
886  for ( i = 0; i < (size_t)n_verts; ++i ) {
887  tree->point_list[i] = *Mc_point_list[i];
888  }
889 
890  tree->n_verts = n_verts;
891 
892  // copy node info. this might be a good time to organize the nodes into a cache efficient tree layout.
893  tree->n_nodes = node_buffer.size();
894  tree->node_list = (bsp_collision_node*)vm_malloc(sizeof(bsp_collision_node) * node_buffer.size());
895  memcpy(tree->node_list, &node_buffer[0], sizeof(bsp_collision_node) * node_buffer.size());
896  node_buffer.clear();
897 
898  // copy leaves.
899  tree->n_leaves = leaf_buffer.size();
900  tree->leaf_list = (bsp_collision_leaf*)vm_malloc(sizeof(bsp_collision_leaf) * leaf_buffer.size());
901  memcpy(tree->leaf_list, &leaf_buffer[0], sizeof(bsp_collision_leaf) * leaf_buffer.size());
902  leaf_buffer.clear();
903 
904  // finally copy the vert list.
905  tree->vert_list = (model_tmap_vert*)vm_malloc(sizeof(model_tmap_vert) * vert_buffer.size());
906  memcpy(tree->vert_list, &vert_buffer[0], sizeof(model_tmap_vert) * vert_buffer.size());
907  vert_buffer.clear();
908 }
909 
911 {
912  vec3d * points[3];
913  vec3d hitpoint;
914 
915  float dist;
916  float sphere_check_closest_shield_dist = FLT_MAX;
917 
918  // Check to see if Mc_pmly is facing away from ray. If so, don't bother
919  // checking it.
920  if (vm_vec_dot(&Mc_direction,&tri->norm) > 0.0f) {
921  return false;
922  }
923  // get the vertices in the form the next function wants them
924  for (int j = 0; j < 3; j++ )
925  points[j] = &Mc_pm->shield.verts[tri->verts[j]].pos;
926 
927  if (!(Mc->flags & MC_CHECK_SPHERELINE) ) { // Don't do this test for sphere colliding against shields
928  // Find the intersection of this ray with the plane that the Mc_pmly
929  // lies in
930  dist = fvi_ray_plane(NULL, points[0],&tri->norm,&Mc_p0,&Mc_direction,0.0f);
931 
932  if ( dist < 0.0f ) return false; // If the ray is behind the plane there is no collision
933  if ( !(Mc->flags & MC_CHECK_RAY) && (dist > 1.0f) ) return false; // The ray isn't long enough to intersect the plane
934 
935  // Find the hit Mc_pmint
936  vm_vec_scale_add( &hitpoint, &Mc_p0, &Mc_direction, dist );
937 
938  // Check to see if the Mc_pmint of intersection is on the plane. If so, this
939  // also finds the uv's where the ray hit.
940  if ( fvi_point_face(&hitpoint, 3, points, &tri->norm, NULL,NULL,NULL ) ) {
941  Mc->hit_dist = dist;
942  Mc->shield_hit_tri = tri - Mc_pm->shield.tris;
943  Mc->hit_point = hitpoint;
944  Mc->hit_normal = tri->norm;
945  Mc->hit_submodel = -1;
946  Mc->num_hits++;
947  return true; // We hit, so we're done
948  }
949  } else { // Sphere check against shield
950  // This needs to look at *all* shield tris and not just return after the first hit
951 
952  // HACK HACK!! The 10000.0 is the face radius, I didn't know this,
953  // so I'm assume 10000 would be as big as ever.
954  mc_check_sphereline_face(3, points, points[0], 10000.0f, &tri->norm, NULL, 0, NULL, NULL);
955  if (Mc->num_hits && Mc->hit_dist < sphere_check_closest_shield_dist) {
956 
957  // same behavior whether face or edge
958  // normal, edge_hit, hit_point all updated thru sphereline_face
959  sphere_check_closest_shield_dist = Mc->hit_dist;
960  Mc->shield_hit_tri = tri - Mc_pm->shield.tris;
961  Mc->hit_submodel = -1;
962  Mc->num_hits++;
963  return true; // We hit, so we're done
964  }
965  } // Mc->flags & MC_CHECK_SPHERELINE else
966 
967  return false;
968 }
969 
971 {
972  if (offset > Mc_pm->sldc_size-5) //no way is this big enough
973  return false;
974  char *type_p = (char *)(Mc_pm->shield_collision_tree+offset);
975 
976  // not used
977  //int *size_p = (int *)(Mc_pm->shield_collision_tree+offset+1);
978  // split and polygons
979  vec3d *minbox_p = (vec3d*)(Mc_pm->shield_collision_tree+offset+5);
980  vec3d *maxbox_p = (vec3d*)(Mc_pm->shield_collision_tree+offset+17);
981 
982  // split
983  unsigned int *front_offset_p = (unsigned int*)(Mc_pm->shield_collision_tree+offset+29);
984  unsigned int *back_offset_p = (unsigned int*)(Mc_pm->shield_collision_tree+offset+33);
985 
986  // polygons
987  unsigned int *num_polygons_p = (unsigned int*)(Mc_pm->shield_collision_tree+offset+29);
988 
989  unsigned int *shld_polys = (unsigned int*)(Mc_pm->shield_collision_tree+offset+33);
990 
991 
992 
993  // see if it fits inside our bbox
994  if (!mc_ray_boundingbox( minbox_p, maxbox_p, &Mc_p0, &Mc_direction, NULL )) {
995  return false;
996  }
997 
998  if (*type_p == 0) // SPLIT
999  {
1000  return mc_check_sldc(offset+*front_offset_p) || mc_check_sldc(offset+*back_offset_p);
1001  }
1002  else
1003  {
1004  // poly list
1005  shield_tri * tri;
1006  for (unsigned int i = 0; i < *num_polygons_p; i++)
1007  {
1008  tri = &Mc_pm->shield.tris[shld_polys[i]];
1009 
1011 
1012  } // for (unsigned int i = 0; i < leaf->num_polygons; i++)
1013  }
1014 
1015  // shouldn't be reached
1016  return false;
1017 }
1018 
1019 // checks a vector collision against a ships shield (if it has shield points defined).
1021 {
1022  int i;
1023 
1024 
1025  if ( Mc_pm->shield.ntris < 1 )
1026  return;
1027  if (Mc_pm->shield_collision_tree)
1028  {
1029  mc_check_sldc(0); // see if we hit the SLDC
1030  }
1031  else
1032  {
1033  int o;
1034  for (o=0; o<8; o++ ) {
1035  model_octant * poct1 = &Mc_pm->octants[o];
1036 
1037  if (!mc_ray_boundingbox( &poct1->min, &poct1->max, &Mc_p0, &Mc_direction, NULL )) {
1038  continue;
1039  }
1040 
1041  for (i = 0; i < poct1->nshield_tris; i++) {
1042  shield_tri * tri = poct1->shield_tris[i];
1044  }
1045  }
1046  }//model has shield_collsion_tree
1047 }
1048 
1049 
1050 // This function recursively checks a submodel and its children
1051 // for a collision with a vector.
1052 void mc_check_subobj( int mn )
1053 {
1054  vec3d tempv;
1055  vec3d hitpt; // used in bounding box check
1056  bsp_info * sm;
1057  int i;
1058 
1059  Assert( mn >= 0 );
1060  Assert( mn < Mc_pm->n_models );
1061  if ( (mn < 0) || (mn>=Mc_pm->n_models) ) return;
1062 
1063  sm = &Mc_pm->submodel[mn];
1064  if (sm->no_collisions) return; // don't do collisions
1065  if (sm->nocollide_this_only) goto NoHit; // Don't collide for this model, but keep checking others
1066 
1067  // Rotate the world check points into the current subobject's
1068  // frame of reference.
1069  // After this block, Mc_p0, Mc_p1, Mc_direction, and Mc_mag are correct
1070  // and relative to this subobjects' frame of reference.
1071  vm_vec_sub(&tempv, Mc->p0, &Mc_base);
1072  vm_vec_rotate(&Mc_p0, &tempv, &Mc_orient);
1073 
1074  vm_vec_sub(&tempv, Mc->p1, &Mc_base);
1075  vm_vec_rotate(&Mc_p1, &tempv, &Mc_orient);
1076  vm_vec_sub(&Mc_direction, &Mc_p1, &Mc_p0);
1077 
1078  // bail early if no ray exists
1079  if ( IS_VEC_NULL(&Mc_direction) ) {
1080  return;
1081  }
1082 
1083  if (Mc_pm->detail[0] == mn) {
1084  // Quickly bail if we aren't inside the full model bbox
1085  if (!mc_ray_boundingbox( &Mc_pm->mins, &Mc_pm->maxs, &Mc_p0, &Mc_direction, NULL)) {
1086  return;
1087  }
1088 
1089  // If we are checking the root submodel, then we might want to check
1090  // the shield at this point
1091  if ((Mc->flags & MC_CHECK_SHIELD) && (Mc_pm->shield.ntris > 0 )) {
1092  mc_check_shield();
1093  return;
1094  }
1095  }
1096 
1097  if (!(Mc->flags & MC_CHECK_MODEL)) {
1098  return;
1099  }
1100 
1101  Mc_submodel = mn;
1102 
1103  // Check if the ray intersects this subobject's bounding box
1104  if ( mc_ray_boundingbox(&sm->min, &sm->max, &Mc_p0, &Mc_direction, &hitpt) ) {
1105  if (Mc->flags & MC_ONLY_BOUND_BOX) {
1106  float dist = vm_vec_dist( &Mc_p0, &hitpt );
1107 
1108  // If the ray is behind the plane there is no collision
1109  if (dist < 0.0f) {
1110  goto NoHit;
1111  }
1112 
1113  // The ray isn't long enough to intersect the plane
1114  if ( !(Mc->flags & MC_CHECK_RAY) && (dist > Mc_mag) ) {
1115  goto NoHit;
1116  }
1117 
1118  // If the ray hits, but a closer intersection has already been found, return
1119  if ( Mc->num_hits && (dist >= Mc->hit_dist) ) {
1120  goto NoHit;
1121  }
1122 
1123  Mc->hit_dist = dist;
1124  Mc->hit_point = hitpt;
1125  Mc->hit_submodel = Mc_submodel;
1126  Mc->hit_bitmap = -1;
1127  Mc->num_hits++;
1128  } else {
1129  // The ray intersects this bounding box, so we have to check all the
1130  // polygons in this submodel.
1131  if ( Cmdline_old_collision_sys ) {
1133  } else {
1134  if (Mc->lod > 0 && sm->num_details > 0) {
1135  bsp_info *lod_sm = sm;
1136 
1137  for (i = Mc->lod - 1; i >= 0; i--) {
1138  if (sm->details[i] != -1) {
1139  lod_sm = &Mc_pm->submodel[sm->details[i]];
1140 
1141  //mprintf(("Checking %s collision for %s using %s instead\n", Mc_pm->filename, sm->name, lod_sm->name));
1142  break;
1143  }
1144  }
1145 
1147  } else {
1149  }
1150  }
1151  }
1152  }
1153 
1154 NoHit:
1155 
1156  // If we're only checking one submodel, return
1157  if (Mc->flags & MC_SUBMODEL) {
1158  return;
1159  }
1160 
1161 
1162  // If this subobject doesn't have any children, we're done checking it.
1163  if ( sm->num_children < 1 ) return;
1164 
1165  // Save instance (Mc_orient, Mc_base, Mc_point_base)
1166  matrix saved_orient = Mc_orient;
1167  vec3d saved_base = Mc_base;
1168 
1169  // Check all of this subobject's children
1170  i = sm->first_child;
1171  while ( i >= 0 ) {
1172  angles angs;
1173  bool blown_off;
1174  bool collision_checked;
1175  bsp_info * csm = &Mc_pm->submodel[i];
1176 
1177  if ( Mc_pmi ) {
1178  angs = Mc_pmi->submodel[i].angs;
1179  blown_off = Mc_pmi->submodel[i].blown_off;
1180  collision_checked = Mc_pmi->submodel[i].collision_checked;
1181  } else {
1182  angs = csm->angs;
1183  blown_off = csm->blown_off ? true : false;
1184  collision_checked = false;
1185  }
1186 
1187  // Don't check it or its children if it is destroyed
1188  // or if it's set to no collision
1189  if ( !blown_off && !collision_checked && !csm->no_collisions ) {
1190  if ( Mc_pmi ) {
1191  Mc_orient = Mc_pmi->submodel[i].mc_orient;
1192  Mc_base = Mc_pmi->submodel[i].mc_base;
1193  vm_vec_add2(&Mc_base, Mc->pos);
1194  } else {
1195  //instance for this subobject
1196  matrix tm = IDENTITY_MATRIX;
1197 
1198  vm_vec_unrotate(&Mc_base, &csm->offset, &saved_orient );
1199  vm_vec_add2(&Mc_base, &saved_base );
1200 
1201  if( vm_matrix_same(&tm, &csm->orientation)) {
1202  // if submodel orientation matrix is identity matrix then don't bother with matrix ops
1203  vm_angles_2_matrix(&tm, &angs);
1204  } else {
1205  matrix rotation_matrix = csm->orientation;
1206  vm_rotate_matrix_by_angles(&rotation_matrix, &angs);
1207 
1208  matrix inv_orientation;
1209  vm_copy_transpose(&inv_orientation, &csm->orientation);
1210 
1211  vm_matrix_x_matrix(&tm, &rotation_matrix, &inv_orientation);
1212  }
1213 
1214  vm_matrix_x_matrix(&Mc_orient, &saved_orient, &tm);
1215  }
1216 
1217  mc_check_subobj( i );
1218  }
1219 
1220  i = csm->next_sibling;
1221  }
1222 
1223 }
1224 
1225 MONITOR(NumFVI)
1226 
1227 // See model.h for usage. I don't want to put the
1228 // usage here because you need to see the #defines and structures
1229 // this uses while reading the help.
1231 {
1232  Mc = mc_info_obj;
1233 
1234  MONITOR_INC(NumFVI,1);
1235 
1236  Mc->num_hits = 0; // How many collisions were found
1237  Mc->shield_hit_tri = -1; // Assume we won't hit any shield polygons
1238  Mc->hit_bitmap = -1;
1239  Mc->edge_hit = 0;
1240 
1241  if ( (Mc->flags & MC_CHECK_SHIELD) && (Mc->flags & MC_CHECK_MODEL) ) {
1242  Error( LOCATION, "Checking both shield and model!\n" );
1243  return 0;
1244  }
1245 
1246  //Fill in some global variables that all the model collide routines need internally.
1247  Mc_pm = model_get(Mc->model_num);
1248  Mc_orient = *Mc->orient;
1249  Mc_base = *Mc->pos;
1250  Mc_mag = vm_vec_dist( Mc->p0, Mc->p1 );
1251  Mc_edge_time = FLT_MAX;
1252 
1253  if ( Mc->model_instance_num >= 0 ) {
1254  Mc_pmi = model_get_instance(Mc->model_instance_num);
1255  } else {
1256  Mc_pmi = NULL;
1257  }
1258 
1259  // DA 11/19/98 - disable this check for rotating submodels
1260  // Don't do check if for very small movement
1261 // if (Mc_mag < 0.01f) {
1262 // return 0;
1263 // }
1264 
1265  float model_radius; // How big is the model we're checking against
1266  int first_submodel; // Which submodel gets returned as hit if MC_ONLY_SPHERE specified
1267 
1268  if ( (Mc->flags & MC_SUBMODEL) || (Mc->flags & MC_SUBMODEL_INSTANCE) ) {
1269  first_submodel = Mc->submodel_num;
1270  model_radius = Mc_pm->submodel[first_submodel].rad;
1271  } else {
1272  first_submodel = Mc_pm->detail[0];
1273  model_radius = Mc_pm->rad;
1274  }
1275 
1276  if ( Mc->flags & MC_CHECK_SPHERELINE ) {
1277  if ( Mc->radius <= 0.0f ) {
1278  Warning(LOCATION, "Attempting to collide with a sphere, but the sphere's radius is <= 0.0f!\n\n(model file is %s; submodel is %d, mc_flags are %d)", Mc_pm->filename, first_submodel, Mc->flags);
1279  return 0;
1280  }
1281 
1282  // Do a quick check on the Bounding Sphere
1283  if (fvi_segment_sphere(&Mc->hit_point_world, Mc->p0, Mc->p1, Mc->pos, model_radius+Mc->radius) ) {
1284  if ( Mc->flags & MC_ONLY_SPHERE ) {
1285  Mc->hit_point = Mc->hit_point_world;
1286  Mc->hit_submodel = first_submodel;
1287  Mc->num_hits++;
1288  return (Mc->num_hits > 0);
1289  }
1290  // continue checking polygons.
1291  } else {
1292  return 0;
1293  }
1294  } else {
1295  int r;
1296 
1297  // Do a quick check on the Bounding Sphere
1298  if ( Mc->flags & MC_CHECK_RAY ) {
1299  r = fvi_ray_sphere(&Mc->hit_point_world, Mc->p0, Mc->p1, Mc->pos, model_radius);
1300  } else {
1301  r = fvi_segment_sphere(&Mc->hit_point_world, Mc->p0, Mc->p1, Mc->pos, model_radius);
1302  }
1303  if (r) {
1304  if ( Mc->flags & MC_ONLY_SPHERE ) {
1305  Mc->hit_point = Mc->hit_point_world;
1306  Mc->hit_submodel = first_submodel;
1307  Mc->num_hits++;
1308  return (Mc->num_hits > 0);
1309  }
1310  // continue checking polygons.
1311  } else {
1312  return 0;
1313  }
1314 
1315  }
1316 
1317  if ( Mc->flags & MC_SUBMODEL ) {
1318  // Check only one subobject
1320  // Check submodel and any children
1321  } else if (Mc->flags & MC_SUBMODEL_INSTANCE) {
1323  } else {
1324  // Check all the the highest detail model polygons and subobjects for intersections
1325 
1326  // Don't check it or its children if it is destroyed
1327  if (!Mc_pm->submodel[Mc_pm->detail[0]].blown_off) {
1328  mc_check_subobj( Mc_pm->detail[0] );
1329  }
1330  }
1331 
1332 
1333  //If we found a hit, then rotate it into world coordinates
1334  if ( Mc->num_hits ) {
1335  if ( Mc->flags & MC_SUBMODEL ) {
1336  // If we're just checking one submodel, don't use normal instancing to find world points
1338  vm_vec_add2(&Mc->hit_point_world, Mc->pos);
1339  } else {
1340  if ( Mc_pmi ) {
1342  } else {
1344  }
1345  }
1346  }
1347 
1348 
1349  return Mc->num_hits;
1350 
1351 }
1352 
1354 {
1355  submodel_instance *smi = &pmi->submodel[subobj_num];
1356 
1357  smi->mc_base = *pos;
1358  smi->mc_orient = *orient;
1359 
1360  int i = pm->submodel[subobj_num].first_child;
1361 
1362  while ( i >= 0 ) {
1363  angles angs = pmi->submodel[i].angs;
1364  bsp_info * csm = &pm->submodel[i];
1365 
1366  matrix tm = IDENTITY_MATRIX;
1367 
1368  vm_vec_unrotate(pos, &csm->offset, &smi->mc_orient );
1369  vm_vec_add2(pos, &smi->mc_base);
1370 
1371  if( vm_matrix_same(&tm, &csm->orientation)) {
1372  // if submodel orientation matrix is identity matrix then don't bother with matrix ops
1373  vm_angles_2_matrix(&tm, &angs);
1374  } else {
1375  matrix rotation_matrix = csm->orientation;
1376  vm_rotate_matrix_by_angles(&rotation_matrix, &angs);
1377 
1378  matrix inv_orientation;
1379  vm_copy_transpose(&inv_orientation, &csm->orientation);
1380 
1381  vm_matrix_x_matrix(&tm, &rotation_matrix, &inv_orientation);
1382  }
1383 
1384  vm_matrix_x_matrix(orient, &smi->mc_orient, &tm);
1385 
1386  model_collide_preprocess_subobj(pos, orient, pm, pmi, i);
1387 
1388  i = csm->next_sibling;
1389  }
1390 }
1391 
1393 {
1394  polymodel_instance *pmi;
1395  polymodel *pm;
1396 
1397  pmi = model_get_instance(model_instance_num);
1398  pm = model_get(pmi->model_num);
1399 
1400  matrix current_orient;
1401  vec3d current_pos;
1402 
1403  current_orient = *orient;
1404 
1405  vm_vec_zero(&current_pos);
1406 
1407  model_collide_preprocess_subobj(&current_pos, &current_orient, pm, pmi, pm->detail[detail_num]);
1408 }
void model_collide_defpoints(ubyte *p)
vec3d max
Definition: model.h:343
void model_collide_sortnorm(ubyte *p)
bsp_info * submodel
Definition: model.h:764
float hit_v
Definition: model.h:1127
void model_collide_parse_bsp_flatpoly(bsp_collision_leaf *leaf, SCP_vector< model_tmap_vert > *vert_buffer, void *model_ptr)
ubyte tmap_num
Definition: model.h:279
int i
Definition: multi_pxo.cpp:466
float hit_u
Definition: model.h:1127
#define vm_free(ptr)
Definition: pstypes.h:548
void mc_check_shield()
void model_collide_parse_bsp(bsp_collision_tree *tree, void *model_ptr, int version)
#define Verify(x)
Definition: pstypes.h:272
vec3d hit_point
Definition: model.h:1123
#define TM_BASE_TYPE
Definition: model.h:657
bsp_collision_leaf * leaf_list
Definition: model.h:288
int fvi_polyedge_sphereline(vec3d *hit_point, const vec3d *xs0, const vec3d *vs, float Rs, int nv, vec3d const *const *verts, float *hit_time)
Definition: fvi.cpp:694
vec3d * pos
Definition: model.h:1113
#define vp(p)
Definition: modelsinc.h:70
int Cmdline_old_collision_sys
Definition: cmdline.cpp:489
void model_find_world_point(vec3d *outpnt, vec3d *mpnt, int model_num, int submodel_num, const matrix *objorient, const vec3d *objpos)
Definition: modelread.cpp:4099
int shield_hit_tri
Definition: model.h:1128
vec3d min
Definition: model.h:342
matrix * vm_matrix_x_matrix(matrix *dest, const matrix *src0, const matrix *src1)
Definition: vecmat.cpp:1006
void vm_vec_scale_add(vec3d *dest, const vec3d *src1, const vec3d *src2, float k)
Definition: vecmat.cpp:266
vec3d mins
Definition: model.h:746
#define OP_BOUNDBOX
Definition: modelsinc.h:25
void model_collide_tmappoly(ubyte *p)
int collision_tree_index
Definition: model.h:336
polymodel * model_get(int model_num)
Definition: modelread.cpp:3134
float model_radius
Definition: modelinterp.cpp:41
float v
Definition: pstypes.h:135
void model_collide_bsp_poly(bsp_collision_tree *tree, int leaf_index)
#define OP_EOF
Definition: modelsinc.h:20
matrix * vm_angles_2_matrix(matrix *m, const angles *a)
Definition: vecmat.cpp:752
void vm_rotate_matrix_by_angles(matrix *orient, const angles *tangles)
Definition: vecmat.cpp:1338
GLsizei const GLfloat * points
Definition: Glext.h:7583
void _cdecl void void _cdecl void _cdecl Warning(char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
int vm_matrix_same(matrix *m1, matrix *m2)
Definition: vecmat.cpp:1535
Assert(pm!=NULL)
#define MAX_MODEL_TEXTURES
Definition: globals.h:78
vec3d max
Definition: model.h:585
int detail[MAX_MODEL_DETAIL_LEVELS]
Definition: model.h:738
Definition: pstypes.h:88
#define mprintf(args)
Definition: pstypes.h:238
model_tmap_vert * vert_list
Definition: model.h:291
hull_check p0
Definition: lua.cpp:5051
int verts[3]
Definition: model.h:552
#define MC_CHECK_RAY
Definition: model.h:1176
struct vec3d::@225::@227 xyz
vec3d mc_base
Definition: model.h:90
GLclampf f
Definition: Glext.h:7097
vec3d * point_list
Definition: model.h:292
matrix * vm_copy_transpose(matrix *dest, const matrix *src)
Definition: vecmat.cpp:984
vec3d * vm_vec_rotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:933
int lod
Definition: model.h:1118
enum_h * u
Definition: lua.cpp:12649
shield_tri ** shield_tris
Definition: model.h:589
vec3d maxs
Definition: model.h:746
bsp_collision_tree * model_get_bsp_collision_tree(int tree_index)
Definition: modelread.cpp:5189
matrix mc_orient
Definition: model.h:91
void model_collide_bsp(bsp_collision_tree *tree, int node_index)
void mc_check_subobj(int mn)
shield_vertex * verts
Definition: model.h:569
hull_check orient
Definition: lua.cpp:5049
float hit_dist
Definition: model.h:1122
int details[MAX_MODEL_DETAIL_LEVELS]
Definition: model.h:365
#define Int3()
Definition: pstypes.h:292
bsp_collision_leaf * bsp_leaf
Definition: model.h:1133
vec3d * p0
Definition: model.h:1114
#define IS_VEC_NULL(v)
Definition: vecmat.h:28
int model_num
Definition: model.h:1110
#define OP_TMAPPOLY
Definition: modelsinc.h:23
int model_collide_parse_bsp_defpoints(ubyte *p)
bool no_collisions
Definition: model.h:390
#define MC_CHECK_SHIELD
Definition: model.h:1170
int sldc_size
Definition: model.h:780
ushort vertnum
Definition: model.h:258
int fvi_sphere_plane(vec3d *intersect_point, const vec3d *sphere_center_start, const vec3d *sphere_velocity, float sphere_radius, const vec3d *plane_normal, const vec3d *plane_point, float *hit_time, float *crossing_time)
Definition: fvi.cpp:516
typedef int(SCP_EXT_CALLCONV *SCPDLL_PFVERSION)(SCPDLL_Version *)
void model_instance_find_world_point(vec3d *outpnt, vec3d *mpnt, int model_instance_num, int submodel_num, const matrix *objorient, const vec3d *objpos)
Definition: modelread.cpp:4135
int edge_hit
Definition: model.h:1130
GLintptr offset
Definition: Glext.h:5497
void vm_vec_add2(vec3d *dest, const vec3d *src)
Definition: vecmat.cpp:178
int model_collide_sub(void *model_ptr)
GLdouble GLdouble GLdouble r
Definition: Glext.h:5337
int flags
Definition: model.h:1116
bsp_info * sm
Definition: lua.cpp:7079
bool mc_check_sldc(int offset)
bool collide_invisible
Definition: model.h:392
int fvi_point_face(const vec3d *checkp, int nv, vec3d const *const *verts, const vec3d *norm1, float *u_out, float *v_out, const uv_pair *uvls)
Definition: fvi.cpp:419
vec3d * p1
Definition: model.h:1115
texture_map maps[MAX_MODEL_TEXTURES]
Definition: model.h:762
ubyte num_verts
Definition: model.h:278
#define w(p)
Definition: modelsinc.h:68
#define MC_SUBMODEL
Definition: model.h:1178
submodel_instance * submodel
Definition: model.h:100
void model_collide_preprocess(matrix *orient, int model_instance_num, int detail_num)
int num_details
Definition: model.h:364
shield_info shield
Definition: model.h:778
int hit_submodel
Definition: model.h:1125
#define OP_SORTNORM
Definition: modelsinc.h:24
float u
Definition: pstypes.h:135
float vm_vec_dist(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:355
#define MONITOR(function_name)
Definition: pstypes.h:454
vec3d offset
Definition: model.h:330
int num_children
Definition: model.h:360
ushort normnum
Definition: model.h:259
float radius
Definition: model.h:1117
#define MC_CHECK_SPHERELINE
Definition: model.h:1177
int nshield_tris
Definition: model.h:588
vec3d * vm_vec_unrotate(vec3d *dest, const vec3d *src, const matrix *m)
Definition: vecmat.cpp:959
ubyte * shield_collision_tree
Definition: model.h:779
void model_collide_parse_bsp_tmappoly(bsp_collision_leaf *leaf, SCP_vector< model_tmap_vert > *vert_buffer, void *model_ptr)
#define MC_SUBMODEL_INSTANCE
Definition: model.h:1179
int fvi_ray_sphere(vec3d *intp, const vec3d *p0, const vec3d *p1, const vec3d *sphere_pos, float sphere_rad)
Definition: fvi.cpp:255
GLclampd n
Definition: Glext.h:7286
unsigned char ubyte
Definition: pstypes.h:62
#define MONITOR_INC(function_name, inc)
Definition: pstypes.h:457
void model_collide_flatpoly(ubyte *p)
#define vm_vec_zero(v)
Definition: vecmat.h:37
float face_rad
Definition: model.h:276
angles angs
Definition: model.h:349
vec3d hit_point_world
Definition: model.h:1124
int version
Definition: model.h:733
vec3d pos
Definition: model.h:560
float rad
Definition: model.h:340
void model_collide_allocate_point_list(int n_points)
void _cdecl void void _cdecl Error(const char *filename, int line, SCP_FORMAT_STRING const char *format,...) SCP_FORMAT_STRING_ARGS(3
int blown_off
Definition: model.h:346
#define vm_malloc(size)
Definition: pstypes.h:547
bool nocollide_this_only
Definition: model.h:391
#define IDENTITY_MATRIX
Definition: vecmat.h:64
void vm_vec_sub(vec3d *dest, const vec3d *src0, const vec3d *src1)
Definition: vecmat.cpp:168
#define OP_DEFPOINTS
Definition: modelsinc.h:21
int mc_ray_boundingbox(vec3d *min, vec3d *max, vec3d *p0, vec3d *pdir, vec3d *hitpos)
int hit_bitmap
Definition: model.h:1126
int num_hits
Definition: model.h:1121
o
Definition: lua.cpp:442
if(aifft_max_checks<=0)
Definition: aiturret.cpp:1581
polymodel_instance * model_get_instance(int model_instance_num)
Definition: modelread.cpp:3154
ubyte * bsp_data
Definition: model.h:334
float rad
Definition: model.h:757
bool collision_checked
Definition: model.h:92
int n_models
Definition: model.h:744
vec3d norm
Definition: model.h:554
#define MC_CHECK_MODEL
Definition: model.h:1169
int next_sibling
Definition: model.h:362
GLfloat GLfloat p
Definition: Glext.h:8373
bool blown_off
Definition: model.h:93
#define MC_ONLY_BOUND_BOX
Definition: model.h:1173
int fvi_segment_sphere(vec3d *intp, const vec3d *p0, const vec3d *p1, const vec3d *sphere_pos, float sphere_rad)
Definition: fvi.cpp:188
texture_info textures[TM_NUM_TYPES]
Definition: model.h:671
GLenum src
Definition: Glext.h:5917
#define LOCATION
Definition: pstypes.h:245
void model_collide_free_point_list()
ubyte * t_poly
Definition: model.h:1132
#define OP_FLATPOLY
Definition: modelsinc.h:22
hull_check pos
Definition: lua.cpp:5050
int model_instance_num
Definition: model.h:1109
float vm_vec_dot(const vec3d *v0, const vec3d *v1)
Definition: vecmat.cpp:312
ubyte * f_poly
Definition: model.h:1131
bsp_collision_node * node_list
Definition: model.h:285
polymodel * pm
Definition: lua.cpp:1598
vec3d hit_normal
Definition: model.h:1129
void model_collide_preprocess_subobj(vec3d *pos, matrix *orient, polymodel *pm, polymodel_instance *pmi, int subobj_num)
model_octant octants[8]
Definition: model.h:791
float fvi_ray_plane(vec3d *new_pnt, const vec3d *plane_pnt, const vec3d *plane_norm, const vec3d *ray_origin, const vec3d *ray_direction, float rad)
Definition: fvi.cpp:118
#define TMAP_MAX_VERTS
Definition: tmapper.h:33
matrix orientation
Definition: model.h:331
int model_collide(mc_info *mc_info_obj)
#define MC_CHECK_INVISIBLE_FACES
Definition: model.h:1180
int model_instance_num
Definition: lua.cpp:4996
int submodel_num
Definition: model.h:1111
angles angs
Definition: model.h:88
char filename[FILESPEC_LENGTH]
Definition: model.h:734
#define MC_ONLY_SPHERE
Definition: model.h:1171
int fvi_ray_boundingbox(const vec3d *min, const vec3d *max, const vec3d *p0, const vec3d *pdir, vec3d *hitpt)
Definition: fvi.cpp:321
matrix * orient
Definition: model.h:1112
const GLdouble * v
Definition: Glext.h:5322
shield_tri * tris
Definition: model.h:570
int ntris
Definition: model.h:568
#define fl(p)
Definition: modelsinc.h:71
int first_child
Definition: model.h:361
vec3d plane_norm
Definition: model.h:275
vec3d min
Definition: model.h:585
vec3d plane_pnt
Definition: model.h:274
bool mc_shield_check_common(shield_tri *tri)