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[0] = tx;
515 tx->currentframe[1] = tx;
518 // sequence the animations
519 for (i = 0;i < m->nummiptex;i++)
521 tx = loadmodel->textures + i;
522 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
524 if (tx->anim_total[0] || tx->anim_total[1])
525 continue; // already sequenced
527 // find the number of frames in the animation
528 memset (anims, 0, sizeof(anims));
529 memset (altanims, 0, sizeof(altanims));
531 for (j = i;j < m->nummiptex;j++)
533 tx2 = loadmodel->textures + j;
534 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
538 if (num >= '0' && num <= '9')
539 anims[num - '0'] = tx2;
540 else if (num >= 'a' && num <= 'j')
541 altanims[num - 'a'] = tx2;
543 Con_Printf ("Bad animating texture %s\n", tx->name);
547 for (j = 0;j < 10;j++)
554 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
557 for (j = 0;j < max;j++)
561 Con_Printf ("Missing frame %i of %s\n", j, tx->name);
565 for (j = 0;j < altmax;j++)
569 Con_Printf ("Missing altframe %i of %s\n", j, tx->name);
578 // if there is no alternate animation, duplicate the primary
579 // animation into the alternate
581 for (k = 0;k < 10;k++)
582 altanims[k] = anims[k];
585 // link together the primary animation
586 for (j = 0;j < max;j++)
589 tx2->animated = true;
590 tx2->anim_total[0] = max;
591 tx2->anim_total[1] = altmax;
592 for (k = 0;k < 10;k++)
594 tx2->anim_frames[0][k] = anims[k];
595 tx2->anim_frames[1][k] = altanims[k];
599 // if there really is an alternate anim...
600 if (anims[0] != altanims[0])
602 // link together the alternate animation
603 for (j = 0;j < altmax;j++)
606 tx2->animated = true;
607 // the primary/alternate are reversed here
608 tx2->anim_total[0] = altmax;
609 tx2->anim_total[1] = max;
610 for (k = 0;k < 10;k++)
612 tx2->anim_frames[0][k] = altanims[k];
613 tx2->anim_frames[1][k] = anims[k];
625 static void Mod_LoadLighting (lump_t *l)
628 qbyte *in, *out, *data, d;
629 char litfilename[1024];
630 loadmodel->lightdata = NULL;
631 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
633 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
634 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
636 else // LordHavoc: bsp version 29 (normal white lighting)
638 // LordHavoc: hope is not lost yet, check for a .lit file to load
639 strcpy(litfilename, loadmodel->name);
640 COM_StripExtension(litfilename, litfilename);
641 strcat(litfilename, ".lit");
642 data = (qbyte*) COM_LoadFile (litfilename, false);
645 if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
647 i = LittleLong(((int *)data)[1]);
650 Con_DPrintf("%s loaded", litfilename);
651 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
652 memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
658 Con_Printf("Unknown .lit file version (%d)\n", i);
665 Con_Printf("Empty .lit file, ignoring\n");
667 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
671 // LordHavoc: oh well, expand the white lighting data
674 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
675 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
676 out = loadmodel->lightdata;
677 memcpy (in, mod_base + l->fileofs, l->filelen);
678 for (i = 0;i < l->filelen;i++)
688 void Mod_LoadLightList(void)
691 char lightsfilename[1024], *s, *t, *lightsstring;
694 strcpy(lightsfilename, loadmodel->name);
695 COM_StripExtension(lightsfilename, lightsfilename);
696 strcat(lightsfilename, ".lights");
697 s = lightsstring = (char *) COM_LoadFile (lightsfilename, false);
703 while (*s && *s != '\n')
707 Mem_Free(lightsstring);
708 Host_Error("lights file must end with a newline\n");
713 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
716 while (*s && n < numlights)
719 while (*s && *s != '\n')
723 Mem_Free(lightsstring);
724 Host_Error("misparsed lights file!\n");
726 e = loadmodel->lights + n;
728 a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &e->origin[0], &e->origin[1], &e->origin[2], &e->falloff, &e->light[0], &e->light[1], &e->light[2], &e->subtract, &e->spotdir[0], &e->spotdir[1], &e->spotdir[2], &e->spotcone, &e->distbias, &e->style);
732 Mem_Free(lightsstring);
733 Host_Error("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
740 Mem_Free(lightsstring);
741 Host_Error("misparsed lights file!\n");
743 loadmodel->numlights = numlights;
744 Mem_Free(lightsstring);
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);
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);
1008 static void Mod_LoadVisibility (lump_t *l)
1010 loadmodel->visdata = NULL;
1013 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
1014 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
1017 // used only for HalfLife maps
1018 void Mod_ParseWadsFromEntityLump(const char *data)
1020 char key[128], value[4096];
1025 if (!COM_ParseToken(&data))
1027 if (com_token[0] != '{')
1031 if (!COM_ParseToken(&data))
1033 if (com_token[0] == '}')
1034 break; // end of worldspawn
1035 if (com_token[0] == '_')
1036 strcpy(key, com_token + 1);
1038 strcpy(key, com_token);
1039 while (key[strlen(key)-1] == ' ') // remove trailing spaces
1040 key[strlen(key)-1] = 0;
1041 if (!COM_ParseToken(&data))
1043 strcpy(value, com_token);
1044 if (!strcmp("wad", key)) // for HalfLife maps
1046 if (loadmodel->ishlbsp)
1049 for (i = 0;i < 4096;i++)
1050 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
1056 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
1057 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
1059 else if (value[i] == ';' || value[i] == 0)
1063 strcpy(wadname, "textures/");
1064 strcat(wadname, &value[j]);
1065 W_LoadTextureWadFile (wadname, false);
1082 static void Mod_LoadEntities (lump_t *l)
1084 loadmodel->entities = NULL;
1087 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
1088 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
1089 if (loadmodel->ishlbsp)
1090 Mod_ParseWadsFromEntityLump(loadmodel->entities);
1099 static void Mod_LoadVertexes (lump_t *l)
1105 in = (void *)(mod_base + l->fileofs);
1106 if (l->filelen % sizeof(*in))
1107 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1108 count = l->filelen / sizeof(*in);
1109 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1111 loadmodel->vertexes = out;
1112 loadmodel->numvertexes = count;
1114 for ( i=0 ; i<count ; i++, in++, out++)
1116 out->position[0] = LittleFloat (in->point[0]);
1117 out->position[1] = LittleFloat (in->point[1]);
1118 out->position[2] = LittleFloat (in->point[2]);
1127 static void Mod_LoadSubmodels (lump_t *l)
1133 in = (void *)(mod_base + l->fileofs);
1134 if (l->filelen % sizeof(*in))
1135 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1136 count = l->filelen / sizeof(*in);
1137 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1139 loadmodel->submodels = out;
1140 loadmodel->numsubmodels = count;
1142 for ( i=0 ; i<count ; i++, in++, out++)
1144 for (j=0 ; j<3 ; j++)
1146 // spread the mins / maxs by a pixel
1147 out->mins[j] = LittleFloat (in->mins[j]) - 1;
1148 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
1149 out->origin[j] = LittleFloat (in->origin[j]);
1151 for (j=0 ; j<MAX_MAP_HULLS ; j++)
1152 out->headnode[j] = LittleLong (in->headnode[j]);
1153 out->visleafs = LittleLong (in->visleafs);
1154 out->firstface = LittleLong (in->firstface);
1155 out->numfaces = LittleLong (in->numfaces);
1164 static void Mod_LoadEdges (lump_t *l)
1170 in = (void *)(mod_base + l->fileofs);
1171 if (l->filelen % sizeof(*in))
1172 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1173 count = l->filelen / sizeof(*in);
1174 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1176 loadmodel->edges = out;
1177 loadmodel->numedges = count;
1179 for ( i=0 ; i<count ; i++, in++, out++)
1181 out->v[0] = (unsigned short)LittleShort(in->v[0]);
1182 out->v[1] = (unsigned short)LittleShort(in->v[1]);
1191 static void Mod_LoadTexinfo (lump_t *l)
1195 int i, j, k, count, miptex;
1197 in = (void *)(mod_base + l->fileofs);
1198 if (l->filelen % sizeof(*in))
1199 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1200 count = l->filelen / sizeof(*in);
1201 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1203 loadmodel->texinfo = out;
1204 loadmodel->numtexinfo = count;
1206 for (i = 0;i < count;i++, in++, out++)
1208 for (k = 0;k < 2;k++)
1209 for (j = 0;j < 4;j++)
1210 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
1212 miptex = LittleLong (in->miptex);
1213 out->flags = LittleLong (in->flags);
1215 out->texture = NULL;
1216 if (loadmodel->textures)
1218 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
1219 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
1221 out->texture = loadmodel->textures + miptex;
1223 if (out->flags & TEX_SPECIAL)
1225 // if texture chosen is NULL or the shader needs a lightmap,
1226 // force to notexture water shader
1227 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
1228 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
1232 // if texture chosen is NULL, force to notexture
1233 if (out->texture == NULL)
1234 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
1243 Fills in s->texturemins[] and s->extents[]
1246 static void CalcSurfaceExtents (msurface_t *s)
1248 float mins[2], maxs[2], val;
1252 int bmins[2], bmaxs[2];
1254 mins[0] = mins[1] = 999999999;
1255 maxs[0] = maxs[1] = -999999999;
1259 for (i=0 ; i<s->numedges ; i++)
1261 e = loadmodel->surfedges[s->firstedge+i];
1263 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
1265 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
1267 for (j=0 ; j<2 ; j++)
1269 val = v->position[0] * tex->vecs[j][0] +
1270 v->position[1] * tex->vecs[j][1] +
1271 v->position[2] * tex->vecs[j][2] +
1280 for (i=0 ; i<2 ; i++)
1282 bmins[i] = floor(mins[i]/16);
1283 bmaxs[i] = ceil(maxs[i]/16);
1285 s->texturemins[i] = bmins[i] * 16;
1286 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
1291 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1296 mins[0] = mins[1] = mins[2] = 9999;
1297 maxs[0] = maxs[1] = maxs[2] = -9999;
1299 for (i = 0;i < numverts;i++)
1301 for (j = 0;j < 3;j++, v++)
1312 #define MAX_SUBDIVPOLYTRIANGLES 4096
1313 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1315 static int subdivpolyverts, subdivpolytriangles;
1316 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1317 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1319 static int subdivpolylookupvert(vec3_t v)
1322 for (i = 0;i < subdivpolyverts;i++)
1323 if (subdivpolyvert[i][0] == v[0]
1324 && subdivpolyvert[i][1] == v[1]
1325 && subdivpolyvert[i][2] == v[2])
1327 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1328 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1329 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1330 return subdivpolyverts++;
1333 static void SubdividePolygon (int numverts, float *verts)
1335 int i, i1, i2, i3, f, b, c, p;
1336 vec3_t mins, maxs, front[256], back[256];
1337 float m, *pv, *cv, dist[256], frac;
1340 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1342 BoundPoly (numverts, verts, mins, maxs);
1344 for (i = 0;i < 3;i++)
1346 m = (mins[i] + maxs[i]) * 0.5;
1347 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1348 if (maxs[i] - m < 8)
1350 if (m - mins[i] < 8)
1354 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1355 dist[c] = cv[i] - m;
1358 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1362 VectorCopy (pv, front[f]);
1367 VectorCopy (pv, back[b]);
1370 if (dist[p] == 0 || dist[c] == 0)
1372 if ( (dist[p] > 0) != (dist[c] > 0) )
1375 frac = dist[p] / (dist[p] - dist[c]);
1376 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1377 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1378 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1384 SubdividePolygon (f, front[0]);
1385 SubdividePolygon (b, back[0]);
1389 i1 = subdivpolylookupvert(verts);
1390 i2 = subdivpolylookupvert(verts + 3);
1391 for (i = 2;i < numverts;i++)
1393 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1395 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1399 i3 = subdivpolylookupvert(verts + i * 3);
1400 subdivpolyindex[subdivpolytriangles][0] = i1;
1401 subdivpolyindex[subdivpolytriangles][1] = i2;
1402 subdivpolyindex[subdivpolytriangles][2] = i3;
1404 subdivpolytriangles++;
1410 Mod_GenerateWarpMesh
1412 Breaks a polygon up along axial 64 unit
1413 boundaries so that turbulent and sky warps
1414 can be done reasonably.
1417 void Mod_GenerateWarpMesh (msurface_t *surf)
1423 subdivpolytriangles = 0;
1424 subdivpolyverts = 0;
1425 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1426 if (subdivpolytriangles < 1)
1427 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1429 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1430 mesh->numverts = subdivpolyverts;
1431 mesh->numtriangles = subdivpolytriangles;
1432 mesh->vertex = (surfvertex_t *)(mesh + 1);
1433 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1434 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1436 for (i = 0;i < mesh->numtriangles;i++)
1437 for (j = 0;j < 3;j++)
1438 mesh->index[i*3+j] = subdivpolyindex[i][j];
1440 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1442 VectorCopy(subdivpolyvert[i], v->v);
1443 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1444 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1449 surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles)
1452 mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (4 + 4 + 4 + 4 + 4 + 4 + 4 + 1) * sizeof(float));
1453 mesh->numverts = numverts;
1454 mesh->numtriangles = numtriangles;
1455 mesh->verts = (float *)(mesh + 1);
1456 mesh->str = mesh->verts + mesh->numverts * 4;
1457 mesh->uvw = mesh->str + mesh->numverts * 4;
1458 mesh->abc = mesh->uvw + mesh->numverts * 4;
1459 mesh->svectors = (float *)(mesh->abc + mesh->numverts * 4);
1460 mesh->tvectors = mesh->svectors + mesh->numverts * 4;
1461 mesh->normals = mesh->tvectors + mesh->numverts * 4;
1462 mesh->lightmapoffsets = (int *)(mesh->normals + mesh->numverts * 4);
1463 mesh->index = mesh->lightmapoffsets + mesh->numverts;
1464 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
1468 void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
1470 int i, iu, iv, *index, smax, tmax;
1471 float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
1474 smax = surf->extents[0] >> 4;
1475 tmax = surf->extents[1] >> 4;
1479 surf->lightmaptexturestride = 0;
1480 surf->lightmaptexture = NULL;
1488 surf->flags |= SURF_LIGHTMAP;
1489 if (r_miplightmaps.integer)
1491 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1492 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);
1496 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1497 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);
1499 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1500 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1501 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1504 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1506 index = mesh->index;
1507 for (i = 0;i < mesh->numtriangles;i++)
1513 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1515 VectorCopy(surf->plane->normal, normal);
1516 if (surf->flags & SURF_PLANEBACK)
1517 VectorNegate(normal, normal);
1518 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1520 s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1521 t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1522 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1523 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1524 // LordHavoc: calc lightmap data offset for vertex lighting to use
1527 iu = bound(0, iu, smax);
1528 iv = bound(0, iv, tmax);
1529 u = u * uscale + ubase;
1530 v = v * vscale + vbase;
1532 mesh->verts[i * 4 + 0] = in[0];
1533 mesh->verts[i * 4 + 1] = in[1];
1534 mesh->verts[i * 4 + 2] = in[2];
1535 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1536 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1537 mesh->uvw[i * 4 + 0] = u;
1538 mesh->uvw[i * 4 + 1] = v;
1539 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1540 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1541 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
1543 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1546 void Mod_GenerateVertexMesh (msurface_t *surf)
1549 float *in, s, t, normal[3];
1552 surf->lightmaptexturestride = 0;
1553 surf->lightmaptexture = NULL;
1555 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1557 index = mesh->index;
1558 for (i = 0;i < mesh->numtriangles;i++)
1564 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1566 VectorCopy(surf->plane->normal, normal);
1567 if (surf->flags & SURF_PLANEBACK)
1568 VectorNegate(normal, normal);
1569 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1571 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
1572 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
1573 mesh->verts[i * 4 + 0] = in[0];
1574 mesh->verts[i * 4 + 1] = in[1];
1575 mesh->verts[i * 4 + 2] = in[2];
1576 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1577 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1578 mesh->uvw[i * 4 + 0] = 0;
1579 mesh->uvw[i * 4 + 1] = 0;
1580 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1581 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1583 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1586 void Mod_GenerateSurfacePolygon (msurface_t *surf)
1589 float *vec, *vert, mins[3], maxs[3], temp[3], dist;
1591 // convert edges back to a normal polygon
1592 surf->poly_numverts = surf->numedges;
1593 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
1594 for (i = 0;i < surf->numedges;i++)
1596 lindex = loadmodel->surfedges[surf->firstedge + i];
1598 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1600 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1601 VectorCopy (vec, vert);
1604 vert = surf->poly_verts;
1605 VectorCopy(vert, mins);
1606 VectorCopy(vert, maxs);
1608 for (i = 1;i < surf->poly_numverts;i++)
1610 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1611 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1612 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1615 VectorCopy(mins, surf->poly_mins);
1616 VectorCopy(maxs, surf->poly_maxs);
1617 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1618 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1619 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1620 surf->poly_radius2 = 0;
1621 vert = surf->poly_verts;
1622 for (i = 0;i < surf->poly_numverts;i++)
1624 VectorSubtract(vert, surf->poly_center, temp);
1625 dist = DotProduct(temp, temp);
1626 if (surf->poly_radius2 < dist)
1627 surf->poly_radius2 = dist;
1630 surf->poly_radius = sqrt(surf->poly_radius2);
1638 static void Mod_LoadFaces (lump_t *l)
1642 int i, count, surfnum, planenum, ssize, tsize;
1644 in = (void *)(mod_base + l->fileofs);
1645 if (l->filelen % sizeof(*in))
1646 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1647 count = l->filelen / sizeof(*in);
1648 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1650 loadmodel->surfaces = out;
1651 loadmodel->numsurfaces = count;
1652 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1653 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1654 loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1656 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1658 out->number = surfnum;
1659 // FIXME: validate edges, texinfo, etc?
1660 out->firstedge = LittleLong(in->firstedge);
1661 out->numedges = LittleShort(in->numedges);
1662 if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges)
1663 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges);
1665 i = LittleShort (in->texinfo);
1666 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1667 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1668 out->texinfo = loadmodel->texinfo + i;
1669 out->flags = out->texinfo->texture->flags;
1671 planenum = LittleShort(in->planenum);
1672 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1673 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1675 if (LittleShort(in->side))
1676 out->flags |= SURF_PLANEBACK;
1678 out->plane = loadmodel->planes + planenum;
1680 // clear lightmap (filled in later)
1681 out->lightmaptexture = NULL;
1683 // force lightmap upload on first time seeing the surface
1684 out->cached_dlight = true;
1686 CalcSurfaceExtents (out);
1688 ssize = (out->extents[0] >> 4) + 1;
1689 tsize = (out->extents[1] >> 4) + 1;
1692 for (i = 0;i < MAXLIGHTMAPS;i++)
1693 out->styles[i] = in->styles[i];
1694 i = LittleLong(in->lightofs);
1696 out->samples = NULL;
1697 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1698 out->samples = loadmodel->lightdata + i;
1699 else // LordHavoc: white lighting (bsp version 29)
1700 out->samples = loadmodel->lightdata + (i * 3);
1702 Mod_GenerateSurfacePolygon(out);
1703 if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
1705 if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
1706 Host_Error ("Bad surface extents");
1707 Mod_GenerateWallMesh (out, false);
1708 // stainmap for permanent marks on walls
1709 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1711 memset(out->stainsamples, 255, ssize * tsize * 3);
1714 Mod_GenerateVertexMesh (out);
1723 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1725 node->parent = parent;
1726 if (node->contents < 0)
1728 Mod_SetParent (node->children[0], node);
1729 Mod_SetParent (node->children[1], node);
1737 static void Mod_LoadNodes (lump_t *l)
1743 in = (void *)(mod_base + l->fileofs);
1744 if (l->filelen % sizeof(*in))
1745 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1746 count = l->filelen / sizeof(*in);
1747 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1749 loadmodel->nodes = out;
1750 loadmodel->numnodes = count;
1752 for ( i=0 ; i<count ; i++, in++, out++)
1754 for (j=0 ; j<3 ; j++)
1756 out->mins[j] = LittleShort (in->mins[j]);
1757 out->maxs[j] = LittleShort (in->maxs[j]);
1760 p = LittleLong(in->planenum);
1761 out->plane = loadmodel->planes + p;
1763 out->firstsurface = LittleShort (in->firstface);
1764 out->numsurfaces = LittleShort (in->numfaces);
1766 for (j=0 ; j<2 ; j++)
1768 p = LittleShort (in->children[j]);
1770 out->children[j] = loadmodel->nodes + p;
1772 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1776 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1784 static void Mod_LoadLeafs (lump_t *l)
1790 in = (void *)(mod_base + l->fileofs);
1791 if (l->filelen % sizeof(*in))
1792 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1793 count = l->filelen / sizeof(*in);
1794 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1796 loadmodel->leafs = out;
1797 loadmodel->numleafs = count;
1799 for ( i=0 ; i<count ; i++, in++, out++)
1801 for (j=0 ; j<3 ; j++)
1803 out->mins[j] = LittleShort (in->mins[j]);
1804 out->maxs[j] = LittleShort (in->maxs[j]);
1807 p = LittleLong(in->contents);
1810 out->firstmarksurface = loadmodel->marksurfaces +
1811 LittleShort(in->firstmarksurface);
1812 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1814 p = LittleLong(in->visofs);
1816 out->compressed_vis = NULL;
1818 out->compressed_vis = loadmodel->visdata + p;
1820 for (j=0 ; j<4 ; j++)
1821 out->ambient_sound_level[j] = in->ambient_level[j];
1823 // FIXME: Insert caustics here
1832 static void Mod_LoadClipnodes (lump_t *l)
1834 dclipnode_t *in, *out;
1838 in = (void *)(mod_base + l->fileofs);
1839 if (l->filelen % sizeof(*in))
1840 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1841 count = l->filelen / sizeof(*in);
1842 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1844 loadmodel->clipnodes = out;
1845 loadmodel->numclipnodes = count;
1847 if (loadmodel->ishlbsp)
1849 hull = &loadmodel->hulls[1];
1850 hull->clipnodes = out;
1851 hull->firstclipnode = 0;
1852 hull->lastclipnode = count-1;
1853 hull->planes = loadmodel->planes;
1854 hull->clip_mins[0] = -16;
1855 hull->clip_mins[1] = -16;
1856 hull->clip_mins[2] = -36;
1857 hull->clip_maxs[0] = 16;
1858 hull->clip_maxs[1] = 16;
1859 hull->clip_maxs[2] = 36;
1860 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1862 hull = &loadmodel->hulls[2];
1863 hull->clipnodes = out;
1864 hull->firstclipnode = 0;
1865 hull->lastclipnode = count-1;
1866 hull->planes = loadmodel->planes;
1867 hull->clip_mins[0] = -32;
1868 hull->clip_mins[1] = -32;
1869 hull->clip_mins[2] = -32;
1870 hull->clip_maxs[0] = 32;
1871 hull->clip_maxs[1] = 32;
1872 hull->clip_maxs[2] = 32;
1873 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1875 hull = &loadmodel->hulls[3];
1876 hull->clipnodes = out;
1877 hull->firstclipnode = 0;
1878 hull->lastclipnode = count-1;
1879 hull->planes = loadmodel->planes;
1880 hull->clip_mins[0] = -16;
1881 hull->clip_mins[1] = -16;
1882 hull->clip_mins[2] = -18;
1883 hull->clip_maxs[0] = 16;
1884 hull->clip_maxs[1] = 16;
1885 hull->clip_maxs[2] = 18;
1886 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1890 hull = &loadmodel->hulls[1];
1891 hull->clipnodes = out;
1892 hull->firstclipnode = 0;
1893 hull->lastclipnode = count-1;
1894 hull->planes = loadmodel->planes;
1895 hull->clip_mins[0] = -16;
1896 hull->clip_mins[1] = -16;
1897 hull->clip_mins[2] = -24;
1898 hull->clip_maxs[0] = 16;
1899 hull->clip_maxs[1] = 16;
1900 hull->clip_maxs[2] = 32;
1901 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1903 hull = &loadmodel->hulls[2];
1904 hull->clipnodes = out;
1905 hull->firstclipnode = 0;
1906 hull->lastclipnode = count-1;
1907 hull->planes = loadmodel->planes;
1908 hull->clip_mins[0] = -32;
1909 hull->clip_mins[1] = -32;
1910 hull->clip_mins[2] = -24;
1911 hull->clip_maxs[0] = 32;
1912 hull->clip_maxs[1] = 32;
1913 hull->clip_maxs[2] = 64;
1914 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1917 for (i=0 ; i<count ; i++, out++, in++)
1919 out->planenum = LittleLong(in->planenum);
1920 out->children[0] = LittleShort(in->children[0]);
1921 out->children[1] = LittleShort(in->children[1]);
1922 if (out->children[0] >= count || out->children[1] >= count)
1923 Host_Error("Corrupt clipping hull (out of range child)\n");
1931 Duplicate the drawing hull structure as a clipping hull
1934 static void Mod_MakeHull0 (void)
1941 hull = &loadmodel->hulls[0];
1943 in = loadmodel->nodes;
1944 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1946 hull->clipnodes = out;
1947 hull->firstclipnode = 0;
1948 hull->lastclipnode = loadmodel->numnodes - 1;
1949 hull->planes = loadmodel->planes;
1951 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1953 out->planenum = in->plane - loadmodel->planes;
1954 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1955 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1961 Mod_LoadMarksurfaces
1964 static void Mod_LoadMarksurfaces (lump_t *l)
1969 in = (void *)(mod_base + l->fileofs);
1970 if (l->filelen % sizeof(*in))
1971 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1972 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1973 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1975 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1977 j = (unsigned) LittleShort(in[i]);
1978 if (j >= loadmodel->numsurfaces)
1979 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1980 loadmodel->marksurfaces[i] = j;
1989 static void Mod_LoadSurfedges (lump_t *l)
1994 in = (void *)(mod_base + l->fileofs);
1995 if (l->filelen % sizeof(*in))
1996 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1997 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1998 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
2000 for (i = 0;i < loadmodel->numsurfedges;i++)
2001 loadmodel->surfedges[i] = LittleLong (in[i]);
2010 static void Mod_LoadPlanes (lump_t *l)
2016 in = (void *)(mod_base + l->fileofs);
2017 if (l->filelen % sizeof(*in))
2018 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
2020 loadmodel->numplanes = l->filelen / sizeof(*in);
2021 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
2023 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
2025 out->normal[0] = LittleFloat (in->normal[0]);
2026 out->normal[1] = LittleFloat (in->normal[1]);
2027 out->normal[2] = LittleFloat (in->normal[2]);
2028 out->dist = LittleFloat (in->dist);
2034 #define MAX_POINTS_ON_WINDING 64
2040 double points[8][3]; // variable sized
2049 static winding_t *NewWinding (int points)
2054 if (points > MAX_POINTS_ON_WINDING)
2055 Sys_Error("NewWinding: too many points\n");
2057 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
2058 w = Mem_Alloc(loadmodel->mempool, size);
2059 memset (w, 0, size);
2064 static void FreeWinding (winding_t *w)
2074 static winding_t *BaseWindingForPlane (mplane_t *p)
2076 double org[3], vright[3], vup[3], normal[3];
2079 VectorCopy(p->normal, normal);
2080 VectorVectorsDouble(normal, vright, vup);
2082 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
2083 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
2085 // project a really big axis aligned box onto the plane
2088 VectorScale (p->normal, p->dist, org);
2090 VectorSubtract (org, vright, w->points[0]);
2091 VectorAdd (w->points[0], vup, w->points[0]);
2093 VectorAdd (org, vright, w->points[1]);
2094 VectorAdd (w->points[1], vup, w->points[1]);
2096 VectorAdd (org, vright, w->points[2]);
2097 VectorSubtract (w->points[2], vup, w->points[2]);
2099 VectorSubtract (org, vright, w->points[3]);
2100 VectorSubtract (w->points[3], vup, w->points[3]);
2111 Clips the winding to the plane, returning the new winding on the positive side
2112 Frees the input winding.
2113 If keepon is true, an exactly on-plane winding will be saved, otherwise
2114 it will be clipped away.
2117 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2119 double dists[MAX_POINTS_ON_WINDING + 1];
2120 int sides[MAX_POINTS_ON_WINDING + 1];
2129 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2131 // determine sides for each point
2132 for (i = 0;i < in->numpoints;i++)
2134 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2135 if (dot > ON_EPSILON)
2136 sides[i] = SIDE_FRONT;
2137 else if (dot < -ON_EPSILON)
2138 sides[i] = SIDE_BACK;
2143 sides[i] = sides[0];
2144 dists[i] = dists[0];
2146 if (keepon && !counts[0] && !counts[1])
2157 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2158 if (maxpts > MAX_POINTS_ON_WINDING)
2159 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2161 neww = NewWinding (maxpts);
2163 for (i = 0;i < in->numpoints;i++)
2165 if (neww->numpoints >= maxpts)
2166 Sys_Error ("ClipWinding: points exceeded estimate");
2170 if (sides[i] == SIDE_ON)
2172 VectorCopy (p1, neww->points[neww->numpoints]);
2177 if (sides[i] == SIDE_FRONT)
2179 VectorCopy (p1, neww->points[neww->numpoints]);
2183 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2186 // generate a split point
2187 p2 = in->points[(i+1)%in->numpoints];
2189 dot = dists[i] / (dists[i]-dists[i+1]);
2190 for (j = 0;j < 3;j++)
2191 { // avoid round off error when possible
2192 if (split->normal[j] == 1)
2193 mid[j] = split->dist;
2194 else if (split->normal[j] == -1)
2195 mid[j] = -split->dist;
2197 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2200 VectorCopy (mid, neww->points[neww->numpoints]);
2204 // free the original winding
2215 Divides a winding by a plane, producing one or two windings. The
2216 original winding is not damaged or freed. If only on one side, the
2217 returned winding will be the input winding. If on both sides, two
2218 new windings will be created.
2221 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2223 double dists[MAX_POINTS_ON_WINDING + 1];
2224 int sides[MAX_POINTS_ON_WINDING + 1];
2233 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2235 // determine sides for each point
2236 for (i = 0;i < in->numpoints;i++)
2238 dot = DotProduct (in->points[i], split->normal);
2241 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2242 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2243 else sides[i] = SIDE_ON;
2246 sides[i] = sides[0];
2247 dists[i] = dists[0];
2249 *front = *back = NULL;
2262 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2264 if (maxpts > MAX_POINTS_ON_WINDING)
2265 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2267 *front = f = NewWinding (maxpts);
2268 *back = b = NewWinding (maxpts);
2270 for (i = 0;i < in->numpoints;i++)
2272 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2273 Sys_Error ("DivideWinding: points exceeded estimate");
2277 if (sides[i] == SIDE_ON)
2279 VectorCopy (p1, f->points[f->numpoints]);
2281 VectorCopy (p1, b->points[b->numpoints]);
2286 if (sides[i] == SIDE_FRONT)
2288 VectorCopy (p1, f->points[f->numpoints]);
2291 else if (sides[i] == SIDE_BACK)
2293 VectorCopy (p1, b->points[b->numpoints]);
2297 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2300 // generate a split point
2301 p2 = in->points[(i+1)%in->numpoints];
2303 dot = dists[i] / (dists[i]-dists[i+1]);
2304 for (j = 0;j < 3;j++)
2305 { // avoid round off error when possible
2306 if (split->normal[j] == 1)
2307 mid[j] = split->dist;
2308 else if (split->normal[j] == -1)
2309 mid[j] = -split->dist;
2311 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2314 VectorCopy (mid, f->points[f->numpoints]);
2316 VectorCopy (mid, b->points[b->numpoints]);
2321 typedef struct portal_s
2324 mnode_t *nodes[2]; // [0] = front side of plane
2325 struct portal_s *next[2];
2327 struct portal_s *chain; // all portals are linked into a list
2331 static portal_t *portalchain;
2338 static portal_t *AllocPortal (void)
2341 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2342 p->chain = portalchain;
2347 static void FreePortal(portal_t *p)
2352 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2354 // calculate children first
2355 if (node->children[0]->contents >= 0)
2356 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2357 if (node->children[1]->contents >= 0)
2358 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2360 // make combined bounding box from children
2361 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2362 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2363 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2364 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2365 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2366 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2369 static void Mod_FinalizePortals(void)
2371 int i, j, numportals, numpoints;
2372 portal_t *p, *pnext;
2375 mleaf_t *leaf, *endleaf;
2378 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2379 leaf = loadmodel->leafs;
2380 endleaf = leaf + loadmodel->numleafs;
2381 for (;leaf < endleaf;leaf++)
2383 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2384 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2391 for (i = 0;i < 2;i++)
2393 leaf = (mleaf_t *)p->nodes[i];
2395 for (j = 0;j < w->numpoints;j++)
2397 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2398 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2399 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2400 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2401 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2402 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2409 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2411 // tally up portal and point counts
2417 // note: this check must match the one below or it will usually corrupt memory
2418 // 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
2419 if (p->winding && p->nodes[0] != p->nodes[1]
2420 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2421 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2424 numpoints += p->winding->numpoints * 2;
2428 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2429 loadmodel->numportals = numportals;
2430 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2431 loadmodel->numportalpoints = numpoints;
2432 // clear all leaf portal chains
2433 for (i = 0;i < loadmodel->numleafs;i++)
2434 loadmodel->leafs[i].portals = NULL;
2435 // process all portals in the global portal chain, while freeing them
2436 portal = loadmodel->portals;
2437 point = loadmodel->portalpoints;
2446 // note: this check must match the one above or it will usually corrupt memory
2447 // 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
2448 if (p->nodes[0] != p->nodes[1]
2449 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2450 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2452 // first make the back to front portal (forward portal)
2453 portal->points = point;
2454 portal->numpoints = p->winding->numpoints;
2455 portal->plane.dist = p->plane.dist;
2456 VectorCopy(p->plane.normal, portal->plane.normal);
2457 portal->here = (mleaf_t *)p->nodes[1];
2458 portal->past = (mleaf_t *)p->nodes[0];
2460 for (j = 0;j < portal->numpoints;j++)
2462 VectorCopy(p->winding->points[j], point->position);
2465 PlaneClassify(&portal->plane);
2467 // link into leaf's portal chain
2468 portal->next = portal->here->portals;
2469 portal->here->portals = portal;
2471 // advance to next portal
2474 // then make the front to back portal (backward portal)
2475 portal->points = point;
2476 portal->numpoints = p->winding->numpoints;
2477 portal->plane.dist = -p->plane.dist;
2478 VectorNegate(p->plane.normal, portal->plane.normal);
2479 portal->here = (mleaf_t *)p->nodes[0];
2480 portal->past = (mleaf_t *)p->nodes[1];
2482 for (j = portal->numpoints - 1;j >= 0;j--)
2484 VectorCopy(p->winding->points[j], point->position);
2487 PlaneClassify(&portal->plane);
2489 // link into leaf's portal chain
2490 portal->next = portal->here->portals;
2491 portal->here->portals = portal;
2493 // advance to next portal
2496 FreeWinding(p->winding);
2508 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2511 Host_Error ("AddPortalToNodes: NULL front node");
2513 Host_Error ("AddPortalToNodes: NULL back node");
2514 if (p->nodes[0] || p->nodes[1])
2515 Host_Error ("AddPortalToNodes: already included");
2516 // 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
2518 p->nodes[0] = front;
2519 p->next[0] = (portal_t *)front->portals;
2520 front->portals = (mportal_t *)p;
2523 p->next[1] = (portal_t *)back->portals;
2524 back->portals = (mportal_t *)p;
2529 RemovePortalFromNode
2532 static void RemovePortalFromNodes(portal_t *portal)
2536 void **portalpointer;
2538 for (i = 0;i < 2;i++)
2540 node = portal->nodes[i];
2542 portalpointer = (void **) &node->portals;
2547 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2551 if (portal->nodes[0] == node)
2553 *portalpointer = portal->next[0];
2554 portal->nodes[0] = NULL;
2556 else if (portal->nodes[1] == node)
2558 *portalpointer = portal->next[1];
2559 portal->nodes[1] = NULL;
2562 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2566 if (t->nodes[0] == node)
2567 portalpointer = (void **) &t->next[0];
2568 else if (t->nodes[1] == node)
2569 portalpointer = (void **) &t->next[1];
2571 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2576 static void Mod_RecursiveNodePortals (mnode_t *node)
2579 mnode_t *front, *back, *other_node;
2580 mplane_t clipplane, *plane;
2581 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2582 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2584 // if a leaf, we're done
2588 plane = node->plane;
2590 front = node->children[0];
2591 back = node->children[1];
2593 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2595 // create the new portal by generating a polygon for the node plane,
2596 // and clipping it by all of the other portals (which came from nodes above this one)
2597 nodeportal = AllocPortal ();
2598 nodeportal->plane = *node->plane;
2600 nodeportalwinding = BaseWindingForPlane (node->plane);
2601 side = 0; // shut up compiler warning
2602 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2604 clipplane = portal->plane;
2605 if (portal->nodes[0] == portal->nodes[1])
2606 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2607 if (portal->nodes[0] == node)
2609 else if (portal->nodes[1] == node)
2611 clipplane.dist = -clipplane.dist;
2612 VectorNegate (clipplane.normal, clipplane.normal);
2616 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2618 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2619 if (!nodeportalwinding)
2621 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2626 if (nodeportalwinding)
2628 // if the plane was not clipped on all sides, there was an error
2629 nodeportal->winding = nodeportalwinding;
2630 AddPortalToNodes (nodeportal, front, back);
2633 // split the portals of this node along this node's plane and assign them to the children of this node
2634 // (migrating the portals downward through the tree)
2635 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2637 if (portal->nodes[0] == portal->nodes[1])
2638 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2639 if (portal->nodes[0] == node)
2641 else if (portal->nodes[1] == node)
2644 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2645 nextportal = portal->next[side];
2647 other_node = portal->nodes[!side];
2648 RemovePortalFromNodes (portal);
2650 // cut the portal into two portals, one on each side of the node plane
2651 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2656 AddPortalToNodes (portal, back, other_node);
2658 AddPortalToNodes (portal, other_node, back);
2664 AddPortalToNodes (portal, front, other_node);
2666 AddPortalToNodes (portal, other_node, front);
2670 // the winding is split
2671 splitportal = AllocPortal ();
2672 temp = splitportal->chain;
2673 *splitportal = *portal;
2674 splitportal->chain = temp;
2675 splitportal->winding = backwinding;
2676 FreeWinding (portal->winding);
2677 portal->winding = frontwinding;
2681 AddPortalToNodes (portal, front, other_node);
2682 AddPortalToNodes (splitportal, back, other_node);
2686 AddPortalToNodes (portal, other_node, front);
2687 AddPortalToNodes (splitportal, other_node, back);
2691 Mod_RecursiveNodePortals(front);
2692 Mod_RecursiveNodePortals(back);
2696 static void Mod_MakePortals(void)
2699 Mod_RecursiveNodePortals (loadmodel->nodes);
2700 Mod_FinalizePortals();
2703 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2705 int surfnum, vertnum, snum, vnum;
2706 msurface_t *surf, *s;
2707 float *v0, *v1, *v2, *v3;
2708 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2710 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2711 for (vertnum = 0;vertnum < surf->poly_numverts;vertnum++)
2713 v0 = surf->poly_verts + ((vertnum + 1) % surf->poly_numverts) * 3;
2714 v1 = surf->poly_verts + vertnum * 3;
2715 surf->neighborsurfaces[vertnum] = NULL;
2716 for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2718 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2719 || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2720 || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2723 for (vnum = 0, v2 = s->poly_verts + (s->poly_numverts - 1) * 3, v3 = s->poly_verts;vnum < s->poly_numverts;vnum++, v2 = v3, v3 += 3)
2725 if (v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2727 surf->neighborsurfaces[vertnum] = s;
2731 if (vnum < s->poly_numverts)
2743 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2744 extern void R_Model_Brush_Draw(entity_render_t *ent);
2745 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2746 extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor);
2747 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2752 mempool_t *mainmempool;
2754 model_t *originalloadmodel;
2756 mod->type = mod_brush;
2758 header = (dheader_t *)buffer;
2760 i = LittleLong (header->version);
2761 if (i != BSPVERSION && i != 30)
2762 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2763 mod->ishlbsp = i == 30;
2764 if (loadmodel->isworldmodel)
2766 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2767 // until we get a texture for it...
2771 // swap all the lumps
2772 mod_base = (qbyte *)header;
2774 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
2775 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2779 // store which lightmap format to use
2780 mod->lightmaprgba = r_lightmaprgba.integer;
2782 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2783 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2784 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2785 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2786 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2787 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2788 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2789 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2790 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2791 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2792 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2793 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2794 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2795 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2796 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2801 mod->numframes = 2; // regular and alternate animation
2803 mainmempool = mod->mempool;
2804 loadname = mod->name;
2806 Mod_LoadLightList ();
2807 originalloadmodel = loadmodel;
2810 // set up the submodels (FIXME: this is confusing)
2812 for (i = 0;i < mod->numsubmodels;i++)
2815 float dist, modelyawradius, modelradius, *vec;
2818 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2819 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2823 bm = &mod->submodels[i];
2825 mod->hulls[0].firstclipnode = bm->headnode[0];
2826 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2828 mod->hulls[j].firstclipnode = bm->headnode[j];
2829 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2832 mod->firstmodelsurface = bm->firstface;
2833 mod->nummodelsurfaces = bm->numfaces;
2835 // this gets altered below if sky is used
2836 mod->DrawSky = NULL;
2837 mod->Draw = R_Model_Brush_Draw;
2838 mod->DrawFakeShadow = NULL;
2839 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2840 mod->DrawLight = R_Model_Brush_DrawLight;
2841 mod->texturesurfacechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t *));
2842 if (mod->nummodelsurfaces)
2844 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2845 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2847 // we only need to have a drawsky function if it is used (usually only on world model)
2848 if (surf->texinfo->texture->shader == &Cshader_sky)
2849 mod->DrawSky = R_Model_Brush_DrawSky;
2850 // link into texture chain
2851 surf->texturechain = mod->texturesurfacechains[surf->texinfo->texture - mod->textures];
2852 mod->texturesurfacechains[surf->texinfo->texture - mod->textures] = surf;
2853 // calculate bounding shapes
2854 for (k = 0;k < surf->numedges;k++)
2856 l = mod->surfedges[k + surf->firstedge];
2858 vec = mod->vertexes[mod->edges[l].v[0]].position;
2860 vec = mod->vertexes[mod->edges[-l].v[1]].position;
2861 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2862 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2863 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2864 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2865 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2866 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2867 dist = vec[0]*vec[0]+vec[1]*vec[1];
2868 if (modelyawradius < dist)
2869 modelyawradius = dist;
2870 dist += vec[2]*vec[2];
2871 if (modelradius < dist)
2875 modelyawradius = sqrt(modelyawradius);
2876 modelradius = sqrt(modelradius);
2877 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2878 mod->yawmins[2] = mod->normalmins[2];
2879 mod->yawmaxs[2] = mod->normalmaxs[2];
2880 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2881 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2882 mod->radius = modelradius;
2883 mod->radius2 = modelradius * modelradius;
2884 // LordHavoc: build triangle meshs for entire model's geometry
2885 // (only used for shadow volumes)
2886 mod->shadowmesh = Mod_ShadowMesh_Begin(originalloadmodel->mempool);
2887 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2888 if (surf->flags & SURF_SHADOWCAST)
2889 Mod_ShadowMesh_AddPolygon(originalloadmodel->mempool, mod->shadowmesh, surf->poly_numverts, surf->poly_verts);
2890 mod->shadowmesh = Mod_ShadowMesh_Finish(originalloadmodel->mempool, mod->shadowmesh);
2891 Mod_ShadowMesh_CalcBBox(mod->shadowmesh, mod->shadowmesh_mins, mod->shadowmesh_maxs, mod->shadowmesh_center, &mod->shadowmesh_radius);
2895 // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2896 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2897 VectorClear(mod->normalmins);
2898 VectorClear(mod->normalmaxs);
2899 VectorClear(mod->yawmins);
2900 VectorClear(mod->yawmaxs);
2901 VectorClear(mod->rotatedmins);
2902 VectorClear(mod->rotatedmaxs);
2905 mod->shadowmesh = NULL;
2907 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2909 mod->numleafs = bm->visleafs;
2911 // LordHavoc: only register submodels if it is the world
2912 // (prevents bsp models from replacing world submodels)
2913 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2916 // duplicate the basic information
2917 sprintf (name, "*%i", i+1);
2918 loadmodel = Mod_FindName (name);
2920 strcpy (loadmodel->name, name);
2921 // textures and memory belong to the main model
2922 loadmodel->texturepool = NULL;
2923 loadmodel->mempool = NULL;
2928 loadmodel = originalloadmodel;
2929 Mod_ProcessLightList ();