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