]> icculus.org git repositories - divverent/darkplaces.git/blob - model_brush.c
varray_* rewritten to remove padding (varray_vertex3f, varray_texcoord2f, varray_texc...
[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                 COM_StripExtension(litfilename, litfilename);
621                 strcat(litfilename, ".lit");
622                 data = (qbyte*) COM_LoadFile (litfilename, false);
623                 if (data)
624                 {
625                         if (loadsize > 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, loadsize - 8);
632                                         memcpy(loadmodel->lightdata, data + 8, loadsize - 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 (loadsize == 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         COM_StripExtension(lightsfilename, lightsfilename);
676         strcat(lightsfilename, ".lights");
677         s = lightsstring = (char *) COM_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_GenerateWallMesh (msurface_t *surf, int vertexonly)
1401 {
1402         int i, iu, iv, *index, smax, tmax;
1403         float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
1404         surfmesh_t *mesh;
1405
1406         smax = surf->extents[0] >> 4;
1407         tmax = surf->extents[1] >> 4;
1408
1409         if (vertexonly)
1410         {
1411                 surf->lightmaptexturestride = 0;
1412                 surf->lightmaptexture = NULL;
1413                 uscale = 0;
1414                 vscale = 0;
1415                 ubase = 0;
1416                 vbase = 0;
1417         }
1418         else
1419         {
1420                 surf->flags |= SURF_LIGHTMAP;
1421                 if (r_miplightmaps.integer)
1422                 {
1423                         surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1424                         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);
1425                 }
1426                 else
1427                 {
1428                         surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1429                         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);
1430                 }
1431                 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1432                 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1433                 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1434         }
1435
1436         surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1437
1438         index = mesh->element3i;
1439         for (i = 0;i < mesh->numtriangles;i++)
1440         {
1441                 *index++ = 0;
1442                 *index++ = i + 1;
1443                 *index++ = i + 2;
1444         }
1445         Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1446
1447         VectorCopy(surf->plane->normal, normal);
1448         if (surf->flags & SURF_PLANEBACK)
1449                 VectorNegate(normal, normal);
1450         for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1451         {
1452                 s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1453                 t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1454                 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1455                 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1456                 // LordHavoc: calc lightmap data offset for vertex lighting to use
1457                 iu = (int) u;
1458                 iv = (int) v;
1459                 iu = bound(0, iu, smax);
1460                 iv = bound(0, iv, tmax);
1461                 u = u * uscale + ubase;
1462                 v = v * vscale + vbase;
1463
1464                 mesh->vertex3f[i * 3 + 0] = in[0];
1465                 mesh->vertex3f[i * 3 + 1] = in[1];
1466                 mesh->vertex3f[i * 3 + 2] = in[2];
1467                 mesh->texcoordtexture2f[i * 2 + 0] = s / surf->texinfo->texture->width;
1468                 mesh->texcoordtexture2f[i * 2 + 1] = t / surf->texinfo->texture->height;
1469                 mesh->texcoordlightmap2f[i * 2 + 0] = u;
1470                 mesh->texcoordlightmap2f[i * 2 + 1] = v;
1471                 mesh->texcoorddetail2f[i * 2 + 0] = s * (1.0f / 16.0f);
1472                 mesh->texcoorddetail2f[i * 2 + 1] = t * (1.0f / 16.0f);
1473                 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
1474         }
1475         Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->vertex3f, mesh->texcoordtexture2f, mesh->element3i, mesh->svector3f, mesh->tvector3f, mesh->normal3f);
1476 }
1477
1478 void Mod_GenerateVertexMesh (msurface_t *surf)
1479 {
1480         int i, *index;
1481         float *in, s, t, normal[3];
1482         surfmesh_t *mesh;
1483
1484         surf->lightmaptexturestride = 0;
1485         surf->lightmaptexture = NULL;
1486
1487         surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1488
1489         index = mesh->element3i;
1490         for (i = 0;i < mesh->numtriangles;i++)
1491         {
1492                 *index++ = 0;
1493                 *index++ = i + 1;
1494                 *index++ = i + 2;
1495         }
1496         Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1497
1498         VectorCopy(surf->plane->normal, normal);
1499         if (surf->flags & SURF_PLANEBACK)
1500                 VectorNegate(normal, normal);
1501         for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1502         {
1503                 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
1504                 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
1505                 mesh->vertex3f[i * 3 + 0] = in[0];
1506                 mesh->vertex3f[i * 3 + 1] = in[1];
1507                 mesh->vertex3f[i * 3 + 2] = in[2];
1508                 mesh->texcoordtexture2f[i * 2 + 0] = s / surf->texinfo->texture->width;
1509                 mesh->texcoordtexture2f[i * 2 + 1] = t / surf->texinfo->texture->height;
1510                 mesh->texcoordlightmap2f[i * 2 + 0] = 0;
1511                 mesh->texcoordlightmap2f[i * 2 + 1] = 0;
1512                 mesh->texcoorddetail2f[i * 2 + 0] = s * (1.0f / 16.0f);
1513                 mesh->texcoorddetail2f[i * 2 + 1] = t * (1.0f / 16.0f);
1514         }
1515         Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->vertex3f, mesh->texcoordtexture2f, mesh->element3i, mesh->svector3f, mesh->tvector3f, mesh->normal3f);
1516 }
1517
1518 void Mod_GenerateSurfacePolygon (msurface_t *surf, int firstedge, int numedges)
1519 {
1520         int i, lindex, j;
1521         float *vec, *vert, mins[3], maxs[3], val, *v;
1522         mtexinfo_t *tex;
1523
1524         // convert edges back to a normal polygon
1525         surf->poly_numverts = numedges;
1526         vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * numedges);
1527         for (i = 0;i < numedges;i++)
1528         {
1529                 lindex = loadmodel->surfedges[firstedge + i];
1530                 if (lindex > 0)
1531                         vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1532                 else
1533                         vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1534                 VectorCopy (vec, vert);
1535                 vert += 3;
1536         }
1537
1538         // calculate polygon bounding box and center
1539         vert = surf->poly_verts;
1540         VectorCopy(vert, mins);
1541         VectorCopy(vert, maxs);
1542         vert += 3;
1543         for (i = 1;i < surf->poly_numverts;i++, vert += 3)
1544         {
1545                 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1546                 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1547                 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1548         }
1549         VectorCopy(mins, surf->poly_mins);
1550         VectorCopy(maxs, surf->poly_maxs);
1551         surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1552         surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1553         surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1554
1555         // generate surface extents information
1556         tex = surf->texinfo;
1557         mins[0] = maxs[0] = DotProduct(surf->poly_verts, tex->vecs[0]) + tex->vecs[0][3];
1558         mins[1] = maxs[1] = DotProduct(surf->poly_verts, tex->vecs[1]) + tex->vecs[1][3];
1559         for (i = 1, v = surf->poly_verts + 3;i < surf->poly_numverts;i++, v += 3)
1560         {
1561                 for (j = 0;j < 2;j++)
1562                 {
1563                         val = DotProduct(v, tex->vecs[j]) + tex->vecs[j][3];
1564                         if (mins[j] > val)
1565                                 mins[j] = val;
1566                         if (maxs[j] < val)
1567                                 maxs[j] = val;
1568                 }
1569         }
1570         for (i = 0;i < 2;i++)
1571         {
1572                 surf->texturemins[i] = (int) floor(mins[i] / 16) * 16;
1573                 surf->extents[i] = (int) ceil(maxs[i] / 16) * 16 - surf->texturemins[i];
1574         }
1575 }
1576
1577 /*
1578 =================
1579 Mod_LoadFaces
1580 =================
1581 */
1582 static void Mod_LoadFaces (lump_t *l)
1583 {
1584         dface_t *in;
1585         msurface_t      *out;
1586         int i, count, surfnum, planenum, ssize, tsize, firstedge, numedges;
1587
1588         in = (void *)(mod_base + l->fileofs);
1589         if (l->filelen % sizeof(*in))
1590                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1591         count = l->filelen / sizeof(*in);
1592         out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1593
1594         loadmodel->surfaces = out;
1595         loadmodel->numsurfaces = count;
1596         loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1597         loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1598         loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1599
1600         for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1601         {
1602                 out->number = surfnum;
1603                 // FIXME: validate edges, texinfo, etc?
1604                 firstedge = LittleLong(in->firstedge);
1605                 numedges = LittleShort(in->numedges);
1606                 if ((unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->numsurfedges)
1607                         Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->numsurfedges);
1608
1609                 i = LittleShort (in->texinfo);
1610                 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1611                         Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1612                 out->texinfo = loadmodel->texinfo + i;
1613                 out->flags = out->texinfo->texture->flags;
1614
1615                 planenum = LittleShort(in->planenum);
1616                 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1617                         Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1618
1619                 if (LittleShort(in->side))
1620                         out->flags |= SURF_PLANEBACK;
1621
1622                 out->plane = loadmodel->planes + planenum;
1623
1624                 // clear lightmap (filled in later)
1625                 out->lightmaptexture = NULL;
1626
1627                 // force lightmap upload on first time seeing the surface
1628                 out->cached_dlight = true;
1629
1630                 Mod_GenerateSurfacePolygon(out, firstedge, numedges);
1631
1632                 ssize = (out->extents[0] >> 4) + 1;
1633                 tsize = (out->extents[1] >> 4) + 1;
1634
1635                 // lighting info
1636                 for (i = 0;i < MAXLIGHTMAPS;i++)
1637                         out->styles[i] = in->styles[i];
1638                 i = LittleLong(in->lightofs);
1639                 if (i == -1)
1640                         out->samples = NULL;
1641                 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1642                         out->samples = loadmodel->lightdata + i;
1643                 else // LordHavoc: white lighting (bsp version 29)
1644                         out->samples = loadmodel->lightdata + (i * 3);
1645
1646                 if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
1647                 {
1648                         if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
1649                                 Host_Error ("Bad surface extents");
1650                         Mod_GenerateWallMesh (out, false);
1651                         // stainmap for permanent marks on walls
1652                         out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1653                         // clear to white
1654                         memset(out->stainsamples, 255, ssize * tsize * 3);
1655                 }
1656                 else
1657                         Mod_GenerateVertexMesh (out);
1658         }
1659 }
1660
1661 /*
1662 =================
1663 Mod_SetParent
1664 =================
1665 */
1666 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1667 {
1668         node->parent = parent;
1669         if (node->contents < 0)
1670                 return;
1671         Mod_SetParent (node->children[0], node);
1672         Mod_SetParent (node->children[1], node);
1673 }
1674
1675 /*
1676 =================
1677 Mod_LoadNodes
1678 =================
1679 */
1680 static void Mod_LoadNodes (lump_t *l)
1681 {
1682         int                     i, j, count, p;
1683         dnode_t         *in;
1684         mnode_t         *out;
1685
1686         in = (void *)(mod_base + l->fileofs);
1687         if (l->filelen % sizeof(*in))
1688                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1689         count = l->filelen / sizeof(*in);
1690         out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1691
1692         loadmodel->nodes = out;
1693         loadmodel->numnodes = count;
1694
1695         for ( i=0 ; i<count ; i++, in++, out++)
1696         {
1697                 for (j=0 ; j<3 ; j++)
1698                 {
1699                         out->mins[j] = LittleShort (in->mins[j]);
1700                         out->maxs[j] = LittleShort (in->maxs[j]);
1701                 }
1702
1703                 p = LittleLong(in->planenum);
1704                 out->plane = loadmodel->planes + p;
1705
1706                 out->firstsurface = LittleShort (in->firstface);
1707                 out->numsurfaces = LittleShort (in->numfaces);
1708
1709                 for (j=0 ; j<2 ; j++)
1710                 {
1711                         p = LittleShort (in->children[j]);
1712                         if (p >= 0)
1713                                 out->children[j] = loadmodel->nodes + p;
1714                         else
1715                                 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1716                 }
1717         }
1718
1719         Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1720 }
1721
1722 /*
1723 =================
1724 Mod_LoadLeafs
1725 =================
1726 */
1727 static void Mod_LoadLeafs (lump_t *l)
1728 {
1729         dleaf_t         *in;
1730         mleaf_t         *out;
1731         int                     i, j, count, p;
1732
1733         in = (void *)(mod_base + l->fileofs);
1734         if (l->filelen % sizeof(*in))
1735                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1736         count = l->filelen / sizeof(*in);
1737         out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1738
1739         loadmodel->leafs = out;
1740         loadmodel->numleafs = count;
1741
1742         for ( i=0 ; i<count ; i++, in++, out++)
1743         {
1744                 for (j=0 ; j<3 ; j++)
1745                 {
1746                         out->mins[j] = LittleShort (in->mins[j]);
1747                         out->maxs[j] = LittleShort (in->maxs[j]);
1748                 }
1749
1750                 p = LittleLong(in->contents);
1751                 out->contents = p;
1752
1753                 out->firstmarksurface = loadmodel->marksurfaces +
1754                         LittleShort(in->firstmarksurface);
1755                 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1756
1757                 p = LittleLong(in->visofs);
1758                 if (p == -1)
1759                         out->compressed_vis = NULL;
1760                 else
1761                         out->compressed_vis = loadmodel->visdata + p;
1762
1763                 for (j=0 ; j<4 ; j++)
1764                         out->ambient_sound_level[j] = in->ambient_level[j];
1765
1766                 // FIXME: Insert caustics here
1767         }
1768 }
1769
1770 /*
1771 =================
1772 Mod_LoadClipnodes
1773 =================
1774 */
1775 static void Mod_LoadClipnodes (lump_t *l)
1776 {
1777         dclipnode_t *in, *out;
1778         int                     i, count;
1779         hull_t          *hull;
1780
1781         in = (void *)(mod_base + l->fileofs);
1782         if (l->filelen % sizeof(*in))
1783                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1784         count = l->filelen / sizeof(*in);
1785         out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1786
1787         loadmodel->clipnodes = out;
1788         loadmodel->numclipnodes = count;
1789
1790         if (loadmodel->ishlbsp)
1791         {
1792                 hull = &loadmodel->hulls[1];
1793                 hull->clipnodes = out;
1794                 hull->firstclipnode = 0;
1795                 hull->lastclipnode = count-1;
1796                 hull->planes = loadmodel->planes;
1797                 hull->clip_mins[0] = -16;
1798                 hull->clip_mins[1] = -16;
1799                 hull->clip_mins[2] = -36;
1800                 hull->clip_maxs[0] = 16;
1801                 hull->clip_maxs[1] = 16;
1802                 hull->clip_maxs[2] = 36;
1803                 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1804
1805                 hull = &loadmodel->hulls[2];
1806                 hull->clipnodes = out;
1807                 hull->firstclipnode = 0;
1808                 hull->lastclipnode = count-1;
1809                 hull->planes = loadmodel->planes;
1810                 hull->clip_mins[0] = -32;
1811                 hull->clip_mins[1] = -32;
1812                 hull->clip_mins[2] = -32;
1813                 hull->clip_maxs[0] = 32;
1814                 hull->clip_maxs[1] = 32;
1815                 hull->clip_maxs[2] = 32;
1816                 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1817
1818                 hull = &loadmodel->hulls[3];
1819                 hull->clipnodes = out;
1820                 hull->firstclipnode = 0;
1821                 hull->lastclipnode = count-1;
1822                 hull->planes = loadmodel->planes;
1823                 hull->clip_mins[0] = -16;
1824                 hull->clip_mins[1] = -16;
1825                 hull->clip_mins[2] = -18;
1826                 hull->clip_maxs[0] = 16;
1827                 hull->clip_maxs[1] = 16;
1828                 hull->clip_maxs[2] = 18;
1829                 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1830         }
1831         else
1832         {
1833                 hull = &loadmodel->hulls[1];
1834                 hull->clipnodes = out;
1835                 hull->firstclipnode = 0;
1836                 hull->lastclipnode = count-1;
1837                 hull->planes = loadmodel->planes;
1838                 hull->clip_mins[0] = -16;
1839                 hull->clip_mins[1] = -16;
1840                 hull->clip_mins[2] = -24;
1841                 hull->clip_maxs[0] = 16;
1842                 hull->clip_maxs[1] = 16;
1843                 hull->clip_maxs[2] = 32;
1844                 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1845
1846                 hull = &loadmodel->hulls[2];
1847                 hull->clipnodes = out;
1848                 hull->firstclipnode = 0;
1849                 hull->lastclipnode = count-1;
1850                 hull->planes = loadmodel->planes;
1851                 hull->clip_mins[0] = -32;
1852                 hull->clip_mins[1] = -32;
1853                 hull->clip_mins[2] = -24;
1854                 hull->clip_maxs[0] = 32;
1855                 hull->clip_maxs[1] = 32;
1856                 hull->clip_maxs[2] = 64;
1857                 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1858         }
1859
1860         for (i=0 ; i<count ; i++, out++, in++)
1861         {
1862                 out->planenum = LittleLong(in->planenum);
1863                 out->children[0] = LittleShort(in->children[0]);
1864                 out->children[1] = LittleShort(in->children[1]);
1865                 if (out->children[0] >= count || out->children[1] >= count)
1866                         Host_Error("Corrupt clipping hull (out of range child)\n");
1867         }
1868 }
1869
1870 /*
1871 =================
1872 Mod_MakeHull0
1873
1874 Duplicate the drawing hull structure as a clipping hull
1875 =================
1876 */
1877 static void Mod_MakeHull0 (void)
1878 {
1879         mnode_t         *in;
1880         dclipnode_t *out;
1881         int                     i;
1882         hull_t          *hull;
1883
1884         hull = &loadmodel->hulls[0];
1885
1886         in = loadmodel->nodes;
1887         out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1888
1889         hull->clipnodes = out;
1890         hull->firstclipnode = 0;
1891         hull->lastclipnode = loadmodel->numnodes - 1;
1892         hull->planes = loadmodel->planes;
1893
1894         for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1895         {
1896                 out->planenum = in->plane - loadmodel->planes;
1897                 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1898                 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1899         }
1900 }
1901
1902 /*
1903 =================
1904 Mod_LoadMarksurfaces
1905 =================
1906 */
1907 static void Mod_LoadMarksurfaces (lump_t *l)
1908 {
1909         int i, j;
1910         short *in;
1911
1912         in = (void *)(mod_base + l->fileofs);
1913         if (l->filelen % sizeof(*in))
1914                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1915         loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1916         loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1917
1918         for (i = 0;i < loadmodel->nummarksurfaces;i++)
1919         {
1920                 j = (unsigned) LittleShort(in[i]);
1921                 if (j >= loadmodel->numsurfaces)
1922                         Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1923                 loadmodel->marksurfaces[i] = j;
1924         }
1925 }
1926
1927 /*
1928 =================
1929 Mod_LoadSurfedges
1930 =================
1931 */
1932 static void Mod_LoadSurfedges (lump_t *l)
1933 {
1934         int             i;
1935         int             *in;
1936
1937         in = (void *)(mod_base + l->fileofs);
1938         if (l->filelen % sizeof(*in))
1939                 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1940         loadmodel->numsurfedges = l->filelen / sizeof(*in);
1941         loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1942
1943         for (i = 0;i < loadmodel->numsurfedges;i++)
1944                 loadmodel->surfedges[i] = LittleLong (in[i]);
1945 }
1946
1947
1948 /*
1949 =================
1950 Mod_LoadPlanes
1951 =================
1952 */
1953 static void Mod_LoadPlanes (lump_t *l)
1954 {
1955         int                     i;
1956         mplane_t        *out;
1957         dplane_t        *in;
1958
1959         in = (void *)(mod_base + l->fileofs);
1960         if (l->filelen % sizeof(*in))
1961                 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1962
1963         loadmodel->numplanes = l->filelen / sizeof(*in);
1964         loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1965
1966         for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1967         {
1968                 out->normal[0] = LittleFloat (in->normal[0]);
1969                 out->normal[1] = LittleFloat (in->normal[1]);
1970                 out->normal[2] = LittleFloat (in->normal[2]);
1971                 out->dist = LittleFloat (in->dist);
1972
1973                 PlaneClassify(out);
1974         }
1975 }
1976
1977 #define MAX_POINTS_ON_WINDING 64
1978
1979 typedef struct
1980 {
1981         int numpoints;
1982         int padding;
1983         double points[8][3]; // variable sized
1984 }
1985 winding_t;
1986
1987 /*
1988 ==================
1989 NewWinding
1990 ==================
1991 */
1992 static winding_t *NewWinding (int points)
1993 {
1994         winding_t *w;
1995         int size;
1996
1997         if (points > MAX_POINTS_ON_WINDING)
1998                 Sys_Error("NewWinding: too many points\n");
1999
2000         size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
2001         w = Mem_Alloc(loadmodel->mempool, size);
2002         memset (w, 0, size);
2003
2004         return w;
2005 }
2006
2007 static void FreeWinding (winding_t *w)
2008 {
2009         Mem_Free(w);
2010 }
2011
2012 /*
2013 =================
2014 BaseWindingForPlane
2015 =================
2016 */
2017 static winding_t *BaseWindingForPlane (mplane_t *p)
2018 {
2019         double org[3], vright[3], vup[3], normal[3];
2020         winding_t *w;
2021
2022         VectorCopy(p->normal, normal);
2023         VectorVectorsDouble(normal, vright, vup);
2024
2025         VectorScale (vup, 1024.0*1024.0*1024.0, vup);
2026         VectorScale (vright, 1024.0*1024.0*1024.0, vright);
2027
2028         // project a really big axis aligned box onto the plane
2029         w = NewWinding (4);
2030
2031         VectorScale (p->normal, p->dist, org);
2032
2033         VectorSubtract (org, vright, w->points[0]);
2034         VectorAdd (w->points[0], vup, w->points[0]);
2035
2036         VectorAdd (org, vright, w->points[1]);
2037         VectorAdd (w->points[1], vup, w->points[1]);
2038
2039         VectorAdd (org, vright, w->points[2]);
2040         VectorSubtract (w->points[2], vup, w->points[2]);
2041
2042         VectorSubtract (org, vright, w->points[3]);
2043         VectorSubtract (w->points[3], vup, w->points[3]);
2044
2045         w->numpoints = 4;
2046
2047         return w;
2048 }
2049
2050 /*
2051 ==================
2052 ClipWinding
2053
2054 Clips the winding to the plane, returning the new winding on the positive side
2055 Frees the input winding.
2056 If keepon is true, an exactly on-plane winding will be saved, otherwise
2057 it will be clipped away.
2058 ==================
2059 */
2060 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2061 {
2062         double  dists[MAX_POINTS_ON_WINDING + 1];
2063         int             sides[MAX_POINTS_ON_WINDING + 1];
2064         int             counts[3];
2065         double  dot;
2066         int             i, j;
2067         double  *p1, *p2;
2068         double  mid[3];
2069         winding_t       *neww;
2070         int             maxpts;
2071
2072         counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2073
2074         // determine sides for each point
2075         for (i = 0;i < in->numpoints;i++)
2076         {
2077                 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2078                 if (dot > ON_EPSILON)
2079                         sides[i] = SIDE_FRONT;
2080                 else if (dot < -ON_EPSILON)
2081                         sides[i] = SIDE_BACK;
2082                 else
2083                         sides[i] = SIDE_ON;
2084                 counts[sides[i]]++;
2085         }
2086         sides[i] = sides[0];
2087         dists[i] = dists[0];
2088
2089         if (keepon && !counts[0] && !counts[1])
2090                 return in;
2091
2092         if (!counts[0])
2093         {
2094                 FreeWinding (in);
2095                 return NULL;
2096         }
2097         if (!counts[1])
2098                 return in;
2099
2100         maxpts = in->numpoints+4;       // can't use counts[0]+2 because of fp grouping errors
2101         if (maxpts > MAX_POINTS_ON_WINDING)
2102                 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2103
2104         neww = NewWinding (maxpts);
2105
2106         for (i = 0;i < in->numpoints;i++)
2107         {
2108                 if (neww->numpoints >= maxpts)
2109                         Sys_Error ("ClipWinding: points exceeded estimate");
2110
2111                 p1 = in->points[i];
2112
2113                 if (sides[i] == SIDE_ON)
2114                 {
2115                         VectorCopy (p1, neww->points[neww->numpoints]);
2116                         neww->numpoints++;
2117                         continue;
2118                 }
2119
2120                 if (sides[i] == SIDE_FRONT)
2121                 {
2122                         VectorCopy (p1, neww->points[neww->numpoints]);
2123                         neww->numpoints++;
2124                 }
2125
2126                 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2127                         continue;
2128
2129                 // generate a split point
2130                 p2 = in->points[(i+1)%in->numpoints];
2131
2132                 dot = dists[i] / (dists[i]-dists[i+1]);
2133                 for (j = 0;j < 3;j++)
2134                 {       // avoid round off error when possible
2135                         if (split->normal[j] == 1)
2136                                 mid[j] = split->dist;
2137                         else if (split->normal[j] == -1)
2138                                 mid[j] = -split->dist;
2139                         else
2140                                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2141                 }
2142
2143                 VectorCopy (mid, neww->points[neww->numpoints]);
2144                 neww->numpoints++;
2145         }
2146
2147         // free the original winding
2148         FreeWinding (in);
2149
2150         return neww;
2151 }
2152
2153
2154 /*
2155 ==================
2156 DivideWinding
2157
2158 Divides a winding by a plane, producing one or two windings.  The
2159 original winding is not damaged or freed.  If only on one side, the
2160 returned winding will be the input winding.  If on both sides, two
2161 new windings will be created.
2162 ==================
2163 */
2164 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2165 {
2166         double  dists[MAX_POINTS_ON_WINDING + 1];
2167         int             sides[MAX_POINTS_ON_WINDING + 1];
2168         int             counts[3];
2169         double  dot;
2170         int             i, j;
2171         double  *p1, *p2;
2172         double  mid[3];
2173         winding_t       *f, *b;
2174         int             maxpts;
2175
2176         counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2177
2178         // determine sides for each point
2179         for (i = 0;i < in->numpoints;i++)
2180         {
2181                 dot = DotProduct (in->points[i], split->normal);
2182                 dot -= split->dist;
2183                 dists[i] = dot;
2184                 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2185                 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2186                 else sides[i] = SIDE_ON;
2187                 counts[sides[i]]++;
2188         }
2189         sides[i] = sides[0];
2190         dists[i] = dists[0];
2191
2192         *front = *back = NULL;
2193
2194         if (!counts[0])
2195         {
2196                 *back = in;
2197                 return;
2198         }
2199         if (!counts[1])
2200         {
2201                 *front = in;
2202                 return;
2203         }
2204
2205         maxpts = in->numpoints+4;       // can't use counts[0]+2 because of fp grouping errors
2206
2207         if (maxpts > MAX_POINTS_ON_WINDING)
2208                 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2209
2210         *front = f = NewWinding (maxpts);
2211         *back = b = NewWinding (maxpts);
2212
2213         for (i = 0;i < in->numpoints;i++)
2214         {
2215                 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2216                         Sys_Error ("DivideWinding: points exceeded estimate");
2217
2218                 p1 = in->points[i];
2219
2220                 if (sides[i] == SIDE_ON)
2221                 {
2222                         VectorCopy (p1, f->points[f->numpoints]);
2223                         f->numpoints++;
2224                         VectorCopy (p1, b->points[b->numpoints]);
2225                         b->numpoints++;
2226                         continue;
2227                 }
2228
2229                 if (sides[i] == SIDE_FRONT)
2230                 {
2231                         VectorCopy (p1, f->points[f->numpoints]);
2232                         f->numpoints++;
2233                 }
2234                 else if (sides[i] == SIDE_BACK)
2235                 {
2236                         VectorCopy (p1, b->points[b->numpoints]);
2237                         b->numpoints++;
2238                 }
2239
2240                 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2241                         continue;
2242
2243                 // generate a split point
2244                 p2 = in->points[(i+1)%in->numpoints];
2245
2246                 dot = dists[i] / (dists[i]-dists[i+1]);
2247                 for (j = 0;j < 3;j++)
2248                 {       // avoid round off error when possible
2249                         if (split->normal[j] == 1)
2250                                 mid[j] = split->dist;
2251                         else if (split->normal[j] == -1)
2252                                 mid[j] = -split->dist;
2253                         else
2254                                 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2255                 }
2256
2257                 VectorCopy (mid, f->points[f->numpoints]);
2258                 f->numpoints++;
2259                 VectorCopy (mid, b->points[b->numpoints]);
2260                 b->numpoints++;
2261         }
2262 }
2263
2264 typedef struct portal_s
2265 {
2266         mplane_t plane;
2267         mnode_t *nodes[2];              // [0] = front side of plane
2268         struct portal_s *next[2];
2269         winding_t *winding;
2270         struct portal_s *chain; // all portals are linked into a list
2271 }
2272 portal_t;
2273
2274 static portal_t *portalchain;
2275
2276 /*
2277 ===========
2278 AllocPortal
2279 ===========
2280 */
2281 static portal_t *AllocPortal (void)
2282 {
2283         portal_t *p;
2284         p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2285         p->chain = portalchain;
2286         portalchain = p;
2287         return p;
2288 }
2289
2290 static void FreePortal(portal_t *p)
2291 {
2292         Mem_Free(p);
2293 }
2294
2295 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2296 {
2297         // calculate children first
2298         if (node->children[0]->contents >= 0)
2299                 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2300         if (node->children[1]->contents >= 0)
2301                 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2302
2303         // make combined bounding box from children
2304         node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2305         node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2306         node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2307         node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2308         node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2309         node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2310 }
2311
2312 static void Mod_FinalizePortals(void)
2313 {
2314         int i, j, numportals, numpoints;
2315         portal_t *p, *pnext;
2316         mportal_t *portal;
2317         mvertex_t *point;
2318         mleaf_t *leaf, *endleaf;
2319         winding_t *w;
2320
2321         // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2322         leaf = loadmodel->leafs;
2323         endleaf = leaf + loadmodel->numleafs;
2324         for (;leaf < endleaf;leaf++)
2325         {
2326                 VectorSet(leaf->mins,  2000000000,  2000000000,  2000000000);
2327                 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2328         }
2329         p = portalchain;
2330         while(p)
2331         {
2332                 if (p->winding)
2333                 {
2334                         for (i = 0;i < 2;i++)
2335                         {
2336                                 leaf = (mleaf_t *)p->nodes[i];
2337                                 w = p->winding;
2338                                 for (j = 0;j < w->numpoints;j++)
2339                                 {
2340                                         if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2341                                         if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2342                                         if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2343                                         if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2344                                         if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2345                                         if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2346                                 }
2347                         }
2348                 }
2349                 p = p->chain;
2350         }
2351
2352         Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2353
2354         // tally up portal and point counts
2355         p = portalchain;
2356         numportals = 0;
2357         numpoints = 0;
2358         while(p)
2359         {
2360                 // note: this check must match the one below or it will usually corrupt memory
2361                 // 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
2362                 if (p->winding && p->nodes[0] != p->nodes[1]
2363                  && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2364                  && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2365                 {
2366                         numportals += 2;
2367                         numpoints += p->winding->numpoints * 2;
2368                 }
2369                 p = p->chain;
2370         }
2371         loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2372         loadmodel->numportals = numportals;
2373         loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2374         loadmodel->numportalpoints = numpoints;
2375         // clear all leaf portal chains
2376         for (i = 0;i < loadmodel->numleafs;i++)
2377                 loadmodel->leafs[i].portals = NULL;
2378         // process all portals in the global portal chain, while freeing them
2379         portal = loadmodel->portals;
2380         point = loadmodel->portalpoints;
2381         p = portalchain;
2382         portalchain = NULL;
2383         while (p)
2384         {
2385                 pnext = p->chain;
2386
2387                 if (p->winding)
2388                 {
2389                         // note: this check must match the one above or it will usually corrupt memory
2390                         // 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
2391                         if (p->nodes[0] != p->nodes[1]
2392                          && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2393                          && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2394                         {
2395                                 // first make the back to front portal (forward portal)
2396                                 portal->points = point;
2397                                 portal->numpoints = p->winding->numpoints;
2398                                 portal->plane.dist = p->plane.dist;
2399                                 VectorCopy(p->plane.normal, portal->plane.normal);
2400                                 portal->here = (mleaf_t *)p->nodes[1];
2401                                 portal->past = (mleaf_t *)p->nodes[0];
2402                                 // copy points
2403                                 for (j = 0;j < portal->numpoints;j++)
2404                                 {
2405                                         VectorCopy(p->winding->points[j], point->position);
2406                                         point++;
2407                                 }
2408                                 PlaneClassify(&portal->plane);
2409
2410                                 // link into leaf's portal chain
2411                                 portal->next = portal->here->portals;
2412                                 portal->here->portals = portal;
2413
2414                                 // advance to next portal
2415                                 portal++;
2416
2417                                 // then make the front to back portal (backward portal)
2418                                 portal->points = point;
2419                                 portal->numpoints = p->winding->numpoints;
2420                                 portal->plane.dist = -p->plane.dist;
2421                                 VectorNegate(p->plane.normal, portal->plane.normal);
2422                                 portal->here = (mleaf_t *)p->nodes[0];
2423                                 portal->past = (mleaf_t *)p->nodes[1];
2424                                 // copy points
2425                                 for (j = portal->numpoints - 1;j >= 0;j--)
2426                                 {
2427                                         VectorCopy(p->winding->points[j], point->position);
2428                                         point++;
2429                                 }
2430                                 PlaneClassify(&portal->plane);
2431
2432                                 // link into leaf's portal chain
2433                                 portal->next = portal->here->portals;
2434                                 portal->here->portals = portal;
2435
2436                                 // advance to next portal
2437                                 portal++;
2438                         }
2439                         FreeWinding(p->winding);
2440                 }
2441                 FreePortal(p);
2442                 p = pnext;
2443         }
2444 }
2445
2446 /*
2447 =============
2448 AddPortalToNodes
2449 =============
2450 */
2451 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2452 {
2453         if (!front)
2454                 Host_Error ("AddPortalToNodes: NULL front node");
2455         if (!back)
2456                 Host_Error ("AddPortalToNodes: NULL back node");
2457         if (p->nodes[0] || p->nodes[1])
2458                 Host_Error ("AddPortalToNodes: already included");
2459         // 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
2460
2461         p->nodes[0] = front;
2462         p->next[0] = (portal_t *)front->portals;
2463         front->portals = (mportal_t *)p;
2464
2465         p->nodes[1] = back;
2466         p->next[1] = (portal_t *)back->portals;
2467         back->portals = (mportal_t *)p;
2468 }
2469
2470 /*
2471 =============
2472 RemovePortalFromNode
2473 =============
2474 */
2475 static void RemovePortalFromNodes(portal_t *portal)
2476 {
2477         int i;
2478         mnode_t *node;
2479         void **portalpointer;
2480         portal_t *t;
2481         for (i = 0;i < 2;i++)
2482         {
2483                 node = portal->nodes[i];
2484
2485                 portalpointer = (void **) &node->portals;
2486                 while (1)
2487                 {
2488                         t = *portalpointer;
2489                         if (!t)
2490                                 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2491
2492                         if (t == portal)
2493                         {
2494                                 if (portal->nodes[0] == node)
2495                                 {
2496                                         *portalpointer = portal->next[0];
2497                                         portal->nodes[0] = NULL;
2498                                 }
2499                                 else if (portal->nodes[1] == node)
2500                                 {
2501                                         *portalpointer = portal->next[1];
2502                                         portal->nodes[1] = NULL;
2503                                 }
2504                                 else
2505                                         Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2506                                 break;
2507                         }
2508
2509                         if (t->nodes[0] == node)
2510                                 portalpointer = (void **) &t->next[0];
2511                         else if (t->nodes[1] == node)
2512                                 portalpointer = (void **) &t->next[1];
2513                         else
2514                                 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2515                 }
2516         }
2517 }
2518
2519 static void Mod_RecursiveNodePortals (mnode_t *node)
2520 {
2521         int side;
2522         mnode_t *front, *back, *other_node;
2523         mplane_t clipplane, *plane;
2524         portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2525         winding_t *nodeportalwinding, *frontwinding, *backwinding;
2526
2527         // if a leaf, we're done
2528         if (node->contents)
2529                 return;
2530
2531         plane = node->plane;
2532
2533         front = node->children[0];
2534         back = node->children[1];
2535         if (front == back)
2536                 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2537
2538         // create the new portal by generating a polygon for the node plane,
2539         // and clipping it by all of the other portals (which came from nodes above this one)
2540         nodeportal = AllocPortal ();
2541         nodeportal->plane = *node->plane;
2542
2543         nodeportalwinding = BaseWindingForPlane (node->plane);
2544         side = 0;       // shut up compiler warning
2545         for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2546         {
2547                 clipplane = portal->plane;
2548                 if (portal->nodes[0] == portal->nodes[1])
2549                         Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2550                 if (portal->nodes[0] == node)
2551                         side = 0;
2552                 else if (portal->nodes[1] == node)
2553                 {
2554                         clipplane.dist = -clipplane.dist;
2555                         VectorNegate (clipplane.normal, clipplane.normal);
2556                         side = 1;
2557                 }
2558                 else
2559                         Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2560
2561                 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2562                 if (!nodeportalwinding)
2563                 {
2564                         Con_Printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2565                         break;
2566                 }
2567         }
2568
2569         if (nodeportalwinding)
2570         {
2571                 // if the plane was not clipped on all sides, there was an error
2572                 nodeportal->winding = nodeportalwinding;
2573                 AddPortalToNodes (nodeportal, front, back);
2574         }
2575
2576         // split the portals of this node along this node's plane and assign them to the children of this node
2577         // (migrating the portals downward through the tree)
2578         for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2579         {
2580                 if (portal->nodes[0] == portal->nodes[1])
2581                         Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2582                 if (portal->nodes[0] == node)
2583                         side = 0;
2584                 else if (portal->nodes[1] == node)
2585                         side = 1;
2586                 else
2587                         Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2588                 nextportal = portal->next[side];
2589
2590                 other_node = portal->nodes[!side];
2591                 RemovePortalFromNodes (portal);
2592
2593                 // cut the portal into two portals, one on each side of the node plane
2594                 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2595
2596                 if (!frontwinding)
2597                 {
2598                         if (side == 0)
2599                                 AddPortalToNodes (portal, back, other_node);
2600                         else
2601                                 AddPortalToNodes (portal, other_node, back);
2602                         continue;
2603                 }
2604                 if (!backwinding)
2605                 {
2606                         if (side == 0)
2607                                 AddPortalToNodes (portal, front, other_node);
2608                         else
2609                                 AddPortalToNodes (portal, other_node, front);
2610                         continue;
2611                 }
2612
2613                 // the winding is split
2614                 splitportal = AllocPortal ();
2615                 temp = splitportal->chain;
2616                 *splitportal = *portal;
2617                 splitportal->chain = temp;
2618                 splitportal->winding = backwinding;
2619                 FreeWinding (portal->winding);
2620                 portal->winding = frontwinding;
2621
2622                 if (side == 0)
2623                 {
2624                         AddPortalToNodes (portal, front, other_node);
2625                         AddPortalToNodes (splitportal, back, other_node);
2626                 }
2627                 else
2628                 {
2629                         AddPortalToNodes (portal, other_node, front);
2630                         AddPortalToNodes (splitportal, other_node, back);
2631                 }
2632         }
2633
2634         Mod_RecursiveNodePortals(front);
2635         Mod_RecursiveNodePortals(back);
2636 }
2637
2638
2639 static void Mod_MakePortals(void)
2640 {
2641         portalchain = NULL;
2642         Mod_RecursiveNodePortals (loadmodel->nodes);
2643         Mod_FinalizePortals();
2644 }
2645
2646 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2647 {
2648 #if 0
2649         int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2650         msurface_t *surf, *s;
2651         float *v0, *v1, *v2, *v3;
2652         for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2653                 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2654         for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2655         {
2656                 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)
2657                 {
2658                         if (surf->neighborsurfaces[vertnum])
2659                                 continue;
2660                         surf->neighborsurfaces[vertnum] = NULL;
2661                         for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2662                         {
2663                                 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2664                                  || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2665                                  || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2666                                  || s == surf)
2667                                         continue;
2668                                 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2669                                         if (s->neighborsurfaces[vnum] == surf)
2670                                                 break;
2671                                 if (vnum < s->poly_numverts)
2672                                         continue;
2673                                 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)
2674                                 {
2675                                         if (s->neighborsurfaces[vnum] == NULL
2676                                          && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2677                                           || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2678                                         {
2679                                                 surf->neighborsurfaces[vertnum] = s;
2680                                                 s->neighborsurfaces[vnum] = surf;
2681                                                 break;
2682                                         }
2683                                 }
2684                                 if (vnum < s->poly_numverts)
2685                                         break;
2686                         }
2687                 }
2688         }
2689 #endif
2690 }
2691
2692 void Mod_BuildLightmapUpdateChains(mempool_t *mempool, model_t *model)
2693 {
2694         int i, j, stylecounts[256], totalcount, remapstyles[256];
2695         msurface_t *surf;
2696         memset(stylecounts, 0, sizeof(stylecounts));
2697         for (i = 0;i < model->nummodelsurfaces;i++)
2698         {
2699                 surf = model->surfaces + model->firstmodelsurface + i;
2700                 for (j = 0;j < MAXLIGHTMAPS;j++)
2701                         stylecounts[surf->styles[j]]++;
2702         }
2703         totalcount = 0;
2704         model->light_styles = 0;
2705         for (i = 0;i < 255;i++)
2706         {
2707                 if (stylecounts[i])
2708                 {
2709                         remapstyles[i] = model->light_styles++;
2710                         totalcount += stylecounts[i] + 1;
2711                 }
2712         }
2713         if (!totalcount)
2714                 return;
2715         model->light_style = Mem_Alloc(mempool, model->light_styles * sizeof(qbyte));
2716         model->light_stylevalue = Mem_Alloc(mempool, model->light_styles * sizeof(int));
2717         model->light_styleupdatechains = Mem_Alloc(mempool, model->light_styles * sizeof(msurface_t **));
2718         model->light_styleupdatechainsbuffer = Mem_Alloc(mempool, totalcount * sizeof(msurface_t *));
2719         model->light_styles = 0;
2720         for (i = 0;i < 255;i++)
2721                 if (stylecounts[i])
2722                         model->light_style[model->light_styles++] = i;
2723         j = 0;
2724         for (i = 0;i < model->light_styles;i++)
2725         {
2726                 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2727                 j += stylecounts[model->light_style[i]] + 1;
2728         }
2729         for (i = 0;i < model->nummodelsurfaces;i++)
2730         {
2731                 surf = model->surfaces + model->firstmodelsurface + i;
2732                 for (j = 0;j < MAXLIGHTMAPS;j++)
2733                         if (surf->styles[j] != 255)
2734                                 *model->light_styleupdatechains[remapstyles[surf->styles[j]]]++ = surf;
2735         }
2736         j = 0;
2737         for (i = 0;i < model->light_styles;i++)
2738         {
2739                 *model->light_styleupdatechains[i] = NULL;
2740                 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2741                 j += stylecounts[model->light_style[i]] + 1;
2742         }
2743 }
2744
2745 void Mod_BuildPVSTextureChains(model_t *model)
2746 {
2747         int i, j;
2748         for (i = 0;i < model->numtextures;i++)
2749                 model->pvstexturechainslength[i] = 0;
2750         for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2751         {
2752                 if (model->surfacepvsframes[j] == model->pvsframecount)
2753                 {
2754                         model->pvssurflist[model->pvssurflistlength++] = j;
2755                         model->pvstexturechainslength[model->surfaces[j].texinfo->texture->number]++;
2756                 }
2757         }
2758         for (i = 0, j = 0;i < model->numtextures;i++)
2759         {
2760                 if (model->pvstexturechainslength[i])
2761                 {
2762                         model->pvstexturechains[i] = model->pvstexturechainsbuffer + j;
2763                         j += model->pvstexturechainslength[i] + 1;
2764                 }
2765                 else
2766                         model->pvstexturechains[i] = NULL;
2767         }
2768         for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2769                 if (model->surfacepvsframes[j] == model->pvsframecount)
2770                         *model->pvstexturechains[model->surfaces[j].texinfo->texture->number]++ = model->surfaces + j;
2771         for (i = 0;i < model->numtextures;i++)
2772         {
2773                 if (model->pvstexturechainslength[i])
2774                 {
2775                         *model->pvstexturechains[i] = NULL;
2776                         model->pvstexturechains[i] -= model->pvstexturechainslength[i];
2777                 }
2778         }
2779 }
2780
2781 /*
2782 =================
2783 Mod_LoadBrushModel
2784 =================
2785 */
2786 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2787 extern void R_Model_Brush_Draw(entity_render_t *ent);
2788 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2789 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);
2790 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2791 {
2792         int i, j, k;
2793         dheader_t *header;
2794         dmodel_t *bm;
2795         mempool_t *mainmempool;
2796         char *loadname;
2797         model_t *originalloadmodel;
2798         float dist, modelyawradius, modelradius, *vec;
2799         msurface_t *surf;
2800         surfmesh_t *mesh;
2801
2802         mod->type = mod_brush;
2803
2804         header = (dheader_t *)buffer;
2805
2806         i = LittleLong (header->version);
2807         if (i != BSPVERSION && i != 30)
2808                 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2809         mod->ishlbsp = i == 30;
2810         if (loadmodel->isworldmodel)
2811         {
2812                 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2813                 // until we get a texture for it...
2814                 R_ResetQuakeSky();
2815         }
2816
2817 // swap all the lumps
2818         mod_base = (qbyte *)header;
2819
2820         for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
2821                 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2822
2823 // load into heap
2824
2825         // store which lightmap format to use
2826         mod->lightmaprgba = r_lightmaprgba.integer;
2827
2828         Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2829         Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2830         Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2831         Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2832         Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2833         Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2834         Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2835         Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2836         Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2837         Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2838         Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2839         Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2840         Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2841         Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2842         Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2843
2844         Mod_MakeHull0 ();
2845         Mod_MakePortals();
2846
2847         mod->numframes = 2;             // regular and alternate animation
2848
2849         mainmempool = mod->mempool;
2850         loadname = mod->name;
2851
2852         Mod_LoadLightList ();
2853         originalloadmodel = loadmodel;
2854
2855 //
2856 // set up the submodels (FIXME: this is confusing)
2857 //
2858         for (i = 0;i < mod->numsubmodels;i++)
2859         {
2860                 bm = &mod->submodels[i];
2861
2862                 mod->hulls[0].firstclipnode = bm->headnode[0];
2863                 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2864                 {
2865                         mod->hulls[j].firstclipnode = bm->headnode[j];
2866                         mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2867                 }
2868
2869                 mod->firstmodelsurface = bm->firstface;
2870                 mod->nummodelsurfaces = bm->numfaces;
2871
2872                 // this gets altered below if sky is used
2873                 mod->DrawSky = NULL;
2874                 mod->Draw = R_Model_Brush_Draw;
2875                 mod->DrawFakeShadow = NULL;
2876                 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2877                 mod->DrawLight = R_Model_Brush_DrawLight;
2878                 mod->pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t **));
2879                 mod->pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool, (mod->nummodelsurfaces + mod->numtextures) * sizeof(msurface_t *));
2880                 mod->pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(int));
2881                 Mod_BuildPVSTextureChains(mod);
2882                 Mod_BuildLightmapUpdateChains(originalloadmodel->mempool, mod);
2883                 if (mod->nummodelsurfaces)
2884                 {
2885                         // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2886                         mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2887                         mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2888                         modelyawradius = 0;
2889                         modelradius = 0;
2890                         for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2891                         {
2892                                 // we only need to have a drawsky function if it is used (usually only on world model)
2893                                 if (surf->texinfo->texture->shader == &Cshader_sky)
2894                                         mod->DrawSky = R_Model_Brush_DrawSky;
2895                                 // LordHavoc: submodels always clip, even if water
2896                                 if (mod->numsubmodels - 1)
2897                                         surf->flags |= SURF_SOLIDCLIP;
2898                                 // calculate bounding shapes
2899                                 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
2900                                 {
2901                                         for (k = 0, vec = mesh->vertex3f;k < mesh->numverts;k++, vec += 3)
2902                                         {
2903                                                 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2904                                                 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2905                                                 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2906                                                 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2907                                                 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2908                                                 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2909                                                 dist = vec[0]*vec[0]+vec[1]*vec[1];
2910                                                 if (modelyawradius < dist)
2911                                                         modelyawradius = dist;
2912                                                 dist += vec[2]*vec[2];
2913                                                 if (modelradius < dist)
2914                                                         modelradius = dist;
2915                                         }
2916                                 }
2917                         }
2918                         modelyawradius = sqrt(modelyawradius);
2919                         modelradius = sqrt(modelradius);
2920                         mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2921                         mod->yawmins[2] = mod->normalmins[2];
2922                         mod->yawmaxs[2] = mod->normalmaxs[2];
2923                         mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2924                         mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2925                         mod->radius = modelradius;
2926                         mod->radius2 = modelradius * modelradius;
2927                 }
2928                 else
2929                 {
2930                         // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2931                         Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2932                 }
2933                 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2934
2935                 mod->numleafs = bm->visleafs;
2936
2937                 // LordHavoc: only register submodels if it is the world
2938                 // (prevents bsp models from replacing world submodels)
2939                 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2940                 {
2941                         char    name[10];
2942                         // duplicate the basic information
2943                         sprintf (name, "*%i", i+1);
2944                         loadmodel = Mod_FindName (name);
2945                         *loadmodel = *mod;
2946                         strcpy (loadmodel->name, name);
2947                         // textures and memory belong to the main model
2948                         loadmodel->texturepool = NULL;
2949                         loadmodel->mempool = NULL;
2950                         mod = loadmodel;
2951                 }
2952         }
2953
2954         loadmodel = originalloadmodel;
2955         //Mod_ProcessLightList ();
2956 }
2957