2 * Copyright (C) Volition, Inc. 1999. All rights reserved.
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
10 * $Logfile: /Freespace2/code/Model/ModelOctant.cpp $
15 * Routines for model octants
18 * Revision 1.4 2002/06/17 06:33:09 relnev
19 * ryan's struct patch for gcc 2.95
21 * Revision 1.3 2002/06/09 04:41:23 relnev
22 * added copyright header
24 * Revision 1.2 2002/05/07 03:16:47 theoddone33
25 * The Great Newline Fix
27 * Revision 1.1.1.1 2002/05/03 03:28:10 root
31 * 3 1/06/99 2:24p Dave
32 * Stubs and release build fixes.
34 * 2 10/07/98 10:53a Dave
37 * 1 10/07/98 10:50a Dave
39 * 16 4/29/98 5:01p Mike
40 * Large overhaul in how turrets fire.
42 * 15 4/02/98 8:16a John
43 * Fixed SDL_assert in model_collide with large ships
45 * 14 4/01/98 5:34p John
46 * Made only the used POFs page in for a level. Reduced some interp
47 * arrays. Made custom detail level work differently.
49 * 13 3/31/98 5:18p John
50 * Removed demo/save/restore. Made NDEBUG defined compile. Removed a
51 * bunch of debug stuff out of player file. Made model code be able to
52 * unload models and malloc out only however many models are needed.
55 * 12 10/31/97 3:19p John
56 * changed id field in face to be radius
58 * 11 9/10/97 11:40a John
59 * took out unused parts of model_octant, like faces and submodels. Made
60 * the vertices actually be face center points. Made the find_faces code
61 * save the poly center as the normal_point in the face structure.
63 * 10 8/15/97 4:10p John
64 * new code to use the new octrees style bsp trees
66 * 9 7/22/97 9:41a John
67 * Made flat faces appear in octant list, so collision detection now
68 * works. Made them do smoothing if needed.
70 * 8 7/03/97 9:14a John
71 * fixed incorrect octant vertices.
73 * 7 6/26/97 12:37p John
74 * fixed bug with octant submodels. disabled octant submodels correctly,
75 * since they aren't yet implemented.
77 * 6 6/26/97 11:19a John
78 * Made model face & shield collisions look only at octants it needs to.
79 * Shield sped up 4x, faces sped up about 2x.
81 * 5 6/26/97 9:02a Mike
82 * Comment out frequent mprintf().
84 * 4 6/25/97 6:08p John
85 * made which_octant functions also return a pointer to the octant data.
87 * 3 6/25/97 5:34p John
88 * Added functions to tell which octant a point is in.
90 * 2 6/25/97 5:11p John
91 * added foundation for model octants.
93 * 1 6/25/97 4:07p John
107 #include "floating.h"
109 #include "lighting.h"
110 #include "modelsinc.h"
113 // returns 1 if a point is in an octant.
114 int point_in_octant( polymodel * pm, model_octant * oct, vector *vert )
116 if ( vert->xyz.x < oct->min.xyz.x ) return 0;
117 if ( vert->xyz.x > oct->max.xyz.x ) return 0;
119 if ( vert->xyz.y < oct->min.xyz.y ) return 0;
120 if ( vert->xyz.y > oct->max.xyz.y ) return 0;
122 if ( vert->xyz.z< oct->min.xyz.z) return 0;
123 if ( vert->xyz.z> oct->max.xyz.z) return 0;
129 void model_octant_find_shields( polymodel * pm, model_octant * oct )
136 // Scan all the triangles in the mesh to find how many tris there are.
137 for (i=0; i<pm->shield.ntris; i++ ) {
139 tri = &pm->shield.tris[i];
141 for (j=0; j<3; j++ ) {
142 if ( point_in_octant( pm, oct, &pm->shield.verts[tri->verts[j]].pos )) {
149 //mprintf(( "Octant has %d shield polys in it\n", n ));
151 oct->nshield_tris = n;
152 oct->shield_tris = (shield_tri **)malloc( sizeof(shield_tri *) * oct->nshield_tris );
153 SDL_assert(oct->shield_tris!=NULL);
157 // Rescan all the triangles in the mesh.
158 for (i=0; i<pm->shield.ntris; i++ ) {
160 tri = &pm->shield.tris[i];
162 for (j=0; j<3; j++ ) {
163 if ( point_in_octant( pm, oct, &pm->shield.verts[tri->verts[j]].pos )) {
164 oct->shield_tris[n++] = tri;
170 SDL_assert( oct->nshield_tris == n );
175 void moff_defpoints(ubyte * p)
179 int offset = w(p+16);
181 ubyte * normcount = p+20;
182 vector *src = vp(p+offset);
184 SDL_assert( nverts < MAX_POLYGON_VECS );
185 // SDL_assert( nnorms < MAX_POLYGON_NORMS );
187 for (n=0; n<nverts; n++ ) {
189 Interp_verts[n] = src;
191 src += normcount[n]+1;
205 // +44 nverts*(model_tmap_vert) vertlist (n,u,v)
206 void moff_tmappoly(ubyte * p, polymodel * pm, model_octant * oct, int just_count )
209 model_tmap_vert *verts;
212 if ( nv < 0 ) return;
214 verts = (model_tmap_vert *)(p+44);
216 if ( pm->version < 2003 ) {
217 // Set the "normal_point" part of field to be the center of the polygon
219 vm_vec_zero( ¢er_point );
222 vm_vec_add2( ¢er_point, Interp_verts[verts[i].vertnum] );
225 center_point.xyz.x /= nv;
226 center_point.xyz.y /= nv;
227 center_point.xyz.z /= nv;
229 *vp(p+20) = center_point;
234 float dist = vm_vec_dist( ¢er_point, Interp_verts[verts[i].vertnum] );
242 // Put each face into a particular octant
243 if ( point_in_octant( pm, oct, vp(p+20) ) ) {
247 oct->verts[oct->nverts++] = vp(p+20);
264 // +44 nverts*int vertlist
265 void moff_flatpoly(ubyte * p, polymodel * pm, model_octant * oct, int just_count )
271 if ( nv < 0 ) return;
273 verts = (short *)(p+44);
275 if ( pm->version < 2003 ) {
276 // Set the "normal_point" part of field to be the center of the polygon
278 vm_vec_zero( ¢er_point );
281 vm_vec_add2( ¢er_point, Interp_verts[verts[i*2]] );
284 center_point.xyz.x /= nv;
285 center_point.xyz.y /= nv;
286 center_point.xyz.z /= nv;
288 *vp(p+20) = center_point;
293 float dist = vm_vec_dist( ¢er_point, Interp_verts[verts[i*2]] );
301 // Put each face's center point into a particular octant
302 if ( point_in_octant( pm, oct, vp(p+20) ) ) {
306 oct->verts[oct->nverts++] = vp(p+20);
312 int model_octant_find_faces_sub(polymodel * pm, model_octant * oct, void *model_ptr, int just_count )
314 ubyte *p = (ubyte *)model_ptr;
315 int chunk_type, chunk_size;
320 while (chunk_type != OP_EOF) {
322 switch (chunk_type) {
323 case OP_EOF: return 1;
327 case OP_FLATPOLY: moff_flatpoly(p, pm, oct, just_count ); break;
328 case OP_TMAPPOLY: moff_tmappoly(p, pm, oct, just_count ); break;
330 int frontlist = w(p+36);
331 int backlist = w(p+40);
332 int prelist = w(p+44);
333 int postlist = w(p+48);
334 int onlist = w(p+52);
336 if (prelist) model_octant_find_faces_sub(pm,oct,p+prelist,just_count);
337 if (backlist) model_octant_find_faces_sub(pm,oct,p+backlist,just_count);
338 if (onlist) model_octant_find_faces_sub(pm,oct,p+onlist,just_count);
339 if (frontlist) model_octant_find_faces_sub(pm,oct,p+frontlist,just_count);
340 if (postlist) model_octant_find_faces_sub(pm,oct,p+postlist,just_count);
343 case OP_BOUNDBOX: break;
345 mprintf(( "Bad chunk type %d, len=%d in model_octant_find_faces_sub\n", chunk_type, chunk_size ));
346 Int3(); // Bad chunk type!
357 void model_octant_find_faces( polymodel * pm, model_octant * oct )
360 int submodel_num = pm->detail[0];
362 p = pm->submodel[submodel_num].bsp_data;
365 model_octant_find_faces_sub(pm, oct, p, 1 );
367 if ( oct->nverts < 1 ) {
373 oct->verts = (vector **)malloc( sizeof(vector *) * oct->nverts );
374 SDL_assert(oct->verts!=NULL);
377 model_octant_find_faces_sub(pm, oct, p, 0 );
379 // mprintf(( "Octant has %d faces\n", oct->nfaces ));
383 // Creates the octants for a given polygon model
384 void model_octant_create( polymodel * pm )
386 vector min, max, center;
392 vm_vec_avg( ¢er, &min, &max );
394 for (i=0; i<8; i++ ) {
400 pm->octants[i].max.xyz.x = max.xyz.x;
401 pm->octants[i].min.xyz.x = center.xyz.x;
403 pm->octants[i].max.xyz.x = center.xyz.x;
404 pm->octants[i].min.xyz.x = min.xyz.x;
408 pm->octants[i].max.xyz.y = max.xyz.y;
409 pm->octants[i].min.xyz.y = center.xyz.y;
411 pm->octants[i].max.xyz.y = center.xyz.y;
412 pm->octants[i].min.xyz.y = min.xyz.y;
416 pm->octants[i].max.xyz.z = max.xyz.z;
417 pm->octants[i].min.xyz.z = center.xyz.z;
419 pm->octants[i].max.xyz.z = center.xyz.z;
420 pm->octants[i].min.xyz.z = min.xyz.z;
423 model_octant_find_shields( pm, &pm->octants[i] );
424 model_octant_find_faces( pm, &pm->octants[i] );
431 // frees the memory the octants use for a given polygon model
432 void model_octant_free( polymodel * pm )
436 for (i=0; i<8; i++ ) {
437 model_octant * oct = &pm->octants[i];
444 if ( oct->shield_tris ) {
445 free( oct->shield_tris );
446 oct->shield_tris = NULL;
453 // Returns which octant point pnt is closet to. This will always return
454 // a valid octant (0-7) since the point doesn't have to be in an octant.
455 // If model_orient and/or model_pos are NULL, pnt is assumed to already
456 // be rotated into the model's local coordinates.
457 // If oct is not null, it will be filled in with a pointer to the octant
459 int model_which_octant_distant_many( vector *pnt, int model_num,matrix *model_orient, vector * model_pos, polymodel **pm, int *octs)
461 vector tempv, rotpnt;
463 *pm = model_get(model_num);
465 if ( model_orient && model_pos ) {
466 // First, rotate pnt into the model's frame of reference.
467 vm_vec_sub( &tempv, pnt, model_pos );
468 vm_vec_rotate( &rotpnt, &tempv, model_orient );
474 vm_vec_avg( ¢er, &((*pm)->mins), &((*pm)->maxs ));
477 if ( rotpnt.xyz.x > center.xyz.x ) x = 1; else x = 0;
478 if ( rotpnt.xyz.y > center.xyz.y ) y = 1; else y = 0;
479 if ( rotpnt.xyz.z > center.xyz.z ) z = 1; else z = 0;
481 i = ( (x<<2) | (y<<1) | z );
484 octs[1] = i ^ 4; // Adjacent octant in x dimension
485 octs[2] = i ^ 2; // Adjacent octant in y dimension
486 octs[3] = i ^ 1; // Adjacent octant in z dimension
492 // Returns which octant point pnt is closet to. This will always return
493 // a valid octant (0-7) since the point doesn't have to be in an octant.
494 // If model_orient and/or model_pos are NULL, pnt is assumed to already
495 // be rotated into the model's local coordinates.
496 // If oct is not null, it will be filled in with a pointer to the octant
498 int model_which_octant_distant( vector *pnt, int model_num,matrix *model_orient, vector * model_pos, model_octant **oct )
501 vector tempv, rotpnt;
503 pm = model_get(model_num);
505 if ( model_orient && model_pos ) {
506 // First, rotate pnt into the model's frame of reference.
507 vm_vec_sub( &tempv, pnt, model_pos );
508 vm_vec_rotate( &rotpnt, &tempv, model_orient );
514 vm_vec_avg( ¢er, &pm->mins, &pm->maxs );
517 if ( rotpnt.xyz.x > center.xyz.x ) x = 1; else x = 0;
518 if ( rotpnt.xyz.y > center.xyz.y ) y = 1; else y = 0;
519 if ( rotpnt.xyz.z > center.xyz.z ) z = 1; else z = 0;
521 i = ( (x<<2) | (y<<1) | z );
524 *oct = &pm->octants[i];
531 // Returns which octant point pnt is in. This might return
532 // -1 if the point isn't in any octant.
533 // If model_orient and/or model_pos are NULL, pnt is assumed to already
534 // be rotated into the model's local coordinates.
535 // If oct is not null, it will be filled in with a pointer to the octant
536 // data. Or NULL if the pnt isn't in the octant.
537 int model_which_octant( vector *pnt, int model_num,matrix *model_orient, vector * model_pos, model_octant **oct )
540 vector tempv, rotpnt;
542 pm = model_get(model_num);
544 if ( model_orient && model_pos ) {
545 // First, rotate pnt into the model's frame of reference.
546 vm_vec_sub( &tempv, pnt, model_pos );
547 vm_vec_rotate( &rotpnt, &tempv, model_orient );
553 vm_vec_avg( ¢er, &pm->mins, &pm->maxs );
556 if ( rotpnt.xyz.x > center.xyz.x ) x = 1; else x = 0;
557 if ( rotpnt.xyz.y > center.xyz.y ) y = 1; else y = 0;
558 if ( rotpnt.xyz.z > center.xyz.z ) z = 1; else z = 0;
560 i = (x<<2) | (y<<1) | z;
562 if ( point_in_octant( pm, &pm->octants[i], &rotpnt ) ) {
564 *oct = &pm->octants[i];