2 Copyright (C) 1996-1997 Id Software, Inc.
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.
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.
13 See the GNU General Public License for more details.
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.
24 // note: model_shared.c sets up r_notexture, and r_surf_notexture
26 qbyte mod_novis[(MAX_MAP_LEAFS + 7)/ 8];
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"};
36 #define NUM_DETAILTEXTURES 1
37 static rtexture_t *detailtextures[NUM_DETAILTEXTURES];
38 static rtexturepool_t *detailtexturepool;
45 void Mod_BrushInit (void)
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));
57 void Mod_BrushStartup (void)
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();
67 VectorNormalize(lightdir);
68 for (i = 0;i < NUM_DETAILTEXTURES;i++)
70 fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4);
71 for (y = 0;y < DETAILRESOLUTION;y++)
73 for (x = 0;x < DETAILRESOLUTION;x++)
77 vc[2] = noise[y][x] * (1.0f / 32.0f);
80 vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f);
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);
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;
94 detailtextures[i] = R_LoadTexture2D(detailtexturepool, va("detailtexture%i", i), DETAILRESOLUTION, DETAILRESOLUTION, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE, NULL);
98 void Mod_BrushShutdown (void)
101 for (i = 0;i < NUM_DETAILTEXTURES;i++)
102 R_FreeTexture(detailtextures[i]);
103 R_FreeTexturePool(&detailtexturepool);
111 mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model)
118 Mod_CheckLoaded(model);
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];
126 return (mleaf_t *)node;
129 int Mod_PointContents (const vec3_t p, model_t *model)
134 return CONTENTS_EMPTY;
136 Mod_CheckLoaded(model);
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];
144 return ((mleaf_t *)node)->contents;
147 void Mod_FindNonSolidLocation(vec3_t pos, model_t *mod)
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;
153 pos[1]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
154 pos[1]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
156 pos[2]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
157 pos[2]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
167 static qbyte *Mod_DecompressVis (qbyte *in, model_t *model)
169 static qbyte decompressed[MAX_MAP_LEAFS/8];
174 row = (model->numleafs+7)>>3;
192 } while (out - decompressed < row);
197 qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
199 if (r_novis.integer || leaf == model->leafs || leaf->compressed_vis == NULL)
201 return Mod_DecompressVis (leaf->compressed_vis, model);
209 static void Mod_LoadTextures (lump_t *l)
211 int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs, incomplete;
213 texture_t *tx, *tx2, *anims[10], *altanims[10];
215 qbyte *data, *mtdata;
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;
223 loadmodel->textures = NULL;
228 m = (dmiptexlump_t *)(mod_base + l->fileofs);
230 m->nummiptex = LittleLong (m->nummiptex);
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));
236 // fill out all slots with notexture
237 for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++)
241 tx->texture = r_notexture;
242 tx->shader = &Cshader_wall_lightmap;
243 if (i == loadmodel->numtextures - 1)
245 tx->flags = SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
246 tx->shader = &Cshader_water;
248 tx->currentframe = tx;
251 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
253 // LordHavoc: mostly rewritten map texture loader
254 for (i = 0;i < m->nummiptex;i++)
256 dofs[i] = LittleLong(dofs[i]);
257 if (dofs[i] == -1 || r_nosurftextures.integer)
259 dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
261 // make sure name is no more than 15 characters
262 for (j = 0;dmiptex->name[j] && j < 15;j++)
263 name[j] = dmiptex->name[j];
266 mtwidth = LittleLong (dmiptex->width);
267 mtheight = LittleLong (dmiptex->height);
269 j = LittleLong (dmiptex->offsets[0]);
273 if (j < 40 || j + mtwidth * mtheight > l->filelen)
275 Con_Printf ("Texture \"%s\" in \"%s\"is corrupt or incomplete\n", dmiptex->name, loadmodel->name);
278 mtdata = (qbyte *)dmiptex + j;
281 if ((mtwidth & 15) || (mtheight & 15))
282 Con_Printf ("warning: texture \"%s\" in \"%s\" is not 16 aligned", dmiptex->name, loadmodel->name);
284 // LordHavoc: force all names to lowercase
285 for (j = 0;name[j];j++)
286 if (name[j] >= 'A' && name[j] <= 'Z')
287 name[j] += 'a' - 'A';
289 tx = loadmodel->textures + i;
290 strcpy(tx->name, name);
292 tx->height = mtheight;
296 sprintf(tx->name, "unnamed%i", i);
297 Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
300 basepixels = NULL;basepixels_width = 0;basepixels_height = 0;
301 bumppixels = NULL;bumppixels_width = 0;bumppixels_height = 0;
302 nmappixels = NULL;nmappixels_width = 0;nmappixels_height = 0;
303 glosspixels = NULL;glosspixels_width = 0;glosspixels_height = 0;
304 glowpixels = NULL;glowpixels_width = 0;glowpixels_height = 0;
305 maskpixels = NULL;maskpixels_width = 0;maskpixels_height = 0;
306 detailtexture = NULL;
308 // LordHavoc: HL sky textures are entirely different than quake
309 if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
311 if (loadmodel->isworldmodel)
313 data = loadimagepixels(tx->name, false, 0, 0);
316 if (image_width == 256 && image_height == 128)
324 Con_Printf ("Invalid replacement texture for sky \"%s\" in %\"%s\", must be 256x128 pixels\n", tx->name, loadmodel->name);
326 R_InitSky (mtdata, 1);
329 else if (mtdata != NULL)
330 R_InitSky (mtdata, 1);
335 if ((basepixels = loadimagepixels(tx->name, false, 0, 0)) != NULL)
337 basepixels_width = image_width;
338 basepixels_height = image_height;
340 // _luma is supported for tenebrae compatibility
341 // (I think it's a very stupid name, but oh well)
342 if ((glowpixels = loadimagepixels(va("%s_glow", tx->name), false, 0, 0)) != NULL
343 || (glowpixels = loadimagepixels(va("%s_luma", tx->name), false, 0, 0)) != NULL)
345 glowpixels_width = image_width;
346 glowpixels_height = image_height;
348 if ((bumppixels = loadimagepixels(va("%s_bump", tx->name), false, 0, 0)) != NULL)
350 bumppixels_width = image_width;
351 bumppixels_height = image_height;
353 if ((glosspixels = loadimagepixels(va("%s_gloss", tx->name), false, 0, 0)) != NULL)
355 glosspixels_width = image_width;
356 glosspixels_height = image_height;
360 if (loadmodel->ishlbsp)
362 // internal texture overrides wad
363 if (mtdata && (basepixels = W_ConvertWAD3Texture(dmiptex)) != NULL)
365 basepixels_width = image_width;
366 basepixels_height = image_height;
368 else if ((basepixels = W_GetTexture(tx->name)) != NULL)
370 // get the size from the wad texture
371 tx->width = basepixels_width = image_width;
372 tx->height = basepixels_height = image_height;
377 if (mtdata) // texture included
379 if (r_fullbrights.integer && tx->name[0] != '*')
381 basepixels_width = tx->width;
382 basepixels_height = tx->height;
383 basepixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
384 Image_Copy8bitRGBA(mtdata, basepixels, basepixels_width * basepixels_height, palette_nofullbrights);
387 for (j = 0;j < (int)(tx->width*tx->height);j++)
388 if (((qbyte *)&palette_onlyfullbrights[mtdata[j]])[3] > 0) // fullbright
390 if (j < (int)(tx->width * tx->height))
392 glowpixels_width = tx->width;
393 glowpixels_height = tx->height;
394 glowpixels = Mem_Alloc(loadmodel->mempool, glowpixels_width * glowpixels_height * 4);
395 Image_Copy8bitRGBA(mtdata, glowpixels, glowpixels_width * glowpixels_height, palette_onlyfullbrights);
401 basepixels_width = tx->width;
402 basepixels_height = tx->height;
403 basepixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
404 Image_Copy8bitRGBA(mtdata, basepixels, tx->width * tx->height, palette_complete);
413 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
414 if (basepixels[j] < 255)
416 if (j < basepixels_width * basepixels_height * 4)
418 maskpixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
419 maskpixels_width = basepixels_width;
420 maskpixels_height = basepixels_height;
421 for (j = 0;j < basepixels_width * basepixels_height * 4;j += 4)
423 maskpixels[j+0] = 255;
424 maskpixels[j+1] = 255;
425 maskpixels[j+2] = 255;
426 maskpixels[j+3] = basepixels[j+3];
432 bumppixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
433 bumppixels_width = basepixels_width;
434 bumppixels_height = basepixels_height;
435 memcpy(bumppixels, basepixels, bumppixels_width * bumppixels_height * 4);
438 if (!nmappixels && bumppixels)
440 nmappixels = Mem_Alloc(loadmodel->mempool, bumppixels_width * bumppixels_height * 4);
441 nmappixels_width = bumppixels_width;
442 nmappixels_height = bumppixels_height;
443 Image_HeightmapToNormalmap(bumppixels, nmappixels, nmappixels_width, nmappixels_height, false, 1);
448 detailtexture = detailtextures[i % NUM_DETAILTEXTURES];
452 tx->texture = R_LoadTexture2D (loadmodel->texturepool, tx->name, basepixels_width, basepixels_height, basepixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
454 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 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 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 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);
461 tx->detailtexture = detailtexture;
468 tx->texture = r_notexture;
469 tx->nmaptexture = NULL;
470 tx->glosstexture = NULL;
471 tx->glowtexture = NULL;
472 tx->fogtexture = NULL;
473 tx->detailtexture = NULL;
477 Mem_Free(basepixels);
479 Mem_Free(bumppixels);
481 Mem_Free(nmappixels);
483 Mem_Free(glosspixels);
485 Mem_Free(glowpixels);
487 Mem_Free(maskpixels);
489 if (tx->name[0] == '*')
491 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
492 // LordHavoc: some turbulent textures should be fullbright and solid
493 if (!strncmp(tx->name,"*lava",5)
494 || !strncmp(tx->name,"*teleport",9)
495 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
496 tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
498 tx->flags |= SURF_WATERALPHA;
499 tx->shader = &Cshader_water;
501 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
503 tx->flags |= SURF_DRAWSKY;
504 tx->shader = &Cshader_sky;
508 tx->flags |= SURF_LIGHTMAP;
510 tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT;
511 tx->shader = &Cshader_wall_lightmap;
514 // start out with no animation
515 tx->currentframe = tx;
518 // sequence the animations
519 for (i = 0;i < m->nummiptex;i++)
521 tx = loadmodel->textures + i;
522 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
524 if (tx->anim_total[0] || tx->anim_total[1])
525 continue; // already sequenced
527 // find the number of frames in the animation
528 memset (anims, 0, sizeof(anims));
529 memset (altanims, 0, sizeof(altanims));
531 for (j = i;j < m->nummiptex;j++)
533 tx2 = loadmodel->textures + j;
534 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
538 if (num >= '0' && num <= '9')
539 anims[num - '0'] = tx2;
540 else if (num >= 'a' && num <= 'j')
541 altanims[num - 'a'] = tx2;
543 Con_Printf ("Bad animating texture %s\n", tx->name);
547 for (j = 0;j < 10;j++)
554 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
557 for (j = 0;j < max;j++)
561 Con_Printf ("Missing frame %i of %s\n", j, tx->name);
565 for (j = 0;j < altmax;j++)
569 Con_Printf ("Missing altframe %i of %s\n", j, tx->name);
578 // if there is no alternate animation, duplicate the primary
579 // animation into the alternate
581 for (k = 0;k < 10;k++)
582 altanims[k] = anims[k];
585 // link together the primary animation
586 for (j = 0;j < max;j++)
589 tx2->animated = true;
590 tx2->anim_total[0] = max;
591 tx2->anim_total[1] = altmax;
592 for (k = 0;k < 10;k++)
594 tx2->anim_frames[0][k] = anims[k];
595 tx2->anim_frames[1][k] = altanims[k];
599 // if there really is an alternate anim...
600 if (anims[0] != altanims[0])
602 // link together the alternate animation
603 for (j = 0;j < altmax;j++)
606 tx2->animated = true;
607 // the primary/alternate are reversed here
608 tx2->anim_total[0] = altmax;
609 tx2->anim_total[1] = max;
610 for (k = 0;k < 10;k++)
612 tx2->anim_frames[0][k] = altanims[k];
613 tx2->anim_frames[1][k] = anims[k];
625 static void Mod_LoadLighting (lump_t *l)
628 qbyte *in, *out, *data, d;
629 char litfilename[1024];
630 loadmodel->lightdata = NULL;
631 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
633 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
634 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
636 else // LordHavoc: bsp version 29 (normal white lighting)
638 // LordHavoc: hope is not lost yet, check for a .lit file to load
639 strcpy(litfilename, loadmodel->name);
640 COM_StripExtension(litfilename, litfilename);
641 strcat(litfilename, ".lit");
642 data = (qbyte*) COM_LoadFile (litfilename, false);
645 if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
647 i = LittleLong(((int *)data)[1]);
650 Con_DPrintf("%s loaded", litfilename);
651 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
652 memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
658 Con_Printf("Unknown .lit file version (%d)\n", i);
665 Con_Printf("Empty .lit file, ignoring\n");
667 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
671 // LordHavoc: oh well, expand the white lighting data
674 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
675 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
676 out = loadmodel->lightdata;
677 memcpy (in, mod_base + l->fileofs, l->filelen);
678 for (i = 0;i < l->filelen;i++)
688 void Mod_LoadLightList(void)
691 char lightsfilename[1024], *s, *t, *lightsstring;
694 strcpy(lightsfilename, loadmodel->name);
695 COM_StripExtension(lightsfilename, lightsfilename);
696 strcat(lightsfilename, ".lights");
697 s = lightsstring = (char *) COM_LoadFile (lightsfilename, false);
703 while (*s && *s != '\n')
707 Mem_Free(lightsstring);
708 Host_Error("lights file must end with a newline\n");
713 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
716 while (*s && n < numlights)
719 while (*s && *s != '\n')
723 Mem_Free(lightsstring);
724 Host_Error("misparsed lights file!\n");
726 e = loadmodel->lights + n;
728 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);
732 Mem_Free(lightsstring);
733 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);
740 Mem_Free(lightsstring);
741 Host_Error("misparsed lights file!\n");
743 loadmodel->numlights = numlights;
744 Mem_Free(lightsstring);
749 static int castshadowcount = 0;
750 void Mod_ProcessLightList(void)
752 int j, k, l, *mark, lnum;
760 for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++)
762 e->cullradius2 = DotProduct(e->light, e->light) / (e->falloff * e->falloff * 8192.0f * 8192.0f * 2.0f * 2.0f);// + 4096.0f;
763 if (e->cullradius2 > 4096.0f * 4096.0f)
764 e->cullradius2 = 4096.0f * 4096.0f;
765 e->cullradius = e->lightradius = sqrt(e->cullradius2);
766 leaf = Mod_PointInLeaf(e->origin, loadmodel);
767 if (leaf->compressed_vis)
768 pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel);
771 for (j = 0;j < loadmodel->numsurfaces;j++)
772 loadmodel->surfacevisframes[j] = -1;
773 for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++)
775 if (pvs[j >> 3] & (1 << (j & 7)))
777 for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++)
779 surf = loadmodel->surfaces + *mark;
780 if (surf->number != *mark)
781 Con_Printf("%d != %d\n", surf->number, *mark);
782 dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
783 if (surf->flags & SURF_PLANEBACK)
785 if (dist > 0 && dist < e->cullradius)
787 temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
788 temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
789 temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
790 if (DotProduct(temp, temp) < lightradius2)
791 loadmodel->surfacevisframes[*mark] = -2;
796 // build list of light receiving surfaces
798 for (j = 0;j < loadmodel->numsurfaces;j++)
799 if (loadmodel->surfacevisframes[j] == -2)
802 if (e->numsurfaces > 0)
804 e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
806 for (j = 0;j < loadmodel->numsurfaces;j++)
807 if (loadmodel->surfacevisframes[j] == -2)
808 e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j;
810 // find bounding box and sphere of lit surfaces
811 // (these will be used for creating a shape to clip the light)
813 for (j = 0;j < e->numsurfaces;j++)
815 surf = e->surfaces[j];
818 VectorCopy(surf->poly_verts, e->mins);
819 VectorCopy(surf->poly_verts, e->maxs);
821 for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
823 if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
824 if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
825 if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
826 VectorSubtract(v, e->origin, temp);
827 dist = DotProduct(temp, temp);
832 if (e->cullradius2 > radius2)
834 e->cullradius2 = radius2;
835 e->cullradius = sqrt(e->cullradius2);
837 if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
838 if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
839 if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
840 if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
841 if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
842 if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
843 // clip shadow volumes against eachother to remove unnecessary
844 // polygons (and sections of polygons)
846 //vec3_t polymins, polymaxs;
848 float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
849 float f, *v0, *v1, projectdistance;
851 e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024);
854 vec3_t outermins, outermaxs, innermins, innermaxs;
855 innermins[0] = e->mins[0] - 1;
856 innermins[1] = e->mins[1] - 1;
857 innermins[2] = e->mins[2] - 1;
858 innermaxs[0] = e->maxs[0] + 1;
859 innermaxs[1] = e->maxs[1] + 1;
860 innermaxs[2] = e->maxs[2] + 1;
861 outermins[0] = loadmodel->normalmins[0] - 1;
862 outermins[1] = loadmodel->normalmins[1] - 1;
863 outermins[2] = loadmodel->normalmins[2] - 1;
864 outermaxs[0] = loadmodel->normalmaxs[0] + 1;
865 outermaxs[1] = loadmodel->normalmaxs[1] + 1;
866 outermaxs[2] = loadmodel->normalmaxs[2] + 1;
867 // add bounding box around the whole shadow volume set,
868 // facing inward to limit light area, with an outer bounding box
869 // facing outward (this is needed by the shadow rendering method)
871 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
872 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
873 verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
874 verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
875 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
876 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
877 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
878 verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
879 verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
880 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
882 verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
883 verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
884 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
885 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
886 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
887 verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
888 verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
889 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
890 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
891 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
893 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
894 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
895 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
896 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
897 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
898 verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
899 verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
900 verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
901 verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
902 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
904 verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
905 verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
906 verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
907 verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
908 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
909 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
910 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
911 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
912 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
913 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
915 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
916 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2];
917 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2];
918 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
919 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
920 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
921 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2];
922 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2];
923 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
924 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
926 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2];
927 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
928 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
929 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2];
930 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
931 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2];
932 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
933 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
934 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2];
935 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
939 for (j = 0;j < e->numsurfaces;j++)
941 surf = e->surfaces[j];
942 if (surf->flags & SURF_SHADOWCAST)
943 surf->castshadow = castshadowcount;
945 for (j = 0;j < e->numsurfaces;j++)
947 surf = e->surfaces[j];
948 if (surf->castshadow != castshadowcount)
950 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
951 if (surf->flags & SURF_PLANEBACK)
953 projectdistance = e->lightradius;
954 if (maxverts < surf->poly_numverts)
956 maxverts = surf->poly_numverts;
959 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
961 // copy the original polygon, for the front cap of the volume
962 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
964 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
965 // project the original polygon, reversed, for the back cap of the volume
966 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
968 VectorSubtract(v0, e->origin, temp);
969 VectorNormalize(temp);
970 VectorMA(v0, projectdistance, temp, v1);
972 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
973 // project the shadow volume sides
974 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 if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount)
978 VectorCopy(v1, &verts[0]);
979 VectorCopy(v0, &verts[3]);
980 VectorCopy(v0, &verts[6]);
981 VectorCopy(v1, &verts[9]);
982 VectorSubtract(&verts[6], e->origin, temp);
983 VectorNormalize(temp);
984 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
985 VectorSubtract(&verts[9], e->origin, temp);
986 VectorNormalize(temp);
987 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
988 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
992 // build the triangle mesh
993 e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume);
997 for (mesh = e->shadowvolume;mesh;mesh = mesh->next)
998 l += mesh->numtriangles;
999 Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l);
1012 static void Mod_LoadVisibility (lump_t *l)
1014 loadmodel->visdata = NULL;
1017 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
1018 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
1021 // used only for HalfLife maps
1022 void Mod_ParseWadsFromEntityLump(const char *data)
1024 char key[128], value[4096];
1029 if (!COM_ParseToken(&data))
1031 if (com_token[0] != '{')
1035 if (!COM_ParseToken(&data))
1037 if (com_token[0] == '}')
1038 break; // end of worldspawn
1039 if (com_token[0] == '_')
1040 strcpy(key, com_token + 1);
1042 strcpy(key, com_token);
1043 while (key[strlen(key)-1] == ' ') // remove trailing spaces
1044 key[strlen(key)-1] = 0;
1045 if (!COM_ParseToken(&data))
1047 strcpy(value, com_token);
1048 if (!strcmp("wad", key)) // for HalfLife maps
1050 if (loadmodel->ishlbsp)
1053 for (i = 0;i < 4096;i++)
1054 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
1060 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
1061 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
1063 else if (value[i] == ';' || value[i] == 0)
1067 strcpy(wadname, "textures/");
1068 strcat(wadname, &value[j]);
1069 W_LoadTextureWadFile (wadname, false);
1086 static void Mod_LoadEntities (lump_t *l)
1088 loadmodel->entities = NULL;
1091 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
1092 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
1093 if (loadmodel->ishlbsp)
1094 Mod_ParseWadsFromEntityLump(loadmodel->entities);
1103 static void Mod_LoadVertexes (lump_t *l)
1109 in = (void *)(mod_base + l->fileofs);
1110 if (l->filelen % sizeof(*in))
1111 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1112 count = l->filelen / sizeof(*in);
1113 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1115 loadmodel->vertexes = out;
1116 loadmodel->numvertexes = count;
1118 for ( i=0 ; i<count ; i++, in++, out++)
1120 out->position[0] = LittleFloat (in->point[0]);
1121 out->position[1] = LittleFloat (in->point[1]);
1122 out->position[2] = LittleFloat (in->point[2]);
1131 static void Mod_LoadSubmodels (lump_t *l)
1137 in = (void *)(mod_base + l->fileofs);
1138 if (l->filelen % sizeof(*in))
1139 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1140 count = l->filelen / sizeof(*in);
1141 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1143 loadmodel->submodels = out;
1144 loadmodel->numsubmodels = count;
1146 for ( i=0 ; i<count ; i++, in++, out++)
1148 for (j=0 ; j<3 ; j++)
1150 // spread the mins / maxs by a pixel
1151 out->mins[j] = LittleFloat (in->mins[j]) - 1;
1152 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
1153 out->origin[j] = LittleFloat (in->origin[j]);
1155 for (j=0 ; j<MAX_MAP_HULLS ; j++)
1156 out->headnode[j] = LittleLong (in->headnode[j]);
1157 out->visleafs = LittleLong (in->visleafs);
1158 out->firstface = LittleLong (in->firstface);
1159 out->numfaces = LittleLong (in->numfaces);
1168 static void Mod_LoadEdges (lump_t *l)
1174 in = (void *)(mod_base + l->fileofs);
1175 if (l->filelen % sizeof(*in))
1176 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1177 count = l->filelen / sizeof(*in);
1178 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1180 loadmodel->edges = out;
1181 loadmodel->numedges = count;
1183 for ( i=0 ; i<count ; i++, in++, out++)
1185 out->v[0] = (unsigned short)LittleShort(in->v[0]);
1186 out->v[1] = (unsigned short)LittleShort(in->v[1]);
1195 static void Mod_LoadTexinfo (lump_t *l)
1199 int i, j, k, count, miptex;
1201 in = (void *)(mod_base + l->fileofs);
1202 if (l->filelen % sizeof(*in))
1203 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1204 count = l->filelen / sizeof(*in);
1205 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1207 loadmodel->texinfo = out;
1208 loadmodel->numtexinfo = count;
1210 for (i = 0;i < count;i++, in++, out++)
1212 for (k = 0;k < 2;k++)
1213 for (j = 0;j < 4;j++)
1214 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
1216 miptex = LittleLong (in->miptex);
1217 out->flags = LittleLong (in->flags);
1219 out->texture = NULL;
1220 if (loadmodel->textures)
1222 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
1223 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
1225 out->texture = loadmodel->textures + miptex;
1227 if (out->flags & TEX_SPECIAL)
1229 // if texture chosen is NULL or the shader needs a lightmap,
1230 // force to notexture water shader
1231 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
1232 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
1236 // if texture chosen is NULL, force to notexture
1237 if (out->texture == NULL)
1238 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
1247 Fills in s->texturemins[] and s->extents[]
1250 static void CalcSurfaceExtents (msurface_t *s)
1252 float mins[2], maxs[2], val;
1256 int bmins[2], bmaxs[2];
1258 mins[0] = mins[1] = 999999999;
1259 maxs[0] = maxs[1] = -999999999;
1263 for (i=0 ; i<s->numedges ; i++)
1265 e = loadmodel->surfedges[s->firstedge+i];
1267 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
1269 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
1271 for (j=0 ; j<2 ; j++)
1273 val = v->position[0] * tex->vecs[j][0] +
1274 v->position[1] * tex->vecs[j][1] +
1275 v->position[2] * tex->vecs[j][2] +
1284 for (i=0 ; i<2 ; i++)
1286 bmins[i] = floor(mins[i]/16);
1287 bmaxs[i] = ceil(maxs[i]/16);
1289 s->texturemins[i] = bmins[i] * 16;
1290 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
1295 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1300 mins[0] = mins[1] = mins[2] = 9999;
1301 maxs[0] = maxs[1] = maxs[2] = -9999;
1303 for (i = 0;i < numverts;i++)
1305 for (j = 0;j < 3;j++, v++)
1316 #define MAX_SUBDIVPOLYTRIANGLES 4096
1317 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1319 static int subdivpolyverts, subdivpolytriangles;
1320 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1321 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1323 static int subdivpolylookupvert(vec3_t v)
1326 for (i = 0;i < subdivpolyverts;i++)
1327 if (subdivpolyvert[i][0] == v[0]
1328 && subdivpolyvert[i][1] == v[1]
1329 && subdivpolyvert[i][2] == v[2])
1331 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1332 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1333 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1334 return subdivpolyverts++;
1337 static void SubdividePolygon (int numverts, float *verts)
1339 int i, i1, i2, i3, f, b, c, p;
1340 vec3_t mins, maxs, front[256], back[256];
1341 float m, *pv, *cv, dist[256], frac;
1344 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1346 BoundPoly (numverts, verts, mins, maxs);
1348 for (i = 0;i < 3;i++)
1350 m = (mins[i] + maxs[i]) * 0.5;
1351 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1352 if (maxs[i] - m < 8)
1354 if (m - mins[i] < 8)
1358 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1359 dist[c] = cv[i] - m;
1362 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1366 VectorCopy (pv, front[f]);
1371 VectorCopy (pv, back[b]);
1374 if (dist[p] == 0 || dist[c] == 0)
1376 if ( (dist[p] > 0) != (dist[c] > 0) )
1379 frac = dist[p] / (dist[p] - dist[c]);
1380 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1381 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1382 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1388 SubdividePolygon (f, front[0]);
1389 SubdividePolygon (b, back[0]);
1393 i1 = subdivpolylookupvert(verts);
1394 i2 = subdivpolylookupvert(verts + 3);
1395 for (i = 2;i < numverts;i++)
1397 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1399 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1403 i3 = subdivpolylookupvert(verts + i * 3);
1404 subdivpolyindex[subdivpolytriangles][0] = i1;
1405 subdivpolyindex[subdivpolytriangles][1] = i2;
1406 subdivpolyindex[subdivpolytriangles][2] = i3;
1408 subdivpolytriangles++;
1414 Mod_GenerateWarpMesh
1416 Breaks a polygon up along axial 64 unit
1417 boundaries so that turbulent and sky warps
1418 can be done reasonably.
1421 void Mod_GenerateWarpMesh (msurface_t *surf)
1427 subdivpolytriangles = 0;
1428 subdivpolyverts = 0;
1429 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1430 if (subdivpolytriangles < 1)
1431 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1433 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1434 mesh->numverts = subdivpolyverts;
1435 mesh->numtriangles = subdivpolytriangles;
1436 mesh->vertex = (surfvertex_t *)(mesh + 1);
1437 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1438 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1440 for (i = 0;i < mesh->numtriangles;i++)
1441 for (j = 0;j < 3;j++)
1442 mesh->index[i*3+j] = subdivpolyindex[i][j];
1444 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1446 VectorCopy(subdivpolyvert[i], v->v);
1447 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1448 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1453 surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles)
1456 mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (4 + 4 + 4 + 4 + 4 + 4 + 4 + 1) * sizeof(float));
1457 mesh->numverts = numverts;
1458 mesh->numtriangles = numtriangles;
1459 mesh->verts = (float *)(mesh + 1);
1460 mesh->str = mesh->verts + mesh->numverts * 4;
1461 mesh->uvw = mesh->str + mesh->numverts * 4;
1462 mesh->abc = mesh->uvw + mesh->numverts * 4;
1463 mesh->svectors = (float *)(mesh->abc + mesh->numverts * 4);
1464 mesh->tvectors = mesh->svectors + mesh->numverts * 4;
1465 mesh->normals = mesh->tvectors + mesh->numverts * 4;
1466 mesh->lightmapoffsets = (int *)(mesh->normals + mesh->numverts * 4);
1467 mesh->index = mesh->lightmapoffsets + mesh->numverts;
1468 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
1472 void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
1474 int i, iu, iv, *index, smax, tmax;
1475 float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
1478 smax = surf->extents[0] >> 4;
1479 tmax = surf->extents[1] >> 4;
1483 surf->lightmaptexturestride = 0;
1484 surf->lightmaptexture = NULL;
1492 surf->flags |= SURF_LIGHTMAP;
1493 if (r_miplightmaps.integer)
1495 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1496 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);
1500 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1501 surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE, NULL);
1503 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1504 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1505 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1508 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1510 index = mesh->index;
1511 for (i = 0;i < mesh->numtriangles;i++)
1517 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
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)
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 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1527 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1528 // LordHavoc: calc lightmap data offset for vertex lighting to use
1531 iu = bound(0, iu, smax);
1532 iv = bound(0, iv, tmax);
1533 u = u * uscale + ubase;
1534 v = v * vscale + vbase;
1536 mesh->verts[i * 4 + 0] = in[0];
1537 mesh->verts[i * 4 + 1] = in[1];
1538 mesh->verts[i * 4 + 2] = in[2];
1539 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1540 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1541 mesh->uvw[i * 4 + 0] = u;
1542 mesh->uvw[i * 4 + 1] = v;
1543 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1544 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1545 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
1547 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1550 void Mod_GenerateVertexMesh (msurface_t *surf)
1553 float *in, s, t, normal[3];
1556 surf->lightmaptexturestride = 0;
1557 surf->lightmaptexture = NULL;
1559 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1561 index = mesh->index;
1562 for (i = 0;i < mesh->numtriangles;i++)
1568 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1570 VectorCopy(surf->plane->normal, normal);
1571 if (surf->flags & SURF_PLANEBACK)
1572 VectorNegate(normal, normal);
1573 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1575 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
1576 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
1577 mesh->verts[i * 4 + 0] = in[0];
1578 mesh->verts[i * 4 + 1] = in[1];
1579 mesh->verts[i * 4 + 2] = in[2];
1580 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1581 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1582 mesh->uvw[i * 4 + 0] = 0;
1583 mesh->uvw[i * 4 + 1] = 0;
1584 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1585 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1587 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1590 void Mod_GenerateSurfacePolygon (msurface_t *surf)
1593 float *vec, *vert, mins[3], maxs[3];
1595 // convert edges back to a normal polygon
1596 surf->poly_numverts = surf->numedges;
1597 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
1598 for (i = 0;i < surf->numedges;i++)
1600 lindex = loadmodel->surfedges[surf->firstedge + i];
1602 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1604 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1605 VectorCopy (vec, vert);
1608 vert = surf->poly_verts;
1609 VectorCopy(vert, mins);
1610 VectorCopy(vert, maxs);
1612 for (i = 1;i < surf->poly_numverts;i++, vert += 3)
1614 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1615 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1616 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1618 VectorCopy(mins, surf->poly_mins);
1619 VectorCopy(maxs, surf->poly_maxs);
1620 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1621 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1622 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1630 static void Mod_LoadFaces (lump_t *l)
1634 int i, count, surfnum, planenum, ssize, tsize;
1636 in = (void *)(mod_base + l->fileofs);
1637 if (l->filelen % sizeof(*in))
1638 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1639 count = l->filelen / sizeof(*in);
1640 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1642 loadmodel->surfaces = out;
1643 loadmodel->numsurfaces = count;
1644 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1645 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1646 loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1648 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1650 out->number = surfnum;
1651 // FIXME: validate edges, texinfo, etc?
1652 out->firstedge = LittleLong(in->firstedge);
1653 out->numedges = LittleShort(in->numedges);
1654 if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges)
1655 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges);
1657 i = LittleShort (in->texinfo);
1658 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1659 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1660 out->texinfo = loadmodel->texinfo + i;
1661 out->flags = out->texinfo->texture->flags;
1663 planenum = LittleShort(in->planenum);
1664 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1665 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1667 if (LittleShort(in->side))
1668 out->flags |= SURF_PLANEBACK;
1670 out->plane = loadmodel->planes + planenum;
1672 // clear lightmap (filled in later)
1673 out->lightmaptexture = NULL;
1675 // force lightmap upload on first time seeing the surface
1676 out->cached_dlight = true;
1678 CalcSurfaceExtents (out);
1680 ssize = (out->extents[0] >> 4) + 1;
1681 tsize = (out->extents[1] >> 4) + 1;
1684 for (i = 0;i < MAXLIGHTMAPS;i++)
1685 out->styles[i] = in->styles[i];
1686 i = LittleLong(in->lightofs);
1688 out->samples = NULL;
1689 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1690 out->samples = loadmodel->lightdata + i;
1691 else // LordHavoc: white lighting (bsp version 29)
1692 out->samples = loadmodel->lightdata + (i * 3);
1694 Mod_GenerateSurfacePolygon(out);
1695 if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
1697 if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
1698 Host_Error ("Bad surface extents");
1699 Mod_GenerateWallMesh (out, false);
1700 // stainmap for permanent marks on walls
1701 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1703 memset(out->stainsamples, 255, ssize * tsize * 3);
1706 Mod_GenerateVertexMesh (out);
1715 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1717 node->parent = parent;
1718 if (node->contents < 0)
1720 Mod_SetParent (node->children[0], node);
1721 Mod_SetParent (node->children[1], node);
1729 static void Mod_LoadNodes (lump_t *l)
1735 in = (void *)(mod_base + l->fileofs);
1736 if (l->filelen % sizeof(*in))
1737 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1738 count = l->filelen / sizeof(*in);
1739 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1741 loadmodel->nodes = out;
1742 loadmodel->numnodes = count;
1744 for ( i=0 ; i<count ; i++, in++, out++)
1746 for (j=0 ; j<3 ; j++)
1748 out->mins[j] = LittleShort (in->mins[j]);
1749 out->maxs[j] = LittleShort (in->maxs[j]);
1752 p = LittleLong(in->planenum);
1753 out->plane = loadmodel->planes + p;
1755 out->firstsurface = LittleShort (in->firstface);
1756 out->numsurfaces = LittleShort (in->numfaces);
1758 for (j=0 ; j<2 ; j++)
1760 p = LittleShort (in->children[j]);
1762 out->children[j] = loadmodel->nodes + p;
1764 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1768 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1776 static void Mod_LoadLeafs (lump_t *l)
1782 in = (void *)(mod_base + l->fileofs);
1783 if (l->filelen % sizeof(*in))
1784 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1785 count = l->filelen / sizeof(*in);
1786 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1788 loadmodel->leafs = out;
1789 loadmodel->numleafs = count;
1791 for ( i=0 ; i<count ; i++, in++, out++)
1793 for (j=0 ; j<3 ; j++)
1795 out->mins[j] = LittleShort (in->mins[j]);
1796 out->maxs[j] = LittleShort (in->maxs[j]);
1799 p = LittleLong(in->contents);
1802 out->firstmarksurface = loadmodel->marksurfaces +
1803 LittleShort(in->firstmarksurface);
1804 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1806 p = LittleLong(in->visofs);
1808 out->compressed_vis = NULL;
1810 out->compressed_vis = loadmodel->visdata + p;
1812 for (j=0 ; j<4 ; j++)
1813 out->ambient_sound_level[j] = in->ambient_level[j];
1815 // FIXME: Insert caustics here
1824 static void Mod_LoadClipnodes (lump_t *l)
1826 dclipnode_t *in, *out;
1830 in = (void *)(mod_base + l->fileofs);
1831 if (l->filelen % sizeof(*in))
1832 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1833 count = l->filelen / sizeof(*in);
1834 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1836 loadmodel->clipnodes = out;
1837 loadmodel->numclipnodes = count;
1839 if (loadmodel->ishlbsp)
1841 hull = &loadmodel->hulls[1];
1842 hull->clipnodes = out;
1843 hull->firstclipnode = 0;
1844 hull->lastclipnode = count-1;
1845 hull->planes = loadmodel->planes;
1846 hull->clip_mins[0] = -16;
1847 hull->clip_mins[1] = -16;
1848 hull->clip_mins[2] = -36;
1849 hull->clip_maxs[0] = 16;
1850 hull->clip_maxs[1] = 16;
1851 hull->clip_maxs[2] = 36;
1852 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1854 hull = &loadmodel->hulls[2];
1855 hull->clipnodes = out;
1856 hull->firstclipnode = 0;
1857 hull->lastclipnode = count-1;
1858 hull->planes = loadmodel->planes;
1859 hull->clip_mins[0] = -32;
1860 hull->clip_mins[1] = -32;
1861 hull->clip_mins[2] = -32;
1862 hull->clip_maxs[0] = 32;
1863 hull->clip_maxs[1] = 32;
1864 hull->clip_maxs[2] = 32;
1865 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1867 hull = &loadmodel->hulls[3];
1868 hull->clipnodes = out;
1869 hull->firstclipnode = 0;
1870 hull->lastclipnode = count-1;
1871 hull->planes = loadmodel->planes;
1872 hull->clip_mins[0] = -16;
1873 hull->clip_mins[1] = -16;
1874 hull->clip_mins[2] = -18;
1875 hull->clip_maxs[0] = 16;
1876 hull->clip_maxs[1] = 16;
1877 hull->clip_maxs[2] = 18;
1878 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1882 hull = &loadmodel->hulls[1];
1883 hull->clipnodes = out;
1884 hull->firstclipnode = 0;
1885 hull->lastclipnode = count-1;
1886 hull->planes = loadmodel->planes;
1887 hull->clip_mins[0] = -16;
1888 hull->clip_mins[1] = -16;
1889 hull->clip_mins[2] = -24;
1890 hull->clip_maxs[0] = 16;
1891 hull->clip_maxs[1] = 16;
1892 hull->clip_maxs[2] = 32;
1893 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1895 hull = &loadmodel->hulls[2];
1896 hull->clipnodes = out;
1897 hull->firstclipnode = 0;
1898 hull->lastclipnode = count-1;
1899 hull->planes = loadmodel->planes;
1900 hull->clip_mins[0] = -32;
1901 hull->clip_mins[1] = -32;
1902 hull->clip_mins[2] = -24;
1903 hull->clip_maxs[0] = 32;
1904 hull->clip_maxs[1] = 32;
1905 hull->clip_maxs[2] = 64;
1906 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1909 for (i=0 ; i<count ; i++, out++, in++)
1911 out->planenum = LittleLong(in->planenum);
1912 out->children[0] = LittleShort(in->children[0]);
1913 out->children[1] = LittleShort(in->children[1]);
1914 if (out->children[0] >= count || out->children[1] >= count)
1915 Host_Error("Corrupt clipping hull (out of range child)\n");
1923 Duplicate the drawing hull structure as a clipping hull
1926 static void Mod_MakeHull0 (void)
1933 hull = &loadmodel->hulls[0];
1935 in = loadmodel->nodes;
1936 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1938 hull->clipnodes = out;
1939 hull->firstclipnode = 0;
1940 hull->lastclipnode = loadmodel->numnodes - 1;
1941 hull->planes = loadmodel->planes;
1943 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1945 out->planenum = in->plane - loadmodel->planes;
1946 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1947 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1953 Mod_LoadMarksurfaces
1956 static void Mod_LoadMarksurfaces (lump_t *l)
1961 in = (void *)(mod_base + l->fileofs);
1962 if (l->filelen % sizeof(*in))
1963 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1964 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1965 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1967 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1969 j = (unsigned) LittleShort(in[i]);
1970 if (j >= loadmodel->numsurfaces)
1971 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1972 loadmodel->marksurfaces[i] = j;
1981 static void Mod_LoadSurfedges (lump_t *l)
1986 in = (void *)(mod_base + l->fileofs);
1987 if (l->filelen % sizeof(*in))
1988 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1989 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1990 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1992 for (i = 0;i < loadmodel->numsurfedges;i++)
1993 loadmodel->surfedges[i] = LittleLong (in[i]);
2002 static void Mod_LoadPlanes (lump_t *l)
2008 in = (void *)(mod_base + l->fileofs);
2009 if (l->filelen % sizeof(*in))
2010 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
2012 loadmodel->numplanes = l->filelen / sizeof(*in);
2013 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
2015 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
2017 out->normal[0] = LittleFloat (in->normal[0]);
2018 out->normal[1] = LittleFloat (in->normal[1]);
2019 out->normal[2] = LittleFloat (in->normal[2]);
2020 out->dist = LittleFloat (in->dist);
2026 #define MAX_POINTS_ON_WINDING 64
2032 double points[8][3]; // variable sized
2041 static winding_t *NewWinding (int points)
2046 if (points > MAX_POINTS_ON_WINDING)
2047 Sys_Error("NewWinding: too many points\n");
2049 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
2050 w = Mem_Alloc(loadmodel->mempool, size);
2051 memset (w, 0, size);
2056 static void FreeWinding (winding_t *w)
2066 static winding_t *BaseWindingForPlane (mplane_t *p)
2068 double org[3], vright[3], vup[3], normal[3];
2071 VectorCopy(p->normal, normal);
2072 VectorVectorsDouble(normal, vright, vup);
2074 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
2075 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
2077 // project a really big axis aligned box onto the plane
2080 VectorScale (p->normal, p->dist, org);
2082 VectorSubtract (org, vright, w->points[0]);
2083 VectorAdd (w->points[0], vup, w->points[0]);
2085 VectorAdd (org, vright, w->points[1]);
2086 VectorAdd (w->points[1], vup, w->points[1]);
2088 VectorAdd (org, vright, w->points[2]);
2089 VectorSubtract (w->points[2], vup, w->points[2]);
2091 VectorSubtract (org, vright, w->points[3]);
2092 VectorSubtract (w->points[3], vup, w->points[3]);
2103 Clips the winding to the plane, returning the new winding on the positive side
2104 Frees the input winding.
2105 If keepon is true, an exactly on-plane winding will be saved, otherwise
2106 it will be clipped away.
2109 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2111 double dists[MAX_POINTS_ON_WINDING + 1];
2112 int sides[MAX_POINTS_ON_WINDING + 1];
2121 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2123 // determine sides for each point
2124 for (i = 0;i < in->numpoints;i++)
2126 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2127 if (dot > ON_EPSILON)
2128 sides[i] = SIDE_FRONT;
2129 else if (dot < -ON_EPSILON)
2130 sides[i] = SIDE_BACK;
2135 sides[i] = sides[0];
2136 dists[i] = dists[0];
2138 if (keepon && !counts[0] && !counts[1])
2149 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2150 if (maxpts > MAX_POINTS_ON_WINDING)
2151 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2153 neww = NewWinding (maxpts);
2155 for (i = 0;i < in->numpoints;i++)
2157 if (neww->numpoints >= maxpts)
2158 Sys_Error ("ClipWinding: points exceeded estimate");
2162 if (sides[i] == SIDE_ON)
2164 VectorCopy (p1, neww->points[neww->numpoints]);
2169 if (sides[i] == SIDE_FRONT)
2171 VectorCopy (p1, neww->points[neww->numpoints]);
2175 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2178 // generate a split point
2179 p2 = in->points[(i+1)%in->numpoints];
2181 dot = dists[i] / (dists[i]-dists[i+1]);
2182 for (j = 0;j < 3;j++)
2183 { // avoid round off error when possible
2184 if (split->normal[j] == 1)
2185 mid[j] = split->dist;
2186 else if (split->normal[j] == -1)
2187 mid[j] = -split->dist;
2189 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2192 VectorCopy (mid, neww->points[neww->numpoints]);
2196 // free the original winding
2207 Divides a winding by a plane, producing one or two windings. The
2208 original winding is not damaged or freed. If only on one side, the
2209 returned winding will be the input winding. If on both sides, two
2210 new windings will be created.
2213 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2215 double dists[MAX_POINTS_ON_WINDING + 1];
2216 int sides[MAX_POINTS_ON_WINDING + 1];
2225 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2227 // determine sides for each point
2228 for (i = 0;i < in->numpoints;i++)
2230 dot = DotProduct (in->points[i], split->normal);
2233 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2234 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2235 else sides[i] = SIDE_ON;
2238 sides[i] = sides[0];
2239 dists[i] = dists[0];
2241 *front = *back = NULL;
2254 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2256 if (maxpts > MAX_POINTS_ON_WINDING)
2257 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2259 *front = f = NewWinding (maxpts);
2260 *back = b = NewWinding (maxpts);
2262 for (i = 0;i < in->numpoints;i++)
2264 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2265 Sys_Error ("DivideWinding: points exceeded estimate");
2269 if (sides[i] == SIDE_ON)
2271 VectorCopy (p1, f->points[f->numpoints]);
2273 VectorCopy (p1, b->points[b->numpoints]);
2278 if (sides[i] == SIDE_FRONT)
2280 VectorCopy (p1, f->points[f->numpoints]);
2283 else if (sides[i] == SIDE_BACK)
2285 VectorCopy (p1, b->points[b->numpoints]);
2289 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2292 // generate a split point
2293 p2 = in->points[(i+1)%in->numpoints];
2295 dot = dists[i] / (dists[i]-dists[i+1]);
2296 for (j = 0;j < 3;j++)
2297 { // avoid round off error when possible
2298 if (split->normal[j] == 1)
2299 mid[j] = split->dist;
2300 else if (split->normal[j] == -1)
2301 mid[j] = -split->dist;
2303 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2306 VectorCopy (mid, f->points[f->numpoints]);
2308 VectorCopy (mid, b->points[b->numpoints]);
2313 typedef struct portal_s
2316 mnode_t *nodes[2]; // [0] = front side of plane
2317 struct portal_s *next[2];
2319 struct portal_s *chain; // all portals are linked into a list
2323 static portal_t *portalchain;
2330 static portal_t *AllocPortal (void)
2333 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2334 p->chain = portalchain;
2339 static void FreePortal(portal_t *p)
2344 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2346 // calculate children first
2347 if (node->children[0]->contents >= 0)
2348 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2349 if (node->children[1]->contents >= 0)
2350 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2352 // make combined bounding box from children
2353 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2354 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2355 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2356 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2357 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2358 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2361 static void Mod_FinalizePortals(void)
2363 int i, j, numportals, numpoints;
2364 portal_t *p, *pnext;
2367 mleaf_t *leaf, *endleaf;
2370 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2371 leaf = loadmodel->leafs;
2372 endleaf = leaf + loadmodel->numleafs;
2373 for (;leaf < endleaf;leaf++)
2375 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2376 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2383 for (i = 0;i < 2;i++)
2385 leaf = (mleaf_t *)p->nodes[i];
2387 for (j = 0;j < w->numpoints;j++)
2389 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2390 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2391 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2392 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2393 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2394 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2401 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2403 // tally up portal and point counts
2409 // note: this check must match the one below or it will usually corrupt memory
2410 // 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
2411 if (p->winding && p->nodes[0] != p->nodes[1]
2412 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2413 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2416 numpoints += p->winding->numpoints * 2;
2420 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2421 loadmodel->numportals = numportals;
2422 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2423 loadmodel->numportalpoints = numpoints;
2424 // clear all leaf portal chains
2425 for (i = 0;i < loadmodel->numleafs;i++)
2426 loadmodel->leafs[i].portals = NULL;
2427 // process all portals in the global portal chain, while freeing them
2428 portal = loadmodel->portals;
2429 point = loadmodel->portalpoints;
2438 // note: this check must match the one above or it will usually corrupt memory
2439 // 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
2440 if (p->nodes[0] != p->nodes[1]
2441 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2442 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2444 // first make the back to front portal (forward portal)
2445 portal->points = point;
2446 portal->numpoints = p->winding->numpoints;
2447 portal->plane.dist = p->plane.dist;
2448 VectorCopy(p->plane.normal, portal->plane.normal);
2449 portal->here = (mleaf_t *)p->nodes[1];
2450 portal->past = (mleaf_t *)p->nodes[0];
2452 for (j = 0;j < portal->numpoints;j++)
2454 VectorCopy(p->winding->points[j], point->position);
2457 PlaneClassify(&portal->plane);
2459 // link into leaf's portal chain
2460 portal->next = portal->here->portals;
2461 portal->here->portals = portal;
2463 // advance to next portal
2466 // then make the front to back portal (backward portal)
2467 portal->points = point;
2468 portal->numpoints = p->winding->numpoints;
2469 portal->plane.dist = -p->plane.dist;
2470 VectorNegate(p->plane.normal, portal->plane.normal);
2471 portal->here = (mleaf_t *)p->nodes[0];
2472 portal->past = (mleaf_t *)p->nodes[1];
2474 for (j = portal->numpoints - 1;j >= 0;j--)
2476 VectorCopy(p->winding->points[j], point->position);
2479 PlaneClassify(&portal->plane);
2481 // link into leaf's portal chain
2482 portal->next = portal->here->portals;
2483 portal->here->portals = portal;
2485 // advance to next portal
2488 FreeWinding(p->winding);
2500 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2503 Host_Error ("AddPortalToNodes: NULL front node");
2505 Host_Error ("AddPortalToNodes: NULL back node");
2506 if (p->nodes[0] || p->nodes[1])
2507 Host_Error ("AddPortalToNodes: already included");
2508 // note: front == back is handled gracefully, because leaf 0 is the shared solid leaf, it can often have portals with the same leaf on both sides
2510 p->nodes[0] = front;
2511 p->next[0] = (portal_t *)front->portals;
2512 front->portals = (mportal_t *)p;
2515 p->next[1] = (portal_t *)back->portals;
2516 back->portals = (mportal_t *)p;
2521 RemovePortalFromNode
2524 static void RemovePortalFromNodes(portal_t *portal)
2528 void **portalpointer;
2530 for (i = 0;i < 2;i++)
2532 node = portal->nodes[i];
2534 portalpointer = (void **) &node->portals;
2539 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2543 if (portal->nodes[0] == node)
2545 *portalpointer = portal->next[0];
2546 portal->nodes[0] = NULL;
2548 else if (portal->nodes[1] == node)
2550 *portalpointer = portal->next[1];
2551 portal->nodes[1] = NULL;
2554 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2558 if (t->nodes[0] == node)
2559 portalpointer = (void **) &t->next[0];
2560 else if (t->nodes[1] == node)
2561 portalpointer = (void **) &t->next[1];
2563 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2568 static void Mod_RecursiveNodePortals (mnode_t *node)
2571 mnode_t *front, *back, *other_node;
2572 mplane_t clipplane, *plane;
2573 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2574 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2576 // if a leaf, we're done
2580 plane = node->plane;
2582 front = node->children[0];
2583 back = node->children[1];
2585 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2587 // create the new portal by generating a polygon for the node plane,
2588 // and clipping it by all of the other portals (which came from nodes above this one)
2589 nodeportal = AllocPortal ();
2590 nodeportal->plane = *node->plane;
2592 nodeportalwinding = BaseWindingForPlane (node->plane);
2593 side = 0; // shut up compiler warning
2594 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2596 clipplane = portal->plane;
2597 if (portal->nodes[0] == portal->nodes[1])
2598 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2599 if (portal->nodes[0] == node)
2601 else if (portal->nodes[1] == node)
2603 clipplane.dist = -clipplane.dist;
2604 VectorNegate (clipplane.normal, clipplane.normal);
2608 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2610 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2611 if (!nodeportalwinding)
2613 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2618 if (nodeportalwinding)
2620 // if the plane was not clipped on all sides, there was an error
2621 nodeportal->winding = nodeportalwinding;
2622 AddPortalToNodes (nodeportal, front, back);
2625 // split the portals of this node along this node's plane and assign them to the children of this node
2626 // (migrating the portals downward through the tree)
2627 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2629 if (portal->nodes[0] == portal->nodes[1])
2630 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2631 if (portal->nodes[0] == node)
2633 else if (portal->nodes[1] == node)
2636 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2637 nextportal = portal->next[side];
2639 other_node = portal->nodes[!side];
2640 RemovePortalFromNodes (portal);
2642 // cut the portal into two portals, one on each side of the node plane
2643 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2648 AddPortalToNodes (portal, back, other_node);
2650 AddPortalToNodes (portal, other_node, back);
2656 AddPortalToNodes (portal, front, other_node);
2658 AddPortalToNodes (portal, other_node, front);
2662 // the winding is split
2663 splitportal = AllocPortal ();
2664 temp = splitportal->chain;
2665 *splitportal = *portal;
2666 splitportal->chain = temp;
2667 splitportal->winding = backwinding;
2668 FreeWinding (portal->winding);
2669 portal->winding = frontwinding;
2673 AddPortalToNodes (portal, front, other_node);
2674 AddPortalToNodes (splitportal, back, other_node);
2678 AddPortalToNodes (portal, other_node, front);
2679 AddPortalToNodes (splitportal, other_node, back);
2683 Mod_RecursiveNodePortals(front);
2684 Mod_RecursiveNodePortals(back);
2688 static void Mod_MakePortals(void)
2691 Mod_RecursiveNodePortals (loadmodel->nodes);
2692 Mod_FinalizePortals();
2695 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2698 int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2699 msurface_t *surf, *s;
2700 float *v0, *v1, *v2, *v3;
2701 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2702 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2703 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2705 for (vertnum = surf->poly_numverts - 1, vertnum2 = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;vertnum2 < surf->poly_numverts;vertnum = vertnum2, vertnum2++, v0 = v1, v1 += 3)
2707 if (surf->neighborsurfaces[vertnum])
2709 surf->neighborsurfaces[vertnum] = NULL;
2710 for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2712 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2713 || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2714 || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2717 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2718 if (s->neighborsurfaces[vnum] == surf)
2720 if (vnum < s->poly_numverts)
2722 for (vnum = s->poly_numverts - 1, vnum2 = 0, v2 = s->poly_verts + (s->poly_numverts - 1) * 3, v3 = s->poly_verts;vnum2 < s->poly_numverts;vnum = vnum2, vnum2++, v2 = v3, v3 += 3)
2724 if (s->neighborsurfaces[vnum] == NULL
2725 && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2726 || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2728 surf->neighborsurfaces[vertnum] = s;
2729 s->neighborsurfaces[vnum] = surf;
2733 if (vnum < s->poly_numverts)
2746 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2747 extern void R_Model_Brush_Draw(entity_render_t *ent);
2748 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2749 extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
2750 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2755 mempool_t *mainmempool;
2757 model_t *originalloadmodel;
2759 mod->type = mod_brush;
2761 header = (dheader_t *)buffer;
2763 i = LittleLong (header->version);
2764 if (i != BSPVERSION && i != 30)
2765 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2766 mod->ishlbsp = i == 30;
2767 if (loadmodel->isworldmodel)
2769 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2770 // until we get a texture for it...
2774 // swap all the lumps
2775 mod_base = (qbyte *)header;
2777 for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
2778 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2782 // store which lightmap format to use
2783 mod->lightmaprgba = r_lightmaprgba.integer;
2785 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2786 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2787 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2788 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2789 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2790 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2791 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2792 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2793 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2794 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2795 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2796 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2797 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2798 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2799 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2804 mod->numframes = 2; // regular and alternate animation
2806 mainmempool = mod->mempool;
2807 loadname = mod->name;
2809 Mod_LoadLightList ();
2810 originalloadmodel = loadmodel;
2813 // set up the submodels (FIXME: this is confusing)
2815 for (i = 0;i < mod->numsubmodels;i++)
2818 float dist, modelyawradius, modelradius, *vec;
2821 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2822 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2826 bm = &mod->submodels[i];
2828 mod->hulls[0].firstclipnode = bm->headnode[0];
2829 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2831 mod->hulls[j].firstclipnode = bm->headnode[j];
2832 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2835 mod->firstmodelsurface = bm->firstface;
2836 mod->nummodelsurfaces = bm->numfaces;
2838 // this gets altered below if sky is used
2839 mod->DrawSky = NULL;
2840 mod->Draw = R_Model_Brush_Draw;
2841 mod->DrawFakeShadow = NULL;
2842 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2843 mod->DrawLight = R_Model_Brush_DrawLight;
2844 mod->texturesurfacechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t *));
2845 if (mod->nummodelsurfaces)
2847 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2848 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2850 // we only need to have a drawsky function if it is used (usually only on world model)
2851 if (surf->texinfo->texture->shader == &Cshader_sky)
2852 mod->DrawSky = R_Model_Brush_DrawSky;
2853 // link into texture chain
2854 surf->texturechain = mod->texturesurfacechains[surf->texinfo->texture - mod->textures];
2855 mod->texturesurfacechains[surf->texinfo->texture - mod->textures] = surf;
2856 // calculate bounding shapes
2857 for (k = 0;k < surf->numedges;k++)
2859 l = mod->surfedges[k + surf->firstedge];
2861 vec = mod->vertexes[mod->edges[l].v[0]].position;
2863 vec = mod->vertexes[mod->edges[-l].v[1]].position;
2864 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2865 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2866 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2867 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2868 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2869 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2870 dist = vec[0]*vec[0]+vec[1]*vec[1];
2871 if (modelyawradius < dist)
2872 modelyawradius = dist;
2873 dist += vec[2]*vec[2];
2874 if (modelradius < dist)
2878 modelyawradius = sqrt(modelyawradius);
2879 modelradius = sqrt(modelradius);
2880 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2881 mod->yawmins[2] = mod->normalmins[2];
2882 mod->yawmaxs[2] = mod->normalmaxs[2];
2883 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2884 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2885 mod->radius = modelradius;
2886 mod->radius2 = modelradius * modelradius;
2887 // LordHavoc: build triangle meshs for entire model's geometry
2888 // (only used for shadow volumes)
2889 mod->shadowmesh = Mod_ShadowMesh_Begin(originalloadmodel->mempool, 1024);
2890 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2891 if (surf->flags & SURF_SHADOWCAST)
2892 Mod_ShadowMesh_AddPolygon(originalloadmodel->mempool, mod->shadowmesh, surf->poly_numverts, surf->poly_verts);
2893 mod->shadowmesh = Mod_ShadowMesh_Finish(originalloadmodel->mempool, mod->shadowmesh);
2894 Mod_ShadowMesh_CalcBBox(mod->shadowmesh, mod->shadowmesh_mins, mod->shadowmesh_maxs, mod->shadowmesh_center, &mod->shadowmesh_radius);
2898 // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2899 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2900 VectorClear(mod->normalmins);
2901 VectorClear(mod->normalmaxs);
2902 VectorClear(mod->yawmins);
2903 VectorClear(mod->yawmaxs);
2904 VectorClear(mod->rotatedmins);
2905 VectorClear(mod->rotatedmaxs);
2908 mod->shadowmesh = NULL;
2910 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2912 mod->numleafs = bm->visleafs;
2914 // LordHavoc: only register submodels if it is the world
2915 // (prevents bsp models from replacing world submodels)
2916 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2919 // duplicate the basic information
2920 sprintf (name, "*%i", i+1);
2921 loadmodel = Mod_FindName (name);
2923 strcpy (loadmodel->name, name);
2924 // textures and memory belong to the main model
2925 loadmodel->texturepool = NULL;
2926 loadmodel->mempool = NULL;
2931 loadmodel = originalloadmodel;
2932 //Mod_ProcessLightList ();