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