optimized AngleVectors calls (pass NULL for vectors that should not be generated)
[divverent/darkplaces.git] / model_brush.c
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
21 #include "quakedef.h"
22
23 byte    mod_novis[MAX_MAP_LEAFS/8];
24
25 qboolean        hlbsp; // LordHavoc: true if it is a HalfLife BSP file (version 30)
26
27 cvar_t gl_subdivide_size = {"gl_subdivide_size", "128", true};
28 cvar_t halflifebsp = {"halflifebsp", "0"};
29
30 /*
31 ===============
32 Mod_BrushInit
33 ===============
34 */
35 void Mod_BrushInit (void)
36 {
37         Cvar_RegisterVariable (&gl_subdivide_size);
38         Cvar_RegisterVariable (&halflifebsp);
39         memset (mod_novis, 0xff, sizeof(mod_novis));
40 }
41
42 /*
43 ===============
44 Mod_PointInLeaf
45 ===============
46 */
47 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
48 {
49         mnode_t         *node;
50         
51 //      if (!model || !model->nodes)
52 //              Sys_Error ("Mod_PointInLeaf: bad model");
53
54         node = model->nodes;
55         if (node->contents < 0)
56                 return (mleaf_t *)node;
57         while (1)
58         {
59                 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
60                 if (node->contents < 0)
61                         return (mleaf_t *)node;
62         }
63         
64         return NULL;    // never reached
65 }
66 /*
67 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
68 {
69         mnode_t         *node;
70         float           d;
71         mplane_t        *plane;
72         
73         if (!model || !model->nodes)
74                 Sys_Error ("Mod_PointInLeaf: bad model");
75
76         node = model->nodes;
77         while (1)
78         {
79                 if (node->contents < 0)
80                         return (mleaf_t *)node;
81                 plane = node->plane;
82                 d = DotProduct (p,plane->normal) - plane->dist;
83                 if (d > 0)
84                         node = node->children[0];
85                 else
86                         node = node->children[1];
87         }
88         
89         return NULL;    // never reached
90 }
91 */
92
93 /*
94 ===================
95 Mod_DecompressVis
96 ===================
97 */
98 byte *Mod_DecompressVis (byte *in, model_t *model)
99 {
100         static byte     decompressed[MAX_MAP_LEAFS/8];
101         int             c;
102         byte    *out;
103         int             row;
104
105         row = (model->numleafs+7)>>3;   
106         out = decompressed;
107
108         if (!in)
109         {       // no vis info, so make all visible
110                 while (row)
111                 {
112                         *out++ = 0xff;
113                         row--;
114                 }
115                 return decompressed;            
116         }
117
118         do
119         {
120                 if (*in)
121                 {
122                         *out++ = *in++;
123                         continue;
124                 }
125         
126                 c = in[1];
127                 in += 2;
128                 while (c)
129                 {
130                         *out++ = 0;
131                         c--;
132                 }
133         } while (out - decompressed < row);
134         
135         return decompressed;
136 }
137
138 byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
139 {
140         if (leaf == model->leafs)
141                 return mod_novis;
142         return Mod_DecompressVis (leaf->compressed_vis, model);
143 }
144
145 extern byte     *mod_base;
146
147 extern cvar_t r_fullbrights;
148
149 /*
150 =================
151 Mod_LoadTextures
152 =================
153 */
154 void Mod_LoadTextures (lump_t *l)
155 {
156         int             i, j, num, max, altmax;
157         miptex_t        *mt;
158         texture_t       *tx, *tx2;
159         texture_t       *anims[10];
160         texture_t       *altanims[10];
161         dmiptexlump_t *m;
162         byte    *data;
163         int             *dofs;
164
165         if (!l->filelen)
166         {
167                 loadmodel->textures = NULL;
168                 return;
169         }
170
171         m = (dmiptexlump_t *)(mod_base + l->fileofs);
172         
173         m->nummiptex = LittleLong (m->nummiptex);
174         
175         loadmodel->numtextures = m->nummiptex;
176         loadmodel->textures = Hunk_AllocName (m->nummiptex * sizeof(*loadmodel->textures), va("%s texture headers", loadname));
177
178         // just to work around bounds checking when debugging with it (array index out of bounds error thing)
179         dofs = m->dataofs;
180         for (i=0 ; i<m->nummiptex ; i++)
181         {
182                 dofs[i] = LittleLong(dofs[i]);
183                 if (dofs[i] == -1)
184                         continue;
185                 mt = (miptex_t *)((byte *)m + dofs[i]);
186                 mt->width = LittleLong (mt->width);
187                 mt->height = LittleLong (mt->height);
188                 for (j=0 ; j<MIPLEVELS ; j++)
189                         mt->offsets[j] = LittleLong (mt->offsets[j]);
190                 
191                 if ( (mt->width & 15) || (mt->height & 15) )
192                         Host_Error ("Texture %s is not 16 aligned", mt->name);
193                 // LordHavoc: rewriting the map texture loader for GLQuake
194                 tx = Hunk_AllocName (sizeof(texture_t), va("%s textures", loadname));
195                 loadmodel->textures[i] = tx;
196
197                 // LordHavoc: force all names to lowercase and make sure they are terminated while copying
198                 for (j = 0;mt->name[j] && j < 15;j++)
199                 {
200                         if (mt->name[j] >= 'A' && mt->name[j] <= 'Z')
201                                 tx->name[j] = mt->name[j] + ('a' - 'A');
202                         else
203                                 tx->name[j] = mt->name[j];
204                 }
205                 for (;j < 16;j++)
206                         tx->name[j] = 0;
207
208                 for (j=0 ; j<MIPLEVELS ; j++)
209                         tx->offsets[j] = 0;
210                 tx->transparent = false;
211                 data = loadimagepixels(tx->name, false, 0, 0);
212                 if (data)
213                 {
214                         if (!hlbsp && !strncmp(tx->name,"sky",3) && image_width == 256 && image_height == 128) // LordHavoc: HL sky textures are entirely unrelated
215                         {
216                                 tx->width = image_width;
217                                 tx->height = image_height;
218                                 tx->transparent = false;
219                                 tx->texture = NULL;
220                                 tx->glowtexture = NULL;
221                                 R_InitSky (data, 4);
222                         }
223                         else
224                         {
225                                 tx->width = mt->width;
226                                 tx->height = mt->height;
227                                 tx->transparent = true;
228                                 tx->texture = R_LoadTexture (tx->name, image_width, image_height, data, TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
229                                 tx->glowtexture = NULL;
230                         }
231                         qfree(data);
232                 }
233                 else
234                 {
235                         if (!hlbsp && !strncmp(tx->name,"sky",3) && mt->width == 256 && mt->height == 128) // LordHavoc: HL sky textures are entirely unrelated
236                         {
237                                 tx->width = mt->width;
238                                 tx->height = mt->height;
239                                 tx->transparent = false;
240                                 tx->texture = NULL;
241                                 tx->glowtexture = NULL;
242                                 R_InitSky ((byte *)((int) mt + mt->offsets[0]), 1);
243                         }
244                         else
245                         {
246                                 if (hlbsp)
247                                 {
248                                         if (mt->offsets[0]) // texture included
249                                         {
250                                                 data = W_ConvertWAD3Texture(mt);
251                                                 if (data)
252                                                 {
253                                                         tx->width = mt->width;
254                                                         tx->height = mt->height;
255                                                         tx->transparent = true;
256                                                         tx->texture = R_LoadTexture (tx->name, mt->width, mt->height, data, TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
257                                                         tx->glowtexture = NULL;
258                                                         qfree(data);
259                                                 }
260                                         }
261                                         if (!data)
262                                         {
263                                                 data = W_GetTexture(mt->name);
264                                                 // get the size from the wad texture
265                                                 if (data)
266                                                 {
267                                                         tx->width = image_width;
268                                                         tx->height = image_height;
269                                                         tx->transparent = true;
270                                                         tx->texture = R_LoadTexture (tx->name, image_width, image_height, data, TEXF_MIPMAP | TEXF_ALPHA | TEXF_RGBA | TEXF_PRECACHE);
271                                                         tx->glowtexture = NULL;
272                                                         qfree(data);
273                                                 }
274                                         }
275                                         if (!data)
276                                         {
277                                                 tx->width = r_notexture_mip->width;
278                                                 tx->height = r_notexture_mip->height;
279                                                 tx->transparent = false;
280                                                 tx->texture = R_LoadTexture ("notexture", tx->width, tx->height, (byte *)((int) r_notexture_mip + r_notexture_mip->offsets[0]), TEXF_MIPMAP | TEXF_PRECACHE);
281                                                 tx->glowtexture = NULL;
282                                         }
283                                 }
284                                 else
285                                 {
286                                         if (mt->offsets[0]) // texture included
287                                         {
288                                                 int fullbrights;
289                                                 data = (byte *)((int) mt + mt->offsets[0]);
290                                                 tx->width = mt->width;
291                                                 tx->height = mt->height;
292                                                 tx->transparent = false;
293                                                 fullbrights = false;
294                                                 if (r_fullbrights.value && tx->name[0] != '*')
295                                                 {
296                                                         for (j = 0;j < tx->width*tx->height;j++)
297                                                         {
298                                                                 if (data[j] >= 224) // fullbright
299                                                                 {
300                                                                         fullbrights = true;
301                                                                         break;
302                                                                 }
303                                                         }
304                                                 }
305                                                 if (fullbrights)
306                                                 {
307                                                         char name[64];
308                                                         byte *data2;
309                                                         data2 = qmalloc(tx->width*tx->height);
310                                                         for (j = 0;j < tx->width*tx->height;j++)
311                                                                 data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights
312                                                         tx->texture = R_LoadTexture (tx->name, tx->width, tx->height, data2, TEXF_MIPMAP | TEXF_PRECACHE);
313                                                         strcpy(name, tx->name);
314                                                         strcat(name, "_glow");
315                                                         for (j = 0;j < tx->width*tx->height;j++)
316                                                                 data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights
317                                                         tx->glowtexture = R_LoadTexture (name, tx->width, tx->height, data2, TEXF_MIPMAP | TEXF_PRECACHE);
318                                                         qfree(data2);
319                                                 }
320                                                 else
321                                                 {
322                                                         tx->texture = R_LoadTexture (tx->name, tx->width, tx->height, data, TEXF_MIPMAP | TEXF_PRECACHE);
323                                                         tx->glowtexture = NULL;
324                                                 }
325                                         }
326                                         else // no texture, and no external replacement texture was found
327                                         {
328                                                 tx->width = r_notexture_mip->width;
329                                                 tx->height = r_notexture_mip->height;
330                                                 tx->transparent = false;
331                                                 tx->texture = R_LoadTexture ("notexture", tx->width, tx->height, (byte *)((int) r_notexture_mip + r_notexture_mip->offsets[0]), TEXF_MIPMAP | TEXF_PRECACHE);
332                                                 tx->glowtexture = NULL;
333                                         }
334                                 }
335                         }
336                 }
337         }
338
339 //
340 // sequence the animations
341 //
342         for (i=0 ; i<m->nummiptex ; i++)
343         {
344                 tx = loadmodel->textures[i];
345                 if (!tx || tx->name[0] != '+')
346                         continue;
347                 if (tx->anim_next)
348                         continue;       // already sequenced
349
350         // find the number of frames in the animation
351                 memset (anims, 0, sizeof(anims));
352                 memset (altanims, 0, sizeof(altanims));
353
354                 max = tx->name[1];
355                 altmax = 0;
356                 if (max >= 'a' && max <= 'z')
357                         max -= 'a' - 'A';
358                 if (max >= '0' && max <= '9')
359                 {
360                         max -= '0';
361                         altmax = 0;
362                         anims[max] = tx;
363                         max++;
364                 }
365                 else if (max >= 'A' && max <= 'J')
366                 {
367                         altmax = max - 'A';
368                         max = 0;
369                         altanims[altmax] = tx;
370                         altmax++;
371                 }
372                 else
373                         Host_Error ("Bad animating texture %s", tx->name);
374
375                 for (j=i+1 ; j<m->nummiptex ; j++)
376                 {
377                         tx2 = loadmodel->textures[j];
378                         if (!tx2 || tx2->name[0] != '+')
379                                 continue;
380                         if (strcmp (tx2->name+2, tx->name+2))
381                                 continue;
382
383                         num = tx2->name[1];
384                         if (num >= 'a' && num <= 'z')
385                                 num -= 'a' - 'A';
386                         if (num >= '0' && num <= '9')
387                         {
388                                 num -= '0';
389                                 anims[num] = tx2;
390                                 if (num+1 > max)
391                                         max = num + 1;
392                         }
393                         else if (num >= 'A' && num <= 'J')
394                         {
395                                 num = num - 'A';
396                                 altanims[num] = tx2;
397                                 if (num+1 > altmax)
398                                         altmax = num+1;
399                         }
400                         else
401                                 Host_Error ("Bad animating texture %s", tx->name);
402                 }
403                 
404 #define ANIM_CYCLE      2
405         // link them all together
406                 for (j=0 ; j<max ; j++)
407                 {
408                         tx2 = anims[j];
409                         if (!tx2)
410                                 Host_Error ("Missing frame %i of %s",j, tx->name);
411                         tx2->anim_total = max * ANIM_CYCLE;
412                         tx2->anim_min = j * ANIM_CYCLE;
413                         tx2->anim_max = (j+1) * ANIM_CYCLE;
414                         tx2->anim_next = anims[ (j+1)%max ];
415                         if (altmax)
416                                 tx2->alternate_anims = altanims[0];
417                 }
418                 for (j=0 ; j<altmax ; j++)
419                 {
420                         tx2 = altanims[j];
421                         if (!tx2)
422                                 Host_Error ("Missing frame %i of %s",j, tx->name);
423                         tx2->anim_total = altmax * ANIM_CYCLE;
424                         tx2->anim_min = j * ANIM_CYCLE;
425                         tx2->anim_max = (j+1) * ANIM_CYCLE;
426                         tx2->anim_next = altanims[ (j+1)%altmax ];
427                         if (max)
428                                 tx2->alternate_anims = anims[0];
429                 }
430         }
431 }
432
433 /*
434 =================
435 Mod_LoadLighting
436 =================
437 */
438 void Mod_LoadLighting (lump_t *l)
439 {
440         int i;
441         byte *in, *out, *data;
442         byte d;
443         char litfilename[1024];
444         loadmodel->lightdata = NULL;
445         if (hlbsp) // LordHavoc: load the colored lighting data straight
446         {
447                 loadmodel->lightdata = Hunk_AllocName ( l->filelen, va("%s lightmaps", loadname));
448                 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
449         }
450         else // LordHavoc: bsp version 29 (normal white lighting)
451         {
452                 // LordHavoc: hope is not lost yet, check for a .lit file to load
453                 strcpy(litfilename, loadmodel->name);
454                 COM_StripExtension(litfilename, litfilename);
455                 strcat(litfilename, ".lit");
456                 data = (byte*) COM_LoadHunkFile (litfilename, false);
457                 if (data)
458                 {
459                         if (data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
460                         {
461                                 i = LittleLong(((int *)data)[1]);
462                                 if (i == 1)
463                                 {
464                                         Con_DPrintf("%s loaded", litfilename);
465                                         loadmodel->lightdata = data + 8;
466                                         return;
467                                 }
468                                 else
469                                         Con_Printf("Unknown .lit file version (%d)\n", i);
470                         }
471                         else
472                                 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
473                 }
474                 // LordHavoc: oh well, expand the white lighting data
475                 if (!l->filelen)
476                         return;
477                 loadmodel->lightdata = Hunk_AllocName ( l->filelen*3, va("%s lightmaps", loadname));
478                 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
479                 out = loadmodel->lightdata;
480                 memcpy (in, mod_base + l->fileofs, l->filelen);
481                 for (i = 0;i < l->filelen;i++)
482                 {
483                         d = *in++;
484                         *out++ = d;
485                         *out++ = d;
486                         *out++ = d;
487                 }
488         }
489 }
490
491
492 /*
493 =================
494 Mod_LoadVisibility
495 =================
496 */
497 void Mod_LoadVisibility (lump_t *l)
498 {
499         if (!l->filelen)
500         {
501                 loadmodel->visdata = NULL;
502                 return;
503         }
504         loadmodel->visdata = Hunk_AllocName ( l->filelen, va("%s visdata", loadname));
505         memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
506 }
507
508 void CL_ParseEntityLump(char *entdata);
509
510 extern qboolean isworldmodel;
511
512 /*
513 =================
514 Mod_LoadEntities
515 =================
516 */
517 void Mod_LoadEntities (lump_t *l)
518 {
519         if (!l->filelen)
520         {
521                 loadmodel->entities = NULL;
522                 return;
523         }
524         loadmodel->entities = Hunk_AllocName ( l->filelen, va("%s entities", loadname));
525         memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
526
527         if (isworldmodel)
528                 CL_ParseEntityLump(loadmodel->entities);
529 }
530
531
532 /*
533 =================
534 Mod_LoadVertexes
535 =================
536 */
537 void Mod_LoadVertexes (lump_t *l)
538 {
539         dvertex_t       *in;
540         mvertex_t       *out;
541         int                     i, count;
542
543         in = (void *)(mod_base + l->fileofs);
544         if (l->filelen % sizeof(*in))
545                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
546         count = l->filelen / sizeof(*in);
547         out = Hunk_AllocName ( count*sizeof(*out), va("%s vertices", loadname));
548
549         loadmodel->vertexes = out;
550         loadmodel->numvertexes = count;
551
552         for ( i=0 ; i<count ; i++, in++, out++)
553         {
554                 out->position[0] = LittleFloat (in->point[0]);
555                 out->position[1] = LittleFloat (in->point[1]);
556                 out->position[2] = LittleFloat (in->point[2]);
557         }
558 }
559
560 /*
561 =================
562 Mod_LoadSubmodels
563 =================
564 */
565 void Mod_LoadSubmodels (lump_t *l)
566 {
567         dmodel_t        *in;
568         dmodel_t        *out;
569         int                     i, j, count;
570
571         in = (void *)(mod_base + l->fileofs);
572         if (l->filelen % sizeof(*in))
573                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
574         count = l->filelen / sizeof(*in);
575         out = Hunk_AllocName ( count*sizeof(*out), va("%s submodels", loadname));
576
577         loadmodel->submodels = out;
578         loadmodel->numsubmodels = count;
579
580         for ( i=0 ; i<count ; i++, in++, out++)
581         {
582                 for (j=0 ; j<3 ; j++)
583                 {       // spread the mins / maxs by a pixel
584                         out->mins[j] = LittleFloat (in->mins[j]) - 1;
585                         out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
586                         out->origin[j] = LittleFloat (in->origin[j]);
587                 }
588                 for (j=0 ; j<MAX_MAP_HULLS ; j++)
589                         out->headnode[j] = LittleLong (in->headnode[j]);
590                 out->visleafs = LittleLong (in->visleafs);
591                 out->firstface = LittleLong (in->firstface);
592                 out->numfaces = LittleLong (in->numfaces);
593         }
594 }
595
596 /*
597 =================
598 Mod_LoadEdges
599 =================
600 */
601 void Mod_LoadEdges (lump_t *l)
602 {
603         dedge_t *in;
604         medge_t *out;
605         int     i, count;
606
607         in = (void *)(mod_base + l->fileofs);
608         if (l->filelen % sizeof(*in))
609                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
610         count = l->filelen / sizeof(*in);
611         out = Hunk_AllocName ( (count + 1) * sizeof(*out), va("%s edges", loadname));
612
613         loadmodel->edges = out;
614         loadmodel->numedges = count;
615
616         for ( i=0 ; i<count ; i++, in++, out++)
617         {
618                 out->v[0] = (unsigned short)LittleShort(in->v[0]);
619                 out->v[1] = (unsigned short)LittleShort(in->v[1]);
620         }
621 }
622
623 /*
624 =================
625 Mod_LoadTexinfo
626 =================
627 */
628 void Mod_LoadTexinfo (lump_t *l)
629 {
630         texinfo_t *in;
631         mtexinfo_t *out;
632         int     i, j, k, count;
633         int             miptex;
634         float   len1, len2;
635
636         in = (void *)(mod_base + l->fileofs);
637         if (l->filelen % sizeof(*in))
638                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
639         count = l->filelen / sizeof(*in);
640         out = Hunk_AllocName ( count*sizeof(*out), va("%s texinfo", loadname));
641
642         loadmodel->texinfo = out;
643         loadmodel->numtexinfo = count;
644
645         for ( i=0 ; i<count ; i++, in++, out++)
646         {
647                 for (k=0 ; k<2 ; k++)
648                         for (j=0 ; j<4 ; j++)
649                                 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
650                 len1 = Length (out->vecs[0]);
651                 len2 = Length (out->vecs[1]);
652                 len1 = (len1 + len2)/2;
653                 if (len1 < 0.32)
654                         out->mipadjust = 4;
655                 else if (len1 < 0.49)
656                         out->mipadjust = 3;
657                 else if (len1 < 0.99)
658                         out->mipadjust = 2;
659                 else
660                         out->mipadjust = 1;
661 #if 0
662                 if (len1 + len2 < 0.001)
663                         out->mipadjust = 1;             // don't crash
664                 else
665                         out->mipadjust = 1 / floor( (len1+len2)/2 + 0.1 );
666 #endif
667
668                 miptex = LittleLong (in->miptex);
669                 out->flags = LittleLong (in->flags);
670         
671                 if (!loadmodel->textures)
672                 {
673                         out->texture = r_notexture_mip; // checkerboard texture
674                         out->flags = 0;
675                         out->texture->transparent = false;
676                 }
677                 else
678                 {
679                         if (miptex >= loadmodel->numtextures)
680                                 Host_Error ("miptex >= loadmodel->numtextures");
681                         out->texture = loadmodel->textures[miptex];
682                         if (!out->texture)
683                         {
684                                 out->texture = r_notexture_mip; // texture not found
685                                 out->flags = 0;
686                                 out->texture->transparent = false;
687                         }
688                 }
689         }
690 }
691
692 /*
693 ================
694 CalcSurfaceExtents
695
696 Fills in s->texturemins[] and s->extents[]
697 ================
698 */
699 void CalcSurfaceExtents (msurface_t *s)
700 {
701         float   mins[2], maxs[2], val;
702         int             i,j, e;
703         mvertex_t       *v;
704         mtexinfo_t      *tex;
705         int             bmins[2], bmaxs[2];
706
707         mins[0] = mins[1] = 999999;
708         maxs[0] = maxs[1] = -99999;
709
710         tex = s->texinfo;
711         
712         for (i=0 ; i<s->numedges ; i++)
713         {
714                 e = loadmodel->surfedges[s->firstedge+i];
715                 if (e >= 0)
716                         v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
717                 else
718                         v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
719                 
720                 for (j=0 ; j<2 ; j++)
721                 {
722                         val = v->position[0] * tex->vecs[j][0] + 
723                                 v->position[1] * tex->vecs[j][1] +
724                                 v->position[2] * tex->vecs[j][2] +
725                                 tex->vecs[j][3];
726                         if (val < mins[j])
727                                 mins[j] = val;
728                         if (val > maxs[j])
729                                 maxs[j] = val;
730                 }
731         }
732
733         for (i=0 ; i<2 ; i++)
734         {       
735                 bmins[i] = floor(mins[i]/16);
736                 bmaxs[i] = ceil(maxs[i]/16);
737
738                 s->texturemins[i] = bmins[i] * 16;
739                 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
740 //              if ( !(tex->flags & TEX_SPECIAL) && s->extents[i] > 512)
741                 if ((tex->flags & TEX_SPECIAL) == 0 && (s->extents[i]+1) > (256*16))
742                         Host_Error ("Bad surface extents");
743         }
744 }
745
746 void GL_SubdivideSurface (msurface_t *fa);
747
748 extern char skyname[];
749
750 /*
751 =================
752 Mod_LoadFaces
753 =================
754 */
755 void Mod_LoadFaces (lump_t *l)
756 {
757         dface_t         *in;
758         msurface_t      *out;
759         int                     i, count, surfnum;
760         int                     planenum, side;
761
762         in = (void *)(mod_base + l->fileofs);
763         if (l->filelen % sizeof(*in))
764                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
765         count = l->filelen / sizeof(*in);
766         out = Hunk_AllocName ( count*sizeof(*out), va("%s faces", loadname));
767
768         loadmodel->surfaces = out;
769         loadmodel->numsurfaces = count;
770
771         for ( surfnum=0 ; surfnum<count ; surfnum++, in++, out++)
772         {
773                 out->firstedge = LittleLong(in->firstedge);
774                 out->numedges = LittleShort(in->numedges);              
775                 out->flags = 0;
776
777                 planenum = LittleShort(in->planenum);
778                 side = LittleShort(in->side);
779                 if (side)
780                         out->flags |= SURF_PLANEBACK;                   
781
782                 out->plane = loadmodel->planes + planenum;
783
784                 out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
785
786                 CalcSurfaceExtents (out);
787                                 
788         // lighting info
789
790                 for (i=0 ; i<MAXLIGHTMAPS ; i++)
791                         out->styles[i] = in->styles[i];
792                 i = LittleLong(in->lightofs);
793                 if (i == -1)
794                         out->samples = NULL;
795                 else if (hlbsp) // LordHavoc: HalfLife map (bsp version 30)
796                         out->samples = loadmodel->lightdata + i;
797                 else // LordHavoc: white lighting (bsp version 29)
798                         out->samples = loadmodel->lightdata + (i * 3); 
799                 
800         // set the drawing flags flag
801                 
802 //              if (!strncmp(out->texinfo->texture->name,"sky",3))      // sky
803                 // LordHavoc: faster check
804                 if ((out->texinfo->texture->name[0] == 's' || out->texinfo->texture->name[0] == 'S')
805                  && (out->texinfo->texture->name[1] == 'k' || out->texinfo->texture->name[1] == 'K')
806                  && (out->texinfo->texture->name[2] == 'y' || out->texinfo->texture->name[2] == 'Y'))
807                 {
808                         // LordHavoc: for consistency reasons, mark sky as fullbright and solid as well
809                         out->flags |= (SURF_DRAWSKY | SURF_DRAWTILED | SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA);
810                         GL_SubdivideSurface (out);      // cut up polygon for warps
811                         continue;
812                 }
813                 
814 //              if (!strncmp(out->texinfo->texture->name,"*",1))                // turbulent
815                 if (out->texinfo->texture->name[0] == '*') // LordHavoc: faster check
816                 {
817                         out->flags |= (SURF_DRAWTURB | SURF_DRAWTILED | SURF_LIGHTBOTHSIDES);
818                         // LordHavoc: some turbulent textures should be fullbright and solid
819                         if (!strncmp(out->texinfo->texture->name,"*lava",5)
820                          || !strncmp(out->texinfo->texture->name,"*teleport",9)
821                          || !strncmp(out->texinfo->texture->name,"*rift",5)) // Scourge of Armagon texture
822                                 out->flags |= (SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA);
823                         for (i=0 ; i<2 ; i++)
824                         {
825                                 out->extents[i] = 16384;
826                                 out->texturemins[i] = -8192;
827                         }
828                         GL_SubdivideSurface (out);      // cut up polygon for warps
829                         continue;
830                 }
831
832         }
833 }
834
835
836 /*
837 =================
838 Mod_SetParent
839 =================
840 */
841 void Mod_SetParent (mnode_t *node, mnode_t *parent)
842 {
843         node->parent = parent;
844         if (node->contents < 0)
845                 return;
846         Mod_SetParent (node->children[0], node);
847         Mod_SetParent (node->children[1], node);
848 }
849
850 /*
851 =================
852 Mod_LoadNodes
853 =================
854 */
855 void Mod_LoadNodes (lump_t *l)
856 {
857         int                     i, j, count, p;
858         dnode_t         *in;
859         mnode_t         *out;
860
861         in = (void *)(mod_base + l->fileofs);
862         if (l->filelen % sizeof(*in))
863                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
864         count = l->filelen / sizeof(*in);
865         out = Hunk_AllocName ( count*sizeof(*out), va("%s nodes", loadname));
866
867         loadmodel->nodes = out;
868         loadmodel->numnodes = count;
869
870         for ( i=0 ; i<count ; i++, in++, out++)
871         {
872                 for (j=0 ; j<3 ; j++)
873                 {
874                         out->minmaxs[j] = LittleShort (in->mins[j]);
875                         out->minmaxs[3+j] = LittleShort (in->maxs[j]);
876                 }
877         
878                 p = LittleLong(in->planenum);
879                 out->plane = loadmodel->planes + p;
880
881                 out->firstsurface = LittleShort (in->firstface);
882                 out->numsurfaces = LittleShort (in->numfaces);
883                 
884                 for (j=0 ; j<2 ; j++)
885                 {
886                         p = LittleShort (in->children[j]);
887                         if (p >= 0)
888                                 out->children[j] = loadmodel->nodes + p;
889                         else
890                                 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
891                 }
892         }
893         
894         Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
895 }
896
897 /*
898 =================
899 Mod_LoadLeafs
900 =================
901 */
902 void Mod_LoadLeafs (lump_t *l)
903 {
904         dleaf_t         *in;
905         mleaf_t         *out;
906         int                     i, j, count, p;
907
908         in = (void *)(mod_base + l->fileofs);
909         if (l->filelen % sizeof(*in))
910                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
911         count = l->filelen / sizeof(*in);
912         out = Hunk_AllocName ( count*sizeof(*out), va("%s leafs", loadname));
913
914         loadmodel->leafs = out;
915         loadmodel->numleafs = count;
916
917         for ( i=0 ; i<count ; i++, in++, out++)
918         {
919                 for (j=0 ; j<3 ; j++)
920                 {
921                         out->minmaxs[j] = LittleShort (in->mins[j]);
922                         out->minmaxs[3+j] = LittleShort (in->maxs[j]);
923                 }
924
925                 p = LittleLong(in->contents);
926                 out->contents = p;
927
928                 out->firstmarksurface = loadmodel->marksurfaces +
929                         LittleShort(in->firstmarksurface);
930                 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
931                 
932                 p = LittleLong(in->visofs);
933                 if (p == -1)
934                         out->compressed_vis = NULL;
935                 else
936                         out->compressed_vis = loadmodel->visdata + p;
937                 out->efrags = NULL;
938                 
939                 for (j=0 ; j<4 ; j++)
940                         out->ambient_sound_level[j] = in->ambient_level[j];
941
942                 // gl underwater warp
943                 // LordHavoc: disabled underwater warping
944                 /*
945                 if (out->contents != CONTENTS_EMPTY)
946                 {
947                         for (j=0 ; j<out->nummarksurfaces ; j++)
948                                 out->firstmarksurface[j]->flags |= SURF_UNDERWATER;
949                 }
950                 */
951         }       
952 }
953
954 /*
955 =================
956 Mod_LoadClipnodes
957 =================
958 */
959 void Mod_LoadClipnodes (lump_t *l)
960 {
961         dclipnode_t *in, *out;
962         int                     i, count;
963         hull_t          *hull;
964
965         in = (void *)(mod_base + l->fileofs);
966         if (l->filelen % sizeof(*in))
967                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
968         count = l->filelen / sizeof(*in);
969         out = Hunk_AllocName ( count*sizeof(*out), va("%s clipnodes", loadname));
970
971         loadmodel->clipnodes = out;
972         loadmodel->numclipnodes = count;
973
974         if (hlbsp)
975         {
976                 hull = &loadmodel->hulls[1];
977                 hull->clipnodes = out;
978                 hull->firstclipnode = 0;
979                 hull->lastclipnode = count-1;
980                 hull->planes = loadmodel->planes;
981                 hull->clip_mins[0] = -16;
982                 hull->clip_mins[1] = -16;
983                 hull->clip_mins[2] = -36;
984                 hull->clip_maxs[0] = 16;
985                 hull->clip_maxs[1] = 16;
986                 hull->clip_maxs[2] = 36;
987
988                 hull = &loadmodel->hulls[2];
989                 hull->clipnodes = out;
990                 hull->firstclipnode = 0;
991                 hull->lastclipnode = count-1;
992                 hull->planes = loadmodel->planes;
993                 hull->clip_mins[0] = -32;
994                 hull->clip_mins[1] = -32;
995                 hull->clip_mins[2] = -32;
996                 hull->clip_maxs[0] = 32;
997                 hull->clip_maxs[1] = 32;
998                 hull->clip_maxs[2] = 32;
999
1000                 hull = &loadmodel->hulls[3];
1001                 hull->clipnodes = out;
1002                 hull->firstclipnode = 0;
1003                 hull->lastclipnode = count-1;
1004                 hull->planes = loadmodel->planes;
1005                 hull->clip_mins[0] = -16;
1006                 hull->clip_mins[1] = -16;
1007                 hull->clip_mins[2] = -18;
1008                 hull->clip_maxs[0] = 16;
1009                 hull->clip_maxs[1] = 16;
1010                 hull->clip_maxs[2] = 18;
1011         }
1012         else
1013         {
1014                 hull = &loadmodel->hulls[1];
1015                 hull->clipnodes = out;
1016                 hull->firstclipnode = 0;
1017                 hull->lastclipnode = count-1;
1018                 hull->planes = loadmodel->planes;
1019                 hull->clip_mins[0] = -16;
1020                 hull->clip_mins[1] = -16;
1021                 hull->clip_mins[2] = -24;
1022                 hull->clip_maxs[0] = 16;
1023                 hull->clip_maxs[1] = 16;
1024                 hull->clip_maxs[2] = 32;
1025
1026                 hull = &loadmodel->hulls[2];
1027                 hull->clipnodes = out;
1028                 hull->firstclipnode = 0;
1029                 hull->lastclipnode = count-1;
1030                 hull->planes = loadmodel->planes;
1031                 hull->clip_mins[0] = -32;
1032                 hull->clip_mins[1] = -32;
1033                 hull->clip_mins[2] = -24;
1034                 hull->clip_maxs[0] = 32;
1035                 hull->clip_maxs[1] = 32;
1036                 hull->clip_maxs[2] = 64;
1037         }
1038
1039         for (i=0 ; i<count ; i++, out++, in++)
1040         {
1041                 out->planenum = LittleLong(in->planenum);
1042                 out->children[0] = LittleShort(in->children[0]);
1043                 out->children[1] = LittleShort(in->children[1]);
1044                 if (out->children[0] >= count || out->children[1] >= count)
1045                         Host_Error("Corrupt clipping hull (out of range child)\n");
1046         }
1047 }
1048
1049 /*
1050 =================
1051 Mod_MakeHull0
1052
1053 Duplicate the drawing hull structure as a clipping hull
1054 =================
1055 */
1056 void Mod_MakeHull0 (void)
1057 {
1058         mnode_t         *in, *child;
1059         dclipnode_t *out;
1060         int                     i, j, count;
1061         hull_t          *hull;
1062         
1063         hull = &loadmodel->hulls[0];    
1064         
1065         in = loadmodel->nodes;
1066         count = loadmodel->numnodes;
1067         out = Hunk_AllocName ( count*sizeof(*out), va("%s hull0", loadname));
1068
1069         hull->clipnodes = out;
1070         hull->firstclipnode = 0;
1071         hull->lastclipnode = count-1;
1072         hull->planes = loadmodel->planes;
1073
1074         for (i=0 ; i<count ; i++, out++, in++)
1075         {
1076                 out->planenum = in->plane - loadmodel->planes;
1077                 for (j=0 ; j<2 ; j++)
1078                 {
1079                         child = in->children[j];
1080                         if (child->contents < 0)
1081                                 out->children[j] = child->contents;
1082                         else
1083                                 out->children[j] = child - loadmodel->nodes;
1084                 }
1085         }
1086 }
1087
1088 /*
1089 =================
1090 Mod_LoadMarksurfaces
1091 =================
1092 */
1093 void Mod_LoadMarksurfaces (lump_t *l)
1094 {       
1095         int             i, j, count;
1096         short           *in;
1097         msurface_t **out;
1098         
1099         in = (void *)(mod_base + l->fileofs);
1100         if (l->filelen % sizeof(*in))
1101                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1102         count = l->filelen / sizeof(*in);
1103         out = Hunk_AllocName ( count*sizeof(*out), va("%s marksurfaces", loadname));
1104
1105         loadmodel->marksurfaces = out;
1106         loadmodel->nummarksurfaces = count;
1107
1108         for ( i=0 ; i<count ; i++)
1109         {
1110                 j = LittleShort(in[i]);
1111                 if (j >= loadmodel->numsurfaces)
1112                         Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1113                 out[i] = loadmodel->surfaces + j;
1114         }
1115 }
1116
1117 /*
1118 =================
1119 Mod_LoadSurfedges
1120 =================
1121 */
1122 void Mod_LoadSurfedges (lump_t *l)
1123 {       
1124         int             i, count;
1125         int             *in, *out;
1126         
1127         in = (void *)(mod_base + l->fileofs);
1128         if (l->filelen % sizeof(*in))
1129                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1130         count = l->filelen / sizeof(*in);
1131         out = Hunk_AllocName ( count*sizeof(*out), va("%s surfedges", loadname));
1132
1133         loadmodel->surfedges = out;
1134         loadmodel->numsurfedges = count;
1135
1136         for ( i=0 ; i<count ; i++)
1137                 out[i] = LittleLong (in[i]);
1138 }
1139
1140
1141 /*
1142 =================
1143 Mod_LoadPlanes
1144 =================
1145 */
1146 void Mod_LoadPlanes (lump_t *l)
1147 {
1148         int                     i, j;
1149         mplane_t        *out;
1150         dplane_t        *in;
1151         int                     count;
1152         int                     bits;
1153         
1154         in = (void *)(mod_base + l->fileofs);
1155         if (l->filelen % sizeof(*in))
1156                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1157         count = l->filelen / sizeof(*in);
1158         out = Hunk_AllocName ( count*2*sizeof(*out), va("%s planes", loadname));
1159
1160         loadmodel->planes = out;
1161         loadmodel->numplanes = count;
1162
1163         for ( i=0 ; i<count ; i++, in++, out++)
1164         {
1165                 bits = 0;
1166                 for (j=0 ; j<3 ; j++)
1167                 {
1168                         out->normal[j] = LittleFloat (in->normal[j]);
1169 //                      if (out->normal[j] < 0)
1170 //                              bits |= 1<<j;
1171                 }
1172
1173                 out->dist = LittleFloat (in->dist);
1174                 out->type = LittleLong (in->type);
1175 //              out->signbits = bits;
1176                 BoxOnPlaneSideClassify(out);
1177         }
1178 }
1179
1180 /*
1181 =================
1182 Mod_LoadBrushModel
1183 =================
1184 */
1185 void Mod_LoadBrushModel (model_t *mod, void *buffer)
1186 {
1187         int                     i, j;
1188         dheader_t       *header;
1189         dmodel_t        *bm;
1190         
1191         loadmodel->type = mod_brush;
1192         
1193         header = (dheader_t *)buffer;
1194
1195         i = LittleLong (header->version);
1196         if (i != BSPVERSION && i != 30)
1197                 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i or 30 (HalfLife))", mod->name, i, BSPVERSION);
1198         hlbsp = i == 30;
1199         halflifebsp.value = hlbsp;
1200
1201 // swap all the lumps
1202         mod_base = (byte *)header;
1203
1204         for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
1205                 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
1206
1207 // load into heap
1208         
1209         // LordHavoc: had to move entity loading above everything to allow parsing various settings from worldspawn
1210         Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
1211
1212         Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
1213         Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
1214         Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
1215         Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
1216         Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
1217         Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
1218         Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
1219         Mod_LoadFaces (&header->lumps[LUMP_FACES]);
1220         Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
1221         Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
1222         Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
1223         Mod_LoadNodes (&header->lumps[LUMP_NODES]);
1224         Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
1225 //      Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
1226         Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
1227
1228         Mod_MakeHull0 ();
1229         
1230         mod->numframes = 2;             // regular and alternate animation
1231         
1232 //
1233 // set up the submodels (FIXME: this is confusing)
1234 //
1235         for (i=0 ; i<mod->numsubmodels ; i++)
1236         {
1237                 bm = &mod->submodels[i];
1238
1239                 mod->hulls[0].firstclipnode = bm->headnode[0];
1240                 for (j=1 ; j<MAX_MAP_HULLS ; j++)
1241                 {
1242                         mod->hulls[j].firstclipnode = bm->headnode[j];
1243                         mod->hulls[j].lastclipnode = mod->numclipnodes-1;
1244                 }
1245                 
1246                 mod->firstmodelsurface = bm->firstface;
1247                 mod->nummodelsurfaces = bm->numfaces;
1248                 
1249                 VectorCopy (bm->maxs, mod->maxs);
1250                 VectorCopy (bm->mins, mod->mins);
1251
1252                 mod->radius = RadiusFromBounds (mod->mins, mod->maxs);
1253
1254                 mod->numleafs = bm->visleafs;
1255
1256                 if (isworldmodel && i < (mod->numsubmodels-1)) // LordHavoc: only register submodels if it is the world (prevents bsp models from replacing world submodels)
1257                 {       // duplicate the basic information
1258                         char    name[10];
1259
1260                         sprintf (name, "*%i", i+1);
1261                         loadmodel = Mod_FindName (name);
1262                         *loadmodel = *mod;
1263                         strcpy (loadmodel->name, name);
1264                         mod = loadmodel;
1265                 }
1266         }
1267 }