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