/* * Copyright (C) Volition, Inc. 1999. All rights reserved. * * All source code herein is the property of Volition, Inc. You may not sell * or otherwise commercially exploit the source or things you created based on the * source. * */ #include #define MODEL_LIB #include "cmdline/cmdline.h" #include "math/vecmat.h" #include "model/model.h" #include "model/modelsinc.h" #include "tracing/tracing.h" // returns 1 if a point is in an octant. int point_in_octant( polymodel * /*pm*/, model_octant * oct, vec3d *vert ) { if ( vert->xyz.x < oct->min.xyz.x ) return 0; if ( vert->xyz.x > oct->max.xyz.x ) return 0; if ( vert->xyz.y < oct->min.xyz.y ) return 0; if ( vert->xyz.y > oct->max.xyz.y ) return 0; if ( vert->xyz.z < oct->min.xyz.z) return 0; if ( vert->xyz.z > oct->max.xyz.z) return 0; return 1; } void model_octant_find_shields( polymodel * pm, model_octant * oct ) { int i, j, n; shield_tri *tri; n = 0; // Scan all the triangles in the mesh to find how many tris there are. for (i=0; ishield.ntris; i++ ) { tri = &pm->shield.tris[i]; for (j=0; j<3; j++ ) { if ( point_in_octant( pm, oct, &pm->shield.verts[tri->verts[j]].pos )) { n++; break; } } } //mprintf(( "Octant has %d shield polys in it\n", n )); oct->nshield_tris = n; // if we don't have any shield polys then don't bother continuing - taylor if (oct->nshield_tris <= 0) { oct->shield_tris = NULL; return; } oct->shield_tris = (shield_tri **)vm_malloc( sizeof(shield_tri *) * oct->nshield_tris ); Assert(oct->shield_tris!=NULL); n = 0; // Rescan all the triangles in the mesh. for (i=0; ishield.ntris; i++ ) { tri = &pm->shield.tris[i]; for (j=0; j<3; j++ ) { if ( point_in_octant( pm, oct, &pm->shield.verts[tri->verts[j]].pos )) { oct->shield_tris[n++] = tri; break; } } } Assert( oct->nshield_tris == n ); } void moff_defpoints(ubyte * p, int just_count) { uint n; uint nverts = uw(p+8); uint offset = uw(p+16); uint nnorms = 0; // only do fill Interp_verts once, in the first pass when we're just counting them up if (!just_count) return; ubyte * normcount = p+20; vec3d *src = vp(p+offset); // make sure we have enough space allocated for the new data for (n = 0; n < nverts; n++) { nnorms += normcount[n]; } model_allocate_interp_data( nverts, nnorms ); Assert( Interp_verts != NULL ); for (n=0; n(&p[TMAP_VERTS]); if ( (pm->version < 2003) && !just_count ) { // Set the "normal_point" part of field to be the center of the polygon vec3d center_point; vm_vec_zero( ¢er_point ); Assert( Interp_verts != nullptr ); for (i=0;i rad ) { rad = dist; } } fl(p+32) = rad; } // Put each face into a particular octant if ( point_in_octant( pm, oct, vp(p+20) ) ) { if (just_count) oct->nverts++; else oct->verts[oct->nverts++] = vp(p+20); return; } } // Textured Poly version 2 // +0 int id = 6 // + 4 int size // + 8 vector min_bounding_box_point // + 20 vector max_bounding_box_point // + 32 vector normal // + 44 int tmap_num // + 48 int nverts // + 52 nverts*(model_tmap2_vert) vertlist (n,u,v) void moff_tmap2poly(ubyte* p, polymodel* pm, model_octant* oct, int just_count) { Assert(pm->version >= 2300); uint i, nv; model_tmap_vert* verts; nv = uw(p + TMAP2_NVERTS); verts = reinterpret_cast(p + TMAP2_VERTS); vec3d center_point; vm_vec_zero(¢er_point); Assert(Interp_verts != nullptr); for (i = 0; i < nv; i++) { vm_vec_add2(¢er_point, Interp_verts[verts[i].vertnum]); } center_point.xyz.x /= nv; center_point.xyz.y /= nv; center_point.xyz.z /= nv; // Put each face into a particular octant if (point_in_octant(pm, oct, ¢er_point)) { if (just_count) oct->nverts++; else oct->verts[oct->nverts++] = ¢er_point; return; } } // Flat Poly // +0 int id // +4 int size // +8 vec3d normal // +20 vec3d center // +32 float radius // +36 int nverts // +40 byte red // +41 byte green // +42 byte blue // +43 byte pad // +44 nverts*int vertlist void moff_flatpoly(ubyte * p, polymodel * pm, model_octant * oct, int just_count ) { uint i, nv; short *verts; nv = uw(p+36); verts = (short *)(p+44); if ( (pm->version < 2003) && !just_count ) { // Set the "normal_point" part of field to be the center of the polygon vec3d center_point; vm_vec_zero( ¢er_point ); Assert( Interp_verts != NULL ); for (i=0;i rad ) { rad = dist; } } fl(p+32) = rad; } // Put each face's center point into a particular octant if ( point_in_octant( pm, oct, vp(p+20) ) ) { if (just_count) oct->nverts++; else oct->verts[oct->nverts++] = vp(p+20); } } int model_octant_find_faces_sub(polymodel * pm, model_octant * oct, void *model_ptr, int just_count ) { ubyte *p = (ubyte *)model_ptr; int chunk_type, chunk_size; chunk_type = w(p); chunk_size = w(p+4); bool end = chunk_type == OP_EOF; while (!end) { switch (chunk_type) { case OP_DEFPOINTS: moff_defpoints(p, just_count); break; case OP_FLATPOLY: moff_flatpoly(p, pm, oct, just_count ); break; case OP_TMAPPOLY: moff_tmappoly(p, pm, oct, just_count ); break; case OP_SORTNORM: { 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); if (prelist) model_octant_find_faces_sub(pm,oct,p+prelist,just_count); if (backlist) model_octant_find_faces_sub(pm,oct,p+backlist,just_count); if (onlist) model_octant_find_faces_sub(pm,oct,p+onlist,just_count); if (frontlist) model_octant_find_faces_sub(pm,oct,p+frontlist,just_count); if (postlist) model_octant_find_faces_sub(pm,oct,p+postlist,just_count); } break; case OP_SORTNORM2: { int frontlist = w(p + 8); int backlist = w(p + 12); if (backlist) model_octant_find_faces_sub(pm, oct, p + backlist, just_count); if (frontlist) model_octant_find_faces_sub(pm, oct, p + frontlist, just_count); end = true; // should not continue after this chunk } break; case OP_BOUNDBOX: break; case OP_TMAP2POLY: moff_tmap2poly(p, pm, oct, just_count); end = true; // should not continue after this chunk break; default: mprintf(( "Bad chunk type %d, len=%d in model_octant_find_faces_sub\n", chunk_type, chunk_size )); Int3(); // Bad chunk type! return 0; } p += chunk_size; chunk_type = w(p); chunk_size = w(p+4); if (chunk_type == OP_EOF) end = true; } return 1; } void model_octant_find_faces( polymodel * pm, model_octant * oct ) { ubyte *p; int submodel_num = pm->detail[0]; p = pm->submodel[submodel_num].bsp_data; oct->nverts = 0; model_octant_find_faces_sub(pm, oct, p, 1 ); if ( oct->nverts < 1 ) { oct->nverts = 0; oct->verts = NULL; return; } oct->verts = (vec3d **)vm_malloc( sizeof(vec3d *) * oct->nverts ); Assert(oct->verts!=NULL); oct->nverts = 0; model_octant_find_faces_sub(pm, oct, p, 0 ); // mprintf(( "Octant has %d faces\n", oct->nfaces )); } // Creates the octants for a given polygon model void model_octant_create( polymodel * pm ) { TRACE_SCOPE(tracing::ModelCreateOctants); vec3d min, max, center; int i, x, y, z; min = pm->mins; max = pm->maxs; vm_vec_avg( ¢er, &min, &max ); for (i=0; i<8; i++ ) { x = i & 4; y = i & 2; z = i & 1; if ( x ) { pm->octants[i].max.xyz.x = max.xyz.x; pm->octants[i].min.xyz.x = center.xyz.x; } else { pm->octants[i].max.xyz.x = center.xyz.x; pm->octants[i].min.xyz.x = min.xyz.x; } if ( y ) { pm->octants[i].max.xyz.y = max.xyz.y; pm->octants[i].min.xyz.y = center.xyz.y; } else { pm->octants[i].max.xyz.y = center.xyz.y; pm->octants[i].min.xyz.y = min.xyz.y; } if ( z ) { pm->octants[i].max.xyz.z = max.xyz.z; pm->octants[i].min.xyz.z = center.xyz.z; } else { pm->octants[i].max.xyz.z = center.xyz.z; pm->octants[i].min.xyz.z = min.xyz.z; } model_octant_find_shields( pm, &pm->octants[i] ); model_octant_find_faces( pm, &pm->octants[i] ); } } // frees the memory the octants use for a given polygon model void model_octant_free( polymodel * pm ) { int i; for (i=0; i<8; i++ ) { model_octant * oct = &pm->octants[i]; if ( oct->verts ) { vm_free(oct->verts); oct->verts = NULL; } if ( oct->shield_tris ) { vm_free( oct->shield_tris ); oct->shield_tris = NULL; } } } // Returns which octant point pnt is closet to. This will always return // a valid octant (0-7) since the point doesn't have to be in an octant. // If model_orient and/or model_pos are NULL, pnt is assumed to already // be rotated into the model's local coordinates. // If oct is not null, it will be filled in with a pointer to the octant // data. int model_which_octant_distant_many( vec3d *pnt, int model_num,matrix *model_orient, vec3d * model_pos, polymodel **pm, int *octs) { vec3d tempv, rotpnt; *pm = model_get(model_num); if ( model_orient && model_pos ) { // First, rotate pnt into the model's frame of reference. vm_vec_sub( &tempv, pnt, model_pos ); vm_vec_rotate( &rotpnt, &tempv, model_orient ); } else { rotpnt = *pnt; } vec3d center; vm_vec_avg( ¢er, &((*pm)->mins), &((*pm)->maxs )); int i, x, y, z; if ( rotpnt.xyz.x > center.xyz.x ) x = 1; else x = 0; if ( rotpnt.xyz.y > center.xyz.y ) y = 1; else y = 0; if ( rotpnt.xyz.z > center.xyz.z ) z = 1; else z = 0; i = ( (x<<2) | (y<<1) | z ); octs[0] = i; octs[1] = i ^ 4; // Adjacent octant in x dimension octs[2] = i ^ 2; // Adjacent octant in y dimension octs[3] = i ^ 1; // Adjacent octant in z dimension return i; }