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