2 * $Logfile: /Freespace2/code/Model/ModelOctant.cpp $
7 * Routines for model octants
10 * Revision 1.1 2002/05/03 03:28:10 root
14 * 3 1/06/99 2:24p Dave
15 * Stubs and release build fixes.
17 * 2 10/07/98 10:53a Dave
20 * 1 10/07/98 10:50a Dave
22 * 16 4/29/98 5:01p Mike
23 * Large overhaul in how turrets fire.
25 * 15 4/02/98 8:16a John
26 * Fixed Assert in model_collide with large ships
28 * 14 4/01/98 5:34p John
29 * Made only the used POFs page in for a level. Reduced some interp
30 * arrays. Made custom detail level work differently.
32 * 13 3/31/98 5:18p John
33 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
34 * bunch of debug stuff out of player file. Made model code be able to
35 * unload models and malloc out only however many models are needed.
38 * 12 10/31/97 3:19p John
39 * changed id field in face to be radius
41 * 11 9/10/97 11:40a John
42 * took out unused parts of model_octant, like faces and submodels. Made
43 * the vertices actually be face center points. Made the find_faces code
44 * save the poly center as the normal_point in the face structure.
46 * 10 8/15/97 4:10p John
47 * new code to use the new octrees style bsp trees
49 * 9 7/22/97 9:41a John
50 * Made flat faces appear in octant list, so collision detection now
51 * works. Made them do smoothing if needed.
53 * 8 7/03/97 9:14a John
54 * fixed incorrect octant vertices.
56 * 7 6/26/97 12:37p John
57 * fixed bug with octant submodels. disabled octant submodels correctly,
58 * since they aren't yet implemented.
60 * 6 6/26/97 11:19a John
61 * Made model face & shield collisions look only at octants it needs to.
62 * Shield sped up 4x, faces sped up about 2x.
64 * 5 6/26/97 9:02a Mike
65 * Comment out frequent mprintf().
67 * 4 6/25/97 6:08p John
68 * made which_octant functions also return a pointer to the octant data.
70 * 3 6/25/97 5:34p John
71 * Added functions to tell which octant a point is in.
73 * 2 6/25/97 5:11p John
74 * added foundation for model octants.
76 * 1 6/25/97 4:07p John
93 #include "modelsinc.h"
96 // returns 1 if a point is in an octant.
97 int point_in_octant( polymodel * pm, model_octant * oct, vector *vert )
99 if ( vert->x < oct->min.x ) return 0;
100 if ( vert->x > oct->max.x ) return 0;
102 if ( vert->y < oct->min.y ) return 0;
103 if ( vert->y > oct->max.y ) return 0;
105 if ( vert->z< oct->min.z) return 0;
106 if ( vert->z> oct->max.z) return 0;
112 void model_octant_find_shields( polymodel * pm, model_octant * oct )
119 // Scan all the triangles in the mesh to find how many tris there are.
120 for (i=0; i<pm->shield.ntris; i++ ) {
122 tri = &pm->shield.tris[i];
124 for (j=0; j<3; j++ ) {
125 if ( point_in_octant( pm, oct, &pm->shield.verts[tri->verts[j]].pos )) {
132 //mprintf(( "Octant has %d shield polys in it\n", n ));
134 oct->nshield_tris = n;
135 oct->shield_tris = (shield_tri **)malloc( sizeof(shield_tri *) * oct->nshield_tris );
136 Assert(oct->shield_tris!=NULL);
140 // Rescan all the triangles in the mesh.
141 for (i=0; i<pm->shield.ntris; i++ ) {
143 tri = &pm->shield.tris[i];
145 for (j=0; j<3; j++ ) {
146 if ( point_in_octant( pm, oct, &pm->shield.verts[tri->verts[j]].pos )) {
147 oct->shield_tris[n++] = tri;
153 Assert( oct->nshield_tris == n );
158 void moff_defpoints(ubyte * p)
162 int offset = w(p+16);
164 ubyte * normcount = p+20;
165 vector *src = vp(p+offset);
167 Assert( nverts < MAX_POLYGON_VECS );
168 // Assert( nnorms < MAX_POLYGON_NORMS );
170 for (n=0; n<nverts; n++ ) {
172 Interp_verts[n] = src;
174 src += normcount[n]+1;
188 // +44 nverts*(model_tmap_vert) vertlist (n,u,v)
189 void moff_tmappoly(ubyte * p, polymodel * pm, model_octant * oct, int just_count )
192 model_tmap_vert *verts;
195 if ( nv < 0 ) return;
197 verts = (model_tmap_vert *)(p+44);
199 if ( pm->version < 2003 ) {
200 // Set the "normal_point" part of field to be the center of the polygon
202 vm_vec_zero( ¢er_point );
205 vm_vec_add2( ¢er_point, Interp_verts[verts[i].vertnum] );
208 center_point.x /= nv;
209 center_point.y /= nv;
210 center_point.z /= nv;
212 *vp(p+20) = center_point;
217 float dist = vm_vec_dist( ¢er_point, Interp_verts[verts[i].vertnum] );
225 // Put each face into a particular octant
226 if ( point_in_octant( pm, oct, vp(p+20) ) ) {
230 oct->verts[oct->nverts++] = vp(p+20);
247 // +44 nverts*int vertlist
248 void moff_flatpoly(ubyte * p, polymodel * pm, model_octant * oct, int just_count )
254 if ( nv < 0 ) return;
256 verts = (short *)(p+44);
258 if ( pm->version < 2003 ) {
259 // Set the "normal_point" part of field to be the center of the polygon
261 vm_vec_zero( ¢er_point );
264 vm_vec_add2( ¢er_point, Interp_verts[verts[i*2]] );
267 center_point.x /= nv;
268 center_point.y /= nv;
269 center_point.z /= nv;
271 *vp(p+20) = center_point;
276 float dist = vm_vec_dist( ¢er_point, Interp_verts[verts[i*2]] );
284 // Put each face's center point into a particular octant
285 if ( point_in_octant( pm, oct, vp(p+20) ) ) {
289 oct->verts[oct->nverts++] = vp(p+20);
295 int model_octant_find_faces_sub(polymodel * pm, model_octant * oct, void *model_ptr, int just_count )
297 ubyte *p = (ubyte *)model_ptr;
298 int chunk_type, chunk_size;
303 while (chunk_type != OP_EOF) {
305 switch (chunk_type) {
306 case OP_EOF: return 1;
310 case OP_FLATPOLY: moff_flatpoly(p, pm, oct, just_count ); break;
311 case OP_TMAPPOLY: moff_tmappoly(p, pm, oct, just_count ); break;
313 int frontlist = w(p+36);
314 int backlist = w(p+40);
315 int prelist = w(p+44);
316 int postlist = w(p+48);
317 int onlist = w(p+52);
319 if (prelist) model_octant_find_faces_sub(pm,oct,p+prelist,just_count);
320 if (backlist) model_octant_find_faces_sub(pm,oct,p+backlist,just_count);
321 if (onlist) model_octant_find_faces_sub(pm,oct,p+onlist,just_count);
322 if (frontlist) model_octant_find_faces_sub(pm,oct,p+frontlist,just_count);
323 if (postlist) model_octant_find_faces_sub(pm,oct,p+postlist,just_count);
326 case OP_BOUNDBOX: break;
328 mprintf(( "Bad chunk type %d, len=%d in model_octant_find_faces_sub\n", chunk_type, chunk_size ));
329 Int3(); // Bad chunk type!
340 void model_octant_find_faces( polymodel * pm, model_octant * oct )
343 int submodel_num = pm->detail[0];
345 p = pm->submodel[submodel_num].bsp_data;
348 model_octant_find_faces_sub(pm, oct, p, 1 );
350 if ( oct->nverts < 1 ) {
356 oct->verts = (vector **)malloc( sizeof(vector *) * oct->nverts );
357 Assert(oct->verts!=NULL);
360 model_octant_find_faces_sub(pm, oct, p, 0 );
362 // mprintf(( "Octant has %d faces\n", oct->nfaces ));
366 // Creates the octants for a given polygon model
367 void model_octant_create( polymodel * pm )
369 vector min, max, center;
375 vm_vec_avg( ¢er, &min, &max );
377 for (i=0; i<8; i++ ) {
383 pm->octants[i].max.x = max.x;
384 pm->octants[i].min.x = center.x;
386 pm->octants[i].max.x = center.x;
387 pm->octants[i].min.x = min.x;
391 pm->octants[i].max.y = max.y;
392 pm->octants[i].min.y = center.y;
394 pm->octants[i].max.y = center.y;
395 pm->octants[i].min.y = min.y;
399 pm->octants[i].max.z = max.z;
400 pm->octants[i].min.z = center.z;
402 pm->octants[i].max.z = center.z;
403 pm->octants[i].min.z = min.z;
406 model_octant_find_shields( pm, &pm->octants[i] );
407 model_octant_find_faces( pm, &pm->octants[i] );
414 // frees the memory the octants use for a given polygon model
415 void model_octant_free( polymodel * pm )
419 for (i=0; i<8; i++ ) {
420 model_octant * oct = &pm->octants[i];
427 if ( oct->shield_tris ) {
428 free( oct->shield_tris );
429 oct->shield_tris = NULL;
436 // Returns which octant point pnt is closet to. This will always return
437 // a valid octant (0-7) since the point doesn't have to be in an octant.
438 // If model_orient and/or model_pos are NULL, pnt is assumed to already
439 // be rotated into the model's local coordinates.
440 // If oct is not null, it will be filled in with a pointer to the octant
442 int model_which_octant_distant_many( vector *pnt, int model_num,matrix *model_orient, vector * model_pos, polymodel **pm, int *octs)
444 vector tempv, rotpnt;
446 *pm = model_get(model_num);
448 if ( model_orient && model_pos ) {
449 // First, rotate pnt into the model's frame of reference.
450 vm_vec_sub( &tempv, pnt, model_pos );
451 vm_vec_rotate( &rotpnt, &tempv, model_orient );
457 vm_vec_avg( ¢er, &((*pm)->mins), &((*pm)->maxs ));
460 if ( rotpnt.x > center.x ) x = 1; else x = 0;
461 if ( rotpnt.y > center.y ) y = 1; else y = 0;
462 if ( rotpnt.z > center.z ) z = 1; else z = 0;
464 i = ( (x<<2) | (y<<1) | z );
467 octs[1] = i ^ 4; // Adjacent octant in x dimension
468 octs[2] = i ^ 2; // Adjacent octant in y dimension
469 octs[3] = i ^ 1; // Adjacent octant in z dimension
475 // Returns which octant point pnt is closet to. This will always return
476 // a valid octant (0-7) since the point doesn't have to be in an octant.
477 // If model_orient and/or model_pos are NULL, pnt is assumed to already
478 // be rotated into the model's local coordinates.
479 // If oct is not null, it will be filled in with a pointer to the octant
481 int model_which_octant_distant( vector *pnt, int model_num,matrix *model_orient, vector * model_pos, model_octant **oct )
484 vector tempv, rotpnt;
486 pm = model_get(model_num);
488 if ( model_orient && model_pos ) {
489 // First, rotate pnt into the model's frame of reference.
490 vm_vec_sub( &tempv, pnt, model_pos );
491 vm_vec_rotate( &rotpnt, &tempv, model_orient );
497 vm_vec_avg( ¢er, &pm->mins, &pm->maxs );
500 if ( rotpnt.x > center.x ) x = 1; else x = 0;
501 if ( rotpnt.y > center.y ) y = 1; else y = 0;
502 if ( rotpnt.z > center.z ) z = 1; else z = 0;
504 i = ( (x<<2) | (y<<1) | z );
507 *oct = &pm->octants[i];
514 // Returns which octant point pnt is in. This might return
515 // -1 if the point isn't in any octant.
516 // If model_orient and/or model_pos are NULL, pnt is assumed to already
517 // be rotated into the model's local coordinates.
518 // If oct is not null, it will be filled in with a pointer to the octant
519 // data. Or NULL if the pnt isn't in the octant.
520 int model_which_octant( vector *pnt, int model_num,matrix *model_orient, vector * model_pos, model_octant **oct )
523 vector tempv, rotpnt;
525 pm = model_get(model_num);
527 if ( model_orient && model_pos ) {
528 // First, rotate pnt into the model's frame of reference.
529 vm_vec_sub( &tempv, pnt, model_pos );
530 vm_vec_rotate( &rotpnt, &tempv, model_orient );
536 vm_vec_avg( ¢er, &pm->mins, &pm->maxs );
539 if ( rotpnt.x > center.x ) x = 1; else x = 0;
540 if ( rotpnt.y > center.y ) y = 1; else y = 0;
541 if ( rotpnt.z > center.z ) z = 1; else z = 0;
543 i = (x<<2) | (y<<1) | z;
545 if ( point_in_octant( pm, &pm->octants[i], &rotpnt ) ) {
547 *oct = &pm->octants[i];