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