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