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;
250 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
252 // LordHavoc: mostly rewritten map texture loader
253 for (i = 0;i < m->nummiptex;i++)
255 dofs[i] = LittleLong(dofs[i]);
256 if (dofs[i] == -1 || r_nosurftextures.integer)
258 dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
260 // make sure name is no more than 15 characters
261 for (j = 0;dmiptex->name[j] && j < 15;j++)
262 name[j] = dmiptex->name[j];
265 mtwidth = LittleLong (dmiptex->width);
266 mtheight = LittleLong (dmiptex->height);
268 j = LittleLong (dmiptex->offsets[0]);
272 if (j < 40 || j + mtwidth * mtheight > l->filelen)
274 Con_Printf ("Texture \"%s\" in \"%s\"is corrupt or incomplete\n", dmiptex->name, loadmodel->name);
277 mtdata = (qbyte *)dmiptex + j;
280 if ((mtwidth & 15) || (mtheight & 15))
281 Con_Printf ("warning: texture \"%s\" in \"%s\" is not 16 aligned", dmiptex->name, loadmodel->name);
283 // LordHavoc: force all names to lowercase
284 for (j = 0;name[j];j++)
285 if (name[j] >= 'A' && name[j] <= 'Z')
286 name[j] += 'a' - 'A';
288 tx = loadmodel->textures + i;
289 strcpy(tx->name, name);
291 tx->height = mtheight;
295 sprintf(tx->name, "unnamed%i", i);
296 Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
299 basepixels = NULL;basepixels_width = 0;basepixels_height = 0;
300 bumppixels = NULL;bumppixels_width = 0;bumppixels_height = 0;
301 nmappixels = NULL;nmappixels_width = 0;nmappixels_height = 0;
302 glosspixels = NULL;glosspixels_width = 0;glosspixels_height = 0;
303 glowpixels = NULL;glowpixels_width = 0;glowpixels_height = 0;
304 maskpixels = NULL;maskpixels_width = 0;maskpixels_height = 0;
305 detailtexture = NULL;
307 // LordHavoc: HL sky textures are entirely different than quake
308 if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
310 if (loadmodel->isworldmodel)
312 data = loadimagepixels(tx->name, false, 0, 0);
315 if (image_width == 256 && image_height == 128)
323 Con_Printf ("Invalid replacement texture for sky \"%s\" in %\"%s\", must be 256x128 pixels\n", tx->name, loadmodel->name);
325 R_InitSky (mtdata, 1);
328 else if (mtdata != NULL)
329 R_InitSky (mtdata, 1);
334 if ((basepixels = loadimagepixels(tx->name, false, 0, 0)) != NULL)
336 basepixels_width = image_width;
337 basepixels_height = image_height;
339 // _luma is supported for tenebrae compatibility
340 // (I think it's a very stupid name, but oh well)
341 if ((glowpixels = loadimagepixels(va("%s_glow", tx->name), false, 0, 0)) != NULL
342 || (glowpixels = loadimagepixels(va("%s_luma", tx->name), false, 0, 0)) != NULL)
344 glowpixels_width = image_width;
345 glowpixels_height = image_height;
347 if ((bumppixels = loadimagepixels(va("%s_bump", tx->name), false, 0, 0)) != NULL)
349 bumppixels_width = image_width;
350 bumppixels_height = image_height;
352 if ((glosspixels = loadimagepixels(va("%s_gloss", tx->name), false, 0, 0)) != NULL)
354 glosspixels_width = image_width;
355 glosspixels_height = image_height;
359 if (loadmodel->ishlbsp)
361 // internal texture overrides wad
362 if (mtdata && (basepixels = W_ConvertWAD3Texture(dmiptex)) != NULL)
364 basepixels_width = image_width;
365 basepixels_height = image_height;
367 else if ((basepixels = W_GetTexture(tx->name)) != NULL)
369 // get the size from the wad texture
370 tx->width = basepixels_width = image_width;
371 tx->height = basepixels_height = image_height;
376 if (mtdata) // texture included
378 if (r_fullbrights.integer && tx->name[0] != '*')
380 basepixels_width = tx->width;
381 basepixels_height = tx->height;
382 basepixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
383 Image_Copy8bitRGBA(mtdata, basepixels, basepixels_width * basepixels_height, palette_nofullbrights);
386 for (j = 0;j < (int)(tx->width*tx->height);j++)
387 if (((qbyte *)&palette_onlyfullbrights[mtdata[j]])[3] > 0) // fullbright
389 if (j < (int)(tx->width * tx->height))
391 glowpixels_width = tx->width;
392 glowpixels_height = tx->height;
393 glowpixels = Mem_Alloc(loadmodel->mempool, glowpixels_width * glowpixels_height * 4);
394 Image_Copy8bitRGBA(mtdata, glowpixels, glowpixels_width * glowpixels_height, palette_onlyfullbrights);
400 basepixels_width = tx->width;
401 basepixels_height = tx->height;
402 basepixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
403 Image_Copy8bitRGBA(mtdata, basepixels, tx->width * tx->height, palette_complete);
412 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
413 if (basepixels[j] < 255)
415 if (j < basepixels_width * basepixels_height * 4)
417 maskpixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
418 maskpixels_width = basepixels_width;
419 maskpixels_height = basepixels_height;
420 for (j = 0;j < basepixels_width * basepixels_height * 4;j += 4)
422 maskpixels[j+0] = 255;
423 maskpixels[j+1] = 255;
424 maskpixels[j+2] = 255;
425 maskpixels[j+3] = basepixels[j+3];
431 bumppixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
432 bumppixels_width = basepixels_width;
433 bumppixels_height = basepixels_height;
434 memcpy(bumppixels, basepixels, bumppixels_width * bumppixels_height * 4);
437 if (!nmappixels && bumppixels)
439 nmappixels = Mem_Alloc(loadmodel->mempool, bumppixels_width * bumppixels_height * 4);
440 nmappixels_width = bumppixels_width;
441 nmappixels_height = bumppixels_height;
442 Image_HeightmapToNormalmap(bumppixels, nmappixels, nmappixels_width, nmappixels_height, false, 1);
447 detailtexture = detailtextures[i % NUM_DETAILTEXTURES];
451 tx->texture = R_LoadTexture2D (loadmodel->texturepool, tx->name, basepixels_width, basepixels_height, basepixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
453 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);
455 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);
457 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);
459 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);
460 tx->detailtexture = detailtexture;
467 tx->texture = r_notexture;
468 tx->nmaptexture = NULL;
469 tx->glosstexture = NULL;
470 tx->glowtexture = NULL;
471 tx->fogtexture = NULL;
472 tx->detailtexture = NULL;
476 Mem_Free(basepixels);
478 Mem_Free(bumppixels);
480 Mem_Free(nmappixels);
482 Mem_Free(glosspixels);
484 Mem_Free(glowpixels);
486 Mem_Free(maskpixels);
488 if (tx->name[0] == '*')
490 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
491 // LordHavoc: some turbulent textures should be fullbright and solid
492 if (!strncmp(tx->name,"*lava",5)
493 || !strncmp(tx->name,"*teleport",9)
494 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
495 tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
497 tx->flags |= SURF_WATERALPHA;
498 tx->shader = &Cshader_water;
500 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
502 tx->flags |= SURF_DRAWSKY;
503 tx->shader = &Cshader_sky;
507 tx->flags |= SURF_LIGHTMAP;
509 tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT;
510 tx->shader = &Cshader_wall_lightmap;
513 // start out with no animation
514 tx->currentframe = tx;
517 // sequence the animations
518 for (i = 0;i < m->nummiptex;i++)
520 tx = loadmodel->textures + i;
521 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
523 if (tx->anim_total[0] || tx->anim_total[1])
524 continue; // already sequenced
526 // find the number of frames in the animation
527 memset (anims, 0, sizeof(anims));
528 memset (altanims, 0, sizeof(altanims));
530 for (j = i;j < m->nummiptex;j++)
532 tx2 = loadmodel->textures + j;
533 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
537 if (num >= '0' && num <= '9')
538 anims[num - '0'] = tx2;
539 else if (num >= 'a' && num <= 'j')
540 altanims[num - 'a'] = tx2;
542 Con_Printf ("Bad animating texture %s\n", tx->name);
546 for (j = 0;j < 10;j++)
553 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
556 for (j = 0;j < max;j++)
560 Con_Printf ("Missing frame %i of %s\n", j, tx->name);
564 for (j = 0;j < altmax;j++)
568 Con_Printf ("Missing altframe %i of %s\n", j, tx->name);
577 // if there is no alternate animation, duplicate the primary
578 // animation into the alternate
580 for (k = 0;k < 10;k++)
581 altanims[k] = anims[k];
584 // link together the primary animation
585 for (j = 0;j < max;j++)
588 tx2->animated = true;
589 tx2->anim_total[0] = max;
590 tx2->anim_total[1] = altmax;
591 for (k = 0;k < 10;k++)
593 tx2->anim_frames[0][k] = anims[k];
594 tx2->anim_frames[1][k] = altanims[k];
598 // if there really is an alternate anim...
599 if (anims[0] != altanims[0])
601 // link together the alternate animation
602 for (j = 0;j < altmax;j++)
605 tx2->animated = true;
606 // the primary/alternate are reversed here
607 tx2->anim_total[0] = altmax;
608 tx2->anim_total[1] = max;
609 for (k = 0;k < 10;k++)
611 tx2->anim_frames[0][k] = altanims[k];
612 tx2->anim_frames[1][k] = anims[k];
624 static void Mod_LoadLighting (lump_t *l)
627 qbyte *in, *out, *data, d;
628 char litfilename[1024];
629 loadmodel->lightdata = NULL;
630 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
632 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
633 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
635 else // LordHavoc: bsp version 29 (normal white lighting)
637 // LordHavoc: hope is not lost yet, check for a .lit file to load
638 strcpy(litfilename, loadmodel->name);
639 COM_StripExtension(litfilename, litfilename);
640 strcat(litfilename, ".lit");
641 data = (qbyte*) COM_LoadFile (litfilename, false);
644 if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
646 i = LittleLong(((int *)data)[1]);
649 Con_DPrintf("%s loaded", litfilename);
650 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
651 memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
657 Con_Printf("Unknown .lit file version (%d)\n", i);
664 Con_Printf("Empty .lit file, ignoring\n");
666 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
670 // LordHavoc: oh well, expand the white lighting data
673 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
674 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
675 out = loadmodel->lightdata;
676 memcpy (in, mod_base + l->fileofs, l->filelen);
677 for (i = 0;i < l->filelen;i++)
687 void Mod_LoadLightList(void)
690 char lightsfilename[1024], *s, *t, *lightsstring;
693 strcpy(lightsfilename, loadmodel->name);
694 COM_StripExtension(lightsfilename, lightsfilename);
695 strcat(lightsfilename, ".lights");
696 s = lightsstring = (char *) COM_LoadFile (lightsfilename, false);
702 while (*s && *s != '\n')
706 Mem_Free(lightsstring);
707 Host_Error("lights file must end with a newline\n");
712 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
715 while (*s && n < numlights)
718 while (*s && *s != '\n')
722 Mem_Free(lightsstring);
723 Host_Error("misparsed lights file!\n");
725 e = loadmodel->lights + n;
727 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);
731 Mem_Free(lightsstring);
732 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);
739 Mem_Free(lightsstring);
740 Host_Error("misparsed lights file!\n");
742 loadmodel->numlights = numlights;
743 Mem_Free(lightsstring);
748 static int castshadowcount = 0;
749 void Mod_ProcessLightList(void)
751 int j, k, l, *mark, lnum;
759 for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++)
761 e->cullradius2 = DotProduct(e->light, e->light) / (e->falloff * e->falloff * 8192.0f * 8192.0f * 2.0f * 2.0f);// + 4096.0f;
762 if (e->cullradius2 > 4096.0f * 4096.0f)
763 e->cullradius2 = 4096.0f * 4096.0f;
764 e->cullradius = e->lightradius = sqrt(e->cullradius2);
765 leaf = Mod_PointInLeaf(e->origin, loadmodel);
766 if (leaf->compressed_vis)
767 pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel);
770 for (j = 0;j < loadmodel->numsurfaces;j++)
771 loadmodel->surfacevisframes[j] = -1;
772 for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++)
774 if (pvs[j >> 3] & (1 << (j & 7)))
776 for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++)
778 surf = loadmodel->surfaces + *mark;
779 if (surf->number != *mark)
780 Con_Printf("%d != %d\n", surf->number, *mark);
781 dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
782 if (surf->flags & SURF_PLANEBACK)
784 if (dist > 0 && dist < e->cullradius)
786 temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
787 temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
788 temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
789 if (DotProduct(temp, temp) < lightradius2)
790 loadmodel->surfacevisframes[*mark] = -2;
795 // build list of light receiving surfaces
797 for (j = 0;j < loadmodel->numsurfaces;j++)
798 if (loadmodel->surfacevisframes[j] == -2)
801 if (e->numsurfaces > 0)
803 e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
805 for (j = 0;j < loadmodel->numsurfaces;j++)
806 if (loadmodel->surfacevisframes[j] == -2)
807 e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j;
809 // find bounding box and sphere of lit surfaces
810 // (these will be used for creating a shape to clip the light)
812 for (j = 0;j < e->numsurfaces;j++)
814 surf = e->surfaces[j];
817 VectorCopy(surf->poly_verts, e->mins);
818 VectorCopy(surf->poly_verts, e->maxs);
820 for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
822 if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
823 if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
824 if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
825 VectorSubtract(v, e->origin, temp);
826 dist = DotProduct(temp, temp);
831 if (e->cullradius2 > radius2)
833 e->cullradius2 = radius2;
834 e->cullradius = sqrt(e->cullradius2);
836 if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
837 if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
838 if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
839 if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
840 if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
841 if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
842 // clip shadow volumes against eachother to remove unnecessary
843 // polygons (and sections of polygons)
845 //vec3_t polymins, polymaxs;
847 float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
848 float f, *v0, *v1, projectdistance;
850 e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024);
853 vec3_t outermins, outermaxs, innermins, innermaxs;
854 innermins[0] = e->mins[0] - 1;
855 innermins[1] = e->mins[1] - 1;
856 innermins[2] = e->mins[2] - 1;
857 innermaxs[0] = e->maxs[0] + 1;
858 innermaxs[1] = e->maxs[1] + 1;
859 innermaxs[2] = e->maxs[2] + 1;
860 outermins[0] = loadmodel->normalmins[0] - 1;
861 outermins[1] = loadmodel->normalmins[1] - 1;
862 outermins[2] = loadmodel->normalmins[2] - 1;
863 outermaxs[0] = loadmodel->normalmaxs[0] + 1;
864 outermaxs[1] = loadmodel->normalmaxs[1] + 1;
865 outermaxs[2] = loadmodel->normalmaxs[2] + 1;
866 // add bounding box around the whole shadow volume set,
867 // facing inward to limit light area, with an outer bounding box
868 // facing outward (this is needed by the shadow rendering method)
870 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
871 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
872 verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
873 verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
874 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
875 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
876 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
877 verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
878 verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
879 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
881 verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
882 verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
883 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
884 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
885 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
886 verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
887 verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
888 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
889 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
890 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
892 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
893 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
894 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
895 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
896 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
897 verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
898 verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
899 verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
900 verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
901 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
903 verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
904 verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
905 verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
906 verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
907 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
908 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
909 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
910 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
911 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
912 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
914 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
915 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2];
916 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2];
917 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
918 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
919 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
920 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2];
921 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2];
922 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
923 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
925 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2];
926 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
927 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
928 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2];
929 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
930 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2];
931 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
932 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
933 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2];
934 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
938 for (j = 0;j < e->numsurfaces;j++)
940 surf = e->surfaces[j];
941 if (surf->flags & SURF_SHADOWCAST)
942 surf->castshadow = castshadowcount;
944 for (j = 0;j < e->numsurfaces;j++)
946 surf = e->surfaces[j];
947 if (surf->castshadow != castshadowcount)
949 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
950 if (surf->flags & SURF_PLANEBACK)
952 projectdistance = e->lightradius;
953 if (maxverts < surf->poly_numverts)
955 maxverts = surf->poly_numverts;
958 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
960 // copy the original polygon, for the front cap of the volume
961 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
963 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
964 // project the original polygon, reversed, for the back cap of the volume
965 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
967 VectorSubtract(v0, e->origin, temp);
968 VectorNormalize(temp);
969 VectorMA(v0, projectdistance, temp, v1);
971 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
972 // project the shadow volume sides
973 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)
975 if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount)
977 VectorCopy(v1, &verts[0]);
978 VectorCopy(v0, &verts[3]);
979 VectorCopy(v0, &verts[6]);
980 VectorCopy(v1, &verts[9]);
981 VectorSubtract(&verts[6], e->origin, temp);
982 VectorNormalize(temp);
983 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
984 VectorSubtract(&verts[9], e->origin, temp);
985 VectorNormalize(temp);
986 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
987 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
991 // build the triangle mesh
992 e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume);
996 for (mesh = e->shadowvolume;mesh;mesh = mesh->next)
997 l += mesh->numtriangles;
998 Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l);
1011 static void Mod_LoadVisibility (lump_t *l)
1013 loadmodel->visdata = NULL;
1016 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
1017 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
1020 // used only for HalfLife maps
1021 void Mod_ParseWadsFromEntityLump(const char *data)
1023 char key[128], value[4096];
1028 if (!COM_ParseToken(&data))
1030 if (com_token[0] != '{')
1034 if (!COM_ParseToken(&data))
1036 if (com_token[0] == '}')
1037 break; // end of worldspawn
1038 if (com_token[0] == '_')
1039 strcpy(key, com_token + 1);
1041 strcpy(key, com_token);
1042 while (key[strlen(key)-1] == ' ') // remove trailing spaces
1043 key[strlen(key)-1] = 0;
1044 if (!COM_ParseToken(&data))
1046 strcpy(value, com_token);
1047 if (!strcmp("wad", key)) // for HalfLife maps
1049 if (loadmodel->ishlbsp)
1052 for (i = 0;i < 4096;i++)
1053 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
1059 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
1060 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
1062 else if (value[i] == ';' || value[i] == 0)
1066 strcpy(wadname, "textures/");
1067 strcat(wadname, &value[j]);
1068 W_LoadTextureWadFile (wadname, false);
1085 static void Mod_LoadEntities (lump_t *l)
1087 loadmodel->entities = NULL;
1090 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
1091 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
1092 if (loadmodel->ishlbsp)
1093 Mod_ParseWadsFromEntityLump(loadmodel->entities);
1102 static void Mod_LoadVertexes (lump_t *l)
1108 in = (void *)(mod_base + l->fileofs);
1109 if (l->filelen % sizeof(*in))
1110 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1111 count = l->filelen / sizeof(*in);
1112 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1114 loadmodel->vertexes = out;
1115 loadmodel->numvertexes = count;
1117 for ( i=0 ; i<count ; i++, in++, out++)
1119 out->position[0] = LittleFloat (in->point[0]);
1120 out->position[1] = LittleFloat (in->point[1]);
1121 out->position[2] = LittleFloat (in->point[2]);
1130 static void Mod_LoadSubmodels (lump_t *l)
1136 in = (void *)(mod_base + l->fileofs);
1137 if (l->filelen % sizeof(*in))
1138 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1139 count = l->filelen / sizeof(*in);
1140 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1142 loadmodel->submodels = out;
1143 loadmodel->numsubmodels = count;
1145 for ( i=0 ; i<count ; i++, in++, out++)
1147 for (j=0 ; j<3 ; j++)
1149 // spread the mins / maxs by a pixel
1150 out->mins[j] = LittleFloat (in->mins[j]) - 1;
1151 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
1152 out->origin[j] = LittleFloat (in->origin[j]);
1154 for (j=0 ; j<MAX_MAP_HULLS ; j++)
1155 out->headnode[j] = LittleLong (in->headnode[j]);
1156 out->visleafs = LittleLong (in->visleafs);
1157 out->firstface = LittleLong (in->firstface);
1158 out->numfaces = LittleLong (in->numfaces);
1167 static void Mod_LoadEdges (lump_t *l)
1173 in = (void *)(mod_base + l->fileofs);
1174 if (l->filelen % sizeof(*in))
1175 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1176 count = l->filelen / sizeof(*in);
1177 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1179 loadmodel->edges = out;
1180 loadmodel->numedges = count;
1182 for ( i=0 ; i<count ; i++, in++, out++)
1184 out->v[0] = (unsigned short)LittleShort(in->v[0]);
1185 out->v[1] = (unsigned short)LittleShort(in->v[1]);
1194 static void Mod_LoadTexinfo (lump_t *l)
1198 int i, j, k, count, miptex;
1200 in = (void *)(mod_base + l->fileofs);
1201 if (l->filelen % sizeof(*in))
1202 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1203 count = l->filelen / sizeof(*in);
1204 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1206 loadmodel->texinfo = out;
1207 loadmodel->numtexinfo = count;
1209 for (i = 0;i < count;i++, in++, out++)
1211 for (k = 0;k < 2;k++)
1212 for (j = 0;j < 4;j++)
1213 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
1215 miptex = LittleLong (in->miptex);
1216 out->flags = LittleLong (in->flags);
1218 out->texture = NULL;
1219 if (loadmodel->textures)
1221 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
1222 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
1224 out->texture = loadmodel->textures + miptex;
1226 if (out->flags & TEX_SPECIAL)
1228 // if texture chosen is NULL or the shader needs a lightmap,
1229 // force to notexture water shader
1230 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
1231 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
1235 // if texture chosen is NULL, force to notexture
1236 if (out->texture == NULL)
1237 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
1246 Fills in s->texturemins[] and s->extents[]
1249 static void CalcSurfaceExtents (msurface_t *s)
1251 float mins[2], maxs[2], val;
1255 int bmins[2], bmaxs[2];
1257 mins[0] = mins[1] = 999999999;
1258 maxs[0] = maxs[1] = -999999999;
1262 for (i=0 ; i<s->numedges ; i++)
1264 e = loadmodel->surfedges[s->firstedge+i];
1266 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
1268 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
1270 for (j=0 ; j<2 ; j++)
1272 val = v->position[0] * tex->vecs[j][0] +
1273 v->position[1] * tex->vecs[j][1] +
1274 v->position[2] * tex->vecs[j][2] +
1283 for (i=0 ; i<2 ; i++)
1285 bmins[i] = floor(mins[i]/16);
1286 bmaxs[i] = ceil(maxs[i]/16);
1288 s->texturemins[i] = bmins[i] * 16;
1289 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
1294 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1299 mins[0] = mins[1] = mins[2] = 9999;
1300 maxs[0] = maxs[1] = maxs[2] = -9999;
1302 for (i = 0;i < numverts;i++)
1304 for (j = 0;j < 3;j++, v++)
1315 #define MAX_SUBDIVPOLYTRIANGLES 4096
1316 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1318 static int subdivpolyverts, subdivpolytriangles;
1319 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1320 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1322 static int subdivpolylookupvert(vec3_t v)
1325 for (i = 0;i < subdivpolyverts;i++)
1326 if (subdivpolyvert[i][0] == v[0]
1327 && subdivpolyvert[i][1] == v[1]
1328 && subdivpolyvert[i][2] == v[2])
1330 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1331 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1332 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1333 return subdivpolyverts++;
1336 static void SubdividePolygon (int numverts, float *verts)
1338 int i, i1, i2, i3, f, b, c, p;
1339 vec3_t mins, maxs, front[256], back[256];
1340 float m, *pv, *cv, dist[256], frac;
1343 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1345 BoundPoly (numverts, verts, mins, maxs);
1347 for (i = 0;i < 3;i++)
1349 m = (mins[i] + maxs[i]) * 0.5;
1350 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1351 if (maxs[i] - m < 8)
1353 if (m - mins[i] < 8)
1357 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1358 dist[c] = cv[i] - m;
1361 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1365 VectorCopy (pv, front[f]);
1370 VectorCopy (pv, back[b]);
1373 if (dist[p] == 0 || dist[c] == 0)
1375 if ( (dist[p] > 0) != (dist[c] > 0) )
1378 frac = dist[p] / (dist[p] - dist[c]);
1379 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1380 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1381 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1387 SubdividePolygon (f, front[0]);
1388 SubdividePolygon (b, back[0]);
1392 i1 = subdivpolylookupvert(verts);
1393 i2 = subdivpolylookupvert(verts + 3);
1394 for (i = 2;i < numverts;i++)
1396 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1398 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1402 i3 = subdivpolylookupvert(verts + i * 3);
1403 subdivpolyindex[subdivpolytriangles][0] = i1;
1404 subdivpolyindex[subdivpolytriangles][1] = i2;
1405 subdivpolyindex[subdivpolytriangles][2] = i3;
1407 subdivpolytriangles++;
1413 Mod_GenerateWarpMesh
1415 Breaks a polygon up along axial 64 unit
1416 boundaries so that turbulent and sky warps
1417 can be done reasonably.
1420 void Mod_GenerateWarpMesh (msurface_t *surf)
1426 subdivpolytriangles = 0;
1427 subdivpolyverts = 0;
1428 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1429 if (subdivpolytriangles < 1)
1430 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1432 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1433 mesh->numverts = subdivpolyverts;
1434 mesh->numtriangles = subdivpolytriangles;
1435 mesh->vertex = (surfvertex_t *)(mesh + 1);
1436 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1437 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1439 for (i = 0;i < mesh->numtriangles;i++)
1440 for (j = 0;j < 3;j++)
1441 mesh->index[i*3+j] = subdivpolyindex[i][j];
1443 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1445 VectorCopy(subdivpolyvert[i], v->v);
1446 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1447 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1452 surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles)
1455 mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (4 + 4 + 4 + 4 + 4 + 4 + 4 + 1) * sizeof(float));
1456 mesh->numverts = numverts;
1457 mesh->numtriangles = numtriangles;
1458 mesh->verts = (float *)(mesh + 1);
1459 mesh->str = mesh->verts + mesh->numverts * 4;
1460 mesh->uvw = mesh->str + mesh->numverts * 4;
1461 mesh->abc = mesh->uvw + mesh->numverts * 4;
1462 mesh->svectors = (float *)(mesh->abc + mesh->numverts * 4);
1463 mesh->tvectors = mesh->svectors + mesh->numverts * 4;
1464 mesh->normals = mesh->tvectors + mesh->numverts * 4;
1465 mesh->lightmapoffsets = (int *)(mesh->normals + mesh->numverts * 4);
1466 mesh->index = mesh->lightmapoffsets + mesh->numverts;
1467 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
1471 void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
1473 int i, iu, iv, *index, smax, tmax;
1474 float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
1477 smax = surf->extents[0] >> 4;
1478 tmax = surf->extents[1] >> 4;
1482 surf->lightmaptexturestride = 0;
1483 surf->lightmaptexture = NULL;
1491 surf->flags |= SURF_LIGHTMAP;
1492 if (r_miplightmaps.integer)
1494 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1495 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);
1499 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1500 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);
1502 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1503 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1504 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1507 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1509 index = mesh->index;
1510 for (i = 0;i < mesh->numtriangles;i++)
1516 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1518 VectorCopy(surf->plane->normal, normal);
1519 if (surf->flags & SURF_PLANEBACK)
1520 VectorNegate(normal, normal);
1521 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1523 s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1524 t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1525 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1526 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1527 // LordHavoc: calc lightmap data offset for vertex lighting to use
1530 iu = bound(0, iu, smax);
1531 iv = bound(0, iv, tmax);
1532 u = u * uscale + ubase;
1533 v = v * vscale + vbase;
1535 mesh->verts[i * 4 + 0] = in[0];
1536 mesh->verts[i * 4 + 1] = in[1];
1537 mesh->verts[i * 4 + 2] = in[2];
1538 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1539 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1540 mesh->uvw[i * 4 + 0] = u;
1541 mesh->uvw[i * 4 + 1] = v;
1542 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1543 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1544 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
1546 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1549 void Mod_GenerateVertexMesh (msurface_t *surf)
1552 float *in, s, t, normal[3];
1555 surf->lightmaptexturestride = 0;
1556 surf->lightmaptexture = NULL;
1558 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1560 index = mesh->index;
1561 for (i = 0;i < mesh->numtriangles;i++)
1567 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1569 VectorCopy(surf->plane->normal, normal);
1570 if (surf->flags & SURF_PLANEBACK)
1571 VectorNegate(normal, normal);
1572 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1574 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
1575 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
1576 mesh->verts[i * 4 + 0] = in[0];
1577 mesh->verts[i * 4 + 1] = in[1];
1578 mesh->verts[i * 4 + 2] = in[2];
1579 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1580 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1581 mesh->uvw[i * 4 + 0] = 0;
1582 mesh->uvw[i * 4 + 1] = 0;
1583 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1584 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1586 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1589 void Mod_GenerateSurfacePolygon (msurface_t *surf)
1592 float *vec, *vert, mins[3], maxs[3];
1594 // convert edges back to a normal polygon
1595 surf->poly_numverts = surf->numedges;
1596 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
1597 for (i = 0;i < surf->numedges;i++)
1599 lindex = loadmodel->surfedges[surf->firstedge + i];
1601 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1603 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1604 VectorCopy (vec, vert);
1607 vert = surf->poly_verts;
1608 VectorCopy(vert, mins);
1609 VectorCopy(vert, maxs);
1611 for (i = 1;i < surf->poly_numverts;i++, vert += 3)
1613 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1614 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1615 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1617 VectorCopy(mins, surf->poly_mins);
1618 VectorCopy(maxs, surf->poly_maxs);
1619 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1620 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1621 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1629 static void Mod_LoadFaces (lump_t *l)
1633 int i, count, surfnum, planenum, ssize, tsize;
1635 in = (void *)(mod_base + l->fileofs);
1636 if (l->filelen % sizeof(*in))
1637 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1638 count = l->filelen / sizeof(*in);
1639 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1641 loadmodel->surfaces = out;
1642 loadmodel->numsurfaces = count;
1643 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1644 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1645 loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1647 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1649 out->number = surfnum;
1650 // FIXME: validate edges, texinfo, etc?
1651 out->firstedge = LittleLong(in->firstedge);
1652 out->numedges = LittleShort(in->numedges);
1653 if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges)
1654 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges);
1656 i = LittleShort (in->texinfo);
1657 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1658 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1659 out->texinfo = loadmodel->texinfo + i;
1660 out->flags = out->texinfo->texture->flags;
1662 planenum = LittleShort(in->planenum);
1663 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1664 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1666 if (LittleShort(in->side))
1667 out->flags |= SURF_PLANEBACK;
1669 out->plane = loadmodel->planes + planenum;
1671 // clear lightmap (filled in later)
1672 out->lightmaptexture = NULL;
1674 // force lightmap upload on first time seeing the surface
1675 out->cached_dlight = true;
1677 CalcSurfaceExtents (out);
1679 ssize = (out->extents[0] >> 4) + 1;
1680 tsize = (out->extents[1] >> 4) + 1;
1683 for (i = 0;i < MAXLIGHTMAPS;i++)
1684 out->styles[i] = in->styles[i];
1685 i = LittleLong(in->lightofs);
1687 out->samples = NULL;
1688 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1689 out->samples = loadmodel->lightdata + i;
1690 else // LordHavoc: white lighting (bsp version 29)
1691 out->samples = loadmodel->lightdata + (i * 3);
1693 Mod_GenerateSurfacePolygon(out);
1694 if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
1696 if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
1697 Host_Error ("Bad surface extents");
1698 Mod_GenerateWallMesh (out, false);
1699 // stainmap for permanent marks on walls
1700 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1702 memset(out->stainsamples, 255, ssize * tsize * 3);
1705 Mod_GenerateVertexMesh (out);
1714 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1716 node->parent = parent;
1717 if (node->contents < 0)
1719 Mod_SetParent (node->children[0], node);
1720 Mod_SetParent (node->children[1], node);
1728 static void Mod_LoadNodes (lump_t *l)
1734 in = (void *)(mod_base + l->fileofs);
1735 if (l->filelen % sizeof(*in))
1736 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1737 count = l->filelen / sizeof(*in);
1738 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1740 loadmodel->nodes = out;
1741 loadmodel->numnodes = count;
1743 for ( i=0 ; i<count ; i++, in++, out++)
1745 for (j=0 ; j<3 ; j++)
1747 out->mins[j] = LittleShort (in->mins[j]);
1748 out->maxs[j] = LittleShort (in->maxs[j]);
1751 p = LittleLong(in->planenum);
1752 out->plane = loadmodel->planes + p;
1754 out->firstsurface = LittleShort (in->firstface);
1755 out->numsurfaces = LittleShort (in->numfaces);
1757 for (j=0 ; j<2 ; j++)
1759 p = LittleShort (in->children[j]);
1761 out->children[j] = loadmodel->nodes + p;
1763 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1767 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1775 static void Mod_LoadLeafs (lump_t *l)
1781 in = (void *)(mod_base + l->fileofs);
1782 if (l->filelen % sizeof(*in))
1783 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1784 count = l->filelen / sizeof(*in);
1785 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1787 loadmodel->leafs = out;
1788 loadmodel->numleafs = count;
1790 for ( i=0 ; i<count ; i++, in++, out++)
1792 for (j=0 ; j<3 ; j++)
1794 out->mins[j] = LittleShort (in->mins[j]);
1795 out->maxs[j] = LittleShort (in->maxs[j]);
1798 p = LittleLong(in->contents);
1801 out->firstmarksurface = loadmodel->marksurfaces +
1802 LittleShort(in->firstmarksurface);
1803 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1805 p = LittleLong(in->visofs);
1807 out->compressed_vis = NULL;
1809 out->compressed_vis = loadmodel->visdata + p;
1811 for (j=0 ; j<4 ; j++)
1812 out->ambient_sound_level[j] = in->ambient_level[j];
1814 // FIXME: Insert caustics here
1823 static void Mod_LoadClipnodes (lump_t *l)
1825 dclipnode_t *in, *out;
1829 in = (void *)(mod_base + l->fileofs);
1830 if (l->filelen % sizeof(*in))
1831 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1832 count = l->filelen / sizeof(*in);
1833 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1835 loadmodel->clipnodes = out;
1836 loadmodel->numclipnodes = count;
1838 if (loadmodel->ishlbsp)
1840 hull = &loadmodel->hulls[1];
1841 hull->clipnodes = out;
1842 hull->firstclipnode = 0;
1843 hull->lastclipnode = count-1;
1844 hull->planes = loadmodel->planes;
1845 hull->clip_mins[0] = -16;
1846 hull->clip_mins[1] = -16;
1847 hull->clip_mins[2] = -36;
1848 hull->clip_maxs[0] = 16;
1849 hull->clip_maxs[1] = 16;
1850 hull->clip_maxs[2] = 36;
1851 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1853 hull = &loadmodel->hulls[2];
1854 hull->clipnodes = out;
1855 hull->firstclipnode = 0;
1856 hull->lastclipnode = count-1;
1857 hull->planes = loadmodel->planes;
1858 hull->clip_mins[0] = -32;
1859 hull->clip_mins[1] = -32;
1860 hull->clip_mins[2] = -32;
1861 hull->clip_maxs[0] = 32;
1862 hull->clip_maxs[1] = 32;
1863 hull->clip_maxs[2] = 32;
1864 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1866 hull = &loadmodel->hulls[3];
1867 hull->clipnodes = out;
1868 hull->firstclipnode = 0;
1869 hull->lastclipnode = count-1;
1870 hull->planes = loadmodel->planes;
1871 hull->clip_mins[0] = -16;
1872 hull->clip_mins[1] = -16;
1873 hull->clip_mins[2] = -18;
1874 hull->clip_maxs[0] = 16;
1875 hull->clip_maxs[1] = 16;
1876 hull->clip_maxs[2] = 18;
1877 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1881 hull = &loadmodel->hulls[1];
1882 hull->clipnodes = out;
1883 hull->firstclipnode = 0;
1884 hull->lastclipnode = count-1;
1885 hull->planes = loadmodel->planes;
1886 hull->clip_mins[0] = -16;
1887 hull->clip_mins[1] = -16;
1888 hull->clip_mins[2] = -24;
1889 hull->clip_maxs[0] = 16;
1890 hull->clip_maxs[1] = 16;
1891 hull->clip_maxs[2] = 32;
1892 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1894 hull = &loadmodel->hulls[2];
1895 hull->clipnodes = out;
1896 hull->firstclipnode = 0;
1897 hull->lastclipnode = count-1;
1898 hull->planes = loadmodel->planes;
1899 hull->clip_mins[0] = -32;
1900 hull->clip_mins[1] = -32;
1901 hull->clip_mins[2] = -24;
1902 hull->clip_maxs[0] = 32;
1903 hull->clip_maxs[1] = 32;
1904 hull->clip_maxs[2] = 64;
1905 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1908 for (i=0 ; i<count ; i++, out++, in++)
1910 out->planenum = LittleLong(in->planenum);
1911 out->children[0] = LittleShort(in->children[0]);
1912 out->children[1] = LittleShort(in->children[1]);
1913 if (out->children[0] >= count || out->children[1] >= count)
1914 Host_Error("Corrupt clipping hull (out of range child)\n");
1922 Duplicate the drawing hull structure as a clipping hull
1925 static void Mod_MakeHull0 (void)
1932 hull = &loadmodel->hulls[0];
1934 in = loadmodel->nodes;
1935 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1937 hull->clipnodes = out;
1938 hull->firstclipnode = 0;
1939 hull->lastclipnode = loadmodel->numnodes - 1;
1940 hull->planes = loadmodel->planes;
1942 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1944 out->planenum = in->plane - loadmodel->planes;
1945 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1946 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1952 Mod_LoadMarksurfaces
1955 static void Mod_LoadMarksurfaces (lump_t *l)
1960 in = (void *)(mod_base + l->fileofs);
1961 if (l->filelen % sizeof(*in))
1962 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1963 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1964 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1966 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1968 j = (unsigned) LittleShort(in[i]);
1969 if (j >= loadmodel->numsurfaces)
1970 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1971 loadmodel->marksurfaces[i] = j;
1980 static void Mod_LoadSurfedges (lump_t *l)
1985 in = (void *)(mod_base + l->fileofs);
1986 if (l->filelen % sizeof(*in))
1987 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1988 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1989 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1991 for (i = 0;i < loadmodel->numsurfedges;i++)
1992 loadmodel->surfedges[i] = LittleLong (in[i]);
2001 static void Mod_LoadPlanes (lump_t *l)
2007 in = (void *)(mod_base + l->fileofs);
2008 if (l->filelen % sizeof(*in))
2009 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
2011 loadmodel->numplanes = l->filelen / sizeof(*in);
2012 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
2014 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
2016 out->normal[0] = LittleFloat (in->normal[0]);
2017 out->normal[1] = LittleFloat (in->normal[1]);
2018 out->normal[2] = LittleFloat (in->normal[2]);
2019 out->dist = LittleFloat (in->dist);
2025 #define MAX_POINTS_ON_WINDING 64
2031 double points[8][3]; // variable sized
2040 static winding_t *NewWinding (int points)
2045 if (points > MAX_POINTS_ON_WINDING)
2046 Sys_Error("NewWinding: too many points\n");
2048 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
2049 w = Mem_Alloc(loadmodel->mempool, size);
2050 memset (w, 0, size);
2055 static void FreeWinding (winding_t *w)
2065 static winding_t *BaseWindingForPlane (mplane_t *p)
2067 double org[3], vright[3], vup[3], normal[3];
2070 VectorCopy(p->normal, normal);
2071 VectorVectorsDouble(normal, vright, vup);
2073 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
2074 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
2076 // project a really big axis aligned box onto the plane
2079 VectorScale (p->normal, p->dist, org);
2081 VectorSubtract (org, vright, w->points[0]);
2082 VectorAdd (w->points[0], vup, w->points[0]);
2084 VectorAdd (org, vright, w->points[1]);
2085 VectorAdd (w->points[1], vup, w->points[1]);
2087 VectorAdd (org, vright, w->points[2]);
2088 VectorSubtract (w->points[2], vup, w->points[2]);
2090 VectorSubtract (org, vright, w->points[3]);
2091 VectorSubtract (w->points[3], vup, w->points[3]);
2102 Clips the winding to the plane, returning the new winding on the positive side
2103 Frees the input winding.
2104 If keepon is true, an exactly on-plane winding will be saved, otherwise
2105 it will be clipped away.
2108 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2110 double dists[MAX_POINTS_ON_WINDING + 1];
2111 int sides[MAX_POINTS_ON_WINDING + 1];
2120 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2122 // determine sides for each point
2123 for (i = 0;i < in->numpoints;i++)
2125 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2126 if (dot > ON_EPSILON)
2127 sides[i] = SIDE_FRONT;
2128 else if (dot < -ON_EPSILON)
2129 sides[i] = SIDE_BACK;
2134 sides[i] = sides[0];
2135 dists[i] = dists[0];
2137 if (keepon && !counts[0] && !counts[1])
2148 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2149 if (maxpts > MAX_POINTS_ON_WINDING)
2150 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2152 neww = NewWinding (maxpts);
2154 for (i = 0;i < in->numpoints;i++)
2156 if (neww->numpoints >= maxpts)
2157 Sys_Error ("ClipWinding: points exceeded estimate");
2161 if (sides[i] == SIDE_ON)
2163 VectorCopy (p1, neww->points[neww->numpoints]);
2168 if (sides[i] == SIDE_FRONT)
2170 VectorCopy (p1, neww->points[neww->numpoints]);
2174 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2177 // generate a split point
2178 p2 = in->points[(i+1)%in->numpoints];
2180 dot = dists[i] / (dists[i]-dists[i+1]);
2181 for (j = 0;j < 3;j++)
2182 { // avoid round off error when possible
2183 if (split->normal[j] == 1)
2184 mid[j] = split->dist;
2185 else if (split->normal[j] == -1)
2186 mid[j] = -split->dist;
2188 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2191 VectorCopy (mid, neww->points[neww->numpoints]);
2195 // free the original winding
2206 Divides a winding by a plane, producing one or two windings. The
2207 original winding is not damaged or freed. If only on one side, the
2208 returned winding will be the input winding. If on both sides, two
2209 new windings will be created.
2212 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2214 double dists[MAX_POINTS_ON_WINDING + 1];
2215 int sides[MAX_POINTS_ON_WINDING + 1];
2224 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2226 // determine sides for each point
2227 for (i = 0;i < in->numpoints;i++)
2229 dot = DotProduct (in->points[i], split->normal);
2232 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2233 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2234 else sides[i] = SIDE_ON;
2237 sides[i] = sides[0];
2238 dists[i] = dists[0];
2240 *front = *back = NULL;
2253 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2255 if (maxpts > MAX_POINTS_ON_WINDING)
2256 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2258 *front = f = NewWinding (maxpts);
2259 *back = b = NewWinding (maxpts);
2261 for (i = 0;i < in->numpoints;i++)
2263 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2264 Sys_Error ("DivideWinding: points exceeded estimate");
2268 if (sides[i] == SIDE_ON)
2270 VectorCopy (p1, f->points[f->numpoints]);
2272 VectorCopy (p1, b->points[b->numpoints]);
2277 if (sides[i] == SIDE_FRONT)
2279 VectorCopy (p1, f->points[f->numpoints]);
2282 else if (sides[i] == SIDE_BACK)
2284 VectorCopy (p1, b->points[b->numpoints]);
2288 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2291 // generate a split point
2292 p2 = in->points[(i+1)%in->numpoints];
2294 dot = dists[i] / (dists[i]-dists[i+1]);
2295 for (j = 0;j < 3;j++)
2296 { // avoid round off error when possible
2297 if (split->normal[j] == 1)
2298 mid[j] = split->dist;
2299 else if (split->normal[j] == -1)
2300 mid[j] = -split->dist;
2302 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2305 VectorCopy (mid, f->points[f->numpoints]);
2307 VectorCopy (mid, b->points[b->numpoints]);
2312 typedef struct portal_s
2315 mnode_t *nodes[2]; // [0] = front side of plane
2316 struct portal_s *next[2];
2318 struct portal_s *chain; // all portals are linked into a list
2322 static portal_t *portalchain;
2329 static portal_t *AllocPortal (void)
2332 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2333 p->chain = portalchain;
2338 static void FreePortal(portal_t *p)
2343 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2345 // calculate children first
2346 if (node->children[0]->contents >= 0)
2347 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2348 if (node->children[1]->contents >= 0)
2349 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2351 // make combined bounding box from children
2352 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2353 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2354 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2355 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2356 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2357 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2360 static void Mod_FinalizePortals(void)
2362 int i, j, numportals, numpoints;
2363 portal_t *p, *pnext;
2366 mleaf_t *leaf, *endleaf;
2369 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2370 leaf = loadmodel->leafs;
2371 endleaf = leaf + loadmodel->numleafs;
2372 for (;leaf < endleaf;leaf++)
2374 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2375 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2382 for (i = 0;i < 2;i++)
2384 leaf = (mleaf_t *)p->nodes[i];
2386 for (j = 0;j < w->numpoints;j++)
2388 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2389 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2390 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2391 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2392 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2393 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2400 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2402 // tally up portal and point counts
2408 // note: this check must match the one below or it will usually corrupt memory
2409 // 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
2410 if (p->winding && p->nodes[0] != p->nodes[1]
2411 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2412 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2415 numpoints += p->winding->numpoints * 2;
2419 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2420 loadmodel->numportals = numportals;
2421 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2422 loadmodel->numportalpoints = numpoints;
2423 // clear all leaf portal chains
2424 for (i = 0;i < loadmodel->numleafs;i++)
2425 loadmodel->leafs[i].portals = NULL;
2426 // process all portals in the global portal chain, while freeing them
2427 portal = loadmodel->portals;
2428 point = loadmodel->portalpoints;
2437 // note: this check must match the one above or it will usually corrupt memory
2438 // 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
2439 if (p->nodes[0] != p->nodes[1]
2440 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2441 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2443 // first make the back to front portal (forward portal)
2444 portal->points = point;
2445 portal->numpoints = p->winding->numpoints;
2446 portal->plane.dist = p->plane.dist;
2447 VectorCopy(p->plane.normal, portal->plane.normal);
2448 portal->here = (mleaf_t *)p->nodes[1];
2449 portal->past = (mleaf_t *)p->nodes[0];
2451 for (j = 0;j < portal->numpoints;j++)
2453 VectorCopy(p->winding->points[j], point->position);
2456 PlaneClassify(&portal->plane);
2458 // link into leaf's portal chain
2459 portal->next = portal->here->portals;
2460 portal->here->portals = portal;
2462 // advance to next portal
2465 // then make the front to back portal (backward portal)
2466 portal->points = point;
2467 portal->numpoints = p->winding->numpoints;
2468 portal->plane.dist = -p->plane.dist;
2469 VectorNegate(p->plane.normal, portal->plane.normal);
2470 portal->here = (mleaf_t *)p->nodes[0];
2471 portal->past = (mleaf_t *)p->nodes[1];
2473 for (j = portal->numpoints - 1;j >= 0;j--)
2475 VectorCopy(p->winding->points[j], point->position);
2478 PlaneClassify(&portal->plane);
2480 // link into leaf's portal chain
2481 portal->next = portal->here->portals;
2482 portal->here->portals = portal;
2484 // advance to next portal
2487 FreeWinding(p->winding);
2499 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2502 Host_Error ("AddPortalToNodes: NULL front node");
2504 Host_Error ("AddPortalToNodes: NULL back node");
2505 if (p->nodes[0] || p->nodes[1])
2506 Host_Error ("AddPortalToNodes: already included");
2507 // 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
2509 p->nodes[0] = front;
2510 p->next[0] = (portal_t *)front->portals;
2511 front->portals = (mportal_t *)p;
2514 p->next[1] = (portal_t *)back->portals;
2515 back->portals = (mportal_t *)p;
2520 RemovePortalFromNode
2523 static void RemovePortalFromNodes(portal_t *portal)
2527 void **portalpointer;
2529 for (i = 0;i < 2;i++)
2531 node = portal->nodes[i];
2533 portalpointer = (void **) &node->portals;
2538 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2542 if (portal->nodes[0] == node)
2544 *portalpointer = portal->next[0];
2545 portal->nodes[0] = NULL;
2547 else if (portal->nodes[1] == node)
2549 *portalpointer = portal->next[1];
2550 portal->nodes[1] = NULL;
2553 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2557 if (t->nodes[0] == node)
2558 portalpointer = (void **) &t->next[0];
2559 else if (t->nodes[1] == node)
2560 portalpointer = (void **) &t->next[1];
2562 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2567 static void Mod_RecursiveNodePortals (mnode_t *node)
2570 mnode_t *front, *back, *other_node;
2571 mplane_t clipplane, *plane;
2572 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2573 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2575 // if a leaf, we're done
2579 plane = node->plane;
2581 front = node->children[0];
2582 back = node->children[1];
2584 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2586 // create the new portal by generating a polygon for the node plane,
2587 // and clipping it by all of the other portals (which came from nodes above this one)
2588 nodeportal = AllocPortal ();
2589 nodeportal->plane = *node->plane;
2591 nodeportalwinding = BaseWindingForPlane (node->plane);
2592 side = 0; // shut up compiler warning
2593 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2595 clipplane = portal->plane;
2596 if (portal->nodes[0] == portal->nodes[1])
2597 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2598 if (portal->nodes[0] == node)
2600 else if (portal->nodes[1] == node)
2602 clipplane.dist = -clipplane.dist;
2603 VectorNegate (clipplane.normal, clipplane.normal);
2607 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2609 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2610 if (!nodeportalwinding)
2612 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2617 if (nodeportalwinding)
2619 // if the plane was not clipped on all sides, there was an error
2620 nodeportal->winding = nodeportalwinding;
2621 AddPortalToNodes (nodeportal, front, back);
2624 // split the portals of this node along this node's plane and assign them to the children of this node
2625 // (migrating the portals downward through the tree)
2626 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2628 if (portal->nodes[0] == portal->nodes[1])
2629 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2630 if (portal->nodes[0] == node)
2632 else if (portal->nodes[1] == node)
2635 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2636 nextportal = portal->next[side];
2638 other_node = portal->nodes[!side];
2639 RemovePortalFromNodes (portal);
2641 // cut the portal into two portals, one on each side of the node plane
2642 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2647 AddPortalToNodes (portal, back, other_node);
2649 AddPortalToNodes (portal, other_node, back);
2655 AddPortalToNodes (portal, front, other_node);
2657 AddPortalToNodes (portal, other_node, front);
2661 // the winding is split
2662 splitportal = AllocPortal ();
2663 temp = splitportal->chain;
2664 *splitportal = *portal;
2665 splitportal->chain = temp;
2666 splitportal->winding = backwinding;
2667 FreeWinding (portal->winding);
2668 portal->winding = frontwinding;
2672 AddPortalToNodes (portal, front, other_node);
2673 AddPortalToNodes (splitportal, back, other_node);
2677 AddPortalToNodes (portal, other_node, front);
2678 AddPortalToNodes (splitportal, other_node, back);
2682 Mod_RecursiveNodePortals(front);
2683 Mod_RecursiveNodePortals(back);
2687 static void Mod_MakePortals(void)
2690 Mod_RecursiveNodePortals (loadmodel->nodes);
2691 Mod_FinalizePortals();
2694 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2697 int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2698 msurface_t *surf, *s;
2699 float *v0, *v1, *v2, *v3;
2700 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2701 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2702 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2704 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)
2706 if (surf->neighborsurfaces[vertnum])
2708 surf->neighborsurfaces[vertnum] = NULL;
2709 for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2711 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2712 || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2713 || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2716 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2717 if (s->neighborsurfaces[vnum] == surf)
2719 if (vnum < s->poly_numverts)
2721 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)
2723 if (s->neighborsurfaces[vnum] == NULL
2724 && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2725 || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2727 surf->neighborsurfaces[vertnum] = s;
2728 s->neighborsurfaces[vnum] = surf;
2732 if (vnum < s->poly_numverts)
2745 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2746 extern void R_Model_Brush_Draw(entity_render_t *ent);
2747 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2748 extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
2749 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2754 mempool_t *mainmempool;
2756 model_t *originalloadmodel;
2758 mod->type = mod_brush;
2760 header = (dheader_t *)buffer;
2762 i = LittleLong (header->version);
2763 if (i != BSPVERSION && i != 30)
2764 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2765 mod->ishlbsp = i == 30;
2766 if (loadmodel->isworldmodel)
2768 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2769 // until we get a texture for it...
2773 // swap all the lumps
2774 mod_base = (qbyte *)header;
2776 for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
2777 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2781 // store which lightmap format to use
2782 mod->lightmaprgba = r_lightmaprgba.integer;
2784 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2785 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2786 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2787 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2788 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2789 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2790 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2791 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2792 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2793 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2794 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2795 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2796 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2797 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2798 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2803 mod->numframes = 2; // regular and alternate animation
2805 mainmempool = mod->mempool;
2806 loadname = mod->name;
2808 Mod_LoadLightList ();
2809 originalloadmodel = loadmodel;
2812 // set up the submodels (FIXME: this is confusing)
2814 for (i = 0;i < mod->numsubmodels;i++)
2817 float dist, modelyawradius, modelradius, *vec;
2820 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2821 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2825 bm = &mod->submodels[i];
2827 mod->hulls[0].firstclipnode = bm->headnode[0];
2828 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2830 mod->hulls[j].firstclipnode = bm->headnode[j];
2831 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2834 mod->firstmodelsurface = bm->firstface;
2835 mod->nummodelsurfaces = bm->numfaces;
2837 // this gets altered below if sky is used
2838 mod->DrawSky = NULL;
2839 mod->Draw = R_Model_Brush_Draw;
2840 mod->DrawFakeShadow = NULL;
2841 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2842 mod->DrawLight = R_Model_Brush_DrawLight;
2843 mod->texturesurfacechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t *));
2844 if (mod->nummodelsurfaces)
2846 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2847 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2849 // we only need to have a drawsky function if it is used (usually only on world model)
2850 if (surf->texinfo->texture->shader == &Cshader_sky)
2851 mod->DrawSky = R_Model_Brush_DrawSky;
2852 // link into texture chain
2853 surf->texturechain = mod->texturesurfacechains[surf->texinfo->texture - mod->textures];
2854 mod->texturesurfacechains[surf->texinfo->texture - mod->textures] = surf;
2855 // calculate bounding shapes
2856 for (k = 0;k < surf->numedges;k++)
2858 l = mod->surfedges[k + surf->firstedge];
2860 vec = mod->vertexes[mod->edges[l].v[0]].position;
2862 vec = mod->vertexes[mod->edges[-l].v[1]].position;
2863 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2864 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2865 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2866 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2867 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2868 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2869 dist = vec[0]*vec[0]+vec[1]*vec[1];
2870 if (modelyawradius < dist)
2871 modelyawradius = dist;
2872 dist += vec[2]*vec[2];
2873 if (modelradius < dist)
2877 modelyawradius = sqrt(modelyawradius);
2878 modelradius = sqrt(modelradius);
2879 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2880 mod->yawmins[2] = mod->normalmins[2];
2881 mod->yawmaxs[2] = mod->normalmaxs[2];
2882 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2883 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2884 mod->radius = modelradius;
2885 mod->radius2 = modelradius * modelradius;
2886 // LordHavoc: build triangle meshs for entire model's geometry
2887 // (only used for shadow volumes)
2888 mod->shadowmesh = Mod_ShadowMesh_Begin(originalloadmodel->mempool, 1024);
2889 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2890 if (surf->flags & SURF_SHADOWCAST)
2891 Mod_ShadowMesh_AddPolygon(originalloadmodel->mempool, mod->shadowmesh, surf->poly_numverts, surf->poly_verts);
2892 mod->shadowmesh = Mod_ShadowMesh_Finish(originalloadmodel->mempool, mod->shadowmesh);
2893 Mod_ShadowMesh_CalcBBox(mod->shadowmesh, mod->shadowmesh_mins, mod->shadowmesh_maxs, mod->shadowmesh_center, &mod->shadowmesh_radius);
2897 // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2898 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2899 VectorClear(mod->normalmins);
2900 VectorClear(mod->normalmaxs);
2901 VectorClear(mod->yawmins);
2902 VectorClear(mod->yawmaxs);
2903 VectorClear(mod->rotatedmins);
2904 VectorClear(mod->rotatedmaxs);
2907 mod->shadowmesh = NULL;
2909 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2911 mod->numleafs = bm->visleafs;
2913 // LordHavoc: only register submodels if it is the world
2914 // (prevents bsp models from replacing world submodels)
2915 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2918 // duplicate the basic information
2919 sprintf (name, "*%i", i+1);
2920 loadmodel = Mod_FindName (name);
2922 strcpy (loadmodel->name, name);
2923 // textures and memory belong to the main model
2924 loadmodel->texturepool = NULL;
2925 loadmodel->mempool = NULL;
2930 loadmodel = originalloadmodel;
2931 //Mod_ProcessLightList ();