1 /*
2 ===========================================================================
3 Copyright (C) 1999 - 2005, Id Software, Inc.
4 Copyright (C) 2000 - 2013, Raven Software, Inc.
5 Copyright (C) 2001 - 2013, Activision, Inc.
6 Copyright (C) 2005 - 2015, ioquake3 contributors
7 Copyright (C) 2013 - 2015, OpenJK contributors
8 
9 This file is part of the OpenJK source code.
10 
11 OpenJK is free software; you can redistribute it and/or modify it
12 under the terms of the GNU General Public License version 2 as
13 published by the Free Software Foundation.
14 
15 This program is distributed in the hope that it will be useful,
16 but WITHOUT ANY WARRANTY; without even the implied warranty of
17 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18 GNU General Public License for more details.
19 
20 You should have received a copy of the GNU General Public License
21 along with this program; if not, see <http://www.gnu.org/licenses/>.
22 ===========================================================================
23 */
24 
25 // tr_models.c -- model loading and caching
26 
27 #include "../server/exe_headers.h"
28 
29 #include "tr_common.h"
30 #include "tr_local.h"
31 #include "qcommon/matcomp.h"
32 #include "../qcommon/sstring.h"
33 
34 #define	LL(x) x=LittleLong(x)
35 #define	LS(x) x=LittleShort(x)
36 #define	LF(x) x=LittleFloat(x)
37 
38 void RE_LoadWorldMap_Actual( const char *name, world_t &worldData, int index ); //should only be called for sub-bsp instances
39 
40 static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *name, qboolean &bAlreadyCached );
41 
42 /*
43 Ghoul2 Insert Start
44 */
45 
46 typedef	struct modelHash_s
47 {
48 	char		name[MAX_QPATH];
49 	qhandle_t	handle;
50 	struct		modelHash_s	*next;
51 
52 }modelHash_t;
53 
54 #define FILE_HASH_SIZE		1024
55 modelHash_t 		*mhHashTable[FILE_HASH_SIZE];
56 
57 
58 /*
59 Ghoul2 Insert End
60 */
61 
62 
63 
64 // This stuff looks a bit messy, but it's kept here as black box, and nothing appears in any .H files for other
65 //	modules to worry about. I may make another module for this sometime.
66 //
67 typedef std::pair<int,int> StringOffsetAndShaderIndexDest_t;
68 typedef std::vector <StringOffsetAndShaderIndexDest_t> ShaderRegisterData_t;
69 struct CachedEndianedModelBinary_s
70 {
71 	void	*pModelDiskImage;
72 	int		iAllocSize;		// may be useful for mem-query, but I don't actually need it
73 	ShaderRegisterData_t ShaderRegisterData;
74 
75 	int		iLastLevelUsedOn;
76 
CachedEndianedModelBinary_sCachedEndianedModelBinary_s77 	CachedEndianedModelBinary_s()
78 	{
79 		pModelDiskImage = 0;
80 		iLastLevelUsedOn    = -1;
81 		iAllocSize = 0;
82 		ShaderRegisterData.clear();
83 	}
84 };
85 typedef struct CachedEndianedModelBinary_s CachedEndianedModelBinary_t;
86 typedef std::map <sstring_t,CachedEndianedModelBinary_t>	CachedModels_t;
87 													CachedModels_t *CachedModels = NULL;	// the important cache item.
88 
RE_RegisterModels_StoreShaderRequest(const char * psModelFileName,const char * psShaderName,const int * piShaderIndexPoke)89 void RE_RegisterModels_StoreShaderRequest(const char *psModelFileName, const char *psShaderName, const int *piShaderIndexPoke)
90 {
91 	char sModelName[MAX_QPATH];
92 
93 	Q_strncpyz(sModelName,psModelFileName,sizeof(sModelName));
94 	Q_strlwr  (sModelName);
95 
96 	CachedEndianedModelBinary_t &ModelBin = (*CachedModels)[sModelName];
97 
98 	if (ModelBin.pModelDiskImage == NULL)
99 	{
100 		assert(0);	// should never happen, means that we're being called on a model that wasn't loaded
101 	}
102 	else
103 	{
104 		const int iNameOffset =		  psShaderName		- (char *)ModelBin.pModelDiskImage;
105 		const int iPokeOffset = (char*) piShaderIndexPoke	- (char *)ModelBin.pModelDiskImage;
106 
107 		ModelBin.ShaderRegisterData.push_back( StringOffsetAndShaderIndexDest_t( iNameOffset,iPokeOffset) );
108 	}
109 }
110 
111 
112 static const byte FakeGLAFile[] =
113 {
114 0x32, 0x4C, 0x47, 0x41, 0x06, 0x00, 0x00, 0x00, 0x2A, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74,
115 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
116 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
117 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
118 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x01, 0x00, 0x00, 0x00,
119 0x14, 0x01, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x18, 0x01, 0x00, 0x00, 0x68, 0x00, 0x00, 0x00,
120 0x26, 0x01, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x4D, 0x6F, 0x64, 0x56, 0x69, 0x65, 0x77, 0x20,
121 0x69, 0x6E, 0x74, 0x65, 0x72, 0x6E, 0x61, 0x6C, 0x20, 0x64, 0x65, 0x66, 0x61, 0x75, 0x6C, 0x74,
122 0x00, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD,
123 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD,
124 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0xCD, 0x00, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
125 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
126 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
127 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00,
128 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
129 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
130 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x3F, 0x00, 0x00, 0x00, 0x00,
131 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xFD, 0xBF, 0xFE, 0x7F, 0xFE, 0x7F, 0xFE, 0x7F,
132 0x00, 0x80, 0x00, 0x80, 0x00, 0x80
133 };
134 
135 
136 // returns qtrue if loaded, and sets the supplied qbool to true if it was from cache (instead of disk)
137 //   (which we need to know to avoid LittleLong()ing everything again (well, the Mac needs to know anyway)...
138 //
RE_RegisterModels_GetDiskFile(const char * psModelFileName,void ** ppvBuffer,qboolean * pqbAlreadyCached)139 qboolean RE_RegisterModels_GetDiskFile( const char *psModelFileName, void **ppvBuffer, qboolean *pqbAlreadyCached)
140 {
141 	char sModelName[MAX_QPATH];
142 
143 	Q_strncpyz(sModelName,psModelFileName,sizeof(sModelName));
144 	Q_strlwr  (sModelName);
145 
146 	CachedEndianedModelBinary_t &ModelBin = (*CachedModels)[sModelName];
147 
148 	if (ModelBin.pModelDiskImage == NULL)
149 	{
150 		// didn't have it cached, so try the disk...
151 		//
152 
153 			// special case intercept first...
154 			//
155 			if (!strcmp(sDEFAULT_GLA_NAME ".gla" , psModelFileName))
156 			{
157 				// return fake params as though it was found on disk...
158 				//
159 				void *pvFakeGLAFile = R_Malloc( sizeof(FakeGLAFile), TAG_FILESYS, qfalse );
160 				memcpy(pvFakeGLAFile, &FakeGLAFile[0],  sizeof(FakeGLAFile));
161 				*ppvBuffer = pvFakeGLAFile;
162 				*pqbAlreadyCached = qfalse;	// faking it like this should mean that it works fine on the Mac as well
163 				return qtrue;
164 			}
165 
166 		ri.FS_ReadFile( sModelName, ppvBuffer );
167 		*pqbAlreadyCached = qfalse;
168 
169 		return (qboolean)(*ppvBuffer != 0);
170 	}
171 	else
172 	{
173 		*ppvBuffer = ModelBin.pModelDiskImage;
174 		*pqbAlreadyCached = qtrue;
175 		return qtrue;
176 	}
177 }
178 
179 
180 // if return == true, no further action needed by the caller...
181 //
RE_RegisterModels_Malloc(int iSize,void * pvDiskBufferIfJustLoaded,const char * psModelFileName,qboolean * pqbAlreadyFound,memtag_t eTag)182 void *RE_RegisterModels_Malloc(int iSize, void *pvDiskBufferIfJustLoaded, const char *psModelFileName, qboolean *pqbAlreadyFound, memtag_t eTag)
183 {
184 	char sModelName[MAX_QPATH];
185 
186 	Q_strncpyz(sModelName,psModelFileName,sizeof(sModelName));
187 	Q_strlwr  (sModelName);
188 
189 	CachedEndianedModelBinary_t &ModelBin = (*CachedModels)[sModelName];
190 
191 	if (ModelBin.pModelDiskImage == NULL)
192 	{
193 		// ... then this entry has only just been created, ie we need to load it fully...
194 		//
195 		// new, instead of doing a R_Malloc and assigning that we just morph the disk buffer alloc
196 		//	then don't thrown it away on return - cuts down on mem overhead
197 		//
198 		// ... groan, but not if doing a limb hierarchy creation (some VV stuff?), in which case it's NULL
199 		//
200 		if ( pvDiskBufferIfJustLoaded )
201 		{
202 			R_MorphMallocTag( pvDiskBufferIfJustLoaded, eTag );
203 		}
204 		else
205 		{
206 			pvDiskBufferIfJustLoaded =  R_Malloc(iSize,eTag, qfalse );
207 		}
208 
209 		ModelBin.pModelDiskImage= pvDiskBufferIfJustLoaded;
210 		ModelBin.iAllocSize		= iSize;
211 		*pqbAlreadyFound		= qfalse;
212 	}
213 	else
214 	{
215 		// if we already had this model entry, then re-register all the shaders it wanted...
216 		//
217 		const int iEntries = ModelBin.ShaderRegisterData.size();
218 		for (int i=0; i<iEntries; i++)
219 		{
220 			int iShaderNameOffset	= ModelBin.ShaderRegisterData[i].first;
221 			int iShaderPokeOffset	= ModelBin.ShaderRegisterData[i].second;
222 
223 			const char *const psShaderName	 =		   &((char*)ModelBin.pModelDiskImage)[iShaderNameOffset];
224 				  int  *const piShaderPokePtr= (int *) &((char*)ModelBin.pModelDiskImage)[iShaderPokeOffset];
225 
226 			shader_t *sh = R_FindShader( psShaderName, lightmapsNone, stylesDefault, qtrue );
227 
228 			if ( sh->defaultShader )
229 			{
230 				*piShaderPokePtr = 0;
231 			} else {
232 				*piShaderPokePtr = sh->index;
233 			}
234 		}
235 		*pqbAlreadyFound = qtrue;	// tell caller not to re-Endian or re-Shader this binary
236 	}
237 
238 	ModelBin.iLastLevelUsedOn = RE_RegisterMedia_GetLevel();
239 
240 	return ModelBin.pModelDiskImage;
241 }
242 
243 
244 // dump any models not being used by this level if we're running low on memory...
245 //
GetModelDataAllocSize(void)246 static int GetModelDataAllocSize(void)
247 {
248 	return	R_MemSize( TAG_MODEL_MD3) +
249 			R_MemSize( TAG_MODEL_GLM) +
250 			R_MemSize( TAG_MODEL_GLA);
251 }
252 extern cvar_t *r_modelpoolmegs;
253 //
254 // return qtrue if at least one cached model was freed (which tells z_malloc()-fail recovery code to try again)
255 //
256 extern qboolean gbInsideRegisterModel;
RE_RegisterModels_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLevel)257 qboolean RE_RegisterModels_LevelLoadEnd(qboolean bDeleteEverythingNotUsedThisLevel /* = qfalse */)
258 {
259 	qboolean bAtLeastoneModelFreed = qfalse;
260 
261 	if (gbInsideRegisterModel)
262 	{
263 		Com_DPrintf( "(Inside RE_RegisterModel (z_malloc recovery?), exiting...\n");
264 	}
265 	else
266 	{
267 		int iLoadedModelBytes	=	GetModelDataAllocSize();
268 		const int iMaxModelBytes=	r_modelpoolmegs->integer * 1024 * 1024;
269 
270 		for (CachedModels_t::iterator itModel = CachedModels->begin(); itModel != CachedModels->end() && ( bDeleteEverythingNotUsedThisLevel || iLoadedModelBytes > iMaxModelBytes ); )
271 		{
272 			CachedEndianedModelBinary_t &CachedModel = (*itModel).second;
273 
274 			qboolean bDeleteThis = qfalse;
275 
276 			if (bDeleteEverythingNotUsedThisLevel)
277 			{
278 				bDeleteThis = (qboolean)(CachedModel.iLastLevelUsedOn != RE_RegisterMedia_GetLevel());
279 			}
280 			else
281 			{
282 				bDeleteThis = (qboolean)(CachedModel.iLastLevelUsedOn < RE_RegisterMedia_GetLevel());
283 			}
284 
285 			// if it wasn't used on this level, dump it...
286 			//
287 			if (bDeleteThis)
288 			{
289 	#ifdef _DEBUG
290 //				LPCSTR psModelName = (*itModel).first.c_str();
291 //				ri.Printf( PRINT_DEVELOPER, "Dumping \"%s\"", psModelName);
292 //				ri.Printf( PRINT_DEVELOPER, ", used on lvl %d\n",CachedModel.iLastLevelUsedOn);
293 	#endif
294 
295 				if (CachedModel.pModelDiskImage) {
296 					R_Free(CachedModel.pModelDiskImage);
297 					//CachedModel.pModelDiskImage = NULL;	// REM for reference, erase() call below negates the need for it.
298 					bAtLeastoneModelFreed = qtrue;
299 				}
300 				CachedModels->erase(itModel++);
301 
302 				iLoadedModelBytes = GetModelDataAllocSize();
303 			}
304 			else
305 			{
306 				++itModel;
307 			}
308 		}
309 	}
310 
311 	//ri.Printf( PRINT_DEVELOPER, "RE_RegisterModels_LevelLoadEnd(): Ok\n");
312 
313 	return bAtLeastoneModelFreed;
314 }
315 
RE_RegisterModels_Info_f(void)316 void RE_RegisterModels_Info_f( void )
317 {
318 	int iTotalBytes = 0;
319 	if(!CachedModels) {
320 		Com_Printf ("%d bytes total (%.2fMB)\n",iTotalBytes, (float)iTotalBytes / 1024.0f / 1024.0f);
321 		return;
322 	}
323 
324 	int iModels = CachedModels->size();
325 	int iModel  = 0;
326 
327 	for (CachedModels_t::iterator itModel = CachedModels->begin(); itModel != CachedModels->end(); ++itModel,iModel++)
328 	{
329 		CachedEndianedModelBinary_t &CachedModel = (*itModel).second;
330 
331 		ri.Printf( PRINT_ALL, "%d/%d: \"%s\" (%d bytes)",iModel,iModels,(*itModel).first.c_str(),CachedModel.iAllocSize );
332 
333 		#ifdef _DEBUG
334 		ri.Printf( PRINT_ALL, ", lvl %d\n",CachedModel.iLastLevelUsedOn);
335 		#endif
336 
337 		iTotalBytes += CachedModel.iAllocSize;
338 	}
339 	ri.Printf( PRINT_ALL, "%d bytes total (%.2fMB)\n",iTotalBytes, (float)iTotalBytes / 1024.0f / 1024.0f);
340 }
341 
342 
RE_RegisterModels_DeleteAll(void)343 static void RE_RegisterModels_DeleteAll(void)
344 {
345 	if(!CachedModels) {
346 		return;	//argh!
347 	}
348 
349 	for (CachedModels_t::iterator itModel = CachedModels->begin(); itModel != CachedModels->end(); )
350 	{
351 		CachedEndianedModelBinary_t &CachedModel = (*itModel).second;
352 
353 		if (CachedModel.pModelDiskImage) {
354 			R_Free(CachedModel.pModelDiskImage);
355 		}
356 
357 		CachedModels->erase(itModel++);
358 	}
359 
360 	extern void RE_AnimationCFGs_DeleteAll(void);
361 	RE_AnimationCFGs_DeleteAll();
362 }
363 
364 
365 static int giRegisterMedia_CurrentLevel=0;
366 static qboolean gbAllowScreenDissolve = qtrue;
367 //
368 // param "bAllowScreenDissolve" is just a convenient way of getting hold of a bool which can be checked by the code that
369 //	issues the InitDissolve command later in RE_RegisterMedia_LevelLoadEnd()
370 //
RE_RegisterMedia_LevelLoadBegin(const char * psMapName,ForceReload_e eForceReload,qboolean bAllowScreenDissolve)371 void RE_RegisterMedia_LevelLoadBegin(const char *psMapName, ForceReload_e eForceReload, qboolean bAllowScreenDissolve)
372 {
373 	gbAllowScreenDissolve = bAllowScreenDissolve;
374 
375 	tr.numBSPModels = 0;
376 
377 	// for development purposes we may want to ditch certain media just before loading a map...
378 	//
379 	switch (eForceReload)
380 	{
381 		case eForceReload_BSP:
382 
383 			ri.CM_DeleteCachedMap(qtrue);
384 			R_Images_DeleteLightMaps();
385 			break;
386 
387 		case eForceReload_MODELS:
388 
389 			RE_RegisterModels_DeleteAll();
390 			break;
391 
392 		case eForceReload_ALL:
393 
394 			// BSP...
395 			//
396 			ri.CM_DeleteCachedMap(qtrue);
397 			R_Images_DeleteLightMaps();
398 			//
399 			// models...
400 			//
401 			RE_RegisterModels_DeleteAll();
402 			break;
403 		default:
404 			break;
405 	}
406 
407 	// at some stage I'll probably want to put some special logic here, like not incrementing the level number
408 	//	when going into a map like "brig" or something, so returning to the previous level doesn't require an
409 	//	asset reload etc, but for now...
410 	//
411 	// only bump level number if we're not on the same level.
412 	//	Note that this will hide uncached models, which is perhaps a bad thing?...
413 	//
414 	static char sPrevMapName[MAX_QPATH]={0};
415 	if (Q_stricmp( psMapName,sPrevMapName ))
416 	{
417 		Q_strncpyz( sPrevMapName, psMapName, sizeof(sPrevMapName) );
418 		giRegisterMedia_CurrentLevel++;
419 	}
420 }
421 
RE_RegisterMedia_GetLevel(void)422 int RE_RegisterMedia_GetLevel(void)
423 {
424 	return giRegisterMedia_CurrentLevel;
425 }
426 
RE_RegisterMedia_LevelLoadEnd(void)427 void RE_RegisterMedia_LevelLoadEnd(void)
428 {
429 	RE_RegisterModels_LevelLoadEnd(qfalse);
430 	RE_RegisterImages_LevelLoadEnd();
431 	ri.SND_RegisterAudio_LevelLoadEnd(qfalse);
432 
433 	if (gbAllowScreenDissolve)
434 	{
435 		RE_InitDissolve(qfalse);
436 	}
437 
438 	ri.S_RestartMusic();
439 
440 	*(ri.gbAlreadyDoingLoad()) = qfalse;
441 }
442 
443 
444 
445 
446 /*
447 ** R_GetModelByHandle
448 */
R_GetModelByHandle(qhandle_t index)449 model_t	*R_GetModelByHandle( qhandle_t index ) {
450 	model_t		*mod;
451 
452 	// out of range gets the defualt model
453 	if ( index < 1 || index >= tr.numModels ) {
454 		return tr.models[0];
455 	}
456 
457 	mod = tr.models[index];
458 
459 	return mod;
460 }
461 
462 //===============================================================================
463 
464 /*
465 ** R_AllocModel
466 */
R_AllocModel(void)467 model_t *R_AllocModel( void ) {
468 	model_t		*mod;
469 
470 	if ( tr.numModels == MAX_MOD_KNOWN ) {
471 		return NULL;
472 	}
473 
474 	mod = (model_t*) R_Hunk_Alloc( sizeof( *tr.models[tr.numModels] ), qtrue );
475 	mod->index= tr.numModels;
476 	tr.models[tr.numModels] = mod;
477 	tr.numModels++;
478 
479 	return mod;
480 }
481 
482 /*
483 Ghoul2 Insert Start
484 */
485 
486 /*
487 ================
488 return a hash value for the filename
489 ================
490 */
generateHashValue(const char * fname,const int size)491 static long generateHashValue( const char *fname, const int size ) {
492 	int		i;
493 	long	hash;
494 	char	letter;
495 
496 	hash = 0;
497 	i = 0;
498 	while (fname[i] != '\0') {
499 		letter = tolower(fname[i]);
500 		if (letter =='.') break;				// don't include extension
501 		if (letter =='\\') letter = '/';		// damn path names
502 		hash+=(long)(letter)*(i+119);
503 		i++;
504 	}
505 	hash &= (size-1);
506 	return hash;
507 }
508 
RE_InsertModelIntoHash(const char * name,model_t * mod)509 void RE_InsertModelIntoHash(const char *name, model_t *mod)
510 {
511 	int			hash;
512 	modelHash_t	*mh;
513 
514 	hash = generateHashValue(name, FILE_HASH_SIZE);
515 
516 	// insert this file into the hash table so we can look it up faster later
517 	mh = (modelHash_t*)R_Hunk_Alloc( sizeof( modelHash_t ), qtrue );
518 
519 	mh->next = mhHashTable[hash];	// I have the breakpoint triggered here where mhHashTable[986] would be assigned
520 	mh->handle = mod->index;
521 	strcpy(mh->name, name);
522 	mhHashTable[hash] = mh;
523 }
524 /*
525 Ghoul2 Insert End
526 */
527 
528 
529 /*
530 ====================
531 RE_RegisterModel
532 
533 Loads in a model for the given name
534 
535 Zero will be returned if the model fails to load.
536 An entry will be retained for failed models as an
537 optimization to prevent disk rescanning if they are
538 asked for again.
539 ====================
540 */
RE_RegisterModel_Actual(const char * name)541 static qhandle_t RE_RegisterModel_Actual( const char *name )
542 {
543 	model_t		*mod;
544 	unsigned	*buf;
545 	int			lod;
546 	int			ident;
547 	qboolean	loaded;
548 //	qhandle_t	hModel;
549 	int			numLoaded;
550 /*
551 Ghoul2 Insert Start
552 */
553 	int			hash;
554 	modelHash_t	*mh;
555 /*
556 Ghoul2 Insert End
557 */
558 
559 	if ( !name || !name[0] ) {
560 		ri.Printf( PRINT_WARNING, "RE_RegisterModel: NULL name\n" );
561 		return 0;
562 	}
563 
564 	if ( strlen( name ) >= MAX_QPATH ) {
565 		ri.Printf( PRINT_DEVELOPER, "Model name exceeds MAX_QPATH\n" );
566 		return 0;
567 	}
568 
569 /*
570 Ghoul2 Insert Start
571 */
572 //	if (!tr.registered) {
573 //		ri.Printf( PRINT_WARNING, "RE_RegisterModel (%s) called before ready!\n",name );
574 //		return 0;
575 //	}
576 	//
577 	// search the currently loaded models
578 	//
579 
580 	hash = generateHashValue(name, FILE_HASH_SIZE);
581 
582 	//
583 	// see if the model is already loaded
584 	//_
585 	for (mh=mhHashTable[hash]; mh; mh=mh->next) {
586 		if (Q_stricmp(mh->name, name) == 0) {
587 			if (tr.models[mh->handle]->type == MOD_BAD)
588 			{
589 				return 0;
590 			}
591 			return mh->handle;
592 		}
593 	}
594 
595 /*
596 Ghoul2 Insert End
597 */
598 
599 	if (name[0] == '#')
600 	{
601 		char		temp[MAX_QPATH];
602 
603 		tr.numBSPModels++;
604 #ifndef DEDICATED
605 		RE_LoadWorldMap_Actual(va("maps/%s.bsp", name + 1), tr.bspModels[tr.numBSPModels - 1], tr.numBSPModels);	//this calls R_LoadSubmodels which will put them into the Hash
606 #endif
607 		Com_sprintf(temp, MAX_QPATH, "*%d-0", tr.numBSPModels);
608 		hash = generateHashValue(temp, FILE_HASH_SIZE);
609 		for (mh=mhHashTable[hash]; mh; mh=mh->next)
610 		{
611 			if (Q_stricmp(mh->name, temp) == 0)
612 			{
613 				return mh->handle;
614 			}
615 		}
616 
617 		return 0;
618 	}
619 
620 	// allocate a new model_t
621 
622 	if ( ( mod = R_AllocModel() ) == NULL ) {
623 		ri.Printf( PRINT_WARNING, "RE_RegisterModel: R_AllocModel() failed for '%s'\n", name);
624 		return 0;
625 	}
626 
627 	// only set the name after the model has been successfully loaded
628 	Q_strncpyz( mod->name, name, sizeof( mod->name ) );
629 
630 	// make sure the render thread is stopped
631 	R_IssuePendingRenderCommands(); //
632 
633 	int iLODStart = 0;
634 	if (strstr (name, ".md3")) {
635 		iLODStart = MD3_MAX_LODS-1;	//this loads the md3s in reverse so they can be biased
636 	}
637 	mod->numLods = 0;
638 
639 	//
640 	// load the files
641 	//
642 	numLoaded = 0;
643 
644 	for ( lod = iLODStart; lod >= 0 ; lod-- ) {
645 		char filename[1024];
646 
647 		strcpy( filename, name );
648 
649 		if ( lod != 0 ) {
650 			char namebuf[80];
651 
652 			if ( strrchr( filename, '.' ) ) {
653 				*strrchr( filename, '.' ) = 0;
654 			}
655 			sprintf( namebuf, "_%d.md3", lod );
656 			strcat( filename, namebuf );
657 		}
658 
659 		qboolean bAlreadyCached = qfalse;
660 		if (!RE_RegisterModels_GetDiskFile(filename, (void **)&buf, &bAlreadyCached))
661 		{
662 			if (numLoaded)	//we loaded one already, but a higher LOD is missing!
663 			{
664 				Com_Error (ERR_DROP, "R_LoadMD3: %s has LOD %d but is missing LOD %d ('%s')!", mod->name, lod+1, lod, filename);
665 			}
666 			continue;
667 		}
668 
669 		//loadmodel = mod;	// this seems to be fairly pointless
670 
671 		// important that from now on we pass 'filename' instead of 'name' to all model load functions,
672 		//	because 'filename' accounts for any LOD mangling etc so guarantees unique lookups for yet more
673 		//	internal caching...
674 		//
675 		ident = *(unsigned *)buf;
676 		if (!bAlreadyCached)
677 		{
678 			ident = LittleLong(ident);
679 		}
680 
681 		switch (ident)
682 		{
683 			// if you add any new types of model load in this switch-case, tell me,
684 			//	or copy what I've done with the cache scheme (-ste).
685 			//
686 			case MDXA_IDENT:
687 
688 				loaded = R_LoadMDXA( mod, buf, filename, bAlreadyCached );
689 				break;
690 
691 			case MDXM_IDENT:
692 
693 				loaded = R_LoadMDXM( mod, buf, filename, bAlreadyCached );
694 				break;
695 
696 			case MD3_IDENT:
697 
698 				loaded = R_LoadMD3( mod, lod, buf, filename, bAlreadyCached );
699 				break;
700 
701 			default:
702 
703 				ri.Printf (PRINT_WARNING,"RE_RegisterModel: unknown fileid for %s\n", filename);
704 				goto fail;
705 		}
706 
707 		if (!bAlreadyCached){	// important to check!!
708 			ri.FS_FreeFile (buf);
709 		}
710 
711 		if ( !loaded ) {
712 			if ( lod == 0 ) {
713 				ri.Printf (PRINT_WARNING,"RE_RegisterModel: cannot load %s\n", filename);
714 				goto fail;
715 			} else {
716 				break;
717 			}
718 		} else {
719 			mod->numLods++;
720 			numLoaded++;
721 			// if we have a valid model and are biased
722 			// so that we won't see any higher detail ones,
723 			// stop loading them
724 			if ( lod <= r_lodbias->integer ) {
725 				break;
726 			}
727 		}
728 	}
729 
730 	if ( numLoaded ) {
731 		// duplicate into higher lod spots that weren't
732 		// loaded, in case the user changes r_lodbias on the fly
733 		for ( lod-- ; lod >= 0 ; lod-- ) {
734 			mod->numLods++;
735 			mod->md3[lod] = mod->md3[lod+1];
736 		}
737 /*
738 Ghoul2 Insert Start
739 */
740 
741 	RE_InsertModelIntoHash(name, mod);
742 	return mod->index;
743 /*
744 Ghoul2 Insert End
745 */
746 
747 	}
748 
749 
750 fail:
751 	// we still keep the model_t around, so if the model name is asked for
752 	// again, we won't bother scanning the filesystem
753 	mod->type = MOD_BAD;
754 	RE_InsertModelIntoHash(name, mod);
755 	return 0;
756 }
757 
758 
759 
760 
761 // wrapper function needed to avoid problems with mid-function returns so I can safely use this bool to tell the
762 //	z_malloc-fail recovery code whether it's safe to ditch any model caches...
763 //
764 qboolean gbInsideRegisterModel = qfalse;
RE_RegisterModel(const char * name)765 qhandle_t RE_RegisterModel( const char *name )
766 {
767 	gbInsideRegisterModel = qtrue;	// !!!!!!!!!!!!!!
768 
769 		qhandle_t q = RE_RegisterModel_Actual( name );
770 
771 	if (Q_stricmp(&name[strlen(name)-4],".gla")){
772 		gbInsideRegisterModel = qfalse;		// GLA files recursively call this, so don't turn off half way. A reference count would be nice, but if any ERR_DROP ever occurs within the load then the refcount will be knackered from then on
773 	}
774 
775 	return q;
776 }
777 
778 
779 /*
780 =================
781 R_LoadMD3
782 =================
783 */
R_LoadMD3(model_t * mod,int lod,void * buffer,const char * mod_name,qboolean & bAlreadyCached)784 static qboolean R_LoadMD3 (model_t *mod, int lod, void *buffer, const char *mod_name, qboolean &bAlreadyCached ) {
785 	int					i, j;
786 	md3Header_t			*pinmodel;
787 	md3Surface_t		*surf;
788 	md3Shader_t			*shader;
789 	int					version;
790 	int					size;
791 
792 #ifdef Q3_BIG_ENDIAN
793 	md3Frame_t			*frame;
794 	md3Triangle_t		*tri;
795 	md3St_t				*st;
796 	md3XyzNormal_t		*xyz;
797 	md3Tag_t			*tag;
798 #endif
799 
800 
801 	pinmodel= (md3Header_t *)buffer;
802 	//
803 	// read some fields from the binary, but only LittleLong() them when we know this wasn't an already-cached model...
804 	//
805 	version = pinmodel->version;
806 	size	= pinmodel->ofsEnd;
807 
808 	if (!bAlreadyCached)
809 	{
810 		version = LittleLong(version);
811 		size	= LittleLong(size);
812 	}
813 
814 	if (version != MD3_VERSION) {
815 		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has wrong version (%i should be %i)\n",
816 				 mod_name, version, MD3_VERSION);
817 		return qfalse;
818 	}
819 
820 	mod->type      = MOD_MESH;
821 	mod->dataSize += size;
822 
823 	qboolean bAlreadyFound = qfalse;
824 	mod->md3[lod] = (md3Header_t *) RE_RegisterModels_Malloc(size, buffer, mod_name, &bAlreadyFound, TAG_MODEL_MD3);
825 
826 	assert(bAlreadyCached == bAlreadyFound);
827 
828 	if (!bAlreadyFound)
829 	{
830 		// horrible new hackery, if !bAlreadyFound then we've just done a tag-morph, so we need to set the
831 		//	bool reference passed into this function to true, to tell the caller NOT to do an FS_Freefile since
832 		//	we've hijacked that memory block...
833 		//
834 		// Aaaargh. Kill me now...
835 		//
836 		bAlreadyCached = qtrue;
837 		assert( mod->md3[lod] == buffer );
838 //		memcpy( mod->md3[lod], buffer, size );	// and don't do this now, since it's the same thing
839 
840 		LL(mod->md3[lod]->ident);
841 		LL(mod->md3[lod]->version);
842 		LL(mod->md3[lod]->numFrames);
843 		LL(mod->md3[lod]->numTags);
844 		LL(mod->md3[lod]->numSurfaces);
845 		LL(mod->md3[lod]->ofsFrames);
846 		LL(mod->md3[lod]->ofsTags);
847 		LL(mod->md3[lod]->ofsSurfaces);
848 		LL(mod->md3[lod]->ofsEnd);
849 	}
850 
851 	if ( mod->md3[lod]->numFrames < 1 ) {
852 		ri.Printf( PRINT_WARNING, "R_LoadMD3: %s has no frames\n", mod_name );
853 		return qfalse;
854 	}
855 
856 	if (bAlreadyFound)
857 	{
858 		return qtrue;	// All done. Stop, go no further, do not pass Go...
859 	}
860 
861 #ifdef Q3_BIG_ENDIAN
862 	// swap all the frames
863 	frame = (md3Frame_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsFrames );
864 	for ( i = 0 ; i < mod->md3[lod]->numFrames ; i++, frame++) {
865 		LF(frame->radius);
866 		for ( j = 0 ; j < 3 ; j++ ) {
867 			LF(frame->bounds[0][j]);
868 			LF(frame->bounds[1][j]);
869 			LF(frame->localOrigin[j]);
870 		}
871 	}
872 
873 	// swap all the tags
874 	tag = (md3Tag_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsTags );
875 	for ( i = 0 ; i < mod->md3[lod]->numTags * mod->md3[lod]->numFrames ; i++, tag++) {
876 		for ( j = 0 ; j < 3 ; j++ ) {
877 			LF(tag->origin[j]);
878 			LF(tag->axis[0][j]);
879 			LF(tag->axis[1][j]);
880 			LF(tag->axis[2][j]);
881 		}
882 	}
883 #endif
884 
885 	// swap all the surfaces
886 	surf = (md3Surface_t *) ( (byte *)mod->md3[lod] + mod->md3[lod]->ofsSurfaces );
887 	for ( i = 0 ; i < mod->md3[lod]->numSurfaces ; i++) {
888         LL(surf->flags);
889         LL(surf->numFrames);
890         LL(surf->numShaders);
891         LL(surf->numTriangles);
892         LL(surf->ofsTriangles);
893         LL(surf->numVerts);
894         LL(surf->ofsShaders);
895         LL(surf->ofsSt);
896         LL(surf->ofsXyzNormals);
897         LL(surf->ofsEnd);
898 
899 		if ( surf->numVerts > SHADER_MAX_VERTEXES ) {
900 			Com_Error (ERR_DROP, "R_LoadMD3: %s has more than %i verts on a surface (%i)",
901 				mod_name, SHADER_MAX_VERTEXES, surf->numVerts );
902 		}
903 		if ( surf->numTriangles*3 > SHADER_MAX_INDEXES ) {
904 			Com_Error (ERR_DROP, "R_LoadMD3: %s has more than %i triangles on a surface (%i)",
905 				mod_name, SHADER_MAX_INDEXES / 3, surf->numTriangles );
906 		}
907 
908 		// change to surface identifier
909 		surf->ident = SF_MD3;
910 
911 		// lowercase the surface name so skin compares are faster
912 		Q_strlwr( surf->name );
913 
914 		// strip off a trailing _1 or _2
915 		// this is a crutch for q3data being a mess
916 		j = strlen( surf->name );
917 		if ( j > 2 && surf->name[j-2] == '_' ) {
918 			surf->name[j-2] = 0;
919 		}
920 
921         // register the shaders
922         shader = (md3Shader_t *) ( (byte *)surf + surf->ofsShaders );
923         for ( j = 0 ; j < surf->numShaders ; j++, shader++ ) {
924             shader_t	*sh;
925 
926             sh = R_FindShader( shader->name, lightmapsNone, stylesDefault, qtrue );
927 			if ( sh->defaultShader ) {
928 				shader->shaderIndex = 0;
929 			} else {
930 				shader->shaderIndex = sh->index;
931 			}
932 			RE_RegisterModels_StoreShaderRequest(mod_name, &shader->name[0], &shader->shaderIndex);
933         }
934 
935 
936 #ifdef Q3_BIG_ENDIAN
937 		// swap all the triangles
938 		tri = (md3Triangle_t *) ( (byte *)surf + surf->ofsTriangles );
939 		for ( j = 0 ; j < surf->numTriangles ; j++, tri++ ) {
940 			LL(tri->indexes[0]);
941 			LL(tri->indexes[1]);
942 			LL(tri->indexes[2]);
943 		}
944 
945 		// swap all the ST
946 		st = (md3St_t *) ( (byte *)surf + surf->ofsSt );
947 		for ( j = 0 ; j < surf->numVerts ; j++, st++ ) {
948 			LF(st->st[0]);
949 			LF(st->st[1]);
950 		}
951 
952 		// swap all the XyzNormals
953 		xyz = (md3XyzNormal_t *) ( (byte *)surf + surf->ofsXyzNormals );
954 		for ( j = 0 ; j < surf->numVerts * surf->numFrames ; j++, xyz++ )
955 		{
956 			LS(xyz->xyz[0]);
957 			LS(xyz->xyz[1]);
958 			LS(xyz->xyz[2]);
959 
960 			LS(xyz->normal);
961 		}
962 #endif
963 
964 		// find the next surface
965 		surf = (md3Surface_t *)( (byte *)surf + surf->ofsEnd );
966 	}
967 
968 	return qtrue;
969 }
970 
971 
972 //=============================================================================
973 
974 void CM_LoadShaderText(bool forceReload);
975 void CM_SetupShaderProperties(void);
976 
977 /*
978 ** RE_BeginRegistration
979 */
RE_BeginRegistration(glconfig_t * glconfigOut)980 void RE_BeginRegistration( glconfig_t *glconfigOut ) {
981 	ri.Hunk_ClearToMark();
982 
983 	R_Init();
984 
985 	*glconfigOut = glConfig;
986 
987 	R_IssuePendingRenderCommands();
988 
989 	tr.viewCluster = -1;		// force markleafs to regenerate
990 
991 
992 	RE_ClearScene();
993 
994 	tr.registered = qtrue;
995 
996 }
997 
998 //=============================================================================
999 
1000 /*
1001 ===============
1002 R_ModelInit
1003 ===============
1004 */
R_ModelInit(void)1005 void R_ModelInit( void )
1006 {
1007 	static CachedModels_t singleton;	// sorry vv, your dynamic allocation was a (false) memory leak
1008 	CachedModels = &singleton;
1009 
1010 	model_t		*mod;
1011 
1012 	// leave a space for NULL model
1013 	tr.numModels = 0;
1014 /*
1015 Ghoul2 Insert Start
1016 */
1017 
1018 	memset(mhHashTable, 0, sizeof(mhHashTable));
1019 /*
1020 Ghoul2 Insert End
1021 */
1022 
1023 	mod = R_AllocModel();
1024 	mod->type = MOD_BAD;
1025 
1026 }
1027 
1028 
1029 /*
1030 ================
1031 R_Modellist_f
1032 ================
1033 */
R_Modellist_f(void)1034 void R_Modellist_f( void ) {
1035 	int		i, j;
1036 	model_t	*mod;
1037 	int		total;
1038 	int		lods;
1039 
1040 	total = 0;
1041 	for ( i = 1 ; i < tr.numModels; i++ ) {
1042 		mod = tr.models[i];
1043 		switch (mod->type)
1044 		{
1045 			default:
1046 				assert(0);
1047 				ri.Printf( PRINT_ALL, "UNKNOWN  :      %s\n", mod->name );
1048 				break;
1049 
1050 			case MOD_BAD:
1051 				ri.Printf( PRINT_ALL, "MOD_BAD  :      %s\n", mod->name );
1052 				break;
1053 
1054 			case MOD_BRUSH:
1055 				ri.Printf( PRINT_ALL, "%8i : (%i) %s\n", mod->dataSize, mod->numLods, mod->name );
1056 				break;
1057 
1058 			case MOD_MDXA:
1059 
1060 				ri.Printf( PRINT_ALL, "%8i : (%i) %s\n", mod->dataSize, mod->numLods, mod->name );
1061 				break;
1062 
1063 			case MOD_MDXM:
1064 
1065 				ri.Printf( PRINT_ALL, "%8i : (%i) %s\n", mod->dataSize, mod->numLods, mod->name );
1066 				break;
1067 
1068 			case MOD_MESH:
1069 
1070 				lods = 1;
1071 				for ( j = 1 ; j < MD3_MAX_LODS ; j++ ) {
1072 					if ( mod->md3[j] && mod->md3[j] != mod->md3[j-1] ) {
1073 						lods++;
1074 					}
1075 				}
1076 				ri.Printf( PRINT_ALL, "%8i : (%i) %s\n",mod->dataSize, lods, mod->name );
1077 				break;
1078 		}
1079 		total += mod->dataSize;
1080 	}
1081 	ri.Printf( PRINT_ALL, "%8i : Total models\n", total );
1082 
1083 /*	this doesn't work with the new hunks
1084 	if ( tr.world ) {
1085 		ri.Printf( PRINT_ALL, "%8i : %s\n", tr.world->dataSize, tr.world->name );
1086 	} */
1087 }
1088 
1089 //=============================================================================
1090 
1091 
1092 /*
1093 ================
1094 R_GetTag for MD3s
1095 ================
1096 */
R_GetTag(md3Header_t * mod,int frame,const char * tagName)1097 static md3Tag_t *R_GetTag( md3Header_t *mod, int frame, const char *tagName ) {
1098 	md3Tag_t		*tag;
1099 	int				i;
1100 
1101 	if ( frame >= mod->numFrames ) {
1102 		// it is possible to have a bad frame while changing models, so don't error
1103 		frame = mod->numFrames - 1;
1104 	}
1105 
1106 	tag = (md3Tag_t *)((byte *)mod + mod->ofsTags) + frame * mod->numTags;
1107 	for ( i = 0 ; i < mod->numTags ; i++, tag++ ) {
1108 		if ( !strcmp( tag->name, tagName ) ) {
1109 			return tag;	// found it
1110 		}
1111 	}
1112 
1113 	return NULL;
1114 }
1115 
1116 /*
1117 ================
1118 R_LerpTag
1119 ================
1120 */
R_LerpTag(orientation_t * tag,qhandle_t handle,int startFrame,int endFrame,float frac,const char * tagName)1121 void	R_LerpTag( orientation_t *tag, qhandle_t handle, int startFrame, int endFrame,
1122 					 float frac, const char *tagName ) {
1123 	md3Tag_t	*start, *finish;
1124 	int		i;
1125 	float		frontLerp, backLerp;
1126 	model_t		*model;
1127 
1128 	model = R_GetModelByHandle( handle );
1129 	if ( model->md3[0] )
1130 	{
1131 		start = R_GetTag( model->md3[0], startFrame, tagName );
1132 		finish = R_GetTag( model->md3[0], endFrame, tagName );
1133 	}
1134 	else
1135 	{
1136 		AxisClear( tag->axis );
1137 		VectorClear( tag->origin );
1138 		return;
1139 	}
1140 
1141 	if ( !start || !finish ) {
1142 		AxisClear( tag->axis );
1143 		VectorClear( tag->origin );
1144 		return;
1145 	}
1146 
1147 	frontLerp = frac;
1148 	backLerp = 1.0 - frac;
1149 
1150 	for ( i = 0 ; i < 3 ; i++ ) {
1151 		tag->origin[i] = start->origin[i] * backLerp +  finish->origin[i] * frontLerp;
1152 		tag->axis[0][i] = start->axis[0][i] * backLerp +  finish->axis[0][i] * frontLerp;
1153 		tag->axis[1][i] = start->axis[1][i] * backLerp +  finish->axis[1][i] * frontLerp;
1154 		tag->axis[2][i] = start->axis[2][i] * backLerp +  finish->axis[2][i] * frontLerp;
1155 	}
1156 	VectorNormalize( tag->axis[0] );
1157 	VectorNormalize( tag->axis[1] );
1158 	VectorNormalize( tag->axis[2] );
1159 }
1160 
1161 
1162 /*
1163 ====================
1164 R_ModelBounds
1165 ====================
1166 */
R_ModelBounds(qhandle_t handle,vec3_t mins,vec3_t maxs)1167 void R_ModelBounds( qhandle_t handle, vec3_t mins, vec3_t maxs ) {
1168 	model_t		*model;
1169 
1170 	model = R_GetModelByHandle( handle );
1171 
1172 	if ( model->bmodel ) {
1173 		VectorCopy( model->bmodel->bounds[0], mins );
1174 		VectorCopy( model->bmodel->bounds[1], maxs );
1175 		return;
1176 	}
1177 
1178 	if ( model->md3[0] ) {
1179 		md3Header_t	*header;
1180 		md3Frame_t	*frame;
1181 		header = model->md3[0];
1182 
1183 		frame = (md3Frame_t *)( (byte *)header + header->ofsFrames );
1184 
1185 		VectorCopy( frame->bounds[0], mins );
1186 		VectorCopy( frame->bounds[1], maxs );
1187 	}
1188 	else
1189 	{
1190 		VectorClear( mins );
1191 		VectorClear( maxs );
1192 		return;
1193 	}
1194 }
1195