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