1 /*
2 Copyright (C) 1996-1997 Id Software, Inc.
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 // models.c -- model loading and caching
21
22 // models are the only shared resource between a client and server running
23 // on the same machine.
24
25 #include "quakedef.h"
26 #include "neh.h"
27 model_t *loadmodel;
28 char loadname[32]; // for hunk tags
29
30 void Mod_LoadSpriteModel (model_t *mod, void *buffer);
31 void Mod_LoadBrushModel (model_t *mod, void *buffer);
32 void Mod_LoadAliasModel (model_t *mod, void *buffer);
33 model_t *Mod_LoadModel (model_t *mod, qboolean crash);
34
35 byte mod_novis[MAX_MAP_LEAFS/8];
36
37 #define MAX_MOD_KNOWN 2048 //512
38 model_t mod_known[MAX_MOD_KNOWN];
39 int mod_numknown;
40
41 cvar_t gl_subdivide_size = {"gl_subdivide_size", "512", true}; //256
42 cvar_t gl_autobright = {"gl_autobright", "1"};
43
44 /*
45 ===============
46 Mod_Init
47 ===============
48 */
Mod_Init(void)49 void Mod_Init (void)
50 {
51 Cvar_RegisterVariable (&gl_subdivide_size);
52 Cvar_RegisterVariable (&gl_autobright);
53 memset (mod_novis, 0xff, sizeof(mod_novis));
54 }
55
56 /*
57 ===============
58 Mod_Extradata
59
60 Caches the data if needed
61 ===============
62 */
Mod_Extradata(model_t * mod)63 void *Mod_Extradata (model_t *mod)
64 {
65 void *r;
66
67 r = Cache_Check (&mod->cache);
68 if (r)
69 return r;
70
71 Mod_LoadModel (mod, true);
72
73 if (!mod->cache.data)
74 Sys_Error ("Mod_Extradata: caching failed, model %s", mod->name);
75 return mod->cache.data;
76 }
77
78 /*
79 ===============
80 Mod_PointInLeaf
81 ===============
82 */
Mod_PointInLeaf(vec3_t p,model_t * model)83 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
84 {
85 mnode_t *node;
86 float d;
87 mplane_t *plane;
88
89 if (!model || !model->nodes)
90 Sys_Error ("Mod_PointInLeaf: bad model");
91
92 node = model->nodes;
93 while (1)
94 {
95 if (node->contents < 0)
96 return (mleaf_t *)node;
97 plane = node->plane;
98 d = DotProduct (p,plane->normal) - plane->dist;
99 if (d > 0)
100 node = node->children[0];
101 else
102 node = node->children[1];
103 }
104
105 return NULL; // never reached
106 }
107
108
109 /*
110 ===================
111 Mod_DecompressVis
112 ===================
113 */
Mod_DecompressVis(byte * in,model_t * model)114 byte *Mod_DecompressVis (byte *in, model_t *model)
115 {
116 static byte decompressed[MAX_MAP_LEAFS/8];
117 int c;
118 byte *out;
119 int row;
120
121 row = (model->numleafs+7)>>3;
122 out = decompressed;
123
124 if (!in || r_novis.value == 2)
125 { // no vis info, so make all visible
126 while (row)
127 {
128 *out++ = 0xff;
129 row--;
130 }
131 return decompressed;
132 }
133
134 do
135 {
136 if (*in)
137 {
138 *out++ = *in++;
139 continue;
140 }
141
142 c = in[1];
143 in += 2;
144 while (c)
145 {
146 *out++ = 0;
147 c--;
148 }
149 } while (out - decompressed < row);
150
151 return decompressed;
152 }
153
Mod_LeafPVS(mleaf_t * leaf,model_t * model)154 byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
155 {
156 if (leaf == model->leafs)
157 return mod_novis;
158 return Mod_DecompressVis (leaf->compressed_vis, model);
159 }
160
161 /*
162 ===================
163 Mod_ClearAll
164 ===================
165 */
Mod_ClearAll(void)166 void Mod_ClearAll (void)
167 {
168 int i;
169 model_t *mod;
170
171 for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
172 if (mod->type != mod_alias)
173 mod->needload = true;
174
175 if (!isDedicated)
176 GL_FreeTextures ();
177 }
178
179 /*
180 ==================
181 Mod_FindName
182
183 ==================
184 */
Mod_FindName(char * name)185 model_t *Mod_FindName (char *name)
186 {
187 int i;
188 model_t *mod;
189
190 if (!name[0])
191 Sys_Error ("Mod_FindName: NULL name");
192
193 //
194 // search the currently loaded models
195 //
196 for (i=0 , mod=mod_known ; i<mod_numknown ; i++, mod++)
197 if (!strcmp (mod->name, name) )
198 break;
199
200 if (i == mod_numknown)
201 {
202 if (mod_numknown == MAX_MOD_KNOWN)
203 Sys_Error ("mod_numknown == MAX_MOD_KNOWN (%d)", MAX_MOD_KNOWN);
204 strcpy (mod->name, name);
205 mod->needload = true;
206 mod_numknown++;
207 }
208
209 return mod;
210 }
211
212 /*
213 ==================
214 Mod_TouchModel
215
216 ==================
217 */
Mod_TouchModel(char * name)218 void Mod_TouchModel (char *name)
219 {
220 model_t *mod;
221
222 mod = Mod_FindName (name);
223
224 if (!mod->needload)
225 {
226 if (mod->type == mod_alias)
227 Cache_Check (&mod->cache);
228 }
229 }
230
231 /*
232 ==================
233 Mod_LoadModel
234
235 Loads a model into the cache
236 ==================
237 */
Mod_LoadModel(model_t * mod,qboolean crash)238 model_t *Mod_LoadModel (model_t *mod, qboolean crash)
239 {
240 void *d;
241 unsigned *buf;
242 byte stackbuf[1024]; // avoid dirtying the cache heap
243
244 if (!mod->needload)
245 {
246 if (mod->type == mod_alias)
247 {
248 d = Cache_Check (&mod->cache);
249 if (d)
250 return mod;
251 }
252 else
253 return mod; // not cached at all
254 }
255
256 //
257 // because the world is so huge, load it one piece at a time
258 //
259
260 //
261 // load the file
262 //
263 buf = (unsigned *)COM_LoadStackFile (mod->name, stackbuf, sizeof(stackbuf));
264 if (!buf)
265 {
266 if (crash)
267 // Sys_Error ("Mod_LoadModel: %s not found", mod->name);
268 Host_Error ("Mod_LoadModel: %s not found", mod->name);
269 return NULL;
270 }
271
272 //
273 // allocate a new model
274 //
275 COM_FileBase (mod->name, loadname);
276
277 loadmodel = mod;
278
279 //
280 // fill it in
281 //
282
283 // call the apropriate loader
284 mod->needload = false;
285
286 switch (LittleLong(*(unsigned *)buf))
287 {
288 case IDPOLYHEADER:
289 Mod_LoadAliasModel (mod, buf);
290 break;
291
292 case IDSPRITEHEADER:
293 Mod_LoadSpriteModel (mod, buf);
294 break;
295
296 default:
297 Mod_LoadBrushModel (mod, buf);
298 break;
299 }
300
301 return mod;
302 }
303
304 /*
305 ==================
306 Mod_ForName
307
308 Loads in a model for the given name
309 ==================
310 */
Mod_ForName(char * name,qboolean crash)311 model_t *Mod_ForName (char *name, qboolean crash)
312 {
313 model_t *mod;
314
315 mod = Mod_FindName (name);
316
317 return Mod_LoadModel (mod, crash);
318 }
319
320
321 /*
322 ===============================================================================
323
324 BRUSHMODEL LOADING
325
326 ===============================================================================
327 */
328
329 static int MissTex;
330 byte *mod_base;
331
332 /*
333 =================
334 Mod_ChkLumpSize
335 =================
336 */
Mod_ChkLumpSize(char * Function,lump_t * l,int Size)337 static void Mod_ChkLumpSize (char *Function, lump_t *l, int Size)
338 {
339 if (l->filelen % Size)
340 Sys_Error ("%s: lump size %d is not a multiple of %d in %s", Function, l->filelen, Size, loadmodel->name);
341 }
342
343 /*
344 =================
345 WithinBounds
346 =================
347 */
WithinBounds(int SItem,int Items,int Limit,int * ErrItem)348 static qboolean WithinBounds (int SItem, int Items, int Limit, int *ErrItem)
349 {
350 int EItem = 0;
351
352 if (SItem < 0)
353 EItem = SItem;
354 else if (Items < 0)
355 EItem = Items;
356 else if (SItem + Items < 0 || SItem + Items > Limit)
357 EItem = SItem + Items;
358
359 if (ErrItem)
360 *ErrItem = EItem;
361
362 return EItem == 0;
363 }
364
365 /*
366 =================
367 Mod_ChkBounds
368 =================
369 */
Mod_ChkBounds(char * Function,char * Object,int SItem,int Items,int Limit)370 static void Mod_ChkBounds (char *Function, char *Object, int SItem, int Items, int Limit)
371 {
372 int ErrItem;
373
374 if (!WithinBounds (SItem, Items, Limit, &ErrItem))
375 Sys_Error ("%s: %s is out of bounds (%d, max = %d) in %s", Function, Object, ErrItem, Limit, loadmodel->name);
376 }
377
378 /*
379 =================
380 Mod_ChkFileSize
381 =================
382 */
Mod_ChkFileSize(char * Function,char * Object,int SItem,int Items)383 static void Mod_ChkFileSize (char *Function, char *Object, int SItem, int Items)
384 {
385 int ErrItem;
386
387 if (!WithinBounds (SItem, Items, com_filesize, &ErrItem))
388 Sys_Error ("%s: %s is outside file (%d, max = %d) in %s", Function, Object, ErrItem, com_filesize, loadmodel->name);
389 }
390
391 /*
392 =================
393 Mod_ChkType
394 =================
395 */
Mod_ChkType(char * Function,char * Object,char * ObjNum,int Type,int Type1,int Type2)396 static void Mod_ChkType (char *Function, char *Object, char *ObjNum, int Type, int Type1, int Type2)
397 {
398 if (Type != Type1 && Type != Type2)
399 {
400 // Should be an error but ...
401 Con_Printf ("\002%s: ", Function);
402 Con_Printf ("invalid %s %d in %s in %s\n", Object, Type, ObjNum, loadmodel->name);
403 // Sys_Error ("%s: invalid %s %d in %s in %s", Function, Object, Type, ObjNum, loadmodel->name);
404 }
405 }
406
407 /*
408 =================
409 Mod_LoadTextures
410 =================
411 */
Mod_LoadTextures(lump_t * l)412 void Mod_LoadTextures (lump_t *l)
413 {
414 int i, j, pixels, num, max, altmax;
415 miptex_t *mt;
416 texture_t *tx, *tx2;
417 texture_t *anims[10];
418 texture_t *altanims[10];
419 dmiptexlump_t *m;
420 char texname[16 + 1];
421
422 if (!l->filelen)
423 {
424 loadmodel->textures = NULL;
425 Con_Printf ("\x02Mod_LoadTextures: ");
426 Con_Printf ("no textures in %s\n", loadmodel->name);
427 return;
428 }
429
430 // Check bounds for nummiptex var
431 Mod_ChkBounds ("Mod_LoadTextures", "nummiptex", 0, sizeof(int), l->filelen);
432
433 m = (dmiptexlump_t *)(mod_base + l->fileofs);
434 m->nummiptex = LittleLong (m->nummiptex);
435
436 // Check bounds for dataofs array
437 if (m->nummiptex > 0)
438 Mod_ChkBounds ("Mod_LoadTextures", "miptex lump", sizeof(int), m->nummiptex * sizeof(int), l->filelen);
439
440 loadmodel->numtextures = m->nummiptex;
441 loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures) , loadname);
442
443 MissTex = 0;
444
445 for (i=0 ; i<m->nummiptex ; i++)
446 {
447 int size, copypixels;
448
449 m->dataofs[i] = LittleLong (m->dataofs[i]);
450 if (m->dataofs[i] == -1)
451 {
452 ++MissTex;
453 continue;
454 }
455 mt = (miptex_t *)((byte *)m + m->dataofs[i]);
456
457 // Check bounds for miptex entry
458 Mod_ChkBounds ("Mod_LoadTextures", "miptex entry", (byte *)mt - (mod_base + l->fileofs), sizeof(miptex_t), l->filelen);
459
460 mt->width = LittleLong (mt->width);
461 mt->height = LittleLong (mt->height);
462 for (j=0 ; j<MIPLEVELS ; j++)
463 mt->offsets[j] = LittleLong (mt->offsets[j]);
464
465 // Make sure tex name is terminated
466 memset (texname, 0, sizeof(texname));
467 memcpy (texname, mt->name, sizeof(texname) - 1);
468
469 if (mt->width <= 0 || mt->height <= 0 || (mt->width & 15) || (mt->height & 15))
470 Sys_Error ("Mod_LoadTextures: texture '%s' is not 16 aligned (%dx%d) in %s", texname, mt->width, mt->height, loadmodel->name);
471
472 // Check bounds for miptex objects
473 for (j=0 ; j<MIPLEVELS ; j++)
474 {
475 int ErrItem, Offset = (byte *)mt - (mod_base + l->fileofs) + mt->offsets[j];
476 int MipSize = mt->width * mt->height / (1 << j * 2);
477
478 if (!WithinBounds(Offset, MipSize, l->filelen, &ErrItem))
479 {
480 Con_Printf ("\x02Mod_LoadTextures: ");
481 Con_Printf ("miptex object %d for '%s' is outside texture lump (%d, max = %d) in %s\n", j, texname, ErrItem, l->filelen, loadmodel->name);
482 mt->offsets[j] = sizeof (miptex_t); // OK?
483 }
484 }
485
486 pixels = copypixels = mt->width*mt->height/64*85;
487
488 size = (byte *)(mt + 1) + pixels - (mod_base + l->fileofs);
489
490 // Check bounds for pixels
491 if (size > l->filelen)
492 {
493 Con_Printf ("\x02Mod_LoadTextures: ");
494 Con_Printf ("pixels for '%s' is outside texture lump (%d, max = %d) in %s\n", texname, size, l->filelen, loadmodel->name);
495 copypixels -= size - l->filelen; // Prevent access violation
496 }
497
498 tx = Hunk_AllocName (sizeof(texture_t) +pixels, loadname );
499 loadmodel->textures[i] = tx;
500
501 strcpy (tx->name, texname);
502 #ifdef _WIN32
503 _strlwr (tx->name);
504 #else
505 strlwr (tx->name);
506 #endif
507 tx->width = mt->width;
508 tx->height = mt->height;
509 for (j=0 ; j<MIPLEVELS ; j++)
510 tx->offsets[j] = mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t);
511 // the pixels immediately follow the structures
512 memcpy ( tx+1, mt+1, copypixels);
513
514 if (!isDedicated) //no texture uploading for dedicated server
515 {
516 if (!Q_strncmp(tx->name,"sky",3))
517 R_InitSky (tx);
518 else
519 {
520 texture_mode = GL_LINEAR_MIPMAP_NEAREST; //_LINEAR;
521 tx->gl_texturenum = GL_LoadTextureFree (tx->name, tx->width, tx->height, (byte *)(tx+1), true, false);
522 texture_mode = GL_LINEAR;
523 }
524 }
525 }
526
527 //
528 // sequence the animations
529 //
530 for (i=0 ; i<m->nummiptex ; i++)
531 {
532 tx = loadmodel->textures[i];
533 if (!tx || tx->name[0] != '+')
534 continue;
535 if (tx->anim_next)
536 continue; // allready sequenced
537
538 // find the number of frames in the animation
539 memset (anims, 0, sizeof(anims));
540 memset (altanims, 0, sizeof(altanims));
541
542 max = tx->name[1];
543 altmax = 0;
544 if (max >= 'a' && max <= 'z')
545 max -= 'a' - 'A';
546 if (max >= '0' && max <= '9')
547 {
548 max -= '0';
549 altmax = 0;
550 anims[max] = tx;
551 max++;
552 }
553 else if (max >= 'A' && max <= 'J')
554 {
555 altmax = max - 'A';
556 max = 0;
557 altanims[altmax] = tx;
558 altmax++;
559 }
560 else
561 Sys_Error ("Bad animating texture '%s'", tx->name);
562
563 for (j=i+1 ; j<m->nummiptex ; j++)
564 {
565 tx2 = loadmodel->textures[j];
566 if (!tx2 || tx2->name[0] != '+')
567 continue;
568 if (strcmp (tx2->name+2, tx->name+2))
569 continue;
570
571 num = tx2->name[1];
572 if (num >= 'a' && num <= 'z')
573 num -= 'a' - 'A';
574 if (num >= '0' && num <= '9')
575 {
576 num -= '0';
577 anims[num] = tx2;
578 if (num+1 > max)
579 max = num + 1;
580 }
581 else if (num >= 'A' && num <= 'J')
582 {
583 num = num - 'A';
584 altanims[num] = tx2;
585 if (num+1 > altmax)
586 altmax = num+1;
587 }
588 else
589 Sys_Error ("Bad animating texture '%s'", tx->name);
590 }
591
592 #define ANIM_CYCLE 2
593 // link them all together
594 for (j=0 ; j<max ; j++)
595 {
596 tx2 = anims[j];
597 if (!tx2)
598 Sys_Error ("Missing frame %i of '%s'", j, tx->name);
599 tx2->anim_total = max * ANIM_CYCLE;
600 tx2->anim_min = j * ANIM_CYCLE;
601 tx2->anim_max = (j+1) * ANIM_CYCLE;
602 tx2->anim_next = anims[ (j+1)%max ];
603 if (altmax)
604 tx2->alternate_anims = altanims[0];
605 }
606 for (j=0 ; j<altmax ; j++)
607 {
608 tx2 = altanims[j];
609 if (!tx2)
610 Sys_Error ("Missing frame %i of '%s'", j, tx->name);
611 tx2->anim_total = altmax * ANIM_CYCLE;
612 tx2->anim_min = j * ANIM_CYCLE;
613 tx2->anim_max = (j+1) * ANIM_CYCLE;
614 tx2->anim_next = altanims[ (j+1)%altmax ];
615 if (max)
616 tx2->alternate_anims = anims[0];
617 }
618 }
619 }
620
621 /*
622 =================
623 Mod_LoadLighting
624 =================
625 */
Mod_LoadLighting(lump_t * l)626 void Mod_LoadLighting (lump_t *l)
627 {
628 if (!l->filelen)
629 {
630 loadmodel->lightdata = NULL;
631 return;
632 }
633 loadmodel->lightdata = Hunk_AllocName ( l->filelen, loadname);
634 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
635 }
636
637
638 /*
639 =================
640 Mod_LoadVisibility
641 =================
642 */
Mod_LoadVisibility(lump_t * l)643 void Mod_LoadVisibility (lump_t *l)
644 {
645 if (!l->filelen)
646 {
647 loadmodel->visdata = NULL;
648 return;
649 }
650 loadmodel->visdata = Hunk_AllocName ( l->filelen, loadname);
651 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
652 }
653
654
655 /*
656 =================
657 Mod_LoadEntities
658 =================
659 */
Mod_LoadEntities(lump_t * l)660 void Mod_LoadEntities (lump_t *l)
661 {
662 if (!l->filelen)
663 {
664 loadmodel->entities = NULL;
665 return;
666 }
667 loadmodel->entities = Hunk_AllocName ( l->filelen + 1, loadname); // +1 for extra NUL below
668 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
669 loadmodel->entities[l->filelen] = 0;
670
671 if (loadmodel->entities[l->filelen - 1] != 0)
672 {
673 Con_Printf ("\x02Mod_LoadEntities: ");
674 Con_Printf ("missing NUL in entity lump in %s\n", loadmodel->name);
675 }
676 }
677
678 /*
679 =================
680 Mod_LoadVertexes
681 =================
682 */
Mod_LoadVertexes(lump_t * l)683 void Mod_LoadVertexes (lump_t *l)
684 {
685 dvertex_t *in;
686 mvertex_t *out;
687 int i, j, count;
688
689 in = (void *)(mod_base + l->fileofs);
690 Mod_ChkLumpSize ("Mod_LoadVertexes", l, sizeof(*in));
691 count = l->filelen / sizeof(*in);
692
693 if (count > 65535)
694 {
695 Con_Printf ("\x02Mod_LoadVertexes: ");
696 Con_Printf ("excessive vertexes (%d, normal max = %d) in %s\n", count, 65535, loadmodel->name);
697 }
698
699 out = Hunk_AllocName ( count*sizeof(*out), loadname);
700
701 loadmodel->vertexes = out;
702 loadmodel->numvertexes = count;
703
704 for ( i=0 ; i<count ; i++, in++, out++)
705 {
706 for (j = 0; j < 3; ++j)
707 {
708 out->position[j] = LittleFloat (in->point[j]);
709
710 // Check bounds
711 if (fabs(out->position[j]) > 65536)
712 // Sys_Error ("Mod_LoadVertexes: vertex way out of bounds (%.0f, max = %d) in %s", out->position[j], 4096, loadmodel->name);
713 {
714 Con_SafePrintf ("\x02Mod_LoadVertexes: ");
715 Con_SafePrintf ("vertex way out of bounds (%.g, max = %d) in %s\n", out->position[j], 4096, loadmodel->name);
716 out->position[j] = 0; // OK?
717 }
718 }
719 }
720 }
721
722 /*
723 =================
724 Mod_LoadSubmodels
725 =================
726 */
Mod_LoadSubmodels(lump_t * l)727 void Mod_LoadSubmodels (lump_t *l)
728 {
729 dmodel_t *in;
730 dmodel_t *out;
731 int i, j, count, firstface;
732
733 in = (void *)(mod_base + l->fileofs);
734 Mod_ChkLumpSize ("Mod_LoadSubmodels", l, sizeof(*in));
735 count = l->filelen / sizeof(*in);
736
737 if (count > MAX_MODELS) // Why not MAX_MAP_MODELS?
738 Sys_Error ("Mod_LoadSubmodels: too many models (%d, max = %d) in %s", count, MAX_MODELS, loadmodel->name);
739
740 if (count > 256) // Old limit
741 {
742 Con_Printf ("\x02Mod_LoadSubmodels: ");
743 Con_Printf ("excessive models (%d, normal max = %d) in %s\n", count, 256, loadmodel->name);
744 }
745
746 out = Hunk_AllocName ( count*sizeof(*out), loadname);
747
748 loadmodel->submodels = out;
749 loadmodel->numsubmodels = count;
750
751 for ( i=0 ; i<count ; i++, in++, out++)
752 {
753 for (j=0 ; j<3 ; j++)
754 { // spread the mins / maxs by a pixel
755 out->mins[j] = LittleFloat (in->mins[j]) - 1;
756 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
757 out->origin[j] = LittleFloat (in->origin[j]);
758 }
759 for (j=0 ; j<MAX_MAP_HULLS ; j++)
760 out->headnode[j] = LittleLong (in->headnode[j]);
761 out->visleafs = LittleLong (in->visleafs);
762
763 firstface = LittleLong (in->firstface);
764 out->numfaces = LittleLong (in->numfaces);
765
766 // Check bounds
767 Mod_ChkBounds ("Mod_LoadSubmodels", "face", firstface, out->numfaces, loadmodel->numsurfaces);
768
769 out->firstface = firstface;
770 }
771
772 // Check world visleafs
773 out = loadmodel->submodels;
774
775 if (out->visleafs > MAX_MAP_LEAFS)
776 Sys_Error ("Mod_LoadSubmodels: too many visleafs (%d, max = %d) in %s", out->visleafs, MAX_MAP_LEAFS, loadmodel->name);
777
778 if (out->visleafs > 8192) // Old limit
779 {
780 Con_Printf ("\x02Mod_LoadSubmodels: ");
781 Con_Printf ("excessive visleafs (%d, normal max = %d) in %s\n", out->visleafs, 8192, loadmodel->name);
782 }
783 }
784
785 /*
786 =================
787 Mod_LoadEdges
788 =================
789 */
Mod_LoadEdges(lump_t * l)790 void Mod_LoadEdges (lump_t *l)
791 {
792 dedge_t *in;
793 medge_t *out;
794 int i, j, count;
795
796 in = (void *)(mod_base + l->fileofs);
797 Mod_ChkLumpSize ("Mod_LoadEdges", l, sizeof(*in));
798 count = l->filelen / sizeof(*in);
799 out = Hunk_AllocName ( (count + 1) * sizeof(*out), loadname);
800
801 loadmodel->edges = out;
802 loadmodel->numedges = count;
803
804 for ( i=0 ; i<count ; i++, in++, out++)
805 {
806 for (j = 0; j < 2; ++j)
807 {
808 out->v[j] = (unsigned short)LittleShort (in->v[j]);
809
810 if (i == 0 && j == 0)
811 continue; // Why is sometimes this edge invalid?
812
813 // Check bounds
814 if (out->v[j] >= loadmodel->numvertexes)
815 {
816 Con_SafePrintf ("\x02Mod_LoadEdges: ");
817 Con_SafePrintf ("vertex out of bounds (%d, max = %d) in %s\n", out->v[j], loadmodel->numvertexes, loadmodel->name);
818 out->v[j] = 0; // OK?
819 }
820 }
821 }
822 }
823
824 /*
825 =================
826 Mod_LoadTexinfo
827 =================
828 */
Mod_LoadTexinfo(lump_t * l)829 void Mod_LoadTexinfo (lump_t *l)
830 {
831 texinfo_t *in;
832 mtexinfo_t *out;
833 int i, j, count;
834 int miptex;
835 float len1, len2;
836
837 in = (void *)(mod_base + l->fileofs);
838 Mod_ChkLumpSize ("Mod_LoadTexinfo", l, sizeof(*in));
839 count = l->filelen / sizeof(*in);
840
841 if (count > 32767)
842 {
843 Con_Printf ("\x02Mod_LoadTexinfo: ");
844 Con_Printf ("excessive texinfo (%d, normal max = %d) in %s\n", count, 32767, loadmodel->name);
845 }
846
847 out = Hunk_AllocName ( count*sizeof(*out), loadname);
848
849 loadmodel->texinfo = out;
850 loadmodel->numtexinfo = count;
851
852 for ( i=0 ; i<count ; i++, in++, out++)
853 {
854 for (j=0 ; j<8 ; j++)
855 out->vecs[0][j] = LittleFloat (in->vecs[0][j]);
856 len1 = Length (out->vecs[0]);
857 len2 = Length (out->vecs[1]);
858 len1 = (len1 + len2)/2;
859 if (len1 < 0.32)
860 out->mipadjust = 4;
861 else if (len1 < 0.49)
862 out->mipadjust = 3;
863 else if (len1 < 0.99)
864 out->mipadjust = 2;
865 else
866 out->mipadjust = 1;
867 #if 0
868 if (len1 + len2 < 0.001)
869 out->mipadjust = 1; // don't crash
870 else
871 out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 );
872 #endif
873
874 miptex = LittleLong (in->miptex);
875 out->flags = LittleLong (in->flags);
876
877 if (!loadmodel->textures)
878 {
879 out->texture = r_notexture_mip; // checkerboard texture
880 out->flags = 0;
881 }
882 else
883 {
884 Mod_ChkBounds ("Mod_LoadTexinfo", "miptex", miptex, 1, loadmodel->numtextures);
885 out->texture = loadmodel->textures[miptex];
886 if (!out->texture)
887 {
888 out->texture = r_notexture_mip; // texture not found
889 out->flags = 0;
890 }
891 }
892 }
893
894 if (MissTex > 0)
895 {
896 Con_Printf ("\x02Mod_LoadTexinfo: ");
897 Con_Printf ("%d texture%s missing in %s\n", MissTex, MissTex == 1 ? " is" : "s are", loadmodel->name);
898 }
899
900 if (!loadmodel->textures || MissTex > 0)
901 {
902 texture_mode = GL_LINEAR_MIPMAP_NEAREST; //_LINEAR;
903 r_notexture_mip->gl_texturenum = GL_LoadTexture (r_notexture_mip->name, r_notexture_mip->width, r_notexture_mip->height, (byte *)(r_notexture_mip+1), true, false);
904 texture_mode = GL_LINEAR;
905 }
906 }
907
908 #define MAX_SURF_EXTENTS 512
909
910 /*
911 ================
912 CalcSurfaceExtents
913
914 Fills in s->texturemins[] and s->extents[]
915 ================
916 */
CalcSurfaceExtents(msurface_t * s)917 void CalcSurfaceExtents (msurface_t *s)
918 {
919 float mins[2], maxs[2], val;
920 int i,j, e;
921 mvertex_t *v;
922 mtexinfo_t *tex;
923 int bmins[2], bmaxs[2];
924
925 mins[0] = mins[1] = 999999;
926 maxs[0] = maxs[1] = -99999;
927
928 tex = s->texinfo;
929
930 for (i=0 ; i<s->numedges ; i++)
931 {
932 e = loadmodel->surfedges[s->firstedge+i];
933 if (e >= 0)
934 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
935 else
936 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
937
938 for (j=0 ; j<2 ; j++)
939 {
940 val = v->position[0] * tex->vecs[j][0] +
941 v->position[1] * tex->vecs[j][1] +
942 v->position[2] * tex->vecs[j][2] +
943 tex->vecs[j][3];
944 if (val < mins[j])
945 mins[j] = val;
946 if (val > maxs[j])
947 maxs[j] = val;
948 }
949 }
950
951 for (i=0 ; i<2 ; i++)
952 {
953 bmins[i] = floor(mins[i]/16);
954 bmaxs[i] = ceil(maxs[i]/16);
955
956 s->texturemins[i] = bmins[i] * 16;
957 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
958 if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > MAX_SURF_EXTENTS /* 256 */ )
959 {
960 Con_SafePrintf ("\002CalcSurfaceExtents: ");
961 Con_SafePrintf ("excessive surface extents (%d, normal max = %d), texture %s in %s\n", s->extents[i], MAX_SURF_EXTENTS, tex->texture->name, loadmodel->name);
962 s->extents[i] = MAX_SURF_EXTENTS; // Kludge, but seems to work
963 }
964 }
965 }
966
967
968 /*
969 =================
970 Mod_LoadFaces
971 =================
972 */
Mod_LoadFaces(lump_t * l)973 void Mod_LoadFaces (lump_t *l)
974 {
975 dface_t *in;
976 msurface_t *out;
977 int i, count, surfnum, texinfo, firstsurfedge;
978 int planenum, side;
979
980 in = (void *)(mod_base + l->fileofs);
981 Mod_ChkLumpSize ("Mod_LoadFaces", l, sizeof(*in));
982 count = l->filelen / sizeof(*in);
983
984 if (count > 32767)
985 {
986 Con_Printf ("\x02Mod_LoadFaces: ");
987 Con_Printf ("excessive faces (%d, normal max = %d) in %s\n", count, 32767, loadmodel->name);
988 }
989
990 out = Hunk_AllocName ( count*sizeof(*out), loadname);
991
992 loadmodel->surfaces = out;
993 loadmodel->numsurfaces = count;
994
995 for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
996 {
997 firstsurfedge = LittleLong (in->firstedge);
998 out->numedges = LittleShort (in->numedges);
999
1000 // Check bounds
1001 Mod_ChkBounds ("MOD_LoadFaces", "surfedge", firstsurfedge, out->numedges, loadmodel->numsurfedges);
1002
1003 out->firstedge = firstsurfedge;
1004 out->flags = 0;
1005
1006 planenum = LittleShort (in->planenum);
1007
1008 Mod_ChkBounds ("MOD_LoadFaces", "plane", planenum, 1, loadmodel->numplanes);
1009
1010 side = LittleShort (in->side);
1011 if (side)
1012 out->flags |= SURF_PLANEBACK;
1013
1014 out->plane = loadmodel->planes + planenum;
1015
1016 texinfo = LittleShort (in->texinfo);
1017
1018 Mod_ChkBounds ("MOD_LoadFaces", "texinfo", texinfo, 1, loadmodel->numtexinfo);
1019
1020 out->texinfo = loadmodel->texinfo + texinfo;
1021
1022 CalcSurfaceExtents (out);
1023
1024 // lighting info
1025
1026 for (i=0 ; i<MAXLIGHTMAPS ; i++)
1027 out->styles[i] = in->styles[i];
1028 i = LittleLong(in->lightofs);
1029
1030 if (i != -1)
1031 {
1032 int LightSize = ((dheader_t *)mod_base)->lumps[LUMP_LIGHTING].filelen;
1033
1034 if (!WithinBounds (i, 1, LightSize, NULL))
1035 {
1036 Con_SafePrintf ("\002MOD_LoadFaces: ");
1037 Con_SafePrintf ("lightofs out of bounds (%d, max = %d) in %s\n", i, LightSize, loadmodel->name);
1038 i = -1;
1039 }
1040 }
1041
1042 if (i == -1)
1043 out->samples = NULL;
1044 else
1045 out->samples = loadmodel->lightdata + i;
1046
1047 // set the drawing flags flag
1048
1049 if (!Q_strncmp(out->texinfo->texture->name,"sky",3)) // sky
1050 {
1051 out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED);
1052 // Nehahra
1053 GL_SubdivideSurface (out); // cut up polygon for warps
1054
1055 continue;
1056 }
1057
1058 if (out->texinfo->texture->name[0] == '*') // turbulent
1059 {
1060 out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED);
1061 for (i=0 ; i<2 ; i++)
1062 {
1063 out->extents[i] = 16384;
1064 out->texturemins[i] = -8192;
1065 }
1066 GL_SubdivideSurface (out); // cut up polygon for warps
1067 continue;
1068 }
1069
1070 }
1071 }
1072
1073 static unsigned RecursLevel;
1074
1075 /*
1076 =================
1077 Mod_SetParent
1078 =================
1079 */
Mod_SetParent(mnode_t * node,mnode_t * parent)1080 void static Mod_SetParent (mnode_t *node, mnode_t *parent)
1081 {
1082 if (!node || ++RecursLevel > 4096) // 512 seems enough for huge maps and 8192 might create stack overflow
1083 Sys_Error ("Mod_SetParent: %s in %s", !node ? "invalid node" : "excessive tree depth", loadmodel->name);
1084
1085 node->parent = parent;
1086 if (node->contents >= 0)
1087 {
1088 Mod_SetParent (node->children[0], node);
1089 Mod_SetParent (node->children[1], node);
1090 }
1091
1092 --RecursLevel;
1093 }
1094
1095 /*
1096 =================
1097 Mod_LoadNodes
1098 =================
1099 */
Mod_LoadNodes(lump_t * l)1100 void Mod_LoadNodes (lump_t *l)
1101 {
1102 int i, j, count, p, firstface;
1103 dnode_t *in;
1104 mnode_t *out;
1105
1106 in = (void *)(mod_base + l->fileofs);
1107 Mod_ChkLumpSize ("Mod_LoadNodes", l, sizeof(*in));
1108 count = l->filelen / sizeof(*in);
1109
1110 // Check nodes
1111 if (count > 32767)
1112 // Sys_Error ("MOD_LoadNodes: too many nodes (%d, max = %d) in %s", count, 32767, loadmodel->name);
1113 {
1114 Con_Printf ("\x02Mod_LoadNodes: ");
1115 Con_Printf ("excessive nodes (%d, normal max = %d) in %s\n", count, 32767, loadmodel->name);
1116 }
1117
1118 out = Hunk_AllocName ( count*sizeof(*out), loadname);
1119
1120 loadmodel->nodes = out;
1121 loadmodel->numnodes = count;
1122
1123 for ( i=0 ; i<count ; i++, in++, out++)
1124 {
1125 for (j=0 ; j<3 ; j++)
1126 {
1127 out->minmaxs[j] = LittleShort (in->mins[j]);
1128 out->minmaxs[3+j] = LittleShort (in->maxs[j]);
1129 }
1130
1131 p = LittleLong (in->planenum);
1132
1133 Mod_ChkBounds ("MOD_LoadNodes", "plane", p, 1, loadmodel->numplanes);
1134
1135 out->plane = loadmodel->planes + p;
1136
1137 firstface = (unsigned short)LittleShort (in->firstface);
1138 out->numsurfaces = (unsigned short)LittleShort (in->numfaces);
1139
1140 // Check bounds
1141 Mod_ChkBounds ("MOD_LoadNodes", "face", firstface, out->numsurfaces, loadmodel->numsurfaces);
1142
1143 out->firstsurface = firstface;
1144
1145 for (j=0 ; j<2 ; j++)
1146 {
1147 p = LittleShort (in->children[j]);
1148
1149 if (p < -loadmodel->numleafs)
1150 p += 65536; // Gross hack to connect as much as possible of the crippled bsp tree
1151
1152 if (p >= 0)
1153 {
1154 if (p >= loadmodel->numnodes)
1155 // Sys_Error ("MOD_LoadNodes: node out of bounds (%d, max = %d)", p, loadmodel->numnodes);
1156 p = loadmodel->numnodes - 1;
1157
1158 out->children[j] = loadmodel->nodes + p;
1159 }
1160 else
1161 {
1162 if ((-1 - p) >= loadmodel->numleafs)
1163 // Sys_Error ("MOD_LoadNodes: leaf out of bounds (%d, max = %d)", (-1 - p), loadmodel->numleafs);
1164 p = -loadmodel->numleafs;
1165
1166 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1167 }
1168 }
1169 }
1170
1171 RecursLevel = 0;
1172 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1173 }
1174
1175 /*
1176 =================
1177 Mod_LoadLeafs
1178 =================
1179 */
Mod_LoadLeafs(lump_t * l)1180 void Mod_LoadLeafs (lump_t *l)
1181 {
1182 dleaf_t *in;
1183 mleaf_t *out;
1184 int i, j, count, p, firstmarksurface;
1185
1186 in = (void *)(mod_base + l->fileofs);
1187 Mod_ChkLumpSize ("Mod_LoadLeafs", l, sizeof(*in));
1188 count = l->filelen / sizeof(*in);
1189
1190 // Check leafs
1191 if (count > 32767)
1192 Sys_Error ("MOD_LoadLeafs: too many leafs (%d, max = %d) in %s", count, 32767, loadmodel->name);
1193
1194 out = Hunk_AllocName ( count*sizeof(*out), loadname);
1195
1196 loadmodel->leafs = out;
1197 loadmodel->numleafs = count;
1198
1199 for ( i=0 ; i<count ; i++, in++, out++)
1200 {
1201 for (j=0 ; j<3 ; j++)
1202 {
1203 out->minmaxs[j] = LittleShort (in->mins[j]);
1204 out->minmaxs[3+j] = LittleShort (in->maxs[j]);
1205 }
1206
1207 p = LittleLong(in->contents);
1208 out->contents = p;
1209
1210 firstmarksurface = (unsigned short)LittleShort (in->firstmarksurface);
1211 out->nummarksurfaces = (unsigned short)LittleShort (in->nummarksurfaces);
1212
1213 // Check bounds
1214 Mod_ChkBounds ("MOD_LoadLeafs", "marksurfaces", firstmarksurface, out->nummarksurfaces, loadmodel->nummarksurfaces);
1215
1216 out->firstmarksurface = loadmodel->marksurfaces + firstmarksurface;
1217
1218 p = LittleLong(in->visofs);
1219 if (p == -1)
1220 out->compressed_vis = NULL;
1221 else
1222 out->compressed_vis = loadmodel->visdata + p;
1223 out->efrags = NULL;
1224
1225 for (j=0 ; j<4 ; j++)
1226 out->ambient_sound_level[j] = in->ambient_level[j];
1227
1228 // gl underwater warp
1229 if (out->contents != CONTENTS_EMPTY)
1230 {
1231 for (j=0 ; j<out->nummarksurfaces ; j++)
1232 {
1233 if (!strcmp(out->firstmarksurface[j]->texinfo->texture->name, "notexture"))
1234 out->firstmarksurface[j]->flags |= SURF_DRAWSKY;
1235 else
1236 out->firstmarksurface[j]->flags |= SURF_UNDERWATER;
1237 }
1238 }
1239 }
1240 }
1241
1242 /*
1243 =================
1244 Mod_LoadClipnodes
1245 =================
1246 */
Mod_LoadClipnodes(lump_t * l)1247 void Mod_LoadClipnodes (lump_t *l)
1248 {
1249 dclipnode_t *in, *out;
1250 int i, count;
1251 hull_t *hull;
1252
1253 in = (void *)(mod_base + l->fileofs);
1254 Mod_ChkLumpSize ("Mod_LoadClipnodes", l, sizeof(*in));
1255 count = l->filelen / sizeof(*in);
1256
1257 if (count > 32767) // Normal limit
1258 {
1259 Con_Printf ("\x02Mod_LoadClipnodes: ");
1260 Con_Printf ("excessive clipnodes (%d, normal max = %d) in %s\n", count, 32767, loadmodel->name);
1261 }
1262
1263 out = Hunk_AllocName ( count*sizeof(*out), loadname);
1264
1265 loadmodel->clipnodes = out;
1266 loadmodel->numclipnodes = count;
1267
1268 hull = &loadmodel->hulls[1];
1269 hull->clipnodes = out;
1270 hull->firstclipnode = 0;
1271 hull->lastclipnode = count-1;
1272 hull->planes = loadmodel->planes;
1273 hull->clip_mins[0] = -16;
1274 hull->clip_mins[1] = -16;
1275 hull->clip_mins[2] = -24;
1276 hull->clip_maxs[0] = 16;
1277 hull->clip_maxs[1] = 16;
1278 hull->clip_maxs[2] = 32;
1279
1280 hull = &loadmodel->hulls[2];
1281 hull->clipnodes = out;
1282 hull->firstclipnode = 0;
1283 hull->lastclipnode = count-1;
1284 hull->planes = loadmodel->planes;
1285 hull->clip_mins[0] = -32;
1286 hull->clip_mins[1] = -32;
1287 hull->clip_mins[2] = -24;
1288 hull->clip_maxs[0] = 32;
1289 hull->clip_maxs[1] = 32;
1290 hull->clip_maxs[2] = 64;
1291
1292 for (i=0 ; i<count ; i++, out++, in++)
1293 {
1294 out->planenum = LittleLong(in->planenum);
1295
1296 // Check bounds
1297 if (out->planenum < 0 || out->planenum >= loadmodel->numplanes)
1298 {
1299 Con_SafePrintf ("\x02Mod_LoadClipnodes: ");
1300 Con_SafePrintf ("plane out of bounds (%d, max = %d) in %s\n", out->planenum, loadmodel->numplanes, loadmodel->name);
1301 out->planenum = 0; // Kludge, but seems to work
1302 }
1303
1304 out->children[0] = LittleShort(in->children[0]);
1305 out->children[1] = LittleShort(in->children[1]);
1306 }
1307 }
1308
1309 /*
1310 =================
1311 Mod_MakeHull0
1312
1313 Deplicate the drawing hull structure as a clipping hull
1314 =================
1315 */
Mod_MakeHull0(void)1316 void Mod_MakeHull0 (void)
1317 {
1318 mnode_t *in, *child;
1319 dclipnode_t *out;
1320 int i, j, count;
1321 hull_t *hull;
1322
1323 hull = &loadmodel->hulls[0];
1324
1325 in = loadmodel->nodes;
1326 count = loadmodel->numnodes;
1327 out = Hunk_AllocName ( count*sizeof(*out), loadname);
1328
1329 hull->clipnodes = out;
1330 hull->firstclipnode = 0;
1331 hull->lastclipnode = count-1;
1332 hull->planes = loadmodel->planes;
1333
1334 for (i=0 ; i<count ; i++, out++, in++)
1335 {
1336 out->planenum = in->plane - loadmodel->planes;
1337 for (j=0 ; j<2 ; j++)
1338 {
1339 child = in->children[j];
1340 if (child->contents < 0)
1341 out->children[j] = child->contents;
1342 else
1343 out->children[j] = child - loadmodel->nodes;
1344 }
1345 }
1346 }
1347
1348 /*
1349 =================
1350 Mod_LoadMarksurfaces
1351 =================
1352 */
Mod_LoadMarksurfaces(lump_t * l)1353 void Mod_LoadMarksurfaces (lump_t *l)
1354 {
1355 int i, j, count;
1356 unsigned short *in;
1357 msurface_t **out;
1358
1359 in = (void *)(mod_base + l->fileofs);
1360 Mod_ChkLumpSize ("Mod_LoadMarksurfaces", l, sizeof(*in));
1361 count = l->filelen / sizeof(*in);
1362
1363 // Check marksurfaces
1364 // if (count > 65535)
1365 // Sys_Error ("Mod_LoadMarksurfaces: too many marksurfaces (%d, max = %d) in %s", count, 65535, loadmodel->name);
1366
1367 if (count > 32767) // Normal limit
1368 {
1369 Con_Printf ("\x02Mod_LoadMarksurfaces: ");
1370 Con_Printf ("excessive marksurfaces (%d, normal max = %d) in %s\n", count, 32767, loadmodel->name);
1371 }
1372
1373 out = Hunk_AllocName ( count*sizeof(*out), loadname);
1374
1375 loadmodel->marksurfaces = out;
1376 loadmodel->nummarksurfaces = count;
1377
1378 for ( i=0 ; i<count ; i++)
1379 {
1380 j = (unsigned short)LittleShort(in[i]);
1381 Mod_ChkBounds ("Mod_LoadMarksurfaces", "face", j, 1, loadmodel->numsurfaces);
1382 out[i] = loadmodel->surfaces + j;
1383 }
1384 }
1385
1386 /*
1387 =================
1388 Mod_LoadSurfedges
1389 =================
1390 */
Mod_LoadSurfedges(lump_t * l)1391 void Mod_LoadSurfedges (lump_t *l)
1392 {
1393 int i, count;
1394 int *in, *out;
1395
1396 in = (void *)(mod_base + l->fileofs);
1397 Mod_ChkLumpSize ("Mod_LoadSurfedges", l, sizeof(*in));
1398 count = l->filelen / sizeof(*in);
1399 out = Hunk_AllocName ( count*sizeof(*out), loadname);
1400
1401 loadmodel->surfedges = out;
1402 loadmodel->numsurfedges = count;
1403
1404 for ( i=0 ; i<count ; i++)
1405 {
1406 out[i] = LittleLong (in[i]);
1407
1408 // Check bounds
1409 if (abs(out[i]) >= loadmodel->numedges)
1410 {
1411 Con_SafePrintf ("\x02Mod_LoadSurfedges: ");
1412 Con_SafePrintf ("edge out of bounds (%d, max = %d) in %s\n", out[i], loadmodel->numedges, loadmodel->name);
1413 out[i] = 0; // OK?
1414 }
1415 }
1416 }
1417
1418 /*
1419 =================
1420 Mod_LoadPlanes
1421 =================
1422 */
Mod_LoadPlanes(lump_t * l)1423 void Mod_LoadPlanes (lump_t *l)
1424 {
1425 int i, j;
1426 mplane_t *out;
1427 dplane_t *in;
1428 int count;
1429 int bits;
1430
1431 in = (void *)(mod_base + l->fileofs);
1432 Mod_ChkLumpSize ("Mod_LoadPlanes", l, sizeof(*in));
1433 count = l->filelen / sizeof(*in);
1434
1435 if (count > 32767)
1436 {
1437 Con_Printf ("\x02Mod_LoadPlanes: ");
1438 Con_Printf ("excessive planes (%d, normal max = %d) in %s\n", count, 32767, loadmodel->name);
1439 }
1440
1441 out = Hunk_AllocName ( count*2*sizeof(*out), loadname);
1442
1443 loadmodel->planes = out;
1444 loadmodel->numplanes = count;
1445
1446 for ( i=0 ; i<count ; i++, in++, out++)
1447 {
1448 bits = 0;
1449 for (j=0 ; j<3 ; j++)
1450 {
1451 out->normal[j] = LittleFloat (in->normal[j]);
1452 if (out->normal[j] < 0)
1453 bits |= 1<<j;
1454 }
1455
1456 out->dist = LittleFloat (in->dist);
1457 out->type = LittleLong (in->type);
1458 out->signbits = bits;
1459 }
1460 }
1461
1462 /*
1463 =================
1464 RadiusFromBounds
1465 =================
1466 */
RadiusFromBounds(vec3_t mins,vec3_t maxs)1467 float RadiusFromBounds (vec3_t mins, vec3_t maxs)
1468 {
1469 int i;
1470 vec3_t corner;
1471
1472 for (i=0 ; i<3 ; i++)
1473 {
1474 corner[i] = fabs(mins[i]) > fabs(maxs[i]) ? fabs(mins[i]) : fabs(maxs[i]);
1475 }
1476
1477 return Length (corner);
1478 }
1479
1480 static char *LumpDesc[] =
1481 {
1482 "entities",
1483 "planes",
1484 "textures",
1485 "vertexes",
1486 "visdata",
1487 "nodes",
1488 "texinfo",
1489 "faces",
1490 "lighting",
1491 "clipnodes",
1492 "leafs",
1493 "marksurfaces",
1494 "edges",
1495 "surfedges",
1496 "models",
1497 };
1498
1499 /*
1500 =================
1501 Mod_LoadBrushModel
1502 =================
1503 */
Mod_LoadBrushModel(model_t * mod,void * buffer)1504 void Mod_LoadBrushModel (model_t *mod, void *buffer)
1505 {
1506 int i, j;
1507 dheader_t *header;
1508 dmodel_t *bm;
1509
1510 loadmodel->type = mod_brush;
1511
1512 header = (dheader_t *)buffer;
1513
1514 // Check header is inside file buffer
1515 Mod_ChkFileSize ("Mod_LoadBrushModel", "header", 0, sizeof(dheader_t));
1516
1517 i = LittleLong (header->version);
1518 if (i != BSPVERSION)
1519 Sys_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
1520
1521 // swap all the lumps
1522 mod_base = (byte *)header;
1523
1524 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
1525 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
1526
1527 // Check all lumps are OK and inside file buffer
1528 for (i = 0; i < HEADER_LUMPS; ++i)
1529 Mod_ChkFileSize ("Mod_LoadBrushModel", LumpDesc[i], header->lumps[i].fileofs, header->lumps[i].filelen);
1530
1531 // load into heap
1532
1533 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
1534 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
1535 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
1536 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
1537 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
1538 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
1539 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
1540 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
1541 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
1542 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
1543 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
1544 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
1545 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
1546 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
1547 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
1548
1549 Mod_MakeHull0 ();
1550
1551 mod->numframes = 2; // regular and alternate animation
1552
1553 //
1554 // set up the submodels (FIXME: this is confusing)
1555 //
1556 for (i=0 ; i<mod->numsubmodels ; i++)
1557 {
1558 bm = &mod->submodels[i];
1559
1560 mod->hulls[0].firstclipnode = bm->headnode[0];
1561 for (j=1 ; j<MAX_MAP_HULLS ; j++)
1562 {
1563 mod->hulls[j].firstclipnode = bm->headnode[j];
1564 mod->hulls[j].lastclipnode = mod->numclipnodes-1;
1565 }
1566
1567 mod->firstmodelsurface = bm->firstface;
1568 mod->nummodelsurfaces = bm->numfaces;
1569
1570 VectorCopy (bm->maxs, mod->maxs);
1571 VectorCopy (bm->mins, mod->mins);
1572
1573 mod->radius = RadiusFromBounds (mod->mins, mod->maxs);
1574
1575 mod->numleafs = bm->visleafs;
1576
1577 if (i < mod->numsubmodels-1)
1578 { // duplicate the basic information
1579 char name[10];
1580
1581 sprintf (name, "*%i", i+1);
1582 loadmodel = Mod_FindName (name);
1583 *loadmodel = *mod;
1584 strcpy (loadmodel->name, name);
1585 mod = loadmodel;
1586 }
1587 }
1588 }
1589
1590 /*
1591 ==============================================================================
1592
1593 ALIAS MODELS
1594
1595 ==============================================================================
1596 */
1597
1598 aliashdr_t *pheader;
1599
1600 stvert_t stverts[MAXALIASVERTS];
1601 mtriangle_t triangles[MAXALIASTRIS];
1602
1603 // a pose is a single set of vertexes. a frame may be
1604 // an animating sequence of poses
1605 trivertx_t *poseverts[MAXALIASFRAMES];
1606 int posenum;
1607
1608 byte **player_8bit_texels_tbl;
1609 byte *player_8bit_texels;
1610
1611 int aliasbboxmin[3], aliasbboxmax[3]; // Nehahra: LordHavoc - proper bounding box considerations
1612 /*
1613 =================
1614 Mod_LoadAliasFrame
1615 =================
1616 */
Mod_LoadAliasFrame(void * pin,maliasframedesc_t * frame)1617 void * Mod_LoadAliasFrame (void * pin, maliasframedesc_t *frame)
1618 {
1619 trivertx_t *pframe, *pinframe;
1620 int i, j;
1621 daliasframe_t *pdaliasframe;
1622
1623 pdaliasframe = (daliasframe_t *)pin;
1624
1625 // Check frame is inside file buffer
1626 Mod_ChkFileSize ("Mod_LoadAliasFrame", "frame", (byte *)pdaliasframe - mod_base, sizeof(daliasframe_t));
1627
1628 strcpy (frame->name, pdaliasframe->name);
1629 frame->firstpose = posenum;
1630 frame->numposes = 1;
1631
1632 for (i=0 ; i<3 ; i++)
1633 {
1634 // these are byte values, so we don't have to worry about
1635 // endianness
1636 frame->bboxmin.v[i] = pdaliasframe->bboxmin.v[i];
1637 frame->bboxmax.v[i] = pdaliasframe->bboxmax.v[i]; // Nehahra - EnderFIX
1638
1639 if (frame->bboxmin.v[i] < aliasbboxmin[i]) // LordHavoc: doing proper bbox for model
1640 aliasbboxmin[i] = frame->bboxmin.v[i];
1641 if (frame->bboxmax.v[i] > aliasbboxmax[i])
1642 aliasbboxmax[i] = frame->bboxmax.v[i];
1643
1644 }
1645
1646 pinframe = (trivertx_t *)(pdaliasframe + 1);
1647
1648 // Check trivertex is inside file buffer
1649 Mod_ChkFileSize ("Mod_LoadAliasFrame", "trivertex", (byte *)pinframe - mod_base, sizeof(trivertx_t));
1650
1651 if (posenum >= MAXALIASFRAMES)
1652 Sys_Error ("Mod_LoadAliasFrame: invalid # of frames (%d, max = %d) in %s", posenum, MAXALIASFRAMES, loadmodel->name);
1653
1654 poseverts[posenum] = pinframe;
1655 posenum++;
1656
1657 pinframe += pheader->numverts;
1658
1659 return (void *)pinframe;
1660 }
1661
1662
1663 /*
1664 =================
1665 Mod_LoadAliasGroup
1666 =================
1667 */
Mod_LoadAliasGroup(void * pin,maliasframedesc_t * frame)1668 void *Mod_LoadAliasGroup (void * pin, maliasframedesc_t *frame)
1669 {
1670 daliasgroup_t *pingroup;
1671 int i, numframes;
1672 daliasinterval_t *pin_intervals;
1673 void *ptemp;
1674
1675 pingroup = (daliasgroup_t *)pin;
1676
1677 // Check group is inside file buffer
1678 Mod_ChkFileSize ("Mod_LoadAliasGroup", "group", (byte *)pingroup - mod_base, sizeof(daliasgroup_t));
1679
1680 numframes = LittleLong (pingroup->numframes);
1681
1682 frame->firstpose = posenum;
1683 frame->numposes = numframes;
1684
1685 for (i=0 ; i<3 ; i++)
1686 {
1687 // these are byte values, so we don't have to worry about endianness
1688 frame->bboxmin.v[i] = pingroup->bboxmin.v[i];
1689 frame->bboxmax.v[i] = pingroup->bboxmax.v[i]; // Nehahra - EnderFIX
1690
1691 if (frame->bboxmin.v[i] < aliasbboxmin[i]) // LordHavoc: doing proper bbox for model
1692 aliasbboxmin[i] = frame->bboxmin.v[i];
1693 if (frame->bboxmax.v[i] > aliasbboxmax[i])
1694 aliasbboxmax[i] = frame->bboxmax.v[i];
1695 }
1696
1697 pin_intervals = (daliasinterval_t *)(pingroup + 1);
1698
1699 // Check intervals are inside file buffer
1700 Mod_ChkFileSize ("Mod_LoadAliasGroup", "intervals", (byte *)pin_intervals - mod_base, numframes * sizeof(daliasinterval_t));
1701
1702 frame->interval = LittleFloat (pin_intervals->interval);
1703
1704 pin_intervals += numframes;
1705
1706 ptemp = (void *)pin_intervals;
1707
1708 for (i=0 ; i<numframes ; i++)
1709 {
1710 // Check trivertex is inside file buffer
1711 Mod_ChkFileSize ("Mod_LoadAliasGroup", "trivertex", (byte *)((daliasframe_t *)ptemp + 1) - mod_base, sizeof(trivertx_t));
1712
1713 if (posenum >= MAXALIASFRAMES)
1714 Sys_Error ("Mod_LoadAliasGroup: invalid # of frames (%d, max = %d) in %s", posenum, MAXALIASFRAMES, loadmodel->name);
1715
1716 poseverts[posenum] = (trivertx_t *)((daliasframe_t *)ptemp + 1);
1717 posenum++;
1718
1719 ptemp = (trivertx_t *)((daliasframe_t *)ptemp + 1) + pheader->numverts;
1720 }
1721
1722 return ptemp;
1723 }
1724
1725 //=========================================================
1726
1727 /*
1728 =================
1729 Mod_FloodFillSkin
1730
1731 Fill background pixels so mipmapping doesn't have haloes - Ed
1732 =================
1733 */
1734
1735 typedef struct
1736 {
1737 short x, y;
1738 } floodfill_t;
1739
1740 extern unsigned d_8to24table[];
1741
1742 // must be a power of 2
1743 #define FLOODFILL_FIFO_SIZE 0x1000
1744 #define FLOODFILL_FIFO_MASK (FLOODFILL_FIFO_SIZE - 1)
1745
1746 #define FLOODFILL_STEP( off, dx, dy ) \
1747 { \
1748 if (pos[off] == fillcolor) \
1749 { \
1750 pos[off] = 255; \
1751 fifo[inpt].x = x + (dx), fifo[inpt].y = y + (dy); \
1752 inpt = (inpt + 1) & FLOODFILL_FIFO_MASK; \
1753 } \
1754 else if (pos[off] != 255) fdc = pos[off]; \
1755 }
1756
Mod_FloodFillSkin(byte * skin,int skinwidth,int skinheight)1757 void Mod_FloodFillSkin( byte *skin, int skinwidth, int skinheight )
1758 {
1759 byte fillcolor = *skin; // assume this is the pixel to fill
1760 floodfill_t fifo[FLOODFILL_FIFO_SIZE];
1761 int inpt = 0, outpt = 0;
1762 int filledcolor = -1;
1763 int i;
1764
1765 if (filledcolor == -1)
1766 {
1767 filledcolor = 0;
1768 // attempt to find opaque black
1769 for (i = 0; i < 256; ++i)
1770 if (d_8to24table[i] == (255 << 0)) // alpha 1.0
1771 {
1772 filledcolor = i;
1773 break;
1774 }
1775 }
1776
1777 // can't fill to filled color or to transparent color (used as visited marker)
1778 if ((fillcolor == filledcolor) || (fillcolor == 255))
1779 {
1780 //printf( "not filling skin from %d to %d\n", fillcolor, filledcolor );
1781 return;
1782 }
1783
1784 fifo[inpt].x = 0, fifo[inpt].y = 0;
1785 inpt = (inpt + 1) & FLOODFILL_FIFO_MASK;
1786
1787 while (outpt != inpt)
1788 {
1789 int x = fifo[outpt].x, y = fifo[outpt].y;
1790 int fdc = filledcolor;
1791 byte *pos = &skin[x + skinwidth * y];
1792
1793 outpt = (outpt + 1) & FLOODFILL_FIFO_MASK;
1794
1795 if (x > 0) FLOODFILL_STEP( -1, -1, 0 );
1796 if (x < skinwidth - 1) FLOODFILL_STEP( 1, 1, 0 );
1797 if (y > 0) FLOODFILL_STEP( -skinwidth, 0, -1 );
1798 if (y < skinheight - 1) FLOODFILL_STEP( skinwidth, 0, 1 );
1799 skin[x + skinwidth * y] = fdc;
1800 }
1801 }
1802
1803 /*
1804 ===============
1805 Mod_LoadAllSkins
1806 ===============
1807 */
Mod_LoadAllSkins(int numskins,daliasskintype_t * pskintype)1808 void *Mod_LoadAllSkins (int numskins, daliasskintype_t *pskintype)
1809 {
1810 int i, j, k;
1811 char name[32];
1812 int s;
1813 byte *copy;
1814 byte *skin;
1815 byte *texels;
1816 daliasskingroup_t *pinskingroup;
1817 int groupskins;
1818 daliasskininterval_t *pinskinintervals;
1819
1820 skin = (byte *)(pskintype + 1);
1821
1822 if (numskins < 1 || numskins > MAX_SKINS)
1823 Sys_Error ("Mod_LoadAllSkins: invalid # of skins (%d, max = %d) in %s", numskins, MAX_SKINS, loadmodel->name);
1824
1825 s = pheader->skinwidth * pheader->skinheight;
1826
1827 for (i=0 ; i<numskins ; i++)
1828 {
1829 char Str[256];
1830
1831 sprintf (Str, "skin %d", i);
1832 Mod_ChkFileSize ("Mod_LoadAllSkins", Str, (byte *)pskintype - mod_base, sizeof(daliasskintype_t));
1833
1834 Mod_ChkType ("Mod_LoadAllSkins", "skintype", Str, pskintype->type, ALIAS_SKIN_SINGLE, ALIAS_SKIN_GROUP);
1835
1836 if (pskintype->type == ALIAS_SKIN_SINGLE) {
1837 Mod_ChkFileSize ("Mod_LoadAllSkins", Str, (byte *)(pskintype + 1) - mod_base, s);
1838
1839 Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight );
1840
1841 // save 8 bit texels for the player model to remap
1842 // if (!strcmp(loadmodel->name,"progs/player.mdl")) {
1843 texels = Hunk_AllocName(s, loadname);
1844 pheader->texels[i] = texels - (byte *)pheader;
1845 memcpy (texels, (byte *)(pskintype + 1), s);
1846 // }
1847 sprintf (name, "%s_%i", loadmodel->name, i);
1848 pheader->gl_texturenum[i][0] =
1849 pheader->gl_texturenum[i][1] =
1850 pheader->gl_texturenum[i][2] =
1851 pheader->gl_texturenum[i][3] =
1852 GL_LoadTexture (name, pheader->skinwidth,
1853 pheader->skinheight, (byte *)(pskintype + 1), true, false);
1854 pskintype = (daliasskintype_t *)((byte *)(pskintype+1) + s);
1855 }
1856 else
1857 {
1858 // animating skin group. yuck.
1859 pskintype++;
1860 pinskingroup = (daliasskingroup_t *)pskintype;
1861
1862 sprintf (Str, "group %d", i);
1863 Mod_ChkFileSize ("Mod_LoadAllSkins", Str, (byte *)pinskingroup - mod_base, sizeof(daliasskingroup_t));
1864
1865 groupskins = LittleLong (pinskingroup->numskins);
1866 pinskinintervals = (daliasskininterval_t *)(pinskingroup + 1);
1867
1868 pskintype = (void *)(pinskinintervals + groupskins);
1869
1870 for (j=0 ; j<groupskins ; j++)
1871 {
1872 sprintf (Str, "group %d, skin %d", i, j);
1873 Mod_ChkFileSize ("Mod_LoadAllSkins", Str, (byte *)pskintype - mod_base, s);
1874
1875 Mod_FloodFillSkin( skin, pheader->skinwidth, pheader->skinheight );
1876 if (j == 0) {
1877 texels = Hunk_AllocName(s, loadname);
1878 pheader->texels[i] = texels - (byte *)pheader;
1879 memcpy (texels, (byte *)(pskintype), s);
1880 }
1881 sprintf (name, "%s_%i_%i", loadmodel->name, i,j);
1882 pheader->gl_texturenum[i][j&3] =
1883 GL_LoadTexture (name, pheader->skinwidth,
1884 pheader->skinheight, (byte *)(pskintype), true, false);
1885 pskintype = (daliasskintype_t *)((byte *)(pskintype) + s);
1886 }
1887 k = j;
1888 for (/* */; j < 4; j++)
1889 pheader->gl_texturenum[i][j&3] =
1890 pheader->gl_texturenum[i][j - k];
1891 }
1892 }
1893
1894 return (void *)pskintype;
1895 }
1896
1897 //=========================================================================
1898
1899 /*
1900 =================
1901 Mod_LoadAliasModel
1902 =================
1903 */
Mod_LoadAliasModel(model_t * mod,void * buffer)1904 void Mod_LoadAliasModel (model_t *mod, void *buffer)
1905 {
1906 int i, j;
1907 mdl_t *pinmodel;
1908 stvert_t *pinstverts;
1909 dtriangle_t *pintriangles;
1910 int version, numframes, numskins;
1911 int size;
1912 daliasframetype_t *pframetype;
1913 daliasskintype_t *pskintype;
1914 int start, end, total;
1915 char *Name;
1916
1917 // HACK HACK HACK -- no fullbright colors, so make torches/flames full light
1918
1919 Name = strrchr (mod->name, '/');
1920
1921 if (Name)
1922 {
1923 int autobright = 0, abstart = 0;
1924
1925 ++Name;
1926
1927 if (!strcmp (mod->name, "progs/flame.mdl") ||
1928 !strcmp (mod->name, "progs/flame2.mdl"))
1929 mod->fullbright = true; // GLQuake compatibility
1930 else if (!strcmp (mod->name, "progs/eyes.mdl"))
1931 mod->eyes = true;
1932 else if (!strcmp (mod->name, "progs/bolt.mdl"))
1933 mod->bolt = true;
1934 else if (!strcmp (mod->name, "progs/missile.mdl"))
1935 mod->missile = true;
1936 else if (!strcmp (mod->name, "progs/quaddama.mdl"))
1937 mod->quaddama = true;
1938 else if (!strcmp (mod->name, "progs/invulner.mdl"))
1939 mod->invulner = true;
1940 else if (!strncmp (Name, "flame", 5) ||
1941 !strcmp (Name, "newfire.mdl") || // For Kinn ...
1942 !strcmp (Name, "longtrch.mdl")) // For Chapters ...
1943 autobright = 255;
1944 else if (!strncmp (Name, "lantern", 7) ||
1945 !strcmp (Name, "brazshrt.mdl") || // For Chapters ...
1946 !strcmp (Name, "braztall.mdl"))
1947 {
1948 mod->lantern = true;
1949 autobright = 150;
1950 }
1951 else if (!strncmp (Name, "bolt", 4) || // Bolts ...
1952 !strcmp (Name, "s_light.mdl"))
1953 {
1954 mod->autobright[abstart++] = 100;
1955 autobright = 150;
1956 }
1957 else if (!strncmp (Name, "candle", 6))
1958 {
1959 mod->candle = true;
1960 autobright = 125;
1961 }
1962 else if (!strcmp (&Name[1], "_g_key.mdl") ||// Keys ...
1963 !strcmp (&Name[1], "_s_key.mdl") ||
1964 !strcmp (Name, "bloodkey.mdl") ||
1965 !strcmp (Name, "catkey.mdl") ||
1966 !strcmp (Name, "spikekey.mdl") ||
1967 !strcmp (Name, "end1.mdl") ||
1968 !strcmp (Name, "end2.mdl") ||
1969 !strcmp (Name, "end3.mdl") ||
1970 !strcmp (Name, "end4.mdl"))
1971 autobright = 125;
1972
1973 if (autobright)
1974 {
1975 for (i = abstart; i < AUTOBRIGHTS; ++i)
1976 mod->autobright[i] = autobright;
1977
1978 // Con_DPrintf ("\002autobright ");
1979 // Con_DPrintf ("%s (level %d)\n", mod->name, autobright);
1980 }
1981 }
1982
1983 start = Hunk_LowMark ();
1984
1985 mod_base = (byte *)buffer;
1986 pinmodel = (mdl_t *)buffer;
1987
1988 // Check version+header is inside file buffer
1989 Mod_ChkFileSize ("Mod_LoadAliasModel", "model header", 0, sizeof(int) + sizeof(mdl_t));
1990
1991 version = LittleLong (pinmodel->version);
1992 if (version != ALIAS_VERSION)
1993 Sys_Error ("Mod_LoadAliasModel: %s has wrong version number (%i should be %i)",
1994 mod->name, version, ALIAS_VERSION);
1995
1996 //
1997 // allocate space for a working header, plus all the data except the frames,
1998 // skin and group info
1999 //
2000 size = sizeof (aliashdr_t)
2001 + (LittleLong (pinmodel->numframes) - 1) *
2002 sizeof (pheader->frames[0]);
2003 pheader = Hunk_AllocName (size, loadname);
2004
2005 mod->flags = LittleLong (pinmodel->flags);
2006
2007 //
2008 // endian-adjust and copy the data, starting with the alias model header
2009 //
2010 pheader->boundingradius = LittleFloat (pinmodel->boundingradius);
2011 pheader->numskins = LittleLong (pinmodel->numskins);
2012 pheader->skinwidth = LittleLong (pinmodel->skinwidth);
2013 pheader->skinheight = LittleLong (pinmodel->skinheight);
2014
2015 if (pheader->skinheight > MAX_LBM_HEIGHT)
2016 Sys_Error ("Mod_LoadAliasModel: model %s has a skin taller than %d (%d)", mod->name,
2017 MAX_LBM_HEIGHT, pheader->skinheight);
2018
2019 pheader->numverts = LittleLong (pinmodel->numverts);
2020
2021 if (pheader->numverts <= 0)
2022 Sys_Error ("Mod_LoadAliasModel: model %s has no vertices", mod->name);
2023
2024 if (pheader->numverts > 1024)
2025 {
2026 // Old limit
2027 Con_Printf ("\002Mod_LoadAliasModel: ");
2028 Con_Printf ("excessive vertices (%d, normal max = %d) in %s\n", pheader->numverts, 1024, loadmodel->name);
2029 }
2030
2031 if (pheader->numverts > MAXALIASVERTS)
2032 Sys_Error ("Mod_LoadAliasModel: model %s has too many vertices (%d, max = %d)", mod->name, pheader->numverts, MAXALIASVERTS);
2033
2034 pheader->numtris = LittleLong (pinmodel->numtris);
2035
2036 if (pheader->numtris <= 0)
2037 Sys_Error ("Mod_LoadAliasModel: model %s has no triangles", mod->name);
2038
2039 pheader->numframes = LittleLong (pinmodel->numframes);
2040
2041 if (pheader->numframes > MAXALIASFRAMES)
2042 {
2043 Con_Printf ("\002Mod_LoadAliasModel: ");
2044 Con_Printf ("too many frames (%d, max = %d) in %s\n", pheader->numframes, MAXALIASFRAMES, loadmodel->name);
2045 pheader->numframes = MAXALIASFRAMES; // Cap
2046 }
2047
2048 numframes = pheader->numframes;
2049 if (numframes < 1)
2050 Sys_Error ("Mod_LoadAliasModel: invalid # of frames %d in %s", numframes, mod->name);
2051
2052 pheader->size = LittleFloat (pinmodel->size) * ALIAS_BASE_SIZE_RATIO;
2053 mod->synctype = LittleLong (pinmodel->synctype);
2054 mod->numframes = pheader->numframes;
2055
2056 for (i=0 ; i<3 ; i++)
2057 {
2058 pheader->scale[i] = LittleFloat (pinmodel->scale[i]);
2059 pheader->scale_origin[i] = LittleFloat (pinmodel->scale_origin[i]);
2060 pheader->eyeposition[i] = LittleFloat (pinmodel->eyeposition[i]);
2061 }
2062
2063
2064 //
2065 // load the skins
2066 //
2067 pskintype = (daliasskintype_t *)&pinmodel[1];
2068 pskintype = Mod_LoadAllSkins (pheader->numskins, pskintype);
2069
2070 if (!mod->fullbright && !mod->autobright[0])
2071 {
2072 byte *skin = (byte *)((daliasskintype_t *)&pinmodel[1] + 1);
2073 int s = pheader->skinwidth * pheader->skinheight;
2074 int FullBrights, FullBrights2, Yellow, Blue;
2075
2076 Yellow = Blue = 0;
2077
2078 for (i = 0; i < s; ++i)
2079 {
2080 if (skin[i] >= 224 && skin[i] <= 254)
2081 {
2082 if (skin[i] >= 244 && skin[i] <= 246)
2083 ++Blue;
2084 else
2085 ++Yellow;
2086 }
2087 }
2088
2089 for (i = 0; i < AUTOBRIGHTS; ++i)
2090 {
2091 // gl_autobright == 0 : GLQuake compatibility
2092 // gl_autobright == 1 : default, count mostly yellow/red fullbrights
2093 // gl_autobright == 2 : count all fullbrights
2094 // gl_autobright == 3 : count all fullbrights, high intensity
2095 if (i == 0)
2096 {
2097 FullBrights = Yellow;
2098 FullBrights2 = Blue;
2099 }
2100 else
2101 {
2102 FullBrights = Yellow + Blue;
2103 FullBrights2 = 0;
2104 }
2105
2106 FullBrights *= 100.0 / s;
2107 FullBrights2 *= 100.0 / s;
2108
2109 if (FullBrights > 75)
2110 mod->autobright[i] = 150;
2111 else if (FullBrights > 50)
2112 mod->autobright[i] = 125;
2113 else if (FullBrights2 > 75)
2114 mod->autobright[i] = 100;
2115
2116 if (mod->autobright[i])
2117 {
2118 // Con_DPrintf ("\002autobright ");
2119 // Con_DPrintf ("%s (type %d, level %d, fb %d, fb2 %d)\n", mod->name, i, mod->autobright[i], FullBrights, FullBrights2);
2120 }
2121 }
2122 }
2123
2124 //
2125 // load base s and t vertices
2126 //
2127 pinstverts = (stvert_t *)pskintype;
2128
2129 // Check vertices are inside file buffer
2130 Mod_ChkFileSize ("Mod_LoadAliasModel", "vertices", (byte *)pinstverts - mod_base, pheader->numverts * sizeof(stvert_t));
2131
2132 for (i=0 ; i<pheader->numverts ; i++)
2133 {
2134 stverts[i].onseam = LittleLong (pinstverts[i].onseam);
2135 stverts[i].s = LittleLong (pinstverts[i].s);
2136 stverts[i].t = LittleLong (pinstverts[i].t);
2137 }
2138
2139 //
2140 // load triangle lists
2141 //
2142 pintriangles = (dtriangle_t *)&pinstverts[pheader->numverts];
2143
2144 // Check triangles are inside file buffer
2145 Mod_ChkFileSize ("Mod_LoadAliasModel", "triangles", (byte *)pintriangles - mod_base, pheader->numtris * sizeof(dtriangle_t));
2146
2147 for (i=0 ; i<pheader->numtris ; i++)
2148 {
2149 triangles[i].facesfront = LittleLong (pintriangles[i].facesfront);
2150
2151 for (j=0 ; j<3 ; j++)
2152 {
2153 triangles[i].vertindex[j] =
2154 LittleLong (pintriangles[i].vertindex[j]);
2155
2156 if (triangles[i].vertindex[j] < 0 || triangles[i].vertindex[j] >= MAXALIASVERTS)
2157 Sys_Error ("Mod_LoadAliasModel: invalid triangles[%d].vertindex[%d] (%d, max = %d) in %s", i, j, triangles[i].vertindex[j], MAXALIASVERTS, mod->name);
2158 }
2159 }
2160
2161 //
2162 // load the frames
2163 //
2164 posenum = 0;
2165 pframetype = (daliasframetype_t *)&pintriangles[pheader->numtris];
2166
2167 // Nehahra: LordHavoc - doing proper bbox for model
2168 aliasbboxmin[0] = aliasbboxmin[1] = aliasbboxmin[2] = 1000;
2169 aliasbboxmax[0] = aliasbboxmax[1] = aliasbboxmax[2] = -1000;
2170
2171 for (i=0 ; i<numframes ; i++)
2172 {
2173 aliasframetype_t frametype;
2174 char Str[256];
2175
2176 sprintf (Str, "frame %d", i);
2177 Mod_ChkFileSize ("Mod_LoadAliasModel", Str, (byte *)pframetype - mod_base, sizeof(aliasframetype_t));
2178
2179 frametype = LittleLong (pframetype->type);
2180
2181 Mod_ChkType ("Mod_LoadAliasModel", "frametype", Str, frametype, ALIAS_SINGLE, ALIAS_GROUP);
2182
2183 if (frametype == ALIAS_SINGLE)
2184 {
2185 pframetype = (daliasframetype_t *)
2186 Mod_LoadAliasFrame (pframetype + 1, &pheader->frames[i]);
2187 }
2188 else
2189 {
2190 pframetype = (daliasframetype_t *)
2191 Mod_LoadAliasGroup (pframetype + 1, &pheader->frames[i]);
2192 }
2193 }
2194
2195 pheader->numposes = posenum;
2196
2197 mod->type = mod_alias;
2198
2199 // FIXME: do this right
2200 // mod->mins[0] = mod->mins[1] = mod->mins[2] = -16;
2201 // mod->maxs[0] = mod->maxs[1] = mod->maxs[2] = 16;
2202
2203 // Nehahra: LordHavoc - Fixed :>
2204 for (j = 0;j < 3;j++)
2205 {
2206 mod->mins[j] = aliasbboxmin[j] * pheader->scale[j] + pheader->scale_origin[j];
2207 mod->maxs[j] = aliasbboxmax[j] * pheader->scale[j] + pheader->scale_origin[j];
2208 }
2209
2210 // Nehahra: End
2211
2212 //
2213 // build the draw lists
2214 //
2215 GL_MakeAliasModelDisplayLists (mod, pheader);
2216
2217 //
2218 // move the complete, relocatable alias model to the cache
2219 //
2220 end = Hunk_LowMark ();
2221 total = end - start;
2222
2223 Cache_Alloc (&mod->cache, total, loadname);
2224 if (!mod->cache.data)
2225 return;
2226 memcpy (mod->cache.data, pheader, total);
2227
2228 Hunk_FreeToLowMark (start);
2229 }
2230
2231 //=============================================================================
2232
2233 /*
2234 =================
2235 Mod_LoadSpriteFrame
2236 =================
2237 */
Mod_LoadSpriteFrame(void * pin,mspriteframe_t ** ppframe,int framenum,int bytes)2238 void * Mod_LoadSpriteFrame (void * pin, mspriteframe_t **ppframe, int framenum, int bytes)
2239 {
2240 dspriteframe_t *pinframe;
2241 mspriteframe_t *pspriteframe;
2242 int i, width, height, size, origin[2];
2243 unsigned short *ppixout;
2244 byte *ppixin;
2245 char name[64], str[256];
2246
2247 pinframe = (dspriteframe_t *)pin;
2248
2249 // Check sprite frame is inside file buffer
2250 sprintf (str, "frame %d", framenum);
2251 Mod_ChkFileSize ("Mod_LoadSpriteFrame", str, (byte *)pinframe - mod_base, sizeof(dspriteframe_t));
2252
2253 width = LittleLong (pinframe->width);
2254 height = LittleLong (pinframe->height);
2255 size = width * height;
2256
2257 Mod_ChkFileSize ("Mod_LoadSpriteFrame", str, (byte *)(pinframe + 1) - mod_base, size);
2258
2259 pspriteframe = Hunk_AllocName (sizeof (mspriteframe_t),loadname);
2260
2261 Q_memset (pspriteframe, 0, sizeof (mspriteframe_t));
2262
2263 *ppframe = pspriteframe;
2264
2265 pspriteframe->width = width;
2266 pspriteframe->height = height;
2267 origin[0] = LittleLong (pinframe->origin[0]);
2268 origin[1] = LittleLong (pinframe->origin[1]);
2269
2270 pspriteframe->up = origin[1];
2271 pspriteframe->down = origin[1] - height;
2272 pspriteframe->left = origin[0];
2273 pspriteframe->right = width + origin[0];
2274
2275 if (size)
2276 {
2277 sprintf (name, "%s_%i", loadmodel->name, framenum);
2278
2279 if (bytes == 1)
2280 pspriteframe->gl_texturenum = GL_LoadTexture (name, width, height, (byte *)(pinframe + 1), true, true);
2281 else
2282 pspriteframe->gl_texturenum = GL_LoadTexture32 (name, width, height, (byte *)(pinframe + 1), true, true);
2283 }
2284
2285 return (void *)((byte *)pinframe + sizeof (dspriteframe_t) + size);
2286 }
2287
2288
2289 /*
2290 =================
2291 Mod_LoadSpriteGroup
2292 =================
2293 */
Mod_LoadSpriteGroup(void * pin,mspriteframe_t ** ppframe,int framenum,int bytes)2294 void * Mod_LoadSpriteGroup (void * pin, mspriteframe_t **ppframe, int framenum, int bytes)
2295 {
2296 dspritegroup_t *pingroup;
2297 mspritegroup_t *pspritegroup;
2298 int i, numframes;
2299 dspriteinterval_t *pin_intervals;
2300 float *poutintervals;
2301 void *ptemp;
2302
2303 pingroup = (dspritegroup_t *)pin;
2304
2305 numframes = LittleLong (pingroup->numframes);
2306
2307 pspritegroup = Hunk_AllocName (sizeof (mspritegroup_t) +
2308 (numframes - 1) * sizeof (pspritegroup->frames[0]), loadname);
2309
2310 pspritegroup->numframes = numframes;
2311
2312 *ppframe = (mspriteframe_t *)pspritegroup;
2313
2314 pin_intervals = (dspriteinterval_t *)(pingroup + 1);
2315
2316 poutintervals = Hunk_AllocName (numframes * sizeof (float), loadname);
2317
2318 pspritegroup->intervals = poutintervals;
2319
2320 for (i=0 ; i<numframes ; i++)
2321 {
2322 *poutintervals = LittleFloat (pin_intervals->interval);
2323 if (*poutintervals <= 0.0)
2324 Sys_Error ("Mod_LoadSpriteGroup: interval %f <= 0 in %s", *poutintervals, loadmodel->name);
2325
2326 poutintervals++;
2327 pin_intervals++;
2328 }
2329
2330 ptemp = (void *)pin_intervals;
2331
2332 for (i=0 ; i<numframes ; i++)
2333 {
2334 ptemp = Mod_LoadSpriteFrame (ptemp, &pspritegroup->frames[i], framenum * 100 + i, bytes);
2335 }
2336
2337 return ptemp;
2338 }
2339
2340
2341 /*
2342 =================
2343 Mod_LoadSpriteModel
2344 =================
2345 */
Mod_LoadSpriteModel(model_t * mod,void * buffer)2346 void Mod_LoadSpriteModel (model_t *mod, void *buffer)
2347 {
2348 int i;
2349 int version;
2350 dsprite_t *pin;
2351 msprite_t *psprite;
2352 int numframes;
2353 int size;
2354 dspriteframetype_t *pframetype;
2355 int bytesperpixel = 1;
2356
2357 mod_base = (byte *)buffer;
2358 pin = (dsprite_t *)buffer;
2359
2360 // Check version+header is inside file buffer
2361 Mod_ChkFileSize ("Mod_LoadSpriteModel", "sprite header", 0, sizeof(int) + sizeof(dsprite_t));
2362
2363 version = LittleLong (pin->version);
2364
2365 // Nehahra - LordHavoc: 32bit textures
2366 if (version != SPRITE_VERSION && version != SPRITE32_VERSION)
2367 Sys_Error ("Mod_LoadSpriteModel: %s has wrong version number (%i should be %i or %i)", mod->name, version, SPRITE_VERSION, SPRITE32_VERSION);
2368
2369 if ((nospr32.value) && (version == SPRITE32_VERSION))
2370 Sys_Error("Mod_LoadSpriteModel: precaching spr32 with nospr32 cvar in %s!", mod->name);
2371
2372 // if (version == SPRITE32_VERSION)
2373 // Con_DPrintf("Mod_LoadSpriteModel: WARNING: SPR32 HAS VERSION NUMBER2\nTHIS HAS BEEN DEPRECATED\n");
2374
2375 if (version == SPRITE32_VERSION)
2376 bytesperpixel = 4;
2377
2378 numframes = LittleLong (pin->numframes);
2379
2380 size = sizeof (msprite_t) + (numframes - 1) * sizeof (psprite->frames);
2381
2382 psprite = Hunk_AllocName (size, loadname);
2383
2384 mod->cache.data = psprite;
2385
2386 psprite->type = LittleLong (pin->type);
2387 psprite->maxwidth = LittleLong (pin->width);
2388 psprite->maxheight = LittleLong (pin->height);
2389 psprite->beamlength = LittleFloat (pin->beamlength);
2390 mod->synctype = LittleLong (pin->synctype);
2391 psprite->numframes = numframes;
2392
2393 mod->mins[0] = mod->mins[1] = -psprite->maxwidth/2;
2394 mod->maxs[0] = mod->maxs[1] = psprite->maxwidth/2;
2395 mod->mins[2] = -psprite->maxheight/2;
2396 mod->maxs[2] = psprite->maxheight/2;
2397
2398 //
2399 // load the frames
2400 //
2401 if (numframes < 1)
2402 Sys_Error ("Mod_LoadSpriteModel: invalid # of frames %d in %s", numframes, mod->name);
2403
2404 mod->numframes = numframes;
2405
2406 pframetype = (dspriteframetype_t *)(pin + 1);
2407
2408 for (i=0 ; i<numframes ; i++)
2409 {
2410 spriteframetype_t frametype;
2411 char Str[256];
2412
2413 sprintf (Str, "frame %d", i);
2414 Mod_ChkFileSize ("Mod_LoadSpriteModel", Str, (byte *)pframetype - mod_base, sizeof(spriteframetype_t));
2415
2416 frametype = LittleLong (pframetype->type);
2417 psprite->frames[i].type = frametype;
2418
2419 Mod_ChkType ("Mod_LoadSpriteModel", "frametype", Str, frametype, SPR_SINGLE, SPR_GROUP);
2420
2421 if (frametype == SPR_SINGLE)
2422 {
2423 pframetype = (dspriteframetype_t *)
2424 Mod_LoadSpriteFrame (pframetype + 1,
2425 &psprite->frames[i].frameptr, i, bytesperpixel);
2426 }
2427 else
2428 {
2429 pframetype = (dspriteframetype_t *)
2430 Mod_LoadSpriteGroup (pframetype + 1,
2431 &psprite->frames[i].frameptr, i, bytesperpixel);
2432 }
2433 }
2434
2435 mod->type = mod_sprite;
2436 }
2437
2438 //=============================================================================
2439
2440 /*
2441 ================
2442 Mod_Print
2443 ================
2444 */
Mod_Print(void)2445 void Mod_Print (void)
2446 {
2447 int i;
2448 model_t *mod;
2449
2450 Con_SafePrintf ("Cached models:\n");
2451 for (i=0, mod=mod_known ; i < mod_numknown ; i++, mod++)
2452 {
2453 Con_SafePrintf ("%8p : %s\n",mod->cache.data, mod->name);
2454 }
2455
2456 Con_SafePrintf ("\n%d models\n", mod_numknown);
2457 }
2458
2459
2460