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