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