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++)
242 tx->texture = r_notexture;
243 tx->shader = &Cshader_wall_lightmap;
244 if (i == loadmodel->numtextures - 1)
246 tx->flags = SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
247 tx->shader = &Cshader_water;
249 tx->currentframe = tx;
252 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
254 // LordHavoc: mostly rewritten map texture loader
255 for (i = 0;i < m->nummiptex;i++)
257 dofs[i] = LittleLong(dofs[i]);
258 if (dofs[i] == -1 || r_nosurftextures.integer)
260 dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
262 // make sure name is no more than 15 characters
263 for (j = 0;dmiptex->name[j] && j < 15;j++)
264 name[j] = dmiptex->name[j];
267 mtwidth = LittleLong (dmiptex->width);
268 mtheight = LittleLong (dmiptex->height);
270 j = LittleLong (dmiptex->offsets[0]);
274 if (j < 40 || j + mtwidth * mtheight > l->filelen)
276 Con_Printf ("Texture \"%s\" in \"%s\"is corrupt or incomplete\n", dmiptex->name, loadmodel->name);
279 mtdata = (qbyte *)dmiptex + j;
282 if ((mtwidth & 15) || (mtheight & 15))
283 Con_Printf ("warning: texture \"%s\" in \"%s\" is not 16 aligned", dmiptex->name, loadmodel->name);
285 // LordHavoc: force all names to lowercase
286 for (j = 0;name[j];j++)
287 if (name[j] >= 'A' && name[j] <= 'Z')
288 name[j] += 'a' - 'A';
290 tx = loadmodel->textures + i;
291 strcpy(tx->name, name);
293 tx->height = mtheight;
297 sprintf(tx->name, "unnamed%i", i);
298 Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
301 basepixels = NULL;basepixels_width = 0;basepixels_height = 0;
302 bumppixels = NULL;bumppixels_width = 0;bumppixels_height = 0;
303 nmappixels = NULL;nmappixels_width = 0;nmappixels_height = 0;
304 glosspixels = NULL;glosspixels_width = 0;glosspixels_height = 0;
305 glowpixels = NULL;glowpixels_width = 0;glowpixels_height = 0;
306 maskpixels = NULL;maskpixels_width = 0;maskpixels_height = 0;
307 detailtexture = NULL;
309 // LordHavoc: HL sky textures are entirely different than quake
310 if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
312 if (loadmodel->isworldmodel)
314 data = loadimagepixels(tx->name, false, 0, 0);
317 if (image_width == 256 && image_height == 128)
325 Con_Printf ("Invalid replacement texture for sky \"%s\" in %\"%s\", must be 256x128 pixels\n", tx->name, loadmodel->name);
327 R_InitSky (mtdata, 1);
330 else if (mtdata != NULL)
331 R_InitSky (mtdata, 1);
336 if ((basepixels = loadimagepixels(tx->name, false, 0, 0)) != NULL)
338 basepixels_width = image_width;
339 basepixels_height = image_height;
341 // _luma is supported for tenebrae compatibility
342 // (I think it's a very stupid name, but oh well)
343 if ((glowpixels = loadimagepixels(va("%s_glow", tx->name), false, 0, 0)) != NULL
344 || (glowpixels = loadimagepixels(va("%s_luma", tx->name), false, 0, 0)) != NULL)
346 glowpixels_width = image_width;
347 glowpixels_height = image_height;
349 if ((bumppixels = loadimagepixels(va("%s_bump", tx->name), false, 0, 0)) != NULL)
351 bumppixels_width = image_width;
352 bumppixels_height = image_height;
354 if ((glosspixels = loadimagepixels(va("%s_gloss", tx->name), false, 0, 0)) != NULL)
356 glosspixels_width = image_width;
357 glosspixels_height = image_height;
361 if (loadmodel->ishlbsp)
363 // internal texture overrides wad
364 if (mtdata && (basepixels = W_ConvertWAD3Texture(dmiptex)) != NULL)
366 basepixels_width = image_width;
367 basepixels_height = image_height;
369 else if ((basepixels = W_GetTexture(tx->name)) != NULL)
371 // get the size from the wad texture
372 tx->width = basepixels_width = image_width;
373 tx->height = basepixels_height = image_height;
378 if (mtdata) // texture included
380 if (r_fullbrights.integer && tx->name[0] != '*')
382 basepixels_width = tx->width;
383 basepixels_height = tx->height;
384 basepixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
385 Image_Copy8bitRGBA(mtdata, basepixels, basepixels_width * basepixels_height, palette_nofullbrights);
388 for (j = 0;j < (int)(tx->width*tx->height);j++)
389 if (((qbyte *)&palette_onlyfullbrights[mtdata[j]])[3] > 0) // fullbright
391 if (j < (int)(tx->width * tx->height))
393 glowpixels_width = tx->width;
394 glowpixels_height = tx->height;
395 glowpixels = Mem_Alloc(loadmodel->mempool, glowpixels_width * glowpixels_height * 4);
396 Image_Copy8bitRGBA(mtdata, glowpixels, glowpixels_width * glowpixels_height, palette_onlyfullbrights);
402 basepixels_width = tx->width;
403 basepixels_height = tx->height;
404 basepixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
405 Image_Copy8bitRGBA(mtdata, basepixels, tx->width * tx->height, palette_complete);
414 for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4)
415 if (basepixels[j] < 255)
417 if (j < basepixels_width * basepixels_height * 4)
419 maskpixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
420 maskpixels_width = basepixels_width;
421 maskpixels_height = basepixels_height;
422 for (j = 0;j < basepixels_width * basepixels_height * 4;j += 4)
424 maskpixels[j+0] = 255;
425 maskpixels[j+1] = 255;
426 maskpixels[j+2] = 255;
427 maskpixels[j+3] = basepixels[j+3];
433 bumppixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4);
434 bumppixels_width = basepixels_width;
435 bumppixels_height = basepixels_height;
436 memcpy(bumppixels, basepixels, bumppixels_width * bumppixels_height * 4);
439 if (!nmappixels && bumppixels)
441 nmappixels = Mem_Alloc(loadmodel->mempool, bumppixels_width * bumppixels_height * 4);
442 nmappixels_width = bumppixels_width;
443 nmappixels_height = bumppixels_height;
444 Image_HeightmapToNormalmap(bumppixels, nmappixels, nmappixels_width, nmappixels_height, false, 1);
449 detailtexture = detailtextures[i % NUM_DETAILTEXTURES];
453 tx->texture = R_LoadTexture2D (loadmodel->texturepool, tx->name, basepixels_width, basepixels_height, basepixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
455 tx->nmaptexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_nmap", tx->name), basepixels_width, basepixels_height, nmappixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
457 tx->glosstexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_gloss", tx->name), glosspixels_width, glosspixels_height, glosspixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
459 tx->glowtexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_glow", tx->name), glowpixels_width, glowpixels_height, glowpixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
461 tx->fogtexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_mask", tx->name), maskpixels_width, maskpixels_height, maskpixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
462 tx->detailtexture = detailtexture;
469 tx->texture = r_notexture;
470 tx->nmaptexture = NULL;
471 tx->glosstexture = NULL;
472 tx->glowtexture = NULL;
473 tx->fogtexture = NULL;
474 tx->detailtexture = NULL;
478 Mem_Free(basepixels);
480 Mem_Free(bumppixels);
482 Mem_Free(nmappixels);
484 Mem_Free(glosspixels);
486 Mem_Free(glowpixels);
488 Mem_Free(maskpixels);
490 if (tx->name[0] == '*')
492 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
493 // LordHavoc: some turbulent textures should be fullbright and solid
494 if (!strncmp(tx->name,"*lava",5)
495 || !strncmp(tx->name,"*teleport",9)
496 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
497 tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
499 tx->flags |= SURF_WATERALPHA;
500 tx->shader = &Cshader_water;
502 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
504 tx->flags |= SURF_DRAWSKY;
505 tx->shader = &Cshader_sky;
509 tx->flags |= SURF_LIGHTMAP;
511 tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT;
512 tx->shader = &Cshader_wall_lightmap;
515 // start out with no animation
516 tx->currentframe = tx;
519 // sequence the animations
520 for (i = 0;i < m->nummiptex;i++)
522 tx = loadmodel->textures + i;
523 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
525 if (tx->anim_total[0] || tx->anim_total[1])
526 continue; // already sequenced
528 // find the number of frames in the animation
529 memset (anims, 0, sizeof(anims));
530 memset (altanims, 0, sizeof(altanims));
532 for (j = i;j < m->nummiptex;j++)
534 tx2 = loadmodel->textures + j;
535 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
539 if (num >= '0' && num <= '9')
540 anims[num - '0'] = tx2;
541 else if (num >= 'a' && num <= 'j')
542 altanims[num - 'a'] = tx2;
544 Con_Printf ("Bad animating texture %s\n", tx->name);
548 for (j = 0;j < 10;j++)
555 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
558 for (j = 0;j < max;j++)
562 Con_Printf ("Missing frame %i of %s\n", j, tx->name);
566 for (j = 0;j < altmax;j++)
570 Con_Printf ("Missing altframe %i of %s\n", j, tx->name);
579 // if there is no alternate animation, duplicate the primary
580 // animation into the alternate
582 for (k = 0;k < 10;k++)
583 altanims[k] = anims[k];
586 // link together the primary animation
587 for (j = 0;j < max;j++)
590 tx2->animated = true;
591 tx2->anim_total[0] = max;
592 tx2->anim_total[1] = altmax;
593 for (k = 0;k < 10;k++)
595 tx2->anim_frames[0][k] = anims[k];
596 tx2->anim_frames[1][k] = altanims[k];
600 // if there really is an alternate anim...
601 if (anims[0] != altanims[0])
603 // link together the alternate animation
604 for (j = 0;j < altmax;j++)
607 tx2->animated = true;
608 // the primary/alternate are reversed here
609 tx2->anim_total[0] = altmax;
610 tx2->anim_total[1] = max;
611 for (k = 0;k < 10;k++)
613 tx2->anim_frames[0][k] = altanims[k];
614 tx2->anim_frames[1][k] = anims[k];
626 static void Mod_LoadLighting (lump_t *l)
629 qbyte *in, *out, *data, d;
630 char litfilename[1024];
631 loadmodel->lightdata = NULL;
632 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
634 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
635 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
637 else // LordHavoc: bsp version 29 (normal white lighting)
639 // LordHavoc: hope is not lost yet, check for a .lit file to load
640 strcpy(litfilename, loadmodel->name);
641 COM_StripExtension(litfilename, litfilename);
642 strcat(litfilename, ".lit");
643 data = (qbyte*) COM_LoadFile (litfilename, false);
646 if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
648 i = LittleLong(((int *)data)[1]);
651 Con_DPrintf("%s loaded", litfilename);
652 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
653 memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
659 Con_Printf("Unknown .lit file version (%d)\n", i);
666 Con_Printf("Empty .lit file, ignoring\n");
668 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
672 // LordHavoc: oh well, expand the white lighting data
675 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
676 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
677 out = loadmodel->lightdata;
678 memcpy (in, mod_base + l->fileofs, l->filelen);
679 for (i = 0;i < l->filelen;i++)
689 void Mod_LoadLightList(void)
692 char lightsfilename[1024], *s, *t, *lightsstring;
695 strcpy(lightsfilename, loadmodel->name);
696 COM_StripExtension(lightsfilename, lightsfilename);
697 strcat(lightsfilename, ".lights");
698 s = lightsstring = (char *) COM_LoadFile (lightsfilename, false);
704 while (*s && *s != '\n')
708 Mem_Free(lightsstring);
709 Host_Error("lights file must end with a newline\n");
714 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
717 while (*s && n < numlights)
720 while (*s && *s != '\n')
724 Mem_Free(lightsstring);
725 Host_Error("misparsed lights file!\n");
727 e = loadmodel->lights + n;
729 a = sscanf(t, "%f %f %f %f %f %f %f %f %f %f %f %f %f %d", &e->origin[0], &e->origin[1], &e->origin[2], &e->falloff, &e->light[0], &e->light[1], &e->light[2], &e->subtract, &e->spotdir[0], &e->spotdir[1], &e->spotdir[2], &e->spotcone, &e->distbias, &e->style);
733 Mem_Free(lightsstring);
734 Host_Error("invalid lights file, found %d parameters on line %i, should be 14 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone distancebias style)\n", a, n + 1);
741 Mem_Free(lightsstring);
742 Host_Error("misparsed lights file!\n");
744 loadmodel->numlights = numlights;
745 Mem_Free(lightsstring);
750 static int castshadowcount = 0;
751 void Mod_ProcessLightList(void)
753 int j, k, l, *mark, lnum;
761 for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++)
763 e->cullradius2 = DotProduct(e->light, e->light) / (e->falloff * e->falloff * 8192.0f * 8192.0f * 2.0f * 2.0f);// + 4096.0f;
764 if (e->cullradius2 > 4096.0f * 4096.0f)
765 e->cullradius2 = 4096.0f * 4096.0f;
766 e->cullradius = e->lightradius = sqrt(e->cullradius2);
767 leaf = Mod_PointInLeaf(e->origin, loadmodel);
768 if (leaf->compressed_vis)
769 pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel);
772 for (j = 0;j < loadmodel->numsurfaces;j++)
773 loadmodel->surfacevisframes[j] = -1;
774 for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++)
776 if (pvs[j >> 3] & (1 << (j & 7)))
778 for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++)
780 surf = loadmodel->surfaces + *mark;
781 if (surf->number != *mark)
782 Con_Printf("%d != %d\n", surf->number, *mark);
783 dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
784 if (surf->flags & SURF_PLANEBACK)
786 if (dist > 0 && dist < e->cullradius)
788 temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
789 temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
790 temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
791 if (DotProduct(temp, temp) < lightradius2)
792 loadmodel->surfacevisframes[*mark] = -2;
797 // build list of light receiving surfaces
799 for (j = 0;j < loadmodel->numsurfaces;j++)
800 if (loadmodel->surfacevisframes[j] == -2)
803 if (e->numsurfaces > 0)
805 e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
807 for (j = 0;j < loadmodel->numsurfaces;j++)
808 if (loadmodel->surfacevisframes[j] == -2)
809 e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j;
811 // find bounding box and sphere of lit surfaces
812 // (these will be used for creating a shape to clip the light)
814 for (j = 0;j < e->numsurfaces;j++)
816 surf = e->surfaces[j];
819 VectorCopy(surf->poly_verts, e->mins);
820 VectorCopy(surf->poly_verts, e->maxs);
822 for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
824 if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
825 if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
826 if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
827 VectorSubtract(v, e->origin, temp);
828 dist = DotProduct(temp, temp);
833 if (e->cullradius2 > radius2)
835 e->cullradius2 = radius2;
836 e->cullradius = sqrt(e->cullradius2);
838 if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
839 if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
840 if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
841 if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
842 if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
843 if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
844 // clip shadow volumes against eachother to remove unnecessary
845 // polygons (and sections of polygons)
847 //vec3_t polymins, polymaxs;
849 float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
850 float f, *v0, *v1, projectdistance;
852 e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024);
855 vec3_t outermins, outermaxs, innermins, innermaxs;
856 innermins[0] = e->mins[0] - 1;
857 innermins[1] = e->mins[1] - 1;
858 innermins[2] = e->mins[2] - 1;
859 innermaxs[0] = e->maxs[0] + 1;
860 innermaxs[1] = e->maxs[1] + 1;
861 innermaxs[2] = e->maxs[2] + 1;
862 outermins[0] = loadmodel->normalmins[0] - 1;
863 outermins[1] = loadmodel->normalmins[1] - 1;
864 outermins[2] = loadmodel->normalmins[2] - 1;
865 outermaxs[0] = loadmodel->normalmaxs[0] + 1;
866 outermaxs[1] = loadmodel->normalmaxs[1] + 1;
867 outermaxs[2] = loadmodel->normalmaxs[2] + 1;
868 // add bounding box around the whole shadow volume set,
869 // facing inward to limit light area, with an outer bounding box
870 // facing outward (this is needed by the shadow rendering method)
872 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
873 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
874 verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
875 verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
876 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
877 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
878 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
879 verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
880 verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
881 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
883 verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
884 verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
885 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
886 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
887 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
888 verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
889 verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
890 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
891 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
892 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
894 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
895 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
896 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
897 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
898 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
899 verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
900 verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
901 verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
902 verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
903 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
905 verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
906 verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
907 verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
908 verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
909 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
910 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
911 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
912 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
913 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
914 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
916 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
917 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2];
918 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2];
919 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
920 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
921 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
922 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2];
923 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2];
924 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
925 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
927 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2];
928 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
929 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
930 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2];
931 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
932 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2];
933 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
934 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
935 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2];
936 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
940 for (j = 0;j < e->numsurfaces;j++)
942 surf = e->surfaces[j];
943 if (surf->flags & SURF_SHADOWCAST)
944 surf->castshadow = castshadowcount;
946 for (j = 0;j < e->numsurfaces;j++)
948 surf = e->surfaces[j];
949 if (surf->castshadow != castshadowcount)
951 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
952 if (surf->flags & SURF_PLANEBACK)
954 projectdistance = e->lightradius;
955 if (maxverts < surf->poly_numverts)
957 maxverts = surf->poly_numverts;
960 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
962 // copy the original polygon, for the front cap of the volume
963 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
965 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
966 // project the original polygon, reversed, for the back cap of the volume
967 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
969 VectorSubtract(v0, e->origin, temp);
970 VectorNormalize(temp);
971 VectorMA(v0, projectdistance, temp, v1);
973 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
974 // project the shadow volume sides
975 for (l = surf->poly_numverts - 1, k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;l = k, k++, v0 = v1, v1 += 3)
977 if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount)
979 VectorCopy(v1, &verts[0]);
980 VectorCopy(v0, &verts[3]);
981 VectorCopy(v0, &verts[6]);
982 VectorCopy(v1, &verts[9]);
983 VectorSubtract(&verts[6], e->origin, temp);
984 VectorNormalize(temp);
985 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
986 VectorSubtract(&verts[9], e->origin, temp);
987 VectorNormalize(temp);
988 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
989 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
993 // build the triangle mesh
994 e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume);
998 for (mesh = e->shadowvolume;mesh;mesh = mesh->next)
999 l += mesh->numtriangles;
1000 Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l);
1013 static void Mod_LoadVisibility (lump_t *l)
1015 loadmodel->visdata = NULL;
1018 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
1019 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
1022 // used only for HalfLife maps
1023 void Mod_ParseWadsFromEntityLump(const char *data)
1025 char key[128], value[4096];
1030 if (!COM_ParseToken(&data))
1032 if (com_token[0] != '{')
1036 if (!COM_ParseToken(&data))
1038 if (com_token[0] == '}')
1039 break; // end of worldspawn
1040 if (com_token[0] == '_')
1041 strcpy(key, com_token + 1);
1043 strcpy(key, com_token);
1044 while (key[strlen(key)-1] == ' ') // remove trailing spaces
1045 key[strlen(key)-1] = 0;
1046 if (!COM_ParseToken(&data))
1048 strcpy(value, com_token);
1049 if (!strcmp("wad", key)) // for HalfLife maps
1051 if (loadmodel->ishlbsp)
1054 for (i = 0;i < 4096;i++)
1055 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
1061 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
1062 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
1064 else if (value[i] == ';' || value[i] == 0)
1068 strcpy(wadname, "textures/");
1069 strcat(wadname, &value[j]);
1070 W_LoadTextureWadFile (wadname, false);
1087 static void Mod_LoadEntities (lump_t *l)
1089 loadmodel->entities = NULL;
1092 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
1093 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
1094 if (loadmodel->ishlbsp)
1095 Mod_ParseWadsFromEntityLump(loadmodel->entities);
1104 static void Mod_LoadVertexes (lump_t *l)
1110 in = (void *)(mod_base + l->fileofs);
1111 if (l->filelen % sizeof(*in))
1112 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1113 count = l->filelen / sizeof(*in);
1114 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1116 loadmodel->vertexes = out;
1117 loadmodel->numvertexes = count;
1119 for ( i=0 ; i<count ; i++, in++, out++)
1121 out->position[0] = LittleFloat (in->point[0]);
1122 out->position[1] = LittleFloat (in->point[1]);
1123 out->position[2] = LittleFloat (in->point[2]);
1132 static void Mod_LoadSubmodels (lump_t *l)
1138 in = (void *)(mod_base + l->fileofs);
1139 if (l->filelen % sizeof(*in))
1140 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1141 count = l->filelen / sizeof(*in);
1142 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1144 loadmodel->submodels = out;
1145 loadmodel->numsubmodels = count;
1147 for ( i=0 ; i<count ; i++, in++, out++)
1149 for (j=0 ; j<3 ; j++)
1151 // spread the mins / maxs by a pixel
1152 out->mins[j] = LittleFloat (in->mins[j]) - 1;
1153 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
1154 out->origin[j] = LittleFloat (in->origin[j]);
1156 for (j=0 ; j<MAX_MAP_HULLS ; j++)
1157 out->headnode[j] = LittleLong (in->headnode[j]);
1158 out->visleafs = LittleLong (in->visleafs);
1159 out->firstface = LittleLong (in->firstface);
1160 out->numfaces = LittleLong (in->numfaces);
1169 static void Mod_LoadEdges (lump_t *l)
1175 in = (void *)(mod_base + l->fileofs);
1176 if (l->filelen % sizeof(*in))
1177 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1178 count = l->filelen / sizeof(*in);
1179 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1181 loadmodel->edges = out;
1182 loadmodel->numedges = count;
1184 for ( i=0 ; i<count ; i++, in++, out++)
1186 out->v[0] = (unsigned short)LittleShort(in->v[0]);
1187 out->v[1] = (unsigned short)LittleShort(in->v[1]);
1196 static void Mod_LoadTexinfo (lump_t *l)
1200 int i, j, k, count, miptex;
1202 in = (void *)(mod_base + l->fileofs);
1203 if (l->filelen % sizeof(*in))
1204 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1205 count = l->filelen / sizeof(*in);
1206 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1208 loadmodel->texinfo = out;
1209 loadmodel->numtexinfo = count;
1211 for (i = 0;i < count;i++, in++, out++)
1213 for (k = 0;k < 2;k++)
1214 for (j = 0;j < 4;j++)
1215 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
1217 miptex = LittleLong (in->miptex);
1218 out->flags = LittleLong (in->flags);
1220 out->texture = NULL;
1221 if (loadmodel->textures)
1223 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
1224 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
1226 out->texture = loadmodel->textures + miptex;
1228 if (out->flags & TEX_SPECIAL)
1230 // if texture chosen is NULL or the shader needs a lightmap,
1231 // force to notexture water shader
1232 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
1233 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
1237 // if texture chosen is NULL, force to notexture
1238 if (out->texture == NULL)
1239 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
1244 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1249 mins[0] = mins[1] = mins[2] = 9999;
1250 maxs[0] = maxs[1] = maxs[2] = -9999;
1252 for (i = 0;i < numverts;i++)
1254 for (j = 0;j < 3;j++, v++)
1265 #define MAX_SUBDIVPOLYTRIANGLES 4096
1266 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1268 static int subdivpolyverts, subdivpolytriangles;
1269 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1270 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1272 static int subdivpolylookupvert(vec3_t v)
1275 for (i = 0;i < subdivpolyverts;i++)
1276 if (subdivpolyvert[i][0] == v[0]
1277 && subdivpolyvert[i][1] == v[1]
1278 && subdivpolyvert[i][2] == v[2])
1280 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1281 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1282 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1283 return subdivpolyverts++;
1286 static void SubdividePolygon (int numverts, float *verts)
1288 int i, i1, i2, i3, f, b, c, p;
1289 vec3_t mins, maxs, front[256], back[256];
1290 float m, *pv, *cv, dist[256], frac;
1293 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1295 BoundPoly (numverts, verts, mins, maxs);
1297 for (i = 0;i < 3;i++)
1299 m = (mins[i] + maxs[i]) * 0.5;
1300 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1301 if (maxs[i] - m < 8)
1303 if (m - mins[i] < 8)
1307 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1308 dist[c] = cv[i] - m;
1311 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1315 VectorCopy (pv, front[f]);
1320 VectorCopy (pv, back[b]);
1323 if (dist[p] == 0 || dist[c] == 0)
1325 if ( (dist[p] > 0) != (dist[c] > 0) )
1328 frac = dist[p] / (dist[p] - dist[c]);
1329 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1330 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1331 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1337 SubdividePolygon (f, front[0]);
1338 SubdividePolygon (b, back[0]);
1342 i1 = subdivpolylookupvert(verts);
1343 i2 = subdivpolylookupvert(verts + 3);
1344 for (i = 2;i < numverts;i++)
1346 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1348 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1352 i3 = subdivpolylookupvert(verts + i * 3);
1353 subdivpolyindex[subdivpolytriangles][0] = i1;
1354 subdivpolyindex[subdivpolytriangles][1] = i2;
1355 subdivpolyindex[subdivpolytriangles][2] = i3;
1357 subdivpolytriangles++;
1363 Mod_GenerateWarpMesh
1365 Breaks a polygon up along axial 64 unit
1366 boundaries so that turbulent and sky warps
1367 can be done reasonably.
1370 void Mod_GenerateWarpMesh (msurface_t *surf)
1376 subdivpolytriangles = 0;
1377 subdivpolyverts = 0;
1378 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1379 if (subdivpolytriangles < 1)
1380 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1382 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1383 mesh->numverts = subdivpolyverts;
1384 mesh->numtriangles = subdivpolytriangles;
1385 mesh->vertex = (surfvertex_t *)(mesh + 1);
1386 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1387 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1389 for (i = 0;i < mesh->numtriangles;i++)
1390 for (j = 0;j < 3;j++)
1391 mesh->index[i*3+j] = subdivpolyindex[i][j];
1393 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1395 VectorCopy(subdivpolyvert[i], v->v);
1396 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1397 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1402 surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles)
1405 mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (4 + 4 + 4 + 4 + 4 + 4 + 4 + 1) * sizeof(float));
1406 mesh->numverts = numverts;
1407 mesh->numtriangles = numtriangles;
1408 mesh->verts = (float *)(mesh + 1);
1409 mesh->str = mesh->verts + mesh->numverts * 4;
1410 mesh->uvw = mesh->str + mesh->numverts * 4;
1411 mesh->abc = mesh->uvw + mesh->numverts * 4;
1412 mesh->svectors = (float *)(mesh->abc + mesh->numverts * 4);
1413 mesh->tvectors = mesh->svectors + mesh->numverts * 4;
1414 mesh->normals = mesh->tvectors + mesh->numverts * 4;
1415 mesh->lightmapoffsets = (int *)(mesh->normals + mesh->numverts * 4);
1416 mesh->index = mesh->lightmapoffsets + mesh->numverts;
1417 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
1421 void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
1423 int i, iu, iv, *index, smax, tmax;
1424 float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
1427 smax = surf->extents[0] >> 4;
1428 tmax = surf->extents[1] >> 4;
1432 surf->lightmaptexturestride = 0;
1433 surf->lightmaptexture = NULL;
1441 surf->flags |= SURF_LIGHTMAP;
1442 if (r_miplightmaps.integer)
1444 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1445 surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_PRECACHE, NULL);
1449 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1450 surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE, NULL);
1452 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1453 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1454 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1457 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1459 index = mesh->index;
1460 for (i = 0;i < mesh->numtriangles;i++)
1466 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1468 VectorCopy(surf->plane->normal, normal);
1469 if (surf->flags & SURF_PLANEBACK)
1470 VectorNegate(normal, normal);
1471 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1473 s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1474 t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1475 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1476 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1477 // LordHavoc: calc lightmap data offset for vertex lighting to use
1480 iu = bound(0, iu, smax);
1481 iv = bound(0, iv, tmax);
1482 u = u * uscale + ubase;
1483 v = v * vscale + vbase;
1485 mesh->verts[i * 4 + 0] = in[0];
1486 mesh->verts[i * 4 + 1] = in[1];
1487 mesh->verts[i * 4 + 2] = in[2];
1488 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1489 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1490 mesh->uvw[i * 4 + 0] = u;
1491 mesh->uvw[i * 4 + 1] = v;
1492 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1493 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1494 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
1496 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1499 void Mod_GenerateVertexMesh (msurface_t *surf)
1502 float *in, s, t, normal[3];
1505 surf->lightmaptexturestride = 0;
1506 surf->lightmaptexture = NULL;
1508 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1510 index = mesh->index;
1511 for (i = 0;i < mesh->numtriangles;i++)
1517 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1519 VectorCopy(surf->plane->normal, normal);
1520 if (surf->flags & SURF_PLANEBACK)
1521 VectorNegate(normal, normal);
1522 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1524 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
1525 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
1526 mesh->verts[i * 4 + 0] = in[0];
1527 mesh->verts[i * 4 + 1] = in[1];
1528 mesh->verts[i * 4 + 2] = in[2];
1529 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1530 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1531 mesh->uvw[i * 4 + 0] = 0;
1532 mesh->uvw[i * 4 + 1] = 0;
1533 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1534 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1536 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1539 void Mod_GenerateSurfacePolygon (msurface_t *surf, int firstedge, int numedges)
1542 float *vec, *vert, mins[3], maxs[3], val, *v;
1545 // convert edges back to a normal polygon
1546 surf->poly_numverts = numedges;
1547 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * numedges);
1548 for (i = 0;i < numedges;i++)
1550 lindex = loadmodel->surfedges[firstedge + i];
1552 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1554 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1555 VectorCopy (vec, vert);
1559 // calculate polygon bounding box and center
1560 vert = surf->poly_verts;
1561 VectorCopy(vert, mins);
1562 VectorCopy(vert, maxs);
1564 for (i = 1;i < surf->poly_numverts;i++, vert += 3)
1566 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1567 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1568 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1570 VectorCopy(mins, surf->poly_mins);
1571 VectorCopy(maxs, surf->poly_maxs);
1572 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1573 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1574 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1576 // generate surface extents information
1577 tex = surf->texinfo;
1578 mins[0] = maxs[0] = DotProduct(surf->poly_verts, tex->vecs[0]) + tex->vecs[0][3];
1579 mins[1] = maxs[1] = DotProduct(surf->poly_verts, tex->vecs[1]) + tex->vecs[1][3];
1580 for (i = 1, v = surf->poly_verts + 3;i < surf->poly_numverts;i++, v += 3)
1582 for (j = 0;j < 2;j++)
1584 val = DotProduct(v, tex->vecs[j]) + tex->vecs[j][3];
1591 for (i = 0;i < 2;i++)
1593 surf->texturemins[i] = (int) floor(mins[i] / 16) * 16;
1594 surf->extents[i] = (int) ceil(maxs[i] / 16) * 16 - surf->texturemins[i];
1603 static void Mod_LoadFaces (lump_t *l)
1607 int i, count, surfnum, planenum, ssize, tsize, firstedge, numedges;
1609 in = (void *)(mod_base + l->fileofs);
1610 if (l->filelen % sizeof(*in))
1611 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1612 count = l->filelen / sizeof(*in);
1613 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1615 loadmodel->surfaces = out;
1616 loadmodel->numsurfaces = count;
1617 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1618 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1619 loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1621 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1623 out->number = surfnum;
1624 // FIXME: validate edges, texinfo, etc?
1625 firstedge = LittleLong(in->firstedge);
1626 numedges = LittleShort(in->numedges);
1627 if ((unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->numsurfedges)
1628 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->numsurfedges);
1630 i = LittleShort (in->texinfo);
1631 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1632 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1633 out->texinfo = loadmodel->texinfo + i;
1634 out->flags = out->texinfo->texture->flags;
1636 planenum = LittleShort(in->planenum);
1637 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1638 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1640 if (LittleShort(in->side))
1641 out->flags |= SURF_PLANEBACK;
1643 out->plane = loadmodel->planes + planenum;
1645 // clear lightmap (filled in later)
1646 out->lightmaptexture = NULL;
1648 // force lightmap upload on first time seeing the surface
1649 out->cached_dlight = true;
1651 Mod_GenerateSurfacePolygon(out, firstedge, numedges);
1653 ssize = (out->extents[0] >> 4) + 1;
1654 tsize = (out->extents[1] >> 4) + 1;
1657 for (i = 0;i < MAXLIGHTMAPS;i++)
1658 out->styles[i] = in->styles[i];
1659 i = LittleLong(in->lightofs);
1661 out->samples = NULL;
1662 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1663 out->samples = loadmodel->lightdata + i;
1664 else // LordHavoc: white lighting (bsp version 29)
1665 out->samples = loadmodel->lightdata + (i * 3);
1667 if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
1669 if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
1670 Host_Error ("Bad surface extents");
1671 Mod_GenerateWallMesh (out, false);
1672 // stainmap for permanent marks on walls
1673 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1675 memset(out->stainsamples, 255, ssize * tsize * 3);
1678 Mod_GenerateVertexMesh (out);
1687 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1689 node->parent = parent;
1690 if (node->contents < 0)
1692 Mod_SetParent (node->children[0], node);
1693 Mod_SetParent (node->children[1], node);
1701 static void Mod_LoadNodes (lump_t *l)
1707 in = (void *)(mod_base + l->fileofs);
1708 if (l->filelen % sizeof(*in))
1709 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1710 count = l->filelen / sizeof(*in);
1711 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1713 loadmodel->nodes = out;
1714 loadmodel->numnodes = count;
1716 for ( i=0 ; i<count ; i++, in++, out++)
1718 for (j=0 ; j<3 ; j++)
1720 out->mins[j] = LittleShort (in->mins[j]);
1721 out->maxs[j] = LittleShort (in->maxs[j]);
1724 p = LittleLong(in->planenum);
1725 out->plane = loadmodel->planes + p;
1727 out->firstsurface = LittleShort (in->firstface);
1728 out->numsurfaces = LittleShort (in->numfaces);
1730 for (j=0 ; j<2 ; j++)
1732 p = LittleShort (in->children[j]);
1734 out->children[j] = loadmodel->nodes + p;
1736 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1740 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1748 static void Mod_LoadLeafs (lump_t *l)
1754 in = (void *)(mod_base + l->fileofs);
1755 if (l->filelen % sizeof(*in))
1756 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1757 count = l->filelen / sizeof(*in);
1758 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1760 loadmodel->leafs = out;
1761 loadmodel->numleafs = count;
1763 for ( i=0 ; i<count ; i++, in++, out++)
1765 for (j=0 ; j<3 ; j++)
1767 out->mins[j] = LittleShort (in->mins[j]);
1768 out->maxs[j] = LittleShort (in->maxs[j]);
1771 p = LittleLong(in->contents);
1774 out->firstmarksurface = loadmodel->marksurfaces +
1775 LittleShort(in->firstmarksurface);
1776 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1778 p = LittleLong(in->visofs);
1780 out->compressed_vis = NULL;
1782 out->compressed_vis = loadmodel->visdata + p;
1784 for (j=0 ; j<4 ; j++)
1785 out->ambient_sound_level[j] = in->ambient_level[j];
1787 // FIXME: Insert caustics here
1796 static void Mod_LoadClipnodes (lump_t *l)
1798 dclipnode_t *in, *out;
1802 in = (void *)(mod_base + l->fileofs);
1803 if (l->filelen % sizeof(*in))
1804 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1805 count = l->filelen / sizeof(*in);
1806 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1808 loadmodel->clipnodes = out;
1809 loadmodel->numclipnodes = count;
1811 if (loadmodel->ishlbsp)
1813 hull = &loadmodel->hulls[1];
1814 hull->clipnodes = out;
1815 hull->firstclipnode = 0;
1816 hull->lastclipnode = count-1;
1817 hull->planes = loadmodel->planes;
1818 hull->clip_mins[0] = -16;
1819 hull->clip_mins[1] = -16;
1820 hull->clip_mins[2] = -36;
1821 hull->clip_maxs[0] = 16;
1822 hull->clip_maxs[1] = 16;
1823 hull->clip_maxs[2] = 36;
1824 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1826 hull = &loadmodel->hulls[2];
1827 hull->clipnodes = out;
1828 hull->firstclipnode = 0;
1829 hull->lastclipnode = count-1;
1830 hull->planes = loadmodel->planes;
1831 hull->clip_mins[0] = -32;
1832 hull->clip_mins[1] = -32;
1833 hull->clip_mins[2] = -32;
1834 hull->clip_maxs[0] = 32;
1835 hull->clip_maxs[1] = 32;
1836 hull->clip_maxs[2] = 32;
1837 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1839 hull = &loadmodel->hulls[3];
1840 hull->clipnodes = out;
1841 hull->firstclipnode = 0;
1842 hull->lastclipnode = count-1;
1843 hull->planes = loadmodel->planes;
1844 hull->clip_mins[0] = -16;
1845 hull->clip_mins[1] = -16;
1846 hull->clip_mins[2] = -18;
1847 hull->clip_maxs[0] = 16;
1848 hull->clip_maxs[1] = 16;
1849 hull->clip_maxs[2] = 18;
1850 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1854 hull = &loadmodel->hulls[1];
1855 hull->clipnodes = out;
1856 hull->firstclipnode = 0;
1857 hull->lastclipnode = count-1;
1858 hull->planes = loadmodel->planes;
1859 hull->clip_mins[0] = -16;
1860 hull->clip_mins[1] = -16;
1861 hull->clip_mins[2] = -24;
1862 hull->clip_maxs[0] = 16;
1863 hull->clip_maxs[1] = 16;
1864 hull->clip_maxs[2] = 32;
1865 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1867 hull = &loadmodel->hulls[2];
1868 hull->clipnodes = out;
1869 hull->firstclipnode = 0;
1870 hull->lastclipnode = count-1;
1871 hull->planes = loadmodel->planes;
1872 hull->clip_mins[0] = -32;
1873 hull->clip_mins[1] = -32;
1874 hull->clip_mins[2] = -24;
1875 hull->clip_maxs[0] = 32;
1876 hull->clip_maxs[1] = 32;
1877 hull->clip_maxs[2] = 64;
1878 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1881 for (i=0 ; i<count ; i++, out++, in++)
1883 out->planenum = LittleLong(in->planenum);
1884 out->children[0] = LittleShort(in->children[0]);
1885 out->children[1] = LittleShort(in->children[1]);
1886 if (out->children[0] >= count || out->children[1] >= count)
1887 Host_Error("Corrupt clipping hull (out of range child)\n");
1895 Duplicate the drawing hull structure as a clipping hull
1898 static void Mod_MakeHull0 (void)
1905 hull = &loadmodel->hulls[0];
1907 in = loadmodel->nodes;
1908 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1910 hull->clipnodes = out;
1911 hull->firstclipnode = 0;
1912 hull->lastclipnode = loadmodel->numnodes - 1;
1913 hull->planes = loadmodel->planes;
1915 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1917 out->planenum = in->plane - loadmodel->planes;
1918 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1919 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1925 Mod_LoadMarksurfaces
1928 static void Mod_LoadMarksurfaces (lump_t *l)
1933 in = (void *)(mod_base + l->fileofs);
1934 if (l->filelen % sizeof(*in))
1935 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1936 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1937 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1939 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1941 j = (unsigned) LittleShort(in[i]);
1942 if (j >= loadmodel->numsurfaces)
1943 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1944 loadmodel->marksurfaces[i] = j;
1953 static void Mod_LoadSurfedges (lump_t *l)
1958 in = (void *)(mod_base + l->fileofs);
1959 if (l->filelen % sizeof(*in))
1960 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1961 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1962 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1964 for (i = 0;i < loadmodel->numsurfedges;i++)
1965 loadmodel->surfedges[i] = LittleLong (in[i]);
1974 static void Mod_LoadPlanes (lump_t *l)
1980 in = (void *)(mod_base + l->fileofs);
1981 if (l->filelen % sizeof(*in))
1982 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1984 loadmodel->numplanes = l->filelen / sizeof(*in);
1985 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1987 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1989 out->normal[0] = LittleFloat (in->normal[0]);
1990 out->normal[1] = LittleFloat (in->normal[1]);
1991 out->normal[2] = LittleFloat (in->normal[2]);
1992 out->dist = LittleFloat (in->dist);
1998 #define MAX_POINTS_ON_WINDING 64
2004 double points[8][3]; // variable sized
2013 static winding_t *NewWinding (int points)
2018 if (points > MAX_POINTS_ON_WINDING)
2019 Sys_Error("NewWinding: too many points\n");
2021 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
2022 w = Mem_Alloc(loadmodel->mempool, size);
2023 memset (w, 0, size);
2028 static void FreeWinding (winding_t *w)
2038 static winding_t *BaseWindingForPlane (mplane_t *p)
2040 double org[3], vright[3], vup[3], normal[3];
2043 VectorCopy(p->normal, normal);
2044 VectorVectorsDouble(normal, vright, vup);
2046 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
2047 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
2049 // project a really big axis aligned box onto the plane
2052 VectorScale (p->normal, p->dist, org);
2054 VectorSubtract (org, vright, w->points[0]);
2055 VectorAdd (w->points[0], vup, w->points[0]);
2057 VectorAdd (org, vright, w->points[1]);
2058 VectorAdd (w->points[1], vup, w->points[1]);
2060 VectorAdd (org, vright, w->points[2]);
2061 VectorSubtract (w->points[2], vup, w->points[2]);
2063 VectorSubtract (org, vright, w->points[3]);
2064 VectorSubtract (w->points[3], vup, w->points[3]);
2075 Clips the winding to the plane, returning the new winding on the positive side
2076 Frees the input winding.
2077 If keepon is true, an exactly on-plane winding will be saved, otherwise
2078 it will be clipped away.
2081 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2083 double dists[MAX_POINTS_ON_WINDING + 1];
2084 int sides[MAX_POINTS_ON_WINDING + 1];
2093 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2095 // determine sides for each point
2096 for (i = 0;i < in->numpoints;i++)
2098 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2099 if (dot > ON_EPSILON)
2100 sides[i] = SIDE_FRONT;
2101 else if (dot < -ON_EPSILON)
2102 sides[i] = SIDE_BACK;
2107 sides[i] = sides[0];
2108 dists[i] = dists[0];
2110 if (keepon && !counts[0] && !counts[1])
2121 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2122 if (maxpts > MAX_POINTS_ON_WINDING)
2123 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2125 neww = NewWinding (maxpts);
2127 for (i = 0;i < in->numpoints;i++)
2129 if (neww->numpoints >= maxpts)
2130 Sys_Error ("ClipWinding: points exceeded estimate");
2134 if (sides[i] == SIDE_ON)
2136 VectorCopy (p1, neww->points[neww->numpoints]);
2141 if (sides[i] == SIDE_FRONT)
2143 VectorCopy (p1, neww->points[neww->numpoints]);
2147 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2150 // generate a split point
2151 p2 = in->points[(i+1)%in->numpoints];
2153 dot = dists[i] / (dists[i]-dists[i+1]);
2154 for (j = 0;j < 3;j++)
2155 { // avoid round off error when possible
2156 if (split->normal[j] == 1)
2157 mid[j] = split->dist;
2158 else if (split->normal[j] == -1)
2159 mid[j] = -split->dist;
2161 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2164 VectorCopy (mid, neww->points[neww->numpoints]);
2168 // free the original winding
2179 Divides a winding by a plane, producing one or two windings. The
2180 original winding is not damaged or freed. If only on one side, the
2181 returned winding will be the input winding. If on both sides, two
2182 new windings will be created.
2185 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2187 double dists[MAX_POINTS_ON_WINDING + 1];
2188 int sides[MAX_POINTS_ON_WINDING + 1];
2197 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2199 // determine sides for each point
2200 for (i = 0;i < in->numpoints;i++)
2202 dot = DotProduct (in->points[i], split->normal);
2205 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2206 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2207 else sides[i] = SIDE_ON;
2210 sides[i] = sides[0];
2211 dists[i] = dists[0];
2213 *front = *back = NULL;
2226 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2228 if (maxpts > MAX_POINTS_ON_WINDING)
2229 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2231 *front = f = NewWinding (maxpts);
2232 *back = b = NewWinding (maxpts);
2234 for (i = 0;i < in->numpoints;i++)
2236 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2237 Sys_Error ("DivideWinding: points exceeded estimate");
2241 if (sides[i] == SIDE_ON)
2243 VectorCopy (p1, f->points[f->numpoints]);
2245 VectorCopy (p1, b->points[b->numpoints]);
2250 if (sides[i] == SIDE_FRONT)
2252 VectorCopy (p1, f->points[f->numpoints]);
2255 else if (sides[i] == SIDE_BACK)
2257 VectorCopy (p1, b->points[b->numpoints]);
2261 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2264 // generate a split point
2265 p2 = in->points[(i+1)%in->numpoints];
2267 dot = dists[i] / (dists[i]-dists[i+1]);
2268 for (j = 0;j < 3;j++)
2269 { // avoid round off error when possible
2270 if (split->normal[j] == 1)
2271 mid[j] = split->dist;
2272 else if (split->normal[j] == -1)
2273 mid[j] = -split->dist;
2275 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2278 VectorCopy (mid, f->points[f->numpoints]);
2280 VectorCopy (mid, b->points[b->numpoints]);
2285 typedef struct portal_s
2288 mnode_t *nodes[2]; // [0] = front side of plane
2289 struct portal_s *next[2];
2291 struct portal_s *chain; // all portals are linked into a list
2295 static portal_t *portalchain;
2302 static portal_t *AllocPortal (void)
2305 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2306 p->chain = portalchain;
2311 static void FreePortal(portal_t *p)
2316 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2318 // calculate children first
2319 if (node->children[0]->contents >= 0)
2320 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2321 if (node->children[1]->contents >= 0)
2322 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2324 // make combined bounding box from children
2325 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2326 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2327 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2328 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2329 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2330 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2333 static void Mod_FinalizePortals(void)
2335 int i, j, numportals, numpoints;
2336 portal_t *p, *pnext;
2339 mleaf_t *leaf, *endleaf;
2342 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2343 leaf = loadmodel->leafs;
2344 endleaf = leaf + loadmodel->numleafs;
2345 for (;leaf < endleaf;leaf++)
2347 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2348 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2355 for (i = 0;i < 2;i++)
2357 leaf = (mleaf_t *)p->nodes[i];
2359 for (j = 0;j < w->numpoints;j++)
2361 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2362 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2363 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2364 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2365 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2366 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2373 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2375 // tally up portal and point counts
2381 // note: this check must match the one below or it will usually corrupt memory
2382 // the nodes[0] != nodes[1] check is because leaf 0 is the shared solid leaf, it can have many portals inside with leaf 0 on both sides
2383 if (p->winding && p->nodes[0] != p->nodes[1]
2384 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2385 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2388 numpoints += p->winding->numpoints * 2;
2392 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2393 loadmodel->numportals = numportals;
2394 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2395 loadmodel->numportalpoints = numpoints;
2396 // clear all leaf portal chains
2397 for (i = 0;i < loadmodel->numleafs;i++)
2398 loadmodel->leafs[i].portals = NULL;
2399 // process all portals in the global portal chain, while freeing them
2400 portal = loadmodel->portals;
2401 point = loadmodel->portalpoints;
2410 // note: this check must match the one above or it will usually corrupt memory
2411 // the nodes[0] != nodes[1] check is because leaf 0 is the shared solid leaf, it can have many portals inside with leaf 0 on both sides
2412 if (p->nodes[0] != p->nodes[1]
2413 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2414 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2416 // first make the back to front portal (forward portal)
2417 portal->points = point;
2418 portal->numpoints = p->winding->numpoints;
2419 portal->plane.dist = p->plane.dist;
2420 VectorCopy(p->plane.normal, portal->plane.normal);
2421 portal->here = (mleaf_t *)p->nodes[1];
2422 portal->past = (mleaf_t *)p->nodes[0];
2424 for (j = 0;j < portal->numpoints;j++)
2426 VectorCopy(p->winding->points[j], point->position);
2429 PlaneClassify(&portal->plane);
2431 // link into leaf's portal chain
2432 portal->next = portal->here->portals;
2433 portal->here->portals = portal;
2435 // advance to next portal
2438 // then make the front to back portal (backward portal)
2439 portal->points = point;
2440 portal->numpoints = p->winding->numpoints;
2441 portal->plane.dist = -p->plane.dist;
2442 VectorNegate(p->plane.normal, portal->plane.normal);
2443 portal->here = (mleaf_t *)p->nodes[0];
2444 portal->past = (mleaf_t *)p->nodes[1];
2446 for (j = portal->numpoints - 1;j >= 0;j--)
2448 VectorCopy(p->winding->points[j], point->position);
2451 PlaneClassify(&portal->plane);
2453 // link into leaf's portal chain
2454 portal->next = portal->here->portals;
2455 portal->here->portals = portal;
2457 // advance to next portal
2460 FreeWinding(p->winding);
2472 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2475 Host_Error ("AddPortalToNodes: NULL front node");
2477 Host_Error ("AddPortalToNodes: NULL back node");
2478 if (p->nodes[0] || p->nodes[1])
2479 Host_Error ("AddPortalToNodes: already included");
2480 // note: front == back is handled gracefully, because leaf 0 is the shared solid leaf, it can often have portals with the same leaf on both sides
2482 p->nodes[0] = front;
2483 p->next[0] = (portal_t *)front->portals;
2484 front->portals = (mportal_t *)p;
2487 p->next[1] = (portal_t *)back->portals;
2488 back->portals = (mportal_t *)p;
2493 RemovePortalFromNode
2496 static void RemovePortalFromNodes(portal_t *portal)
2500 void **portalpointer;
2502 for (i = 0;i < 2;i++)
2504 node = portal->nodes[i];
2506 portalpointer = (void **) &node->portals;
2511 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2515 if (portal->nodes[0] == node)
2517 *portalpointer = portal->next[0];
2518 portal->nodes[0] = NULL;
2520 else if (portal->nodes[1] == node)
2522 *portalpointer = portal->next[1];
2523 portal->nodes[1] = NULL;
2526 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2530 if (t->nodes[0] == node)
2531 portalpointer = (void **) &t->next[0];
2532 else if (t->nodes[1] == node)
2533 portalpointer = (void **) &t->next[1];
2535 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2540 static void Mod_RecursiveNodePortals (mnode_t *node)
2543 mnode_t *front, *back, *other_node;
2544 mplane_t clipplane, *plane;
2545 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2546 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2548 // if a leaf, we're done
2552 plane = node->plane;
2554 front = node->children[0];
2555 back = node->children[1];
2557 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2559 // create the new portal by generating a polygon for the node plane,
2560 // and clipping it by all of the other portals (which came from nodes above this one)
2561 nodeportal = AllocPortal ();
2562 nodeportal->plane = *node->plane;
2564 nodeportalwinding = BaseWindingForPlane (node->plane);
2565 side = 0; // shut up compiler warning
2566 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2568 clipplane = portal->plane;
2569 if (portal->nodes[0] == portal->nodes[1])
2570 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2571 if (portal->nodes[0] == node)
2573 else if (portal->nodes[1] == node)
2575 clipplane.dist = -clipplane.dist;
2576 VectorNegate (clipplane.normal, clipplane.normal);
2580 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2582 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2583 if (!nodeportalwinding)
2585 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2590 if (nodeportalwinding)
2592 // if the plane was not clipped on all sides, there was an error
2593 nodeportal->winding = nodeportalwinding;
2594 AddPortalToNodes (nodeportal, front, back);
2597 // split the portals of this node along this node's plane and assign them to the children of this node
2598 // (migrating the portals downward through the tree)
2599 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2601 if (portal->nodes[0] == portal->nodes[1])
2602 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2603 if (portal->nodes[0] == node)
2605 else if (portal->nodes[1] == node)
2608 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2609 nextportal = portal->next[side];
2611 other_node = portal->nodes[!side];
2612 RemovePortalFromNodes (portal);
2614 // cut the portal into two portals, one on each side of the node plane
2615 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2620 AddPortalToNodes (portal, back, other_node);
2622 AddPortalToNodes (portal, other_node, back);
2628 AddPortalToNodes (portal, front, other_node);
2630 AddPortalToNodes (portal, other_node, front);
2634 // the winding is split
2635 splitportal = AllocPortal ();
2636 temp = splitportal->chain;
2637 *splitportal = *portal;
2638 splitportal->chain = temp;
2639 splitportal->winding = backwinding;
2640 FreeWinding (portal->winding);
2641 portal->winding = frontwinding;
2645 AddPortalToNodes (portal, front, other_node);
2646 AddPortalToNodes (splitportal, back, other_node);
2650 AddPortalToNodes (portal, other_node, front);
2651 AddPortalToNodes (splitportal, other_node, back);
2655 Mod_RecursiveNodePortals(front);
2656 Mod_RecursiveNodePortals(back);
2660 static void Mod_MakePortals(void)
2663 Mod_RecursiveNodePortals (loadmodel->nodes);
2664 Mod_FinalizePortals();
2667 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2670 int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2671 msurface_t *surf, *s;
2672 float *v0, *v1, *v2, *v3;
2673 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2674 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2675 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2677 for (vertnum = surf->poly_numverts - 1, vertnum2 = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;vertnum2 < surf->poly_numverts;vertnum = vertnum2, vertnum2++, v0 = v1, v1 += 3)
2679 if (surf->neighborsurfaces[vertnum])
2681 surf->neighborsurfaces[vertnum] = NULL;
2682 for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2684 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2685 || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2686 || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2689 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2690 if (s->neighborsurfaces[vnum] == surf)
2692 if (vnum < s->poly_numverts)
2694 for (vnum = s->poly_numverts - 1, vnum2 = 0, v2 = s->poly_verts + (s->poly_numverts - 1) * 3, v3 = s->poly_verts;vnum2 < s->poly_numverts;vnum = vnum2, vnum2++, v2 = v3, v3 += 3)
2696 if (s->neighborsurfaces[vnum] == NULL
2697 && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2698 || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2700 surf->neighborsurfaces[vertnum] = s;
2701 s->neighborsurfaces[vnum] = surf;
2705 if (vnum < s->poly_numverts)
2713 void Mod_BuildLightmapUpdateChains(mempool_t *mempool, model_t *model)
2715 int i, j, stylecounts[256], totalcount, remapstyles[256];
2717 memset(stylecounts, 0, sizeof(stylecounts));
2718 for (i = 0;i < model->nummodelsurfaces;i++)
2720 surf = model->surfaces + model->firstmodelsurface + i;
2721 for (j = 0;j < MAXLIGHTMAPS;j++)
2722 stylecounts[surf->styles[j]]++;
2725 model->light_styles = 0;
2726 for (i = 0;i < 255;i++)
2730 remapstyles[i] = model->light_styles++;
2731 totalcount += stylecounts[i] + 1;
2736 model->light_style = Mem_Alloc(mempool, model->light_styles * sizeof(qbyte));
2737 model->light_stylevalue = Mem_Alloc(mempool, model->light_styles * sizeof(int));
2738 model->light_styleupdatechains = Mem_Alloc(mempool, model->light_styles * sizeof(msurface_t **));
2739 model->light_styleupdatechainsbuffer = Mem_Alloc(mempool, totalcount * sizeof(msurface_t *));
2740 model->light_styles = 0;
2741 for (i = 0;i < 255;i++)
2743 model->light_style[model->light_styles++] = i;
2745 for (i = 0;i < model->light_styles;i++)
2747 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2748 j += stylecounts[model->light_style[i]] + 1;
2750 for (i = 0;i < model->nummodelsurfaces;i++)
2752 surf = model->surfaces + model->firstmodelsurface + i;
2753 for (j = 0;j < MAXLIGHTMAPS;j++)
2754 if (surf->styles[j] != 255)
2755 *model->light_styleupdatechains[remapstyles[surf->styles[j]]]++ = surf;
2758 for (i = 0;i < model->light_styles;i++)
2760 *model->light_styleupdatechains[i] = NULL;
2761 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2762 j += stylecounts[model->light_style[i]] + 1;
2766 void Mod_BuildPVSTextureChains(model_t *model)
2769 for (i = 0;i < model->numtextures;i++)
2770 model->pvstexturechainslength[i] = 0;
2771 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2773 if (model->surfacepvsframes[j] == model->pvsframecount)
2775 model->pvssurflist[model->pvssurflistlength++] = j;
2776 model->pvstexturechainslength[model->surfaces[j].texinfo->texture->number]++;
2779 for (i = 0, j = 0;i < model->numtextures;i++)
2781 if (model->pvstexturechainslength[i])
2783 model->pvstexturechains[i] = model->pvstexturechainsbuffer + j;
2784 j += model->pvstexturechainslength[i] + 1;
2787 model->pvstexturechains[i] = NULL;
2789 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2790 if (model->surfacepvsframes[j] == model->pvsframecount)
2791 *model->pvstexturechains[model->surfaces[j].texinfo->texture->number]++ = model->surfaces + j;
2792 for (i = 0;i < model->numtextures;i++)
2794 if (model->pvstexturechainslength[i])
2796 *model->pvstexturechains[i] = NULL;
2797 model->pvstexturechains[i] -= model->pvstexturechainslength[i];
2807 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2808 extern void R_Model_Brush_Draw(entity_render_t *ent);
2809 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2810 extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
2811 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2816 mempool_t *mainmempool;
2818 model_t *originalloadmodel;
2819 float dist, modelyawradius, modelradius, *vec;
2823 mod->type = mod_brush;
2825 header = (dheader_t *)buffer;
2827 i = LittleLong (header->version);
2828 if (i != BSPVERSION && i != 30)
2829 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2830 mod->ishlbsp = i == 30;
2831 if (loadmodel->isworldmodel)
2833 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2834 // until we get a texture for it...
2838 // swap all the lumps
2839 mod_base = (qbyte *)header;
2841 for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
2842 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2846 // store which lightmap format to use
2847 mod->lightmaprgba = r_lightmaprgba.integer;
2849 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2850 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2851 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2852 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2853 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2854 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2855 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2856 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2857 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2858 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2859 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2860 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2861 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2862 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2863 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2868 mod->numframes = 2; // regular and alternate animation
2870 mainmempool = mod->mempool;
2871 loadname = mod->name;
2873 Mod_LoadLightList ();
2874 originalloadmodel = loadmodel;
2877 // set up the submodels (FIXME: this is confusing)
2879 for (i = 0;i < mod->numsubmodels;i++)
2881 bm = &mod->submodels[i];
2883 mod->hulls[0].firstclipnode = bm->headnode[0];
2884 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2886 mod->hulls[j].firstclipnode = bm->headnode[j];
2887 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2890 mod->firstmodelsurface = bm->firstface;
2891 mod->nummodelsurfaces = bm->numfaces;
2893 // this gets altered below if sky is used
2894 mod->DrawSky = NULL;
2895 mod->Draw = R_Model_Brush_Draw;
2896 mod->DrawFakeShadow = NULL;
2897 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2898 mod->DrawLight = R_Model_Brush_DrawLight;
2899 mod->pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t **));
2900 mod->pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool, (mod->nummodelsurfaces + mod->numtextures) * sizeof(msurface_t *));
2901 mod->pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(int));
2902 Mod_BuildPVSTextureChains(mod);
2903 Mod_BuildLightmapUpdateChains(originalloadmodel->mempool, mod);
2904 if (mod->nummodelsurfaces)
2906 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2907 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2908 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2911 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2913 // we only need to have a drawsky function if it is used (usually only on world model)
2914 if (surf->texinfo->texture->shader == &Cshader_sky)
2915 mod->DrawSky = R_Model_Brush_DrawSky;
2916 // calculate bounding shapes
2917 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
2919 for (k = 0, vec = mesh->verts;k < mesh->numverts;k++, vec += 4)
2921 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2922 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2923 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2924 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2925 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2926 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2927 dist = vec[0]*vec[0]+vec[1]*vec[1];
2928 if (modelyawradius < dist)
2929 modelyawradius = dist;
2930 dist += vec[2]*vec[2];
2931 if (modelradius < dist)
2936 modelyawradius = sqrt(modelyawradius);
2937 modelradius = sqrt(modelradius);
2938 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2939 mod->yawmins[2] = mod->normalmins[2];
2940 mod->yawmaxs[2] = mod->normalmaxs[2];
2941 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2942 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2943 mod->radius = modelradius;
2944 mod->radius2 = modelradius * modelradius;
2948 // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2949 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2951 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2953 mod->numleafs = bm->visleafs;
2955 // LordHavoc: only register submodels if it is the world
2956 // (prevents bsp models from replacing world submodels)
2957 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2960 // duplicate the basic information
2961 sprintf (name, "*%i", i+1);
2962 loadmodel = Mod_FindName (name);
2964 strcpy (loadmodel->name, name);
2965 // textures and memory belong to the main model
2966 loadmodel->texturepool = NULL;
2967 loadmodel->mempool = NULL;
2972 loadmodel = originalloadmodel;
2973 //Mod_ProcessLightList ();