1 /*
2 Copyright (C) 2003-2006 Andrey Nazarov
3 
4 This program is free software; you can redistribute it and/or
5 modify it under the terms of the GNU General Public License
6 as published by the Free Software Foundation; either version 2
7 of the License, or (at your option) any later version.
8 
9 This program is distributed in the hope that it will be useful,
10 but WITHOUT ANY WARRANTY; without even the implied warranty of
11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12 
13 See the GNU General Public License for more details.
14 
15 You should have received a copy of the GNU General Public License
16 along with this program; if not, write to the Free Software
17 Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
18 
19 */
20 
21 #include "gl_local.h"
22 
23 #define Model_Malloc( size )	sys.HunkAlloc( &model->pool, size )
24 
25 static model_t		r_models[MAX_MODELS];
26 static int			r_numModels;
27 
28 static cvar_t       *gl_override_models;
29 
Model_Alloc(const char * name)30 static model_t *Model_Alloc( const char *name ) {
31 	model_t *model;
32 	int i;
33 
34 	for( i = 0, model = r_models; i < r_numModels; i++, model++ ) {
35 		if( !model->name[0] ) {
36 			break;
37 		}
38 	}
39 
40 	if( i == r_numModels ) {
41 		if( r_numModels == MAX_MODELS ) {
42 			Com_Error( ERR_DROP, "Model_Alloc: MAX_MODELS" );
43 		}
44 		r_numModels++;
45 	}
46 
47 	strcpy( model->name, name );
48 	model->registration_sequence = registration_sequence;
49 	model->type = MODEL_NULL;
50 
51 	return model;
52 }
53 
Model_Find(const char * name)54 static model_t *Model_Find( const char *name ) {
55 	model_t *model;
56 	aliasMesh_t *mesh;
57 	int i, j;
58 
59 	for( i = 0, model = r_models; i < r_numModels; i++, model++ ) {
60 		if( !model->name[0] ) {
61 			continue;
62 		}
63 		if( !strcmp( model->name, name ) ) {
64 			break;
65 		}
66 	}
67 
68 	if( i == r_numModels ) {
69 		return NULL;
70 	}
71 
72 	switch( model->type ) {
73 	case MODEL_ALIAS:
74 		for( i = 0; i < model->numMeshes; i++ ) {
75 			mesh = &model->meshes[i];
76 			for( j = 0; j < mesh->numSkins; j++ ) {
77 				mesh->skins[j]->registration_sequence = registration_sequence;
78 			}
79 		}
80 		break;
81 	case MODEL_SPRITE:
82 		for( i = 0; i < model->numFrames; i++ ) {
83 			model->sframes[i].image->registration_sequence = registration_sequence;
84 		}
85 		break;
86 	default:
87 		Com_Error( ERR_DROP, "Model_Find: bad model type: %d", model->type );
88 		break;
89 	}
90 
91 	model->registration_sequence = registration_sequence;
92 	return model;
93 }
94 
Model_List_f(void)95 static void Model_List_f( void ) {
96 	int		i;
97 	model_t	*model;
98 	int		bytes;
99 
100 	Com_Printf( "------------------\n");
101 	bytes = 0;
102 
103 	for( i = 0, model = r_models; i < r_numModels; i++, model++ ) {
104 		if( !model->name[0] ) {
105 			continue;
106 		}
107 
108 		Com_Printf( "%8i : %s\n", model->pool.cursize, model->name );
109 		bytes += model->pool.cursize;
110 	}
111 	Com_Printf( "Total resident: %i\n", bytes );
112 }
113 
Model_FreeUnused(void)114 void Model_FreeUnused( void ) {
115 	model_t *model;
116 	int i;
117 
118 	for( i = 0, model = r_models; i < r_numModels; i++, model++ ) {
119 		if( !model->name[0] ) {
120 			continue;
121 		}
122 		if( model->registration_sequence != registration_sequence ) {
123 			sys.HunkFree( &model->pool );
124 			model->name[0] = 0;
125 		}
126 	}
127 }
128 
Model_FreeAll(void)129 void Model_FreeAll( void ) {
130 	model_t *model;
131 	int i;
132 
133 	for( i = 0, model = r_models; i < r_numModels; i++, model++ ) {
134 		if( !model->name[0] ) {
135 			continue;
136 		}
137 
138 		sys.HunkFree( &model->pool );
139 		model->name[0] = 0;
140 	}
141 
142 	r_numModels = 0;
143 }
144 
Model_LoadMd2(model_t * model,const byte * rawdata,int length)145 static qboolean Model_LoadMd2( model_t *model, const byte *rawdata, int length ) {
146 	dmdl_t header;
147 	daliasframe_t *src_frame;
148 	dtrivertx_t *src_vert;
149 	dtriangle_t *src_tri;
150 	dstvert_t *src_tc;
151 	aliasFrame_t *dst_frame;
152 	aliasVert_t *dst_vert;
153 	aliasMesh_t *dst_mesh;
154 	uint32 *finalIndices;
155 	tcoord_t *dst_tc;
156 	int i, j, k;
157 	uint16 remap[MAX_TRIANGLES*3];
158 	uint16 vertIndices[MAX_TRIANGLES*3];
159 	uint16 tcIndices[MAX_TRIANGLES*3];
160 	int numVerts, numIndices;
161 	char skinname[MAX_QPATH];
162 	char *src_skin;
163 	image_t *skin;
164 	vec_t scaleS, scaleT;
165 	int offset, val;
166 	vec3_t mins, maxs;
167 	const byte *rawend;
168 
169 	if( length < sizeof( header ) ) {
170 		Com_EPrintf( "%s has length < header length\n", model->name );
171 		return qfalse;
172 	}
173 
174 	/* byte swap the header */
175 	header = *( dmdl_t * )rawdata;
176 	for( i = 0; i < sizeof( header )/4; i++ ) {
177 		(( uint32 * )&header)[i] = LittleLong( (( uint32 * )&header)[i] );
178 	}
179 
180 	if( header.ident != IDALIASHEADER ) {
181 		Com_EPrintf( "%s is not an MD2 file\n", model->name );
182 		return qfalse;
183 	}
184 
185 	if( header.version != ALIAS_VERSION ) {
186 		Com_EPrintf( "%s has bad version: %d != %d\n",
187 			model->name, header.version, ALIAS_VERSION );
188 		return qfalse;
189 	}
190 
191 	if( header.num_frames < 1 ) {
192 		Com_EPrintf( "%s has bad number of frames: %d\n",
193 			model->name, header.num_frames );
194 		return qfalse;
195 	}
196 	if( header.num_frames > MAX_FRAMES ) {
197 		Com_EPrintf( "%s has too many frames: %d > %d\n",
198 			model->name, header.num_frames, MAX_FRAMES );
199 		return qfalse;
200 	}
201 	if( header.num_tris < 1 ) {
202 		Com_EPrintf( "%s has bad number of triangles: %d\n",
203 			model->name, header.num_tris );
204 		return qfalse;
205 	}
206 	if( header.num_tris > MAX_TRIANGLES ) {
207 		Com_EPrintf( "%s has too many triangles: %d > %d\n",
208 			model->name, header.num_tris, MAX_TRIANGLES );
209 		return qfalse;
210 	}
211 	if( ( uint32 )header.num_skins > MAX_MD2SKINS ) {
212 		Com_EPrintf( "%s has too many skins: %d > %d\n",
213 			model->name, header.num_skins, MAX_MD2SKINS );
214 		return qfalse;
215 	}
216 
217 	if( header.skinwidth <= 0 || header.skinheight <= 0 ) {
218 		Com_EPrintf( "%s has bad skin dimensions: %d x %d\n",
219 			model->name, header.skinwidth, header.skinheight );
220 		return qfalse;
221 	}
222 
223 	rawend = rawdata + length;
224 
225 	model->type = MODEL_ALIAS;
226 	sys.HunkBegin( &model->pool, 0x400000 );
227 
228 	/* load all triangle indices */
229 	src_tri = ( dtriangle_t * )( ( byte * )rawdata + header.ofs_tris );
230 	if( ( byte * )( src_tri + header.num_tris ) > rawend ) {
231 		Com_EPrintf( "%s has bad triangles offset\n", model->name );
232 		goto fail;
233 	}
234 	for( i = 0; i < header.num_tris; i++ ) {
235 		vertIndices[i*3+0] = LittleShort( src_tri->index_xyz[0] );
236 		vertIndices[i*3+1] = LittleShort( src_tri->index_xyz[1] );
237 		vertIndices[i*3+2] = LittleShort( src_tri->index_xyz[2] );
238 
239 		tcIndices[i*3+0] = LittleShort( src_tri->index_st[0] );
240 		tcIndices[i*3+1] = LittleShort( src_tri->index_st[1] );
241 		tcIndices[i*3+2] = LittleShort( src_tri->index_st[2] );
242 
243 		src_tri++;
244 	}
245 
246 	numIndices = header.num_tris * 3;
247 
248 	model->meshes = Model_Malloc( sizeof( aliasMesh_t ) );
249 	model->numMeshes = 1;
250 
251 	dst_mesh = model->meshes;
252 	dst_mesh->indices = Model_Malloc( numIndices * sizeof( uint32 ) );
253 	dst_mesh->numTris = header.num_tris;
254 	dst_mesh->numIndices = numIndices;
255 
256 	for( i = 0; i < numIndices; i++ ) {
257 		remap[i] = 0xFFFF;
258 	}
259 
260 	numVerts = 0;
261 	src_tc = ( dstvert_t * )( ( byte * )rawdata + header.ofs_st );
262 	finalIndices = dst_mesh->indices;
263 	for( i = 0; i < numIndices; i++ ) {
264 		if( remap[i] != 0xFFFF ) {
265 			continue; /* already remapped */
266 		}
267 
268 		for( j = i + 1; j < numIndices; j++ ) {
269 			if( vertIndices[i] == vertIndices[j] &&
270 				( src_tc[tcIndices[i]].s == src_tc[tcIndices[j]].s &&
271 					src_tc[tcIndices[i]].t == src_tc[tcIndices[j]].t ) )
272 			{
273 				/* duplicate vertex */
274 				remap[j] = i;
275 				finalIndices[j] = numVerts;
276 			}
277 		}
278 
279 		/* new vertex */
280 		remap[i] = i;
281 		finalIndices[i] = numVerts++;
282 	}
283 
284 	dst_mesh->verts = Model_Malloc( numVerts * header.num_frames * sizeof( aliasVert_t ) );
285 	dst_mesh->tcoords = Model_Malloc( numVerts * sizeof( tcoord_t ) );
286 	dst_mesh->numVerts = numVerts;
287 
288 	/* load all skins */
289 	src_skin = ( char * )rawdata + header.ofs_skins;
290 	if( ( byte * )( src_skin + MAX_SKINNAME * header.num_skins ) > rawend ) {
291 		Com_EPrintf( "%s has bad skins offset\n", model->name );
292 		goto fail;
293 	}
294 	for( i = 0; i < header.num_skins; i++ ) {
295 		Q_strncpyz( skinname, src_skin, sizeof( skinname ) );
296 		skin = R_FindImage( skinname, it_skin );
297 		if( !skin ) {
298 			skin = r_notexture;
299 		}
300 		dst_mesh->skins[i] = skin;
301 		src_skin += MAX_SKINNAME;
302 	}
303 	dst_mesh->numSkins = header.num_skins;
304 
305 	/* load all tcoords */
306 	src_tc = ( dstvert_t * )( ( byte * )rawdata + header.ofs_st );
307 	dst_tc = dst_mesh->tcoords;
308 	skin = dst_mesh->skins[0];
309 	scaleS = 1.0f / header.skinwidth;
310 	scaleT = 1.0f / header.skinheight;
311 	for( i = 0; i < numIndices; i++ ) {
312 		if( remap[i] == i ) {
313 			dst_tc[ finalIndices[i] ].st[0] = LittleShort( src_tc[ tcIndices[i] ].s ) * scaleS;
314 			dst_tc[ finalIndices[i] ].st[1] = LittleShort( src_tc[ tcIndices[i] ].t ) * scaleT;
315 		}
316 	}
317 
318 	/* load all frames */
319 	model->frames = Model_Malloc( header.num_frames * sizeof( aliasFrame_t ) );
320 	model->numFrames = header.num_frames;
321 
322 	offset = header.ofs_frames;
323 	dst_frame = model->frames;
324 	for( j = 0; j < header.num_frames; j++ ) {
325 		src_frame = ( daliasframe_t * )( ( byte * )rawdata + offset );
326 		if( ( byte * )( src_frame + 1 ) > rawend ) {
327 			Com_EPrintf( "%s has bad offset for frame %d\n", model->name, j );
328 			goto fail;
329 		}
330 
331 		dst_frame->scale[0] = LittleFloat( src_frame->scale[0] );
332 		dst_frame->scale[1] = LittleFloat( src_frame->scale[1] );
333 		dst_frame->scale[2] = LittleFloat( src_frame->scale[2] );
334 
335 		dst_frame->translate[0] = LittleFloat( src_frame->translate[0] );
336 		dst_frame->translate[1] = LittleFloat( src_frame->translate[1] );
337 		dst_frame->translate[2] = LittleFloat( src_frame->translate[2] );
338 
339 		/* load frame vertices */
340 		ClearBounds( mins, maxs );
341 		for( i = 0; i < numIndices; i++ ) {
342 			if( remap[i] == i ) {
343 				src_vert = &src_frame->verts[ vertIndices[i] ];
344 				dst_vert = &dst_mesh->verts[ j * numVerts + finalIndices[i] ];
345 
346 				dst_vert->pos[0] = src_vert->v[0];
347 				dst_vert->pos[1] = src_vert->v[1];
348 				dst_vert->pos[2] = src_vert->v[2];
349 				k = src_vert->lightnormalindex;
350 				if( k >= NUMVERTEXNORMALS ) {
351 					Com_EPrintf( "%s has bad normal index\n", model->name );
352 					goto fail;
353 				}
354 				dst_vert->normalIndex = k;
355 
356 				for ( k = 0; k < 3; k++ ) {
357 					val = dst_vert->pos[k];
358 					if( val < mins[k] )
359 						mins[k] = val;
360 					if( val > maxs[k] )
361 						maxs[k] = val;
362 				}
363 			}
364 		}
365 
366 		VectorVectorScale( mins, dst_frame->scale, mins );
367 		VectorVectorScale( maxs, dst_frame->scale, maxs );
368 
369 		dst_frame->radius = RadiusFromBounds( mins, maxs );
370 
371 		VectorAdd( mins, dst_frame->translate, dst_frame->bounds[0] );
372 		VectorAdd( maxs, dst_frame->translate, dst_frame->bounds[1] );
373 
374 		offset += header.framesize;
375 		dst_frame++;
376 	}
377 
378     sys.HunkEnd( &model->pool );
379 
380 	return qtrue;
381 
382 fail:
383 	sys.HunkFree( &model->pool );
384 	return qfalse;
385 }
386 
Model_LoadMd3(model_t * model,const byte * rawdata,int length)387 static qboolean Model_LoadMd3( model_t *model, const byte *rawdata, int length ) {
388 	dmd3header_t header;
389 	uint32 offset;
390 	dmd3frame_t *src_frame;
391 	dmd3mesh_t *src_mesh;
392 	dmd3vertex_t *src_vert;
393 	dmd3coord_t *src_tc;
394 	dmd3skin_t *src_skin;
395 	uint32 *src_idx;
396 	aliasFrame_t *dst_frame;
397 	aliasMesh_t *dst_mesh;
398 	aliasVert_t *dst_vert;
399 	tcoord_t *dst_tc;
400 	uint32 *dst_idx;
401 	uint32 numVerts, numTris, numSkins;
402 	uint32 totalVerts;
403 	char skinname[MAX_QPATH];
404 	image_t *skin;
405 	const byte *rawend;
406 	int i, j;
407 
408 	if( length < sizeof( header ) ) {
409 		Com_EPrintf( "%s has length < header length\n", model->name );
410 		return qfalse;
411 	}
412 
413 	/* byte swap the header */
414 	header = *( dmd3header_t * )rawdata;
415 	for( i = 0; i < sizeof( header )/4; i++ ) {
416 		(( uint32 * )&header)[i] = LittleLong( (( uint32 * )&header)[i] );
417 	}
418 
419 	if( header.ident != MD3_IDENT ) {
420 		Com_EPrintf( "%s is not an MD3 file\n", model->name );
421 		return qfalse;
422 	}
423 
424 	if( header.version != MD3_VERSION ) {
425 		Com_EPrintf( "%s has bad version: %d != %d\n",
426 			model->name, header.version, MD3_VERSION );
427 		return qfalse;
428 	}
429 
430 	if( header.num_frames < 1 ) {
431 		Com_EPrintf( "%s has bad number of frames: %d\n",
432 			model->name, header.num_frames );
433 		return qfalse;
434 	}
435 	if( header.num_frames > MD3_MAX_FRAMES ) {
436 		Com_EPrintf( "%s has too many frames: %d > %d\n",
437 			model->name, header.num_frames, MD3_MAX_FRAMES );
438 		return qfalse;
439 	}
440 
441 	if( header.num_meshes < 1 || header.num_meshes > MD3_MAX_SURFACES ) {
442 		Com_EPrintf( "%s has bad number of meshes\n", model->name );
443 		return qfalse;
444 	}
445 
446 	model->type = MODEL_ALIAS;
447 	sys.HunkBegin( &model->pool, 0x400000 );
448 	model->numFrames = header.num_frames;
449 	model->numMeshes = header.num_meshes;
450 	model->meshes = Model_Malloc( sizeof( aliasMesh_t ) * header.num_meshes );
451 	model->frames = Model_Malloc( sizeof( aliasFrame_t ) * header.num_frames );
452 
453 	rawend = rawdata + length;
454 
455 	/* load all frames */
456 	src_frame = ( dmd3frame_t * )( rawdata + header.ofs_frames );
457 	if( ( byte * )( src_frame + header.num_frames ) > rawend ) {
458 		Com_EPrintf( "%s has bad frames offset\n", model->name );
459 		goto fail;
460 	}
461 	dst_frame = model->frames;
462 	for( i = 0; i < header.num_frames; i++ ) {
463 		dst_frame->translate[0] = LittleFloat( src_frame->translate[0] );
464 		dst_frame->translate[1] = LittleFloat( src_frame->translate[1] );
465 		dst_frame->translate[2] = LittleFloat( src_frame->translate[2] );
466 
467 		VectorSet( dst_frame->scale,
468 				MD3_XYZ_SCALE, MD3_XYZ_SCALE, MD3_XYZ_SCALE );
469 
470 		dst_frame->bounds[0][0] = LittleFloat( src_frame->mins[0] );
471 		dst_frame->bounds[0][1] = LittleFloat( src_frame->mins[1] );
472 		dst_frame->bounds[0][2] = LittleFloat( src_frame->mins[2] );
473 
474 		dst_frame->bounds[1][0] = LittleFloat( src_frame->maxs[0] );
475 		dst_frame->bounds[1][1] = LittleFloat( src_frame->maxs[1] );
476 		dst_frame->bounds[1][2] = LittleFloat( src_frame->maxs[2] );
477 
478 		dst_frame->radius = LittleFloat( src_frame->radius );
479 
480 		src_frame++; dst_frame++;
481 	}
482 
483 	/* load all meshes */
484 	src_mesh = ( dmd3mesh_t * )( rawdata + header.ofs_meshes );
485 	dst_mesh = model->meshes;
486 	for( i = 0; i < header.num_meshes; i++ ) {
487 		if( ( byte * )( src_mesh + 1 ) > rawend ) {
488 			Com_EPrintf( "%s has bad offset for mesh %d\n", model->name, i );
489 			goto fail;
490 		}
491 
492 		numVerts = LittleLong( src_mesh->num_verts );
493 		numTris = LittleLong( src_mesh->num_tris );
494 
495 		if( numVerts < 3 || numVerts > TESS_MAX_VERTICES ) {
496 			Com_EPrintf( "%s has bad number of vertices for mesh %d\n", model->name, i );
497 			goto fail;
498 		}
499 		if( numTris < 1 || numTris > TESS_MAX_INDICES / 3 ) {
500 			Com_EPrintf( "%s has bad number of faces for mesh %d\n", model->name, i );
501 			goto fail;
502 		}
503 
504 		dst_mesh->numTris = numTris;
505 		dst_mesh->numIndices = numTris * 3;
506 		dst_mesh->numVerts = numVerts;
507 		dst_mesh->verts = Model_Malloc( sizeof( aliasVert_t ) * numVerts * header.num_frames );
508 		dst_mesh->tcoords = Model_Malloc( sizeof( tcoord_t ) * numVerts );
509 		dst_mesh->indices = Model_Malloc( sizeof( uint32 ) * numTris * 3 );
510 
511 		/* load all skins */
512 		numSkins = LittleLong( src_mesh->num_skins );
513 		if( numSkins < 1 || numSkins > MAX_MD2SKINS ) {
514 			Com_EPrintf( "%s has bad number of skins for mesh %d\n", model->name, i );
515 			goto fail;
516 		}
517 		offset = LittleLong( src_mesh->ofs_skins );
518 		src_skin = ( dmd3skin_t * )( ( byte * )src_mesh + offset );
519 		if( ( byte * )( src_skin + numSkins ) > rawend ) {
520 			Com_EPrintf( "%s has bad skins offset for mesh %d\n", model->name, i );
521 			goto fail;
522 		}
523 		for( j = 0; j < numSkins; j++ ) {
524 			Q_strncpyz( skinname, src_skin->name, sizeof( skinname ) );
525 			skin = R_FindImage( skinname, it_skin );
526 			if( !skin ) {
527 				skin = r_notexture;
528 			}
529 			dst_mesh->skins[j] = skin;
530 		}
531 		dst_mesh->numSkins = numSkins;
532 
533 		/* load all vertices */
534 		totalVerts = numVerts * header.num_frames;
535 		offset = LittleLong( src_mesh->ofs_verts );
536 		src_vert = ( dmd3vertex_t * )( ( byte * )src_mesh + offset );
537 		if( ( byte * )( src_vert + totalVerts ) > rawend ) {
538 			Com_EPrintf( "%s has bad vertices offset for mesh %d\n", model->name, i );
539 			goto fail;
540 		}
541 		dst_vert = dst_mesh->verts;
542 		for( j = 0; j < totalVerts; j++ ) {
543 			dst_vert->pos[0] = LittleShort( src_vert->point[0] );
544 			dst_vert->pos[1] = LittleShort( src_vert->point[1] );
545 			dst_vert->pos[2] = LittleShort( src_vert->point[2] );
546 
547 			{
548 				float s[2], c[2];
549 				vec3_t normal;
550 
551 				s[0] = sin( src_vert->norm[0] / 255.0f );
552 				c[0] = cos( src_vert->norm[0] / 255.0f );
553 
554 				s[1] = sin( src_vert->norm[1] / 255.0f );
555 				c[1] = cos( src_vert->norm[1] / 255.0f );
556 
557 				VectorSet( normal,
558 						s[0] * c[1], s[0] * s[1], c[0] );
559 				dst_vert->normalIndex = DirToByte( normal );
560 			}
561 
562 			src_vert++; dst_vert++;
563 		}
564 
565 		/* load all texture coords */
566 		offset = LittleLong( src_mesh->ofs_tcs );
567 		src_tc = ( dmd3coord_t * )( ( byte * )src_mesh + offset );
568 		if( ( byte * )( src_tc + numVerts ) > rawend ) {
569 			Com_EPrintf( "%s has bad tcoords offset for mesh %d\n", model->name, i );
570 			goto fail;
571 		}
572 		dst_tc = dst_mesh->tcoords;
573 		for( j = 0; j < numVerts; j++ ) {
574 			dst_tc->st[0] = LittleFloat( src_tc->st[0] );
575 			dst_tc->st[1] = LittleFloat( src_tc->st[1] );
576 
577 			src_tc++; dst_tc++;
578 		}
579 
580 		/* load all triangle indices */
581 		offset = LittleLong( src_mesh->ofs_indexes );
582 		src_idx = ( uint32 * )( ( byte * )src_mesh + offset );
583 		if( ( byte * )( src_idx + numTris * 3 ) > rawend ) {
584 			Com_EPrintf( "%s has bad indices offset for mesh %d\n", model->name, i );
585 			goto fail;
586 		}
587 		dst_idx = dst_mesh->indices;
588 		for( j = 0; j < numTris; j++ ) {
589 			dst_idx[0] = LittleLong( src_idx[0] ) % numVerts;
590 			dst_idx[1] = LittleLong( src_idx[1] ) % numVerts;
591 			dst_idx[2] = LittleLong( src_idx[2] ) % numVerts;
592 
593 			src_idx += 3; dst_idx += 3;
594 		}
595 
596 		offset = LittleLong( src_mesh->meshsize );
597 		src_mesh = ( dmd3mesh_t * )( ( byte * )src_mesh + offset );
598 		dst_mesh++;
599 	}
600 
601     sys.HunkEnd( &model->pool );
602 
603 	return qtrue;
604 
605 fail:
606 	sys.HunkFree( &model->pool );
607 	return qfalse;
608 }
609 
Model_LoadSp2(model_t * model,const byte * rawdata,int length)610 static qboolean Model_LoadSp2( model_t *model, const byte *rawdata, int length ) {
611 	dsprite_t *header;
612 	dsprframe_t *src_frame;
613 	spriteFrame_t *dst_frame;
614 	int ident, version, numframes;
615 	int i, width, height;
616 	char buffer[MAX_SKINNAME];
617 	image_t *image;
618 
619 	if( length < sizeof( *header ) ) {
620 		Com_EPrintf( "%s has length < header length\n", model->name );
621 		return qfalse;
622 	}
623 
624 	/* byte swap the header */
625 	header = ( dsprite_t * )rawdata;
626 	for( i = 0; i < sizeof( header )/4; i++ ) {
627 		(( uint32 * )&header)[i] = LittleLong( (( uint32 * )&header)[i] );
628 	}
629 
630 	ident = LittleLong( header->ident );
631 	version = LittleLong( header->version );
632 	numframes = LittleLong( header->numframes );
633 
634 	if( ident != IDSPRITEHEADER ) {
635 		Com_EPrintf( "%s is not an sp2 file\n", model->name );
636 		return qfalse;
637 	}
638 
639 	if( version != SPRITE_VERSION ) {
640 		Com_EPrintf( "%s has bad version: %d != %d\n",
641 			model->name, version, ALIAS_VERSION );
642 		return qfalse;
643 	}
644 
645 	if( numframes < 1 ) {
646 		Com_EPrintf( "%s has bad number of frames: %d\n",
647 			model->name, numframes );
648 		return qfalse;
649 	}
650 
651 	if( numframes > MAX_MD2SKINS ) {
652 		Com_EPrintf( "%s has too many frames: %d > %d\n",
653 			model->name, numframes, MAX_MD2SKINS );
654 		return qfalse;
655 	}
656 
657 	model->type = MODEL_SPRITE;
658 	sys.HunkBegin( &model->pool, 0x10000 );
659 
660 	model->sframes = Model_Malloc( sizeof( spriteFrame_t ) * numframes );
661 	model->numFrames = numframes;
662 
663 	src_frame = header->frames;
664 	dst_frame = model->sframes;
665 	for( i = 0; i < numframes; i++ ) {
666 		width = LittleLong( src_frame->width );
667 		height = LittleLong( src_frame->height );
668 		if( width <= 0 || height <= 0 ) {
669 			Com_WPrintf( "%s has bad image dimensions for frame #%d: %d x %d\n",
670 				model->name, width, height, i );
671 			width = 1;
672 			height = 1;
673 		}
674 		dst_frame->width = width;
675 		dst_frame->height = height;
676 		dst_frame->x = LittleLong( src_frame->origin_x );
677 		dst_frame->y = LittleLong( src_frame->origin_y );
678 
679 		Q_strncpyz( buffer, src_frame->name, sizeof( buffer ) );
680 		image = R_FindImage( buffer, it_sprite );
681 		if( !image ) {
682 			Com_DPrintf( "Couldn't find image '%s' for frame #%d for sprite '%s'\n",
683 				buffer, i, model->name );
684 			image = r_notexture;
685 		}
686 		dst_frame->image = image;
687 
688 		dst_frame++; src_frame++;
689 	}
690 
691     sys.HunkEnd( &model->pool );
692 
693 	return qtrue;
694 }
695 
GL_GetModelSize(qhandle_t hModel,vec3_t mins,vec3_t maxs)696 void GL_GetModelSize( qhandle_t hModel, vec3_t mins, vec3_t maxs ) {
697     VectorClear( mins );
698     VectorClear( maxs );
699 }
700 
GL_RegisterModel(const char * name)701 qhandle_t GL_RegisterModel( const char *name ) {
702 	int index, length, nameLength;
703 	model_t *model;
704 	byte *rawdata;
705 	uint32 ident;
706 	qboolean success;
707 
708 	if( name[0] == '*' ) {
709 		/* inline bsp model */
710 		index = atoi( name + 1 );
711 		if( index < 1 || index >= r_world.numSubmodels ) {
712 			Com_Error( ERR_DROP, "GL_RegisterModel: bad inline model index: %d", index );
713 		}
714 		return ~index;
715 	}
716 
717 	if( !strcmp( r_world.name, name ) ) {
718 		/* TODO: change client code and remove this hack */
719 		return 0;
720 	}
721 
722 	nameLength = strlen( name );
723 	if( nameLength > MAX_QPATH - 1 ) {
724 		Com_Error( ERR_DROP, "GL_RegisterModel: oversize name: %d chars", nameLength );
725 	}
726 
727 	model = Model_Find( name );
728 	if( model ) {
729 		goto finish;
730 	}
731 
732 	length = -1;
733 	if( gl_override_models->integer ) {
734 		char buffer[MAX_QPATH];
735 
736 		if( nameLength > 4 && !strcmp( name + nameLength - 4, ".md2" ) ) {
737 			strcpy( buffer, name );
738 			buffer[nameLength - 1] = '3';
739 		}
740 		length = fs.LoadFile( buffer, ( void ** )&rawdata );
741 	}
742 	if( length == -1 ) {
743 		length = fs.LoadFile( name, ( void ** )&rawdata );
744 		if( length == -1 ) {
745 			Com_DPrintf( "Couldn't load %s\n", name );
746 			return 0;
747 		}
748 	}
749 
750 	if( length < 4 ) {
751 		Com_WPrintf( "%s has invalid length\n", name );
752 		return 0;
753 	}
754 
755 	model = Model_Alloc( name );
756 
757 	ident = LittleLong( *( uint32 * )rawdata );
758 	switch( ident ) {
759 	case IDALIASHEADER:
760 		success = Model_LoadMd2( model, rawdata, length );
761 		break;
762 	case MD3_IDENT:
763 		success = Model_LoadMd3( model, rawdata, length );
764 		break;
765 	case IDSPRITEHEADER:
766 		success = Model_LoadSp2( model, rawdata, length );
767 		break;
768 	case IDBSPHEADER:
769 		Com_WPrintf( "Loaded bsp model '%s' after the world\n", name );
770 		success = qfalse;
771 		break;
772 	default:
773 		Com_WPrintf( "%s has unknown ident: %x\n", name, ident );
774 		success = qfalse;
775 		break;
776 	}
777 
778 	fs.FreeFile( rawdata );
779 
780 	if( !success ) {
781 		model->name[0] = 0;
782 		return 0;
783 	}
784 
785 finish:
786 	index = ( model - r_models ) + 1;
787 	return index;
788 }
789 
GL_ModelForHandle(qhandle_t hModel)790 modelType_t *GL_ModelForHandle( qhandle_t hModel ) {
791 	model_t *model;
792 	bspSubmodel_t *submodel;
793 
794 	if( !hModel ) {
795 		return NULL;
796 	}
797 
798 	if( hModel & 0x80000000 ) {
799 		hModel = ~hModel;
800 
801 		if( hModel < 1 || hModel >= r_world.numSubmodels ) {
802 			Com_Error( ERR_FATAL,
803 				"GL_ModelForHandle: submodel %d out of range", hModel );
804 			return NULL;
805 		}
806 
807 		submodel = &r_world.submodels[hModel];
808 		return &submodel->type;
809 	}
810 
811 	if( hModel > r_numModels ) {
812 		Com_Error( ERR_FATAL, "GL_ModelForHandle: %d out of range", hModel );
813 		return NULL;
814 	}
815 	model = &r_models[ hModel - 1 ];
816 	if( !model->name[0] ) {
817 		return NULL;
818 	}
819 	return &model->type;
820 
821 }
822 
GL_InitModels(void)823 void GL_InitModels( void ) {
824 	gl_override_models = cvar.Get( "r_override_models", "0",
825         CVAR_ARCHIVE|CVAR_LATCHED );
826 
827 	cmd.AddCommand( "modellist", Model_List_f );
828 }
829 
GL_ShutdownModels(void)830 void GL_ShutdownModels( void ) {
831     Model_FreeAll();
832 	cmd.RemoveCommand( "modellist" );
833 }
834