doom3-gpl
Doom 3 GPL source release
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
Model.cpp
Go to the documentation of this file.
1 /*
2 ===========================================================================
3 
4 Doom 3 GPL Source Code
5 Copyright (C) 1999-2011 id Software LLC, a ZeniMax Media company.
6 
7 This file is part of the Doom 3 GPL Source Code (?Doom 3 Source Code?).
8 
9 Doom 3 Source Code is free software: you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation, either version 3 of the License, or
12 (at your option) any later version.
13 
14 Doom 3 Source Code is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18 
19 You should have received a copy of the GNU General Public License
20 along with Doom 3 Source Code. If not, see <http://www.gnu.org/licenses/>.
21 
22 In addition, the Doom 3 Source Code is also subject to certain additional terms. You should have received a copy of these additional terms immediately following the terms and conditions of the GNU General Public License which accompanied the Doom 3 Source Code. If not, please request a copy in writing from id Software at the address below.
23 
24 If you have questions concerning this license or the applicable additional terms, you may contact in writing id Software LLC, c/o ZeniMax Media Inc., Suite 120, Rockville, Maryland 20850 USA.
25 
26 ===========================================================================
27 */
28 
29 #include "../idlib/precompiled.h"
30 #pragma hdrstop
31 
32 #include "tr_local.h"
33 #include "Model_local.h"
34 #include "Model_ase.h"
35 #include "Model_lwo.h"
36 #include "Model_ma.h"
37 
38 idCVar idRenderModelStatic::r_mergeModelSurfaces( "r_mergeModelSurfaces", "1", CVAR_BOOL|CVAR_RENDERER, "combine model surfaces with the same material" );
39 idCVar idRenderModelStatic::r_slopVertex( "r_slopVertex", "0.01", CVAR_RENDERER, "merge xyz coordinates this far apart" );
40 idCVar idRenderModelStatic::r_slopTexCoord( "r_slopTexCoord", "0.001", CVAR_RENDERER, "merge texture coordinates this far apart" );
41 idCVar idRenderModelStatic::r_slopNormal( "r_slopNormal", "0.02", CVAR_RENDERER, "merge normals that dot less than this" );
42 
43 /*
44 ================
45 idRenderModelStatic::idRenderModelStatic
46 ================
47 */
49  name = "<undefined>";
50  bounds.Clear();
53  overlaysAdded = 0;
54  shadowHull = NULL;
55  isStaticWorldModel = false;
56  defaulted = false;
57  purged = false;
58  fastLoad = false;
59  reloadable = true;
60  levelLoadReferenced = false;
61  timeStamp = 0;
62 }
63 
64 /*
65 ================
66 idRenderModelStatic::~idRenderModelStatic
67 ================
68 */
70  PurgeModel();
71 }
72 
73 /*
74 ==============
75 idRenderModelStatic::Print
76 ==============
77 */
79  common->Printf( "%s\n", name.c_str() );
80  common->Printf( "Static model.\n" );
81  common->Printf( "bounds: (%f %f %f) to (%f %f %f)\n",
82  bounds[0][0], bounds[0][1], bounds[0][2],
83  bounds[1][0], bounds[1][1], bounds[1][2] );
84 
85  common->Printf( " verts tris material\n" );
86  for ( int i = 0 ; i < NumSurfaces() ; i++ ) {
87  const modelSurface_t *surf = Surface( i );
88 
89  srfTriangles_t *tri = surf->geometry;
90  const idMaterial *material = surf->shader;
91 
92  if ( !tri ) {
93  common->Printf( "%2i: %s, NULL surface geometry\n", i, material->GetName() );
94  continue;
95  }
96 
97  common->Printf( "%2i: %5i %5i %s", i, tri->numVerts, tri->numIndexes / 3, material->GetName() );
98  if ( tri->generateNormals ) {
99  common->Printf( " (smoothed)\n" );
100  } else {
101  common->Printf( "\n" );
102  }
103  }
104 }
105 
106 /*
107 ==============
108 idRenderModelStatic::Memory
109 ==============
110 */
112  int totalBytes = 0;
113 
114  totalBytes += sizeof( *this );
115  totalBytes += name.DynamicMemoryUsed();
116  totalBytes += surfaces.MemoryUsed();
117 
118  if ( shadowHull ) {
119  totalBytes += R_TriSurfMemory( shadowHull );
120  }
121 
122  for ( int j = 0 ; j < NumSurfaces() ; j++ ) {
123  const modelSurface_t *surf = Surface( j );
124  if ( !surf->geometry ) {
125  continue;
126  }
127  totalBytes += R_TriSurfMemory( surf->geometry );
128  }
129 
130  return totalBytes;
131 }
132 
133 /*
134 ==============
135 idRenderModelStatic::List
136 ==============
137 */
139  int totalTris = 0;
140  int totalVerts = 0;
141  int totalBytes = 0;
142 
143  totalBytes = Memory();
144 
145  char closed = 'C';
146  for ( int j = 0 ; j < NumSurfaces() ; j++ ) {
147  const modelSurface_t *surf = Surface( j );
148  if ( !surf->geometry ) {
149  continue;
150  }
151  if ( !surf->geometry->perfectHull ) {
152  closed = ' ';
153  }
154  totalTris += surf->geometry->numIndexes / 3;
155  totalVerts += surf->geometry->numVerts;
156  }
157  common->Printf( "%c%4ik %3i %4i %4i %s", closed, totalBytes/1024, NumSurfaces(), totalVerts, totalTris, Name() );
158 
159  if ( IsDynamicModel() == DM_CACHED ) {
160  common->Printf( " (DM_CACHED)" );
161  }
162  if ( IsDynamicModel() == DM_CONTINUOUS ) {
163  common->Printf( " (DM_CONTINUOUS)" );
164  }
165  if ( defaulted ) {
166  common->Printf( " (DEFAULTED)" );
167  }
168  if ( bounds[0][0] >= bounds[1][0] ) {
169  common->Printf( " (EMPTY BOUNDS)" );
170  }
171  if ( bounds[1][0] - bounds[0][0] > 100000 ) {
172  common->Printf( " (HUGE BOUNDS)" );
173  }
174 
175  common->Printf( "\n" );
176 }
177 
178 /*
179 ================
180 idRenderModelStatic::IsDefaultModel
181 ================
182 */
184  return defaulted;
185 }
186 
187 /*
188 ================
189 AddCubeFace
190 ================
191 */
192 static void AddCubeFace( srfTriangles_t *tri, idVec3 v1, idVec3 v2, idVec3 v3, idVec3 v4 ) {
193  tri->verts[tri->numVerts+0].Clear();
194  tri->verts[tri->numVerts+0].xyz = v1 * 8;
195  tri->verts[tri->numVerts+0].st[0] = 0;
196  tri->verts[tri->numVerts+0].st[1] = 0;
197 
198  tri->verts[tri->numVerts+1].Clear();
199  tri->verts[tri->numVerts+1].xyz = v2 * 8;
200  tri->verts[tri->numVerts+1].st[0] = 1;
201  tri->verts[tri->numVerts+1].st[1] = 0;
202 
203  tri->verts[tri->numVerts+2].Clear();
204  tri->verts[tri->numVerts+2].xyz = v3 * 8;
205  tri->verts[tri->numVerts+2].st[0] = 1;
206  tri->verts[tri->numVerts+2].st[1] = 1;
207 
208  tri->verts[tri->numVerts+3].Clear();
209  tri->verts[tri->numVerts+3].xyz = v4 * 8;
210  tri->verts[tri->numVerts+3].st[0] = 0;
211  tri->verts[tri->numVerts+3].st[1] = 1;
212 
213  tri->indexes[tri->numIndexes+0] = tri->numVerts + 0;
214  tri->indexes[tri->numIndexes+1] = tri->numVerts + 1;
215  tri->indexes[tri->numIndexes+2] = tri->numVerts + 2;
216  tri->indexes[tri->numIndexes+3] = tri->numVerts + 0;
217  tri->indexes[tri->numIndexes+4] = tri->numVerts + 2;
218  tri->indexes[tri->numIndexes+5] = tri->numVerts + 3;
219 
220  tri->numVerts += 4;
221  tri->numIndexes += 6;
222 }
223 
224 /*
225 ================
226 idRenderModelStatic::MakeDefaultModel
227 ================
228 */
230 
231  defaulted = true;
232 
233  // throw out any surfaces we already have
234  PurgeModel();
235 
236  // create one new surface
237  modelSurface_t surf;
238 
240 
241  surf.shader = tr.defaultMaterial;
242  surf.geometry = tri;
243 
244  R_AllocStaticTriSurfVerts( tri, 24 );
245  R_AllocStaticTriSurfIndexes( tri, 36 );
246 
247  AddCubeFace( tri, idVec3(-1, 1, 1), idVec3(1, 1, 1), idVec3(1, -1, 1), idVec3(-1, -1, 1) );
248  AddCubeFace( tri, idVec3(-1, 1, -1), idVec3(-1, -1, -1), idVec3(1, -1, -1), idVec3(1, 1, -1) );
249 
250  AddCubeFace( tri, idVec3(1, -1, 1), idVec3(1, 1, 1), idVec3(1, 1, -1), idVec3(1, -1, -1) );
251  AddCubeFace( tri, idVec3(-1, -1, 1), idVec3(-1, -1, -1), idVec3(-1, 1, -1), idVec3(-1, 1, 1) );
252 
253  AddCubeFace( tri, idVec3(-1, -1, 1), idVec3(1, -1, 1), idVec3(1, -1, -1), idVec3(-1, -1, -1) );
254  AddCubeFace( tri, idVec3(-1, 1, 1), idVec3(-1, 1, -1), idVec3(1, 1, -1), idVec3(1, 1, 1) );
255 
256  tri->generateNormals = true;
257 
258  AddSurface( surf );
259  FinishSurfaces();
260 }
261 
262 /*
263 ================
264 idRenderModelStatic::PartialInitFromFile
265 ================
266 */
267 void idRenderModelStatic::PartialInitFromFile( const char *fileName ) {
268  fastLoad = true;
269  InitFromFile( fileName );
270 }
271 
272 /*
273 ================
274 idRenderModelStatic::InitFromFile
275 ================
276 */
277 void idRenderModelStatic::InitFromFile( const char *fileName ) {
278  bool loaded;
279  idStr extension;
280 
281  InitEmpty( fileName );
282 
283  // FIXME: load new .proc map format
284 
285  name.ExtractFileExtension( extension );
286 
287  if ( extension.Icmp( "ase" ) == 0 ) {
288  loaded = LoadASE( name );
289  reloadable = true;
290  } else if ( extension.Icmp( "lwo" ) == 0 ) {
291  loaded = LoadLWO( name );
292  reloadable = true;
293  } else if ( extension.Icmp( "flt" ) == 0 ) {
294  loaded = LoadFLT( name );
295  reloadable = true;
296  } else if ( extension.Icmp( "ma" ) == 0 ) {
297  loaded = LoadMA( name );
298  reloadable = true;
299  } else {
300  common->Warning( "idRenderModelStatic::InitFromFile: unknown type for model: \'%s\'", name.c_str() );
301  loaded = false;
302  }
303 
304  if ( !loaded ) {
305  common->Warning( "Couldn't load model: '%s'", name.c_str() );
307  return;
308  }
309 
310  // it is now available for use
311  purged = false;
312 
313  // create the bounds for culling and dynamic surface creation
314  FinishSurfaces();
315 }
316 
317 /*
318 ================
319 idRenderModelStatic::LoadModel
320 ================
321 */
323  PurgeModel();
324  InitFromFile( name );
325 }
326 
327 /*
328 ================
329 idRenderModelStatic::InitEmpty
330 ================
331 */
332 void idRenderModelStatic::InitEmpty( const char *fileName ) {
333  // model names of the form _area* are static parts of the
334  // world, and have already been considered for optimized shadows
335  // other model names are inline entity models, and need to be
336  // shadowed normally
337  if ( !idStr::Cmpn( fileName, "_area", 5 ) ) {
338  isStaticWorldModel = true;
339  } else {
340  isStaticWorldModel = false;
341  }
342 
343  name = fileName;
344  reloadable = false; // if it didn't come from a file, we can't reload it
345  PurgeModel();
346  purged = false;
347  bounds.Zero();
348 }
349 
350 /*
351 ================
352 idRenderModelStatic::AddSurface
353 ================
354 */
356  surfaces.Append( surface );
357  if ( surface.geometry ) {
358  bounds += surface.geometry->bounds;
359  }
360 }
361 
362 /*
363 ================
364 idRenderModelStatic::Name
365 ================
366 */
367 const char *idRenderModelStatic::Name() const {
368  return name;
369 }
370 
371 /*
372 ================
373 idRenderModelStatic::Timestamp
374 ================
375 */
377  return timeStamp;
378 }
379 
380 /*
381 ================
382 idRenderModelStatic::NumSurfaces
383 ================
384 */
386  return surfaces.Num();
387 }
388 
389 /*
390 ================
391 idRenderModelStatic::NumBaseSurfaces
392 ================
393 */
395  return surfaces.Num() - overlaysAdded;
396 }
397 
398 /*
399 ================
400 idRenderModelStatic::Surface
401 ================
402 */
403 const modelSurface_t *idRenderModelStatic::Surface( int surfaceNum ) const {
404  return &surfaces[surfaceNum];
405 }
406 
407 /*
408 ================
409 idRenderModelStatic::AllocSurfaceTriangles
410 ================
411 */
412 srfTriangles_t *idRenderModelStatic::AllocSurfaceTriangles( int numVerts, int numIndexes ) const {
414  R_AllocStaticTriSurfVerts( tri, numVerts );
415  R_AllocStaticTriSurfIndexes( tri, numIndexes );
416  return tri;
417 }
418 
419 /*
420 ================
421 idRenderModelStatic::FreeSurfaceTriangles
422 ================
423 */
425  R_FreeStaticTriSurf( tris );
426 }
427 
428 /*
429 ================
430 idRenderModelStatic::ShadowHull
431 ================
432 */
434  return shadowHull;
435 }
436 
437 /*
438 ================
439 idRenderModelStatic::IsStaticWorldModel
440 ================
441 */
443  return isStaticWorldModel;
444 }
445 
446 /*
447 ================
448 idRenderModelStatic::IsDynamicModel
449 ================
450 */
452  // dynamic subclasses will override this
453  return DM_STATIC;
454 }
455 
456 /*
457 ================
458 idRenderModelStatic::IsReloadable
459 ================
460 */
462  return reloadable;
463 }
464 
465 /*
466 ================
467 idRenderModelStatic::Bounds
468 ================
469 */
471  return bounds;
472 }
473 
474 /*
475 ================
476 idRenderModelStatic::DepthHack
477 ================
478 */
480  return 0.0f;
481 }
482 
483 /*
484 ================
485 idRenderModelStatic::InstantiateDynamicModel
486 ================
487 */
489  if ( cachedModel ) {
490  delete cachedModel;
491  cachedModel = NULL;
492  }
493  common->Error( "InstantiateDynamicModel called on static model '%s'", name.c_str() );
494  return NULL;
495 }
496 
497 /*
498 ================
499 idRenderModelStatic::NumJoints
500 ================
501 */
503  return 0;
504 }
505 
506 /*
507 ================
508 idRenderModelStatic::GetJoints
509 ================
510 */
512  return NULL;
513 }
514 
515 /*
516 ================
517 idRenderModelStatic::GetJointHandle
518 ================
519 */
521  return INVALID_JOINT;
522 }
523 
524 /*
525 ================
526 idRenderModelStatic::GetJointName
527 ================
528 */
529 const char * idRenderModelStatic::GetJointName( jointHandle_t handle ) const {
530  return "";
531 }
532 
533 /*
534 ================
535 idRenderModelStatic::GetDefaultPose
536 ================
537 */
539  return NULL;
540 }
541 
542 /*
543 ================
544 idRenderModelStatic::NearestJoint
545 ================
546 */
547 int idRenderModelStatic::NearestJoint( int surfaceNum, int a, int b, int c ) const {
548  return INVALID_JOINT;
549 }
550 
551 
552 //=====================================================================
553 
554 
555 /*
556 ================
557 idRenderModelStatic::FinishSurfaces
558 
559 The mergeShadows option allows surfaces with different textures to share
560 silhouette edges for shadow calculation, instead of leaving shared edges
561 hanging.
562 
563 If any of the original shaders have the noSelfShadow flag set, the surfaces
564 can't be merged, because they will need to be drawn in different order.
565 
566 If there is only one surface, a separate merged surface won't be generated.
567 
568 A model with multiple surfaces can't later have a skinned shader change the
569 state of the noSelfShadow flag.
570 
571 -----------------
572 
573 Creates mirrored copies of two sided surfaces with normal maps, which would
574 otherwise light funny.
575 
576 Extends the bounds of deformed surfaces so they don't cull incorrectly at screen edges.
577 
578 ================
579 */
581  int i;
582  int totalVerts, totalIndexes;
583 
584  purged = false;
585 
586  // make sure we don't have a huge bounds even if we don't finish everything
587  bounds.Zero();
588 
589  if ( surfaces.Num() == 0 ) {
590  return;
591  }
592 
593  // renderBump doesn't care about most of this
594  if ( fastLoad ) {
595  bounds.Zero();
596  for ( i = 0 ; i < surfaces.Num() ; i++ ) {
597  const modelSurface_t *surf = &surfaces[i];
598 
599  R_BoundTriSurf( surf->geometry );
600  bounds.AddBounds( surf->geometry->bounds );
601  }
602 
603  return;
604  }
605 
606  // cleanup all the final surfaces, but don't create sil edges
607  totalVerts = 0;
608  totalIndexes = 0;
609 
610  // decide if we are going to merge all the surfaces into one shadower
611  int numOriginalSurfaces = surfaces.Num();
612 
613  // make sure there aren't any NULL shaders or geometry
614  for ( i = 0 ; i < numOriginalSurfaces ; i++ ) {
615  const modelSurface_t *surf = &surfaces[i];
616 
617  if ( surf->geometry == NULL || surf->shader == NULL ) {
619  common->Error( "Model %s, surface %i had NULL geometry", name.c_str(), i );
620  }
621  if ( surf->shader == NULL ) {
623  common->Error( "Model %s, surface %i had NULL shader", name.c_str(), i );
624  }
625  }
626 
627  // duplicate and reverse triangles for two sided bump mapped surfaces
628  // note that this won't catch surfaces that have their shaders dynamically
629  // changed, and won't work with animated models.
630  // It is better to create completely separate surfaces, rather than
631  // add vertexes and indexes to the existing surface, because the
632  // tangent generation wouldn't like the acute shared edges
633  for ( i = 0 ; i < numOriginalSurfaces ; i++ ) {
634  const modelSurface_t *surf = &surfaces[i];
635 
636  if ( surf->shader->ShouldCreateBackSides() ) {
637  srfTriangles_t *newTri;
638 
639  newTri = R_CopyStaticTriSurf( surf->geometry );
640  R_ReverseTriangles( newTri );
641 
642  modelSurface_t newSurf;
643 
644  newSurf.shader = surf->shader;
645  newSurf.geometry = newTri;
646 
647  AddSurface( newSurf );
648  }
649  }
650 
651  // clean the surfaces
652  for ( i = 0 ; i < surfaces.Num() ; i++ ) {
653  const modelSurface_t *surf = &surfaces[i];
654 
656  if ( surf->shader->SurfaceCastsShadow() ) {
657  totalVerts += surf->geometry->numVerts;
658  totalIndexes += surf->geometry->numIndexes;
659  }
660  }
661 
662  // add up the total surface area for development information
663  for ( i = 0 ; i < surfaces.Num() ; i++ ) {
664  const modelSurface_t *surf = &surfaces[i];
665  srfTriangles_t *tri = surf->geometry;
666 
667  for ( int j = 0 ; j < tri->numIndexes ; j += 3 ) {
668  float area = idWinding::TriangleArea( tri->verts[tri->indexes[j]].xyz,
669  tri->verts[tri->indexes[j+1]].xyz, tri->verts[tri->indexes[j+2]].xyz );
670  const_cast<idMaterial *>(surf->shader)->AddToSurfaceArea( area );
671  }
672  }
673 
674  // calculate the bounds
675  if ( surfaces.Num() == 0 ) {
676  bounds.Zero();
677  } else {
678  bounds.Clear();
679  for ( i = 0 ; i < surfaces.Num() ; i++ ) {
680  modelSurface_t *surf = &surfaces[i];
681 
682  // if the surface has a deformation, increase the bounds
683  // the amount here is somewhat arbitrary, designed to handle
684  // autosprites and flares, but could be done better with exact
685  // deformation information.
686  // Note that this doesn't handle deformations that are skinned in
687  // at run time...
688  if ( surf->shader->Deform() != DFRM_NONE ) {
689  srfTriangles_t *tri = surf->geometry;
690  idVec3 mid = ( tri->bounds[1] + tri->bounds[0] ) * 0.5f;
691  float radius = ( tri->bounds[0] - mid ).Length();
692  radius += 20.0f;
693 
694  tri->bounds[0][0] = mid[0] - radius;
695  tri->bounds[0][1] = mid[1] - radius;
696  tri->bounds[0][2] = mid[2] - radius;
697 
698  tri->bounds[1][0] = mid[0] + radius;
699  tri->bounds[1][1] = mid[1] + radius;
700  tri->bounds[1][2] = mid[2] + radius;
701  }
702 
703  // add to the model bounds
704  bounds.AddBounds( surf->geometry->bounds );
705 
706  }
707  }
708 }
709 
710 /*
711 =================
712 idRenderModelStatic::ConvertASEToModelSurfaces
713 =================
714 */
715 typedef struct matchVert_s {
716  struct matchVert_s *next;
717  int v, tv;
720 } matchVert_t;
721 
723  aseObject_t * object;
724  aseMesh_t * mesh;
725  aseMaterial_t * material;
726  const idMaterial *im1, *im2;
727  srfTriangles_t *tri;
728  int objectNum;
729  int i, j, k;
730  int v, tv;
731  int * vRemap;
732  int * tvRemap;
733  matchVert_t * mvTable; // all of the match verts
734  matchVert_t ** mvHash; // points inside mvTable for each xyz index
735  matchVert_t * lastmv;
736  matchVert_t * mv;
737  idVec3 normal;
738  float uOffset, vOffset, textureSin, textureCos;
739  float uTiling, vTiling;
740  int * mergeTo;
741  byte * color;
742  static byte identityColor[4] = { 255, 255, 255, 255 };
743  modelSurface_t surf, *modelSurf;
744 
745  if ( !ase ) {
746  return false;
747  }
748  if ( ase->objects.Num() < 1 ) {
749  return false;
750  }
751 
752  timeStamp = ase->timeStamp;
753 
754  // the modeling programs can save out multiple surfaces with a common
755  // material, but we would like to mege them together where possible
756  // meaning that this->NumSurfaces() <= ase->objects.currentElements
757  mergeTo = (int *)_alloca( ase->objects.Num() * sizeof( *mergeTo ) );
758  surf.geometry = NULL;
759  if ( ase->materials.Num() == 0 ) {
760  // if we don't have any materials, dump everything into a single surface
761  surf.shader = tr.defaultMaterial;
762  surf.id = 0;
763  this->AddSurface( surf );
764  for ( i = 0 ; i < ase->objects.Num() ; i++ ) {
765  mergeTo[i] = 0;
766  }
767  } else if ( !r_mergeModelSurfaces.GetBool() ) {
768  // don't merge any
769  for ( i = 0 ; i < ase->objects.Num() ; i++ ) {
770  mergeTo[i] = i;
771  object = ase->objects[i];
772  material = ase->materials[object->materialRef];
773  surf.shader = declManager->FindMaterial( material->name );
774  surf.id = this->NumSurfaces();
775  this->AddSurface( surf );
776  }
777  } else {
778  // search for material matches
779  for ( i = 0 ; i < ase->objects.Num() ; i++ ) {
780  object = ase->objects[i];
781  material = ase->materials[object->materialRef];
782  im1 = declManager->FindMaterial( material->name );
783  if ( im1->IsDiscrete() ) {
784  // flares, autosprites, etc
785  j = this->NumSurfaces();
786  } else {
787  for ( j = 0 ; j < this->NumSurfaces() ; j++ ) {
788  modelSurf = &this->surfaces[j];
789  im2 = modelSurf->shader;
790  if ( im1 == im2 ) {
791  // merge this
792  mergeTo[i] = j;
793  break;
794  }
795  }
796  }
797  if ( j == this->NumSurfaces() ) {
798  // didn't merge
799  mergeTo[i] = j;
800  surf.shader = im1;
801  surf.id = this->NumSurfaces();
802  this->AddSurface( surf );
803  }
804  }
805  }
806 
807  idVectorSubset<idVec3, 3> vertexSubset;
808  idVectorSubset<idVec2, 2> texCoordSubset;
809 
810  // build the surfaces
811  for ( objectNum = 0 ; objectNum < ase->objects.Num() ; objectNum++ ) {
812  object = ase->objects[objectNum];
813  mesh = &object->mesh;
814  material = ase->materials[object->materialRef];
815  im1 = declManager->FindMaterial( material->name );
816 
817  bool normalsParsed = mesh->normalsParsed;
818 
819  // completely ignore any explict normals on surfaces with a renderbump command
820  // which will guarantee the best contours and least vertexes.
821  const char *rb = im1->GetRenderBump();
822  if ( rb && rb[0] ) {
823  normalsParsed = false;
824  }
825 
826  // It seems like the tools our artists are using often generate
827  // verts and texcoords slightly separated that should be merged
828  // note that we really should combine the surfaces with common materials
829  // before doing this operation, because we can miss a slop combination
830  // if they are in different surfaces
831 
832  vRemap = (int *)R_StaticAlloc( mesh->numVertexes * sizeof( vRemap[0] ) );
833 
834  if ( fastLoad ) {
835  // renderbump doesn't care about vertex count
836  for ( j = 0; j < mesh->numVertexes; j++ ) {
837  vRemap[j] = j;
838  }
839  } else {
840  float vertexEpsilon = r_slopVertex.GetFloat();
841  float expand = 2 * 32 * vertexEpsilon;
842  idVec3 mins, maxs;
843 
844  SIMDProcessor->MinMax( mins, maxs, mesh->vertexes, mesh->numVertexes );
845  mins -= idVec3( expand, expand, expand );
846  maxs += idVec3( expand, expand, expand );
847  vertexSubset.Init( mins, maxs, 32, 1024 );
848  for ( j = 0; j < mesh->numVertexes; j++ ) {
849  vRemap[j] = vertexSubset.FindVector( mesh->vertexes, j, vertexEpsilon );
850  }
851  }
852 
853  tvRemap = (int *)R_StaticAlloc( mesh->numTVertexes * sizeof( tvRemap[0] ) );
854 
855  if ( fastLoad ) {
856  // renderbump doesn't care about vertex count
857  for ( j = 0; j < mesh->numTVertexes; j++ ) {
858  tvRemap[j] = j;
859  }
860  } else {
861  float texCoordEpsilon = r_slopTexCoord.GetFloat();
862  float expand = 2 * 32 * texCoordEpsilon;
863  idVec2 mins, maxs;
864 
865  SIMDProcessor->MinMax( mins, maxs, mesh->tvertexes, mesh->numTVertexes );
866  mins -= idVec2( expand, expand );
867  maxs += idVec2( expand, expand );
868  texCoordSubset.Init( mins, maxs, 32, 1024 );
869  for ( j = 0; j < mesh->numTVertexes; j++ ) {
870  tvRemap[j] = texCoordSubset.FindVector( mesh->tvertexes, j, texCoordEpsilon );
871  }
872  }
873 
874  // we need to find out how many unique vertex / texcoord combinations
875  // there are, because ASE tracks them separately but we need them unified
876 
877  // the maximum possible number of combined vertexes is the number of indexes
878  mvTable = (matchVert_t *)R_ClearedStaticAlloc( mesh->numFaces * 3 * sizeof( mvTable[0] ) );
879 
880  // we will have a hash chain based on the xyz values
881  mvHash = (matchVert_t **)R_ClearedStaticAlloc( mesh->numVertexes * sizeof( mvHash[0] ) );
882 
883  // allocate triangle surface
884  tri = R_AllocStaticTriSurf();
885  tri->numVerts = 0;
886  tri->numIndexes = 0;
887  R_AllocStaticTriSurfIndexes( tri, mesh->numFaces * 3 );
888  tri->generateNormals = !normalsParsed;
889 
890  // init default normal, color and tex coord index
891  normal.Zero();
892  color = identityColor;
893  tv = 0;
894 
895  // find all the unique combinations
896  float normalEpsilon = 1.0f - r_slopNormal.GetFloat();
897  for ( j = 0; j < mesh->numFaces; j++ ) {
898  for ( k = 0; k < 3; k++ ) {
899  v = mesh->faces[j].vertexNum[k];
900 
901  if ( v < 0 || v >= mesh->numVertexes ) {
902  common->Error( "ConvertASEToModelSurfaces: bad vertex index in ASE file %s", name.c_str() );
903  }
904 
905  // collapse the position if it was slightly offset
906  v = vRemap[v];
907 
908  // we may or may not have texcoords to compare
909  if ( mesh->numTVFaces == mesh->numFaces && mesh->numTVertexes != 0 ) {
910  tv = mesh->faces[j].tVertexNum[k];
911  if ( tv < 0 || tv >= mesh->numTVertexes ) {
912  common->Error( "ConvertASEToModelSurfaces: bad tex coord index in ASE file %s", name.c_str() );
913  }
914  // collapse the tex coord if it was slightly offset
915  tv = tvRemap[tv];
916  }
917 
918  // we may or may not have normals to compare
919  if ( normalsParsed ) {
920  normal = mesh->faces[j].vertexNormals[k];
921  }
922 
923  // we may or may not have colors to compare
924  if ( mesh->colorsParsed ) {
925  color = mesh->faces[j].vertexColors[k];
926  }
927 
928  // find a matching vert
929  for ( lastmv = NULL, mv = mvHash[v]; mv != NULL; lastmv = mv, mv = mv->next ) {
930  if ( mv->tv != tv ) {
931  continue;
932  }
933  if ( *(unsigned *)mv->color != *(unsigned *)color ) {
934  continue;
935  }
936  if ( !normalsParsed ) {
937  // if we are going to create the normals, just
938  // matching texcoords is enough
939  break;
940  }
941  if ( mv->normal * normal > normalEpsilon ) {
942  break; // we already have this one
943  }
944  }
945  if ( !mv ) {
946  // allocate a new match vert and link to hash chain
947  mv = &mvTable[ tri->numVerts ];
948  mv->v = v;
949  mv->tv = tv;
950  mv->normal = normal;
951  *(unsigned *)mv->color = *(unsigned *)color;
952  mv->next = NULL;
953  if ( lastmv ) {
954  lastmv->next = mv;
955  } else {
956  mvHash[v] = mv;
957  }
958  tri->numVerts++;
959  }
960 
961  tri->indexes[tri->numIndexes] = mv - mvTable;
962  tri->numIndexes++;
963  }
964  }
965 
966  // allocate space for the indexes and copy them
967  if ( tri->numIndexes > mesh->numFaces * 3 ) {
968  common->FatalError( "ConvertASEToModelSurfaces: index miscount in ASE file %s", name.c_str() );
969  }
970  if ( tri->numVerts > mesh->numFaces * 3 ) {
971  common->FatalError( "ConvertASEToModelSurfaces: vertex miscount in ASE file %s", name.c_str() );
972  }
973 
974  // an ASE allows the texture coordinates to be scaled, translated, and rotated
975  if ( ase->materials.Num() == 0 ) {
976  uOffset = vOffset = 0.0f;
977  uTiling = vTiling = 1.0f;
978  textureSin = 0.0f;
979  textureCos = 1.0f;
980  } else {
981  material = ase->materials[object->materialRef];
982  uOffset = -material->uOffset;
983  vOffset = material->vOffset;
984  uTiling = material->uTiling;
985  vTiling = material->vTiling;
986  textureSin = idMath::Sin( material->angle );
987  textureCos = idMath::Cos( material->angle );
988  }
989 
990  // now allocate and generate the combined vertexes
991  R_AllocStaticTriSurfVerts( tri, tri->numVerts );
992  for ( j = 0; j < tri->numVerts; j++ ) {
993  mv = &mvTable[j];
994  tri->verts[ j ].Clear();
995  tri->verts[ j ].xyz = mesh->vertexes[ mv->v ];
996  tri->verts[ j ].normal = mv->normal;
997  *(unsigned *)tri->verts[j].color = *(unsigned *)mv->color;
998  if ( mesh->numTVFaces == mesh->numFaces && mesh->numTVertexes != 0 ) {
999  const idVec2 &tv = mesh->tvertexes[ mv->tv ];
1000  float u = tv.x * uTiling + uOffset;
1001  float v = tv.y * vTiling + vOffset;
1002  tri->verts[ j ].st[0] = u * textureCos + v * textureSin;
1003  tri->verts[ j ].st[1] = u * -textureSin + v * textureCos;
1004  }
1005  }
1006 
1007  R_StaticFree( mvTable );
1008  R_StaticFree( mvHash );
1009  R_StaticFree( tvRemap );
1010  R_StaticFree( vRemap );
1011 
1012  // see if we need to merge with a previous surface of the same material
1013  modelSurf = &this->surfaces[mergeTo[ objectNum ]];
1014  srfTriangles_t *mergeTri = modelSurf->geometry;
1015  if ( !mergeTri ) {
1016  modelSurf->geometry = tri;
1017  } else {
1018  modelSurf->geometry = R_MergeTriangles( mergeTri, tri );
1019  R_FreeStaticTriSurf( tri );
1020  R_FreeStaticTriSurf( mergeTri );
1021  }
1022  }
1023 
1024  return true;
1025 }
1026 
1027 /*
1028 =================
1029 idRenderModelStatic::ConvertLWOToModelSurfaces
1030 =================
1031 */
1033  const idMaterial *im1, *im2;
1034  srfTriangles_t *tri;
1035  lwSurface * lwoSurf;
1036  int numTVertexes;
1037  int i, j, k;
1038  int v, tv;
1039  idVec3 * vList;
1040  int * vRemap;
1041  idVec2 * tvList;
1042  int * tvRemap;
1043  matchVert_t * mvTable; // all of the match verts
1044  matchVert_t ** mvHash; // points inside mvTable for each xyz index
1045  matchVert_t * lastmv;
1046  matchVert_t * mv;
1047  idVec3 normal;
1048  int * mergeTo;
1049  byte color[4];
1050  modelSurface_t surf, *modelSurf;
1051 
1052  if ( !lwo ) {
1053  return false;
1054  }
1055  if ( lwo->surf == NULL ) {
1056  return false;
1057  }
1058 
1059  timeStamp = lwo->timeStamp;
1060 
1061  // count the number of surfaces
1062  i = 0;
1063  for ( lwoSurf = lwo->surf; lwoSurf; lwoSurf = lwoSurf->next ) {
1064  i++;
1065  }
1066 
1067  // the modeling programs can save out multiple surfaces with a common
1068  // material, but we would like to merge them together where possible
1069  mergeTo = (int *)_alloca( i * sizeof( mergeTo[0] ) );
1070  memset( &surf, 0, sizeof( surf ) );
1071 
1072  if ( !r_mergeModelSurfaces.GetBool() ) {
1073  // don't merge any
1074  for ( lwoSurf = lwo->surf, i = 0; lwoSurf; lwoSurf = lwoSurf->next, i++ ) {
1075  mergeTo[i] = i;
1076  surf.shader = declManager->FindMaterial( lwoSurf->name );
1077  surf.id = this->NumSurfaces();
1078  this->AddSurface( surf );
1079  }
1080  } else {
1081  // search for material matches
1082  for ( lwoSurf = lwo->surf, i = 0; lwoSurf; lwoSurf = lwoSurf->next, i++ ) {
1083  im1 = declManager->FindMaterial( lwoSurf->name );
1084  if ( im1->IsDiscrete() ) {
1085  // flares, autosprites, etc
1086  j = this->NumSurfaces();
1087  } else {
1088  for ( j = 0 ; j < this->NumSurfaces() ; j++ ) {
1089  modelSurf = &this->surfaces[j];
1090  im2 = modelSurf->shader;
1091  if ( im1 == im2 ) {
1092  // merge this
1093  mergeTo[i] = j;
1094  break;
1095  }
1096  }
1097  }
1098  if ( j == this->NumSurfaces() ) {
1099  // didn't merge
1100  mergeTo[i] = j;
1101  surf.shader = im1;
1102  surf.id = this->NumSurfaces();
1103  this->AddSurface( surf );
1104  }
1105  }
1106  }
1107 
1108  idVectorSubset<idVec3, 3> vertexSubset;
1109  idVectorSubset<idVec2, 2> texCoordSubset;
1110 
1111  // we only ever use the first layer
1112  lwLayer *layer = lwo->layer;
1113 
1114  // vertex positions
1115  if ( layer->point.count <= 0 ) {
1116  common->Warning( "ConvertLWOToModelSurfaces: model \'%s\' has bad or missing vertex data", name.c_str() );
1117  return false;
1118  }
1119 
1120  vList = (idVec3 *)R_StaticAlloc( layer->point.count * sizeof( vList[0] ) );
1121  for ( j = 0; j < layer->point.count; j++ ) {
1122  vList[j].x = layer->point.pt[j].pos[0];
1123  vList[j].y = layer->point.pt[j].pos[2];
1124  vList[j].z = layer->point.pt[j].pos[1];
1125  }
1126 
1127  // vertex texture coords
1128  numTVertexes = 0;
1129 
1130  if ( layer->nvmaps ) {
1131  for( lwVMap *vm = layer->vmap; vm; vm = vm->next ) {
1132  if ( vm->type == LWID_('T','X','U','V') ) {
1133  numTVertexes += vm->nverts;
1134  }
1135  }
1136  }
1137 
1138  if ( numTVertexes ) {
1139  tvList = (idVec2 *)Mem_Alloc( numTVertexes * sizeof( tvList[0] ) );
1140  int offset = 0;
1141  for( lwVMap *vm = layer->vmap; vm; vm = vm->next ) {
1142  if ( vm->type == LWID_('T','X','U','V') ) {
1143  vm->offset = offset;
1144  for ( k = 0; k < vm->nverts; k++ ) {
1145  tvList[k + offset].x = vm->val[k][0];
1146  tvList[k + offset].y = 1.0f - vm->val[k][1]; // invert the t
1147  }
1148  offset += vm->nverts;
1149  }
1150  }
1151  } else {
1152  common->Warning( "ConvertLWOToModelSurfaces: model \'%s\' has bad or missing uv data", name.c_str() );
1153  numTVertexes = 1;
1154  tvList = (idVec2 *)Mem_ClearedAlloc( numTVertexes * sizeof( tvList[0] ) );
1155  }
1156 
1157  // It seems like the tools our artists are using often generate
1158  // verts and texcoords slightly separated that should be merged
1159  // note that we really should combine the surfaces with common materials
1160  // before doing this operation, because we can miss a slop combination
1161  // if they are in different surfaces
1162 
1163  vRemap = (int *)R_StaticAlloc( layer->point.count * sizeof( vRemap[0] ) );
1164 
1165  if ( fastLoad ) {
1166  // renderbump doesn't care about vertex count
1167  for ( j = 0; j < layer->point.count; j++ ) {
1168  vRemap[j] = j;
1169  }
1170  } else {
1171  float vertexEpsilon = r_slopVertex.GetFloat();
1172  float expand = 2 * 32 * vertexEpsilon;
1173  idVec3 mins, maxs;
1174 
1175  SIMDProcessor->MinMax( mins, maxs, vList, layer->point.count );
1176  mins -= idVec3( expand, expand, expand );
1177  maxs += idVec3( expand, expand, expand );
1178  vertexSubset.Init( mins, maxs, 32, 1024 );
1179  for ( j = 0; j < layer->point.count; j++ ) {
1180  vRemap[j] = vertexSubset.FindVector( vList, j, vertexEpsilon );
1181  }
1182  }
1183 
1184  tvRemap = (int *)R_StaticAlloc( numTVertexes * sizeof( tvRemap[0] ) );
1185 
1186  if ( fastLoad ) {
1187  // renderbump doesn't care about vertex count
1188  for ( j = 0; j < numTVertexes; j++ ) {
1189  tvRemap[j] = j;
1190  }
1191  } else {
1192  float texCoordEpsilon = r_slopTexCoord.GetFloat();
1193  float expand = 2 * 32 * texCoordEpsilon;
1194  idVec2 mins, maxs;
1195 
1196  SIMDProcessor->MinMax( mins, maxs, tvList, numTVertexes );
1197  mins -= idVec2( expand, expand );
1198  maxs += idVec2( expand, expand );
1199  texCoordSubset.Init( mins, maxs, 32, 1024 );
1200  for ( j = 0; j < numTVertexes; j++ ) {
1201  tvRemap[j] = texCoordSubset.FindVector( tvList, j, texCoordEpsilon );
1202  }
1203  }
1204 
1205  // build the surfaces
1206  for ( lwoSurf = lwo->surf, i = 0; lwoSurf; lwoSurf = lwoSurf->next, i++ ) {
1207  im1 = declManager->FindMaterial( lwoSurf->name );
1208 
1209  bool normalsParsed = true;
1210 
1211  // completely ignore any explict normals on surfaces with a renderbump command
1212  // which will guarantee the best contours and least vertexes.
1213  const char *rb = im1->GetRenderBump();
1214  if ( rb && rb[0] ) {
1215  normalsParsed = false;
1216  }
1217 
1218  // we need to find out how many unique vertex / texcoord combinations there are
1219 
1220  // the maximum possible number of combined vertexes is the number of indexes
1221  mvTable = (matchVert_t *)R_ClearedStaticAlloc( layer->polygon.count * 3 * sizeof( mvTable[0] ) );
1222 
1223  // we will have a hash chain based on the xyz values
1224  mvHash = (matchVert_t **)R_ClearedStaticAlloc( layer->point.count * sizeof( mvHash[0] ) );
1225 
1226  // allocate triangle surface
1227  tri = R_AllocStaticTriSurf();
1228  tri->numVerts = 0;
1229  tri->numIndexes = 0;
1230  R_AllocStaticTriSurfIndexes( tri, layer->polygon.count * 3 );
1231  tri->generateNormals = !normalsParsed;
1232 
1233  // find all the unique combinations
1234  float normalEpsilon;
1235  if ( fastLoad ) {
1236  normalEpsilon = 1.0f; // don't merge unless completely exact
1237  } else {
1238  normalEpsilon = 1.0f - r_slopNormal.GetFloat();
1239  }
1240  for ( j = 0; j < layer->polygon.count; j++ ) {
1241  lwPolygon *poly = &layer->polygon.pol[j];
1242 
1243  if ( poly->surf != lwoSurf ) {
1244  continue;
1245  }
1246 
1247  if ( poly->nverts != 3 ) {
1248  common->Warning( "ConvertLWOToModelSurfaces: model %s has too many verts for a poly! Make sure you triplet it down", name.c_str() );
1249  continue;
1250  }
1251 
1252  for ( k = 0; k < 3; k++ ) {
1253 
1254  v = vRemap[poly->v[k].index];
1255 
1256  normal.x = poly->v[k].norm[0];
1257  normal.y = poly->v[k].norm[2];
1258  normal.z = poly->v[k].norm[1];
1259 
1260  // LWO models aren't all that pretty when it comes down to the floating point values they store
1261  normal.FixDegenerateNormal();
1262 
1263  tv = 0;
1264 
1265  color[0] = lwoSurf->color.rgb[0] * 255;
1266  color[1] = lwoSurf->color.rgb[1] * 255;
1267  color[2] = lwoSurf->color.rgb[2] * 255;
1268  color[3] = 255;
1269 
1270  // first set attributes from the vertex
1271  lwPoint *pt = &layer->point.pt[poly->v[k].index];
1272  int nvm;
1273  for ( nvm = 0; nvm < pt->nvmaps; nvm++ ) {
1274  lwVMapPt *vm = &pt->vm[nvm];
1275 
1276  if ( vm->vmap->type == LWID_('T','X','U','V') ) {
1277  tv = tvRemap[vm->index + vm->vmap->offset];
1278  }
1279  if ( vm->vmap->type == LWID_('R','G','B','A') ) {
1280  for ( int chan = 0; chan < 4; chan++ ) {
1281  color[chan] = 255 * vm->vmap->val[vm->index][chan];
1282  }
1283  }
1284  }
1285 
1286  // then override with polygon attributes
1287  for ( nvm = 0; nvm < poly->v[k].nvmaps; nvm++ ) {
1288  lwVMapPt *vm = &poly->v[k].vm[nvm];
1289 
1290  if ( vm->vmap->type == LWID_('T','X','U','V') ) {
1291  tv = tvRemap[vm->index + vm->vmap->offset];
1292  }
1293  if ( vm->vmap->type == LWID_('R','G','B','A') ) {
1294  for ( int chan = 0; chan < 4; chan++ ) {
1295  color[chan] = 255 * vm->vmap->val[vm->index][chan];
1296  }
1297  }
1298  }
1299 
1300  // find a matching vert
1301  for ( lastmv = NULL, mv = mvHash[v]; mv != NULL; lastmv = mv, mv = mv->next ) {
1302  if ( mv->tv != tv ) {
1303  continue;
1304  }
1305  if ( *(unsigned *)mv->color != *(unsigned *)color ) {
1306  continue;
1307  }
1308  if ( !normalsParsed ) {
1309  // if we are going to create the normals, just
1310  // matching texcoords is enough
1311  break;
1312  }
1313  if ( mv->normal * normal > normalEpsilon ) {
1314  break; // we already have this one
1315  }
1316  }
1317  if ( !mv ) {
1318  // allocate a new match vert and link to hash chain
1319  mv = &mvTable[ tri->numVerts ];
1320  mv->v = v;
1321  mv->tv = tv;
1322  mv->normal = normal;
1323  *(unsigned *)mv->color = *(unsigned *)color;
1324  mv->next = NULL;
1325  if ( lastmv ) {
1326  lastmv->next = mv;
1327  } else {
1328  mvHash[v] = mv;
1329  }
1330  tri->numVerts++;
1331  }
1332 
1333  tri->indexes[tri->numIndexes] = mv - mvTable;
1334  tri->numIndexes++;
1335  }
1336  }
1337 
1338  // allocate space for the indexes and copy them
1339  if ( tri->numIndexes > layer->polygon.count * 3 ) {
1340  common->FatalError( "ConvertLWOToModelSurfaces: index miscount in LWO file %s", name.c_str() );
1341  }
1342  if ( tri->numVerts > layer->polygon.count * 3 ) {
1343  common->FatalError( "ConvertLWOToModelSurfaces: vertex miscount in LWO file %s", name.c_str() );
1344  }
1345 
1346  // now allocate and generate the combined vertexes
1347  R_AllocStaticTriSurfVerts( tri, tri->numVerts );
1348  for ( j = 0; j < tri->numVerts; j++ ) {
1349  mv = &mvTable[j];
1350  tri->verts[ j ].Clear();
1351  tri->verts[ j ].xyz = vList[ mv->v ];
1352  tri->verts[ j ].st = tvList[ mv->tv ];
1353  tri->verts[ j ].normal = mv->normal;
1354  *(unsigned *)tri->verts[j].color = *(unsigned *)mv->color;
1355  }
1356 
1357  R_StaticFree( mvTable );
1358  R_StaticFree( mvHash );
1359 
1360  // see if we need to merge with a previous surface of the same material
1361  modelSurf = &this->surfaces[mergeTo[ i ]];
1362  srfTriangles_t *mergeTri = modelSurf->geometry;
1363  if ( !mergeTri ) {
1364  modelSurf->geometry = tri;
1365  } else {
1366  modelSurf->geometry = R_MergeTriangles( mergeTri, tri );
1367  R_FreeStaticTriSurf( tri );
1368  R_FreeStaticTriSurf( mergeTri );
1369  }
1370  }
1371 
1372  R_StaticFree( tvRemap );
1373  R_StaticFree( vRemap );
1374  R_StaticFree( tvList );
1375  R_StaticFree( vList );
1376 
1377  return true;
1378 }
1379 
1380 /*
1381 =================
1382 idRenderModelStatic::ConvertLWOToASE
1383 =================
1384 */
1385 struct aseModel_s *idRenderModelStatic::ConvertLWOToASE( const struct st_lwObject *obj, const char *fileName ) {
1386  int j, k;
1387  aseModel_t *ase;
1388 
1389  if ( !obj ) {
1390  return NULL;
1391  }
1392 
1393  // NOTE: using new operator because aseModel_t contains idList class objects
1394  ase = new aseModel_t;
1395  ase->timeStamp = obj->timeStamp;
1396  ase->objects.Resize( obj->nlayers, obj->nlayers );
1397 
1398  int materialRef = 0;
1399 
1400  for ( lwSurface *surf = obj->surf; surf; surf = surf->next ) {
1401 
1402  aseMaterial_t *mat = (aseMaterial_t *)Mem_ClearedAlloc( sizeof( *mat ) );
1403  strcpy( mat->name, surf->name );
1404  mat->uTiling = mat->vTiling = 1;
1405  mat->angle = mat->uOffset = mat->vOffset = 0;
1406  ase->materials.Append( mat );
1407 
1408  lwLayer *layer = obj->layer;
1409 
1410  aseObject_t *object = (aseObject_t *)Mem_ClearedAlloc( sizeof( *object ) );
1411  object->materialRef = materialRef++;
1412 
1413  aseMesh_t *mesh = &object->mesh;
1414  ase->objects.Append( object );
1415 
1416  mesh->numFaces = layer->polygon.count;
1417  mesh->numTVFaces = mesh->numFaces;
1418  mesh->faces = (aseFace_t *)Mem_Alloc( mesh->numFaces * sizeof( mesh->faces[0] ) );
1419 
1420  mesh->numVertexes = layer->point.count;
1421  mesh->vertexes = (idVec3 *)Mem_Alloc( mesh->numVertexes * sizeof( mesh->vertexes[0] ) );
1422 
1423  // vertex positions
1424  if ( layer->point.count <= 0 ) {
1425  common->Warning( "ConvertLWOToASE: model \'%s\' has bad or missing vertex data", name.c_str() );
1426  }
1427 
1428  for ( j = 0; j < layer->point.count; j++ ) {
1429  mesh->vertexes[j].x = layer->point.pt[j].pos[0];
1430  mesh->vertexes[j].y = layer->point.pt[j].pos[2];
1431  mesh->vertexes[j].z = layer->point.pt[j].pos[1];
1432  }
1433 
1434  // vertex texture coords
1435  mesh->numTVertexes = 0;
1436 
1437  if ( layer->nvmaps ) {
1438  for( lwVMap *vm = layer->vmap; vm; vm = vm->next ) {
1439  if ( vm->type == LWID_('T','X','U','V') ) {
1440  mesh->numTVertexes += vm->nverts;
1441  }
1442  }
1443  }
1444 
1445  if ( mesh->numTVertexes ) {
1446  mesh->tvertexes = (idVec2 *)Mem_Alloc( mesh->numTVertexes * sizeof( mesh->tvertexes[0] ) );
1447  int offset = 0;
1448  for( lwVMap *vm = layer->vmap; vm; vm = vm->next ) {
1449  if ( vm->type == LWID_('T','X','U','V') ) {
1450  vm->offset = offset;
1451  for ( k = 0; k < vm->nverts; k++ ) {
1452  mesh->tvertexes[k + offset].x = vm->val[k][0];
1453  mesh->tvertexes[k + offset].y = 1.0f - vm->val[k][1]; // invert the t
1454  }
1455  offset += vm->nverts;
1456  }
1457  }
1458  } else {
1459  common->Warning( "ConvertLWOToASE: model \'%s\' has bad or missing uv data", fileName );
1460  mesh->numTVertexes = 1;
1461  mesh->tvertexes = (idVec2 *)Mem_ClearedAlloc( mesh->numTVertexes * sizeof( mesh->tvertexes[0] ) );
1462  }
1463 
1464  mesh->normalsParsed = true;
1465  mesh->colorsParsed = true; // because we are falling back to the surface color
1466 
1467  // triangles
1468  int faceIndex = 0;
1469  for ( j = 0; j < layer->polygon.count; j++ ) {
1470  lwPolygon *poly = &layer->polygon.pol[j];
1471 
1472  if ( poly->surf != surf ) {
1473  continue;
1474  }
1475 
1476  if ( poly->nverts != 3 ) {
1477  common->Warning( "ConvertLWOToASE: model %s has too many verts for a poly! Make sure you triplet it down", fileName );
1478  continue;
1479  }
1480 
1481  mesh->faces[faceIndex].faceNormal.x = poly->norm[0];
1482  mesh->faces[faceIndex].faceNormal.y = poly->norm[2];
1483  mesh->faces[faceIndex].faceNormal.z = poly->norm[1];
1484 
1485  for ( k = 0; k < 3; k++ ) {
1486 
1487  mesh->faces[faceIndex].vertexNum[k] = poly->v[k].index;
1488 
1489  mesh->faces[faceIndex].vertexNormals[k].x = poly->v[k].norm[0];
1490  mesh->faces[faceIndex].vertexNormals[k].y = poly->v[k].norm[2];
1491  mesh->faces[faceIndex].vertexNormals[k].z = poly->v[k].norm[1];
1492 
1493  // complete fallbacks
1494  mesh->faces[faceIndex].tVertexNum[k] = 0;
1495 
1496  mesh->faces[faceIndex].vertexColors[k][0] = surf->color.rgb[0] * 255;
1497  mesh->faces[faceIndex].vertexColors[k][1] = surf->color.rgb[1] * 255;
1498  mesh->faces[faceIndex].vertexColors[k][2] = surf->color.rgb[2] * 255;
1499  mesh->faces[faceIndex].vertexColors[k][3] = 255;
1500 
1501  // first set attributes from the vertex
1502  lwPoint *pt = &layer->point.pt[poly->v[k].index];
1503  int nvm;
1504  for ( nvm = 0; nvm < pt->nvmaps; nvm++ ) {
1505  lwVMapPt *vm = &pt->vm[nvm];
1506 
1507  if ( vm->vmap->type == LWID_('T','X','U','V') ) {
1508  mesh->faces[faceIndex].tVertexNum[k] = vm->index + vm->vmap->offset;
1509  }
1510  if ( vm->vmap->type == LWID_('R','G','B','A') ) {
1511  for ( int chan = 0; chan < 4; chan++ ) {
1512  mesh->faces[faceIndex].vertexColors[k][chan] = 255 * vm->vmap->val[vm->index][chan];
1513  }
1514  }
1515  }
1516 
1517  // then override with polygon attributes
1518  for ( nvm = 0; nvm < poly->v[k].nvmaps; nvm++ ) {
1519  lwVMapPt *vm = &poly->v[k].vm[nvm];
1520 
1521  if ( vm->vmap->type == LWID_('T','X','U','V') ) {
1522  mesh->faces[faceIndex].tVertexNum[k] = vm->index + vm->vmap->offset;
1523  }
1524  if ( vm->vmap->type == LWID_('R','G','B','A') ) {
1525  for ( int chan = 0; chan < 4; chan++ ) {
1526  mesh->faces[faceIndex].vertexColors[k][chan] = 255 * vm->vmap->val[vm->index][chan];
1527  }
1528  }
1529  }
1530  }
1531 
1532  faceIndex++;
1533  }
1534 
1535  mesh->numFaces = faceIndex;
1536  mesh->numTVFaces = faceIndex;
1537 
1538  aseFace_t *newFaces = ( aseFace_t* )Mem_Alloc( mesh->numFaces * sizeof ( mesh->faces[0] ) );
1539  memcpy( newFaces, mesh->faces, sizeof( mesh->faces[0] ) * mesh->numFaces );
1540  Mem_Free( mesh->faces );
1541  mesh->faces = newFaces;
1542  }
1543 
1544  return ase;
1545 }
1546 
1547 /*
1548 =================
1549 idRenderModelStatic::ConvertMAToModelSurfaces
1550 =================
1551 */
1553 
1554  maObject_t * object;
1555  maMesh_t * mesh;
1556  maMaterial_t * material;
1557 
1558  const idMaterial *im1, *im2;
1559  srfTriangles_t *tri;
1560  int objectNum;
1561  int i, j, k;
1562  int v, tv;
1563  int * vRemap;
1564  int * tvRemap;
1565  matchVert_t * mvTable; // all of the match verts
1566  matchVert_t ** mvHash; // points inside mvTable for each xyz index
1567  matchVert_t * lastmv;
1568  matchVert_t * mv;
1569  idVec3 normal;
1570  float uOffset, vOffset, textureSin, textureCos;
1571  float uTiling, vTiling;
1572  int * mergeTo;
1573  byte * color;
1574  static byte identityColor[4] = { 255, 255, 255, 255 };
1575  modelSurface_t surf, *modelSurf;
1576 
1577  if ( !ma ) {
1578  return false;
1579  }
1580  if ( ma->objects.Num() < 1 ) {
1581  return false;
1582  }
1583 
1584  timeStamp = ma->timeStamp;
1585 
1586  // the modeling programs can save out multiple surfaces with a common
1587  // material, but we would like to mege them together where possible
1588  // meaning that this->NumSurfaces() <= ma->objects.currentElements
1589  mergeTo = (int *)_alloca( ma->objects.Num() * sizeof( *mergeTo ) );
1590 
1591  surf.geometry = NULL;
1592  if ( ma->materials.Num() == 0 ) {
1593  // if we don't have any materials, dump everything into a single surface
1594  surf.shader = tr.defaultMaterial;
1595  surf.id = 0;
1596  this->AddSurface( surf );
1597  for ( i = 0 ; i < ma->objects.Num() ; i++ ) {
1598  mergeTo[i] = 0;
1599  }
1600  } else if ( !r_mergeModelSurfaces.GetBool() ) {
1601  // don't merge any
1602  for ( i = 0 ; i < ma->objects.Num() ; i++ ) {
1603  mergeTo[i] = i;
1604  object = ma->objects[i];
1605  if(object->materialRef >= 0) {
1606  material = ma->materials[object->materialRef];
1607  surf.shader = declManager->FindMaterial( material->name );
1608  } else {
1609  surf.shader = tr.defaultMaterial;
1610  }
1611  surf.id = this->NumSurfaces();
1612  this->AddSurface( surf );
1613  }
1614  } else {
1615  // search for material matches
1616  for ( i = 0 ; i < ma->objects.Num() ; i++ ) {
1617  object = ma->objects[i];
1618  if(object->materialRef >= 0) {
1619  material = ma->materials[object->materialRef];
1620  im1 = declManager->FindMaterial( material->name );
1621  } else {
1622  im1 = tr.defaultMaterial;
1623  }
1624  if ( im1->IsDiscrete() ) {
1625  // flares, autosprites, etc
1626  j = this->NumSurfaces();
1627  } else {
1628  for ( j = 0 ; j < this->NumSurfaces() ; j++ ) {
1629  modelSurf = &this->surfaces[j];
1630  im2 = modelSurf->shader;
1631  if ( im1 == im2 ) {
1632  // merge this
1633  mergeTo[i] = j;
1634  break;
1635  }
1636  }
1637  }
1638  if ( j == this->NumSurfaces() ) {
1639  // didn't merge
1640  mergeTo[i] = j;
1641  surf.shader = im1;
1642  surf.id = this->NumSurfaces();
1643  this->AddSurface( surf );
1644  }
1645  }
1646  }
1647 
1648  idVectorSubset<idVec3, 3> vertexSubset;
1649  idVectorSubset<idVec2, 2> texCoordSubset;
1650 
1651  // build the surfaces
1652  for ( objectNum = 0 ; objectNum < ma->objects.Num() ; objectNum++ ) {
1653  object = ma->objects[objectNum];
1654  mesh = &object->mesh;
1655  if(object->materialRef >= 0) {
1656  material = ma->materials[object->materialRef];
1657  im1 = declManager->FindMaterial( material->name );
1658  } else {
1659  im1 = tr.defaultMaterial;
1660  }
1661 
1662  bool normalsParsed = mesh->normalsParsed;
1663 
1664  // completely ignore any explict normals on surfaces with a renderbump command
1665  // which will guarantee the best contours and least vertexes.
1666  const char *rb = im1->GetRenderBump();
1667  if ( rb && rb[0] ) {
1668  normalsParsed = false;
1669  }
1670 
1671  // It seems like the tools our artists are using often generate
1672  // verts and texcoords slightly separated that should be merged
1673  // note that we really should combine the surfaces with common materials
1674  // before doing this operation, because we can miss a slop combination
1675  // if they are in different surfaces
1676 
1677  vRemap = (int *)R_StaticAlloc( mesh->numVertexes * sizeof( vRemap[0] ) );
1678 
1679  if ( fastLoad ) {
1680  // renderbump doesn't care about vertex count
1681  for ( j = 0; j < mesh->numVertexes; j++ ) {
1682  vRemap[j] = j;
1683  }
1684  } else {
1685  float vertexEpsilon = r_slopVertex.GetFloat();
1686  float expand = 2 * 32 * vertexEpsilon;
1687  idVec3 mins, maxs;
1688 
1689  SIMDProcessor->MinMax( mins, maxs, mesh->vertexes, mesh->numVertexes );
1690  mins -= idVec3( expand, expand, expand );
1691  maxs += idVec3( expand, expand, expand );
1692  vertexSubset.Init( mins, maxs, 32, 1024 );
1693  for ( j = 0; j < mesh->numVertexes; j++ ) {
1694  vRemap[j] = vertexSubset.FindVector( mesh->vertexes, j, vertexEpsilon );
1695  }
1696  }
1697 
1698  tvRemap = (int *)R_StaticAlloc( mesh->numTVertexes * sizeof( tvRemap[0] ) );
1699 
1700  if ( fastLoad ) {
1701  // renderbump doesn't care about vertex count
1702  for ( j = 0; j < mesh->numTVertexes; j++ ) {
1703  tvRemap[j] = j;
1704  }
1705  } else {
1706  float texCoordEpsilon = r_slopTexCoord.GetFloat();
1707  float expand = 2 * 32 * texCoordEpsilon;
1708  idVec2 mins, maxs;
1709 
1710  SIMDProcessor->MinMax( mins, maxs, mesh->tvertexes, mesh->numTVertexes );
1711  mins -= idVec2( expand, expand );
1712  maxs += idVec2( expand, expand );
1713  texCoordSubset.Init( mins, maxs, 32, 1024 );
1714  for ( j = 0; j < mesh->numTVertexes; j++ ) {
1715  tvRemap[j] = texCoordSubset.FindVector( mesh->tvertexes, j, texCoordEpsilon );
1716  }
1717  }
1718 
1719  // we need to find out how many unique vertex / texcoord / color combinations
1720  // there are, because MA tracks them separately but we need them unified
1721 
1722  // the maximum possible number of combined vertexes is the number of indexes
1723  mvTable = (matchVert_t *)R_ClearedStaticAlloc( mesh->numFaces * 3 * sizeof( mvTable[0] ) );
1724 
1725  // we will have a hash chain based on the xyz values
1726  mvHash = (matchVert_t **)R_ClearedStaticAlloc( mesh->numVertexes * sizeof( mvHash[0] ) );
1727 
1728  // allocate triangle surface
1729  tri = R_AllocStaticTriSurf();
1730  tri->numVerts = 0;
1731  tri->numIndexes = 0;
1732  R_AllocStaticTriSurfIndexes( tri, mesh->numFaces * 3 );
1733  tri->generateNormals = !normalsParsed;
1734 
1735  // init default normal, color and tex coord index
1736  normal.Zero();
1737  color = identityColor;
1738  tv = 0;
1739 
1740  // find all the unique combinations
1741  float normalEpsilon = 1.0f - r_slopNormal.GetFloat();
1742  for ( j = 0; j < mesh->numFaces; j++ ) {
1743  for ( k = 0; k < 3; k++ ) {
1744  v = mesh->faces[j].vertexNum[k];
1745 
1746  if ( v < 0 || v >= mesh->numVertexes ) {
1747  common->Error( "ConvertMAToModelSurfaces: bad vertex index in MA file %s", name.c_str() );
1748  }
1749 
1750  // collapse the position if it was slightly offset
1751  v = vRemap[v];
1752 
1753  // we may or may not have texcoords to compare
1754  if ( mesh->numTVertexes != 0 ) {
1755  tv = mesh->faces[j].tVertexNum[k];
1756  if ( tv < 0 || tv >= mesh->numTVertexes ) {
1757  common->Error( "ConvertMAToModelSurfaces: bad tex coord index in MA file %s", name.c_str() );
1758  }
1759  // collapse the tex coord if it was slightly offset
1760  tv = tvRemap[tv];
1761  }
1762 
1763  // we may or may not have normals to compare
1764  if ( normalsParsed ) {
1765  normal = mesh->faces[j].vertexNormals[k];
1766  }
1767 
1768  //BSM: Todo: Fix the vertex colors
1769  // we may or may not have colors to compare
1770  if ( mesh->faces[j].vertexColors[k] != -1 && mesh->faces[j].vertexColors[k] != -999 ) {
1771 
1772  color = &mesh->colors[mesh->faces[j].vertexColors[k]*4];
1773  }
1774 
1775  // find a matching vert
1776  for ( lastmv = NULL, mv = mvHash[v]; mv != NULL; lastmv = mv, mv = mv->next ) {
1777  if ( mv->tv != tv ) {
1778  continue;
1779  }
1780  if ( *(unsigned *)mv->color != *(unsigned *)color ) {
1781  continue;
1782  }
1783  if ( !normalsParsed ) {
1784  // if we are going to create the normals, just
1785  // matching texcoords is enough
1786  break;
1787  }
1788  if ( mv->normal * normal > normalEpsilon ) {
1789  break; // we already have this one
1790  }
1791  }
1792  if ( !mv ) {
1793  // allocate a new match vert and link to hash chain
1794  mv = &mvTable[ tri->numVerts ];
1795  mv->v = v;
1796  mv->tv = tv;
1797  mv->normal = normal;
1798  *(unsigned *)mv->color = *(unsigned *)color;
1799  mv->next = NULL;
1800  if ( lastmv ) {
1801  lastmv->next = mv;
1802  } else {
1803  mvHash[v] = mv;
1804  }
1805  tri->numVerts++;
1806  }
1807 
1808  tri->indexes[tri->numIndexes] = mv - mvTable;
1809  tri->numIndexes++;
1810  }
1811  }
1812 
1813  // allocate space for the indexes and copy them
1814  if ( tri->numIndexes > mesh->numFaces * 3 ) {
1815  common->FatalError( "ConvertMAToModelSurfaces: index miscount in MA file %s", name.c_str() );
1816  }
1817  if ( tri->numVerts > mesh->numFaces * 3 ) {
1818  common->FatalError( "ConvertMAToModelSurfaces: vertex miscount in MA file %s", name.c_str() );
1819  }
1820 
1821  // an MA allows the texture coordinates to be scaled, translated, and rotated
1822  //BSM: Todo: Does Maya support this and if so how
1823  //if ( ase->materials.Num() == 0 ) {
1824  uOffset = vOffset = 0.0f;
1825  uTiling = vTiling = 1.0f;
1826  textureSin = 0.0f;
1827  textureCos = 1.0f;
1828  //} else {
1829  // material = ase->materials[object->materialRef];
1830  // uOffset = -material->uOffset;
1831  // vOffset = material->vOffset;
1832  // uTiling = material->uTiling;
1833  // vTiling = material->vTiling;
1834  // textureSin = idMath::Sin( material->angle );
1835  // textureCos = idMath::Cos( material->angle );
1836  //}
1837 
1838  // now allocate and generate the combined vertexes
1839  R_AllocStaticTriSurfVerts( tri, tri->numVerts );
1840  for ( j = 0; j < tri->numVerts; j++ ) {
1841  mv = &mvTable[j];
1842  tri->verts[ j ].Clear();
1843  tri->verts[ j ].xyz = mesh->vertexes[ mv->v ];
1844  tri->verts[ j ].normal = mv->normal;
1845  *(unsigned *)tri->verts[j].color = *(unsigned *)mv->color;
1846  if ( mesh->numTVertexes != 0 ) {
1847  const idVec2 &tv = mesh->tvertexes[ mv->tv ];
1848  float u = tv.x * uTiling + uOffset;
1849  float v = tv.y * vTiling + vOffset;
1850  tri->verts[ j ].st[0] = u * textureCos + v * textureSin;
1851  tri->verts[ j ].st[1] = u * -textureSin + v * textureCos;
1852  }
1853  }
1854 
1855  R_StaticFree( mvTable );
1856  R_StaticFree( mvHash );
1857  R_StaticFree( tvRemap );
1858  R_StaticFree( vRemap );
1859 
1860  // see if we need to merge with a previous surface of the same material
1861  modelSurf = &this->surfaces[mergeTo[ objectNum ]];
1862  srfTriangles_t *mergeTri = modelSurf->geometry;
1863  if ( !mergeTri ) {
1864  modelSurf->geometry = tri;
1865  } else {
1866  modelSurf->geometry = R_MergeTriangles( mergeTri, tri );
1867  R_FreeStaticTriSurf( tri );
1868  R_FreeStaticTriSurf( mergeTri );
1869  }
1870  }
1871 
1872  return true;
1873 }
1874 
1875 /*
1876 =================
1877 idRenderModelStatic::LoadASE
1878 =================
1879 */
1880 bool idRenderModelStatic::LoadASE( const char *fileName ) {
1881  aseModel_t *ase;
1882 
1883  ase = ASE_Load( fileName );
1884  if ( ase == NULL ) {
1885  return false;
1886  }
1887 
1889 
1890  ASE_Free( ase );
1891 
1892  return true;
1893 }
1894 
1895 /*
1896 =================
1897 idRenderModelStatic::LoadLWO
1898 =================
1899 */
1900 bool idRenderModelStatic::LoadLWO( const char *fileName ) {
1901  unsigned int failID;
1902  int failPos;
1903  lwObject *lwo;
1904 
1905  lwo = lwGetObject( fileName, &failID, &failPos );
1906  if ( lwo == NULL ) {
1907  return false;
1908  }
1909 
1911 
1912  lwFreeObject( lwo );
1913 
1914  return true;
1915 }
1916 
1917 /*
1918 =================
1919 idRenderModelStatic::LoadMA
1920 =================
1921 */
1922 bool idRenderModelStatic::LoadMA( const char *fileName ) {
1923  maModel_t *ma;
1924 
1925  ma = MA_Load( fileName );
1926  if ( ma == NULL ) {
1927  return false;
1928  }
1929 
1931 
1932  MA_Free( ma );
1933 
1934  return true;
1935 }
1936 
1937 /*
1938 =================
1939 idRenderModelStatic::LoadFLT
1940 
1941 USGS height map data for megaTexture experiments
1942 =================
1943 */
1944 bool idRenderModelStatic::LoadFLT( const char *fileName ) {
1945  float *data;
1946  int len;
1947 
1948  len = fileSystem->ReadFile( fileName, (void **)&data );
1949  if ( len <= 0 ) {
1950  return false;
1951  }
1952  int size = sqrt( len / 4.0f );
1953 
1954  // bound the altitudes
1955  float min = 9999999;
1956  float max = -9999999;
1957  for ( int i = 0 ; i < len/4 ; i++ ) {
1958  data[i] = BigFloat( data[i] );
1959  if ( data[i] == -9999 ) {
1960  data[i] = 0; // unscanned areas
1961  }
1962 
1963  if ( data[i] < min ) {
1964  min = data[i];
1965  }
1966  if ( data[i] > max ) {
1967  max = data[i];
1968  }
1969  }
1970 #if 1
1971  // write out a gray scale height map
1972  byte *image = (byte *)R_StaticAlloc( len );
1973  byte *image_p = image;
1974  for ( int i = 0 ; i < len/4 ; i++ ) {
1975  float v = ( data[i] - min ) / ( max - min );
1976  image_p[0] =
1977  image_p[1] =
1978  image_p[2] = v * 255;
1979  image_p[3] = 255;
1980  image_p += 4;
1981  }
1982  idStr tgaName = fileName;
1983  tgaName.StripFileExtension();
1984  tgaName += ".tga";
1985  R_WriteTGA( tgaName.c_str(), image, size, size, false );
1986  R_StaticFree( image );
1987 //return false;
1988 #endif
1989 
1990  // find the island above sea level
1991  int minX, maxX, minY, maxY;
1992  {
1993  int i;
1994  for ( minX = 0 ; minX < size ; minX++ ) {
1995  for ( i = 0 ; i < size ; i++ ) {
1996  if ( data[i*size + minX] > 1.0 ) {
1997  break;
1998  }
1999  }
2000  if ( i != size ) {
2001  break;
2002  }
2003  }
2004 
2005  for ( maxX = size-1 ; maxX > 0 ; maxX-- ) {
2006  for ( i = 0 ; i < size ; i++ ) {
2007  if ( data[i*size + maxX] > 1.0 ) {
2008  break;
2009  }
2010  }
2011  if ( i != size ) {
2012  break;
2013  }
2014  }
2015 
2016  for ( minY = 0 ; minY < size ; minY++ ) {
2017  for ( i = 0 ; i < size ; i++ ) {
2018  if ( data[minY*size + i] > 1.0 ) {
2019  break;
2020  }
2021  }
2022  if ( i != size ) {
2023  break;
2024  }
2025  }
2026 
2027  for ( maxY = size-1 ; maxY < size ; maxY-- ) {
2028  for ( i = 0 ; i < size ; i++ ) {
2029  if ( data[maxY*size + i] > 1.0 ) {
2030  break;
2031  }
2032  }
2033  if ( i != size ) {
2034  break;
2035  }
2036  }
2037  }
2038 
2039  int width = maxX - minX + 1;
2040  int height = maxY - minY + 1;
2041 
2042 //width /= 2;
2043  // allocate triangle surface
2045  tri->numVerts = width * height;
2046  tri->numIndexes = (width-1) * (height-1) * 6;
2047 
2048  fastLoad = true; // don't do all the sil processing
2049 
2051  R_AllocStaticTriSurfVerts( tri, tri->numVerts );
2052 
2053  for ( int i = 0 ; i < height ; i++ ) {
2054  for ( int j = 0; j < width ; j++ ) {
2055  int v = i * width + j;
2056  tri->verts[ v ].Clear();
2057  tri->verts[ v ].xyz[0] = j * 10; // each sample is 10 meters
2058  tri->verts[ v ].xyz[1] = -i * 10;
2059  tri->verts[ v ].xyz[2] = data[(minY+i)*size+minX+j]; // height is in meters
2060  tri->verts[ v ].st[0] = (float) j / (width-1);
2061  tri->verts[ v ].st[1] = 1.0 - ( (float) i / (height-1) );
2062  }
2063  }
2064 
2065  for ( int i = 0 ; i < height-1 ; i++ ) {
2066  for ( int j = 0; j < width-1 ; j++ ) {
2067  int v = ( i * (width-1) + j ) * 6;
2068 #if 0
2069  tri->indexes[ v + 0 ] = i * width + j;
2070  tri->indexes[ v + 1 ] = (i+1) * width + j;
2071  tri->indexes[ v + 2 ] = (i+1) * width + j + 1;
2072  tri->indexes[ v + 3 ] = i * width + j;
2073  tri->indexes[ v + 4 ] = (i+1) * width + j + 1;
2074  tri->indexes[ v + 5 ] = i * width + j + 1;
2075 #else
2076  tri->indexes[ v + 0 ] = i * width + j;
2077  tri->indexes[ v + 1 ] = i * width + j + 1;
2078  tri->indexes[ v + 2 ] = (i+1) * width + j + 1;
2079  tri->indexes[ v + 3 ] = i * width + j;
2080  tri->indexes[ v + 4 ] = (i+1) * width + j + 1;
2081  tri->indexes[ v + 5 ] = (i+1) * width + j;
2082 #endif
2083  }
2084  }
2085 
2086  fileSystem->FreeFile( data );
2087 
2088  modelSurface_t surface;
2089 
2090  surface.geometry = tri;
2091  surface.id = 0;
2092  surface.shader = tr.defaultMaterial; // declManager->FindMaterial( "shaderDemos/megaTexture" );
2093 
2094  this->AddSurface( surface );
2095 
2096  return true;
2097 }
2098 
2099 
2100 //=============================================================================
2101 
2102 /*
2103 ================
2104 idRenderModelStatic::PurgeModel
2105 ================
2106 */
2108  int i;
2109  modelSurface_t *surf;
2110 
2111  for ( i = 0 ; i < surfaces.Num() ; i++ ) {
2112  surf = &surfaces[i];
2113 
2114  if ( surf->geometry ) {
2115  R_FreeStaticTriSurf( surf->geometry );
2116  }
2117  }
2118  surfaces.Clear();
2119 
2120  purged = true;
2121 }
2122 
2123 /*
2124 ==============
2125 idRenderModelStatic::FreeVertexCache
2126 
2127 We are about to restart the vertex cache, so dump everything
2128 ==============
2129 */
2131  for ( int j = 0 ; j < surfaces.Num() ; j++ ) {
2132  srfTriangles_t *tri = surfaces[j].geometry;
2133  if ( !tri ) {
2134  continue;
2135  }
2136  if ( tri->ambientCache ) {
2137  vertexCache.Free( tri->ambientCache );
2138  tri->ambientCache = NULL;
2139  }
2140  // static shadows may be present
2141  if ( tri->shadowCache ) {
2142  vertexCache.Free( tri->shadowCache );
2143  tri->shadowCache = NULL;
2144  }
2145  }
2146 }
2147 
2148 /*
2149 ================
2150 idRenderModelStatic::ReadFromDemoFile
2151 ================
2152 */
2154  PurgeModel();
2155 
2156  InitEmpty( f->ReadHashString() );
2157 
2158  int i, j, numSurfaces;
2159  f->ReadInt( numSurfaces );
2160 
2161  for ( i = 0 ; i < numSurfaces ; i++ ) {
2162  modelSurface_t surf;
2163 
2165 
2167 
2168  f->ReadInt( tri->numIndexes );
2170  for ( j = 0; j < tri->numIndexes; ++j )
2171  f->ReadInt( (int&)tri->indexes[j] );
2172 
2173  f->ReadInt( tri->numVerts );
2174  R_AllocStaticTriSurfVerts( tri, tri->numVerts );
2175  for ( j = 0; j < tri->numVerts; ++j ) {
2176  f->ReadVec3( tri->verts[j].xyz );
2177  f->ReadVec2( tri->verts[j].st );
2178  f->ReadVec3( tri->verts[j].normal );
2179  f->ReadVec3( tri->verts[j].tangents[0] );
2180  f->ReadVec3( tri->verts[j].tangents[1] );
2181  f->ReadUnsignedChar( tri->verts[j].color[0] );
2182  f->ReadUnsignedChar( tri->verts[j].color[1] );
2183  f->ReadUnsignedChar( tri->verts[j].color[2] );
2184  f->ReadUnsignedChar( tri->verts[j].color[3] );
2185  }
2186 
2187  surf.geometry = tri;
2188 
2189  this->AddSurface( surf );
2190  }
2191  this->FinishSurfaces();
2192 }
2193 
2194 /*
2195 ================
2196 idRenderModelStatic::WriteToDemoFile
2197 ================
2198 */
2200  int data[1];
2201 
2202  // note that it has been updated
2204 
2205  data[0] = DC_DEFINE_MODEL;
2206  f->WriteInt( data[0] );
2207  f->WriteHashString( this->Name() );
2208 
2209  int i, j, iData = surfaces.Num();
2210  f->WriteInt( iData );
2211 
2212  for ( i = 0 ; i < surfaces.Num() ; i++ ) {
2213  const modelSurface_t *surf = &surfaces[i];
2214 
2215  f->WriteHashString( surf->shader->GetName() );
2216 
2217  srfTriangles_t *tri = surf->geometry;
2218  f->WriteInt( tri->numIndexes );
2219  for ( j = 0; j < tri->numIndexes; ++j )
2220  f->WriteInt( (int&)tri->indexes[j] );
2221  f->WriteInt( tri->numVerts );
2222  for ( j = 0; j < tri->numVerts; ++j ) {
2223  f->WriteVec3( tri->verts[j].xyz );
2224  f->WriteVec2( tri->verts[j].st );
2225  f->WriteVec3( tri->verts[j].normal );
2226  f->WriteVec3( tri->verts[j].tangents[0] );
2227  f->WriteVec3( tri->verts[j].tangents[1] );
2228  f->WriteUnsignedChar( tri->verts[j].color[0] );
2229  f->WriteUnsignedChar( tri->verts[j].color[1] );
2230  f->WriteUnsignedChar( tri->verts[j].color[2] );
2231  f->WriteUnsignedChar( tri->verts[j].color[3] );
2232  }
2233  }
2234 }
2235 
2236 /*
2237 ================
2238 idRenderModelStatic::IsLoaded
2239 ================
2240 */
2242  return !purged;
2243 }
2244 
2245 /*
2246 ================
2247 idRenderModelStatic::SetLevelLoadReferenced
2248 ================
2249 */
2251  levelLoadReferenced = referenced;
2252 }
2253 
2254 /*
2255 ================
2256 idRenderModelStatic::IsLevelLoadReferenced
2257 ================
2258 */
2260  return levelLoadReferenced;
2261 }
2262 
2263 /*
2264 =================
2265 idRenderModelStatic::TouchData
2266 =================
2267 */
2269  for ( int i = 0 ; i < surfaces.Num() ; i++ ) {
2270  const modelSurface_t *surf = &surfaces[i];
2271 
2272  // re-find the material to make sure it gets added to the
2273  // level keep list
2274  declManager->FindMaterial( surf->shader->GetName() );
2275  }
2276 }
2277 
2278 /*
2279 =================
2280 idRenderModelStatic::DeleteSurfaceWithId
2281 =================
2282 */
2284  int i;
2285 
2286  for ( i = 0; i < surfaces.Num(); i++ ) {
2287  if ( surfaces[i].id == id ) {
2288  R_FreeStaticTriSurf( surfaces[i].geometry );
2289  surfaces.RemoveIndex( i );
2290  return true;
2291  }
2292  }
2293  return false;
2294 }
2295 
2296 /*
2297 =================
2298 idRenderModelStatic::DeleteSurfacesWithNegativeId
2299 =================
2300 */
2302  int i;
2303 
2304  for ( i = 0; i < surfaces.Num(); i++ ) {
2305  if ( surfaces[i].id < 0 ) {
2306  R_FreeStaticTriSurf( surfaces[i].geometry );
2307  surfaces.RemoveIndex( i );
2308  i--;
2309  }
2310  }
2311 }
2312 
2313 /*
2314 =================
2315 idRenderModelStatic::FindSurfaceWithId
2316 =================
2317 */
2318 bool idRenderModelStatic::FindSurfaceWithId( int id, int &surfaceNum ) {
2319  int i;
2320 
2321  for ( i = 0; i < surfaces.Num(); i++ ) {
2322  if ( surfaces[i].id == id ) {
2323  surfaceNum = i;
2324  return true;
2325  }
2326  }
2327  return false;
2328 }
struct st_lwSurface * next
Definition: Model_lwo.h:435
jointHandle_t
Definition: Model.h:156
bool SurfaceCastsShadow(void) const
Definition: Material.h:392
virtual int NumJoints(void) const
Definition: Model.cpp:502
virtual ~idRenderModelStatic()
Definition: Model.cpp:69
virtual const char * Name() const
Definition: Model.cpp:367
virtual int ReadUnsignedChar(unsigned char &value)
Definition: File.cpp:364
byte color[4]
Definition: MegaTexture.cpp:54
int offset
Definition: Model_lwo.h:477
virtual int WriteUnsignedChar(const unsigned char value)
Definition: File.cpp:517
virtual const char * GetJointName(jointHandle_t handle) const
Definition: Model.cpp:529
bool AddBounds(const idBounds &a)
Definition: Bounds.h:255
maModel_t * MA_Load(const char *fileName)
Definition: Model_ma.cpp:1008
bool FindSurfaceWithId(int id, int &surfaceNum)
Definition: Model.cpp:2318
idList< modelSurface_t > surfaces
Definition: Model_local.h:106
float uTiling
Definition: Model_ase.h:71
#define min(a, b)
virtual jointHandle_t GetJointHandle(const char *name) const
Definition: Model.cpp:520
virtual int virtual int ReadInt(int &value)
Definition: File.cpp:311
#define LWID_(a, b, c, d)
Definition: Model_lwo.h:44
lwCParam color
Definition: Model_lwo.h:438
virtual const idMD5Joint * GetJoints(void) const
Definition: Model.cpp:511
srfTriangles_t * R_MergeTriangles(const srfTriangles_t *tri1, const srfTriangles_t *tri2)
void Clear(void)
Definition: DrawVert.h:73
lwSurface * surf
Definition: Model_lwo.h:504
virtual int Memory() const
Definition: Model.cpp:111
int numVerts
Definition: Model.h:98
bool ConvertASEToModelSurfaces(const struct aseModel_s *ase)
Definition: Model.cpp:722
void Zero(void)
Definition: Bounds.h:206
bool normalsParsed
Definition: Model_ase.h:61
virtual void InitFromFile(const char *fileName)
Definition: Model.cpp:277
virtual void List() const
Definition: Model.cpp:138
float y
Definition: Vector.h:55
virtual bool IsReloadable() const
Definition: Model.cpp:461
byte vertexColors[3][4]
Definition: Model_ase.h:45
float GetFloat(void) const
Definition: CVarSystem.h:144
const GLdouble * v
Definition: glext.h:2936
bool ConvertLWOToModelSurfaces(const struct st_lwObject *lwo)
Definition: Model.cpp:1032
maFace_t * faces
Definition: Model_ma.h:91
virtual void PartialInitFromFile(const char *fileName)
Definition: Model.cpp:267
virtual int ReadFile(const char *relativePath, void **buffer, ID_TIME_T *timestamp=NULL)=0
struct matchVert_s * next
Definition: Model.cpp:716
idVec3 xyz
Definition: DrawVert.h:42
virtual idRenderModel * InstantiateDynamicModel(const struct renderEntity_s *ent, const struct viewDef_s *view, idRenderModel *cachedModel)
Definition: Model.cpp:488
virtual srfTriangles_t * AllocSurfaceTriangles(int numVerts, int numIndexes) const
Definition: Model.cpp:412
virtual const modelSurface_t * Surface(int surfaceNum) const
Definition: Model.cpp:403
lwVMap * vmap
Definition: Model_lwo.h:542
bool LoadMA(const char *filename)
Definition: Model.cpp:1922
float z
Definition: Vector.h:320
lwPolVert * v
Definition: Model_lwo.h:511
idVec3 tangents[2]
Definition: DrawVert.h:45
idFileSystem * fileSystem
Definition: FileSystem.cpp:500
virtual void SetLevelLoadReferenced(bool referenced)
Definition: Model.cpp:2250
const idMaterial * shader
Definition: Model.h:146
void ASE_Free(aseModel_t *ase)
Definition: Model_ase.cpp:857
lwVMapPt * vm
Definition: Model_lwo.h:493
deform_t Deform(void) const
Definition: Material.h:516
bool ConvertMAToModelSurfaces(const struct maModel_s *ma)
Definition: Model.cpp:1552
const char * GetName(void) const
Definition: DeclManager.h:140
Definition: Vector.h:316
case const float
Definition: Callbacks.cpp:62
virtual dynamicModel_t IsDynamicModel() const
Definition: Model.cpp:451
GLenum GLsizei GLenum GLenum const GLvoid * image
Definition: glext.h:2855
idVec2 * tvertexes
Definition: Model_ma.h:79
lwVMap * vmap
Definition: Model_lwo.h:481
bool perfectHull
Definition: Model.h:94
virtual bool IsStaticWorldModel() const
Definition: Model.cpp:442
int vertexNum[3]
Definition: Model_ase.h:41
int vertexColors[3]
Definition: Model_ma.h:61
void Clear(void)
Definition: Bounds.h:201
lwPoint * pt
Definition: Model_lwo.h:517
virtual const idMaterial * FindMaterial(const char *name, bool makeDefault=true)=0
int nvmaps
Definition: Model_lwo.h:541
idList< aseMaterial_t * > materials
Definition: Model_ase.h:87
float vTiling
Definition: Model_ase.h:71
srfTriangles_t * R_AllocStaticTriSurf(void)
Definition: tr_trisurf.cpp:523
GLenum GLsizei len
Definition: glext.h:3472
GLhandleARB obj
Definition: glext.h:3602
float x
Definition: Vector.h:318
bool DeleteSurfaceWithId(int id)
Definition: Model.cpp:2283
idList< aseObject_t * > objects
Definition: Model_ase.h:88
virtual void WriteToDemoFile(class idDemoFile *f)
Definition: Model.cpp:2199
virtual int WriteVec2(const idVec2 &vec)
Definition: File.cpp:559
struct vertCache_s * ambientCache
Definition: Model.h:137
int i
Definition: process.py:33
virtual void FreeFile(void *buffer)=0
aseFace_t * faces
Definition: Model_ase.h:65
int Cmpn(const char *text, int n) const
Definition: Str.h:657
GLintptr offset
Definition: glext.h:3113
void MakeDefaultModel()
Definition: Model.cpp:229
static idCVar r_slopTexCoord
Definition: Model_local.h:126
int numFaces
Definition: Model_ma.h:90
srfTriangles_t * R_CopyStaticTriSurf(const srfTriangles_t *tri)
Definition: tr_trisurf.cpp:536
int Icmp(const char *text) const
Definition: Str.h:667
virtual void ReadFromDemoFile(class idDemoFile *f)
Definition: Model.cpp:2153
idList< maObject_t * > objects
Definition: Model_ma.h:133
lwPointList point
Definition: Model_lwo.h:539
virtual void LoadModel()
Definition: Model.cpp:322
lwPolygon * pol
Definition: Model_lwo.h:525
idVec2 st
Definition: DrawVert.h:43
GLfloat GLfloat GLfloat v2
Definition: glext.h:3608
bool normalsParsed
Definition: Model_ma.h:96
virtual void VPCALL MinMax(float &min, float &max, const float *src, const int count)=0
int tVertexNum[3]
Definition: Model_ase.h:42
virtual void InitEmpty(const char *name)
Definition: Model.cpp:332
idVec3 faceNormal
Definition: Model_ase.h:43
float uOffset
Definition: Model_ase.h:70
Definition: Vector.h:52
virtual int WriteInt(const int value)
Definition: File.cpp:468
const char * GetRenderBump() const
Definition: Material.h:485
const GLubyte * c
Definition: glext.h:4677
idStr & StripFileExtension(void)
Definition: Str.cpp:757
virtual void FinishSurfaces()
Definition: Model.cpp:580
idVec3 vertexNormals[3]
Definition: Model_ase.h:44
void DeleteSurfacesWithNegativeId(void)
Definition: Model.cpp:2301
idVec3 normal
Definition: Model.cpp:719
static float Sin(float a)
Definition: Math.h:310
idBounds bounds
Definition: Model.h:87
ID_TIME_T timeStamp
Definition: Model_ase.h:86
idCommon * common
Definition: Common.cpp:206
virtual int ReadVec2(idVec2 &vec)
Definition: File.cpp:413
void R_CleanupTriangles(srfTriangles_t *tri, bool createNormals, bool identifySilEdges, bool useUnsmoothedTangents)
static float TriangleArea(const idVec3 &a, const idVec3 &b, const idVec3 &c)
Definition: Winding.cpp:1446
#define NULL
Definition: Lib.h:88
srfTriangles_t * geometry
Definition: Model.h:147
float y
Definition: Vector.h:319
virtual int ReadVec3(idVec3 &vec)
Definition: File.cpp:424
GLsizei GLsizei GLenum GLenum const GLvoid * data
Definition: glext.h:2853
struct aseModel_s * ConvertLWOToASE(const struct st_lwObject *obj, const char *fileName)
Definition: Model.cpp:1385
lwLayer * layer
Definition: Model_lwo.h:559
int tVertexNum[3]
Definition: Model_ma.h:60
virtual void virtual void FatalError(const char *fmt,...) id_attribute((format(printf
int numTVertexes
Definition: Model_ase.h:52
void R_FreeStaticTriSurf(srfTriangles_t *tri)
Definition: tr_trisurf.cpp:489
int numTVFaces
Definition: Model_ase.h:55
lwPolygonList polygon
Definition: Model_lwo.h:540
byte * colors
Definition: Model_ma.h:87
float x
Definition: Vector.h:54
byte color[4]
Definition: Model.cpp:718
void R_WriteTGA(const char *filename, const byte *data, int width, int height, bool flipVertical=false)
Definition: Image_files.cpp:85
int vertexNum[3]
Definition: Model_ma.h:59
struct matchVert_s matchVert_t
float vOffset
Definition: Model_ase.h:70
void Mem_Free(void *ptr)
Definition: Heap.cpp:1087
idVec3 normal
Definition: DrawVert.h:44
virtual ID_TIME_T Timestamp() const
Definition: Model.cpp:376
virtual const idJointQuat * GetDefaultPose(void) const
Definition: Model.cpp:538
void R_ReverseTriangles(srfTriangles_t *tri)
ID_TIME_T timeStamp
Definition: Model_ma.h:131
float BigFloat(float l)
Definition: Lib.cpp:282
GLenum GLsizei width
Definition: glext.h:2846
char name[128]
Definition: Model_ma.h:102
int numFaces
Definition: Model_ase.h:54
ID_TIME_T timeStamp
Definition: Model_lwo.h:558
struct vertCache_s * shadowCache
Definition: Model.h:139
virtual int NumBaseSurfaces() const
Definition: Model.cpp:394
GLubyte GLubyte GLubyte a
Definition: glext.h:4662
virtual void Printf(const char *fmt,...) id_attribute((format(printf
void R_BoundTriSurf(srfTriangles_t *tri)
Definition: tr_trisurf.cpp:704
struct aseModel_s aseModel_t
bool FixDegenerateNormal(void)
Definition: Vector.h:535
void MA_Free(maModel_t *ma)
Definition: Model_ma.cpp:1039
bool UseUnsmoothedTangents(void) const
Definition: Material.h:417
virtual void FreeVertexCache()
Definition: Model.cpp:2130
bool colorsParsed
Definition: Model_ase.h:60
bool LoadASE(const char *fileName)
Definition: Model.cpp:1880
idList< maMaterial_t * > materials
Definition: Model_ma.h:132
float angle
Definition: Model_ase.h:72
GLfloat GLfloat v1
Definition: glext.h:3607
GLenum GLsizei GLsizei height
Definition: glext.h:2856
int numTVertexes
Definition: Model_ma.h:78
int FindVector(const type *vectorList, const int vectorNum, const float epsilon)
Definition: VectorSet.h:230
virtual bool IsDefaultModel() const
Definition: Model.cpp:183
virtual idBounds Bounds(const struct renderEntity_s *ent) const
Definition: Model.cpp:470
idDeclManager * declManager
float rgb[3]
Definition: Model_lwo.h:406
GLubyte GLubyte b
Definition: glext.h:4662
int nvmaps
Definition: Model_lwo.h:492
lwVMapPt * vm
Definition: Model_lwo.h:500
idVec2 * tvertexes
Definition: Model_ase.h:63
GLfloat GLfloat GLfloat GLfloat v3
Definition: glext.h:3609
int Append(const type &obj)
Definition: List.h:646
virtual float DepthHack() const
Definition: Model.cpp:479
bool GetBool(void) const
Definition: CVarSystem.h:142
lwSurface * surf
Definition: Model_lwo.h:562
tuple f
Definition: idal.py:89
void * R_ClearedStaticAlloc(int bytes)
Definition: tr_main.cpp:322
float ** val
Definition: Model_lwo.h:474
char name[128]
Definition: Model_ase.h:69
int Num(void) const
Definition: List.h:265
unsigned char byte
Definition: Lib.h:75
void * R_StaticAlloc(int bytes)
Definition: tr_main.cpp:301
dynamicModel_t
Definition: Model.h:150
unsigned int type
Definition: Model_lwo.h:468
const GLcharARB * name
Definition: glext.h:3629
GLsizeiptr size
Definition: glext.h:3112
bool ShouldCreateBackSides(void) const
Definition: Material.h:412
Definition: Str.h:116
static idCVar r_slopNormal
Definition: Model_local.h:127
byte color[4]
Definition: DrawVert.h:46
virtual void Print() const
Definition: Model.cpp:78
virtual void FreeSurfaceTriangles(srfTriangles_t *tris) const
Definition: Model.cpp:424
void * Mem_ClearedAlloc(const int size)
Definition: Heap.cpp:1149
const char * c_str(void) const
Definition: Str.h:487
float norm[3]
Definition: Model_lwo.h:509
glIndex_t * indexes
Definition: Model.h:102
idVertexCache vertexCache
Definition: VertexCache.cpp:41
virtual int NumSurfaces() const
Definition: Model.cpp:385
idRenderSystemLocal tr
lwObject * lwGetObject(const char *filename, unsigned int *failID, int *failpos)
Definition: Model_lwo.cpp:1445
virtual void PurgeModel()
Definition: Model.cpp:2107
const char * ReadHashString()
Definition: DemoFile.cpp:212
void R_AllocStaticTriSurfIndexes(srfTriangles_t *tri, int numIndexes)
Definition: tr_trisurf.cpp:565
float pos[3]
Definition: Model_lwo.h:489
void * Mem_Alloc(const int size)
Definition: Heap.cpp:1067
GLint j
Definition: qgl.h:264
void Free(vertCache_t *buffer)
idVec3 vertexNormals[3]
Definition: Model_ma.h:62
virtual bool IsLevelLoadReferenced()
Definition: Model.cpp:2259
void Init(const type &mins, const type &maxs, const int boxHashSize, const int initialSize)
Definition: VectorSet.h:206
int numIndexes
Definition: Model.h:101
int numVertexes
Definition: Model_ma.h:71
static idCVar r_mergeModelSurfaces
Definition: Model_local.h:124
virtual void TouchData()
Definition: Model.cpp:2268
void lwFreeObject(lwObject *object)
Definition: Model_lwo.cpp:1411
void R_StaticFree(void *data)
Definition: tr_main.cpp:335
bool LoadFLT(const char *fileName)
Definition: Model.cpp:1944
struct st_lwVMap * next
Definition: Model_lwo.h:466
#define max(x, y)
Definition: os.h:70
virtual void Error(const char *fmt,...) id_attribute((format(printf
static idCVar r_slopVertex
Definition: Model_local.h:125
bool IsDiscrete(void) const
Definition: Material.h:441
virtual srfTriangles_t * ShadowHull() const
Definition: Model.cpp:433
int R_TriSurfMemory(const srfTriangles_t *tri)
Definition: tr_trisurf.cpp:290
int numVertexes
Definition: Model_ase.h:51
srfTriangles_t * shadowHull
Definition: Model_local.h:115
void R_AllocStaticTriSurfVerts(srfTriangles_t *tri, int numVerts)
Definition: tr_trisurf.cpp:555
void Zero(void)
Definition: Vector.h:415
virtual void virtual void Warning(const char *fmt,...) id_attribute((format(printf
void Resize(int newsize)
Definition: List.h:360
idVec3 * vertexes
Definition: Model_ase.h:62
virtual bool IsLoaded()
Definition: Model.cpp:2241
virtual int WriteVec3(const idVec3 &vec)
Definition: File.cpp:570
int materialRef
Definition: Model_ma.h:110
const idMaterial * defaultMaterial
Definition: tr_local.h:779
aseModel_t * ASE_Load(const char *fileName)
Definition: Model_ase.cpp:834
idDrawVert * verts
Definition: Model.h:99
bool LoadLWO(const char *fileName)
Definition: Model.cpp:1900
float norm[3]
Definition: Model_lwo.h:498
virtual int NearestJoint(int surfaceNum, int a, int b, int c) const
Definition: Model.cpp:547
char * name
Definition: Model_lwo.h:436
virtual void AddSurface(modelSurface_t surface)
Definition: Model.cpp:355
idVec3 * vertexes
Definition: Model_ma.h:72
static float Cos(float a)
Definition: Math.h:346
void WriteHashString(const char *str)
Definition: DemoFile.cpp:248
idSIMDProcessor * SIMDProcessor
Definition: Simd.cpp:43
bool generateNormals
Definition: Model.h:91