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);
1248 Fills in s->texturemins[] and s->extents[]
1251 static void CalcSurfaceExtents (msurface_t *s)
1253 float mins[2], maxs[2], val;
1257 int bmins[2], bmaxs[2];
1259 mins[0] = mins[1] = 999999999;
1260 maxs[0] = maxs[1] = -999999999;
1264 for (i=0 ; i<s->numedges ; i++)
1266 e = loadmodel->surfedges[s->firstedge+i];
1268 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
1270 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
1272 for (j=0 ; j<2 ; j++)
1274 val = v->position[0] * tex->vecs[j][0] +
1275 v->position[1] * tex->vecs[j][1] +
1276 v->position[2] * tex->vecs[j][2] +
1285 for (i=0 ; i<2 ; i++)
1287 bmins[i] = floor(mins[i]/16);
1288 bmaxs[i] = ceil(maxs[i]/16);
1290 s->texturemins[i] = bmins[i] * 16;
1291 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
1296 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1301 mins[0] = mins[1] = mins[2] = 9999;
1302 maxs[0] = maxs[1] = maxs[2] = -9999;
1304 for (i = 0;i < numverts;i++)
1306 for (j = 0;j < 3;j++, v++)
1317 #define MAX_SUBDIVPOLYTRIANGLES 4096
1318 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1320 static int subdivpolyverts, subdivpolytriangles;
1321 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1322 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1324 static int subdivpolylookupvert(vec3_t v)
1327 for (i = 0;i < subdivpolyverts;i++)
1328 if (subdivpolyvert[i][0] == v[0]
1329 && subdivpolyvert[i][1] == v[1]
1330 && subdivpolyvert[i][2] == v[2])
1332 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1333 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1334 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1335 return subdivpolyverts++;
1338 static void SubdividePolygon (int numverts, float *verts)
1340 int i, i1, i2, i3, f, b, c, p;
1341 vec3_t mins, maxs, front[256], back[256];
1342 float m, *pv, *cv, dist[256], frac;
1345 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1347 BoundPoly (numverts, verts, mins, maxs);
1349 for (i = 0;i < 3;i++)
1351 m = (mins[i] + maxs[i]) * 0.5;
1352 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1353 if (maxs[i] - m < 8)
1355 if (m - mins[i] < 8)
1359 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1360 dist[c] = cv[i] - m;
1363 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1367 VectorCopy (pv, front[f]);
1372 VectorCopy (pv, back[b]);
1375 if (dist[p] == 0 || dist[c] == 0)
1377 if ( (dist[p] > 0) != (dist[c] > 0) )
1380 frac = dist[p] / (dist[p] - dist[c]);
1381 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1382 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1383 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1389 SubdividePolygon (f, front[0]);
1390 SubdividePolygon (b, back[0]);
1394 i1 = subdivpolylookupvert(verts);
1395 i2 = subdivpolylookupvert(verts + 3);
1396 for (i = 2;i < numverts;i++)
1398 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1400 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1404 i3 = subdivpolylookupvert(verts + i * 3);
1405 subdivpolyindex[subdivpolytriangles][0] = i1;
1406 subdivpolyindex[subdivpolytriangles][1] = i2;
1407 subdivpolyindex[subdivpolytriangles][2] = i3;
1409 subdivpolytriangles++;
1415 Mod_GenerateWarpMesh
1417 Breaks a polygon up along axial 64 unit
1418 boundaries so that turbulent and sky warps
1419 can be done reasonably.
1422 void Mod_GenerateWarpMesh (msurface_t *surf)
1428 subdivpolytriangles = 0;
1429 subdivpolyverts = 0;
1430 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1431 if (subdivpolytriangles < 1)
1432 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1434 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1435 mesh->numverts = subdivpolyverts;
1436 mesh->numtriangles = subdivpolytriangles;
1437 mesh->vertex = (surfvertex_t *)(mesh + 1);
1438 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1439 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1441 for (i = 0;i < mesh->numtriangles;i++)
1442 for (j = 0;j < 3;j++)
1443 mesh->index[i*3+j] = subdivpolyindex[i][j];
1445 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1447 VectorCopy(subdivpolyvert[i], v->v);
1448 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1449 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1454 surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles)
1457 mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (4 + 4 + 4 + 4 + 4 + 4 + 4 + 1) * sizeof(float));
1458 mesh->numverts = numverts;
1459 mesh->numtriangles = numtriangles;
1460 mesh->verts = (float *)(mesh + 1);
1461 mesh->str = mesh->verts + mesh->numverts * 4;
1462 mesh->uvw = mesh->str + mesh->numverts * 4;
1463 mesh->abc = mesh->uvw + mesh->numverts * 4;
1464 mesh->svectors = (float *)(mesh->abc + mesh->numverts * 4);
1465 mesh->tvectors = mesh->svectors + mesh->numverts * 4;
1466 mesh->normals = mesh->tvectors + mesh->numverts * 4;
1467 mesh->lightmapoffsets = (int *)(mesh->normals + mesh->numverts * 4);
1468 mesh->index = mesh->lightmapoffsets + mesh->numverts;
1469 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
1473 void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
1475 int i, iu, iv, *index, smax, tmax;
1476 float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
1479 smax = surf->extents[0] >> 4;
1480 tmax = surf->extents[1] >> 4;
1484 surf->lightmaptexturestride = 0;
1485 surf->lightmaptexture = NULL;
1493 surf->flags |= SURF_LIGHTMAP;
1494 if (r_miplightmaps.integer)
1496 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1497 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);
1501 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1502 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);
1504 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1505 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1506 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1509 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1511 index = mesh->index;
1512 for (i = 0;i < mesh->numtriangles;i++)
1518 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1520 VectorCopy(surf->plane->normal, normal);
1521 if (surf->flags & SURF_PLANEBACK)
1522 VectorNegate(normal, normal);
1523 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1525 s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1526 t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1527 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1528 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1529 // LordHavoc: calc lightmap data offset for vertex lighting to use
1532 iu = bound(0, iu, smax);
1533 iv = bound(0, iv, tmax);
1534 u = u * uscale + ubase;
1535 v = v * vscale + vbase;
1537 mesh->verts[i * 4 + 0] = in[0];
1538 mesh->verts[i * 4 + 1] = in[1];
1539 mesh->verts[i * 4 + 2] = in[2];
1540 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1541 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1542 mesh->uvw[i * 4 + 0] = u;
1543 mesh->uvw[i * 4 + 1] = v;
1544 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1545 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1546 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
1548 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1551 void Mod_GenerateVertexMesh (msurface_t *surf)
1554 float *in, s, t, normal[3];
1557 surf->lightmaptexturestride = 0;
1558 surf->lightmaptexture = NULL;
1560 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1562 index = mesh->index;
1563 for (i = 0;i < mesh->numtriangles;i++)
1569 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1571 VectorCopy(surf->plane->normal, normal);
1572 if (surf->flags & SURF_PLANEBACK)
1573 VectorNegate(normal, normal);
1574 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1576 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
1577 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
1578 mesh->verts[i * 4 + 0] = in[0];
1579 mesh->verts[i * 4 + 1] = in[1];
1580 mesh->verts[i * 4 + 2] = in[2];
1581 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1582 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1583 mesh->uvw[i * 4 + 0] = 0;
1584 mesh->uvw[i * 4 + 1] = 0;
1585 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1586 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1588 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1591 void Mod_GenerateSurfacePolygon (msurface_t *surf)
1594 float *vec, *vert, mins[3], maxs[3];
1596 // convert edges back to a normal polygon
1597 surf->poly_numverts = surf->numedges;
1598 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
1599 for (i = 0;i < surf->numedges;i++)
1601 lindex = loadmodel->surfedges[surf->firstedge + i];
1603 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1605 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1606 VectorCopy (vec, vert);
1609 vert = surf->poly_verts;
1610 VectorCopy(vert, mins);
1611 VectorCopy(vert, maxs);
1613 for (i = 1;i < surf->poly_numverts;i++, vert += 3)
1615 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1616 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1617 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1619 VectorCopy(mins, surf->poly_mins);
1620 VectorCopy(maxs, surf->poly_maxs);
1621 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1622 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1623 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1631 static void Mod_LoadFaces (lump_t *l)
1635 int i, count, surfnum, planenum, ssize, tsize;
1637 in = (void *)(mod_base + l->fileofs);
1638 if (l->filelen % sizeof(*in))
1639 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1640 count = l->filelen / sizeof(*in);
1641 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1643 loadmodel->surfaces = out;
1644 loadmodel->numsurfaces = count;
1645 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1646 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1647 loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1649 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1651 out->number = surfnum;
1652 // FIXME: validate edges, texinfo, etc?
1653 out->firstedge = LittleLong(in->firstedge);
1654 out->numedges = LittleShort(in->numedges);
1655 if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges)
1656 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges);
1658 i = LittleShort (in->texinfo);
1659 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1660 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1661 out->texinfo = loadmodel->texinfo + i;
1662 out->flags = out->texinfo->texture->flags;
1664 planenum = LittleShort(in->planenum);
1665 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1666 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1668 if (LittleShort(in->side))
1669 out->flags |= SURF_PLANEBACK;
1671 out->plane = loadmodel->planes + planenum;
1673 // clear lightmap (filled in later)
1674 out->lightmaptexture = NULL;
1676 // force lightmap upload on first time seeing the surface
1677 out->cached_dlight = true;
1679 CalcSurfaceExtents (out);
1681 ssize = (out->extents[0] >> 4) + 1;
1682 tsize = (out->extents[1] >> 4) + 1;
1685 for (i = 0;i < MAXLIGHTMAPS;i++)
1686 out->styles[i] = in->styles[i];
1687 i = LittleLong(in->lightofs);
1689 out->samples = NULL;
1690 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1691 out->samples = loadmodel->lightdata + i;
1692 else // LordHavoc: white lighting (bsp version 29)
1693 out->samples = loadmodel->lightdata + (i * 3);
1695 Mod_GenerateSurfacePolygon(out);
1696 if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
1698 if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
1699 Host_Error ("Bad surface extents");
1700 Mod_GenerateWallMesh (out, false);
1701 // stainmap for permanent marks on walls
1702 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1704 memset(out->stainsamples, 255, ssize * tsize * 3);
1707 Mod_GenerateVertexMesh (out);
1716 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1718 node->parent = parent;
1719 if (node->contents < 0)
1721 Mod_SetParent (node->children[0], node);
1722 Mod_SetParent (node->children[1], node);
1730 static void Mod_LoadNodes (lump_t *l)
1736 in = (void *)(mod_base + l->fileofs);
1737 if (l->filelen % sizeof(*in))
1738 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1739 count = l->filelen / sizeof(*in);
1740 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1742 loadmodel->nodes = out;
1743 loadmodel->numnodes = count;
1745 for ( i=0 ; i<count ; i++, in++, out++)
1747 for (j=0 ; j<3 ; j++)
1749 out->mins[j] = LittleShort (in->mins[j]);
1750 out->maxs[j] = LittleShort (in->maxs[j]);
1753 p = LittleLong(in->planenum);
1754 out->plane = loadmodel->planes + p;
1756 out->firstsurface = LittleShort (in->firstface);
1757 out->numsurfaces = LittleShort (in->numfaces);
1759 for (j=0 ; j<2 ; j++)
1761 p = LittleShort (in->children[j]);
1763 out->children[j] = loadmodel->nodes + p;
1765 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1769 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1777 static void Mod_LoadLeafs (lump_t *l)
1783 in = (void *)(mod_base + l->fileofs);
1784 if (l->filelen % sizeof(*in))
1785 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1786 count = l->filelen / sizeof(*in);
1787 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1789 loadmodel->leafs = out;
1790 loadmodel->numleafs = count;
1792 for ( i=0 ; i<count ; i++, in++, out++)
1794 for (j=0 ; j<3 ; j++)
1796 out->mins[j] = LittleShort (in->mins[j]);
1797 out->maxs[j] = LittleShort (in->maxs[j]);
1800 p = LittleLong(in->contents);
1803 out->firstmarksurface = loadmodel->marksurfaces +
1804 LittleShort(in->firstmarksurface);
1805 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1807 p = LittleLong(in->visofs);
1809 out->compressed_vis = NULL;
1811 out->compressed_vis = loadmodel->visdata + p;
1813 for (j=0 ; j<4 ; j++)
1814 out->ambient_sound_level[j] = in->ambient_level[j];
1816 // FIXME: Insert caustics here
1825 static void Mod_LoadClipnodes (lump_t *l)
1827 dclipnode_t *in, *out;
1831 in = (void *)(mod_base + l->fileofs);
1832 if (l->filelen % sizeof(*in))
1833 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1834 count = l->filelen / sizeof(*in);
1835 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1837 loadmodel->clipnodes = out;
1838 loadmodel->numclipnodes = count;
1840 if (loadmodel->ishlbsp)
1842 hull = &loadmodel->hulls[1];
1843 hull->clipnodes = out;
1844 hull->firstclipnode = 0;
1845 hull->lastclipnode = count-1;
1846 hull->planes = loadmodel->planes;
1847 hull->clip_mins[0] = -16;
1848 hull->clip_mins[1] = -16;
1849 hull->clip_mins[2] = -36;
1850 hull->clip_maxs[0] = 16;
1851 hull->clip_maxs[1] = 16;
1852 hull->clip_maxs[2] = 36;
1853 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1855 hull = &loadmodel->hulls[2];
1856 hull->clipnodes = out;
1857 hull->firstclipnode = 0;
1858 hull->lastclipnode = count-1;
1859 hull->planes = loadmodel->planes;
1860 hull->clip_mins[0] = -32;
1861 hull->clip_mins[1] = -32;
1862 hull->clip_mins[2] = -32;
1863 hull->clip_maxs[0] = 32;
1864 hull->clip_maxs[1] = 32;
1865 hull->clip_maxs[2] = 32;
1866 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1868 hull = &loadmodel->hulls[3];
1869 hull->clipnodes = out;
1870 hull->firstclipnode = 0;
1871 hull->lastclipnode = count-1;
1872 hull->planes = loadmodel->planes;
1873 hull->clip_mins[0] = -16;
1874 hull->clip_mins[1] = -16;
1875 hull->clip_mins[2] = -18;
1876 hull->clip_maxs[0] = 16;
1877 hull->clip_maxs[1] = 16;
1878 hull->clip_maxs[2] = 18;
1879 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1883 hull = &loadmodel->hulls[1];
1884 hull->clipnodes = out;
1885 hull->firstclipnode = 0;
1886 hull->lastclipnode = count-1;
1887 hull->planes = loadmodel->planes;
1888 hull->clip_mins[0] = -16;
1889 hull->clip_mins[1] = -16;
1890 hull->clip_mins[2] = -24;
1891 hull->clip_maxs[0] = 16;
1892 hull->clip_maxs[1] = 16;
1893 hull->clip_maxs[2] = 32;
1894 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1896 hull = &loadmodel->hulls[2];
1897 hull->clipnodes = out;
1898 hull->firstclipnode = 0;
1899 hull->lastclipnode = count-1;
1900 hull->planes = loadmodel->planes;
1901 hull->clip_mins[0] = -32;
1902 hull->clip_mins[1] = -32;
1903 hull->clip_mins[2] = -24;
1904 hull->clip_maxs[0] = 32;
1905 hull->clip_maxs[1] = 32;
1906 hull->clip_maxs[2] = 64;
1907 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1910 for (i=0 ; i<count ; i++, out++, in++)
1912 out->planenum = LittleLong(in->planenum);
1913 out->children[0] = LittleShort(in->children[0]);
1914 out->children[1] = LittleShort(in->children[1]);
1915 if (out->children[0] >= count || out->children[1] >= count)
1916 Host_Error("Corrupt clipping hull (out of range child)\n");
1924 Duplicate the drawing hull structure as a clipping hull
1927 static void Mod_MakeHull0 (void)
1934 hull = &loadmodel->hulls[0];
1936 in = loadmodel->nodes;
1937 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1939 hull->clipnodes = out;
1940 hull->firstclipnode = 0;
1941 hull->lastclipnode = loadmodel->numnodes - 1;
1942 hull->planes = loadmodel->planes;
1944 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1946 out->planenum = in->plane - loadmodel->planes;
1947 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1948 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1954 Mod_LoadMarksurfaces
1957 static void Mod_LoadMarksurfaces (lump_t *l)
1962 in = (void *)(mod_base + l->fileofs);
1963 if (l->filelen % sizeof(*in))
1964 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1965 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1966 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1968 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1970 j = (unsigned) LittleShort(in[i]);
1971 if (j >= loadmodel->numsurfaces)
1972 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1973 loadmodel->marksurfaces[i] = j;
1982 static void Mod_LoadSurfedges (lump_t *l)
1987 in = (void *)(mod_base + l->fileofs);
1988 if (l->filelen % sizeof(*in))
1989 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1990 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1991 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1993 for (i = 0;i < loadmodel->numsurfedges;i++)
1994 loadmodel->surfedges[i] = LittleLong (in[i]);
2003 static void Mod_LoadPlanes (lump_t *l)
2009 in = (void *)(mod_base + l->fileofs);
2010 if (l->filelen % sizeof(*in))
2011 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
2013 loadmodel->numplanes = l->filelen / sizeof(*in);
2014 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
2016 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
2018 out->normal[0] = LittleFloat (in->normal[0]);
2019 out->normal[1] = LittleFloat (in->normal[1]);
2020 out->normal[2] = LittleFloat (in->normal[2]);
2021 out->dist = LittleFloat (in->dist);
2027 #define MAX_POINTS_ON_WINDING 64
2033 double points[8][3]; // variable sized
2042 static winding_t *NewWinding (int points)
2047 if (points > MAX_POINTS_ON_WINDING)
2048 Sys_Error("NewWinding: too many points\n");
2050 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
2051 w = Mem_Alloc(loadmodel->mempool, size);
2052 memset (w, 0, size);
2057 static void FreeWinding (winding_t *w)
2067 static winding_t *BaseWindingForPlane (mplane_t *p)
2069 double org[3], vright[3], vup[3], normal[3];
2072 VectorCopy(p->normal, normal);
2073 VectorVectorsDouble(normal, vright, vup);
2075 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
2076 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
2078 // project a really big axis aligned box onto the plane
2081 VectorScale (p->normal, p->dist, org);
2083 VectorSubtract (org, vright, w->points[0]);
2084 VectorAdd (w->points[0], vup, w->points[0]);
2086 VectorAdd (org, vright, w->points[1]);
2087 VectorAdd (w->points[1], vup, w->points[1]);
2089 VectorAdd (org, vright, w->points[2]);
2090 VectorSubtract (w->points[2], vup, w->points[2]);
2092 VectorSubtract (org, vright, w->points[3]);
2093 VectorSubtract (w->points[3], vup, w->points[3]);
2104 Clips the winding to the plane, returning the new winding on the positive side
2105 Frees the input winding.
2106 If keepon is true, an exactly on-plane winding will be saved, otherwise
2107 it will be clipped away.
2110 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2112 double dists[MAX_POINTS_ON_WINDING + 1];
2113 int sides[MAX_POINTS_ON_WINDING + 1];
2122 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2124 // determine sides for each point
2125 for (i = 0;i < in->numpoints;i++)
2127 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2128 if (dot > ON_EPSILON)
2129 sides[i] = SIDE_FRONT;
2130 else if (dot < -ON_EPSILON)
2131 sides[i] = SIDE_BACK;
2136 sides[i] = sides[0];
2137 dists[i] = dists[0];
2139 if (keepon && !counts[0] && !counts[1])
2150 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2151 if (maxpts > MAX_POINTS_ON_WINDING)
2152 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2154 neww = NewWinding (maxpts);
2156 for (i = 0;i < in->numpoints;i++)
2158 if (neww->numpoints >= maxpts)
2159 Sys_Error ("ClipWinding: points exceeded estimate");
2163 if (sides[i] == SIDE_ON)
2165 VectorCopy (p1, neww->points[neww->numpoints]);
2170 if (sides[i] == SIDE_FRONT)
2172 VectorCopy (p1, neww->points[neww->numpoints]);
2176 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2179 // generate a split point
2180 p2 = in->points[(i+1)%in->numpoints];
2182 dot = dists[i] / (dists[i]-dists[i+1]);
2183 for (j = 0;j < 3;j++)
2184 { // avoid round off error when possible
2185 if (split->normal[j] == 1)
2186 mid[j] = split->dist;
2187 else if (split->normal[j] == -1)
2188 mid[j] = -split->dist;
2190 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2193 VectorCopy (mid, neww->points[neww->numpoints]);
2197 // free the original winding
2208 Divides a winding by a plane, producing one or two windings. The
2209 original winding is not damaged or freed. If only on one side, the
2210 returned winding will be the input winding. If on both sides, two
2211 new windings will be created.
2214 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2216 double dists[MAX_POINTS_ON_WINDING + 1];
2217 int sides[MAX_POINTS_ON_WINDING + 1];
2226 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2228 // determine sides for each point
2229 for (i = 0;i < in->numpoints;i++)
2231 dot = DotProduct (in->points[i], split->normal);
2234 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2235 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2236 else sides[i] = SIDE_ON;
2239 sides[i] = sides[0];
2240 dists[i] = dists[0];
2242 *front = *back = NULL;
2255 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2257 if (maxpts > MAX_POINTS_ON_WINDING)
2258 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2260 *front = f = NewWinding (maxpts);
2261 *back = b = NewWinding (maxpts);
2263 for (i = 0;i < in->numpoints;i++)
2265 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2266 Sys_Error ("DivideWinding: points exceeded estimate");
2270 if (sides[i] == SIDE_ON)
2272 VectorCopy (p1, f->points[f->numpoints]);
2274 VectorCopy (p1, b->points[b->numpoints]);
2279 if (sides[i] == SIDE_FRONT)
2281 VectorCopy (p1, f->points[f->numpoints]);
2284 else if (sides[i] == SIDE_BACK)
2286 VectorCopy (p1, b->points[b->numpoints]);
2290 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2293 // generate a split point
2294 p2 = in->points[(i+1)%in->numpoints];
2296 dot = dists[i] / (dists[i]-dists[i+1]);
2297 for (j = 0;j < 3;j++)
2298 { // avoid round off error when possible
2299 if (split->normal[j] == 1)
2300 mid[j] = split->dist;
2301 else if (split->normal[j] == -1)
2302 mid[j] = -split->dist;
2304 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2307 VectorCopy (mid, f->points[f->numpoints]);
2309 VectorCopy (mid, b->points[b->numpoints]);
2314 typedef struct portal_s
2317 mnode_t *nodes[2]; // [0] = front side of plane
2318 struct portal_s *next[2];
2320 struct portal_s *chain; // all portals are linked into a list
2324 static portal_t *portalchain;
2331 static portal_t *AllocPortal (void)
2334 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2335 p->chain = portalchain;
2340 static void FreePortal(portal_t *p)
2345 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2347 // calculate children first
2348 if (node->children[0]->contents >= 0)
2349 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2350 if (node->children[1]->contents >= 0)
2351 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2353 // make combined bounding box from children
2354 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2355 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2356 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2357 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2358 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2359 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2362 static void Mod_FinalizePortals(void)
2364 int i, j, numportals, numpoints;
2365 portal_t *p, *pnext;
2368 mleaf_t *leaf, *endleaf;
2371 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2372 leaf = loadmodel->leafs;
2373 endleaf = leaf + loadmodel->numleafs;
2374 for (;leaf < endleaf;leaf++)
2376 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2377 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2384 for (i = 0;i < 2;i++)
2386 leaf = (mleaf_t *)p->nodes[i];
2388 for (j = 0;j < w->numpoints;j++)
2390 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2391 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2392 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2393 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2394 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2395 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2402 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2404 // tally up portal and point counts
2410 // note: this check must match the one below 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->winding && 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)
2417 numpoints += p->winding->numpoints * 2;
2421 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2422 loadmodel->numportals = numportals;
2423 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2424 loadmodel->numportalpoints = numpoints;
2425 // clear all leaf portal chains
2426 for (i = 0;i < loadmodel->numleafs;i++)
2427 loadmodel->leafs[i].portals = NULL;
2428 // process all portals in the global portal chain, while freeing them
2429 portal = loadmodel->portals;
2430 point = loadmodel->portalpoints;
2439 // note: this check must match the one above or it will usually corrupt memory
2440 // 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
2441 if (p->nodes[0] != p->nodes[1]
2442 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2443 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2445 // first make the back to front portal (forward portal)
2446 portal->points = point;
2447 portal->numpoints = p->winding->numpoints;
2448 portal->plane.dist = p->plane.dist;
2449 VectorCopy(p->plane.normal, portal->plane.normal);
2450 portal->here = (mleaf_t *)p->nodes[1];
2451 portal->past = (mleaf_t *)p->nodes[0];
2453 for (j = 0;j < portal->numpoints;j++)
2455 VectorCopy(p->winding->points[j], point->position);
2458 PlaneClassify(&portal->plane);
2460 // link into leaf's portal chain
2461 portal->next = portal->here->portals;
2462 portal->here->portals = portal;
2464 // advance to next portal
2467 // then make the front to back portal (backward portal)
2468 portal->points = point;
2469 portal->numpoints = p->winding->numpoints;
2470 portal->plane.dist = -p->plane.dist;
2471 VectorNegate(p->plane.normal, portal->plane.normal);
2472 portal->here = (mleaf_t *)p->nodes[0];
2473 portal->past = (mleaf_t *)p->nodes[1];
2475 for (j = portal->numpoints - 1;j >= 0;j--)
2477 VectorCopy(p->winding->points[j], point->position);
2480 PlaneClassify(&portal->plane);
2482 // link into leaf's portal chain
2483 portal->next = portal->here->portals;
2484 portal->here->portals = portal;
2486 // advance to next portal
2489 FreeWinding(p->winding);
2501 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2504 Host_Error ("AddPortalToNodes: NULL front node");
2506 Host_Error ("AddPortalToNodes: NULL back node");
2507 if (p->nodes[0] || p->nodes[1])
2508 Host_Error ("AddPortalToNodes: already included");
2509 // 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
2511 p->nodes[0] = front;
2512 p->next[0] = (portal_t *)front->portals;
2513 front->portals = (mportal_t *)p;
2516 p->next[1] = (portal_t *)back->portals;
2517 back->portals = (mportal_t *)p;
2522 RemovePortalFromNode
2525 static void RemovePortalFromNodes(portal_t *portal)
2529 void **portalpointer;
2531 for (i = 0;i < 2;i++)
2533 node = portal->nodes[i];
2535 portalpointer = (void **) &node->portals;
2540 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2544 if (portal->nodes[0] == node)
2546 *portalpointer = portal->next[0];
2547 portal->nodes[0] = NULL;
2549 else if (portal->nodes[1] == node)
2551 *portalpointer = portal->next[1];
2552 portal->nodes[1] = NULL;
2555 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2559 if (t->nodes[0] == node)
2560 portalpointer = (void **) &t->next[0];
2561 else if (t->nodes[1] == node)
2562 portalpointer = (void **) &t->next[1];
2564 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2569 static void Mod_RecursiveNodePortals (mnode_t *node)
2572 mnode_t *front, *back, *other_node;
2573 mplane_t clipplane, *plane;
2574 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2575 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2577 // if a leaf, we're done
2581 plane = node->plane;
2583 front = node->children[0];
2584 back = node->children[1];
2586 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2588 // create the new portal by generating a polygon for the node plane,
2589 // and clipping it by all of the other portals (which came from nodes above this one)
2590 nodeportal = AllocPortal ();
2591 nodeportal->plane = *node->plane;
2593 nodeportalwinding = BaseWindingForPlane (node->plane);
2594 side = 0; // shut up compiler warning
2595 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2597 clipplane = portal->plane;
2598 if (portal->nodes[0] == portal->nodes[1])
2599 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2600 if (portal->nodes[0] == node)
2602 else if (portal->nodes[1] == node)
2604 clipplane.dist = -clipplane.dist;
2605 VectorNegate (clipplane.normal, clipplane.normal);
2609 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2611 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2612 if (!nodeportalwinding)
2614 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2619 if (nodeportalwinding)
2621 // if the plane was not clipped on all sides, there was an error
2622 nodeportal->winding = nodeportalwinding;
2623 AddPortalToNodes (nodeportal, front, back);
2626 // split the portals of this node along this node's plane and assign them to the children of this node
2627 // (migrating the portals downward through the tree)
2628 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2630 if (portal->nodes[0] == portal->nodes[1])
2631 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2632 if (portal->nodes[0] == node)
2634 else if (portal->nodes[1] == node)
2637 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2638 nextportal = portal->next[side];
2640 other_node = portal->nodes[!side];
2641 RemovePortalFromNodes (portal);
2643 // cut the portal into two portals, one on each side of the node plane
2644 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2649 AddPortalToNodes (portal, back, other_node);
2651 AddPortalToNodes (portal, other_node, back);
2657 AddPortalToNodes (portal, front, other_node);
2659 AddPortalToNodes (portal, other_node, front);
2663 // the winding is split
2664 splitportal = AllocPortal ();
2665 temp = splitportal->chain;
2666 *splitportal = *portal;
2667 splitportal->chain = temp;
2668 splitportal->winding = backwinding;
2669 FreeWinding (portal->winding);
2670 portal->winding = frontwinding;
2674 AddPortalToNodes (portal, front, other_node);
2675 AddPortalToNodes (splitportal, back, other_node);
2679 AddPortalToNodes (portal, other_node, front);
2680 AddPortalToNodes (splitportal, other_node, back);
2684 Mod_RecursiveNodePortals(front);
2685 Mod_RecursiveNodePortals(back);
2689 static void Mod_MakePortals(void)
2692 Mod_RecursiveNodePortals (loadmodel->nodes);
2693 Mod_FinalizePortals();
2696 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2699 int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2700 msurface_t *surf, *s;
2701 float *v0, *v1, *v2, *v3;
2702 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2703 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2704 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2706 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)
2708 if (surf->neighborsurfaces[vertnum])
2710 surf->neighborsurfaces[vertnum] = NULL;
2711 for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2713 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2714 || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2715 || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2718 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2719 if (s->neighborsurfaces[vnum] == surf)
2721 if (vnum < s->poly_numverts)
2723 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)
2725 if (s->neighborsurfaces[vnum] == NULL
2726 && ((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 || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2729 surf->neighborsurfaces[vertnum] = s;
2730 s->neighborsurfaces[vnum] = surf;
2734 if (vnum < s->poly_numverts)
2742 void Mod_BuildLightmapUpdateChains(mempool_t *mempool, model_t *model)
2744 int i, j, stylecounts[256], totalcount, remapstyles[256];
2746 memset(stylecounts, 0, sizeof(stylecounts));
2747 for (i = 0;i < model->nummodelsurfaces;i++)
2749 surf = model->surfaces + model->firstmodelsurface + i;
2750 for (j = 0;j < MAXLIGHTMAPS;j++)
2751 stylecounts[surf->styles[j]]++;
2754 model->light_styles = 0;
2755 for (i = 0;i < 255;i++)
2759 remapstyles[i] = model->light_styles++;
2760 totalcount += stylecounts[i] + 1;
2765 model->light_style = Mem_Alloc(mempool, model->light_styles * sizeof(qbyte));
2766 model->light_stylevalue = Mem_Alloc(mempool, model->light_styles * sizeof(int));
2767 model->light_styleupdatechains = Mem_Alloc(mempool, model->light_styles * sizeof(msurface_t **));
2768 model->light_styleupdatechainsbuffer = Mem_Alloc(mempool, totalcount * sizeof(msurface_t *));
2769 model->light_styles = 0;
2770 for (i = 0;i < 255;i++)
2772 model->light_style[model->light_styles++] = i;
2774 for (i = 0;i < model->light_styles;i++)
2776 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2777 j += stylecounts[model->light_style[i]] + 1;
2779 for (i = 0;i < model->nummodelsurfaces;i++)
2781 surf = model->surfaces + model->firstmodelsurface + i;
2782 for (j = 0;j < MAXLIGHTMAPS;j++)
2783 if (surf->styles[j] != 255)
2784 *model->light_styleupdatechains[remapstyles[surf->styles[j]]]++ = surf;
2787 for (i = 0;i < model->light_styles;i++)
2789 *model->light_styleupdatechains[i] = NULL;
2790 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2791 j += stylecounts[model->light_style[i]] + 1;
2795 void Mod_BuildPVSTextureChains(model_t *model)
2798 for (i = 0;i < model->numtextures;i++)
2799 model->pvstexturechainslength[i] = 0;
2800 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2802 if (model->surfacepvsframes[j] == model->pvsframecount)
2804 model->pvssurflist[model->pvssurflistlength++] = j;
2805 model->pvstexturechainslength[model->surfaces[j].texinfo->texture->number]++;
2808 for (i = 0, j = 0;i < model->numtextures;i++)
2810 if (model->pvstexturechainslength[i])
2812 model->pvstexturechains[i] = model->pvstexturechainsbuffer + j;
2813 j += model->pvstexturechainslength[i] + 1;
2816 model->pvstexturechains[i] = NULL;
2818 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2819 if (model->surfacepvsframes[j] == model->pvsframecount)
2820 *model->pvstexturechains[model->surfaces[j].texinfo->texture->number]++ = model->surfaces + j;
2821 for (i = 0;i < model->numtextures;i++)
2823 if (model->pvstexturechainslength[i])
2825 *model->pvstexturechains[i] = NULL;
2826 model->pvstexturechains[i] -= model->pvstexturechainslength[i];
2836 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2837 extern void R_Model_Brush_Draw(entity_render_t *ent);
2838 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2839 extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
2840 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2845 mempool_t *mainmempool;
2847 model_t *originalloadmodel;
2849 mod->type = mod_brush;
2851 header = (dheader_t *)buffer;
2853 i = LittleLong (header->version);
2854 if (i != BSPVERSION && i != 30)
2855 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2856 mod->ishlbsp = i == 30;
2857 if (loadmodel->isworldmodel)
2859 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2860 // until we get a texture for it...
2864 // swap all the lumps
2865 mod_base = (qbyte *)header;
2867 for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
2868 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2872 // store which lightmap format to use
2873 mod->lightmaprgba = r_lightmaprgba.integer;
2875 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2876 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2877 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2878 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2879 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2880 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2881 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2882 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2883 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2884 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2885 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2886 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2887 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2888 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2889 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2894 mod->numframes = 2; // regular and alternate animation
2896 mainmempool = mod->mempool;
2897 loadname = mod->name;
2899 Mod_LoadLightList ();
2900 originalloadmodel = loadmodel;
2903 // set up the submodels (FIXME: this is confusing)
2905 for (i = 0;i < mod->numsubmodels;i++)
2908 float dist, modelyawradius, modelradius, *vec;
2911 bm = &mod->submodels[i];
2913 mod->hulls[0].firstclipnode = bm->headnode[0];
2914 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2916 mod->hulls[j].firstclipnode = bm->headnode[j];
2917 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2920 mod->firstmodelsurface = bm->firstface;
2921 mod->nummodelsurfaces = bm->numfaces;
2923 // this gets altered below if sky is used
2924 mod->DrawSky = NULL;
2925 mod->Draw = R_Model_Brush_Draw;
2926 mod->DrawFakeShadow = NULL;
2927 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2928 mod->DrawLight = R_Model_Brush_DrawLight;
2929 mod->pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t **));
2930 mod->pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool, (mod->nummodelsurfaces + mod->numtextures) * sizeof(msurface_t *));
2931 mod->pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(int));
2932 Mod_BuildPVSTextureChains(mod);
2933 Mod_BuildLightmapUpdateChains(originalloadmodel->mempool, mod);
2934 if (mod->nummodelsurfaces)
2936 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2937 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2938 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2941 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2943 // we only need to have a drawsky function if it is used (usually only on world model)
2944 if (surf->texinfo->texture->shader == &Cshader_sky)
2945 mod->DrawSky = R_Model_Brush_DrawSky;
2946 // calculate bounding shapes
2947 for (k = 0;k < surf->numedges;k++)
2949 l = mod->surfedges[k + surf->firstedge];
2951 vec = mod->vertexes[mod->edges[l].v[0]].position;
2953 vec = mod->vertexes[mod->edges[-l].v[1]].position;
2954 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2955 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2956 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2957 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2958 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2959 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2960 dist = vec[0]*vec[0]+vec[1]*vec[1];
2961 if (modelyawradius < dist)
2962 modelyawradius = dist;
2963 dist += vec[2]*vec[2];
2964 if (modelradius < dist)
2968 modelyawradius = sqrt(modelyawradius);
2969 modelradius = sqrt(modelradius);
2970 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2971 mod->yawmins[2] = mod->normalmins[2];
2972 mod->yawmaxs[2] = mod->normalmaxs[2];
2973 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2974 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2975 mod->radius = modelradius;
2976 mod->radius2 = modelradius * modelradius;
2980 // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2981 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2983 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2985 mod->numleafs = bm->visleafs;
2987 // LordHavoc: only register submodels if it is the world
2988 // (prevents bsp models from replacing world submodels)
2989 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2992 // duplicate the basic information
2993 sprintf (name, "*%i", i+1);
2994 loadmodel = Mod_FindName (name);
2996 strcpy (loadmodel->name, name);
2997 // textures and memory belong to the main model
2998 loadmodel->texturepool = NULL;
2999 loadmodel->mempool = NULL;
3004 loadmodel = originalloadmodel;
3005 //Mod_ProcessLightList ();