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