]> icculus.org git repositories - divverent/darkplaces.git/blob - model_brush.c
fixed bug that used bmodel collision geometry on non-SOLID_BSP entities (thanks to...
[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 #include "image.h"
23 #include "r_shadow.h"
24
25 // note: model_shared.c sets up r_notexture, and r_surf_notexture
26
27 qbyte mod_novis[(MAX_MAP_LEAFS + 7)/ 8];
28
29 //cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"};
30 cvar_t halflifebsp = {0, "halflifebsp", "0"};
31 cvar_t r_novis = {0, "r_novis", "0"};
32 cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"};
33 cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
34 cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
35 cvar_t r_sortsurfaces = {0, "r_sortsurfaces", "0"};
36
37 /*
38 ===============
39 Mod_BrushInit
40 ===============
41 */
42 void Mod_BrushInit (void)
43 {
44 //      Cvar_RegisterVariable(&r_subdivide_size);
45         Cvar_RegisterVariable(&halflifebsp);
46         Cvar_RegisterVariable(&r_novis);
47         Cvar_RegisterVariable(&r_miplightmaps);
48         Cvar_RegisterVariable(&r_lightmaprgba);
49         Cvar_RegisterVariable(&r_nosurftextures);
50         Cvar_RegisterVariable(&r_sortsurfaces);
51         memset(mod_novis, 0xff, sizeof(mod_novis));
52 }
53
54 /*
55 ===============
56 Mod_PointInLeaf
57 ===============
58 */
59 mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model)
60 {
61         mnode_t *node;
62
63         if (model == NULL)
64                 return NULL;
65
66         Mod_CheckLoaded(model);
67
68         // LordHavoc: modified to start at first clip node,
69         // in other words: first node of the (sub)model
70         node = model->nodes + model->hulls[0].firstclipnode;
71         while (node->contents == 0)
72                 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
73
74         return (mleaf_t *)node;
75 }
76
77 int Mod_PointContents (const vec3_t p, model_t *model)
78 {
79         mnode_t *node;
80
81         if (model == NULL)
82                 return CONTENTS_EMPTY;
83
84         Mod_CheckLoaded(model);
85
86         // LordHavoc: modified to start at first clip node,
87         // in other words: first node of the (sub)model
88         node = model->nodes + model->hulls[0].firstclipnode;
89         while (node->contents == 0)
90                 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
91
92         return ((mleaf_t *)node)->contents;
93 }
94
95 typedef struct findnonsolidlocationinfo_s
96 {
97         vec3_t center;
98         vec_t radius;
99         vec3_t nudge;
100         vec_t bestdist;
101         model_t *model;
102 }
103 findnonsolidlocationinfo_t;
104
105 #if 0
106 extern cvar_t samelevel;
107 #endif
108 void Mod_FindNonSolidLocation_r_Leaf(findnonsolidlocationinfo_t *info, mleaf_t *leaf)
109 {
110         int i, surfnum, k, *tri, *mark;
111         float dist, f, vert[3][3], edge[3][3], facenormal[3], edgenormal[3][3], point[3];
112 #if 0
113         float surfnormal[3];
114 #endif
115         msurface_t *surf;
116         surfmesh_t *mesh;
117         for (surfnum = 0, mark = leaf->firstmarksurface;surfnum < leaf->nummarksurfaces;surfnum++, mark++)
118         {
119                 surf = info->model->surfaces + *mark;
120                 if (surf->flags & SURF_SOLIDCLIP)
121                 {
122 #if 0
123                         VectorCopy(surf->plane->normal, surfnormal);
124                         if (surf->flags & SURF_PLANEBACK)
125                                 VectorNegate(surfnormal, surfnormal);
126 #endif
127                         for (mesh = surf->mesh;mesh;mesh = mesh->chain)
128                         {
129                                 for (k = 0;k < mesh->numtriangles;k++)
130                                 {
131                                         tri = mesh->element3i + k * 3;
132                                         VectorCopy((mesh->vertex3f + tri[0] * 3), vert[0]);
133                                         VectorCopy((mesh->vertex3f + tri[1] * 3), vert[1]);
134                                         VectorCopy((mesh->vertex3f + tri[2] * 3), vert[2]);
135                                         VectorSubtract(vert[1], vert[0], edge[0]);
136                                         VectorSubtract(vert[2], vert[1], edge[1]);
137                                         CrossProduct(edge[1], edge[0], facenormal);
138                                         if (facenormal[0] || facenormal[1] || facenormal[2])
139                                         {
140                                                 VectorNormalize(facenormal);
141 #if 0
142                                                 if (VectorDistance(facenormal, surfnormal) > 0.01f)
143                                                         Con_Printf("a2! %f %f %f != %f %f %f\n", facenormal[0], facenormal[1], facenormal[2], surfnormal[0], surfnormal[1], surfnormal[2]);
144 #endif
145                                                 f = DotProduct(info->center, facenormal) - DotProduct(vert[0], facenormal);
146                                                 if (f <= info->bestdist && f >= -info->bestdist)
147                                                 {
148                                                         VectorSubtract(vert[0], vert[2], edge[2]);
149                                                         VectorNormalize(edge[0]);
150                                                         VectorNormalize(edge[1]);
151                                                         VectorNormalize(edge[2]);
152                                                         CrossProduct(facenormal, edge[0], edgenormal[0]);
153                                                         CrossProduct(facenormal, edge[1], edgenormal[1]);
154                                                         CrossProduct(facenormal, edge[2], edgenormal[2]);
155 #if 0
156                                                         if (samelevel.integer & 1)
157                                                                 VectorNegate(edgenormal[0], edgenormal[0]);
158                                                         if (samelevel.integer & 2)
159                                                                 VectorNegate(edgenormal[1], edgenormal[1]);
160                                                         if (samelevel.integer & 4)
161                                                                 VectorNegate(edgenormal[2], edgenormal[2]);
162                                                         for (i = 0;i < 3;i++)
163                                                                 if (DotProduct(vert[0], edgenormal[i]) > DotProduct(vert[i], edgenormal[i]) + 0.1f
164                                                                  || DotProduct(vert[1], edgenormal[i]) > DotProduct(vert[i], edgenormal[i]) + 0.1f
165                                                                  || DotProduct(vert[2], edgenormal[i]) > DotProduct(vert[i], edgenormal[i]) + 0.1f)
166                                                                         Con_Printf("a! %i : %f %f %f (%f %f %f)\n", i, edgenormal[i][0], edgenormal[i][1], edgenormal[i][2], facenormal[0], facenormal[1], facenormal[2]);
167 #endif
168                                                         // face distance
169                                                         if (DotProduct(info->center, edgenormal[0]) < DotProduct(vert[0], edgenormal[0])
170                                                          && DotProduct(info->center, edgenormal[1]) < DotProduct(vert[1], edgenormal[1])
171                                                          && DotProduct(info->center, edgenormal[2]) < DotProduct(vert[2], edgenormal[2]))
172                                                         {
173                                                                 // we got lucky, the center is within the face
174                                                                 dist = DotProduct(info->center, facenormal) - DotProduct(vert[0], facenormal);
175                                                                 if (dist < 0)
176                                                                 {
177                                                                         dist = -dist;
178                                                                         if (info->bestdist > dist)
179                                                                         {
180                                                                                 info->bestdist = dist;
181                                                                                 VectorScale(facenormal, (info->radius - -dist), info->nudge);
182                                                                         }
183                                                                 }
184                                                                 else
185                                                                 {
186                                                                         if (info->bestdist > dist)
187                                                                         {
188                                                                                 info->bestdist = dist;
189                                                                                 VectorScale(facenormal, (info->radius - dist), info->nudge);
190                                                                         }
191                                                                 }
192                                                         }
193                                                         else
194                                                         {
195                                                                 // check which edge or vertex the center is nearest
196                                                                 for (i = 0;i < 3;i++)
197                                                                 {
198                                                                         f = DotProduct(info->center, edge[i]);
199                                                                         if (f >= DotProduct(vert[0], edge[i])
200                                                                          && f <= DotProduct(vert[1], edge[i]))
201                                                                         {
202                                                                                 // on edge
203                                                                                 VectorMA(info->center, -f, edge[i], point);
204                                                                                 dist = sqrt(DotProduct(point, point));
205                                                                                 if (info->bestdist > dist)
206                                                                                 {
207                                                                                         info->bestdist = dist;
208                                                                                         VectorScale(point, (info->radius / dist), info->nudge);
209                                                                                 }
210                                                                                 // skip both vertex checks
211                                                                                 // (both are further away than this edge)
212                                                                                 i++;
213                                                                         }
214                                                                         else
215                                                                         {
216                                                                                 // not on edge, check first vertex of edge
217                                                                                 VectorSubtract(info->center, vert[i], point);
218                                                                                 dist = sqrt(DotProduct(point, point));
219                                                                                 if (info->bestdist > dist)
220                                                                                 {
221                                                                                         info->bestdist = dist;
222                                                                                         VectorScale(point, (info->radius / dist), info->nudge);
223                                                                                 }
224                                                                         }
225                                                                 }
226                                                         }
227                                                 }
228                                         }
229                                 }
230                         }
231                 }
232         }
233 }
234
235 void Mod_FindNonSolidLocation_r(findnonsolidlocationinfo_t *info, mnode_t *node)
236 {
237         if (node->contents)
238         {
239                 if (((mleaf_t *)node)->nummarksurfaces)
240                         Mod_FindNonSolidLocation_r_Leaf(info, (mleaf_t *)node);
241         }
242         else
243         {
244                 float f = PlaneDiff(info->center, node->plane);
245                 if (f >= -info->bestdist)
246                         Mod_FindNonSolidLocation_r(info, node->children[0]);
247                 if (f <= info->bestdist)
248                         Mod_FindNonSolidLocation_r(info, node->children[1]);
249         }
250 }
251
252 void Mod_FindNonSolidLocation(vec3_t in, vec3_t out, model_t *model, float radius)
253 {
254         int i;
255         findnonsolidlocationinfo_t info;
256         if (model == NULL)
257         {
258                 VectorCopy(in, out);
259                 return;
260         }
261         VectorCopy(in, info.center);
262         info.radius = radius;
263         info.model = model;
264         i = 0;
265         do
266         {
267                 VectorClear(info.nudge);
268                 info.bestdist = radius;
269                 Mod_FindNonSolidLocation_r(&info, model->nodes + model->hulls[0].firstclipnode);
270                 VectorAdd(info.center, info.nudge, info.center);
271         }
272         while(info.bestdist < radius && ++i < 10);
273         VectorCopy(info.center, out);
274 }
275
276 /*
277 ===================
278 Mod_DecompressVis
279 ===================
280 */
281 static qbyte *Mod_DecompressVis (qbyte *in, model_t *model)
282 {
283         static qbyte decompressed[MAX_MAP_LEAFS/8];
284         int c;
285         qbyte *out;
286         int row;
287
288         row = (model->numleafs+7)>>3;
289         out = decompressed;
290
291         do
292         {
293                 if (*in)
294                 {
295                         *out++ = *in++;
296                         continue;
297                 }
298
299                 c = in[1];
300                 in += 2;
301                 while (c)
302                 {
303                         *out++ = 0;
304                         c--;
305                 }
306         } while (out - decompressed < row);
307
308         return decompressed;
309 }
310
311 qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
312 {
313         if (r_novis.integer || leaf == model->leafs || leaf->compressed_vis == NULL)
314                 return mod_novis;
315         return Mod_DecompressVis (leaf->compressed_vis, model);
316 }
317
318 /*
319 =================
320 Mod_LoadTextures
321 =================
322 */
323 static void Mod_LoadTextures (lump_t *l)
324 {
325         int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs, incomplete;
326         miptex_t *dmiptex;
327         texture_t *tx, *tx2, *anims[10], *altanims[10];
328         dmiptexlump_t *m;
329         qbyte *data, *mtdata;
330         char name[256];
331
332         loadmodel->textures = NULL;
333
334         if (!l->filelen)
335                 return;
336
337         m = (dmiptexlump_t *)(mod_base + l->fileofs);
338
339         m->nummiptex = LittleLong (m->nummiptex);
340
341         // add two slots for notexture walls and notexture liquids
342         loadmodel->numtextures = m->nummiptex + 2;
343         loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(texture_t));
344
345         // fill out all slots with notexture
346         for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++)
347         {
348                 tx->number = i;
349                 strcpy(tx->name, "NO TEXTURE FOUND");
350                 tx->width = 16;
351                 tx->height = 16;
352                 tx->skin.base = r_notexture;
353                 tx->shader = &Cshader_wall_lightmap;
354                 tx->flags = SURF_SOLIDCLIP;
355                 if (i == loadmodel->numtextures - 1)
356                 {
357                         tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
358                         tx->shader = &Cshader_water;
359                 }
360                 tx->currentframe = tx;
361         }
362
363         // just to work around bounds checking when debugging with it (array index out of bounds error thing)
364         dofs = m->dataofs;
365         // LordHavoc: mostly rewritten map texture loader
366         for (i = 0;i < m->nummiptex;i++)
367         {
368                 dofs[i] = LittleLong(dofs[i]);
369                 if (dofs[i] == -1 || r_nosurftextures.integer)
370                         continue;
371                 dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
372
373                 // make sure name is no more than 15 characters
374                 for (j = 0;dmiptex->name[j] && j < 15;j++)
375                         name[j] = dmiptex->name[j];
376                 name[j] = 0;
377
378                 mtwidth = LittleLong (dmiptex->width);
379                 mtheight = LittleLong (dmiptex->height);
380                 mtdata = NULL;
381                 j = LittleLong (dmiptex->offsets[0]);
382                 if (j)
383                 {
384                         // texture included
385                         if (j < 40 || j + mtwidth * mtheight > l->filelen)
386                         {
387                                 Con_Printf ("Texture \"%s\" in \"%s\"is corrupt or incomplete\n", dmiptex->name, loadmodel->name);
388                                 continue;
389                         }
390                         mtdata = (qbyte *)dmiptex + j;
391                 }
392
393                 if ((mtwidth & 15) || (mtheight & 15))
394                         Con_Printf ("warning: texture \"%s\" in \"%s\" is not 16 aligned", dmiptex->name, loadmodel->name);
395
396                 // LordHavoc: force all names to lowercase
397                 for (j = 0;name[j];j++)
398                         if (name[j] >= 'A' && name[j] <= 'Z')
399                                 name[j] += 'a' - 'A';
400
401                 tx = loadmodel->textures + i;
402                 strcpy(tx->name, name);
403                 tx->width = mtwidth;
404                 tx->height = mtheight;
405
406                 if (!tx->name[0])
407                 {
408                         sprintf(tx->name, "unnamed%i", i);
409                         Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
410                 }
411
412                 // LordHavoc: HL sky textures are entirely different than quake
413                 if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
414                 {
415                         if (loadmodel->isworldmodel)
416                         {
417                                 data = loadimagepixels(tx->name, false, 0, 0);
418                                 if (data)
419                                 {
420                                         if (image_width == 256 && image_height == 128)
421                                         {
422                                                 R_InitSky (data, 4);
423                                                 Mem_Free(data);
424                                         }
425                                         else
426                                         {
427                                                 Mem_Free(data);
428                                                 Con_Printf ("Invalid replacement texture for sky \"%s\" in %\"%s\", must be 256x128 pixels\n", tx->name, loadmodel->name);
429                                                 if (mtdata != NULL)
430                                                         R_InitSky (mtdata, 1);
431                                         }
432                                 }
433                                 else if (mtdata != NULL)
434                                         R_InitSky (mtdata, 1);
435                         }
436                 }
437                 else
438                 {
439                         if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true))
440                         {
441                                 // did not find external texture, load it from the bsp or wad3
442                                 if (loadmodel->ishlbsp)
443                                 {
444                                         // internal texture overrides wad
445                                         qbyte *pixels, *freepixels, *fogpixels;
446                                         pixels = freepixels = NULL;
447                                         if (mtdata)
448                                                 pixels = W_ConvertWAD3Texture(dmiptex);
449                                         if (pixels == NULL)
450                                                 pixels = freepixels = W_GetTexture(tx->name);
451                                         if (pixels != NULL)
452                                         {
453                                                 tx->width = image_width;
454                                                 tx->height = image_height;
455                                                 tx->skin.base = tx->skin.merged = R_LoadTexture2D(loadmodel->texturepool, tx->name, image_width, image_height, pixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
456                                                 if (Image_CheckAlpha(pixels, image_width * image_height, true))
457                                                 {
458                                                         fogpixels = Mem_Alloc(tempmempool, image_width * image_height * 4);
459                                                         for (j = 0;j < image_width * image_height * 4;j += 4)
460                                                         {
461                                                                 fogpixels[j + 0] = 255;
462                                                                 fogpixels[j + 1] = 255;
463                                                                 fogpixels[j + 2] = 255;
464                                                                 fogpixels[j + 3] = pixels[j + 3];
465                                                         }
466                                                         tx->skin.fog = R_LoadTexture2D(loadmodel->texturepool, tx->name, image_width, image_height, pixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
467                                                         Mem_Free(fogpixels);
468                                                 }
469                                         }
470                                         if (freepixels)
471                                                 Mem_Free(freepixels);
472                                 }
473                                 else if (mtdata) // texture included
474                                         Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_PRECACHE, false, true, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height);
475                         }
476                 }
477                 if (tx->skin.base == NULL)
478                 {
479                         // no texture found
480                         tx->width = 16;
481                         tx->height = 16;
482                         tx->skin.base = r_notexture;
483                 }
484
485                 if (tx->name[0] == '*')
486                 {
487                         // turb does not block movement
488                         tx->flags &= ~SURF_SOLIDCLIP;
489                         tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
490                         // LordHavoc: some turbulent textures should be fullbright and solid
491                         if (!strncmp(tx->name,"*lava",5)
492                          || !strncmp(tx->name,"*teleport",9)
493                          || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
494                                 tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
495                         else
496                                 tx->flags |= SURF_WATERALPHA;
497                         tx->shader = &Cshader_water;
498                 }
499                 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
500                 {
501                         tx->flags |= SURF_DRAWSKY;
502                         tx->shader = &Cshader_sky;
503                 }
504                 else
505                 {
506                         tx->flags |= SURF_LIGHTMAP;
507                         if (!tx->skin.fog)
508                                 tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT;
509                         tx->shader = &Cshader_wall_lightmap;
510                 }
511
512                 // start out with no animation
513                 tx->currentframe = tx;
514         }
515
516         // sequence the animations
517         for (i = 0;i < m->nummiptex;i++)
518         {
519                 tx = loadmodel->textures + i;
520                 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
521                         continue;
522                 if (tx->anim_total[0] || tx->anim_total[1])
523                         continue;       // already sequenced
524
525                 // find the number of frames in the animation
526                 memset (anims, 0, sizeof(anims));
527                 memset (altanims, 0, sizeof(altanims));
528
529                 for (j = i;j < m->nummiptex;j++)
530                 {
531                         tx2 = loadmodel->textures + j;
532                         if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
533                                 continue;
534
535                         num = tx2->name[1];
536                         if (num >= '0' && num <= '9')
537                                 anims[num - '0'] = tx2;
538                         else if (num >= 'a' && num <= 'j')
539                                 altanims[num - 'a'] = tx2;
540                         else
541                                 Con_Printf ("Bad animating texture %s\n", tx->name);
542                 }
543
544                 max = altmax = 0;
545                 for (j = 0;j < 10;j++)
546                 {
547                         if (anims[j])
548                                 max = j + 1;
549                         if (altanims[j])
550                                 altmax = j + 1;
551                 }
552                 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
553
554                 incomplete = false;
555                 for (j = 0;j < max;j++)
556                 {
557                         if (!anims[j])
558                         {
559                                 Con_Printf ("Missing frame %i of %s\n", j, tx->name);
560                                 incomplete = true;
561                         }
562                 }
563                 for (j = 0;j < altmax;j++)
564                 {
565                         if (!altanims[j])
566                         {
567                                 Con_Printf ("Missing altframe %i of %s\n", j, tx->name);
568                                 incomplete = true;
569                         }
570                 }
571                 if (incomplete)
572                         continue;
573
574                 if (altmax < 1)
575                 {
576                         // if there is no alternate animation, duplicate the primary
577                         // animation into the alternate
578                         altmax = max;
579                         for (k = 0;k < 10;k++)
580                                 altanims[k] = anims[k];
581                 }
582
583                 // link together the primary animation
584                 for (j = 0;j < max;j++)
585                 {
586                         tx2 = anims[j];
587                         tx2->animated = true;
588                         tx2->anim_total[0] = max;
589                         tx2->anim_total[1] = altmax;
590                         for (k = 0;k < 10;k++)
591                         {
592                                 tx2->anim_frames[0][k] = anims[k];
593                                 tx2->anim_frames[1][k] = altanims[k];
594                         }
595                 }
596
597                 // if there really is an alternate anim...
598                 if (anims[0] != altanims[0])
599                 {
600                         // link together the alternate animation
601                         for (j = 0;j < altmax;j++)
602                         {
603                                 tx2 = altanims[j];
604                                 tx2->animated = true;
605                                 // the primary/alternate are reversed here
606                                 tx2->anim_total[0] = altmax;
607                                 tx2->anim_total[1] = max;
608                                 for (k = 0;k < 10;k++)
609                                 {
610                                         tx2->anim_frames[0][k] = altanims[k];
611                                         tx2->anim_frames[1][k] = anims[k];
612                                 }
613                         }
614                 }
615         }
616 }
617
618 /*
619 =================
620 Mod_LoadLighting
621 =================
622 */
623 static void Mod_LoadLighting (lump_t *l)
624 {
625         int i;
626         qbyte *in, *out, *data, d;
627         char litfilename[1024];
628         loadmodel->lightdata = NULL;
629         if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
630         {
631                 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
632                 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
633         }
634         else // LordHavoc: bsp version 29 (normal white lighting)
635         {
636                 // LordHavoc: hope is not lost yet, check for a .lit file to load
637                 strcpy(litfilename, loadmodel->name);
638                 FS_StripExtension(litfilename, litfilename);
639                 strcat(litfilename, ".lit");
640                 data = (qbyte*) FS_LoadFile (litfilename, false);
641                 if (data)
642                 {
643                         if (fs_filesize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
644                         {
645                                 i = LittleLong(((int *)data)[1]);
646                                 if (i == 1)
647                                 {
648                                         Con_DPrintf("loaded %s\n", litfilename);
649                                         loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, fs_filesize - 8);
650                                         memcpy(loadmodel->lightdata, data + 8, fs_filesize - 8);
651                                         Mem_Free(data);
652                                         return;
653                                 }
654                                 else
655                                 {
656                                         Con_Printf("Unknown .lit file version (%d)\n", i);
657                                         Mem_Free(data);
658                                 }
659                         }
660                         else
661                         {
662                                 if (fs_filesize == 8)
663                                         Con_Printf("Empty .lit file, ignoring\n");
664                                 else
665                                         Con_Printf("Corrupt .lit file (old version?), ignoring\n");
666                                 Mem_Free(data);
667                         }
668                 }
669                 // LordHavoc: oh well, expand the white lighting data
670                 if (!l->filelen)
671                         return;
672                 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
673                 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
674                 out = loadmodel->lightdata;
675                 memcpy (in, mod_base + l->fileofs, l->filelen);
676                 for (i = 0;i < l->filelen;i++)
677                 {
678                         d = *in++;
679                         *out++ = d;
680                         *out++ = d;
681                         *out++ = d;
682                 }
683         }
684 }
685
686 void Mod_LoadLightList(void)
687 {
688         int a, n, numlights;
689         char lightsfilename[1024], *s, *t, *lightsstring;
690         mlight_t *e;
691
692         strcpy(lightsfilename, loadmodel->name);
693         FS_StripExtension(lightsfilename, lightsfilename);
694         strcat(lightsfilename, ".lights");
695         s = lightsstring = (char *) FS_LoadFile (lightsfilename, false);
696         if (s)
697         {
698                 numlights = 0;
699                 while (*s)
700                 {
701                         while (*s && *s != '\n')
702                                 s++;
703                         if (!*s)
704                         {
705                                 Mem_Free(lightsstring);
706                                 Host_Error("lights file must end with a newline\n");
707                         }
708                         s++;
709                         numlights++;
710                 }
711                 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
712                 s = lightsstring;
713                 n = 0;
714                 while (*s && n < numlights)
715                 {
716                         t = s;
717                         while (*s && *s != '\n')
718                                 s++;
719                         if (!*s)
720                         {
721                                 Mem_Free(lightsstring);
722                                 Host_Error("misparsed lights file!\n");
723                         }
724                         e = loadmodel->lights + n;
725                         *s = 0;
726                         a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &e->origin[0], &e->origin[1], &e->origin[2], &e->falloff, &e->light[0], &e->light[1], &e->light[2], &e->subtract, &e->spotdir[0], &e->spotdir[1], &e->spotdir[2], &e->spotcone, &e->distbias, &e->style);
727                         *s = '\n';
728                         if (a != 14)
729                         {
730                                 Mem_Free(lightsstring);
731                                 Host_Error("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
732                         }
733                         s++;
734                         n++;
735                 }
736                 if (*s)
737                 {
738                         Mem_Free(lightsstring);
739                         Host_Error("misparsed lights file!\n");
740                 }
741                 loadmodel->numlights = numlights;
742                 Mem_Free(lightsstring);
743         }
744 }
745
746 /*
747 static int castshadowcount = 0;
748 void Mod_ProcessLightList(void)
749 {
750         int j, k, l, *mark, lnum;
751         mlight_t *e;
752         msurface_t *surf;
753         float dist;
754         mleaf_t *leaf;
755         qbyte *pvs;
756         vec3_t temp;
757         float *v, radius2;
758         for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++)
759         {
760                 e->cullradius2 = DotProduct(e->light, e->light) / (e->falloff * e->falloff * 8192.0f * 8192.0f * 2.0f * 2.0f);// + 4096.0f;
761                 if (e->cullradius2 > 4096.0f * 4096.0f)
762                         e->cullradius2 = 4096.0f * 4096.0f;
763                 e->cullradius = e->lightradius = sqrt(e->cullradius2);
764                 leaf = Mod_PointInLeaf(e->origin, loadmodel);
765                 if (leaf->compressed_vis)
766                         pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel);
767                 else
768                         pvs = mod_novis;
769                 for (j = 0;j < loadmodel->numsurfaces;j++)
770                         loadmodel->surfacevisframes[j] = -1;
771                 for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++)
772                 {
773                         if (pvs[j >> 3] & (1 << (j & 7)))
774                         {
775                                 for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++)
776                                 {
777                                         surf = loadmodel->surfaces + *mark;
778                                         if (surf->number != *mark)
779                                                 Con_Printf("%d != %d\n", surf->number, *mark);
780                                         dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
781                                         if (surf->flags & SURF_PLANEBACK)
782                                                 dist = -dist;
783                                         if (dist > 0 && dist < e->cullradius)
784                                         {
785                                                 temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
786                                                 temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
787                                                 temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
788                                                 if (DotProduct(temp, temp) < lightradius2)
789                                                         loadmodel->surfacevisframes[*mark] = -2;
790                                         }
791                                 }
792                         }
793                 }
794                 // build list of light receiving surfaces
795                 e->numsurfaces = 0;
796                 for (j = 0;j < loadmodel->numsurfaces;j++)
797                         if (loadmodel->surfacevisframes[j] == -2)
798                                 e->numsurfaces++;
799                 e->surfaces = NULL;
800                 if (e->numsurfaces > 0)
801                 {
802                         e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
803                         e->numsurfaces = 0;
804                         for (j = 0;j < loadmodel->numsurfaces;j++)
805                                 if (loadmodel->surfacevisframes[j] == -2)
806                                         e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j;
807                 }
808                 // find bounding box and sphere of lit surfaces
809                 // (these will be used for creating a shape to clip the light)
810                 radius2 = 0;
811                 for (j = 0;j < e->numsurfaces;j++)
812                 {
813                         surf = e->surfaces[j];
814                         if (j == 0)
815                         {
816                                 VectorCopy(surf->poly_verts, e->mins);
817                                 VectorCopy(surf->poly_verts, e->maxs);
818                         }
819                         for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
820                         {
821                                 if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
822                                 if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
823                                 if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
824                                 VectorSubtract(v, e->origin, temp);
825                                 dist = DotProduct(temp, temp);
826                                 if (radius2 < dist)
827                                         radius2 = dist;
828                         }
829                 }
830                 if (e->cullradius2 > radius2)
831                 {
832                         e->cullradius2 = radius2;
833                         e->cullradius = sqrt(e->cullradius2);
834                 }
835                 if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
836                 if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
837                 if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
838                 if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
839                 if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
840                 if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
841                 // clip shadow volumes against eachother to remove unnecessary
842                 // polygons (and sections of polygons)
843                 {
844                         //vec3_t polymins, polymaxs;
845                         int maxverts = 4;
846                         float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
847                         float f, *v0, *v1, projectdistance;
848
849                         e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024);
850 #if 0
851                         {
852                         vec3_t outermins, outermaxs, innermins, innermaxs;
853                         innermins[0] = e->mins[0] - 1;
854                         innermins[1] = e->mins[1] - 1;
855                         innermins[2] = e->mins[2] - 1;
856                         innermaxs[0] = e->maxs[0] + 1;
857                         innermaxs[1] = e->maxs[1] + 1;
858                         innermaxs[2] = e->maxs[2] + 1;
859                         outermins[0] = loadmodel->normalmins[0] - 1;
860                         outermins[1] = loadmodel->normalmins[1] - 1;
861                         outermins[2] = loadmodel->normalmins[2] - 1;
862                         outermaxs[0] = loadmodel->normalmaxs[0] + 1;
863                         outermaxs[1] = loadmodel->normalmaxs[1] + 1;
864                         outermaxs[2] = loadmodel->normalmaxs[2] + 1;
865                         // add bounding box around the whole shadow volume set,
866                         // facing inward to limit light area, with an outer bounding box
867                         // facing outward (this is needed by the shadow rendering method)
868                         // X major
869                         verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
870                         verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
871                         verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
872                         verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
873                         Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
874                         verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
875                         verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
876                         verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
877                         verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
878                         Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
879                         // X minor
880                         verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
881                         verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
882                         verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
883                         verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
884                         Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
885                         verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
886                         verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
887                         verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
888                         verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
889                         Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
890                         // Y major
891                         verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
892                         verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
893                         verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
894                         verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
895                         Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
896                         verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
897                         verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
898                         verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
899                         verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
900                         Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
901                         // Y minor
902                         verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
903                         verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
904                         verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
905                         verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
906                         Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
907                         verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
908                         verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
909                         verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
910                         verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
911                         Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
912                         // Z major
913                         verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
914                         verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2];
915                         verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2];
916                         verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
917                         Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
918                         verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
919                         verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2];
920                         verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2];
921                         verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
922                         Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
923                         // Z minor
924                         verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2];
925                         verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
926                         verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
927                         verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2];
928                         Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
929                         verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2];
930                         verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
931                         verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
932                         verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2];
933                         Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
934                         }
935 #endif
936                         castshadowcount++;
937                         for (j = 0;j < e->numsurfaces;j++)
938                         {
939                                 surf = e->surfaces[j];
940                                 if (surf->flags & SURF_SHADOWCAST)
941                                         surf->castshadow = castshadowcount;
942                         }
943                         for (j = 0;j < e->numsurfaces;j++)
944                         {
945                                 surf = e->surfaces[j];
946                                 if (surf->castshadow != castshadowcount)
947                                         continue;
948                                 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
949                                 if (surf->flags & SURF_PLANEBACK)
950                                         f = -f;
951                                 projectdistance = e->lightradius;
952                                 if (maxverts < surf->poly_numverts)
953                                 {
954                                         maxverts = surf->poly_numverts;
955                                         if (verts)
956                                                 Mem_Free(verts);
957                                         verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
958                                 }
959                                 // copy the original polygon, for the front cap of the volume
960                                 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
961                                         VectorCopy(v0, v1);
962                                 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
963                                 // project the original polygon, reversed, for the back cap of the volume
964                                 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
965                                 {
966                                         VectorSubtract(v0, e->origin, temp);
967                                         VectorNormalize(temp);
968                                         VectorMA(v0, projectdistance, temp, v1);
969                                 }
970                                 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
971                                 // project the shadow volume sides
972                                 for (l = surf->poly_numverts - 1, k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;l = k, k++, v0 = v1, v1 += 3)
973                                 {
974                                         if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount)
975                                         {
976                                                 VectorCopy(v1, &verts[0]);
977                                                 VectorCopy(v0, &verts[3]);
978                                                 VectorCopy(v0, &verts[6]);
979                                                 VectorCopy(v1, &verts[9]);
980                                                 VectorSubtract(&verts[6], e->origin, temp);
981                                                 VectorNormalize(temp);
982                                                 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
983                                                 VectorSubtract(&verts[9], e->origin, temp);
984                                                 VectorNormalize(temp);
985                                                 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
986                                                 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
987                                         }
988                                 }
989                         }
990                         // build the triangle mesh
991                         e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume);
992                         {
993                                 shadowmesh_t *mesh;
994                                 l = 0;
995                                 for (mesh = e->shadowvolume;mesh;mesh = mesh->next)
996                                         l += mesh->numtriangles;
997                                 Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l);
998                         }
999                 }
1000         }
1001 }
1002 */
1003
1004
1005 /*
1006 =================
1007 Mod_LoadVisibility
1008 =================
1009 */
1010 static void Mod_LoadVisibility (lump_t *l)
1011 {
1012         loadmodel->visdata = NULL;
1013         if (!l->filelen)
1014                 return;
1015         loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
1016         memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
1017 }
1018
1019 // used only for HalfLife maps
1020 void Mod_ParseWadsFromEntityLump(const char *data)
1021 {
1022         char key[128], value[4096];
1023         char wadname[128];
1024         int i, j, k;
1025         if (!data)
1026                 return;
1027         if (!COM_ParseToken(&data))
1028                 return; // error
1029         if (com_token[0] != '{')
1030                 return; // error
1031         while (1)
1032         {
1033                 if (!COM_ParseToken(&data))
1034                         return; // error
1035                 if (com_token[0] == '}')
1036                         break; // end of worldspawn
1037                 if (com_token[0] == '_')
1038                         strcpy(key, com_token + 1);
1039                 else
1040                         strcpy(key, com_token);
1041                 while (key[strlen(key)-1] == ' ') // remove trailing spaces
1042                         key[strlen(key)-1] = 0;
1043                 if (!COM_ParseToken(&data))
1044                         return; // error
1045                 strcpy(value, com_token);
1046                 if (!strcmp("wad", key)) // for HalfLife maps
1047                 {
1048                         if (loadmodel->ishlbsp)
1049                         {
1050                                 j = 0;
1051                                 for (i = 0;i < 4096;i++)
1052                                         if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
1053                                                 break;
1054                                 if (value[i])
1055                                 {
1056                                         for (;i < 4096;i++)
1057                                         {
1058                                                 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
1059                                                 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
1060                                                         j = i+1;
1061                                                 else if (value[i] == ';' || value[i] == 0)
1062                                                 {
1063                                                         k = value[i];
1064                                                         value[i] = 0;
1065                                                         strcpy(wadname, "textures/");
1066                                                         strcat(wadname, &value[j]);
1067                                                         W_LoadTextureWadFile (wadname, false);
1068                                                         j = i+1;
1069                                                         if (!k)
1070                                                                 break;
1071                                                 }
1072                                         }
1073                                 }
1074                         }
1075                 }
1076         }
1077 }
1078
1079 /*
1080 =================
1081 Mod_LoadEntities
1082 =================
1083 */
1084 static void Mod_LoadEntities (lump_t *l)
1085 {
1086         loadmodel->entities = NULL;
1087         if (!l->filelen)
1088                 return;
1089         loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
1090         memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
1091         if (loadmodel->ishlbsp)
1092                 Mod_ParseWadsFromEntityLump(loadmodel->entities);
1093 }
1094
1095
1096 /*
1097 =================
1098 Mod_LoadVertexes
1099 =================
1100 */
1101 static void Mod_LoadVertexes (lump_t *l)
1102 {
1103         dvertex_t       *in;
1104         mvertex_t       *out;
1105         int                     i, count;
1106
1107         in = (void *)(mod_base + l->fileofs);
1108         if (l->filelen % sizeof(*in))
1109                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1110         count = l->filelen / sizeof(*in);
1111         out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1112
1113         loadmodel->vertexes = out;
1114         loadmodel->numvertexes = count;
1115
1116         for ( i=0 ; i<count ; i++, in++, out++)
1117         {
1118                 out->position[0] = LittleFloat (in->point[0]);
1119                 out->position[1] = LittleFloat (in->point[1]);
1120                 out->position[2] = LittleFloat (in->point[2]);
1121         }
1122 }
1123
1124 /*
1125 =================
1126 Mod_LoadSubmodels
1127 =================
1128 */
1129 static void Mod_LoadSubmodels (lump_t *l)
1130 {
1131         dmodel_t        *in;
1132         dmodel_t        *out;
1133         int                     i, j, count;
1134
1135         in = (void *)(mod_base + l->fileofs);
1136         if (l->filelen % sizeof(*in))
1137                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1138         count = l->filelen / sizeof(*in);
1139         out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1140
1141         loadmodel->submodels = out;
1142         loadmodel->numsubmodels = count;
1143
1144         for ( i=0 ; i<count ; i++, in++, out++)
1145         {
1146                 for (j=0 ; j<3 ; j++)
1147                 {
1148                         // spread the mins / maxs by a pixel
1149                         out->mins[j] = LittleFloat (in->mins[j]) - 1;
1150                         out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
1151                         out->origin[j] = LittleFloat (in->origin[j]);
1152                 }
1153                 for (j=0 ; j<MAX_MAP_HULLS ; j++)
1154                         out->headnode[j] = LittleLong (in->headnode[j]);
1155                 out->visleafs = LittleLong (in->visleafs);
1156                 out->firstface = LittleLong (in->firstface);
1157                 out->numfaces = LittleLong (in->numfaces);
1158         }
1159 }
1160
1161 /*
1162 =================
1163 Mod_LoadEdges
1164 =================
1165 */
1166 static void Mod_LoadEdges (lump_t *l)
1167 {
1168         dedge_t *in;
1169         medge_t *out;
1170         int     i, count;
1171
1172         in = (void *)(mod_base + l->fileofs);
1173         if (l->filelen % sizeof(*in))
1174                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1175         count = l->filelen / sizeof(*in);
1176         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1177
1178         loadmodel->edges = out;
1179         loadmodel->numedges = count;
1180
1181         for ( i=0 ; i<count ; i++, in++, out++)
1182         {
1183                 out->v[0] = (unsigned short)LittleShort(in->v[0]);
1184                 out->v[1] = (unsigned short)LittleShort(in->v[1]);
1185         }
1186 }
1187
1188 /*
1189 =================
1190 Mod_LoadTexinfo
1191 =================
1192 */
1193 static void Mod_LoadTexinfo (lump_t *l)
1194 {
1195         texinfo_t *in;
1196         mtexinfo_t *out;
1197         int i, j, k, count, miptex;
1198
1199         in = (void *)(mod_base + l->fileofs);
1200         if (l->filelen % sizeof(*in))
1201                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1202         count = l->filelen / sizeof(*in);
1203         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1204
1205         loadmodel->texinfo = out;
1206         loadmodel->numtexinfo = count;
1207
1208         for (i = 0;i < count;i++, in++, out++)
1209         {
1210                 for (k = 0;k < 2;k++)
1211                         for (j = 0;j < 4;j++)
1212                                 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
1213
1214                 miptex = LittleLong (in->miptex);
1215                 out->flags = LittleLong (in->flags);
1216
1217                 out->texture = NULL;
1218                 if (loadmodel->textures)
1219                 {
1220                         if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
1221                                 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
1222                         else
1223                                 out->texture = loadmodel->textures + miptex;
1224                 }
1225                 if (out->flags & TEX_SPECIAL)
1226                 {
1227                         // if texture chosen is NULL or the shader needs a lightmap,
1228                         // force to notexture water shader
1229                         if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
1230                                 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
1231                 }
1232                 else
1233                 {
1234                         // if texture chosen is NULL, force to notexture
1235                         if (out->texture == NULL)
1236                                 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
1237                 }
1238         }
1239 }
1240
1241 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1242 {
1243         int             i, j;
1244         float   *v;
1245
1246         mins[0] = mins[1] = mins[2] = 9999;
1247         maxs[0] = maxs[1] = maxs[2] = -9999;
1248         v = verts;
1249         for (i = 0;i < numverts;i++)
1250         {
1251                 for (j = 0;j < 3;j++, v++)
1252                 {
1253                         if (*v < mins[j])
1254                                 mins[j] = *v;
1255                         if (*v > maxs[j])
1256                                 maxs[j] = *v;
1257                 }
1258         }
1259 }
1260
1261 #if 0
1262 #define MAX_SUBDIVPOLYTRIANGLES 4096
1263 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1264
1265 static int subdivpolyverts, subdivpolytriangles;
1266 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1267 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1268
1269 static int subdivpolylookupvert(vec3_t v)
1270 {
1271         int i;
1272         for (i = 0;i < subdivpolyverts;i++)
1273                 if (subdivpolyvert[i][0] == v[0]
1274                  && subdivpolyvert[i][1] == v[1]
1275                  && subdivpolyvert[i][2] == v[2])
1276                         return i;
1277         if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1278                 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1279         VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1280         return subdivpolyverts++;
1281 }
1282
1283 static void SubdividePolygon (int numverts, float *verts)
1284 {
1285         int             i, i1, i2, i3, f, b, c, p;
1286         vec3_t  mins, maxs, front[256], back[256];
1287         float   m, *pv, *cv, dist[256], frac;
1288
1289         if (numverts > 250)
1290                 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1291
1292         BoundPoly (numverts, verts, mins, maxs);
1293
1294         for (i = 0;i < 3;i++)
1295         {
1296                 m = (mins[i] + maxs[i]) * 0.5;
1297                 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1298                 if (maxs[i] - m < 8)
1299                         continue;
1300                 if (m - mins[i] < 8)
1301                         continue;
1302
1303                 // cut it
1304                 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1305                         dist[c] = cv[i] - m;
1306
1307                 f = b = 0;
1308                 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1309                 {
1310                         if (dist[p] >= 0)
1311                         {
1312                                 VectorCopy (pv, front[f]);
1313                                 f++;
1314                         }
1315                         if (dist[p] <= 0)
1316                         {
1317                                 VectorCopy (pv, back[b]);
1318                                 b++;
1319                         }
1320                         if (dist[p] == 0 || dist[c] == 0)
1321                                 continue;
1322                         if ( (dist[p] > 0) != (dist[c] > 0) )
1323                         {
1324                                 // clip point
1325                                 frac = dist[p] / (dist[p] - dist[c]);
1326                                 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1327                                 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1328                                 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1329                                 f++;
1330                                 b++;
1331                         }
1332                 }
1333
1334                 SubdividePolygon (f, front[0]);
1335                 SubdividePolygon (b, back[0]);
1336                 return;
1337         }
1338
1339         i1 = subdivpolylookupvert(verts);
1340         i2 = subdivpolylookupvert(verts + 3);
1341         for (i = 2;i < numverts;i++)
1342         {
1343                 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1344                 {
1345                         Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1346                         return;
1347                 }
1348
1349                 i3 = subdivpolylookupvert(verts + i * 3);
1350                 subdivpolyindex[subdivpolytriangles][0] = i1;
1351                 subdivpolyindex[subdivpolytriangles][1] = i2;
1352                 subdivpolyindex[subdivpolytriangles][2] = i3;
1353                 i2 = i3;
1354                 subdivpolytriangles++;
1355         }
1356 }
1357
1358 /*
1359 ================
1360 Mod_GenerateWarpMesh
1361
1362 Breaks a polygon up along axial 64 unit
1363 boundaries so that turbulent and sky warps
1364 can be done reasonably.
1365 ================
1366 */
1367 void Mod_GenerateWarpMesh (msurface_t *surf)
1368 {
1369         int i, j;
1370         surfvertex_t *v;
1371         surfmesh_t *mesh;
1372
1373         subdivpolytriangles = 0;
1374         subdivpolyverts = 0;
1375         SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1376         if (subdivpolytriangles < 1)
1377                 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1378
1379         surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1380         mesh->numverts = subdivpolyverts;
1381         mesh->numtriangles = subdivpolytriangles;
1382         mesh->vertex = (surfvertex_t *)(mesh + 1);
1383         mesh->index = (int *)(mesh->vertex + mesh->numverts);
1384         memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1385
1386         for (i = 0;i < mesh->numtriangles;i++)
1387                 for (j = 0;j < 3;j++)
1388                         mesh->index[i*3+j] = subdivpolyindex[i][j];
1389
1390         for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1391         {
1392                 VectorCopy(subdivpolyvert[i], v->v);
1393                 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1394                 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1395         }
1396 }
1397 #endif
1398
1399 surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles)
1400 {
1401         surfmesh_t *mesh;
1402         mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (3 + 2 + 2 + 2 + 3 + 3 + 3 + 1) * sizeof(float));
1403         mesh->numverts = numverts;
1404         mesh->numtriangles = numtriangles;
1405         mesh->vertex3f = (float *)(mesh + 1);
1406         mesh->texcoordtexture2f = mesh->vertex3f + mesh->numverts * 3;
1407         mesh->texcoordlightmap2f = mesh->texcoordtexture2f + mesh->numverts * 2;
1408         mesh->texcoorddetail2f = mesh->texcoordlightmap2f + mesh->numverts * 2;
1409         mesh->svector3f = (float *)(mesh->texcoorddetail2f + mesh->numverts * 2);
1410         mesh->tvector3f = mesh->svector3f + mesh->numverts * 3;
1411         mesh->normal3f = mesh->tvector3f + mesh->numverts * 3;
1412         mesh->lightmapoffsets = (int *)(mesh->normal3f + mesh->numverts * 3);
1413         mesh->element3i = mesh->lightmapoffsets + mesh->numverts;
1414         mesh->neighbor3i = mesh->element3i + mesh->numtriangles * 3;
1415         return mesh;
1416 }
1417
1418 void Mod_GenerateSurfacePolygon (msurface_t *surf, int firstedge, int numedges)
1419 {
1420         int i, lindex, j;
1421         float *vec, *vert, mins[3], maxs[3], val, *v;
1422         mtexinfo_t *tex;
1423
1424         // convert edges back to a normal polygon
1425         surf->poly_numverts = numedges;
1426         vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * numedges);
1427         for (i = 0;i < numedges;i++)
1428         {
1429                 lindex = loadmodel->surfedges[firstedge + i];
1430                 if (lindex > 0)
1431                         vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1432                 else
1433                         vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1434                 VectorCopy (vec, vert);
1435                 vert += 3;
1436         }
1437
1438         // calculate polygon bounding box and center
1439         vert = surf->poly_verts;
1440         VectorCopy(vert, mins);
1441         VectorCopy(vert, maxs);
1442         vert += 3;
1443         for (i = 1;i < surf->poly_numverts;i++, vert += 3)
1444         {
1445                 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1446                 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1447                 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1448         }
1449         VectorCopy(mins, surf->poly_mins);
1450         VectorCopy(maxs, surf->poly_maxs);
1451         surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1452         surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1453         surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1454
1455         // generate surface extents information
1456         tex = surf->texinfo;
1457         mins[0] = maxs[0] = DotProduct(surf->poly_verts, tex->vecs[0]) + tex->vecs[0][3];
1458         mins[1] = maxs[1] = DotProduct(surf->poly_verts, tex->vecs[1]) + tex->vecs[1][3];
1459         for (i = 1, v = surf->poly_verts + 3;i < surf->poly_numverts;i++, v += 3)
1460         {
1461                 for (j = 0;j < 2;j++)
1462                 {
1463                         val = DotProduct(v, tex->vecs[j]) + tex->vecs[j][3];
1464                         if (mins[j] > val)
1465                                 mins[j] = val;
1466                         if (maxs[j] < val)
1467                                 maxs[j] = val;
1468                 }
1469         }
1470         for (i = 0;i < 2;i++)
1471         {
1472                 surf->texturemins[i] = (int) floor(mins[i] / 16) * 16;
1473                 surf->extents[i] = (int) ceil(maxs[i] / 16) * 16 - surf->texturemins[i];
1474         }
1475 }
1476
1477 /*
1478 =================
1479 Mod_LoadFaces
1480 =================
1481 */
1482 static void Mod_LoadFaces (lump_t *l)
1483 {
1484         dface_t *in;
1485         msurface_t *surf;
1486         int i, count, surfnum, planenum, ssize, tsize, firstedge, numedges, totalverts, totaltris, totalmeshes;
1487         surfmesh_t *mesh;
1488         float s, t;
1489
1490         in = (void *)(mod_base + l->fileofs);
1491         if (l->filelen % sizeof(*in))
1492                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1493         count = l->filelen / sizeof(*in);
1494         loadmodel->surfaces = Mem_Alloc(loadmodel->mempool, count*sizeof(msurface_t));
1495
1496         loadmodel->numsurfaces = count;
1497         loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1498         loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1499         loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1500
1501         for (surfnum = 0, surf = loadmodel->surfaces, totalverts = 0, totaltris = 0, totalmeshes = 0;surfnum < count;surfnum++, totalverts += surf->poly_numverts, totaltris += surf->poly_numverts - 2, totalmeshes++, in++, surf++)
1502         {
1503                 surf->number = surfnum;
1504                 // FIXME: validate edges, texinfo, etc?
1505                 firstedge = LittleLong(in->firstedge);
1506                 numedges = LittleShort(in->numedges);
1507                 if ((unsigned int) firstedge > (unsigned int) loadmodel->numsurfedges || (unsigned int) numedges > (unsigned int) loadmodel->numsurfedges || (unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->numsurfedges)
1508                         Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->numsurfedges);
1509                 i = LittleShort (in->texinfo);
1510                 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1511                         Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1512                 surf->texinfo = loadmodel->texinfo + i;
1513                 surf->flags = surf->texinfo->texture->flags;
1514
1515                 planenum = LittleShort(in->planenum);
1516                 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1517                         Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1518
1519                 if (LittleShort(in->side))
1520                         surf->flags |= SURF_PLANEBACK;
1521
1522                 surf->plane = loadmodel->planes + planenum;
1523
1524                 // clear lightmap (filled in later)
1525                 surf->lightmaptexture = NULL;
1526
1527                 // force lightmap upload on first time seeing the surface
1528                 surf->cached_dlight = true;
1529
1530                 Mod_GenerateSurfacePolygon(surf, firstedge, numedges);
1531
1532                 ssize = (surf->extents[0] >> 4) + 1;
1533                 tsize = (surf->extents[1] >> 4) + 1;
1534
1535                 // lighting info
1536                 for (i = 0;i < MAXLIGHTMAPS;i++)
1537                         surf->styles[i] = in->styles[i];
1538                 i = LittleLong(in->lightofs);
1539                 if (i == -1)
1540                         surf->samples = NULL;
1541                 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1542                         surf->samples = loadmodel->lightdata + i;
1543                 else // LordHavoc: white lighting (bsp version 29)
1544                         surf->samples = loadmodel->lightdata + (i * 3);
1545
1546                 if (surf->texinfo->texture->shader == &Cshader_wall_lightmap)
1547                 {
1548                         if ((surf->extents[0] >> 4) + 1 > (256) || (surf->extents[1] >> 4) + 1 > (256))
1549                                 Host_Error ("Bad surface extents");
1550                         // stainmap for permanent marks on walls
1551                         surf->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1552                         // clear to white
1553                         memset(surf->stainsamples, 255, ssize * tsize * 3);
1554                 }
1555         }
1556
1557         loadmodel->entiremesh = Mod_AllocSurfMesh(totalverts, totaltris);
1558         loadmodel->surfmeshes = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) * totalmeshes);
1559
1560         for (surfnum = 0, surf = loadmodel->surfaces, totalverts = 0, totaltris = 0, totalmeshes = 0;surfnum < count;surfnum++, totalverts += surf->poly_numverts, totaltris += surf->poly_numverts - 2, totalmeshes++, surf++)
1561         {
1562                 mesh = surf->mesh = loadmodel->surfmeshes + totalmeshes;
1563                 mesh->numverts = surf->poly_numverts;
1564                 mesh->numtriangles = surf->poly_numverts - 2;
1565                 mesh->vertex3f = loadmodel->entiremesh->vertex3f + totalverts * 3;
1566                 mesh->texcoordtexture2f = loadmodel->entiremesh->texcoordtexture2f + totalverts * 2;
1567                 mesh->texcoordlightmap2f = loadmodel->entiremesh->texcoordlightmap2f + totalverts * 2;
1568                 mesh->texcoorddetail2f = loadmodel->entiremesh->texcoorddetail2f + totalverts * 2;
1569                 mesh->svector3f = loadmodel->entiremesh->svector3f + totalverts * 3;
1570                 mesh->tvector3f = loadmodel->entiremesh->tvector3f + totalverts * 3;
1571                 mesh->normal3f = loadmodel->entiremesh->normal3f + totalverts * 3;
1572                 mesh->lightmapoffsets = loadmodel->entiremesh->lightmapoffsets + totalverts;
1573                 mesh->element3i = loadmodel->entiremesh->element3i + totaltris * 3;
1574                 mesh->neighbor3i = loadmodel->entiremesh->neighbor3i + totaltris * 3;
1575
1576                 surf->lightmaptexturestride = 0;
1577                 surf->lightmaptexture = NULL;
1578
1579                 for (i = 0;i < mesh->numverts;i++)
1580                 {
1581                         mesh->vertex3f[i * 3 + 0] = surf->poly_verts[i * 3 + 0];
1582                         mesh->vertex3f[i * 3 + 1] = surf->poly_verts[i * 3 + 1];
1583                         mesh->vertex3f[i * 3 + 2] = surf->poly_verts[i * 3 + 2];
1584                         s = DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1585                         t = DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1586                         mesh->texcoordtexture2f[i * 2 + 0] = s / surf->texinfo->texture->width;
1587                         mesh->texcoordtexture2f[i * 2 + 1] = t / surf->texinfo->texture->height;
1588                         mesh->texcoorddetail2f[i * 2 + 0] = s * (1.0f / 16.0f);
1589                         mesh->texcoorddetail2f[i * 2 + 1] = t * (1.0f / 16.0f);
1590                         mesh->texcoordlightmap2f[i * 2 + 0] = 0;
1591                         mesh->texcoordlightmap2f[i * 2 + 1] = 0;
1592                         mesh->lightmapoffsets[i] = 0;
1593                 }
1594
1595                 for (i = 0;i < mesh->numtriangles;i++)
1596                 {
1597                         mesh->element3i[i * 3 + 0] = 0;
1598                         mesh->element3i[i * 3 + 1] = i + 1;
1599                         mesh->element3i[i * 3 + 2] = i + 2;
1600                 }
1601
1602                 Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1603                 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->vertex3f, mesh->texcoordtexture2f, mesh->element3i, mesh->svector3f, mesh->tvector3f, mesh->normal3f);
1604
1605                 if (surf->texinfo->texture->shader == &Cshader_wall_lightmap)
1606                 {
1607                         int i, iu, iv, smax, tmax;
1608                         float u, v, ubase, vbase, uscale, vscale;
1609
1610                         smax = surf->extents[0] >> 4;
1611                         tmax = surf->extents[1] >> 4;
1612
1613                         surf->flags |= SURF_LIGHTMAP;
1614                         if (r_miplightmaps.integer)
1615                         {
1616                                 surf->lightmaptexturestride = smax+1;
1617                                 surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
1618                         }
1619                         else
1620                         {
1621                                 surf->lightmaptexturestride = R_CompatibleFragmentWidth(smax+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1622                                 surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
1623                         }
1624                         R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1625                         uscale = (uscale - ubase) / (smax + 1);
1626                         vscale = (vscale - vbase) / (tmax + 1);
1627
1628                         for (i = 0;i < mesh->numverts;i++)
1629                         {
1630                                 u = ((DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1631                                 v = ((DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1632                                 mesh->texcoordlightmap2f[i * 2 + 0] = u * uscale + ubase;
1633                                 mesh->texcoordlightmap2f[i * 2 + 1] = v * vscale + vbase;
1634                                 // LordHavoc: calc lightmap data offset for vertex lighting to use
1635                                 iu = (int) u;
1636                                 iv = (int) v;
1637                                 mesh->lightmapoffsets[i] = (bound(0, iv, tmax) * (smax+1) + bound(0, iu, smax)) * 3;
1638                         }
1639                 }
1640         }
1641 }
1642
1643 /*
1644 =================
1645 Mod_SetParent
1646 =================
1647 */
1648 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1649 {
1650         node->parent = parent;
1651         if (node->contents < 0)
1652                 return;
1653         Mod_SetParent (node->children[0], node);
1654         Mod_SetParent (node->children[1], node);
1655 }
1656
1657 /*
1658 =================
1659 Mod_LoadNodes
1660 =================
1661 */
1662 static void Mod_LoadNodes (lump_t *l)
1663 {
1664         int                     i, j, count, p;
1665         dnode_t         *in;
1666         mnode_t         *out;
1667
1668         in = (void *)(mod_base + l->fileofs);
1669         if (l->filelen % sizeof(*in))
1670                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1671         count = l->filelen / sizeof(*in);
1672         out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1673
1674         loadmodel->nodes = out;
1675         loadmodel->numnodes = count;
1676
1677         for ( i=0 ; i<count ; i++, in++, out++)
1678         {
1679                 for (j=0 ; j<3 ; j++)
1680                 {
1681                         out->mins[j] = LittleShort (in->mins[j]);
1682                         out->maxs[j] = LittleShort (in->maxs[j]);
1683                 }
1684
1685                 p = LittleLong(in->planenum);
1686                 out->plane = loadmodel->planes + p;
1687
1688                 out->firstsurface = LittleShort (in->firstface);
1689                 out->numsurfaces = LittleShort (in->numfaces);
1690
1691                 for (j=0 ; j<2 ; j++)
1692                 {
1693                         p = LittleShort (in->children[j]);
1694                         if (p >= 0)
1695                                 out->children[j] = loadmodel->nodes + p;
1696                         else
1697                                 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1698                 }
1699         }
1700
1701         Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1702 }
1703
1704 /*
1705 =================
1706 Mod_LoadLeafs
1707 =================
1708 */
1709 static void Mod_LoadLeafs (lump_t *l)
1710 {
1711         dleaf_t         *in;
1712         mleaf_t         *out;
1713         int                     i, j, count, p;
1714
1715         in = (void *)(mod_base + l->fileofs);
1716         if (l->filelen % sizeof(*in))
1717                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1718         count = l->filelen / sizeof(*in);
1719         out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1720
1721         loadmodel->leafs = out;
1722         loadmodel->numleafs = count;
1723
1724         for ( i=0 ; i<count ; i++, in++, out++)
1725         {
1726                 for (j=0 ; j<3 ; j++)
1727                 {
1728                         out->mins[j] = LittleShort (in->mins[j]);
1729                         out->maxs[j] = LittleShort (in->maxs[j]);
1730                 }
1731
1732                 p = LittleLong(in->contents);
1733                 out->contents = p;
1734
1735                 out->firstmarksurface = loadmodel->marksurfaces +
1736                         LittleShort(in->firstmarksurface);
1737                 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1738
1739                 p = LittleLong(in->visofs);
1740                 if (p == -1)
1741                         out->compressed_vis = NULL;
1742                 else
1743                         out->compressed_vis = loadmodel->visdata + p;
1744
1745                 for (j=0 ; j<4 ; j++)
1746                         out->ambient_sound_level[j] = in->ambient_level[j];
1747
1748                 // FIXME: Insert caustics here
1749         }
1750 }
1751
1752 /*
1753 =================
1754 Mod_LoadClipnodes
1755 =================
1756 */
1757 static void Mod_LoadClipnodes (lump_t *l)
1758 {
1759         dclipnode_t *in, *out;
1760         int                     i, count;
1761         hull_t          *hull;
1762
1763         in = (void *)(mod_base + l->fileofs);
1764         if (l->filelen % sizeof(*in))
1765                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1766         count = l->filelen / sizeof(*in);
1767         out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1768
1769         loadmodel->clipnodes = out;
1770         loadmodel->numclipnodes = count;
1771
1772         if (loadmodel->ishlbsp)
1773         {
1774                 hull = &loadmodel->hulls[1];
1775                 hull->clipnodes = out;
1776                 hull->firstclipnode = 0;
1777                 hull->lastclipnode = count-1;
1778                 hull->planes = loadmodel->planes;
1779                 hull->clip_mins[0] = -16;
1780                 hull->clip_mins[1] = -16;
1781                 hull->clip_mins[2] = -36;
1782                 hull->clip_maxs[0] = 16;
1783                 hull->clip_maxs[1] = 16;
1784                 hull->clip_maxs[2] = 36;
1785                 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1786
1787                 hull = &loadmodel->hulls[2];
1788                 hull->clipnodes = out;
1789                 hull->firstclipnode = 0;
1790                 hull->lastclipnode = count-1;
1791                 hull->planes = loadmodel->planes;
1792                 hull->clip_mins[0] = -32;
1793                 hull->clip_mins[1] = -32;
1794                 hull->clip_mins[2] = -32;
1795                 hull->clip_maxs[0] = 32;
1796                 hull->clip_maxs[1] = 32;
1797                 hull->clip_maxs[2] = 32;
1798                 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1799
1800                 hull = &loadmodel->hulls[3];
1801                 hull->clipnodes = out;
1802                 hull->firstclipnode = 0;
1803                 hull->lastclipnode = count-1;
1804                 hull->planes = loadmodel->planes;
1805                 hull->clip_mins[0] = -16;
1806                 hull->clip_mins[1] = -16;
1807                 hull->clip_mins[2] = -18;
1808                 hull->clip_maxs[0] = 16;
1809                 hull->clip_maxs[1] = 16;
1810                 hull->clip_maxs[2] = 18;
1811                 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1812         }
1813         else
1814         {
1815                 hull = &loadmodel->hulls[1];
1816                 hull->clipnodes = out;
1817                 hull->firstclipnode = 0;
1818                 hull->lastclipnode = count-1;
1819                 hull->planes = loadmodel->planes;
1820                 hull->clip_mins[0] = -16;
1821                 hull->clip_mins[1] = -16;
1822                 hull->clip_mins[2] = -24;
1823                 hull->clip_maxs[0] = 16;
1824                 hull->clip_maxs[1] = 16;
1825                 hull->clip_maxs[2] = 32;
1826                 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1827
1828                 hull = &loadmodel->hulls[2];
1829                 hull->clipnodes = out;
1830                 hull->firstclipnode = 0;
1831                 hull->lastclipnode = count-1;
1832                 hull->planes = loadmodel->planes;
1833                 hull->clip_mins[0] = -32;
1834                 hull->clip_mins[1] = -32;
1835                 hull->clip_mins[2] = -24;
1836                 hull->clip_maxs[0] = 32;
1837                 hull->clip_maxs[1] = 32;
1838                 hull->clip_maxs[2] = 64;
1839                 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1840         }
1841
1842         for (i=0 ; i<count ; i++, out++, in++)
1843         {
1844                 out->planenum = LittleLong(in->planenum);
1845                 out->children[0] = LittleShort(in->children[0]);
1846                 out->children[1] = LittleShort(in->children[1]);
1847                 if (out->children[0] >= count || out->children[1] >= count)
1848                         Host_Error("Corrupt clipping hull (out of range child)\n");
1849         }
1850 }
1851
1852 /*
1853 =================
1854 Mod_MakeHull0
1855
1856 Duplicate the drawing hull structure as a clipping hull
1857 =================
1858 */
1859 static void Mod_MakeHull0 (void)
1860 {
1861         mnode_t         *in;
1862         dclipnode_t *out;
1863         int                     i;
1864         hull_t          *hull;
1865
1866         hull = &loadmodel->hulls[0];
1867
1868         in = loadmodel->nodes;
1869         out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1870
1871         hull->clipnodes = out;
1872         hull->firstclipnode = 0;
1873         hull->lastclipnode = loadmodel->numnodes - 1;
1874         hull->planes = loadmodel->planes;
1875
1876         for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1877         {
1878                 out->planenum = in->plane - loadmodel->planes;
1879                 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1880                 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1881         }
1882 }
1883
1884 /*
1885 =================
1886 Mod_LoadMarksurfaces
1887 =================
1888 */
1889 static void Mod_LoadMarksurfaces (lump_t *l)
1890 {
1891         int i, j;
1892         short *in;
1893
1894         in = (void *)(mod_base + l->fileofs);
1895         if (l->filelen % sizeof(*in))
1896                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1897         loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1898         loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1899
1900         for (i = 0;i < loadmodel->nummarksurfaces;i++)
1901         {
1902                 j = (unsigned) LittleShort(in[i]);
1903                 if (j >= loadmodel->numsurfaces)
1904                         Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1905                 loadmodel->marksurfaces[i] = j;
1906         }
1907 }
1908
1909 /*
1910 =================
1911 Mod_LoadSurfedges
1912 =================
1913 */
1914 static void Mod_LoadSurfedges (lump_t *l)
1915 {
1916         int             i;
1917         int             *in;
1918
1919         in = (void *)(mod_base + l->fileofs);
1920         if (l->filelen % sizeof(*in))
1921                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1922         loadmodel->numsurfedges = l->filelen / sizeof(*in);
1923         loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1924
1925         for (i = 0;i < loadmodel->numsurfedges;i++)
1926                 loadmodel->surfedges[i] = LittleLong (in[i]);
1927 }
1928
1929
1930 /*
1931 =================
1932 Mod_LoadPlanes
1933 =================
1934 */
1935 static void Mod_LoadPlanes (lump_t *l)
1936 {
1937         int                     i;
1938         mplane_t        *out;
1939         dplane_t        *in;
1940
1941         in = (void *)(mod_base + l->fileofs);
1942         if (l->filelen % sizeof(*in))
1943                 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1944
1945         loadmodel->numplanes = l->filelen / sizeof(*in);
1946         loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1947
1948         for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1949         {
1950                 out->normal[0] = LittleFloat (in->normal[0]);
1951                 out->normal[1] = LittleFloat (in->normal[1]);
1952                 out->normal[2] = LittleFloat (in->normal[2]);
1953                 out->dist = LittleFloat (in->dist);
1954
1955                 PlaneClassify(out);
1956         }
1957 }
1958
1959 #define MAX_POINTS_ON_WINDING 64
1960
1961 typedef struct
1962 {
1963         int numpoints;
1964         int padding;
1965         double points[8][3]; // variable sized
1966 }
1967 winding_t;
1968
1969 /*
1970 ==================
1971 NewWinding
1972 ==================
1973 */
1974 static winding_t *NewWinding (int points)
1975 {
1976         winding_t *w;
1977         int size;
1978
1979         if (points > MAX_POINTS_ON_WINDING)
1980                 Sys_Error("NewWinding: too many points\n");
1981
1982         size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
1983         w = Mem_Alloc(loadmodel->mempool, size);
1984         memset (w, 0, size);
1985
1986         return w;
1987 }
1988
1989 static void FreeWinding (winding_t *w)
1990 {
1991         Mem_Free(w);
1992 }
1993
1994 /*
1995 =================
1996 BaseWindingForPlane
1997 =================
1998 */
1999 static winding_t *BaseWindingForPlane (mplane_t *p)
2000 {
2001         double org[3], vright[3], vup[3], normal[3];
2002         winding_t *w;
2003
2004         VectorCopy(p->normal, normal);
2005         VectorVectorsDouble(normal, vright, vup);
2006
2007         VectorScale (vup, 1024.0*1024.0*1024.0, vup);
2008         VectorScale (vright, 1024.0*1024.0*1024.0, vright);
2009
2010         // project a really big axis aligned box onto the plane
2011         w = NewWinding (4);
2012
2013         VectorScale (p->normal, p->dist, org);
2014
2015         VectorSubtract (org, vright, w->points[0]);
2016         VectorAdd (w->points[0], vup, w->points[0]);
2017
2018         VectorAdd (org, vright, w->points[1]);
2019         VectorAdd (w->points[1], vup, w->points[1]);
2020
2021         VectorAdd (org, vright, w->points[2]);
2022         VectorSubtract (w->points[2], vup, w->points[2]);
2023
2024         VectorSubtract (org, vright, w->points[3]);
2025         VectorSubtract (w->points[3], vup, w->points[3]);
2026
2027         w->numpoints = 4;
2028
2029         return w;
2030 }
2031
2032 /*
2033 ==================
2034 ClipWinding
2035
2036 Clips the winding to the plane, returning the new winding on the positive side
2037 Frees the input winding.
2038 If keepon is true, an exactly on-plane winding will be saved, otherwise
2039 it will be clipped away.
2040 ==================
2041 */
2042 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2043 {
2044         double  dists[MAX_POINTS_ON_WINDING + 1];
2045         int             sides[MAX_POINTS_ON_WINDING + 1];
2046         int             counts[3];
2047         double  dot;
2048         int             i, j;
2049         double  *p1, *p2;
2050         double  mid[3];
2051         winding_t       *neww;
2052         int             maxpts;
2053
2054         counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2055
2056         // determine sides for each point
2057         for (i = 0;i < in->numpoints;i++)
2058         {
2059                 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2060                 if (dot > ON_EPSILON)
2061                         sides[i] = SIDE_FRONT;
2062                 else if (dot < -ON_EPSILON)
2063                         sides[i] = SIDE_BACK;
2064                 else
2065                         sides[i] = SIDE_ON;
2066                 counts[sides[i]]++;
2067         }
2068         sides[i] = sides[0];
2069         dists[i] = dists[0];
2070
2071         if (keepon && !counts[0] && !counts[1])
2072                 return in;
2073
2074         if (!counts[0])
2075         {
2076                 FreeWinding (in);
2077                 return NULL;
2078         }
2079         if (!counts[1])
2080                 return in;
2081
2082         maxpts = in->numpoints+4;       // can't use counts[0]+2 because of fp grouping errors
2083         if (maxpts > MAX_POINTS_ON_WINDING)
2084                 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2085
2086         neww = NewWinding (maxpts);
2087
2088         for (i = 0;i < in->numpoints;i++)
2089         {
2090                 if (neww->numpoints >= maxpts)
2091                         Sys_Error ("ClipWinding: points exceeded estimate");
2092
2093                 p1 = in->points[i];
2094
2095                 if (sides[i] == SIDE_ON)
2096                 {
2097                         VectorCopy (p1, neww->points[neww->numpoints]);
2098                         neww->numpoints++;
2099                         continue;
2100                 }
2101
2102                 if (sides[i] == SIDE_FRONT)
2103                 {
2104                         VectorCopy (p1, neww->points[neww->numpoints]);
2105                         neww->numpoints++;
2106                 }
2107
2108                 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2109                         continue;
2110
2111                 // generate a split point
2112                 p2 = in->points[(i+1)%in->numpoints];
2113
2114                 dot = dists[i] / (dists[i]-dists[i+1]);
2115                 for (j = 0;j < 3;j++)
2116                 {       // avoid round off error when possible
2117                         if (split->normal[j] == 1)
2118                                 mid[j] = split->dist;
2119                         else if (split->normal[j] == -1)
2120                                 mid[j] = -split->dist;
2121                         else
2122                                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2123                 }
2124
2125                 VectorCopy (mid, neww->points[neww->numpoints]);
2126                 neww->numpoints++;
2127         }
2128
2129         // free the original winding
2130         FreeWinding (in);
2131
2132         return neww;
2133 }
2134
2135
2136 /*
2137 ==================
2138 DivideWinding
2139
2140 Divides a winding by a plane, producing one or two windings.  The
2141 original winding is not damaged or freed.  If only on one side, the
2142 returned winding will be the input winding.  If on both sides, two
2143 new windings will be created.
2144 ==================
2145 */
2146 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2147 {
2148         double  dists[MAX_POINTS_ON_WINDING + 1];
2149         int             sides[MAX_POINTS_ON_WINDING + 1];
2150         int             counts[3];
2151         double  dot;
2152         int             i, j;
2153         double  *p1, *p2;
2154         double  mid[3];
2155         winding_t       *f, *b;
2156         int             maxpts;
2157
2158         counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2159
2160         // determine sides for each point
2161         for (i = 0;i < in->numpoints;i++)
2162         {
2163                 dot = DotProduct (in->points[i], split->normal);
2164                 dot -= split->dist;
2165                 dists[i] = dot;
2166                 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2167                 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2168                 else sides[i] = SIDE_ON;
2169                 counts[sides[i]]++;
2170         }
2171         sides[i] = sides[0];
2172         dists[i] = dists[0];
2173
2174         *front = *back = NULL;
2175
2176         if (!counts[0])
2177         {
2178                 *back = in;
2179                 return;
2180         }
2181         if (!counts[1])
2182         {
2183                 *front = in;
2184                 return;
2185         }
2186
2187         maxpts = in->numpoints+4;       // can't use counts[0]+2 because of fp grouping errors
2188
2189         if (maxpts > MAX_POINTS_ON_WINDING)
2190                 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2191
2192         *front = f = NewWinding (maxpts);
2193         *back = b = NewWinding (maxpts);
2194
2195         for (i = 0;i < in->numpoints;i++)
2196         {
2197                 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2198                         Sys_Error ("DivideWinding: points exceeded estimate");
2199
2200                 p1 = in->points[i];
2201
2202                 if (sides[i] == SIDE_ON)
2203                 {
2204                         VectorCopy (p1, f->points[f->numpoints]);
2205                         f->numpoints++;
2206                         VectorCopy (p1, b->points[b->numpoints]);
2207                         b->numpoints++;
2208                         continue;
2209                 }
2210
2211                 if (sides[i] == SIDE_FRONT)
2212                 {
2213                         VectorCopy (p1, f->points[f->numpoints]);
2214                         f->numpoints++;
2215                 }
2216                 else if (sides[i] == SIDE_BACK)
2217                 {
2218                         VectorCopy (p1, b->points[b->numpoints]);
2219                         b->numpoints++;
2220                 }
2221
2222                 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2223                         continue;
2224
2225                 // generate a split point
2226                 p2 = in->points[(i+1)%in->numpoints];
2227
2228                 dot = dists[i] / (dists[i]-dists[i+1]);
2229                 for (j = 0;j < 3;j++)
2230                 {       // avoid round off error when possible
2231                         if (split->normal[j] == 1)
2232                                 mid[j] = split->dist;
2233                         else if (split->normal[j] == -1)
2234                                 mid[j] = -split->dist;
2235                         else
2236                                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2237                 }
2238
2239                 VectorCopy (mid, f->points[f->numpoints]);
2240                 f->numpoints++;
2241                 VectorCopy (mid, b->points[b->numpoints]);
2242                 b->numpoints++;
2243         }
2244 }
2245
2246 typedef struct portal_s
2247 {
2248         mplane_t plane;
2249         mnode_t *nodes[2];              // [0] = front side of plane
2250         struct portal_s *next[2];
2251         winding_t *winding;
2252         struct portal_s *chain; // all portals are linked into a list
2253 }
2254 portal_t;
2255
2256 static portal_t *portalchain;
2257
2258 /*
2259 ===========
2260 AllocPortal
2261 ===========
2262 */
2263 static portal_t *AllocPortal (void)
2264 {
2265         portal_t *p;
2266         p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2267         p->chain = portalchain;
2268         portalchain = p;
2269         return p;
2270 }
2271
2272 static void FreePortal(portal_t *p)
2273 {
2274         Mem_Free(p);
2275 }
2276
2277 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2278 {
2279         // calculate children first
2280         if (node->children[0]->contents >= 0)
2281                 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2282         if (node->children[1]->contents >= 0)
2283                 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2284
2285         // make combined bounding box from children
2286         node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2287         node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2288         node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2289         node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2290         node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2291         node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2292 }
2293
2294 static void Mod_FinalizePortals(void)
2295 {
2296         int i, j, numportals, numpoints;
2297         portal_t *p, *pnext;
2298         mportal_t *portal;
2299         mvertex_t *point;
2300         mleaf_t *leaf, *endleaf;
2301         winding_t *w;
2302
2303         // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2304         leaf = loadmodel->leafs;
2305         endleaf = leaf + loadmodel->numleafs;
2306         for (;leaf < endleaf;leaf++)
2307         {
2308                 VectorSet(leaf->mins,  2000000000,  2000000000,  2000000000);
2309                 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2310         }
2311         p = portalchain;
2312         while(p)
2313         {
2314                 if (p->winding)
2315                 {
2316                         for (i = 0;i < 2;i++)
2317                         {
2318                                 leaf = (mleaf_t *)p->nodes[i];
2319                                 w = p->winding;
2320                                 for (j = 0;j < w->numpoints;j++)
2321                                 {
2322                                         if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2323                                         if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2324                                         if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2325                                         if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2326                                         if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2327                                         if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2328                                 }
2329                         }
2330                 }
2331                 p = p->chain;
2332         }
2333
2334         Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2335
2336         // tally up portal and point counts
2337         p = portalchain;
2338         numportals = 0;
2339         numpoints = 0;
2340         while(p)
2341         {
2342                 // note: this check must match the one below or it will usually corrupt memory
2343                 // the nodes[0] != nodes[1] check is because leaf 0 is the shared solid leaf, it can have many portals inside with leaf 0 on both sides
2344                 if (p->winding && p->nodes[0] != p->nodes[1]
2345                  && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2346                  && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2347                 {
2348                         numportals += 2;
2349                         numpoints += p->winding->numpoints * 2;
2350                 }
2351                 p = p->chain;
2352         }
2353         loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2354         loadmodel->numportals = numportals;
2355         loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2356         loadmodel->numportalpoints = numpoints;
2357         // clear all leaf portal chains
2358         for (i = 0;i < loadmodel->numleafs;i++)
2359                 loadmodel->leafs[i].portals = NULL;
2360         // process all portals in the global portal chain, while freeing them
2361         portal = loadmodel->portals;
2362         point = loadmodel->portalpoints;
2363         p = portalchain;
2364         portalchain = NULL;
2365         while (p)
2366         {
2367                 pnext = p->chain;
2368
2369                 if (p->winding)
2370                 {
2371                         // note: this check must match the one above or it will usually corrupt memory
2372                         // the nodes[0] != nodes[1] check is because leaf 0 is the shared solid leaf, it can have many portals inside with leaf 0 on both sides
2373                         if (p->nodes[0] != p->nodes[1]
2374                          && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2375                          && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2376                         {
2377                                 // first make the back to front portal (forward portal)
2378                                 portal->points = point;
2379                                 portal->numpoints = p->winding->numpoints;
2380                                 portal->plane.dist = p->plane.dist;
2381                                 VectorCopy(p->plane.normal, portal->plane.normal);
2382                                 portal->here = (mleaf_t *)p->nodes[1];
2383                                 portal->past = (mleaf_t *)p->nodes[0];
2384                                 // copy points
2385                                 for (j = 0;j < portal->numpoints;j++)
2386                                 {
2387                                         VectorCopy(p->winding->points[j], point->position);
2388                                         point++;
2389                                 }
2390                                 PlaneClassify(&portal->plane);
2391
2392                                 // link into leaf's portal chain
2393                                 portal->next = portal->here->portals;
2394                                 portal->here->portals = portal;
2395
2396                                 // advance to next portal
2397                                 portal++;
2398
2399                                 // then make the front to back portal (backward portal)
2400                                 portal->points = point;
2401                                 portal->numpoints = p->winding->numpoints;
2402                                 portal->plane.dist = -p->plane.dist;
2403                                 VectorNegate(p->plane.normal, portal->plane.normal);
2404                                 portal->here = (mleaf_t *)p->nodes[0];
2405                                 portal->past = (mleaf_t *)p->nodes[1];
2406                                 // copy points
2407                                 for (j = portal->numpoints - 1;j >= 0;j--)
2408                                 {
2409                                         VectorCopy(p->winding->points[j], point->position);
2410                                         point++;
2411                                 }
2412                                 PlaneClassify(&portal->plane);
2413
2414                                 // link into leaf's portal chain
2415                                 portal->next = portal->here->portals;
2416                                 portal->here->portals = portal;
2417
2418                                 // advance to next portal
2419                                 portal++;
2420                         }
2421                         FreeWinding(p->winding);
2422                 }
2423                 FreePortal(p);
2424                 p = pnext;
2425         }
2426 }
2427
2428 /*
2429 =============
2430 AddPortalToNodes
2431 =============
2432 */
2433 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2434 {
2435         if (!front)
2436                 Host_Error ("AddPortalToNodes: NULL front node");
2437         if (!back)
2438                 Host_Error ("AddPortalToNodes: NULL back node");
2439         if (p->nodes[0] || p->nodes[1])
2440                 Host_Error ("AddPortalToNodes: already included");
2441         // note: front == back is handled gracefully, because leaf 0 is the shared solid leaf, it can often have portals with the same leaf on both sides
2442
2443         p->nodes[0] = front;
2444         p->next[0] = (portal_t *)front->portals;
2445         front->portals = (mportal_t *)p;
2446
2447         p->nodes[1] = back;
2448         p->next[1] = (portal_t *)back->portals;
2449         back->portals = (mportal_t *)p;
2450 }
2451
2452 /*
2453 =============
2454 RemovePortalFromNode
2455 =============
2456 */
2457 static void RemovePortalFromNodes(portal_t *portal)
2458 {
2459         int i;
2460         mnode_t *node;
2461         void **portalpointer;
2462         portal_t *t;
2463         for (i = 0;i < 2;i++)
2464         {
2465                 node = portal->nodes[i];
2466
2467                 portalpointer = (void **) &node->portals;
2468                 while (1)
2469                 {
2470                         t = *portalpointer;
2471                         if (!t)
2472                                 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2473
2474                         if (t == portal)
2475                         {
2476                                 if (portal->nodes[0] == node)
2477                                 {
2478                                         *portalpointer = portal->next[0];
2479                                         portal->nodes[0] = NULL;
2480                                 }
2481                                 else if (portal->nodes[1] == node)
2482                                 {
2483                                         *portalpointer = portal->next[1];
2484                                         portal->nodes[1] = NULL;
2485                                 }
2486                                 else
2487                                         Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2488                                 break;
2489                         }
2490
2491                         if (t->nodes[0] == node)
2492                                 portalpointer = (void **) &t->next[0];
2493                         else if (t->nodes[1] == node)
2494                                 portalpointer = (void **) &t->next[1];
2495                         else
2496                                 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2497                 }
2498         }
2499 }
2500
2501 static void Mod_RecursiveNodePortals (mnode_t *node)
2502 {
2503         int side;
2504         mnode_t *front, *back, *other_node;
2505         mplane_t clipplane, *plane;
2506         portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2507         winding_t *nodeportalwinding, *frontwinding, *backwinding;
2508
2509         // if a leaf, we're done
2510         if (node->contents)
2511                 return;
2512
2513         plane = node->plane;
2514
2515         front = node->children[0];
2516         back = node->children[1];
2517         if (front == back)
2518                 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2519
2520         // create the new portal by generating a polygon for the node plane,
2521         // and clipping it by all of the other portals (which came from nodes above this one)
2522         nodeportal = AllocPortal ();
2523         nodeportal->plane = *node->plane;
2524
2525         nodeportalwinding = BaseWindingForPlane (node->plane);
2526         side = 0;       // shut up compiler warning
2527         for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2528         {
2529                 clipplane = portal->plane;
2530                 if (portal->nodes[0] == portal->nodes[1])
2531                         Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2532                 if (portal->nodes[0] == node)
2533                         side = 0;
2534                 else if (portal->nodes[1] == node)
2535                 {
2536                         clipplane.dist = -clipplane.dist;
2537                         VectorNegate (clipplane.normal, clipplane.normal);
2538                         side = 1;
2539                 }
2540                 else
2541                         Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2542
2543                 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2544                 if (!nodeportalwinding)
2545                 {
2546                         Con_Printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2547                         break;
2548                 }
2549         }
2550
2551         if (nodeportalwinding)
2552         {
2553                 // if the plane was not clipped on all sides, there was an error
2554                 nodeportal->winding = nodeportalwinding;
2555                 AddPortalToNodes (nodeportal, front, back);
2556         }
2557
2558         // split the portals of this node along this node's plane and assign them to the children of this node
2559         // (migrating the portals downward through the tree)
2560         for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2561         {
2562                 if (portal->nodes[0] == portal->nodes[1])
2563                         Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2564                 if (portal->nodes[0] == node)
2565                         side = 0;
2566                 else if (portal->nodes[1] == node)
2567                         side = 1;
2568                 else
2569                         Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2570                 nextportal = portal->next[side];
2571
2572                 other_node = portal->nodes[!side];
2573                 RemovePortalFromNodes (portal);
2574
2575                 // cut the portal into two portals, one on each side of the node plane
2576                 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2577
2578                 if (!frontwinding)
2579                 {
2580                         if (side == 0)
2581                                 AddPortalToNodes (portal, back, other_node);
2582                         else
2583                                 AddPortalToNodes (portal, other_node, back);
2584                         continue;
2585                 }
2586                 if (!backwinding)
2587                 {
2588                         if (side == 0)
2589                                 AddPortalToNodes (portal, front, other_node);
2590                         else
2591                                 AddPortalToNodes (portal, other_node, front);
2592                         continue;
2593                 }
2594
2595                 // the winding is split
2596                 splitportal = AllocPortal ();
2597                 temp = splitportal->chain;
2598                 *splitportal = *portal;
2599                 splitportal->chain = temp;
2600                 splitportal->winding = backwinding;
2601                 FreeWinding (portal->winding);
2602                 portal->winding = frontwinding;
2603
2604                 if (side == 0)
2605                 {
2606                         AddPortalToNodes (portal, front, other_node);
2607                         AddPortalToNodes (splitportal, back, other_node);
2608                 }
2609                 else
2610                 {
2611                         AddPortalToNodes (portal, other_node, front);
2612                         AddPortalToNodes (splitportal, other_node, back);
2613                 }
2614         }
2615
2616         Mod_RecursiveNodePortals(front);
2617         Mod_RecursiveNodePortals(back);
2618 }
2619
2620
2621 static void Mod_MakePortals(void)
2622 {
2623         portalchain = NULL;
2624         Mod_RecursiveNodePortals (loadmodel->nodes);
2625         Mod_FinalizePortals();
2626 }
2627
2628 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2629 {
2630 #if 0
2631         int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2632         msurface_t *surf, *s;
2633         float *v0, *v1, *v2, *v3;
2634         for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2635                 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2636         for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2637         {
2638                 for (vertnum = surf->poly_numverts - 1, vertnum2 = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;vertnum2 < surf->poly_numverts;vertnum = vertnum2, vertnum2++, v0 = v1, v1 += 3)
2639                 {
2640                         if (surf->neighborsurfaces[vertnum])
2641                                 continue;
2642                         surf->neighborsurfaces[vertnum] = NULL;
2643                         for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2644                         {
2645                                 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2646                                  || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2647                                  || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2648                                  || s == surf)
2649                                         continue;
2650                                 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2651                                         if (s->neighborsurfaces[vnum] == surf)
2652                                                 break;
2653                                 if (vnum < s->poly_numverts)
2654                                         continue;
2655                                 for (vnum = s->poly_numverts - 1, vnum2 = 0, v2 = s->poly_verts + (s->poly_numverts - 1) * 3, v3 = s->poly_verts;vnum2 < s->poly_numverts;vnum = vnum2, vnum2++, v2 = v3, v3 += 3)
2656                                 {
2657                                         if (s->neighborsurfaces[vnum] == NULL
2658                                          && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2659                                           || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2660                                         {
2661                                                 surf->neighborsurfaces[vertnum] = s;
2662                                                 s->neighborsurfaces[vnum] = surf;
2663                                                 break;
2664                                         }
2665                                 }
2666                                 if (vnum < s->poly_numverts)
2667                                         break;
2668                         }
2669                 }
2670         }
2671 #endif
2672 }
2673
2674 void Mod_BuildLightmapUpdateChains(mempool_t *mempool, model_t *model)
2675 {
2676         int i, j, stylecounts[256], totalcount, remapstyles[256];
2677         msurface_t *surf;
2678         memset(stylecounts, 0, sizeof(stylecounts));
2679         for (i = 0;i < model->nummodelsurfaces;i++)
2680         {
2681                 surf = model->surfaces + model->firstmodelsurface + i;
2682                 for (j = 0;j < MAXLIGHTMAPS;j++)
2683                         stylecounts[surf->styles[j]]++;
2684         }
2685         totalcount = 0;
2686         model->light_styles = 0;
2687         for (i = 0;i < 255;i++)
2688         {
2689                 if (stylecounts[i])
2690                 {
2691                         remapstyles[i] = model->light_styles++;
2692                         totalcount += stylecounts[i] + 1;
2693                 }
2694         }
2695         if (!totalcount)
2696                 return;
2697         model->light_style = Mem_Alloc(mempool, model->light_styles * sizeof(qbyte));
2698         model->light_stylevalue = Mem_Alloc(mempool, model->light_styles * sizeof(int));
2699         model->light_styleupdatechains = Mem_Alloc(mempool, model->light_styles * sizeof(msurface_t **));
2700         model->light_styleupdatechainsbuffer = Mem_Alloc(mempool, totalcount * sizeof(msurface_t *));
2701         model->light_styles = 0;
2702         for (i = 0;i < 255;i++)
2703                 if (stylecounts[i])
2704                         model->light_style[model->light_styles++] = i;
2705         j = 0;
2706         for (i = 0;i < model->light_styles;i++)
2707         {
2708                 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2709                 j += stylecounts[model->light_style[i]] + 1;
2710         }
2711         for (i = 0;i < model->nummodelsurfaces;i++)
2712         {
2713                 surf = model->surfaces + model->firstmodelsurface + i;
2714                 for (j = 0;j < MAXLIGHTMAPS;j++)
2715                         if (surf->styles[j] != 255)
2716                                 *model->light_styleupdatechains[remapstyles[surf->styles[j]]]++ = surf;
2717         }
2718         j = 0;
2719         for (i = 0;i < model->light_styles;i++)
2720         {
2721                 *model->light_styleupdatechains[i] = NULL;
2722                 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2723                 j += stylecounts[model->light_style[i]] + 1;
2724         }
2725 }
2726
2727 void Mod_BuildPVSTextureChains(model_t *model)
2728 {
2729         int i, j;
2730         for (i = 0;i < model->numtextures;i++)
2731                 model->pvstexturechainslength[i] = 0;
2732         for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2733         {
2734                 if (model->surfacepvsframes[j] == model->pvsframecount)
2735                 {
2736                         model->pvssurflist[model->pvssurflistlength++] = j;
2737                         model->pvstexturechainslength[model->surfaces[j].texinfo->texture->number]++;
2738                 }
2739         }
2740         for (i = 0, j = 0;i < model->numtextures;i++)
2741         {
2742                 if (model->pvstexturechainslength[i])
2743                 {
2744                         model->pvstexturechains[i] = model->pvstexturechainsbuffer + j;
2745                         j += model->pvstexturechainslength[i] + 1;
2746                 }
2747                 else
2748                         model->pvstexturechains[i] = NULL;
2749         }
2750         for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2751                 if (model->surfacepvsframes[j] == model->pvsframecount)
2752                         *model->pvstexturechains[model->surfaces[j].texinfo->texture->number]++ = model->surfaces + j;
2753         for (i = 0;i < model->numtextures;i++)
2754         {
2755                 if (model->pvstexturechainslength[i])
2756                 {
2757                         *model->pvstexturechains[i] = NULL;
2758                         model->pvstexturechains[i] -= model->pvstexturechainslength[i];
2759                 }
2760         }
2761 }
2762
2763 /*
2764 =================
2765 Mod_LoadBrushModel
2766 =================
2767 */
2768 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2769 extern void R_Model_Brush_Draw(entity_render_t *ent);
2770 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2771 extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
2772 void Mod_LoadBrushModelQ1orHL (model_t *mod, void *buffer)
2773 {
2774         int i, j, k;
2775         dheader_t *header;
2776         dmodel_t *bm;
2777         mempool_t *mainmempool;
2778         char *loadname;
2779         model_t *originalloadmodel;
2780         float dist, modelyawradius, modelradius, *vec;
2781         msurface_t *surf;
2782         surfmesh_t *mesh;
2783
2784         mod->type = mod_brush;
2785
2786         header = (dheader_t *)buffer;
2787
2788         i = LittleLong (header->version);
2789         if (i != BSPVERSION && i != 30)
2790                 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2791         mod->ishlbsp = i == 30;
2792         if (loadmodel->isworldmodel)
2793         {
2794                 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2795                 // until we get a texture for it...
2796                 R_ResetQuakeSky();
2797         }
2798
2799 // swap all the lumps
2800         mod_base = (qbyte *)header;
2801
2802         for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
2803                 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2804
2805 // load into heap
2806
2807         // store which lightmap format to use
2808         mod->lightmaprgba = r_lightmaprgba.integer;
2809
2810         Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2811         Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2812         Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2813         Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2814         Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2815         Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2816         Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2817         Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2818         Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2819         Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2820         Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2821         Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2822         Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2823         Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2824         Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2825
2826         Mod_MakeHull0 ();
2827         Mod_MakePortals();
2828
2829         mod->numframes = 2;             // regular and alternate animation
2830
2831         mainmempool = mod->mempool;
2832         loadname = mod->name;
2833
2834         Mod_LoadLightList ();
2835         originalloadmodel = loadmodel;
2836
2837 //
2838 // set up the submodels (FIXME: this is confusing)
2839 //
2840         for (i = 0;i < mod->numsubmodels;i++)
2841         {
2842                 bm = &mod->submodels[i];
2843
2844                 mod->hulls[0].firstclipnode = bm->headnode[0];
2845                 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2846                 {
2847                         mod->hulls[j].firstclipnode = bm->headnode[j];
2848                         mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2849                 }
2850
2851                 mod->firstmodelsurface = bm->firstface;
2852                 mod->nummodelsurfaces = bm->numfaces;
2853
2854                 // this gets altered below if sky is used
2855                 mod->DrawSky = NULL;
2856                 mod->Draw = R_Model_Brush_Draw;
2857                 mod->DrawFakeShadow = NULL;
2858                 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2859                 mod->DrawLight = R_Model_Brush_DrawLight;
2860                 mod->pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t **));
2861                 mod->pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool, (mod->nummodelsurfaces + mod->numtextures) * sizeof(msurface_t *));
2862                 mod->pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(int));
2863                 Mod_BuildPVSTextureChains(mod);
2864                 Mod_BuildLightmapUpdateChains(originalloadmodel->mempool, mod);
2865                 if (mod->nummodelsurfaces)
2866                 {
2867                         // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2868                         mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2869                         mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2870                         modelyawradius = 0;
2871                         modelradius = 0;
2872                         for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2873                         {
2874                                 // we only need to have a drawsky function if it is used (usually only on world model)
2875                                 if (surf->texinfo->texture->shader == &Cshader_sky)
2876                                         mod->DrawSky = R_Model_Brush_DrawSky;
2877                                 // LordHavoc: submodels always clip, even if water
2878                                 if (mod->numsubmodels - 1)
2879                                         surf->flags |= SURF_SOLIDCLIP;
2880                                 // calculate bounding shapes
2881                                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
2882                                 {
2883                                         for (k = 0, vec = mesh->vertex3f;k < mesh->numverts;k++, vec += 3)
2884                                         {
2885                                                 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2886                                                 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2887                                                 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2888                                                 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2889                                                 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2890                                                 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2891                                                 dist = vec[0]*vec[0]+vec[1]*vec[1];
2892                                                 if (modelyawradius < dist)
2893                                                         modelyawradius = dist;
2894                                                 dist += vec[2]*vec[2];
2895                                                 if (modelradius < dist)
2896                                                         modelradius = dist;
2897                                         }
2898                                 }
2899                         }
2900                         modelyawradius = sqrt(modelyawradius);
2901                         modelradius = sqrt(modelradius);
2902                         mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2903                         mod->yawmins[2] = mod->normalmins[2];
2904                         mod->yawmaxs[2] = mod->normalmaxs[2];
2905                         mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2906                         mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2907                         mod->radius = modelradius;
2908                         mod->radius2 = modelradius * modelradius;
2909                 }
2910                 else
2911                 {
2912                         // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2913                         Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2914                 }
2915                 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2916
2917                 mod->numleafs = bm->visleafs;
2918
2919                 // LordHavoc: only register submodels if it is the world
2920                 // (prevents bsp models from replacing world submodels)
2921                 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2922                 {
2923                         char    name[10];
2924                         // duplicate the basic information
2925                         sprintf (name, "*%i", i+1);
2926                         loadmodel = Mod_FindName (name);
2927                         *loadmodel = *mod;
2928                         strcpy (loadmodel->name, name);
2929                         // textures and memory belong to the main model
2930                         loadmodel->texturepool = NULL;
2931                         loadmodel->mempool = NULL;
2932                         mod = loadmodel;
2933                 }
2934         }
2935
2936         loadmodel = originalloadmodel;
2937         //Mod_ProcessLightList ();
2938 }
2939
2940 static void Mod_Q2LoadEntities (lump_t *l)
2941 {
2942 }
2943
2944 static void Mod_Q2LoadPlanes (lump_t *l)
2945 {
2946 /*
2947         d_t *in;
2948         m_t *out;
2949         int i, count;
2950
2951         in = (void *)(mod_base + l->fileofs);
2952         if (l->filelen % sizeof(*in))
2953                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
2954         count = l->filelen / sizeof(*in);
2955         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
2956
2957         loadmodel-> = out;
2958         loadmodel->num = count;
2959
2960         for (i = 0;i < count;i++, in++, out++)
2961         {
2962         }
2963 */
2964 }
2965
2966 static void Mod_Q2LoadVertices (lump_t *l)
2967 {
2968 /*
2969         d_t *in;
2970         m_t *out;
2971         int i, count;
2972
2973         in = (void *)(mod_base + l->fileofs);
2974         if (l->filelen % sizeof(*in))
2975                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
2976         count = l->filelen / sizeof(*in);
2977         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
2978
2979         loadmodel-> = out;
2980         loadmodel->num = count;
2981
2982         for (i = 0;i < count;i++, in++, out++)
2983         {
2984         }
2985 */
2986 }
2987
2988 static void Mod_Q2LoadVisibility (lump_t *l)
2989 {
2990 /*
2991         d_t *in;
2992         m_t *out;
2993         int i, count;
2994
2995         in = (void *)(mod_base + l->fileofs);
2996         if (l->filelen % sizeof(*in))
2997                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
2998         count = l->filelen / sizeof(*in);
2999         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3000
3001         loadmodel-> = out;
3002         loadmodel->num = count;
3003
3004         for (i = 0;i < count;i++, in++, out++)
3005         {
3006         }
3007 */
3008 }
3009
3010 static void Mod_Q2LoadNodes (lump_t *l)
3011 {
3012 /*
3013         d_t *in;
3014         m_t *out;
3015         int i, count;
3016
3017         in = (void *)(mod_base + l->fileofs);
3018         if (l->filelen % sizeof(*in))
3019                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3020         count = l->filelen / sizeof(*in);
3021         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3022
3023         loadmodel-> = out;
3024         loadmodel->num = count;
3025
3026         for (i = 0;i < count;i++, in++, out++)
3027         {
3028         }
3029 */
3030 }
3031
3032 static void Mod_Q2LoadTexInfo (lump_t *l)
3033 {
3034 /*
3035         d_t *in;
3036         m_t *out;
3037         int i, count;
3038
3039         in = (void *)(mod_base + l->fileofs);
3040         if (l->filelen % sizeof(*in))
3041                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3042         count = l->filelen / sizeof(*in);
3043         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3044
3045         loadmodel-> = out;
3046         loadmodel->num = count;
3047
3048         for (i = 0;i < count;i++, in++, out++)
3049         {
3050         }
3051 */
3052 }
3053
3054 static void Mod_Q2LoadFaces (lump_t *l)
3055 {
3056 /*
3057         d_t *in;
3058         m_t *out;
3059         int i, count;
3060
3061         in = (void *)(mod_base + l->fileofs);
3062         if (l->filelen % sizeof(*in))
3063                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3064         count = l->filelen / sizeof(*in);
3065         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3066
3067         loadmodel-> = out;
3068         loadmodel->num = count;
3069
3070         for (i = 0;i < count;i++, in++, out++)
3071         {
3072         }
3073 */
3074 }
3075
3076 static void Mod_Q2LoadLighting (lump_t *l)
3077 {
3078 /*
3079         d_t *in;
3080         m_t *out;
3081         int i, count;
3082
3083         in = (void *)(mod_base + l->fileofs);
3084         if (l->filelen % sizeof(*in))
3085                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3086         count = l->filelen / sizeof(*in);
3087         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3088
3089         loadmodel-> = out;
3090         loadmodel->num = count;
3091
3092         for (i = 0;i < count;i++, in++, out++)
3093         {
3094         }
3095 */
3096 }
3097
3098 static void Mod_Q2LoadLeafs (lump_t *l)
3099 {
3100 /*
3101         d_t *in;
3102         m_t *out;
3103         int i, count;
3104
3105         in = (void *)(mod_base + l->fileofs);
3106         if (l->filelen % sizeof(*in))
3107                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3108         count = l->filelen / sizeof(*in);
3109         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3110
3111         loadmodel-> = out;
3112         loadmodel->num = count;
3113
3114         for (i = 0;i < count;i++, in++, out++)
3115         {
3116         }
3117 */
3118 }
3119
3120 static void Mod_Q2LoadLeafFaces (lump_t *l)
3121 {
3122 /*
3123         d_t *in;
3124         m_t *out;
3125         int i, count;
3126
3127         in = (void *)(mod_base + l->fileofs);
3128         if (l->filelen % sizeof(*in))
3129                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3130         count = l->filelen / sizeof(*in);
3131         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3132
3133         loadmodel-> = out;
3134         loadmodel->num = count;
3135
3136         for (i = 0;i < count;i++, in++, out++)
3137         {
3138         }
3139 */
3140 }
3141
3142 static void Mod_Q2LoadLeafBrushes (lump_t *l)
3143 {
3144 /*
3145         d_t *in;
3146         m_t *out;
3147         int i, count;
3148
3149         in = (void *)(mod_base + l->fileofs);
3150         if (l->filelen % sizeof(*in))
3151                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3152         count = l->filelen / sizeof(*in);
3153         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3154
3155         loadmodel-> = out;
3156         loadmodel->num = count;
3157
3158         for (i = 0;i < count;i++, in++, out++)
3159         {
3160         }
3161 */
3162 }
3163
3164 static void Mod_Q2LoadEdges (lump_t *l)
3165 {
3166 /*
3167         d_t *in;
3168         m_t *out;
3169         int i, count;
3170
3171         in = (void *)(mod_base + l->fileofs);
3172         if (l->filelen % sizeof(*in))
3173                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3174         count = l->filelen / sizeof(*in);
3175         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3176
3177         loadmodel-> = out;
3178         loadmodel->num = count;
3179
3180         for (i = 0;i < count;i++, in++, out++)
3181         {
3182         }
3183 */
3184 }
3185
3186 static void Mod_Q2LoadSurfEdges (lump_t *l)
3187 {
3188 /*
3189         d_t *in;
3190         m_t *out;
3191         int i, count;
3192
3193         in = (void *)(mod_base + l->fileofs);
3194         if (l->filelen % sizeof(*in))
3195                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3196         count = l->filelen / sizeof(*in);
3197         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3198
3199         loadmodel-> = out;
3200         loadmodel->num = count;
3201
3202         for (i = 0;i < count;i++, in++, out++)
3203         {
3204         }
3205 */
3206 }
3207
3208 static void Mod_Q2LoadBrushes (lump_t *l)
3209 {
3210 /*
3211         d_t *in;
3212         m_t *out;
3213         int i, count;
3214
3215         in = (void *)(mod_base + l->fileofs);
3216         if (l->filelen % sizeof(*in))
3217                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3218         count = l->filelen / sizeof(*in);
3219         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3220
3221         loadmodel-> = out;
3222         loadmodel->num = count;
3223
3224         for (i = 0;i < count;i++, in++, out++)
3225         {
3226         }
3227 */
3228 }
3229
3230 static void Mod_Q2LoadBrushSides (lump_t *l)
3231 {
3232 /*
3233         d_t *in;
3234         m_t *out;
3235         int i, count;
3236
3237         in = (void *)(mod_base + l->fileofs);
3238         if (l->filelen % sizeof(*in))
3239                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3240         count = l->filelen / sizeof(*in);
3241         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3242
3243         loadmodel-> = out;
3244         loadmodel->num = count;
3245
3246         for (i = 0;i < count;i++, in++, out++)
3247         {
3248         }
3249 */
3250 }
3251
3252 static void Mod_Q2LoadAreas (lump_t *l)
3253 {
3254 /*
3255         d_t *in;
3256         m_t *out;
3257         int i, count;
3258
3259         in = (void *)(mod_base + l->fileofs);
3260         if (l->filelen % sizeof(*in))
3261                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3262         count = l->filelen / sizeof(*in);
3263         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3264
3265         loadmodel-> = out;
3266         loadmodel->num = count;
3267
3268         for (i = 0;i < count;i++, in++, out++)
3269         {
3270         }
3271 */
3272 }
3273
3274 static void Mod_Q2LoadAreaPortals (lump_t *l)
3275 {
3276 /*
3277         d_t *in;
3278         m_t *out;
3279         int i, count;
3280
3281         in = (void *)(mod_base + l->fileofs);
3282         if (l->filelen % sizeof(*in))
3283                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3284         count = l->filelen / sizeof(*in);
3285         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3286
3287         loadmodel-> = out;
3288         loadmodel->num = count;
3289
3290         for (i = 0;i < count;i++, in++, out++)
3291         {
3292         }
3293 */
3294 }
3295
3296 static void Mod_Q2LoadModels (lump_t *l)
3297 {
3298 /*
3299         d_t *in;
3300         m_t *out;
3301         int i, count;
3302
3303         in = (void *)(mod_base + l->fileofs);
3304         if (l->filelen % sizeof(*in))
3305                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3306         count = l->filelen / sizeof(*in);
3307         out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3308
3309         loadmodel-> = out;
3310         loadmodel->num = count;
3311
3312         for (i = 0;i < count;i++, in++, out++)
3313         {
3314         }
3315 */
3316 }
3317
3318 void Mod_LoadBrushModelQ2 (model_t *mod, void *buffer)
3319 {
3320         int i;
3321         q2dheader_t *header;
3322
3323         mod->type = mod_brushq2;
3324
3325         header = (q2dheader_t *)buffer;
3326
3327         i = LittleLong (header->version);
3328         if (i != Q2BSPVERSION)
3329                 Host_Error ("Mod_LoadBrushModelQ2: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
3330         mod->ishlbsp = false;
3331         if (loadmodel->isworldmodel)
3332         {
3333                 Cvar_SetValue("halflifebsp", mod->ishlbsp);
3334                 // until we get a texture for it...
3335                 R_ResetQuakeSky();
3336         }
3337
3338         mod_base = (qbyte *)header;
3339
3340         // swap all the lumps
3341         for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
3342                 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
3343
3344         // store which lightmap format to use
3345         mod->lightmaprgba = r_lightmaprgba.integer;
3346
3347         Mod_Q2LoadEntities(&header->lumps[Q2LUMP_ENTITIES]);
3348         Mod_Q2LoadPlanes(&header->lumps[Q2LUMP_PLANES]);
3349         Mod_Q2LoadVertices(&header->lumps[Q2LUMP_VERTEXES]);
3350         Mod_Q2LoadVisibility(&header->lumps[Q2LUMP_VISIBILITY]);
3351         Mod_Q2LoadNodes(&header->lumps[Q2LUMP_NODES]);
3352         Mod_Q2LoadTexInfo(&header->lumps[Q2LUMP_TEXINFO]);
3353         Mod_Q2LoadFaces(&header->lumps[Q2LUMP_FACES]);
3354         Mod_Q2LoadLighting(&header->lumps[Q2LUMP_LIGHTING]);
3355         Mod_Q2LoadLeafs(&header->lumps[Q2LUMP_LEAFS]);
3356         Mod_Q2LoadLeafFaces(&header->lumps[Q2LUMP_LEAFFACES]);
3357         Mod_Q2LoadLeafBrushes(&header->lumps[Q2LUMP_LEAFBRUSHES]);
3358         Mod_Q2LoadEdges(&header->lumps[Q2LUMP_EDGES]);
3359         Mod_Q2LoadSurfEdges(&header->lumps[Q2LUMP_SURFEDGES]);
3360         Mod_Q2LoadBrushes(&header->lumps[Q2LUMP_BRUSHES]);
3361         Mod_Q2LoadBrushSides(&header->lumps[Q2LUMP_BRUSHSIDES]);
3362         Mod_Q2LoadAreas(&header->lumps[Q2LUMP_AREAS]);
3363         Mod_Q2LoadAreaPortals(&header->lumps[Q2LUMP_AREAPORTALS]);
3364         // LordHavoc: must go last because this makes the submodels
3365         Mod_Q2LoadModels(&header->lumps[Q2LUMP_MODELS]);
3366 }
3367
3368 void Mod_LoadBrushModelQ3 (model_t *mod, void *buffer)
3369 {
3370         Host_Error("Mod_LoadBrushModelQ3: not yet implemented\n");
3371 }
3372
3373 void Mod_LoadBrushModelIBSP (model_t *mod, void *buffer)
3374 {
3375         int i = LittleLong(*((int *)buffer));
3376         if (i == 46)
3377                 Mod_LoadBrushModelQ3 (mod,buffer);
3378         else if (i == 38)
3379                 Mod_LoadBrushModelQ2 (mod,buffer);
3380         else
3381                 Host_Error("Mod_LoadBrushModelIBSP: unknown/unsupported version %i\n", i);
3382 }
3383