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