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 < tx->width*tx->height;j++)
387 if (((qbyte *)&palette_onlyfullbrights[mtdata[j]])[3] > 0) // fullbright
389 if (j < 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 VectorSubtract(e->origin, surf->poly_center, temp);
787 if (DotProduct(temp, temp) - surf->poly_radius2 < e->cullradius2)
788 loadmodel->surfacevisframes[*mark] = -2;
793 // build list of light receiving surfaces
795 for (j = 0;j < loadmodel->numsurfaces;j++)
796 if (loadmodel->surfacevisframes[j] == -2)
799 if (e->numsurfaces > 0)
801 e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
803 for (j = 0;j < loadmodel->numsurfaces;j++)
804 if (loadmodel->surfacevisframes[j] == -2)
805 e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j;
807 // find bounding box and sphere of lit surfaces
808 // (these will be used for creating a shape to clip the light)
810 for (j = 0;j < e->numsurfaces;j++)
812 surf = e->surfaces[j];
815 VectorCopy(surf->poly_verts, e->mins);
816 VectorCopy(surf->poly_verts, e->maxs);
818 for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
820 if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
821 if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
822 if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
823 VectorSubtract(v, e->origin, temp);
824 dist = DotProduct(temp, temp);
829 if (e->cullradius2 > radius2)
831 e->cullradius2 = radius2;
832 e->cullradius = sqrt(e->cullradius2);
834 if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
835 if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
836 if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
837 if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
838 if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
839 if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
840 // clip shadow volumes against eachother to remove unnecessary
841 // polygons (and sections of polygons)
843 //vec3_t polymins, polymaxs;
845 float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
846 float f, *v0, *v1, projectdistance;
848 e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024);
851 vec3_t outermins, outermaxs, innermins, innermaxs;
852 innermins[0] = e->mins[0] - 1;
853 innermins[1] = e->mins[1] - 1;
854 innermins[2] = e->mins[2] - 1;
855 innermaxs[0] = e->maxs[0] + 1;
856 innermaxs[1] = e->maxs[1] + 1;
857 innermaxs[2] = e->maxs[2] + 1;
858 outermins[0] = loadmodel->normalmins[0] - 1;
859 outermins[1] = loadmodel->normalmins[1] - 1;
860 outermins[2] = loadmodel->normalmins[2] - 1;
861 outermaxs[0] = loadmodel->normalmaxs[0] + 1;
862 outermaxs[1] = loadmodel->normalmaxs[1] + 1;
863 outermaxs[2] = loadmodel->normalmaxs[2] + 1;
864 // add bounding box around the whole shadow volume set,
865 // facing inward to limit light area, with an outer bounding box
866 // facing outward (this is needed by the shadow rendering method)
868 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
869 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
870 verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
871 verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
872 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
873 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
874 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
875 verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
876 verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
877 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
879 verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
880 verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
881 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
882 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
883 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
884 verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
885 verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
886 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
887 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
888 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
890 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
891 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
892 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
893 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
894 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
895 verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
896 verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
897 verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
898 verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
899 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
901 verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
902 verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
903 verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
904 verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
905 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
906 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
907 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
908 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
909 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
910 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
912 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
913 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2];
914 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2];
915 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
916 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
917 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
918 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2];
919 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2];
920 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
921 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
923 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2];
924 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
925 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
926 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2];
927 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
928 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2];
929 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
930 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
931 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2];
932 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
936 for (j = 0;j < e->numsurfaces;j++)
938 surf = e->surfaces[j];
939 if (surf->flags & SURF_SHADOWCAST)
940 surf->castshadow = castshadowcount;
942 for (j = 0;j < e->numsurfaces;j++)
944 surf = e->surfaces[j];
945 if (surf->castshadow != castshadowcount)
947 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
948 if (surf->flags & SURF_PLANEBACK)
950 projectdistance = e->lightradius;
951 if (maxverts < surf->poly_numverts)
953 maxverts = surf->poly_numverts;
956 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
958 // copy the original polygon, for the front cap of the volume
959 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
961 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
962 // project the original polygon, reversed, for the back cap of the volume
963 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
965 VectorSubtract(v0, e->origin, temp);
966 VectorNormalize(temp);
967 VectorMA(v0, projectdistance, temp, v1);
969 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
970 // project the shadow volume sides
971 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)
973 if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount)
975 VectorCopy(v1, &verts[0]);
976 VectorCopy(v0, &verts[3]);
977 VectorCopy(v0, &verts[6]);
978 VectorCopy(v1, &verts[9]);
979 VectorSubtract(&verts[6], e->origin, temp);
980 VectorNormalize(temp);
981 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
982 VectorSubtract(&verts[9], e->origin, temp);
983 VectorNormalize(temp);
984 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
985 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
989 // build the triangle mesh
990 e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume);
994 for (mesh = e->shadowvolume;mesh;mesh = mesh->next)
995 l += mesh->numtriangles;
996 Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l);
1009 static void Mod_LoadVisibility (lump_t *l)
1011 loadmodel->visdata = NULL;
1014 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
1015 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
1018 // used only for HalfLife maps
1019 void Mod_ParseWadsFromEntityLump(const char *data)
1021 char key[128], value[4096];
1026 if (!COM_ParseToken(&data))
1028 if (com_token[0] != '{')
1032 if (!COM_ParseToken(&data))
1034 if (com_token[0] == '}')
1035 break; // end of worldspawn
1036 if (com_token[0] == '_')
1037 strcpy(key, com_token + 1);
1039 strcpy(key, com_token);
1040 while (key[strlen(key)-1] == ' ') // remove trailing spaces
1041 key[strlen(key)-1] = 0;
1042 if (!COM_ParseToken(&data))
1044 strcpy(value, com_token);
1045 if (!strcmp("wad", key)) // for HalfLife maps
1047 if (loadmodel->ishlbsp)
1050 for (i = 0;i < 4096;i++)
1051 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
1057 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
1058 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
1060 else if (value[i] == ';' || value[i] == 0)
1064 strcpy(wadname, "textures/");
1065 strcat(wadname, &value[j]);
1066 W_LoadTextureWadFile (wadname, false);
1083 static void Mod_LoadEntities (lump_t *l)
1085 loadmodel->entities = NULL;
1088 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
1089 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
1090 if (loadmodel->ishlbsp)
1091 Mod_ParseWadsFromEntityLump(loadmodel->entities);
1100 static void Mod_LoadVertexes (lump_t *l)
1106 in = (void *)(mod_base + l->fileofs);
1107 if (l->filelen % sizeof(*in))
1108 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1109 count = l->filelen / sizeof(*in);
1110 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1112 loadmodel->vertexes = out;
1113 loadmodel->numvertexes = count;
1115 for ( i=0 ; i<count ; i++, in++, out++)
1117 out->position[0] = LittleFloat (in->point[0]);
1118 out->position[1] = LittleFloat (in->point[1]);
1119 out->position[2] = LittleFloat (in->point[2]);
1128 static void Mod_LoadSubmodels (lump_t *l)
1134 in = (void *)(mod_base + l->fileofs);
1135 if (l->filelen % sizeof(*in))
1136 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1137 count = l->filelen / sizeof(*in);
1138 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1140 loadmodel->submodels = out;
1141 loadmodel->numsubmodels = count;
1143 for ( i=0 ; i<count ; i++, in++, out++)
1145 for (j=0 ; j<3 ; j++)
1147 // spread the mins / maxs by a pixel
1148 out->mins[j] = LittleFloat (in->mins[j]) - 1;
1149 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
1150 out->origin[j] = LittleFloat (in->origin[j]);
1152 for (j=0 ; j<MAX_MAP_HULLS ; j++)
1153 out->headnode[j] = LittleLong (in->headnode[j]);
1154 out->visleafs = LittleLong (in->visleafs);
1155 out->firstface = LittleLong (in->firstface);
1156 out->numfaces = LittleLong (in->numfaces);
1165 static void Mod_LoadEdges (lump_t *l)
1171 in = (void *)(mod_base + l->fileofs);
1172 if (l->filelen % sizeof(*in))
1173 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1174 count = l->filelen / sizeof(*in);
1175 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1177 loadmodel->edges = out;
1178 loadmodel->numedges = count;
1180 for ( i=0 ; i<count ; i++, in++, out++)
1182 out->v[0] = (unsigned short)LittleShort(in->v[0]);
1183 out->v[1] = (unsigned short)LittleShort(in->v[1]);
1192 static void Mod_LoadTexinfo (lump_t *l)
1196 int i, j, k, count, miptex;
1198 in = (void *)(mod_base + l->fileofs);
1199 if (l->filelen % sizeof(*in))
1200 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1201 count = l->filelen / sizeof(*in);
1202 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1204 loadmodel->texinfo = out;
1205 loadmodel->numtexinfo = count;
1207 for (i = 0;i < count;i++, in++, out++)
1209 for (k = 0;k < 2;k++)
1210 for (j = 0;j < 4;j++)
1211 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
1213 miptex = LittleLong (in->miptex);
1214 out->flags = LittleLong (in->flags);
1216 out->texture = NULL;
1217 if (loadmodel->textures)
1219 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
1220 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
1222 out->texture = loadmodel->textures + miptex;
1224 if (out->flags & TEX_SPECIAL)
1226 // if texture chosen is NULL or the shader needs a lightmap,
1227 // force to notexture water shader
1228 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
1229 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
1233 // if texture chosen is NULL, force to notexture
1234 if (out->texture == NULL)
1235 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
1244 Fills in s->texturemins[] and s->extents[]
1247 static void CalcSurfaceExtents (msurface_t *s)
1249 float mins[2], maxs[2], val;
1253 int bmins[2], bmaxs[2];
1255 mins[0] = mins[1] = 999999999;
1256 maxs[0] = maxs[1] = -999999999;
1260 for (i=0 ; i<s->numedges ; i++)
1262 e = loadmodel->surfedges[s->firstedge+i];
1264 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
1266 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
1268 for (j=0 ; j<2 ; j++)
1270 val = v->position[0] * tex->vecs[j][0] +
1271 v->position[1] * tex->vecs[j][1] +
1272 v->position[2] * tex->vecs[j][2] +
1281 for (i=0 ; i<2 ; i++)
1283 bmins[i] = floor(mins[i]/16);
1284 bmaxs[i] = ceil(maxs[i]/16);
1286 s->texturemins[i] = bmins[i] * 16;
1287 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
1292 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1297 mins[0] = mins[1] = mins[2] = 9999;
1298 maxs[0] = maxs[1] = maxs[2] = -9999;
1300 for (i = 0;i < numverts;i++)
1302 for (j = 0;j < 3;j++, v++)
1313 #define MAX_SUBDIVPOLYTRIANGLES 4096
1314 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1316 static int subdivpolyverts, subdivpolytriangles;
1317 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1318 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1320 static int subdivpolylookupvert(vec3_t v)
1323 for (i = 0;i < subdivpolyverts;i++)
1324 if (subdivpolyvert[i][0] == v[0]
1325 && subdivpolyvert[i][1] == v[1]
1326 && subdivpolyvert[i][2] == v[2])
1328 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1329 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1330 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1331 return subdivpolyverts++;
1334 static void SubdividePolygon (int numverts, float *verts)
1336 int i, i1, i2, i3, f, b, c, p;
1337 vec3_t mins, maxs, front[256], back[256];
1338 float m, *pv, *cv, dist[256], frac;
1341 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1343 BoundPoly (numverts, verts, mins, maxs);
1345 for (i = 0;i < 3;i++)
1347 m = (mins[i] + maxs[i]) * 0.5;
1348 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1349 if (maxs[i] - m < 8)
1351 if (m - mins[i] < 8)
1355 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1356 dist[c] = cv[i] - m;
1359 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1363 VectorCopy (pv, front[f]);
1368 VectorCopy (pv, back[b]);
1371 if (dist[p] == 0 || dist[c] == 0)
1373 if ( (dist[p] > 0) != (dist[c] > 0) )
1376 frac = dist[p] / (dist[p] - dist[c]);
1377 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1378 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1379 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1385 SubdividePolygon (f, front[0]);
1386 SubdividePolygon (b, back[0]);
1390 i1 = subdivpolylookupvert(verts);
1391 i2 = subdivpolylookupvert(verts + 3);
1392 for (i = 2;i < numverts;i++)
1394 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1396 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1400 i3 = subdivpolylookupvert(verts + i * 3);
1401 subdivpolyindex[subdivpolytriangles][0] = i1;
1402 subdivpolyindex[subdivpolytriangles][1] = i2;
1403 subdivpolyindex[subdivpolytriangles][2] = i3;
1405 subdivpolytriangles++;
1411 Mod_GenerateWarpMesh
1413 Breaks a polygon up along axial 64 unit
1414 boundaries so that turbulent and sky warps
1415 can be done reasonably.
1418 void Mod_GenerateWarpMesh (msurface_t *surf)
1424 subdivpolytriangles = 0;
1425 subdivpolyverts = 0;
1426 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1427 if (subdivpolytriangles < 1)
1428 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1430 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1431 mesh->numverts = subdivpolyverts;
1432 mesh->numtriangles = subdivpolytriangles;
1433 mesh->vertex = (surfvertex_t *)(mesh + 1);
1434 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1435 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1437 for (i = 0;i < mesh->numtriangles;i++)
1438 for (j = 0;j < 3;j++)
1439 mesh->index[i*3+j] = subdivpolyindex[i][j];
1441 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1443 VectorCopy(subdivpolyvert[i], v->v);
1444 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1445 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1450 surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles)
1453 mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (4 + 4 + 4 + 4 + 4 + 4 + 4 + 1) * sizeof(float));
1454 mesh->numverts = numverts;
1455 mesh->numtriangles = numtriangles;
1456 mesh->verts = (float *)(mesh + 1);
1457 mesh->str = mesh->verts + mesh->numverts * 4;
1458 mesh->uvw = mesh->str + mesh->numverts * 4;
1459 mesh->abc = mesh->uvw + mesh->numverts * 4;
1460 mesh->svectors = (float *)(mesh->abc + mesh->numverts * 4);
1461 mesh->tvectors = mesh->svectors + mesh->numverts * 4;
1462 mesh->normals = mesh->tvectors + mesh->numverts * 4;
1463 mesh->lightmapoffsets = (int *)(mesh->normals + mesh->numverts * 4);
1464 mesh->index = mesh->lightmapoffsets + mesh->numverts;
1465 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
1469 void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
1471 int i, iu, iv, *index, smax, tmax;
1472 float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
1475 smax = surf->extents[0] >> 4;
1476 tmax = surf->extents[1] >> 4;
1480 surf->lightmaptexturestride = 0;
1481 surf->lightmaptexture = NULL;
1489 surf->flags |= SURF_LIGHTMAP;
1490 if (r_miplightmaps.integer)
1492 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1493 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);
1497 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1498 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);
1500 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1501 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1502 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1505 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1507 index = mesh->index;
1508 for (i = 0;i < mesh->numtriangles;i++)
1514 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1516 VectorCopy(surf->plane->normal, normal);
1517 if (surf->flags & SURF_PLANEBACK)
1518 VectorNegate(normal, normal);
1519 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1521 s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1522 t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1523 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1524 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1525 // LordHavoc: calc lightmap data offset for vertex lighting to use
1528 iu = bound(0, iu, smax);
1529 iv = bound(0, iv, tmax);
1530 u = u * uscale + ubase;
1531 v = v * vscale + vbase;
1533 mesh->verts[i * 4 + 0] = in[0];
1534 mesh->verts[i * 4 + 1] = in[1];
1535 mesh->verts[i * 4 + 2] = in[2];
1536 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1537 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1538 mesh->uvw[i * 4 + 0] = u;
1539 mesh->uvw[i * 4 + 1] = v;
1540 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1541 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1542 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
1544 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1547 void Mod_GenerateVertexMesh (msurface_t *surf)
1550 float *in, s, t, normal[3];
1553 surf->lightmaptexturestride = 0;
1554 surf->lightmaptexture = NULL;
1556 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1558 index = mesh->index;
1559 for (i = 0;i < mesh->numtriangles;i++)
1565 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1567 VectorCopy(surf->plane->normal, normal);
1568 if (surf->flags & SURF_PLANEBACK)
1569 VectorNegate(normal, normal);
1570 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1572 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
1573 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
1574 mesh->verts[i * 4 + 0] = in[0];
1575 mesh->verts[i * 4 + 1] = in[1];
1576 mesh->verts[i * 4 + 2] = in[2];
1577 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1578 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1579 mesh->uvw[i * 4 + 0] = 0;
1580 mesh->uvw[i * 4 + 1] = 0;
1581 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1582 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1584 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1587 void Mod_GenerateSurfacePolygon (msurface_t *surf)
1590 float *vec, *vert, mins[3], maxs[3], temp[3], dist;
1592 // convert edges back to a normal polygon
1593 surf->poly_numverts = surf->numedges;
1594 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
1595 for (i = 0;i < surf->numedges;i++)
1597 lindex = loadmodel->surfedges[surf->firstedge + i];
1599 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1601 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1602 VectorCopy (vec, vert);
1605 vert = surf->poly_verts;
1606 VectorCopy(vert, mins);
1607 VectorCopy(vert, maxs);
1609 for (i = 1;i < surf->poly_numverts;i++)
1611 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1612 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1613 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1616 VectorCopy(mins, surf->poly_mins);
1617 VectorCopy(maxs, surf->poly_maxs);
1618 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1619 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1620 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1621 surf->poly_radius2 = 0;
1622 vert = surf->poly_verts;
1623 for (i = 0;i < surf->poly_numverts;i++)
1625 VectorSubtract(vert, surf->poly_center, temp);
1626 dist = DotProduct(temp, temp);
1627 if (surf->poly_radius2 < dist)
1628 surf->poly_radius2 = dist;
1631 surf->poly_radius = sqrt(surf->poly_radius2);
1639 static void Mod_LoadFaces (lump_t *l)
1643 int i, count, surfnum, planenum, ssize, tsize;
1645 in = (void *)(mod_base + l->fileofs);
1646 if (l->filelen % sizeof(*in))
1647 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1648 count = l->filelen / sizeof(*in);
1649 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1651 loadmodel->surfaces = out;
1652 loadmodel->numsurfaces = count;
1653 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1654 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1655 loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1657 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1659 out->number = surfnum;
1660 // FIXME: validate edges, texinfo, etc?
1661 out->firstedge = LittleLong(in->firstedge);
1662 out->numedges = LittleShort(in->numedges);
1663 if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges)
1664 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges);
1666 i = LittleShort (in->texinfo);
1667 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1668 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1669 out->texinfo = loadmodel->texinfo + i;
1670 out->flags = out->texinfo->texture->flags;
1672 planenum = LittleShort(in->planenum);
1673 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1674 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1676 if (LittleShort(in->side))
1677 out->flags |= SURF_PLANEBACK;
1679 out->plane = loadmodel->planes + planenum;
1681 // clear lightmap (filled in later)
1682 out->lightmaptexture = NULL;
1684 // force lightmap upload on first time seeing the surface
1685 out->cached_dlight = true;
1687 CalcSurfaceExtents (out);
1689 ssize = (out->extents[0] >> 4) + 1;
1690 tsize = (out->extents[1] >> 4) + 1;
1693 for (i = 0;i < MAXLIGHTMAPS;i++)
1694 out->styles[i] = in->styles[i];
1695 i = LittleLong(in->lightofs);
1697 out->samples = NULL;
1698 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1699 out->samples = loadmodel->lightdata + i;
1700 else // LordHavoc: white lighting (bsp version 29)
1701 out->samples = loadmodel->lightdata + (i * 3);
1703 Mod_GenerateSurfacePolygon(out);
1704 if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
1706 if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
1707 Host_Error ("Bad surface extents");
1708 Mod_GenerateWallMesh (out, false);
1709 // stainmap for permanent marks on walls
1710 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1712 memset(out->stainsamples, 255, ssize * tsize * 3);
1715 Mod_GenerateVertexMesh (out);
1724 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1726 node->parent = parent;
1727 if (node->contents < 0)
1729 Mod_SetParent (node->children[0], node);
1730 Mod_SetParent (node->children[1], node);
1738 static void Mod_LoadNodes (lump_t *l)
1744 in = (void *)(mod_base + l->fileofs);
1745 if (l->filelen % sizeof(*in))
1746 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1747 count = l->filelen / sizeof(*in);
1748 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1750 loadmodel->nodes = out;
1751 loadmodel->numnodes = count;
1753 for ( i=0 ; i<count ; i++, in++, out++)
1755 for (j=0 ; j<3 ; j++)
1757 out->mins[j] = LittleShort (in->mins[j]);
1758 out->maxs[j] = LittleShort (in->maxs[j]);
1761 p = LittleLong(in->planenum);
1762 out->plane = loadmodel->planes + p;
1764 out->firstsurface = LittleShort (in->firstface);
1765 out->numsurfaces = LittleShort (in->numfaces);
1767 for (j=0 ; j<2 ; j++)
1769 p = LittleShort (in->children[j]);
1771 out->children[j] = loadmodel->nodes + p;
1773 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1777 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1785 static void Mod_LoadLeafs (lump_t *l)
1791 in = (void *)(mod_base + l->fileofs);
1792 if (l->filelen % sizeof(*in))
1793 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1794 count = l->filelen / sizeof(*in);
1795 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1797 loadmodel->leafs = out;
1798 loadmodel->numleafs = count;
1800 for ( i=0 ; i<count ; i++, in++, out++)
1802 for (j=0 ; j<3 ; j++)
1804 out->mins[j] = LittleShort (in->mins[j]);
1805 out->maxs[j] = LittleShort (in->maxs[j]);
1808 p = LittleLong(in->contents);
1811 out->firstmarksurface = loadmodel->marksurfaces +
1812 LittleShort(in->firstmarksurface);
1813 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1815 p = LittleLong(in->visofs);
1817 out->compressed_vis = NULL;
1819 out->compressed_vis = loadmodel->visdata + p;
1821 for (j=0 ; j<4 ; j++)
1822 out->ambient_sound_level[j] = in->ambient_level[j];
1824 // FIXME: Insert caustics here
1833 static void Mod_LoadClipnodes (lump_t *l)
1835 dclipnode_t *in, *out;
1839 in = (void *)(mod_base + l->fileofs);
1840 if (l->filelen % sizeof(*in))
1841 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1842 count = l->filelen / sizeof(*in);
1843 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1845 loadmodel->clipnodes = out;
1846 loadmodel->numclipnodes = count;
1848 if (loadmodel->ishlbsp)
1850 hull = &loadmodel->hulls[1];
1851 hull->clipnodes = out;
1852 hull->firstclipnode = 0;
1853 hull->lastclipnode = count-1;
1854 hull->planes = loadmodel->planes;
1855 hull->clip_mins[0] = -16;
1856 hull->clip_mins[1] = -16;
1857 hull->clip_mins[2] = -36;
1858 hull->clip_maxs[0] = 16;
1859 hull->clip_maxs[1] = 16;
1860 hull->clip_maxs[2] = 36;
1861 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1863 hull = &loadmodel->hulls[2];
1864 hull->clipnodes = out;
1865 hull->firstclipnode = 0;
1866 hull->lastclipnode = count-1;
1867 hull->planes = loadmodel->planes;
1868 hull->clip_mins[0] = -32;
1869 hull->clip_mins[1] = -32;
1870 hull->clip_mins[2] = -32;
1871 hull->clip_maxs[0] = 32;
1872 hull->clip_maxs[1] = 32;
1873 hull->clip_maxs[2] = 32;
1874 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1876 hull = &loadmodel->hulls[3];
1877 hull->clipnodes = out;
1878 hull->firstclipnode = 0;
1879 hull->lastclipnode = count-1;
1880 hull->planes = loadmodel->planes;
1881 hull->clip_mins[0] = -16;
1882 hull->clip_mins[1] = -16;
1883 hull->clip_mins[2] = -18;
1884 hull->clip_maxs[0] = 16;
1885 hull->clip_maxs[1] = 16;
1886 hull->clip_maxs[2] = 18;
1887 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1891 hull = &loadmodel->hulls[1];
1892 hull->clipnodes = out;
1893 hull->firstclipnode = 0;
1894 hull->lastclipnode = count-1;
1895 hull->planes = loadmodel->planes;
1896 hull->clip_mins[0] = -16;
1897 hull->clip_mins[1] = -16;
1898 hull->clip_mins[2] = -24;
1899 hull->clip_maxs[0] = 16;
1900 hull->clip_maxs[1] = 16;
1901 hull->clip_maxs[2] = 32;
1902 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1904 hull = &loadmodel->hulls[2];
1905 hull->clipnodes = out;
1906 hull->firstclipnode = 0;
1907 hull->lastclipnode = count-1;
1908 hull->planes = loadmodel->planes;
1909 hull->clip_mins[0] = -32;
1910 hull->clip_mins[1] = -32;
1911 hull->clip_mins[2] = -24;
1912 hull->clip_maxs[0] = 32;
1913 hull->clip_maxs[1] = 32;
1914 hull->clip_maxs[2] = 64;
1915 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1918 for (i=0 ; i<count ; i++, out++, in++)
1920 out->planenum = LittleLong(in->planenum);
1921 out->children[0] = LittleShort(in->children[0]);
1922 out->children[1] = LittleShort(in->children[1]);
1923 if (out->children[0] >= count || out->children[1] >= count)
1924 Host_Error("Corrupt clipping hull (out of range child)\n");
1932 Duplicate the drawing hull structure as a clipping hull
1935 static void Mod_MakeHull0 (void)
1942 hull = &loadmodel->hulls[0];
1944 in = loadmodel->nodes;
1945 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1947 hull->clipnodes = out;
1948 hull->firstclipnode = 0;
1949 hull->lastclipnode = loadmodel->numnodes - 1;
1950 hull->planes = loadmodel->planes;
1952 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1954 out->planenum = in->plane - loadmodel->planes;
1955 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1956 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1962 Mod_LoadMarksurfaces
1965 static void Mod_LoadMarksurfaces (lump_t *l)
1970 in = (void *)(mod_base + l->fileofs);
1971 if (l->filelen % sizeof(*in))
1972 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1973 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1974 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1976 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1978 j = (unsigned) LittleShort(in[i]);
1979 if (j >= loadmodel->numsurfaces)
1980 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1981 loadmodel->marksurfaces[i] = j;
1990 static void Mod_LoadSurfedges (lump_t *l)
1995 in = (void *)(mod_base + l->fileofs);
1996 if (l->filelen % sizeof(*in))
1997 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1998 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1999 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
2001 for (i = 0;i < loadmodel->numsurfedges;i++)
2002 loadmodel->surfedges[i] = LittleLong (in[i]);
2011 static void Mod_LoadPlanes (lump_t *l)
2017 in = (void *)(mod_base + l->fileofs);
2018 if (l->filelen % sizeof(*in))
2019 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
2021 loadmodel->numplanes = l->filelen / sizeof(*in);
2022 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
2024 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
2026 out->normal[0] = LittleFloat (in->normal[0]);
2027 out->normal[1] = LittleFloat (in->normal[1]);
2028 out->normal[2] = LittleFloat (in->normal[2]);
2029 out->dist = LittleFloat (in->dist);
2035 #define MAX_POINTS_ON_WINDING 64
2041 double points[8][3]; // variable sized
2050 static winding_t *NewWinding (int points)
2055 if (points > MAX_POINTS_ON_WINDING)
2056 Sys_Error("NewWinding: too many points\n");
2058 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
2059 w = Mem_Alloc(loadmodel->mempool, size);
2060 memset (w, 0, size);
2065 static void FreeWinding (winding_t *w)
2075 static winding_t *BaseWindingForPlane (mplane_t *p)
2077 double org[3], vright[3], vup[3], normal[3];
2080 VectorCopy(p->normal, normal);
2081 VectorVectorsDouble(normal, vright, vup);
2083 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
2084 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
2086 // project a really big axis aligned box onto the plane
2089 VectorScale (p->normal, p->dist, org);
2091 VectorSubtract (org, vright, w->points[0]);
2092 VectorAdd (w->points[0], vup, w->points[0]);
2094 VectorAdd (org, vright, w->points[1]);
2095 VectorAdd (w->points[1], vup, w->points[1]);
2097 VectorAdd (org, vright, w->points[2]);
2098 VectorSubtract (w->points[2], vup, w->points[2]);
2100 VectorSubtract (org, vright, w->points[3]);
2101 VectorSubtract (w->points[3], vup, w->points[3]);
2112 Clips the winding to the plane, returning the new winding on the positive side
2113 Frees the input winding.
2114 If keepon is true, an exactly on-plane winding will be saved, otherwise
2115 it will be clipped away.
2118 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2120 double dists[MAX_POINTS_ON_WINDING + 1];
2121 int sides[MAX_POINTS_ON_WINDING + 1];
2130 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2132 // determine sides for each point
2133 for (i = 0;i < in->numpoints;i++)
2135 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2136 if (dot > ON_EPSILON)
2137 sides[i] = SIDE_FRONT;
2138 else if (dot < -ON_EPSILON)
2139 sides[i] = SIDE_BACK;
2144 sides[i] = sides[0];
2145 dists[i] = dists[0];
2147 if (keepon && !counts[0] && !counts[1])
2158 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2159 if (maxpts > MAX_POINTS_ON_WINDING)
2160 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2162 neww = NewWinding (maxpts);
2164 for (i = 0;i < in->numpoints;i++)
2166 if (neww->numpoints >= maxpts)
2167 Sys_Error ("ClipWinding: points exceeded estimate");
2171 if (sides[i] == SIDE_ON)
2173 VectorCopy (p1, neww->points[neww->numpoints]);
2178 if (sides[i] == SIDE_FRONT)
2180 VectorCopy (p1, neww->points[neww->numpoints]);
2184 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2187 // generate a split point
2188 p2 = in->points[(i+1)%in->numpoints];
2190 dot = dists[i] / (dists[i]-dists[i+1]);
2191 for (j = 0;j < 3;j++)
2192 { // avoid round off error when possible
2193 if (split->normal[j] == 1)
2194 mid[j] = split->dist;
2195 else if (split->normal[j] == -1)
2196 mid[j] = -split->dist;
2198 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2201 VectorCopy (mid, neww->points[neww->numpoints]);
2205 // free the original winding
2216 Divides a winding by a plane, producing one or two windings. The
2217 original winding is not damaged or freed. If only on one side, the
2218 returned winding will be the input winding. If on both sides, two
2219 new windings will be created.
2222 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2224 double dists[MAX_POINTS_ON_WINDING + 1];
2225 int sides[MAX_POINTS_ON_WINDING + 1];
2234 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2236 // determine sides for each point
2237 for (i = 0;i < in->numpoints;i++)
2239 dot = DotProduct (in->points[i], split->normal);
2242 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2243 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2244 else sides[i] = SIDE_ON;
2247 sides[i] = sides[0];
2248 dists[i] = dists[0];
2250 *front = *back = NULL;
2263 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2265 if (maxpts > MAX_POINTS_ON_WINDING)
2266 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2268 *front = f = NewWinding (maxpts);
2269 *back = b = NewWinding (maxpts);
2271 for (i = 0;i < in->numpoints;i++)
2273 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2274 Sys_Error ("DivideWinding: points exceeded estimate");
2278 if (sides[i] == SIDE_ON)
2280 VectorCopy (p1, f->points[f->numpoints]);
2282 VectorCopy (p1, b->points[b->numpoints]);
2287 if (sides[i] == SIDE_FRONT)
2289 VectorCopy (p1, f->points[f->numpoints]);
2292 else if (sides[i] == SIDE_BACK)
2294 VectorCopy (p1, b->points[b->numpoints]);
2298 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2301 // generate a split point
2302 p2 = in->points[(i+1)%in->numpoints];
2304 dot = dists[i] / (dists[i]-dists[i+1]);
2305 for (j = 0;j < 3;j++)
2306 { // avoid round off error when possible
2307 if (split->normal[j] == 1)
2308 mid[j] = split->dist;
2309 else if (split->normal[j] == -1)
2310 mid[j] = -split->dist;
2312 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2315 VectorCopy (mid, f->points[f->numpoints]);
2317 VectorCopy (mid, b->points[b->numpoints]);
2322 typedef struct portal_s
2325 mnode_t *nodes[2]; // [0] = front side of plane
2326 struct portal_s *next[2];
2328 struct portal_s *chain; // all portals are linked into a list
2332 static portal_t *portalchain;
2339 static portal_t *AllocPortal (void)
2342 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2343 p->chain = portalchain;
2348 static void FreePortal(portal_t *p)
2353 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2355 // calculate children first
2356 if (node->children[0]->contents >= 0)
2357 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2358 if (node->children[1]->contents >= 0)
2359 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2361 // make combined bounding box from children
2362 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2363 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2364 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2365 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2366 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2367 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2370 static void Mod_FinalizePortals(void)
2372 int i, j, numportals, numpoints;
2373 portal_t *p, *pnext;
2376 mleaf_t *leaf, *endleaf;
2379 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2380 leaf = loadmodel->leafs;
2381 endleaf = leaf + loadmodel->numleafs;
2382 for (;leaf < endleaf;leaf++)
2384 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2385 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2392 for (i = 0;i < 2;i++)
2394 leaf = (mleaf_t *)p->nodes[i];
2396 for (j = 0;j < w->numpoints;j++)
2398 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2399 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2400 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2401 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2402 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2403 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2410 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2412 // tally up portal and point counts
2418 // note: this check must match the one below or it will usually corrupt memory
2419 // 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
2420 if (p->winding && p->nodes[0] != p->nodes[1]
2421 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2422 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2425 numpoints += p->winding->numpoints * 2;
2429 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2430 loadmodel->numportals = numportals;
2431 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2432 loadmodel->numportalpoints = numpoints;
2433 // clear all leaf portal chains
2434 for (i = 0;i < loadmodel->numleafs;i++)
2435 loadmodel->leafs[i].portals = NULL;
2436 // process all portals in the global portal chain, while freeing them
2437 portal = loadmodel->portals;
2438 point = loadmodel->portalpoints;
2447 // note: this check must match the one above or it will usually corrupt memory
2448 // 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
2449 if (p->nodes[0] != p->nodes[1]
2450 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2451 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2453 // first make the back to front portal (forward portal)
2454 portal->points = point;
2455 portal->numpoints = p->winding->numpoints;
2456 portal->plane.dist = p->plane.dist;
2457 VectorCopy(p->plane.normal, portal->plane.normal);
2458 portal->here = (mleaf_t *)p->nodes[1];
2459 portal->past = (mleaf_t *)p->nodes[0];
2461 for (j = 0;j < portal->numpoints;j++)
2463 VectorCopy(p->winding->points[j], point->position);
2466 PlaneClassify(&portal->plane);
2468 // link into leaf's portal chain
2469 portal->next = portal->here->portals;
2470 portal->here->portals = portal;
2472 // advance to next portal
2475 // then make the front to back portal (backward portal)
2476 portal->points = point;
2477 portal->numpoints = p->winding->numpoints;
2478 portal->plane.dist = -p->plane.dist;
2479 VectorNegate(p->plane.normal, portal->plane.normal);
2480 portal->here = (mleaf_t *)p->nodes[0];
2481 portal->past = (mleaf_t *)p->nodes[1];
2483 for (j = portal->numpoints - 1;j >= 0;j--)
2485 VectorCopy(p->winding->points[j], point->position);
2488 PlaneClassify(&portal->plane);
2490 // link into leaf's portal chain
2491 portal->next = portal->here->portals;
2492 portal->here->portals = portal;
2494 // advance to next portal
2497 FreeWinding(p->winding);
2509 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2512 Host_Error ("AddPortalToNodes: NULL front node");
2514 Host_Error ("AddPortalToNodes: NULL back node");
2515 if (p->nodes[0] || p->nodes[1])
2516 Host_Error ("AddPortalToNodes: already included");
2517 // 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
2519 p->nodes[0] = front;
2520 p->next[0] = (portal_t *)front->portals;
2521 front->portals = (mportal_t *)p;
2524 p->next[1] = (portal_t *)back->portals;
2525 back->portals = (mportal_t *)p;
2530 RemovePortalFromNode
2533 static void RemovePortalFromNodes(portal_t *portal)
2537 void **portalpointer;
2539 for (i = 0;i < 2;i++)
2541 node = portal->nodes[i];
2543 portalpointer = (void **) &node->portals;
2548 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2552 if (portal->nodes[0] == node)
2554 *portalpointer = portal->next[0];
2555 portal->nodes[0] = NULL;
2557 else if (portal->nodes[1] == node)
2559 *portalpointer = portal->next[1];
2560 portal->nodes[1] = NULL;
2563 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2567 if (t->nodes[0] == node)
2568 portalpointer = (void **) &t->next[0];
2569 else if (t->nodes[1] == node)
2570 portalpointer = (void **) &t->next[1];
2572 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2577 static void Mod_RecursiveNodePortals (mnode_t *node)
2580 mnode_t *front, *back, *other_node;
2581 mplane_t clipplane, *plane;
2582 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2583 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2585 // if a leaf, we're done
2589 plane = node->plane;
2591 front = node->children[0];
2592 back = node->children[1];
2594 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2596 // create the new portal by generating a polygon for the node plane,
2597 // and clipping it by all of the other portals (which came from nodes above this one)
2598 nodeportal = AllocPortal ();
2599 nodeportal->plane = *node->plane;
2601 nodeportalwinding = BaseWindingForPlane (node->plane);
2602 side = 0; // shut up compiler warning
2603 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2605 clipplane = portal->plane;
2606 if (portal->nodes[0] == portal->nodes[1])
2607 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2608 if (portal->nodes[0] == node)
2610 else if (portal->nodes[1] == node)
2612 clipplane.dist = -clipplane.dist;
2613 VectorNegate (clipplane.normal, clipplane.normal);
2617 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2619 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2620 if (!nodeportalwinding)
2622 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2627 if (nodeportalwinding)
2629 // if the plane was not clipped on all sides, there was an error
2630 nodeportal->winding = nodeportalwinding;
2631 AddPortalToNodes (nodeportal, front, back);
2634 // split the portals of this node along this node's plane and assign them to the children of this node
2635 // (migrating the portals downward through the tree)
2636 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2638 if (portal->nodes[0] == portal->nodes[1])
2639 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2640 if (portal->nodes[0] == node)
2642 else if (portal->nodes[1] == node)
2645 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2646 nextportal = portal->next[side];
2648 other_node = portal->nodes[!side];
2649 RemovePortalFromNodes (portal);
2651 // cut the portal into two portals, one on each side of the node plane
2652 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2657 AddPortalToNodes (portal, back, other_node);
2659 AddPortalToNodes (portal, other_node, back);
2665 AddPortalToNodes (portal, front, other_node);
2667 AddPortalToNodes (portal, other_node, front);
2671 // the winding is split
2672 splitportal = AllocPortal ();
2673 temp = splitportal->chain;
2674 *splitportal = *portal;
2675 splitportal->chain = temp;
2676 splitportal->winding = backwinding;
2677 FreeWinding (portal->winding);
2678 portal->winding = frontwinding;
2682 AddPortalToNodes (portal, front, other_node);
2683 AddPortalToNodes (splitportal, back, other_node);
2687 AddPortalToNodes (portal, other_node, front);
2688 AddPortalToNodes (splitportal, other_node, back);
2692 Mod_RecursiveNodePortals(front);
2693 Mod_RecursiveNodePortals(back);
2697 static void Mod_MakePortals(void)
2700 Mod_RecursiveNodePortals (loadmodel->nodes);
2701 Mod_FinalizePortals();
2704 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2707 int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2708 msurface_t *surf, *s;
2709 float *v0, *v1, *v2, *v3;
2710 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2711 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2712 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2714 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)
2716 if (surf->neighborsurfaces[vertnum])
2718 surf->neighborsurfaces[vertnum] = NULL;
2719 for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2721 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2722 || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2723 || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2726 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2727 if (s->neighborsurfaces[vnum] == surf)
2729 if (vnum < s->poly_numverts)
2731 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)
2733 if (s->neighborsurfaces[vnum] == NULL
2734 && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2735 || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2737 surf->neighborsurfaces[vertnum] = s;
2738 s->neighborsurfaces[vnum] = surf;
2742 if (vnum < s->poly_numverts)
2755 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2756 extern void R_Model_Brush_Draw(entity_render_t *ent);
2757 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2758 extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
2759 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2764 mempool_t *mainmempool;
2766 model_t *originalloadmodel;
2768 mod->type = mod_brush;
2770 header = (dheader_t *)buffer;
2772 i = LittleLong (header->version);
2773 if (i != BSPVERSION && i != 30)
2774 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2775 mod->ishlbsp = i == 30;
2776 if (loadmodel->isworldmodel)
2778 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2779 // until we get a texture for it...
2783 // swap all the lumps
2784 mod_base = (qbyte *)header;
2786 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
2787 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2791 // store which lightmap format to use
2792 mod->lightmaprgba = r_lightmaprgba.integer;
2794 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2795 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2796 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2797 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2798 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2799 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2800 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2801 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2802 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2803 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2804 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2805 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2806 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2807 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2808 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2813 mod->numframes = 2; // regular and alternate animation
2815 mainmempool = mod->mempool;
2816 loadname = mod->name;
2818 Mod_LoadLightList ();
2819 originalloadmodel = loadmodel;
2822 // set up the submodels (FIXME: this is confusing)
2824 for (i = 0;i < mod->numsubmodels;i++)
2827 float dist, modelyawradius, modelradius, *vec;
2830 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2831 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2835 bm = &mod->submodels[i];
2837 mod->hulls[0].firstclipnode = bm->headnode[0];
2838 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2840 mod->hulls[j].firstclipnode = bm->headnode[j];
2841 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2844 mod->firstmodelsurface = bm->firstface;
2845 mod->nummodelsurfaces = bm->numfaces;
2847 // this gets altered below if sky is used
2848 mod->DrawSky = NULL;
2849 mod->Draw = R_Model_Brush_Draw;
2850 mod->DrawFakeShadow = NULL;
2851 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2852 mod->DrawLight = R_Model_Brush_DrawLight;
2853 mod->texturesurfacechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t *));
2854 if (mod->nummodelsurfaces)
2856 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2857 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2859 // we only need to have a drawsky function if it is used (usually only on world model)
2860 if (surf->texinfo->texture->shader == &Cshader_sky)
2861 mod->DrawSky = R_Model_Brush_DrawSky;
2862 // link into texture chain
2863 surf->texturechain = mod->texturesurfacechains[surf->texinfo->texture - mod->textures];
2864 mod->texturesurfacechains[surf->texinfo->texture - mod->textures] = surf;
2865 // calculate bounding shapes
2866 for (k = 0;k < surf->numedges;k++)
2868 l = mod->surfedges[k + surf->firstedge];
2870 vec = mod->vertexes[mod->edges[l].v[0]].position;
2872 vec = mod->vertexes[mod->edges[-l].v[1]].position;
2873 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2874 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2875 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2876 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2877 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2878 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2879 dist = vec[0]*vec[0]+vec[1]*vec[1];
2880 if (modelyawradius < dist)
2881 modelyawradius = dist;
2882 dist += vec[2]*vec[2];
2883 if (modelradius < dist)
2887 modelyawradius = sqrt(modelyawradius);
2888 modelradius = sqrt(modelradius);
2889 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2890 mod->yawmins[2] = mod->normalmins[2];
2891 mod->yawmaxs[2] = mod->normalmaxs[2];
2892 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2893 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2894 mod->radius = modelradius;
2895 mod->radius2 = modelradius * modelradius;
2896 // LordHavoc: build triangle meshs for entire model's geometry
2897 // (only used for shadow volumes)
2898 mod->shadowmesh = Mod_ShadowMesh_Begin(originalloadmodel->mempool, 1024);
2899 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2900 if (surf->flags & SURF_SHADOWCAST)
2901 Mod_ShadowMesh_AddPolygon(originalloadmodel->mempool, mod->shadowmesh, surf->poly_numverts, surf->poly_verts);
2902 mod->shadowmesh = Mod_ShadowMesh_Finish(originalloadmodel->mempool, mod->shadowmesh);
2903 Mod_ShadowMesh_CalcBBox(mod->shadowmesh, mod->shadowmesh_mins, mod->shadowmesh_maxs, mod->shadowmesh_center, &mod->shadowmesh_radius);
2907 // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2908 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2909 VectorClear(mod->normalmins);
2910 VectorClear(mod->normalmaxs);
2911 VectorClear(mod->yawmins);
2912 VectorClear(mod->yawmaxs);
2913 VectorClear(mod->rotatedmins);
2914 VectorClear(mod->rotatedmaxs);
2917 mod->shadowmesh = NULL;
2919 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2921 mod->numleafs = bm->visleafs;
2923 // LordHavoc: only register submodels if it is the world
2924 // (prevents bsp models from replacing world submodels)
2925 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2928 // duplicate the basic information
2929 sprintf (name, "*%i", i+1);
2930 loadmodel = Mod_FindName (name);
2932 strcpy (loadmodel->name, name);
2933 // textures and memory belong to the main model
2934 loadmodel->texturepool = NULL;
2935 loadmodel->mempool = NULL;
2940 loadmodel = originalloadmodel;
2941 //Mod_ProcessLightList ();