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