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