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 <float.h>
26 #include <stdint.h>
27
28 #include "cmd.h"
29 #include "common.h"
30 #include "console.h"
31 #include "model.h"
32
33 #ifdef SERVERONLY
34 #include "qwsvdef.h"
35 /* A dummy texture to point to. FIXME - should server care about textures? */
36 static texture_t r_notexture_mip_qwsv;
37 #else
38 #include "quakedef.h"
39 #include "render.h"
40 #include "sys.h"
41 #ifdef QW_HACK
42 #include "crc.h"
43 #endif
44 /* FIXME - quick hack to enable merging of NQ/QWSV shared code */
45 #define SV_Error Sys_Error
46 #endif
47
48 static model_t *loadmodel;
49 static char loadname[MAX_QPATH]; /* for hunk tags */
50
51 static void Mod_LoadBrushModel(model_t *mod, void *buffer, unsigned long size);
52 static model_t *Mod_LoadModel(model_t *mod, qboolean crash);
53
54 #define MAX_MOD_KNOWN 512
55 static model_t mod_known[MAX_MOD_KNOWN];
56 static int mod_numknown;
57
58 static const model_loader_t *mod_loader;
59
60 static void PVSCache_f(void);
61
62 // leilei HACK
63
64 int coloredlights = 0; // to debug the colored lights as we have no menu option yet.
65
66
67 /*
68 ===============
69 Mod_Init
70 ===============
71 */
72 void
Mod_Init(const model_loader_t * loader)73 Mod_Init(const model_loader_t *loader)
74 {
75 Cmd_AddCommand("pvscache", PVSCache_f);
76 mod_loader = loader;
77 }
78
79 /*
80 ===============
81 Mod_PointInLeaf
82 ===============
83 */
Mod_PointInLeaf(const model_t * model,const vec3_t point)84 mleaf_t * Mod_PointInLeaf(const model_t *model, const vec3_t point)
85 {
86 mnode_t *node;
87
88 if (!model || !model->nodes)
89 SV_Error("%s: bad model", __func__);
90
91 node = model->nodes;
92
93 while (1)
94 {
95 float dist;
96 mplane_t *plane;
97 if (node->contents < 0)
98 return (mleaf_t *)node;
99 plane = node->plane;
100 dist = DotProduct(point, plane->normal) - plane->dist;
101 if (dist > 0)
102 node = node->children[0];
103 else
104 node = node->children[1];
105 }
106
107 return NULL; // never reached
108 }
109
110 void
Mod_AddLeafBits(leafbits_t * dst,const leafbits_t * src)111 Mod_AddLeafBits(leafbits_t *dst, const leafbits_t *src)
112 {
113 int i, leafblocks;
114 const leafblock_t *srcblock;
115 leafblock_t *dstblock;
116
117 if (src->numleafs != dst->numleafs)
118 SV_Error("%s: src->numleafs (%d) != dst->numleafs (%d)",
119 __func__, src->numleafs, dst->numleafs);
120
121 srcblock = src->bits;
122 dstblock = dst->bits;
123 leafblocks = (src->numleafs + LEAFMASK) >> LEAFSHIFT;
124 for (i = 0; i < leafblocks; i++)
125 *dstblock++ |= *srcblock++;
126 }
127
128 #ifdef SERVERONLY
129 int
Mod_CountLeafBits(const leafbits_t * leafbits)130 Mod_CountLeafBits(const leafbits_t *leafbits)
131 {
132 int i, leafblocks, count;
133 leafblock_t block;
134
135 count = 0;
136 leafblocks = (leafbits->numleafs + LEAFMASK) >> LEAFSHIFT;
137 for (i = 0; i < leafblocks; i++) {
138 block = leafbits->bits[i];
139 while (block) {
140 count++;
141 block &= (block - 1); /* remove least significant bit */
142 }
143 }
144
145 return count;
146 };
147 #endif
148
149 /*
150 * Simple LRU cache for decompressed vis data
151 */
152 typedef struct {
153 const model_t *model;
154 const mleaf_t *leaf;
155 leafbits_t *leafbits;
156 } pvscache_t;
157 static pvscache_t pvscache[2];
158 static leafbits_t *fatpvs;
159 static int pvscache_numleafs;
160 static int pvscache_bytes;
161 static int pvscache_blocks;
162
163 static int c_cachehit, c_cachemiss;
164
165 #define PVSCACHE_SIZE ARRAY_SIZE(pvscache)
166
167 static void
Mod_InitPVSCache(int numleafs)168 Mod_InitPVSCache(int numleafs)
169 {
170 int i;
171 int memsize;
172 byte *leafmem;
173
174 pvscache_numleafs = numleafs;
175 pvscache_bytes = ((numleafs + LEAFMASK) & ~LEAFMASK) >> 3;
176 pvscache_blocks = pvscache_bytes / sizeof(leafblock_t);
177 memsize = Mod_LeafbitsSize(numleafs);
178 fatpvs = (leafbits_t*)Hunk_AllocName(memsize, "fatpvs");
179
180 memset(pvscache, 0, sizeof(pvscache));
181 leafmem = (byte*)Hunk_AllocName(PVSCACHE_SIZE * memsize, "pvscache");
182 for (i = 0; i < PVSCACHE_SIZE; i++)
183 pvscache[i].leafbits = (leafbits_t *)(leafmem + i * memsize);
184 }
185
186 /*
187 ===================
188 Mod_DecompressVis
189 ===================
190 */
191
192 static void
Mod_DecompressVis(const byte * in,const model_t * model,leafbits_t * dest)193 Mod_DecompressVis(const byte *in, const model_t *model, leafbits_t *dest)
194 {
195 leafblock_t *out;
196 int num_out;
197 int shift;
198 int count;
199
200 dest->numleafs = model->numleafs;
201 out = dest->bits;
202
203 if (!in) {
204 /* no vis info, so make all visible */
205 memset(out, 0xff, pvscache_bytes);
206 return;
207 }
208
209 memset(out, 0, pvscache_bytes);
210 num_out = 0;
211 shift = 0;
212 do {
213 if (*in) {
214 *out |= (leafblock_t)*in++ << shift;
215 shift += 8;
216 num_out += 8;
217 if (shift == (1 << LEAFSHIFT)) {
218 shift = 0;
219 out++;
220 }
221 continue;
222 }
223
224 /* Run of zeros - skip over */
225 count = in[1];
226 in += 2;
227 out += count / sizeof(leafblock_t);
228 shift += (count % sizeof(leafblock_t)) << 3;
229 num_out += count << 3;
230 if (shift >= (1 << LEAFSHIFT)) {
231 shift -= (1 << LEAFSHIFT);
232 out++;
233 }
234 } while (num_out < dest->numleafs);
235 }
236
237 const leafbits_t *
Mod_LeafPVS(const model_t * model,const mleaf_t * leaf)238 Mod_LeafPVS(const model_t *model, const mleaf_t *leaf)
239 {
240 int slot;
241 pvscache_t tmp;
242
243 for (slot = 0; slot < PVSCACHE_SIZE; slot++)
244 if (pvscache[slot].model == model && pvscache[slot].leaf == leaf) {
245 c_cachehit++;
246 break;
247 }
248
249 if (slot) {
250 if (slot == PVSCACHE_SIZE) {
251 slot--;
252 tmp.model = model;
253 tmp.leaf = leaf;
254 tmp.leafbits = pvscache[slot].leafbits;
255 if (leaf == model->leafs) {
256 /* return set with everything visible */
257 tmp.leafbits->numleafs = model->numleafs;
258 memset(tmp.leafbits->bits, 0xff, pvscache_bytes);
259 } else {
260 Mod_DecompressVis(leaf->compressed_vis, model, tmp.leafbits);
261 }
262 c_cachemiss++;
263 } else {
264 tmp = pvscache[slot];
265 }
266 memmove(pvscache + 1, pvscache, slot * sizeof(pvscache_t));
267 pvscache[0] = tmp;
268 }
269
270 return pvscache[0].leafbits;
271 }
272
273 static void
PVSCache_f(void)274 PVSCache_f(void)
275 {
276 Con_Printf("PVSCache: %7d hits %7d misses\n", c_cachehit, c_cachemiss);
277 }
278
Mod_AddToFatPVS(const model_t * model,const vec3_t point,const mnode_t * node)279 static void Mod_AddToFatPVS(const model_t *model, const vec3_t point, const mnode_t *node)
280 {
281 while (1)
282 {
283 float d;
284 mplane_t *plane;
285
286 /* if this is a leaf, accumulate the pvs bits */
287 if (node->contents < 0)
288 {
289 if (node->contents != CONTENTS_SOLID)
290 {
291 const leafbits_t *pvs = Mod_LeafPVS(model, (const mleaf_t *)node);
292 Mod_AddLeafBits(fatpvs, pvs);
293 }
294 return;
295 }
296
297 plane = node->plane;
298 d = DotProduct(point, plane->normal) - plane->dist;
299
300 if (d > 8)
301 node = node->children[0];
302 else if (d < -8)
303 node = node->children[1];
304 else
305 { // go down both
306 Mod_AddToFatPVS(model, point, node->children[0]);
307 node = node->children[1];
308 }
309 }
310 }
311
312 /*
313 =============
314 Mod_FatPVS
315
316 Calculates a PVS that is the inclusive or of all leafs within 8 pixels of the
317 given point.
318
319 The FatPVS must include a small area around the client to allow head bobbing
320 or other small motion on the client side. Otherwise, a bob might cause an
321 entity that should be visible to not show up, especially when the bob
322 crosses a waterline.
323 =============
324 */
325 const leafbits_t *
Mod_FatPVS(const model_t * model,const vec3_t point)326 Mod_FatPVS(const model_t *model, const vec3_t point)
327 {
328 fatpvs->numleafs = model->numleafs;
329 memset(fatpvs->bits, 0, pvscache_bytes);
330 Mod_AddToFatPVS(model, point, model->nodes);
331
332 return fatpvs;
333 }
334
335 /*
336 ===================
337 Mod_ClearAll
338 ===================
339 */
340 void
Mod_ClearAll(void)341 Mod_ClearAll(void)
342 {
343 int i;
344 model_t *mod;
345
346 for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++) {
347 if (mod->type != mod_alias)
348 mod->needload = true;
349 /*
350 * FIXME: sprites use the cache data pointer for their own purposes,
351 * bypassing the Cache_Alloc/Free functions.
352 */
353 if (mod->type == mod_sprite)
354 mod->cache.data = NULL;
355 }
356
357 fatpvs = NULL;
358 memset(pvscache, 0, sizeof(pvscache));
359 pvscache_numleafs = 0;
360 pvscache_bytes = pvscache_blocks = 0;
361 c_cachehit = c_cachemiss = 0;
362 }
363
364 /*
365 ==================
366 Mod_FindName
367
368 ==================
369 */
370 static model_t *
Mod_FindName(const char * name)371 Mod_FindName(const char *name)
372 {
373 int i;
374 model_t *mod;
375
376 if (!name[0])
377 SV_Error("%s: NULL name", __func__);
378
379 //
380 // search the currently loaded models
381 //
382 for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++)
383 if (!strcmp(mod->name, name))
384 break;
385
386 if (i == mod_numknown) {
387 if (mod_numknown == MAX_MOD_KNOWN)
388 SV_Error("mod_numknown == MAX_MOD_KNOWN");
389 strncpy(mod->name, name, MAX_QPATH - 1);
390 mod->name[MAX_QPATH - 1] = 0;
391 mod->needload = true;
392 mod_numknown++;
393 }
394
395 return mod;
396 }
397
398 /*
399 ==================
400 Mod_LoadModel
401
402 Loads a model into the cache
403 ==================
404 */
405 static model_t *
Mod_LoadModel(model_t * mod,qboolean crash)406 Mod_LoadModel(model_t *mod, qboolean crash)
407 {
408 unsigned *buf;
409 byte stackbuf[1024]; // avoid dirtying the cache heap
410 unsigned long size;
411
412 if (!mod->needload) {
413 if (mod->type == mod_alias) {
414 if (Cache_Check(&mod->cache))
415 return mod;
416 } else
417 return mod; // not cached at all
418 }
419 //
420 // load the file
421 //
422 buf = (unsigned int*)COM_LoadStackFile(mod->name, stackbuf, sizeof(stackbuf), &size);
423 if (!buf) {
424 if (crash)
425 SV_Error("%s: %s not found", __func__, mod->name);
426 return NULL;
427 }
428 //
429 // allocate a new model
430 //
431 COM_FileBase(mod->name, loadname, sizeof(loadname));
432
433 loadmodel = mod;
434
435 //
436 // fill it in
437 //
438
439 // call the apropriate loader
440 mod->needload = false;
441
442 switch (LittleLong(*(unsigned *)buf))
443 {
444 #ifndef SERVERONLY
445 case IDPOLYHEADER:
446 Mod_LoadAliasModel(mod_loader, mod, buf, loadmodel, loadname);
447 break;
448
449 case IDSPRITEHEADER:
450 Mod_LoadSpriteModel(mod, buf, loadname);
451 break;
452 #endif
453 default:
454 Mod_LoadBrushModel(mod, buf, size);
455 break;
456 }
457
458 return mod;
459 }
460
461 /*
462 ==================
463 Mod_ForName
464
465 Loads in a model for the given name
466 ==================
467 */
468 model_t *
Mod_ForName(const char * name,qboolean crash)469 Mod_ForName(const char *name, qboolean crash)
470 {
471 model_t *mod;
472
473 mod = Mod_FindName(name);
474
475 return Mod_LoadModel(mod, crash);
476 }
477
478
479 /*
480 ===============================================================================
481
482 BRUSHMODEL LOADING
483
484 ===============================================================================
485 */
486
487 static byte *mod_base;
488
489
490 /*
491 =================
492 Mod_LoadTextures
493 =================
494 */
495 static void
Mod_LoadTextures(lump_t * l)496 Mod_LoadTextures(lump_t *l)
497 {
498 int i, j, pixels, num, max, altmax = 0;
499 miptex_t *mt;
500 texture_t *tx, *tx2;
501 texture_t *anims[10];
502 texture_t *altanims[10];
503 dmiptexlump_t *m;
504
505 if (!l->filelen) {
506 loadmodel->textures = NULL;
507 return;
508 }
509 m = (dmiptexlump_t *)(mod_base + l->fileofs);
510
511 #ifdef MSB_FIRST
512 m->nummiptex = LittleLong(m->nummiptex);
513 #endif
514
515 loadmodel->numtextures = m->nummiptex;
516 loadmodel->textures = (texture_t**)Hunk_AllocName(m->nummiptex * sizeof(*loadmodel->textures), loadname);
517
518 for (i = 0; i < m->nummiptex; i++)
519 {
520 #ifdef MSB_FIRST
521 m->dataofs[i] = LittleLong(m->dataofs[i]);
522 #endif
523 if (m->dataofs[i] == -1)
524 continue;
525 mt = (miptex_t *)((byte *)m + m->dataofs[i]);
526 #ifdef MSB_FIRST
527 mt->width = (uint32_t)LittleLong(mt->width);
528 mt->height = (uint32_t)LittleLong(mt->height);
529 for (j = 0; j < MIPLEVELS; j++)
530 mt->offsets[j] = (uint32_t)LittleLong(mt->offsets[j]);
531 #endif
532
533 if ((mt->width & 15) || (mt->height & 15))
534 SV_Error("Texture %s is not 16 aligned", mt->name);
535 pixels = mt->width * mt->height / 64 * 85;
536 tx = (texture_t*)Hunk_AllocName(sizeof(texture_t) + pixels, loadname);
537 loadmodel->textures[i] = tx;
538
539 memcpy(tx->name, mt->name, sizeof(tx->name));
540 tx->width = mt->width;
541 tx->height = mt->height;
542 for (j = 0; j < MIPLEVELS; j++)
543 tx->offsets[j] =
544 mt->offsets[j] + sizeof(texture_t) - sizeof(miptex_t);
545 // the pixels immediately follow the structures
546 memcpy(tx + 1, mt + 1, pixels);
547
548 #ifndef SERVERONLY
549 if (!strncmp(mt->name, "sky", 3))
550 R_InitSky(tx);
551 #endif
552 }
553
554 //
555 // sequence the animations
556 //
557 for (i = 0; i < m->nummiptex; i++) {
558 tx = loadmodel->textures[i];
559 if (!tx || tx->name[0] != '+')
560 continue;
561 if (tx->anim_next)
562 continue; // allready sequenced
563
564 // find the number of frames in the animation
565 memset(anims, 0, sizeof(anims));
566 memset(altanims, 0, sizeof(altanims));
567
568 max = tx->name[1];
569 if (max >= 'a' && max <= 'z')
570 max -= 'a' - 'A';
571 if (max >= '0' && max <= '9') {
572 max -= '0';
573 altmax = 0;
574 anims[max] = tx;
575 max++;
576 } else if (max >= 'A' && max <= 'J') {
577 altmax = max - 'A';
578 max = 0;
579 altanims[altmax] = tx;
580 altmax++;
581 } else
582 SV_Error("Bad animating texture %s", tx->name);
583
584 for (j = i + 1; j < m->nummiptex; j++) {
585 tx2 = loadmodel->textures[j];
586 if (!tx2 || tx2->name[0] != '+')
587 continue;
588 if (strcmp(tx2->name + 2, tx->name + 2))
589 continue;
590
591 num = tx2->name[1];
592 if (num >= 'a' && num <= 'z')
593 num -= 'a' - 'A';
594 if (num >= '0' && num <= '9') {
595 num -= '0';
596 anims[num] = tx2;
597 if (num + 1 > max)
598 max = num + 1;
599 } else if (num >= 'A' && num <= 'J') {
600 num = num - 'A';
601 altanims[num] = tx2;
602 if (num + 1 > altmax)
603 altmax = num + 1;
604 } else
605 SV_Error("Bad animating texture %s", tx->name);
606 }
607
608 #define ANIM_CYCLE 2
609 // link them all together
610 for (j = 0; j < max; j++) {
611 tx2 = anims[j];
612 if (!tx2)
613 SV_Error("Missing frame %i of %s", j, tx->name);
614 tx2->anim_total = max * ANIM_CYCLE;
615 tx2->anim_min = j * ANIM_CYCLE;
616 tx2->anim_max = (j + 1) * ANIM_CYCLE;
617 tx2->anim_next = anims[(j + 1) % max];
618 if (altmax)
619 tx2->alternate_anims = altanims[0];
620 }
621 for (j = 0; j < altmax; j++) {
622 tx2 = altanims[j];
623 if (!tx2)
624 SV_Error("Missing frame %i of %s", j, tx->name);
625 tx2->anim_total = altmax * ANIM_CYCLE;
626 tx2->anim_min = j * ANIM_CYCLE;
627 tx2->anim_max = (j + 1) * ANIM_CYCLE;
628 tx2->anim_next = altanims[(j + 1) % altmax];
629 if (max)
630 tx2->alternate_anims = anims[0];
631 }
632 }
633 }
634
635 /*
636 =================
637 Mod_LoadLighting
638 =================
639 */
640
641
642 static void
Mod_LoadLighting(lump_t * l)643 Mod_LoadLighting(lump_t *l)
644 {
645 int i;
646 byte *in, *out, *data;
647 byte d;
648 char litname[1024];
649 byte *lightmapfile;
650
651 if (!l->filelen) {
652 loadmodel->lightdata = NULL;
653 return;
654 }
655
656 if (coloredlights) // if colored lights are enabled, look for a lit file to load
657 {
658 strcpy(litname, loadmodel->name);
659 COM_StripExtension(litname);
660 COM_DefaultExtension(litname, ".lit");
661 lightmapfile = COM_LoadHunkFile(litname);
662 if (lightmapfile)
663 {
664 data = lightmapfile;
665 if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
666 {
667 i = LittleLong(((int *)data)[1]);
668 if (i == 1)
669 {
670 loadmodel->lightdata = data + 8;
671 return;
672 }
673 else
674 Con_Printf("Unknown .LIT file version (%d)\n", i);
675 }
676 else
677 Con_Printf("Corrupt .LIT file (old version?), ignoring\n");
678
679 }
680 else
681 {
682 //expand the mono lighting to 24 bit
683 int i;
684 byte *dest, *src = mod_base + l->fileofs;
685 loadmodel->lightdata = Hunk_AllocName ( l->filelen*3, loadname);
686 dest = loadmodel->lightdata;
687 for (i = 0; i<l->filelen; i++)
688 {
689 dest[0] = *src;
690 dest[1] = *src;
691 dest[2] = *src;
692
693 src++;
694 dest+=3;
695
696 }
697
698
699 }
700 }
701 else // mono lights
702 {
703 loadmodel->lightdata = (byte*)Hunk_AllocName(l->filelen, loadname);
704 memcpy(loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
705 }
706 }
707
708
709 /*
710 =================
711 Mod_LoadVisibility
712 =================
713 */
714 static void
Mod_LoadVisibility(lump_t * l)715 Mod_LoadVisibility(lump_t *l)
716 {
717 if (!l->filelen) {
718 loadmodel->visdata = NULL;
719 return;
720 }
721 loadmodel->visdata = (byte*)Hunk_AllocName(l->filelen, loadname);
722 memcpy(loadmodel->visdata, mod_base + l->fileofs, l->filelen);
723 }
724
725
726 /*
727 =================
728 Mod_LoadEntities
729 =================
730 */
731 static void
Mod_LoadEntities(lump_t * l)732 Mod_LoadEntities(lump_t *l)
733 {
734 if (!l->filelen) {
735 loadmodel->entities = NULL;
736 return;
737 }
738 loadmodel->entities = (char*)Hunk_AllocName(l->filelen, loadname);
739 memcpy(loadmodel->entities, mod_base + l->fileofs, l->filelen);
740 }
741
742
743 /*
744 =================
745 Mod_LoadVertexes
746 =================
747 */
748 static void
Mod_LoadVertexes(lump_t * l)749 Mod_LoadVertexes(lump_t *l)
750 {
751 dvertex_t *in;
752 mvertex_t *out;
753 int i, count;
754
755 in = (dvertex_t*)(void *)(mod_base + l->fileofs);
756 if (l->filelen % sizeof(*in))
757 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
758 count = l->filelen / sizeof(*in);
759 out = (mvertex_t*)Hunk_AllocName(count * sizeof(*out), loadname);
760
761 loadmodel->vertexes = out;
762 loadmodel->numvertexes = count;
763
764 for (i = 0; i < count; i++, in++, out++)
765 {
766 #ifdef MSB_FIRST
767 out->position[0] = LittleFloat(in->point[0]);
768 out->position[1] = LittleFloat(in->point[1]);
769 out->position[2] = LittleFloat(in->point[2]);
770 #else
771 out->position[0] = (in->point[0]);
772 out->position[1] = (in->point[1]);
773 out->position[2] = (in->point[2]);
774 #endif
775 }
776 }
777
778 /*
779 =================
780 Mod_LoadSubmodels
781 =================
782 */
783 static void
Mod_LoadSubmodels(lump_t * l)784 Mod_LoadSubmodels(lump_t *l)
785 {
786 dmodel_t *in;
787 dmodel_t *out;
788 int i, j, count;
789
790 in = (dmodel_t*)(void *)(mod_base + l->fileofs);
791 if (l->filelen % sizeof(*in))
792 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
793 count = l->filelen / sizeof(*in);
794 out = (dmodel_t*)Hunk_AllocName(count * sizeof(*out), loadname);
795
796 loadmodel->submodels = out;
797 loadmodel->numsubmodels = count;
798
799 for (i = 0; i < count; i++, in++, out++)
800 {
801 for (j = 0; j < 3; j++)
802 { // spread the mins / maxs by a pixel
803 #ifdef MSB_FIRST
804 out->mins[j] = LittleFloat(in->mins[j]) - 1;
805 out->maxs[j] = LittleFloat(in->maxs[j]) + 1;
806 out->origin[j] = LittleFloat(in->origin[j]);
807 #else
808 out->mins[j] = (in->mins[j]) - 1;
809 out->maxs[j] = (in->maxs[j]) + 1;
810 out->origin[j] = (in->origin[j]);
811 #endif
812 }
813 for (j = 0; j < MAX_MAP_HULLS; j++)
814 {
815 #ifdef MSB_FIRST
816 out->headnode[j] = LittleLong(in->headnode[j]);
817 #else
818 out->headnode[j] = (in->headnode[j]);
819 #endif
820 }
821 #ifdef MSB_FIRST
822 out->visleafs = LittleLong(in->visleafs);
823 out->firstface = LittleLong(in->firstface);
824 out->numfaces = LittleLong(in->numfaces);
825 #else
826 out->visleafs = (in->visleafs);
827 out->firstface = (in->firstface);
828 out->numfaces = (in->numfaces);
829 #endif
830 }
831 }
832
833 /*
834 =================
835 Mod_LoadEdges
836 => Two versions for the different BSP file formats
837 =================
838 */
839 static void
Mod_LoadEdges_BSP29(lump_t * l)840 Mod_LoadEdges_BSP29(lump_t *l)
841 {
842 bsp29_dedge_t *in;
843 medge_t *out;
844 int i, count;
845
846 in = (bsp29_dedge_t *)(mod_base + l->fileofs);
847 if (l->filelen % sizeof(*in))
848 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
849 count = l->filelen / sizeof(*in);
850 out = (medge_t*)Hunk_AllocName((count + 1) * sizeof(*out), loadname);
851
852 loadmodel->edges = out;
853 loadmodel->numedges = count;
854
855 for (i = 0; i < count; i++, in++, out++)
856 {
857 #ifdef MSB_FIRST
858 out->v[0] = (uint16_t)LittleShort(in->v[0]);
859 out->v[1] = (uint16_t)LittleShort(in->v[1]);
860 #else
861 out->v[0] = (uint16_t)(in->v[0]);
862 out->v[1] = (uint16_t)(in->v[1]);
863 #endif
864 }
865 }
866
867 static void
Mod_LoadEdges_BSP2(lump_t * l)868 Mod_LoadEdges_BSP2(lump_t *l)
869 {
870 bsp2_dedge_t *in;
871 medge_t *out;
872 int i, count;
873
874 in = (bsp2_dedge_t *)(mod_base + l->fileofs);
875 if (l->filelen % sizeof(*in))
876 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
877 count = l->filelen / sizeof(*in);
878 out = (medge_t*)Hunk_AllocName((count + 1) * sizeof(*out), loadname);
879
880 loadmodel->edges = out;
881 loadmodel->numedges = count;
882
883 for (i = 0; i < count; i++, in++, out++) {
884 #ifdef MSB_FIRST
885 out->v[0] = (uint32_t)LittleLong(in->v[0]);
886 out->v[1] = (uint32_t)LittleLong(in->v[1]);
887 #else
888 out->v[0] = (uint32_t)(in->v[0]);
889 out->v[1] = (uint32_t)(in->v[1]);
890 #endif
891 }
892 }
893
894 /*
895 =================
896 Mod_LoadTexinfo
897 =================
898 */
Mod_LoadTexinfo(lump_t * l)899 static void Mod_LoadTexinfo(lump_t *l)
900 {
901 texinfo_t *in;
902 mtexinfo_t *out;
903 int i, j, count;
904 int miptex;
905 float len1, len2;
906
907 in = (texinfo_t*)(void *)(mod_base + l->fileofs);
908 if (l->filelen % sizeof(*in))
909 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
910 count = l->filelen / sizeof(*in);
911 out = (mtexinfo_t*)Hunk_AllocName(count * sizeof(*out), loadname);
912
913 loadmodel->texinfo = out;
914 loadmodel->numtexinfo = count;
915
916 for (i = 0; i < count; i++, in++, out++)
917 {
918 for (j = 0; j < 4; j++)
919 {
920 #ifdef MSB_FIRST
921 out->vecs[0][j] = LittleFloat(in->vecs[0][j]);
922 out->vecs[1][j] = LittleFloat(in->vecs[1][j]);
923 #else
924 out->vecs[0][j] = (in->vecs[0][j]);
925 out->vecs[1][j] = (in->vecs[1][j]);
926 #endif
927 }
928 len1 = Length(out->vecs[0]);
929 len2 = Length(out->vecs[1]);
930 len1 = (len1 + len2) / 2;
931 if (len1 < 0.32)
932 out->mipadjust = 4;
933 else if (len1 < 0.49)
934 out->mipadjust = 3;
935 else if (len1 < 0.99)
936 out->mipadjust = 2;
937 else
938 out->mipadjust = 1;
939
940 #ifdef MSB_FIRST
941 miptex = LittleLong(in->miptex);
942 out->flags = LittleLong(in->flags);
943 #else
944 miptex = (in->miptex);
945 out->flags = (in->flags);
946 #endif
947
948 if (!loadmodel->textures) {
949 #ifndef SERVERONLY
950 out->texture = r_notexture_mip; // checkerboard texture
951 #else
952 out->texture = &r_notexture_mip_qwsv; // checkerboard texture
953 #endif
954 out->flags = 0;
955 } else {
956 if (miptex >= loadmodel->numtextures)
957 SV_Error("miptex >= loadmodel->numtextures");
958 out->texture = loadmodel->textures[miptex];
959 if (!out->texture) {
960 #ifndef SERVERONLY
961 out->texture = r_notexture_mip; // texture not found
962 #else
963 out->texture = &r_notexture_mip_qwsv; // texture not found
964 #endif
965 out->flags = 0;
966 }
967 }
968 }
969 }
970
971 /*
972 ================
973 CalcSurfaceExtents
974
975 Fills in s->texturemins[] and s->extents[]
976 ================
977 */
978 static void
CalcSurfaceExtents(msurface_t * s)979 CalcSurfaceExtents(msurface_t *s)
980 {
981 float mins[2], maxs[2], val;
982 int i, j, e;
983 mvertex_t *v;
984 mtexinfo_t *tex;
985 int bmins[2], bmaxs[2];
986
987 mins[0] = mins[1] = FLT_MAX;
988 maxs[0] = maxs[1] = -FLT_MAX;
989
990 tex = s->texinfo;
991
992 for (i = 0; i < s->numedges; i++) {
993 e = loadmodel->surfedges[s->firstedge + i];
994 if (e >= 0)
995 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
996 else
997 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
998
999 /*
1000 * The (long double) casts below are important: The original code was
1001 * written for x87 floating-point which uses 80-bit floats for
1002 * intermediate calculations. But if you compile it without the casts
1003 * for modern x86_64, the compiler will round each intermediate result
1004 * to a 32-bit float, which introduces extra rounding error.
1005 *
1006 * This becomes a problem if the rounding error causes the light
1007 * utilities and the engine to disagree about the lightmap size for
1008 * some surfaces.
1009 *
1010 * Casting to (long double) keeps the intermediate values at at least
1011 * 64 bits of precision, probably 128.
1012 */
1013
1014 for (j = 0; j < 2; j++) {
1015 val =
1016 (long double)v->position[0] * tex->vecs[j][0] +
1017 (long double)v->position[1] * tex->vecs[j][1] +
1018 (long double)v->position[2] * tex->vecs[j][2] +
1019 tex->vecs[j][3];
1020 if (val < mins[j])
1021 mins[j] = val;
1022 if (val > maxs[j])
1023 maxs[j] = val;
1024 }
1025 }
1026
1027 for (i = 0; i < 2; i++) {
1028 bmins[i] = floor(mins[i] / 16);
1029 bmaxs[i] = ceil(maxs[i] / 16);
1030
1031 s->texturemins[i] = bmins[i] * 16;
1032 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
1033 if (!(tex->flags & TEX_SPECIAL) && s->extents[i] > 256)
1034 SV_Error("Bad surface extents");
1035 }
1036 }
1037
1038 static void
CalcSurfaceBounds(msurface_t * surf)1039 CalcSurfaceBounds(msurface_t *surf)
1040 {
1041 int i, j, edgenum;
1042 medge_t *edge;
1043 mvertex_t *v;
1044
1045 surf->mins[0] = surf->mins[1] = surf->mins[2] = FLT_MAX;
1046 surf->maxs[0] = surf->maxs[1] = surf->maxs[2] = -FLT_MAX;
1047
1048 for (i = 0; i < surf->numedges; i++) {
1049 edgenum = loadmodel->surfedges[surf->firstedge + i];
1050 if (edgenum >= 0) {
1051 edge = &loadmodel->edges[edgenum];
1052 v = &loadmodel->vertexes[edge->v[0]];
1053 } else {
1054 edge = &loadmodel->edges[-edgenum];
1055 v = &loadmodel->vertexes[edge->v[1]];
1056 }
1057
1058 for (j = 0; j < 3; j++) {
1059 if (surf->mins[j] > v->position[j])
1060 surf->mins[j] = v->position[j];
1061 if (surf->maxs[j] < v->position[j])
1062 surf->maxs[j] = v->position[j];
1063 }
1064 }
1065 }
1066
1067 /*
1068 =================
1069 Mod_LoadFaces
1070 => Two versions for the different BSP file formats
1071 =================
1072 */
1073 static void
Mod_LoadFaces_BSP29(lump_t * l)1074 Mod_LoadFaces_BSP29(lump_t *l)
1075 {
1076 bsp29_dface_t *in;
1077 msurface_t *out;
1078 int i, count, surfnum;
1079 int planenum, side;
1080
1081 in = (bsp29_dface_t *)(mod_base + l->fileofs);
1082 if (l->filelen % sizeof(*in))
1083 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
1084 count = l->filelen / sizeof(*in);
1085 out = (msurface_t*)Hunk_AllocName(count * sizeof(*out), loadname);
1086
1087 loadmodel->surfaces = out;
1088 loadmodel->numsurfaces = count;
1089
1090 for (surfnum = 0; surfnum < count; surfnum++, in++, out++)
1091 {
1092 #ifdef MSB_FIRST
1093 out->firstedge = LittleLong(in->firstedge);
1094 out->numedges = LittleShort(in->numedges);
1095 #else
1096 out->firstedge = (in->firstedge);
1097 out->numedges = (in->numedges);
1098 #endif
1099 out->flags = 0;
1100
1101 /* FIXME - Also check numedges doesn't overflow edges */
1102 if (out->numedges <= 0)
1103 SV_Error("%s: bmodel %s has surface with no edges", __func__,
1104 loadmodel->name);
1105
1106 #ifdef MSB_FIRST
1107 planenum = LittleShort(in->planenum);
1108 side = LittleShort(in->side);
1109 #else
1110 planenum = (in->planenum);
1111 side = (in->side);
1112 #endif
1113 if (side)
1114 out->flags |= SURF_PLANEBACK;
1115
1116 out->plane = loadmodel->planes + planenum;
1117 #ifdef MSB_FIRST
1118 out->texinfo = loadmodel->texinfo + LittleShort(in->texinfo);
1119 #else
1120 out->texinfo = &loadmodel->texinfo[in->texinfo];
1121 #endif
1122
1123 CalcSurfaceExtents(out);
1124 CalcSurfaceBounds(out);
1125
1126 // lighting info
1127
1128 for (i = 0; i < MAXLIGHTMAPS; i++)
1129 out->styles[i] = in->styles[i];
1130 #ifdef MSB_FIRST
1131 i = LittleLong(in->lightofs);
1132 #else
1133 i = (in->lightofs);
1134 #endif
1135 if (coloredlights)
1136 {
1137 if (i == -1)
1138 out->samples = NULL;
1139 out->samples = loadmodel->lightdata + i * 3;
1140 }
1141 else
1142 {
1143 if (i == -1)
1144 out->samples = NULL;
1145 else
1146 out->samples = loadmodel->lightdata + i;
1147 }
1148
1149 /* set the surface drawing flags */
1150 if (!strncmp(out->texinfo->texture->name, "sky", 3)) {
1151 out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED);
1152 } else if (!strncmp(out->texinfo->texture->name, "*", 1)) {
1153 out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED);
1154 for (i = 0; i < 2; i++) {
1155 out->extents[i] = 16384;
1156 out->texturemins[i] = -8192;
1157 }
1158 }
1159 }
1160 }
1161
Mod_LoadFaces_BSP2(lump_t * l)1162 static void Mod_LoadFaces_BSP2(lump_t *l)
1163 {
1164 msurface_t *out;
1165 int i, count, surfnum;
1166 int planenum, side;
1167 bsp2_dface_t *in = (bsp2_dface_t *)(mod_base + l->fileofs);
1168
1169 if (l->filelen % sizeof(*in))
1170 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
1171
1172 count = l->filelen / sizeof(*in);
1173 out = (msurface_t*)Hunk_AllocName(count * sizeof(*out), loadname);
1174
1175 loadmodel->surfaces = out;
1176 loadmodel->numsurfaces = count;
1177
1178 for (surfnum = 0; surfnum < count; surfnum++, in++, out++)
1179 {
1180 #ifdef MSB_FIRST
1181 out->firstedge = LittleLong(in->firstedge);
1182 out->numedges = LittleLong(in->numedges);
1183 #else
1184 out->firstedge = (in->firstedge);
1185 out->numedges = (in->numedges);
1186 #endif
1187 out->flags = 0;
1188
1189 #ifdef MSB_FIRST
1190 planenum = LittleLong(in->planenum);
1191 side = LittleLong(in->side);
1192 #else
1193 planenum = (in->planenum);
1194 side = (in->side);
1195 #endif
1196 if (side)
1197 out->flags |= SURF_PLANEBACK;
1198
1199 out->plane = loadmodel->planes + planenum;
1200 #ifdef MSB_FIRST
1201 out->texinfo = loadmodel->texinfo + LittleLong(in->texinfo);
1202 #else
1203 out->texinfo = &loadmodel->texinfo[in->texinfo];
1204 #endif
1205
1206 CalcSurfaceExtents(out);
1207 CalcSurfaceBounds(out);
1208
1209 // lighting info
1210
1211 for (i = 0; i < MAXLIGHTMAPS; i++)
1212 out->styles[i] = in->styles[i];
1213 #ifdef MSB_FIRST
1214 i = LittleLong(in->lightofs);
1215 #else
1216 i = (in->lightofs);
1217 #endif
1218 if (i == -1)
1219 out->samples = NULL;
1220 else
1221 out->samples = loadmodel->lightdata + i;
1222
1223 /* set the surface drawing flags */
1224 if (!strncmp(out->texinfo->texture->name, "sky", 3))
1225 out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED);
1226 else if (!strncmp(out->texinfo->texture->name, "*", 1))
1227 {
1228 out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED);
1229 for (i = 0; i < 2; i++)
1230 {
1231 out->extents[i] = 16384;
1232 out->texturemins[i] = -8192;
1233 }
1234 }
1235 }
1236 }
1237
1238 /*
1239 =================
1240 Mod_SetParent
1241 =================
1242 */
1243 static void
Mod_SetParent(mnode_t * node,mnode_t * parent)1244 Mod_SetParent(mnode_t *node, mnode_t *parent)
1245 {
1246 node->parent = parent;
1247 if (node->contents < 0)
1248 return;
1249 Mod_SetParent(node->children[0], node);
1250 Mod_SetParent(node->children[1], node);
1251 }
1252
1253 /*
1254 =================
1255 Mod_LoadNodes
1256 => Two versions for the different BSP file formats
1257 =================
1258 */
1259 static void
Mod_LoadNodes_BSP29(lump_t * l)1260 Mod_LoadNodes_BSP29(lump_t *l)
1261 {
1262 int i, j, count, p;
1263 bsp29_dnode_t *in;
1264 mnode_t *out;
1265
1266 in = (bsp29_dnode_t *)(mod_base + l->fileofs);
1267 if (l->filelen % sizeof(*in))
1268 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
1269 count = l->filelen / sizeof(*in);
1270 out = (mnode_t*)Hunk_AllocName(count * sizeof(*out), loadname);
1271
1272 loadmodel->nodes = out;
1273 loadmodel->numnodes = count;
1274
1275 for (i = 0; i < count; i++, in++, out++) {
1276 for (j = 0; j < 3; j++) {
1277 #ifdef MSB_FIRST
1278 out->mins[j] = LittleShort(in->mins[j]);
1279 out->maxs[j] = LittleShort(in->maxs[j]);
1280 #else
1281 out->mins[j] = (in->mins[j]);
1282 out->maxs[j] = (in->maxs[j]);
1283 #endif
1284 }
1285
1286 #ifdef MSB_FIRST
1287 p = LittleLong(in->planenum);
1288 #else
1289 p = (in->planenum);
1290 #endif
1291 out->plane = loadmodel->planes + p;
1292
1293 #ifdef MSB_FIRST
1294 out->firstsurface = (uint16_t)LittleShort(in->firstface);
1295 out->numsurfaces = (uint16_t)LittleShort(in->numfaces);
1296 #else
1297 out->firstsurface = (uint16_t)(in->firstface);
1298 out->numsurfaces = (uint16_t)(in->numfaces);
1299 #endif
1300
1301 for (j = 0; j < 2; j++)
1302 {
1303 #ifdef MSB_FIRST
1304 p = LittleShort(in->children[j]);
1305 #else
1306 p = (in->children[j]);
1307 #endif
1308 if (p >= 0)
1309 out->children[j] = loadmodel->nodes + p;
1310 else
1311 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1312 }
1313 }
1314
1315 Mod_SetParent(loadmodel->nodes, NULL); // sets nodes and leafs
1316 }
1317
Mod_LoadNodes_BSP2(lump_t * l)1318 static void Mod_LoadNodes_BSP2(lump_t *l)
1319 {
1320 int i, count;
1321 mnode_t *out;
1322 bsp2_dnode_t *in = (bsp2_dnode_t *)(mod_base + l->fileofs);
1323
1324 if (l->filelen % sizeof(*in))
1325 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
1326
1327 count = l->filelen / sizeof(*in);
1328 out = (mnode_t*)Hunk_AllocName(count * sizeof(*out), loadname);
1329
1330 loadmodel->nodes = out;
1331 loadmodel->numnodes = count;
1332
1333 for (i = 0; i < count; i++, in++, out++)
1334 {
1335 int j, p;
1336
1337 for (j = 0; j < 3; j++)
1338 {
1339 #ifdef MSB_FIRST
1340 out->mins[j] = LittleShort(in->mins[j]);
1341 out->maxs[j] = LittleShort(in->maxs[j]);
1342 #else
1343 out->mins[j] = (in->mins[j]);
1344 out->maxs[j] = (in->maxs[j]);
1345 #endif
1346 }
1347
1348 #ifdef MSB_FIRST
1349 p = LittleLong(in->planenum);
1350 #else
1351 p = (in->planenum);
1352 #endif
1353 out->plane = loadmodel->planes + p;
1354
1355 #ifdef MSB_FIRST
1356 out->firstsurface = (uint32_t)LittleLong(in->firstface);
1357 out->numsurfaces = (uint32_t)LittleLong(in->numfaces);
1358 #else
1359 out->firstsurface = (uint32_t)(in->firstface);
1360 out->numsurfaces = (uint32_t)(in->numfaces);
1361 #endif
1362
1363 for (j = 0; j < 2; j++)
1364 {
1365 #ifdef MSB_FIRST
1366 p = LittleLong(in->children[j]);
1367 #else
1368 p = (in->children[j]);
1369 #endif
1370 if (p >= 0)
1371 out->children[j] = loadmodel->nodes + p;
1372 else
1373 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1374 }
1375 }
1376
1377 Mod_SetParent(loadmodel->nodes, NULL); // sets nodes and leafs
1378 }
1379
1380 /*
1381 =================
1382 Mod_LoadLeafs
1383 => Two versions for the different BSP file formats
1384 =================
1385 */
1386 static void
Mod_LoadLeafs_BSP29(lump_t * l)1387 Mod_LoadLeafs_BSP29(lump_t *l)
1388 {
1389 bsp29_dleaf_t *in;
1390 mleaf_t *out;
1391 int i, j, count, p;
1392
1393 in = (bsp29_dleaf_t *)(mod_base + l->fileofs);
1394 if (l->filelen % sizeof(*in))
1395 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
1396 count = l->filelen / sizeof(*in);
1397 out = (mleaf_t*)Hunk_AllocName(count * sizeof(*out), loadname);
1398
1399 loadmodel->leafs = out;
1400 loadmodel->numleafs = count;
1401
1402 for (i = 0; i < count; i++, in++, out++)
1403 {
1404 for (j = 0; j < 3; j++)
1405 {
1406 #ifdef MSB_FIRST
1407 out->mins[j] = LittleShort(in->mins[j]);
1408 out->maxs[j] = LittleShort(in->maxs[j]);
1409 #else
1410 out->mins[j] = (in->mins[j]);
1411 out->maxs[j] = (in->maxs[j]);
1412 #endif
1413 }
1414
1415 #ifdef MSB_FIRST
1416 p = LittleLong(in->contents);
1417 #else
1418 p = (in->contents);
1419 #endif
1420 out->contents = p;
1421
1422 #ifdef MSB_FIRST
1423 out->firstmarksurface = loadmodel->marksurfaces +
1424 (uint16_t)LittleShort(in->firstmarksurface);
1425 out->nummarksurfaces = (uint16_t)LittleShort(in->nummarksurfaces);
1426
1427 p = LittleLong(in->visofs);
1428 #else
1429 out->firstmarksurface = &loadmodel->marksurfaces[in->firstmarksurface];
1430 out->nummarksurfaces = (uint16_t)(in->nummarksurfaces);
1431
1432 p = (in->visofs);
1433 #endif
1434 if (p == -1)
1435 out->compressed_vis = NULL;
1436 else
1437 out->compressed_vis = loadmodel->visdata + p;
1438 out->efrags = NULL;
1439
1440 for (j = 0; j < 4; j++)
1441 out->ambient_sound_level[j] = in->ambient_level[j];
1442 }
1443 }
1444
1445 static void
Mod_LoadLeafs_BSP2(lump_t * l)1446 Mod_LoadLeafs_BSP2(lump_t *l)
1447 {
1448 bsp2_dleaf_t *in;
1449 mleaf_t *out;
1450 int i, j, count, p;
1451
1452 in = (bsp2_dleaf_t *)(mod_base + l->fileofs);
1453 if (l->filelen % sizeof(*in))
1454 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
1455 count = l->filelen / sizeof(*in);
1456 out = (mleaf_t*)Hunk_AllocName(count * sizeof(*out), loadname);
1457
1458 loadmodel->leafs = out;
1459 loadmodel->numleafs = count;
1460
1461 for (i = 0; i < count; i++, in++, out++) {
1462 for (j = 0; j < 3; j++) {
1463 #ifdef MSB_FIRST
1464 out->mins[j] = LittleShort(in->mins[j]);
1465 out->maxs[j] = LittleShort(in->maxs[j]);
1466 #else
1467 out->mins[j] = (in->mins[j]);
1468 out->maxs[j] = (in->maxs[j]);
1469 #endif
1470 }
1471
1472 #ifdef MSB_FIRST
1473 p = LittleLong(in->contents);
1474 #else
1475 p = (in->contents);
1476 #endif
1477 out->contents = p;
1478
1479 #ifdef MSB_FIRST
1480 out->firstmarksurface = loadmodel->marksurfaces +
1481 (uint32_t)LittleLong(in->firstmarksurface);
1482 out->nummarksurfaces = (uint32_t)LittleLong(in->nummarksurfaces);
1483
1484 p = LittleLong(in->visofs);
1485 #else
1486 out->firstmarksurface = &loadmodel->marksurfaces[in->firstmarksurface];
1487 out->nummarksurfaces = (uint32_t)(in->nummarksurfaces);
1488
1489 p = (in->visofs);
1490 #endif
1491
1492 if (p == -1)
1493 out->compressed_vis = NULL;
1494 else
1495 out->compressed_vis = loadmodel->visdata + p;
1496 out->efrags = NULL;
1497
1498 for (j = 0; j < 4; j++)
1499 out->ambient_sound_level[j] = in->ambient_level[j];
1500 }
1501 }
1502
1503 /*
1504 =================
1505 Mod_LoadClipnodes
1506 => Two versions for the different BSP file formats
1507 =================
1508 */
1509 static void
Mod_LoadClipnodes_BSP29(lump_t * l)1510 Mod_LoadClipnodes_BSP29(lump_t *l)
1511 {
1512 bsp29_dclipnode_t *in;
1513 mclipnode_t *out;
1514 int i, j, count;
1515 hull_t *hull;
1516
1517 in = (bsp29_dclipnode_t *)(mod_base + l->fileofs);
1518 if (l->filelen % sizeof(*in))
1519 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
1520 count = l->filelen / sizeof(*in);
1521 out = (mclipnode_t*)Hunk_AllocName(count * sizeof(*out), loadname);
1522
1523 loadmodel->clipnodes = out;
1524 loadmodel->numclipnodes = count;
1525
1526 hull = &loadmodel->hulls[1];
1527 hull->clipnodes = out;
1528 hull->firstclipnode = 0;
1529 hull->lastclipnode = count - 1;
1530 hull->planes = loadmodel->planes;
1531 hull->clip_mins[0] = -16;
1532 hull->clip_mins[1] = -16;
1533 hull->clip_mins[2] = -24;
1534 hull->clip_maxs[0] = 16;
1535 hull->clip_maxs[1] = 16;
1536 hull->clip_maxs[2] = 32;
1537
1538 hull = &loadmodel->hulls[2];
1539 hull->clipnodes = out;
1540 hull->firstclipnode = 0;
1541 hull->lastclipnode = count - 1;
1542 hull->planes = loadmodel->planes;
1543 hull->clip_mins[0] = -32;
1544 hull->clip_mins[1] = -32;
1545 hull->clip_mins[2] = -24;
1546 hull->clip_maxs[0] = 32;
1547 hull->clip_maxs[1] = 32;
1548 hull->clip_maxs[2] = 64;
1549
1550 for (i = 0; i < count; i++, out++, in++)
1551 {
1552 #ifdef MSB_FIRST
1553 out->planenum = LittleLong(in->planenum);
1554 #else
1555 out->planenum = (in->planenum);
1556 #endif
1557 for (j = 0; j < 2; j++) {
1558 #ifdef MSB_FIRST
1559 out->children[j] = (uint16_t)LittleShort(in->children[j]);
1560 #else
1561 out->children[j] = (uint16_t)(in->children[j]);
1562 #endif
1563 if (out->children[j] > 0xfff0)
1564 out->children[j] -= 0x10000;
1565 if (out->children[j] >= count)
1566 SV_Error("%s: bad clipnode child number", __func__);
1567 }
1568 }
1569 }
1570
1571 static void
Mod_LoadClipnodes_BSP2(lump_t * l)1572 Mod_LoadClipnodes_BSP2(lump_t *l)
1573 {
1574 bsp2_dclipnode_t *in;
1575 mclipnode_t *out;
1576 int i, j, count;
1577 hull_t *hull;
1578
1579 in = (bsp2_dclipnode_t *)(mod_base + l->fileofs);
1580 if (l->filelen % sizeof(*in))
1581 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
1582 count = l->filelen / sizeof(*in);
1583 out = (mclipnode_t*)Hunk_AllocName(count * sizeof(*out), loadname);
1584
1585 loadmodel->clipnodes = out;
1586 loadmodel->numclipnodes = count;
1587
1588 hull = &loadmodel->hulls[1];
1589 hull->clipnodes = out;
1590 hull->firstclipnode = 0;
1591 hull->lastclipnode = count - 1;
1592 hull->planes = loadmodel->planes;
1593 hull->clip_mins[0] = -16;
1594 hull->clip_mins[1] = -16;
1595 hull->clip_mins[2] = -24;
1596 hull->clip_maxs[0] = 16;
1597 hull->clip_maxs[1] = 16;
1598 hull->clip_maxs[2] = 32;
1599
1600 hull = &loadmodel->hulls[2];
1601 hull->clipnodes = out;
1602 hull->firstclipnode = 0;
1603 hull->lastclipnode = count - 1;
1604 hull->planes = loadmodel->planes;
1605 hull->clip_mins[0] = -32;
1606 hull->clip_mins[1] = -32;
1607 hull->clip_mins[2] = -24;
1608 hull->clip_maxs[0] = 32;
1609 hull->clip_maxs[1] = 32;
1610 hull->clip_maxs[2] = 64;
1611
1612 for (i = 0; i < count; i++, out++, in++) {
1613 #ifdef MSB_FIRST
1614 out->planenum = LittleLong(in->planenum);
1615 #else
1616 out->planenum = (in->planenum);
1617 #endif
1618 for (j = 0; j < 2; j++) {
1619 #ifdef MSB_FIRST
1620 out->children[j] = LittleLong(in->children[j]);
1621 #else
1622 out->children[j] = (in->children[j]);
1623 #endif
1624 if (out->children[j] >= count)
1625 SV_Error("%s: bad clipnode child number", __func__);
1626 }
1627 }
1628 }
1629
1630 /*
1631 =================
1632 Mod_MakeHull0
1633
1634 Duplicate the drawing hull structure as a clipping hull
1635 =================
1636 */
1637 static void
Mod_MakeHull0(void)1638 Mod_MakeHull0(void)
1639 {
1640 mnode_t *in, *child;
1641 mclipnode_t *out;
1642 int i, j, count;
1643 hull_t *hull;
1644
1645 hull = &loadmodel->hulls[0];
1646
1647 in = loadmodel->nodes;
1648 count = loadmodel->numnodes;
1649 out = (mclipnode_t*)Hunk_AllocName(count * sizeof(*out), loadname);
1650
1651 hull->clipnodes = out;
1652 hull->firstclipnode = 0;
1653 hull->lastclipnode = count - 1;
1654 hull->planes = loadmodel->planes;
1655
1656 for (i = 0; i < count; i++, out++, in++) {
1657 out->planenum = in->plane - loadmodel->planes;
1658 for (j = 0; j < 2; j++) {
1659 child = in->children[j];
1660 if (child->contents < 0)
1661 out->children[j] = child->contents;
1662 else
1663 out->children[j] = child - loadmodel->nodes;
1664 }
1665 }
1666 }
1667
1668 /*
1669 =================
1670 Mod_LoadMarksurfaces
1671 => Two versions for the different BSP file formats
1672 =================
1673 */
1674 static void
Mod_LoadMarksurfaces_BSP29(lump_t * l)1675 Mod_LoadMarksurfaces_BSP29(lump_t *l)
1676 {
1677 int i, j, count;
1678 uint16_t *in;
1679 msurface_t **out;
1680
1681 in = (uint16_t *)(mod_base + l->fileofs);
1682 if (l->filelen % sizeof(*in))
1683 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
1684 count = l->filelen / sizeof(*in);
1685 out = (msurface_t**)Hunk_AllocName(count * sizeof(*out), loadname);
1686
1687 loadmodel->marksurfaces = out;
1688 loadmodel->nummarksurfaces = count;
1689
1690 for (i = 0; i < count; i++)
1691 {
1692 #ifdef MSB_FIRST
1693 j = (uint16_t)LittleShort(in[i]);
1694 #else
1695 j = (uint16_t)(in[i]);
1696 #endif
1697 if (j >= loadmodel->numsurfaces)
1698 SV_Error("%s: bad surface number", __func__);
1699 out[i] = loadmodel->surfaces + j;
1700 }
1701 }
1702
1703 static void
Mod_LoadMarksurfaces_BSP2(lump_t * l)1704 Mod_LoadMarksurfaces_BSP2(lump_t *l)
1705 {
1706 int i, j, count;
1707 uint32_t *in;
1708 msurface_t **out;
1709
1710 in = (uint32_t *)(mod_base + l->fileofs);
1711 if (l->filelen % sizeof(*in))
1712 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
1713 count = l->filelen / sizeof(*in);
1714 out = (msurface_t**)Hunk_AllocName(count * sizeof(*out), loadname);
1715
1716 loadmodel->marksurfaces = out;
1717 loadmodel->nummarksurfaces = count;
1718
1719 for (i = 0; i < count; i++) {
1720 #ifdef MSB_FIRST
1721 j = (uint32_t)LittleLong(in[i]);
1722 #else
1723 j = (uint32_t)(in[i]);
1724 #endif
1725 if (j >= loadmodel->numsurfaces)
1726 SV_Error("%s: bad surface number", __func__);
1727 out[i] = loadmodel->surfaces + j;
1728 }
1729 }
1730
1731 /*
1732 =================
1733 Mod_LoadSurfedges
1734 =================
1735 */
1736 static void
Mod_LoadSurfedges(lump_t * l)1737 Mod_LoadSurfedges(lump_t *l)
1738 {
1739 int i, count;
1740 int *in, *out;
1741
1742 in = (int*)(void *)(mod_base + l->fileofs);
1743 if (l->filelen % sizeof(*in))
1744 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
1745 count = l->filelen / sizeof(*in);
1746 out = (int*)Hunk_AllocName(count * sizeof(*out), loadname);
1747
1748 loadmodel->surfedges = out;
1749 loadmodel->numsurfedges = count;
1750
1751 for (i = 0; i < count; i++)
1752 #ifdef MSB_FIRST
1753 out[i] = LittleLong(in[i]);
1754 #else
1755 out[i] = (in[i]);
1756 #endif
1757 }
1758
1759 /*
1760 =================
1761 Mod_LoadPlanes
1762 =================
1763 */
Mod_LoadPlanes(lump_t * l)1764 static void Mod_LoadPlanes(lump_t *l)
1765 {
1766 int i, j, count;
1767 mplane_t *out;
1768 dplane_t *in = (dplane_t*)(void *)(mod_base + l->fileofs);
1769
1770 if (l->filelen % sizeof(*in))
1771 SV_Error("%s: funny lump size in %s", __func__, loadmodel->name);
1772
1773 count = l->filelen / sizeof(*in);
1774 out = (mplane_t*)
1775 Hunk_AllocName(count * 2 * sizeof(*out), loadname);
1776
1777 loadmodel->planes = out;
1778 loadmodel->numplanes = count;
1779
1780 for (i = 0; i < count; i++, in++, out++)
1781 {
1782 int bits = 0;
1783 for (j = 0; j < 3; j++)
1784 {
1785 #ifdef MSB_FIRST
1786 out->normal[j] = LittleFloat(in->normal[j]);
1787 #else
1788 out->normal[j] = (in->normal[j]);
1789 #endif
1790 if (out->normal[j] < 0)
1791 bits |= 1 << j;
1792 }
1793
1794 #ifdef MSB_FIRST
1795 out->dist = LittleFloat(in->dist);
1796 out->type = LittleLong(in->type);
1797 #else
1798 out->dist = (in->dist);
1799 out->type = (in->type);
1800 #endif
1801 out->signbits = bits;
1802 }
1803 }
1804
1805 /*
1806 =================
1807 RadiusFromBounds
1808 =================
1809 */
RadiusFromBounds(vec3_t mins,vec3_t maxs)1810 static float RadiusFromBounds(vec3_t mins, vec3_t maxs)
1811 {
1812 int i;
1813 vec3_t corner;
1814
1815 for (i = 0; i < 3; i++)
1816 corner[i] = qmax(fabs(mins[i]), fabs(maxs[i]));
1817
1818 return Length(corner);
1819 }
1820
1821 /*
1822 =================
1823 Mod_LoadBrushModel
1824 =================
1825 */
Mod_LoadBrushModel(model_t * mod,void * buffer,unsigned long size)1826 static void Mod_LoadBrushModel(model_t *mod, void *buffer, unsigned long size)
1827 {
1828 int i, j;
1829 dheader_t *header;
1830 dmodel_t *bm;
1831
1832 loadmodel->type = mod_brush;
1833 header = (dheader_t *)buffer;
1834
1835 #ifdef MSB_FIRST
1836 /* swap all the header entries */
1837 header->version = LittleLong(header->version);
1838 for (i = 0; i < HEADER_LUMPS; i++) {
1839 header->lumps[i].fileofs = LittleLong(header->lumps[i].fileofs);
1840 header->lumps[i].filelen = LittleLong(header->lumps[i].filelen);
1841 }
1842 #endif
1843
1844 if (header->version != BSPVERSION && header->version != BSP2VERSION)
1845 SV_Error("%s: %s has wrong version number (%i should be %i or %i)",
1846 __func__, mod->name, header->version, BSPVERSION, BSP2VERSION);
1847
1848 mod_base = (byte *)header;
1849
1850 /*
1851 * Check the lump extents
1852 * FIXME - do this more generally... cleanly...?
1853 */
1854 for (i = 0; i < HEADER_LUMPS; ++i)
1855 {
1856 int b1 = header->lumps[i].fileofs;
1857 int e1 = b1 + header->lumps[i].filelen;
1858
1859 /*
1860 * Sanity checks
1861 * - begin and end >= 0 (end might overflow).
1862 * - end > begin (again, overflow reqd.)
1863 * - end < size of file.
1864 */
1865 if (b1 > e1 || e1 > size || b1 < 0 || e1 < 0)
1866 SV_Error("%s: bad lump extents in %s", __func__,
1867 loadmodel->name);
1868
1869 /* Now, check that it doesn't overlap any other lumps */
1870 for (j = 0; j < HEADER_LUMPS; ++j)
1871 {
1872 int b2 = header->lumps[j].fileofs;
1873 int e2 = b2 + header->lumps[j].filelen;
1874
1875 if ((b1 < b2 && e1 > b2) || (b2 < b1 && e2 > b1))
1876 SV_Error("%s: overlapping lumps in %s", __func__,
1877 loadmodel->name);
1878 }
1879 }
1880
1881 #ifdef QW_HACK
1882 mod->checksum = 0;
1883 mod->checksum2 = 0;
1884
1885 // checksum all of the map, except for entities
1886 for (i = 0; i < HEADER_LUMPS; i++) {
1887 const lump_t *l = &header->lumps[i];
1888 unsigned int checksum;
1889
1890 if (i == LUMP_ENTITIES)
1891 continue;
1892 checksum = Com_BlockChecksum(mod_base + l->fileofs, l->filelen);
1893 mod->checksum ^= checksum;
1894 if (i == LUMP_VISIBILITY || i == LUMP_LEAFS || i == LUMP_NODES)
1895 continue;
1896 mod->checksum2 ^= checksum;
1897 }
1898 #ifdef MSB_FIRST
1899 mod->checksum = LittleLong(mod->checksum);
1900 mod->checksum2 = LittleLong(mod->checksum2);
1901 #endif
1902 #endif
1903
1904 /* load into heap */
1905 Mod_LoadVertexes(&header->lumps[LUMP_VERTEXES]);
1906 if (header->version == BSPVERSION)
1907 Mod_LoadEdges_BSP29(&header->lumps[LUMP_EDGES]);
1908 else
1909 Mod_LoadEdges_BSP2(&header->lumps[LUMP_EDGES]);
1910 Mod_LoadSurfedges(&header->lumps[LUMP_SURFEDGES]);
1911 Mod_LoadTextures(&header->lumps[LUMP_TEXTURES]);
1912 Mod_LoadLighting(&header->lumps[LUMP_LIGHTING]);
1913 Mod_LoadPlanes(&header->lumps[LUMP_PLANES]);
1914 Mod_LoadTexinfo(&header->lumps[LUMP_TEXINFO]);
1915 if (header->version == BSPVERSION) {
1916 Mod_LoadFaces_BSP29(&header->lumps[LUMP_FACES]);
1917 Mod_LoadMarksurfaces_BSP29(&header->lumps[LUMP_MARKSURFACES]);
1918 } else {
1919 Mod_LoadFaces_BSP2(&header->lumps[LUMP_FACES]);
1920 Mod_LoadMarksurfaces_BSP2(&header->lumps[LUMP_MARKSURFACES]);
1921 }
1922 Mod_LoadVisibility(&header->lumps[LUMP_VISIBILITY]);
1923 if (header->version == BSPVERSION) {
1924 Mod_LoadLeafs_BSP29(&header->lumps[LUMP_LEAFS]);
1925 Mod_LoadNodes_BSP29(&header->lumps[LUMP_NODES]);
1926 Mod_LoadClipnodes_BSP29(&header->lumps[LUMP_CLIPNODES]);
1927 } else {
1928 Mod_LoadLeafs_BSP2(&header->lumps[LUMP_LEAFS]);
1929 Mod_LoadNodes_BSP2(&header->lumps[LUMP_NODES]);
1930 Mod_LoadClipnodes_BSP2(&header->lumps[LUMP_CLIPNODES]);
1931 }
1932 Mod_LoadEntities(&header->lumps[LUMP_ENTITIES]);
1933 Mod_LoadSubmodels(&header->lumps[LUMP_MODELS]);
1934
1935 Mod_MakeHull0();
1936
1937 mod->numframes = 2; // regular and alternate animation
1938 mod->flags = 0;
1939
1940 /*
1941 * Create space for the decompressed vis data
1942 * - We assume the main map is the first BSP file loaded (should be)
1943 * - If any other model has more leafs, then we may be in trouble...
1944 */
1945 if (mod->numleafs > pvscache_numleafs) {
1946 if (pvscache[0].leafbits)
1947 SV_Error("%s: %d allocated for visdata, but model %s has %d leafs",
1948 __func__, pvscache_numleafs, loadmodel->name, mod->numleafs);
1949 Mod_InitPVSCache(mod->numleafs);
1950 }
1951
1952 //
1953 // set up the submodels (FIXME: this is confusing)
1954 //
1955 for (i = 0; i < mod->numsubmodels; i++) {
1956 bm = &mod->submodels[i];
1957
1958 mod->hulls[0].firstclipnode = bm->headnode[0];
1959 for (j = 1; j < MAX_MAP_HULLS; j++) {
1960 mod->hulls[j].firstclipnode = bm->headnode[j];
1961 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
1962 }
1963
1964 mod->firstmodelsurface = bm->firstface;
1965 mod->nummodelsurfaces = bm->numfaces;
1966
1967 VectorCopy(bm->maxs, mod->maxs);
1968 VectorCopy(bm->mins, mod->mins);
1969
1970 mod->radius = RadiusFromBounds(mod->mins, mod->maxs);
1971 mod->numleafs = bm->visleafs;
1972
1973 /* duplicate the basic information */
1974 if (i < mod->numsubmodels - 1) {
1975 char name[10];
1976
1977 snprintf(name, sizeof(name), "*%i", i + 1);
1978 loadmodel = Mod_FindName(name);
1979 *loadmodel = *mod;
1980 strcpy(loadmodel->name, name);
1981 mod = loadmodel;
1982 }
1983 }
1984 }
1985
1986 /*
1987 * =========================================================================
1988 * CLIENT ONLY FUNCTIONS
1989 * =========================================================================
1990 */
1991 #ifndef SERVERONLY
1992
1993 /*
1994 ===============
1995 Mod_Extradata
1996
1997 Caches the data if needed
1998 ===============
1999 */
Mod_Extradata(model_t * mod)2000 void *Mod_Extradata(model_t *mod)
2001 {
2002 void *r = Cache_Check(&mod->cache);
2003 if (r)
2004 return r;
2005
2006 Mod_LoadModel(mod, true);
2007
2008 if (!mod->cache.data)
2009 Sys_Error("%s: caching failed", __func__);
2010 return mod->cache.data;
2011 }
2012
2013 /*
2014 ================
2015 Mod_Print
2016 ================
2017 */
Mod_Print(void)2018 void Mod_Print(void)
2019 {
2020 int i;
2021 model_t *mod;
2022
2023 Con_Printf("Cached models:\n");
2024 for (i = 0, mod = mod_known; i < mod_numknown; i++, mod++)
2025 Con_Printf("%*p : %s\n", (int)sizeof(void *) * 2 + 2,
2026 mod->cache.data, mod->name);
2027 }
2028
2029 /*
2030 ==================
2031 Mod_TouchModel
2032
2033 ==================
2034 */
Mod_TouchModel(char * name)2035 void Mod_TouchModel(char *name)
2036 {
2037 model_t *mod = Mod_FindName(name);
2038
2039 if (!mod->needload)
2040 {
2041 if (mod->type == mod_alias)
2042 Cache_Check(&mod->cache);
2043 }
2044 }
2045
2046 #endif /* !SERVERONLY */
2047