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