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.
23 // note: model_shared.c sets up r_notexture, and r_surf_notexture
25 qbyte mod_novis[(MAX_MAP_LEAFS + 7)/ 8];
27 //cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"};
28 cvar_t halflifebsp = {0, "halflifebsp", "0"};
29 cvar_t r_novis = {0, "r_novis", "0"};
30 cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"};
31 cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
32 cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
33 cvar_t r_sortsurfaces = {0, "r_sortsurfaces", "0"};
35 #define NUM_DETAILTEXTURES 1
36 static rtexture_t *detailtextures[NUM_DETAILTEXTURES];
37 static rtexturepool_t *detailtexturepool;
44 void Mod_BrushInit (void)
46 // Cvar_RegisterVariable(&r_subdivide_size);
47 Cvar_RegisterVariable(&halflifebsp);
48 Cvar_RegisterVariable(&r_novis);
49 Cvar_RegisterVariable(&r_miplightmaps);
50 Cvar_RegisterVariable(&r_lightmaprgba);
51 Cvar_RegisterVariable(&r_nosurftextures);
52 Cvar_RegisterVariable(&r_sortsurfaces);
53 memset(mod_novis, 0xff, sizeof(mod_novis));
56 void Mod_BrushStartup (void)
59 float vc[3], vx[3], vy[3], vn[3], lightdir[3];
60 #define DETAILRESOLUTION 256
61 qbyte data[DETAILRESOLUTION][DETAILRESOLUTION][4], noise[DETAILRESOLUTION][DETAILRESOLUTION];
62 detailtexturepool = R_AllocTexturePool();
66 VectorNormalize(lightdir);
67 for (i = 0;i < NUM_DETAILTEXTURES;i++)
69 fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4);
70 for (y = 0;y < DETAILRESOLUTION;y++)
72 for (x = 0;x < DETAILRESOLUTION;x++)
76 vc[2] = noise[y][x] * (1.0f / 32.0f);
79 vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f);
82 vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f);
83 VectorSubtract(vx, vc, vx);
84 VectorSubtract(vy, vc, vy);
85 CrossProduct(vx, vy, vn);
87 light = 128 - DotProduct(vn, lightdir) * 128;
88 light = bound(0, light, 255);
89 data[y][x][0] = data[y][x][1] = data[y][x][2] = light;
93 detailtextures[i] = R_LoadTexture(detailtexturepool, va("detailtexture%i", i), DETAILRESOLUTION, DETAILRESOLUTION, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE);
97 void Mod_BrushShutdown (void)
100 for (i = 0;i < NUM_DETAILTEXTURES;i++)
101 R_FreeTexture(detailtextures[i]);
102 R_FreeTexturePool(&detailtexturepool);
110 mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model)
117 Mod_CheckLoaded(model);
119 // LordHavoc: modified to start at first clip node,
120 // in other words: first node of the (sub)model
121 node = model->nodes + model->hulls[0].firstclipnode;
122 while (node->contents == 0)
123 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
125 return (mleaf_t *)node;
128 int Mod_PointContents (const vec3_t p, model_t *model)
133 return CONTENTS_EMPTY;
135 Mod_CheckLoaded(model);
137 // LordHavoc: modified to start at first clip node,
138 // in other words: first node of the (sub)model
139 node = model->nodes + model->hulls[0].firstclipnode;
140 while (node->contents == 0)
141 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
143 return ((mleaf_t *)node)->contents;
146 void Mod_FindNonSolidLocation(vec3_t pos, model_t *mod)
148 if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
149 pos[0]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
150 pos[0]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
152 pos[1]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
153 pos[1]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
155 pos[2]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
156 pos[2]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
166 static qbyte *Mod_DecompressVis (qbyte *in, model_t *model)
168 static qbyte decompressed[MAX_MAP_LEAFS/8];
173 row = (model->numleafs+7)>>3;
191 } while (out - decompressed < row);
196 qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
198 if (r_novis.integer || leaf == model->leafs || leaf->compressed_vis == NULL)
200 return Mod_DecompressVis (leaf->compressed_vis, model);
208 static void Mod_LoadTextures (lump_t *l)
210 int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs, incomplete;
212 texture_t *tx, *tx2, *anims[10], *altanims[10];
214 qbyte *data, *mtdata, *data2;
217 loadmodel->textures = NULL;
222 m = (dmiptexlump_t *)(mod_base + l->fileofs);
224 m->nummiptex = LittleLong (m->nummiptex);
226 // add two slots for notexture walls and notexture liquids
227 loadmodel->numtextures = m->nummiptex + 2;
228 loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(texture_t));
230 // fill out all slots with notexture
231 for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++)
235 tx->texture = r_notexture;
236 tx->shader = &Cshader_wall_lightmap;
237 if (i == loadmodel->numtextures - 1)
239 tx->flags = SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
240 tx->shader = &Cshader_water;
244 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
246 // LordHavoc: mostly rewritten map texture loader
247 for (i = 0;i < m->nummiptex;i++)
249 dofs[i] = LittleLong(dofs[i]);
250 if (dofs[i] == -1 || r_nosurftextures.integer)
252 dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
254 // make sure name is no more than 15 characters
255 for (j = 0;dmiptex->name[j] && j < 15;j++)
256 name[j] = dmiptex->name[j];
259 mtwidth = LittleLong (dmiptex->width);
260 mtheight = LittleLong (dmiptex->height);
262 j = LittleLong (dmiptex->offsets[0]);
266 if (j < 40 || j + mtwidth * mtheight > l->filelen)
268 Con_Printf ("Texture \"%s\" in \"%s\"is corrupt or incomplete\n", dmiptex->name, loadmodel->name);
271 mtdata = (qbyte *)dmiptex + j;
274 if ((mtwidth & 15) || (mtheight & 15))
275 Con_Printf ("warning: texture \"%s\" in \"%s\" is not 16 aligned", dmiptex->name, loadmodel->name);
277 // LordHavoc: force all names to lowercase
278 for (j = 0;name[j];j++)
279 if (name[j] >= 'A' && name[j] <= 'Z')
280 name[j] += 'a' - 'A';
282 tx = loadmodel->textures + i;
283 strcpy(tx->name, name);
285 tx->height = mtheight;
289 sprintf(tx->name, "unnamed%i", i);
290 Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
293 // LordHavoc: HL sky textures are entirely different than quake
294 if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
296 if (loadmodel->isworldmodel)
298 data = loadimagepixels(tx->name, false, 0, 0);
301 if (image_width == 256 && image_height == 128)
309 Con_Printf ("Invalid replacement texture for sky \"%s\" in %\"%s\", must be 256x128 pixels\n", tx->name, loadmodel->name);
311 R_InitSky (mtdata, 1);
314 else if (mtdata != NULL)
315 R_InitSky (mtdata, 1);
318 else if ((tx->texture = loadtextureimagewithmask(loadmodel->texturepool, tx->name, 0, 0, false, true, true)))
320 tx->fogtexture = image_masktex;
321 strcpy(name, tx->name);
322 strcat(name, "_glow");
323 tx->glowtexture = loadtextureimage(loadmodel->texturepool, name, 0, 0, false, true, true);
327 if (loadmodel->ishlbsp)
329 if (mtdata && (data = W_ConvertWAD3Texture(dmiptex)))
332 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
333 if (R_TextureHasAlpha(tx->texture))
336 for (j = 0;j < image_width * image_height;j++)
337 data[j*4+0] = data[j*4+1] = data[j*4+2] = 255;
338 strcpy(name, tx->name);
339 strcat(name, "_fog");
340 tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
344 else if ((data = W_GetTexture(tx->name)))
346 // get the size from the wad texture
347 tx->width = image_width;
348 tx->height = image_height;
349 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
350 if (R_TextureHasAlpha(tx->texture))
353 for (j = 0;j < image_width * image_height;j++)
354 data[j*4+0] = data[j*4+1] = data[j*4+2] = 255;
355 strcpy(name, tx->name);
356 strcat(name, "_fog");
357 tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
365 tx->texture = r_notexture;
370 if (mtdata) // texture included
375 if (r_fullbrights.value && tx->name[0] != '*')
377 for (j = 0;j < tx->width*tx->height;j++)
379 if (data[j] >= 224) // fullbright
388 data2 = Mem_Alloc(loadmodel->mempool, tx->width*tx->height);
389 for (j = 0;j < tx->width*tx->height;j++)
390 data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights
391 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
392 strcpy(name, tx->name);
393 strcat(name, "_glow");
394 for (j = 0;j < tx->width*tx->height;j++)
395 data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights
396 tx->glowtexture = R_LoadTexture (loadmodel->texturepool, name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
400 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
402 else // no texture, and no external replacement texture was found
406 tx->texture = r_notexture;
411 if (tx->name[0] == '*')
413 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
414 // LordHavoc: some turbulent textures should be fullbright and solid
415 if (!strncmp(tx->name,"*lava",5)
416 || !strncmp(tx->name,"*teleport",9)
417 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
418 tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
419 tx->shader = &Cshader_water;
421 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
423 tx->flags |= SURF_DRAWSKY;
424 tx->shader = &Cshader_sky;
428 tx->flags |= SURF_LIGHTMAP;
430 tx->flags |= SURF_CLIPSOLID;
431 tx->shader = &Cshader_wall_lightmap;
434 tx->detailtexture = detailtextures[i % NUM_DETAILTEXTURES];
437 // sequence the animations
438 for (i = 0;i < m->nummiptex;i++)
440 tx = loadmodel->textures + i;
441 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
443 if (tx->anim_total[0] || tx->anim_total[1])
444 continue; // already sequenced
446 // find the number of frames in the animation
447 memset (anims, 0, sizeof(anims));
448 memset (altanims, 0, sizeof(altanims));
450 for (j = i;j < m->nummiptex;j++)
452 tx2 = loadmodel->textures + j;
453 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
457 if (num >= '0' && num <= '9')
458 anims[num - '0'] = tx2;
459 else if (num >= 'a' && num <= 'j')
460 altanims[num - 'a'] = tx2;
462 Con_Printf ("Bad animating texture %s\n", tx->name);
466 for (j = 0;j < 10;j++)
473 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
476 for (j = 0;j < max;j++)
480 Con_Printf ("Missing frame %i of %s\n", j, tx->name);
484 for (j = 0;j < altmax;j++)
488 Con_Printf ("Missing altframe %i of %s\n", j, tx->name);
497 // if there is no alternate animation, duplicate the primary
498 // animation into the alternate
500 for (k = 0;k < 10;k++)
501 altanims[k] = anims[k];
504 // link together the primary animation
505 for (j = 0;j < max;j++)
508 tx2->animated = true;
509 tx2->anim_total[0] = max;
510 tx2->anim_total[1] = altmax;
511 for (k = 0;k < 10;k++)
513 tx2->anim_frames[0][k] = anims[k];
514 tx2->anim_frames[1][k] = altanims[k];
518 // if there really is an alternate anim...
519 if (anims[0] != altanims[0])
521 // link together the alternate animation
522 for (j = 0;j < altmax;j++)
525 tx2->animated = true;
526 // the primary/alternate are reversed here
527 tx2->anim_total[0] = altmax;
528 tx2->anim_total[1] = max;
529 for (k = 0;k < 10;k++)
531 tx2->anim_frames[0][k] = altanims[k];
532 tx2->anim_frames[1][k] = anims[k];
544 static void Mod_LoadLighting (lump_t *l)
547 qbyte *in, *out, *data, d;
548 char litfilename[1024];
549 loadmodel->lightdata = NULL;
550 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
552 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
553 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
555 else // LordHavoc: bsp version 29 (normal white lighting)
557 // LordHavoc: hope is not lost yet, check for a .lit file to load
558 strcpy(litfilename, loadmodel->name);
559 COM_StripExtension(litfilename, litfilename);
560 strcat(litfilename, ".lit");
561 data = (qbyte*) COM_LoadFile (litfilename, false);
564 if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
566 i = LittleLong(((int *)data)[1]);
569 Con_DPrintf("%s loaded", litfilename);
570 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
571 memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
577 Con_Printf("Unknown .lit file version (%d)\n", i);
584 Con_Printf("Empty .lit file, ignoring\n");
586 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
590 // LordHavoc: oh well, expand the white lighting data
593 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
594 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
595 out = loadmodel->lightdata;
596 memcpy (in, mod_base + l->fileofs, l->filelen);
597 for (i = 0;i < l->filelen;i++)
607 void Mod_LoadLightList(void)
610 char lightsfilename[1024], *s, *t, *lightsstring;
613 strcpy(lightsfilename, loadmodel->name);
614 COM_StripExtension(lightsfilename, lightsfilename);
615 strcat(lightsfilename, ".lights");
616 s = lightsstring = (char *) COM_LoadFile (lightsfilename, false);
622 while (*s && *s != '\n')
626 Mem_Free(lightsstring);
627 Host_Error("lights file must end with a newline\n");
632 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
635 while (*s && n < numlights)
638 while (*s && *s != '\n')
642 Mem_Free(lightsstring);
643 Host_Error("misparsed lights file!\n");
645 e = loadmodel->lights + n;
647 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);
651 Mem_Free(lightsstring);
652 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);
659 Mem_Free(lightsstring);
660 Host_Error("misparsed lights file!\n");
662 loadmodel->numlights = numlights;
663 Mem_Free(lightsstring);
670 // svbspmesh_t is in model_brush.h
672 typedef struct svbsppolygon_s
674 struct svbsppolygon_s *next;
677 float normal[3], dist;
681 typedef struct svbspnode_s
683 // true if this is a leaf (has no children), not a node
685 // (shared) parent node
686 struct svbspnode_s *parent;
687 // (leaf) dark or lit leaf
689 // (leaf) polygons bounding this leaf
690 svbsppolygon_t *polygons;
692 struct svbspnode_s *children[2];
693 // (node) splitting plane
694 float normal[3], dist;
698 svbspnode_t *Mod_SVBSP_AllocNode(svbspnode_t *parent, svbspnode_t *child0, svbspnode_t *child1, float *normal, float dist)
701 node = Mem_Alloc(loadmodel->mempool, sizeof(svbspnode_t));
702 node->parent = parent;
703 node->children[0] = child0;
704 node->children[1] = child1;
705 VectorCopy(normal, node->normal);
710 svbspnode_t *Mod_SVBSP_AllocLeaf(svbspnode_t *parent, int dark)
713 leaf = Mem_Alloc(loadmodel->mempool, sizeof(svbspnode_t));
715 leaf->parent = parent;
720 svbspnode_t *Mod_SVBSP_NewTree(void)
722 return Mod_SVBSP_AllocLeaf(NULL, false);
725 void Mod_SVBSP_FreeTree(svbspnode_t *node)
729 Mod_SVBSP_FreeTree(node->children[0]);
730 Mod_SVBSP_FreeTree(node->children[1]);
735 void Mod_SVBSP_RecursiveAddPolygon(svbspnode_t *node, int numverts, float *verts, float *normal, float dist, int constructmode)
737 int i, j, numvertsfront, numvertsback, maxverts, counts[3];
738 float *vertsfront, *vertsback, *v, d, temp[3];
741 svbsppolygon_t *poly;
744 if (constructmode == 0)
746 // construct tree structure
747 node->isleaf = false;
748 node->children[0] = Mod_SVBSP_AllocLeaf(node, false);
749 node->children[1] = Mod_SVBSP_AllocLeaf(node, false);
750 VectorCopy(normal, node->normal);
753 else if (constructmode == 1)
760 // link polygons into lit leafs only (this is the optimization)
763 poly = Mem_Alloc(loadmodel->mempool, sizeof(svbsppolygon_t) + numverts * sizeof(float[3]));
764 poly->numverts = numverts;
765 poly->verts = (float *)(poly + 1);
766 VectorCopy(normal, poly->normal);
768 memcpy(poly->verts, verts, numverts * sizeof(float[3]));
769 poly->next = node->polygons;
770 node->polygons = poly;
776 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
777 for (i = 0, v = verts;i < numverts;i++, v += 3)
779 dists[i] = DotProduct(v, node->normal) - node->dist;
781 sides[i] = SIDE_FRONT;
782 else if (dists[i] <= -0.1)
783 sides[i] = SIDE_BACK;
788 if (counts[SIDE_FRONT] && counts[SIDE_BACK])
790 // some front, some back... sliced
793 // this is excessive, but nice for safety...
794 maxverts = numverts + 4;
795 vertsfront = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
796 vertsback = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
797 for (i = 0, j = numverts - 1;i < numverts;j = i, i++)
799 if (sides[j] == SIDE_FRONT)
801 VectorCopy(&verts[j * 3], &vertsfront[numvertsfront * 3]);
803 if (sides[i] == SIDE_BACK)
805 d = dists[j] / (dists[j] - dists[i]);
806 VectorSubtract(&verts[i * 3], &verts[j * 3], temp);
807 VectorMA(&verts[j * 3], d, temp, temp);
808 VectorCopy(temp, &vertsfront[numvertsfront * 3]);
809 VectorCopy(temp, &vertsback[numvertsback * 3]);
814 else if (sides[j] == SIDE_BACK)
816 VectorCopy(&verts[j * 3], &vertsback[numvertsback * 3]);
818 if (sides[i] == SIDE_FRONT)
820 d = dists[j] / (dists[j] - dists[i]);
821 VectorSubtract(&verts[i * 3], &verts[j * 3], temp);
822 VectorMA(&verts[j * 3], d, temp, temp);
823 VectorCopy(temp, &vertsfront[numvertsfront * 3]);
824 VectorCopy(temp, &vertsback[numvertsback * 3]);
831 VectorCopy(&verts[j * 3], &vertsfront[numvertsfront * 3]);
832 VectorCopy(&verts[j * 3], &vertsback[numvertsback * 3]);
837 Mod_SVBSP_RecursiveAddPolygon(node->children[1], numvertsfront, vertsfront, normal, dist, constructmode);
838 Mod_SVBSP_RecursiveAddPolygon(node->children[0], numvertsback, vertsback, normal, dist, constructmode);
839 Mem_Free(vertsfront);
842 else if (counts[SIDE_BACK])
843 Mod_SVBSP_RecursiveAddPolygon(node->children[0], numverts, verts, normal, dist, constructmode);
844 else if (counts[SIDE_FRONT])
845 Mod_SVBSP_RecursiveAddPolygon(node->children[1], numverts, verts, normal, dist, constructmode);
848 // mode 0 is constructing tree, don't make unnecessary splits
849 if (constructmode == 1)
851 // marking dark leafs
852 // send it down the side it is not facing
853 Mod_SVBSP_RecursiveAddPolygon(node->children[DotProduct(node->normal, normal) < 0], numverts, verts, normal, dist, constructmode);
855 else if (constructmode == 2)
857 // linking polygons into lit leafs only
858 // send it down the side it is facing
859 Mod_SVBSP_RecursiveAddPolygon(node->children[DotProduct(node->normal, normal) >= 0], numverts, verts, normal, dist, constructmode);
865 int svbsp_count_nodes;
866 int svbsp_count_leafs;
867 int svbsp_count_polygons;
868 int svbsp_count_darkleafs;
869 int svbsp_count_originalpolygons;
870 int svbsp_count_meshs;
871 int svbsp_count_triangles;
872 int svbsp_count_vertices;
874 void Mod_SVBSP_AddPolygon(svbspnode_t *root, int numverts, float *verts, int constructmode, float *test, int linenumber)
877 float normal[3], dist, dir0[3], dir1[3], *v0, *v1, *v2;
878 svbsp_count_originalpolygons++;
879 for (i = 0, v0 = verts + (numverts - 2) * 3, v1 = verts + (numverts - 1) * 3, v2 = verts;i < numverts;i++, v0 = v1, v1 = v2, v2 += 3)
881 VectorSubtract(v0, v1, dir0);
882 VectorSubtract(v2, v1, dir1);
883 CrossProduct(dir0, dir1, normal);
884 if (DotProduct(normal, normal) >= 0.1)
889 VectorNormalize(normal);
890 dist = DotProduct(verts, normal);
891 if (test && DotProduct(test, normal) > dist + 0.1)
892 Con_Printf("%i %f %f %f %f : %f %f %f %f\n", linenumber, normal[0], normal[1], normal[2], dist, test[0], test[1], test[2], DotProduct(test, normal));
893 Mod_SVBSP_RecursiveAddPolygon(root, numverts, verts, normal, dist, constructmode);
896 void Mod_SVBSP_RecursiveGatherStats(svbspnode_t *node)
898 svbsppolygon_t *poly;
899 for (poly = node->polygons;poly;poly = poly->next)
900 svbsp_count_polygons++;
905 svbsp_count_darkleafs++;
910 Mod_SVBSP_RecursiveGatherStats(node->children[0]);
911 Mod_SVBSP_RecursiveGatherStats(node->children[1]);
915 svbspmesh_t *Mod_SVBSP_AllocMesh(int maxverts)
918 mesh = Mem_Alloc(loadmodel->mempool, sizeof(svbspmesh_t) + maxverts * sizeof(float[4]) + maxverts * sizeof(int[3]));
919 mesh->maxverts = maxverts;
920 mesh->maxtriangles = maxverts;
922 mesh->numtriangles = 0;
923 mesh->verts = (float *)(mesh + 1);
924 mesh->elements = (int *)(mesh->verts + mesh->maxverts * 4);
928 svbspmesh_t *Mod_SVBSP_ReAllocMesh(svbspmesh_t *oldmesh)
930 svbspmesh_t *newmesh;
931 newmesh = Mem_Alloc(loadmodel->mempool, sizeof(svbspmesh_t) + oldmesh->numverts * sizeof(float[4]) + oldmesh->numtriangles * sizeof(int[3]));
932 newmesh->maxverts = newmesh->numverts = oldmesh->numverts;
933 newmesh->maxtriangles = newmesh->numtriangles = oldmesh->numtriangles;
934 newmesh->verts = (float *)(newmesh + 1);
935 newmesh->elements = (int *)(newmesh->verts + newmesh->maxverts * 4);
936 memcpy(newmesh->verts, oldmesh->verts, newmesh->numverts * sizeof(float[4]));
937 memcpy(newmesh->elements, oldmesh->elements, newmesh->numtriangles * sizeof(int[3]));
941 void Mod_SVBSP_RecursiveBuildTriangleMeshs(svbspmesh_t *firstmesh, svbspnode_t *node)
943 svbsppolygon_t *poly;
946 float *v, *m, temp[3];
949 for (poly = node->polygons;poly;poly = poly->next)
952 while (poly->numverts + mesh->numverts > mesh->maxverts || (poly->numverts - 2) + mesh->numtriangles > mesh->maxtriangles)
954 if (mesh->next == NULL)
955 mesh->next = Mod_SVBSP_AllocMesh(max(1000, poly->numverts));
958 for (i = 0, v = poly->verts;i < poly->numverts - 2;i++, v += 3)
960 for (k = 0;k < 3;k++)
965 v = poly->verts + (i + 1) * 3;
967 v = poly->verts + (i + 2) * 3;
968 for (j = 0, m = mesh->verts;j < mesh->numverts;j++, m += 4)
970 VectorSubtract(v, m, temp);
971 if (DotProduct(temp, temp) < 0.1)
974 if (j == mesh->numverts)
979 mesh->elements[mesh->numtriangles * 3 + k] = j;
981 mesh->numtriangles++;
987 Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, node->children[0]);
988 Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, node->children[1]);
992 svbspmesh_t *Mod_SVBSP_BuildTriangleMeshs(svbspnode_t *root, vec3_t mins, vec3_t maxs)
994 svbspmesh_t *firstmesh, *mesh, *newmesh, *nextmesh;
997 firstmesh = Mod_SVBSP_AllocMesh(1000);
998 Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, root);
999 // reallocate meshs to conserve space
1000 for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh)
1002 svbsp_count_meshs++;
1003 svbsp_count_triangles += mesh->numtriangles;
1004 svbsp_count_vertices += mesh->numverts;
1007 if (firstmesh == NULL)
1009 VectorCopy(mesh->verts, mins);
1010 VectorCopy(mesh->verts, maxs);
1012 for (i = 0, v = mesh->verts;i < mesh->numverts;i++, v += 4)
1014 if (mins[0] > v[0]) mins[0] = v[0];if (maxs[0] < v[0]) maxs[0] = v[0];
1015 if (mins[1] > v[1]) mins[1] = v[1];if (maxs[1] < v[1]) maxs[1] = v[1];
1016 if (mins[2] > v[2]) mins[2] = v[2];if (maxs[2] < v[2]) maxs[2] = v[2];
1019 nextmesh = mesh->next;
1020 newmesh = Mod_SVBSP_ReAllocMesh(mesh);
1021 newmesh->next = firstmesh;
1022 firstmesh = newmesh;
1028 void Mod_SVBSP_FreeTriangleMeshs(svbspmesh_t *mesh)
1030 svbspmesh_t *nextmesh;
1031 for (;mesh;mesh = nextmesh)
1033 nextmesh = mesh->next;
1039 typedef struct svpolygon_s
1041 struct svpolygon_s *next;
1045 float normal[3], dist;
1049 typedef struct svbrush_s
1051 struct svbrush_s *next;
1052 svpolygon_t *polygons;
1057 typedef struct svworld_s
1063 svworld_t *Mod_ShadowBrush_NewWorld(mempool_t *mempool)
1065 return Mem_Alloc(mempool, sizeof(svworld_t));
1068 void Mod_ShadowBrush_FreeWorld(svworld_t *world)
1070 svbrush_t *brush, *brushnext;
1071 svpolygon_t *poly, *polynext;
1072 for (brush = world->brushs;brush;brush = brushnext)
1074 brushnext = brush->next;
1075 for (poly = brush->polygons;poly;poly = polynext)
1077 polynext = poly->next;
1085 svbrush_t *Mod_ShadowBrush_BeginBrush(mempool_t *mempool)
1087 return Mem_Alloc(mempool, sizeof(svbrush_t));
1090 void Mod_ShadowBrush_AddPolygon(mempool_t *mempool, svbrush_t *brush, int numverts, float *verts)
1093 float normal[3], dist, dir0[3], dir1[3], *v0, *v1, *v2;
1095 for (i = 0, v0 = verts + (numverts - 2) * 3, v1 = verts + (numverts - 1) * 3, v2 = verts;i < numverts;i++, v0 = v1, v1 = v2, v2 += 3)
1097 VectorSubtract(v0, v1, dir0);
1098 VectorSubtract(v2, v1, dir1);
1099 CrossProduct(dir0, dir1, normal);
1100 if (DotProduct(normal, normal) >= 0.1)
1105 VectorNormalize(normal);
1106 dist = DotProduct(verts, normal);
1108 poly = Mem_Alloc(mempool, sizeof(svpolygon_t) + numverts * sizeof(float[3]));
1109 poly->numverts = numverts;
1110 poly->verts = (float *)(poly + 1);
1111 VectorCopy(normal, poly->normal);
1113 poly->next = brush->polygons;
1114 brush->polygons = poly;
1115 memcpy(poly->verts, verts, numverts * sizeof(float[3]));
1118 void Mod_ShadowBrush_EndBrush(svworld_t *world, svbrush_t *brush)
1123 if (!brush->polygons)
1128 brush->next = world->brushs;
1129 world->brushs = brush;
1130 VectorCopy(brush->polygons->verts, brush->mins);
1131 VectorCopy(brush->polygons->verts, brush->maxs);
1132 for (poly = brush->polygons;poly;poly = poly->next)
1134 for (i = 0, v = poly->verts;i < poly->numverts;i++, v += 3)
1136 if (brush->mins[0] > v[0]) brush->mins[0] = v[0];if (brush->maxs[0] < v[0]) brush->maxs[0] = v[0];
1137 if (brush->mins[1] > v[1]) brush->mins[1] = v[1];if (brush->maxs[1] < v[1]) brush->maxs[1] = v[1];
1138 if (brush->mins[2] > v[2]) brush->mins[2] = v[2];if (brush->maxs[2] < v[2]) brush->maxs[2] = v[2];
1143 void Mod_ShadowBrush_ProcessWorld(mempool_t *mempool, svworld_t *world)
1146 for (clipbrush = world->brushs;clipbrush;clipbrush = clipbrush->next)
1148 for (brush = world->brushs;brush;brush = brush->next)
1150 if (brush != clipbrush
1151 && brush->mins[0] <= clipbrush->maxs[0]
1152 && brush->maxs[0] >= clipbrush->mins[0]
1153 && brush->mins[1] <= clipbrush->maxs[1]
1154 && brush->maxs[1] >= clipbrush->mins[1]
1155 && brush->mins[2] <= clipbrush->maxs[2]
1156 && brush->maxs[2] >= clipbrush->mins[2])
1158 for (poly = brush->polygons;poly;poly = poly->next)
1167 shadowmesh_t *Mod_ShadowBrush_BuildMeshs(mempool_t *mempool, svworld_t *world)
1172 mesh = Mod_ShadowMesh_Begin(mempool);
1173 for (brush = world->brushs;brush;brush = brush->next)
1174 for (poly = brush->polygons;poly;poly = poly->next)
1175 Mod_ShadowMesh_AddPolygon(mempool, mesh, poly->numverts, poly->verts);
1176 mesh = Mod_ShadowMesh_Finish(mempool, mesh);
1180 void Mod_ProcessLightList(void)
1182 int j, k, *mark, lnum;
1188 for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++)
1190 e->cullradius2 = DotProduct(e->light, e->light) * (1.0f / (8192.0f * 8192.0f)) / (e->falloff * e->falloff) + 4096.0f;
1191 if (e->cullradius2 > 4096.0f * 4096.0f)
1192 e->cullradius2 = 4096.0f * 4096.0f;
1193 e->cullradius = sqrt(e->cullradius2);
1194 leaf = Mod_PointInLeaf(e->origin, loadmodel);
1195 if (leaf->compressed_vis)
1196 pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel);
1199 for (j = 0;j < loadmodel->numsurfaces;j++)
1200 loadmodel->surfacevisframes[j] = -1;
1201 for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++)
1203 if (pvs[j >> 3] & (1 << (j & 7)))
1205 for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++)
1207 surf = loadmodel->surfaces + *mark;
1208 if (surf->number != *mark)
1209 Con_Printf("%d != %d\n", surf->number, *mark);
1210 dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
1211 if (surf->flags & SURF_PLANEBACK)
1213 if (dist > 0 && dist < e->cullradius)
1214 loadmodel->surfacevisframes[*mark] = -2;
1218 // build list of light receiving surfaces
1220 for (j = 0;j < loadmodel->numsurfaces;j++)
1221 if (loadmodel->surfacevisframes[j] == -2)
1224 if (e->numsurfaces > 0)
1226 e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
1228 for (j = 0;j < loadmodel->numsurfaces;j++)
1229 if (loadmodel->surfacevisframes[j] == -2)
1230 e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j;
1233 // find bounding box and sphere of lit surfaces
1234 // (these will be used for creating a shape to clip the light)
1235 float *v, temp[3], radius2;
1237 for (j = 0;j < e->numsurfaces;j++)
1239 surf = e->surfaces[j];
1242 VectorCopy(surf->poly_verts, e->mins);
1243 VectorCopy(surf->poly_verts, e->maxs);
1245 for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
1247 if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
1248 if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
1249 if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
1250 VectorSubtract(v, e->origin, temp);
1251 dist = DotProduct(temp, temp);
1257 if (e->cullradius2 > radius2)
1259 e->cullradius2 = radius2;
1260 e->cullradius = sqrt(e->cullradius2);
1265 // clip shadow volumes against eachother to remove unnecessary
1266 // polygons (and sections of polygons)
1268 vec3_t temp, outermins, outermaxs, innermins, innermaxs;
1270 float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
1271 float f, *v0, *v1, projectdistance;
1275 innermins[0] = e->mins[0] - 1;
1276 innermins[1] = e->mins[1] - 1;
1277 innermins[2] = e->mins[2] - 1;
1278 innermaxs[0] = e->maxs[0] + 1;
1279 innermaxs[1] = e->maxs[1] + 1;
1280 innermaxs[2] = e->maxs[2] + 1;
1281 outermins[0] = loadmodel->normalmins[0] - 1;
1282 outermins[1] = loadmodel->normalmins[1] - 1;
1283 outermins[2] = loadmodel->normalmins[2] - 1;
1284 outermaxs[0] = loadmodel->normalmaxs[0] + 1;
1285 outermaxs[1] = loadmodel->normalmaxs[1] + 1;
1286 outermaxs[2] = loadmodel->normalmaxs[2] + 1;
1287 svworld = Mod_ShadowBrush_NewWorld(loadmodel->mempool);
1288 for (j = 0, surf = loadmodel->surfaces + loadmodel->firstmodelsurface;j < loadmodel->nummodelsurfaces;j++, surf++)
1290 if (!(surf->flags & SURF_CLIPSOLID))
1292 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
1293 if (surf->flags & SURF_PLANEBACK)
1295 projectdistance = e->cullradius + f;
1296 if (projectdistance < 0.1 || projectdistance > e->cullradius)
1298 VectorSubtract(e->origin, surf->poly_center, temp);
1299 if (DotProduct(temp, temp) > (surf->poly_radius2 + e->cullradius2))
1301 if (maxverts < surf->poly_numverts)
1303 maxverts = surf->poly_numverts;
1306 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
1308 svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool);
1309 // copy the original polygon, reversed, for the front cap of the volume
1310 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
1312 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, surf->poly_numverts, verts);
1313 // project the original polygon, for the back cap of the volume
1314 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
1316 VectorSubtract(v0, e->origin, temp);
1317 VectorNormalize(temp);
1318 VectorMA(v0, projectdistance, temp, v1);
1320 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, surf->poly_numverts, verts);
1321 // project the shadow volume sides
1322 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;k++, v0 = v1, v1 += 3)
1324 VectorCopy(v0, &verts[0]);
1325 VectorCopy(v1, &verts[3]);
1326 VectorCopy(v1, &verts[6]);
1327 VectorCopy(v0, &verts[9]);
1328 VectorSubtract(&verts[6], e->origin, temp);
1329 VectorNormalize(temp);
1330 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
1331 VectorSubtract(&verts[9], e->origin, temp);
1332 VectorNormalize(temp);
1333 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
1334 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1336 Mod_ShadowBrush_EndBrush(svworld, svbrush);
1338 // add bounding box around the whole shadow volume set,
1339 // facing inward to limit light area, with an outer bounding box
1340 // facing outward (this is needed by the shadow rendering method)
1342 svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool);
1343 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
1344 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
1345 verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
1346 verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
1347 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1348 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
1349 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
1350 verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
1351 verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
1352 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1353 Mod_ShadowBrush_EndBrush(svworld, svbrush);
1355 svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool);
1356 verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
1357 verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
1358 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
1359 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
1360 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1361 verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
1362 verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
1363 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
1364 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
1365 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1366 Mod_ShadowBrush_EndBrush(svworld, svbrush);
1368 svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool);
1369 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
1370 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
1371 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
1372 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
1373 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1374 verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
1375 verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
1376 verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
1377 verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
1378 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1379 Mod_ShadowBrush_EndBrush(svworld, svbrush);
1381 svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool);
1382 verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
1383 verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
1384 verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
1385 verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
1386 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1387 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
1388 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
1389 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
1390 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
1391 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1392 Mod_ShadowBrush_EndBrush(svworld, svbrush);
1394 svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool);
1395 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
1396 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2];
1397 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2];
1398 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
1399 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1400 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
1401 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2];
1402 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2];
1403 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
1404 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1405 Mod_ShadowBrush_EndBrush(svworld, svbrush);
1407 svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool);
1408 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2];
1409 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
1410 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
1411 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2];
1412 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1413 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2];
1414 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
1415 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
1416 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2];
1417 Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts);
1418 Mod_ShadowBrush_EndBrush(svworld, svbrush);
1419 // clip away hidden polygons
1420 Mod_ShadowBrush_ProcessWorld(loadmodel->mempool, svworld);
1421 // build the triangle mesh
1422 e->shadowvolume = Mod_ShadowBrush_BuildMeshs(loadmodel->mempool, svworld);
1423 Mod_ShadowBrush_FreeWorld(svworld);
1426 // build svbsp (shadow volume bsp)
1428 int maxverts = 0, constructmode;
1429 float *verts = NULL, projectdistance, *v0, *v1, f, temp[3];
1430 svbspnode_t *svbsproot;
1431 svbsproot = Mod_SVBSP_NewTree();
1432 // we do this in three stages:
1433 // 1. construct the svbsp structure
1434 // 2. mark which leafs are dark (shadow)
1435 // 3. link polygons into only leafs that are not dark
1436 // this results in polygons that are only on the outside of the
1437 // shadow volume, removing polygons that are inside the shadow
1438 // volume (which waste time)
1439 for (constructmode = 0;constructmode < 3;constructmode++)
1441 svbsp_count_originalpolygons = 0;
1443 for (j = 0, surf = loadmodel->surfaces + loadmodel->firstmodelsurface;j < loadmodel->nummodelsurfaces;j++, surf++)
1445 if (!(surf->flags & SURF_CLIPSOLID))
1448 if (surf->poly_maxs[0] < e->mins[0]
1449 || surf->poly_mins[0] > e->maxs[0]
1450 || surf->poly_maxs[1] < e->mins[1]
1451 || surf->poly_mins[1] > e->maxs[1]
1452 || surf->poly_maxs[2] < e->mins[2]
1453 || surf->poly_mins[2] > e->maxs[2])
1456 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
1457 if (surf->flags & SURF_PLANEBACK)
1459 projectdistance = e->cullradius + f;
1460 if (projectdistance < 0.1 || projectdistance > e->cullradius)
1463 // find the nearest vertex of the projected volume
1464 for (k = 0, v0 = surf->poly_verts;k < surf->poly_numverts;k++, v0 += 3)
1466 VectorSubtract(v0, e->origin, temp);
1467 VectorNormalize(temp);
1468 if (maxdist00 > v0[0] - e->origin[0]) maxdist00 = v0[0] - e->origin[0];
1469 if (maxdist01 < e->origin[0] - v0[0]) maxdist01 = e->origin[0] - v0[0];
1470 if (maxdist10 > v0[1] - e->origin[1]) maxdist10 = v0[1] - e->origin[1];
1471 if (maxdist11 < e->origin[1] - v0[1]) maxdist11 = e->origin[1] - v0[1];
1472 if (maxdist20 > v0[2] - e->origin[2]) maxdist20 = v0[2] - e->origin[2];
1473 if (maxdist21 < e->origin[2] - v0[2]) maxdist21 = e->origin[2] - v0[2];
1476 dist = DotProduct(temp, temp);
1477 if (bestdist > dist)
1480 VectorCopy(temp, bestvec);
1483 projectdistance = e->cullradius - sqrt(bestdist);
1484 if (projectdistance < 0.1)
1486 for (k = 0, v0 = surf->poly_verts;k < surf->poly_numverts;k++, v0 += 3)
1488 VectorNormalize(temp);
1491 dist = (e->maxs[0] - e->origin[0]) / temp[0];
1494 else if (temp[0] < 0)
1495 dist = (e->mins[0] - e->origin[0]) / temp[0];
1497 VectorMA(v0, projectdistance, temp, temp);
1499 VectorSubtract(temp, e->origin,
1502 VectorSubtract(e->origin, surf->poly_center, temp);
1503 if (DotProduct(temp, temp) > (surf->poly_radius2 + e->cullradius2))
1505 if (maxverts < surf->poly_numverts)
1507 maxverts = surf->poly_numverts;
1510 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
1512 // copy the original polygon, reversed, for the front cap of the volume
1513 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
1515 Mod_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__);
1516 // project the original polygon, for the back cap of the volume
1517 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
1519 VectorSubtract(v0, e->origin, temp);
1520 VectorNormalize(temp);
1521 VectorMA(v0, projectdistance, temp, v1);
1523 Mod_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__);
1524 // project the shadow volume sides
1525 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;k++, v0 = v1, v1 += 3)
1527 VectorCopy(v0, &verts[0]);
1528 VectorCopy(v1, &verts[3]);
1529 VectorCopy(v1, &verts[6]);
1530 VectorCopy(v0, &verts[9]);
1531 VectorSubtract(&verts[6], e->origin, temp);
1532 VectorNormalize(temp);
1533 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
1534 VectorSubtract(&verts[9], e->origin, temp);
1535 VectorNormalize(temp);
1536 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
1537 Mod_SVBSP_AddPolygon(svbsproot, 4, verts, constructmode, surf->poly_center, __LINE__);
1541 for (j = 0;j < e->numsurfaces;j++)
1543 surf = e->surfaces[j];
1544 if (!(surf->flags & SURF_CLIPSOLID))
1546 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
1547 if (surf->flags & SURF_PLANEBACK)
1549 projectdistance = e->cullradius - f;
1550 if (projectdistance < 0.1 || projectdistance > e->cullradius)
1552 VectorSubtract(e->origin, surf->poly_center, temp);
1553 if (DotProduct(temp, temp) > (surf->poly_radius2 + e->cullradius2))
1555 if (maxverts < surf->poly_numverts)
1557 maxverts = surf->poly_numverts;
1560 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
1562 // copy the original polygon, for the front cap of the volume
1563 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
1565 Mod_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__);
1566 // project the original polygon, reversed, for the back cap of the volume
1567 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
1569 VectorSubtract(v0, e->origin, temp);
1570 VectorNormalize(temp);
1571 VectorMA(v0, projectdistance, temp, v1);
1573 Mod_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__);
1574 // project the shadow volume sides
1575 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;k++, v0 = v1, v1 += 3)
1577 VectorCopy(v1, &verts[0]);
1578 VectorCopy(v0, &verts[3]);
1579 VectorCopy(v0, &verts[6]);
1580 VectorCopy(v1, &verts[9]);
1581 VectorSubtract(&verts[6], e->origin, temp);
1582 VectorNormalize(temp);
1583 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
1584 VectorSubtract(&verts[9], e->origin, temp);
1585 VectorNormalize(temp);
1586 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
1587 Mod_SVBSP_AddPolygon(svbsproot, 4, verts, constructmode, surf->poly_center, __LINE__);
1595 svbsp_count_nodes = 0;
1596 svbsp_count_leafs = 0;
1597 svbsp_count_polygons = 0;
1598 svbsp_count_darkleafs = 0;
1599 svbsp_count_meshs = 0;
1600 svbsp_count_triangles = 0;
1601 svbsp_count_vertices = 0;
1602 e->shadowvolume = Mod_SVBSP_BuildTriangleMeshs(svbsproot, e->shadowvolumemins, e->shadowvolumemaxs);
1603 Mod_SVBSP_RecursiveGatherStats(svbsproot);
1604 Mod_SVBSP_FreeTree(svbsproot);
1605 Con_Printf("light %d (radius %d) has %d surfaces, svbsp contains %d nodes, %d leafs, %d are dark (%d%%), %d original polygons, %d polygons stored (%d%%), %d meshs %d vertices %d triangles\n", lnum, (int)e->cullradius, e->numsurfaces, svbsp_count_nodes, svbsp_count_leafs, svbsp_count_darkleafs, svbsp_count_leafs ? (100 * svbsp_count_darkleafs / svbsp_count_leafs) : 0, svbsp_count_originalpolygons, svbsp_count_polygons, svbsp_count_originalpolygons ? (100 * svbsp_count_polygons / svbsp_count_originalpolygons) : 0, svbsp_count_meshs, svbsp_count_triangles, svbsp_count_vertices);
1617 static void Mod_LoadVisibility (lump_t *l)
1619 loadmodel->visdata = NULL;
1622 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
1623 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
1626 // used only for HalfLife maps
1627 void Mod_ParseWadsFromEntityLump(const char *data)
1629 char key[128], value[4096];
1634 if (!COM_ParseToken(&data))
1636 if (com_token[0] != '{')
1640 if (!COM_ParseToken(&data))
1642 if (com_token[0] == '}')
1643 break; // end of worldspawn
1644 if (com_token[0] == '_')
1645 strcpy(key, com_token + 1);
1647 strcpy(key, com_token);
1648 while (key[strlen(key)-1] == ' ') // remove trailing spaces
1649 key[strlen(key)-1] = 0;
1650 if (!COM_ParseToken(&data))
1652 strcpy(value, com_token);
1653 if (!strcmp("wad", key)) // for HalfLife maps
1655 if (loadmodel->ishlbsp)
1658 for (i = 0;i < 4096;i++)
1659 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
1665 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
1666 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
1668 else if (value[i] == ';' || value[i] == 0)
1672 strcpy(wadname, "textures/");
1673 strcat(wadname, &value[j]);
1674 W_LoadTextureWadFile (wadname, false);
1691 static void Mod_LoadEntities (lump_t *l)
1693 loadmodel->entities = NULL;
1696 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
1697 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
1698 if (loadmodel->ishlbsp)
1699 Mod_ParseWadsFromEntityLump(loadmodel->entities);
1708 static void Mod_LoadVertexes (lump_t *l)
1714 in = (void *)(mod_base + l->fileofs);
1715 if (l->filelen % sizeof(*in))
1716 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1717 count = l->filelen / sizeof(*in);
1718 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1720 loadmodel->vertexes = out;
1721 loadmodel->numvertexes = count;
1723 for ( i=0 ; i<count ; i++, in++, out++)
1725 out->position[0] = LittleFloat (in->point[0]);
1726 out->position[1] = LittleFloat (in->point[1]);
1727 out->position[2] = LittleFloat (in->point[2]);
1736 static void Mod_LoadSubmodels (lump_t *l)
1742 in = (void *)(mod_base + l->fileofs);
1743 if (l->filelen % sizeof(*in))
1744 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1745 count = l->filelen / sizeof(*in);
1746 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1748 loadmodel->submodels = out;
1749 loadmodel->numsubmodels = count;
1751 for ( i=0 ; i<count ; i++, in++, out++)
1753 for (j=0 ; j<3 ; j++)
1755 // spread the mins / maxs by a pixel
1756 out->mins[j] = LittleFloat (in->mins[j]) - 1;
1757 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
1758 out->origin[j] = LittleFloat (in->origin[j]);
1760 for (j=0 ; j<MAX_MAP_HULLS ; j++)
1761 out->headnode[j] = LittleLong (in->headnode[j]);
1762 out->visleafs = LittleLong (in->visleafs);
1763 out->firstface = LittleLong (in->firstface);
1764 out->numfaces = LittleLong (in->numfaces);
1773 static void Mod_LoadEdges (lump_t *l)
1779 in = (void *)(mod_base + l->fileofs);
1780 if (l->filelen % sizeof(*in))
1781 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1782 count = l->filelen / sizeof(*in);
1783 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1785 loadmodel->edges = out;
1786 loadmodel->numedges = count;
1788 for ( i=0 ; i<count ; i++, in++, out++)
1790 out->v[0] = (unsigned short)LittleShort(in->v[0]);
1791 out->v[1] = (unsigned short)LittleShort(in->v[1]);
1800 static void Mod_LoadTexinfo (lump_t *l)
1804 int i, j, k, count, miptex;
1806 in = (void *)(mod_base + l->fileofs);
1807 if (l->filelen % sizeof(*in))
1808 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1809 count = l->filelen / sizeof(*in);
1810 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1812 loadmodel->texinfo = out;
1813 loadmodel->numtexinfo = count;
1815 for (i = 0;i < count;i++, in++, out++)
1817 for (k = 0;k < 2;k++)
1818 for (j = 0;j < 4;j++)
1819 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
1821 miptex = LittleLong (in->miptex);
1822 out->flags = LittleLong (in->flags);
1824 out->texture = NULL;
1825 if (loadmodel->textures)
1827 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
1828 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
1830 out->texture = loadmodel->textures + miptex;
1832 if (out->flags & TEX_SPECIAL)
1834 // if texture chosen is NULL or the shader needs a lightmap,
1835 // force to notexture water shader
1836 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
1837 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
1841 // if texture chosen is NULL, force to notexture
1842 if (out->texture == NULL)
1843 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
1852 Fills in s->texturemins[] and s->extents[]
1855 static void CalcSurfaceExtents (msurface_t *s)
1857 float mins[2], maxs[2], val;
1861 int bmins[2], bmaxs[2];
1863 mins[0] = mins[1] = 999999999;
1864 maxs[0] = maxs[1] = -999999999;
1868 for (i=0 ; i<s->numedges ; i++)
1870 e = loadmodel->surfedges[s->firstedge+i];
1872 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
1874 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
1876 for (j=0 ; j<2 ; j++)
1878 val = v->position[0] * tex->vecs[j][0] +
1879 v->position[1] * tex->vecs[j][1] +
1880 v->position[2] * tex->vecs[j][2] +
1889 for (i=0 ; i<2 ; i++)
1891 bmins[i] = floor(mins[i]/16);
1892 bmaxs[i] = ceil(maxs[i]/16);
1894 s->texturemins[i] = bmins[i] * 16;
1895 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
1900 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1905 mins[0] = mins[1] = mins[2] = 9999;
1906 maxs[0] = maxs[1] = maxs[2] = -9999;
1908 for (i = 0;i < numverts;i++)
1910 for (j = 0;j < 3;j++, v++)
1921 #define MAX_SUBDIVPOLYTRIANGLES 4096
1922 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1924 static int subdivpolyverts, subdivpolytriangles;
1925 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1926 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1928 static int subdivpolylookupvert(vec3_t v)
1931 for (i = 0;i < subdivpolyverts;i++)
1932 if (subdivpolyvert[i][0] == v[0]
1933 && subdivpolyvert[i][1] == v[1]
1934 && subdivpolyvert[i][2] == v[2])
1936 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1937 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1938 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1939 return subdivpolyverts++;
1942 static void SubdividePolygon (int numverts, float *verts)
1944 int i, i1, i2, i3, f, b, c, p;
1945 vec3_t mins, maxs, front[256], back[256];
1946 float m, *pv, *cv, dist[256], frac;
1949 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1951 BoundPoly (numverts, verts, mins, maxs);
1953 for (i = 0;i < 3;i++)
1955 m = (mins[i] + maxs[i]) * 0.5;
1956 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1957 if (maxs[i] - m < 8)
1959 if (m - mins[i] < 8)
1963 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1964 dist[c] = cv[i] - m;
1967 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1971 VectorCopy (pv, front[f]);
1976 VectorCopy (pv, back[b]);
1979 if (dist[p] == 0 || dist[c] == 0)
1981 if ( (dist[p] > 0) != (dist[c] > 0) )
1984 frac = dist[p] / (dist[p] - dist[c]);
1985 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1986 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1987 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1993 SubdividePolygon (f, front[0]);
1994 SubdividePolygon (b, back[0]);
1998 i1 = subdivpolylookupvert(verts);
1999 i2 = subdivpolylookupvert(verts + 3);
2000 for (i = 2;i < numverts;i++)
2002 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
2004 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
2008 i3 = subdivpolylookupvert(verts + i * 3);
2009 subdivpolyindex[subdivpolytriangles][0] = i1;
2010 subdivpolyindex[subdivpolytriangles][1] = i2;
2011 subdivpolyindex[subdivpolytriangles][2] = i3;
2013 subdivpolytriangles++;
2019 Mod_GenerateWarpMesh
2021 Breaks a polygon up along axial 64 unit
2022 boundaries so that turbulent and sky warps
2023 can be done reasonably.
2026 void Mod_GenerateWarpMesh (msurface_t *surf)
2032 subdivpolytriangles = 0;
2033 subdivpolyverts = 0;
2034 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
2035 if (subdivpolytriangles < 1)
2036 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
2038 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
2039 mesh->numverts = subdivpolyverts;
2040 mesh->numtriangles = subdivpolytriangles;
2041 mesh->vertex = (surfvertex_t *)(mesh + 1);
2042 mesh->index = (int *)(mesh->vertex + mesh->numverts);
2043 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
2045 for (i = 0;i < mesh->numtriangles;i++)
2046 for (j = 0;j < 3;j++)
2047 mesh->index[i*3+j] = subdivpolyindex[i][j];
2049 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
2051 VectorCopy(subdivpolyvert[i], v->v);
2052 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
2053 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
2058 void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
2060 int i, iu, iv, *index, smax, tmax;
2061 float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
2064 smax = surf->extents[0] >> 4;
2065 tmax = surf->extents[1] >> 4;
2069 surf->lightmaptexturestride = 0;
2070 surf->lightmaptexture = NULL;
2078 surf->flags |= SURF_LIGHTMAP;
2079 if (r_miplightmaps.integer)
2081 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
2082 surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_PRECACHE);
2086 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
2087 surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE);
2089 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
2090 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
2091 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
2094 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[6]) + surf->poly_numverts * (4 + 4 + 4 + 4 + 1 + 3) * sizeof(float));
2095 mesh->numverts = surf->poly_numverts;
2096 mesh->numtriangles = surf->poly_numverts - 2;
2097 mesh->verts = (float *)(mesh + 1);
2098 mesh->str = mesh->verts + mesh->numverts * 4;
2099 mesh->uvw = mesh->str + mesh->numverts * 4;
2100 mesh->abc = mesh->uvw + mesh->numverts * 4;
2101 mesh->lightmapoffsets = (int *)(mesh->abc + mesh->numverts * 4);
2102 mesh->index = mesh->lightmapoffsets + mesh->numverts;
2103 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
2104 mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3);
2106 index = mesh->index;
2107 for (i = 0;i < mesh->numtriangles;i++)
2113 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
2115 VectorCopy(surf->plane->normal, normal);
2116 if (surf->flags & SURF_PLANEBACK)
2117 VectorNegate(normal, normal);
2118 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
2120 s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
2121 t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
2122 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
2123 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
2124 // LordHavoc: calc lightmap data offset for vertex lighting to use
2127 iu = bound(0, iu, smax);
2128 iv = bound(0, iv, tmax);
2129 u = u * uscale + ubase;
2130 v = v * vscale + vbase;
2132 mesh->verts[i * 4 + 0] = in[0];
2133 mesh->verts[i * 4 + 1] = in[1];
2134 mesh->verts[i * 4 + 2] = in[2];
2135 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
2136 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
2137 mesh->uvw[i * 4 + 0] = u;
2138 mesh->uvw[i * 4 + 1] = v;
2139 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
2140 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
2141 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
2142 mesh->normals[i * 3 + 0] = normal[0];
2143 mesh->normals[i * 3 + 1] = normal[1];
2144 mesh->normals[i * 3 + 2] = normal[2];
2148 void Mod_GenerateVertexMesh (msurface_t *surf)
2151 float *in, s, t, normal[3];
2154 surf->lightmaptexturestride = 0;
2155 surf->lightmaptexture = NULL;
2157 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[6]) + surf->poly_numverts * (4 + 4 + 4 + 3) * sizeof(float));
2158 mesh->numverts = surf->poly_numverts;
2159 mesh->numtriangles = surf->poly_numverts - 2;
2160 mesh->verts = (float *)(mesh + 1);
2161 mesh->str = mesh->verts + mesh->numverts * 4;
2162 mesh->abc = mesh->str + mesh->numverts * 4;
2163 mesh->index = (int *)(mesh->abc + mesh->numverts * 4);
2164 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
2165 mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3);
2167 index = mesh->index;
2168 for (i = 0;i < mesh->numtriangles;i++)
2174 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
2176 VectorCopy(surf->plane->normal, normal);
2177 if (surf->flags & SURF_PLANEBACK)
2178 VectorNegate(normal, normal);
2179 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
2181 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
2182 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
2183 mesh->verts[i * 4 + 0] = in[0];
2184 mesh->verts[i * 4 + 1] = in[1];
2185 mesh->verts[i * 4 + 2] = in[2];
2186 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
2187 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
2188 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
2189 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
2190 mesh->normals[i * 3 + 0] = normal[0];
2191 mesh->normals[i * 3 + 1] = normal[1];
2192 mesh->normals[i * 3 + 2] = normal[2];
2196 void Mod_GenerateSurfacePolygon (msurface_t *surf)
2199 float *vec, *vert, mins[3], maxs[3], temp[3], dist;
2201 // convert edges back to a normal polygon
2202 surf->poly_numverts = surf->numedges;
2203 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
2204 for (i = 0;i < surf->numedges;i++)
2206 lindex = loadmodel->surfedges[surf->firstedge + i];
2208 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
2210 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
2211 VectorCopy (vec, vert);
2214 vert = surf->poly_verts;
2215 VectorCopy(vert, mins);
2216 VectorCopy(vert, maxs);
2218 for (i = 1;i < surf->poly_numverts;i++)
2220 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
2221 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
2222 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
2225 VectorCopy(mins, surf->poly_mins);
2226 VectorCopy(maxs, surf->poly_maxs);
2227 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
2228 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
2229 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
2230 surf->poly_radius2 = 0;
2231 vert = surf->poly_verts;
2232 for (i = 0;i < surf->poly_numverts;i++)
2234 VectorSubtract(vert, surf->poly_center, temp);
2235 dist = DotProduct(temp, temp);
2236 if (surf->poly_radius2 < dist)
2237 surf->poly_radius2 = dist;
2240 surf->poly_radius = sqrt(surf->poly_radius2);
2248 static void Mod_LoadFaces (lump_t *l)
2252 int i, count, surfnum, planenum, ssize, tsize;
2254 in = (void *)(mod_base + l->fileofs);
2255 if (l->filelen % sizeof(*in))
2256 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
2257 count = l->filelen / sizeof(*in);
2258 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
2260 loadmodel->surfaces = out;
2261 loadmodel->numsurfaces = count;
2262 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
2263 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
2265 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
2267 out->number = surfnum;
2268 // FIXME: validate edges, texinfo, etc?
2269 out->firstedge = LittleLong(in->firstedge);
2270 out->numedges = LittleShort(in->numedges);
2271 if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges)
2272 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges);
2274 i = LittleShort (in->texinfo);
2275 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
2276 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
2277 out->texinfo = loadmodel->texinfo + i;
2278 out->flags = out->texinfo->texture->flags;
2280 planenum = LittleShort(in->planenum);
2281 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
2282 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
2284 if (LittleShort(in->side))
2285 out->flags |= SURF_PLANEBACK;
2287 out->plane = loadmodel->planes + planenum;
2289 // clear lightmap (filled in later)
2290 out->lightmaptexture = NULL;
2292 // force lightmap upload on first time seeing the surface
2293 out->cached_dlight = true;
2295 CalcSurfaceExtents (out);
2297 ssize = (out->extents[0] >> 4) + 1;
2298 tsize = (out->extents[1] >> 4) + 1;
2301 for (i = 0;i < MAXLIGHTMAPS;i++)
2302 out->styles[i] = in->styles[i];
2303 i = LittleLong(in->lightofs);
2305 out->samples = NULL;
2306 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
2307 out->samples = loadmodel->lightdata + i;
2308 else // LordHavoc: white lighting (bsp version 29)
2309 out->samples = loadmodel->lightdata + (i * 3);
2311 Mod_GenerateSurfacePolygon(out);
2312 if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
2314 if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
2315 Host_Error ("Bad surface extents");
2316 Mod_GenerateWallMesh (out, false);
2317 // stainmap for permanent marks on walls
2318 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
2320 memset(out->stainsamples, 255, ssize * tsize * 3);
2323 Mod_GenerateVertexMesh (out);
2332 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
2334 node->parent = parent;
2335 if (node->contents < 0)
2337 Mod_SetParent (node->children[0], node);
2338 Mod_SetParent (node->children[1], node);
2346 static void Mod_LoadNodes (lump_t *l)
2352 in = (void *)(mod_base + l->fileofs);
2353 if (l->filelen % sizeof(*in))
2354 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
2355 count = l->filelen / sizeof(*in);
2356 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
2358 loadmodel->nodes = out;
2359 loadmodel->numnodes = count;
2361 for ( i=0 ; i<count ; i++, in++, out++)
2363 for (j=0 ; j<3 ; j++)
2365 out->mins[j] = LittleShort (in->mins[j]);
2366 out->maxs[j] = LittleShort (in->maxs[j]);
2369 p = LittleLong(in->planenum);
2370 out->plane = loadmodel->planes + p;
2372 out->firstsurface = LittleShort (in->firstface);
2373 out->numsurfaces = LittleShort (in->numfaces);
2375 for (j=0 ; j<2 ; j++)
2377 p = LittleShort (in->children[j]);
2379 out->children[j] = loadmodel->nodes + p;
2381 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
2385 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
2393 static void Mod_LoadLeafs (lump_t *l)
2399 in = (void *)(mod_base + l->fileofs);
2400 if (l->filelen % sizeof(*in))
2401 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
2402 count = l->filelen / sizeof(*in);
2403 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
2405 loadmodel->leafs = out;
2406 loadmodel->numleafs = count;
2408 for ( i=0 ; i<count ; i++, in++, out++)
2410 for (j=0 ; j<3 ; j++)
2412 out->mins[j] = LittleShort (in->mins[j]);
2413 out->maxs[j] = LittleShort (in->maxs[j]);
2416 p = LittleLong(in->contents);
2419 out->firstmarksurface = loadmodel->marksurfaces +
2420 LittleShort(in->firstmarksurface);
2421 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
2423 p = LittleLong(in->visofs);
2425 out->compressed_vis = NULL;
2427 out->compressed_vis = loadmodel->visdata + p;
2429 for (j=0 ; j<4 ; j++)
2430 out->ambient_sound_level[j] = in->ambient_level[j];
2432 // FIXME: Insert caustics here
2441 static void Mod_LoadClipnodes (lump_t *l)
2443 dclipnode_t *in, *out;
2447 in = (void *)(mod_base + l->fileofs);
2448 if (l->filelen % sizeof(*in))
2449 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
2450 count = l->filelen / sizeof(*in);
2451 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
2453 loadmodel->clipnodes = out;
2454 loadmodel->numclipnodes = count;
2456 if (loadmodel->ishlbsp)
2458 hull = &loadmodel->hulls[1];
2459 hull->clipnodes = out;
2460 hull->firstclipnode = 0;
2461 hull->lastclipnode = count-1;
2462 hull->planes = loadmodel->planes;
2463 hull->clip_mins[0] = -16;
2464 hull->clip_mins[1] = -16;
2465 hull->clip_mins[2] = -36;
2466 hull->clip_maxs[0] = 16;
2467 hull->clip_maxs[1] = 16;
2468 hull->clip_maxs[2] = 36;
2469 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
2471 hull = &loadmodel->hulls[2];
2472 hull->clipnodes = out;
2473 hull->firstclipnode = 0;
2474 hull->lastclipnode = count-1;
2475 hull->planes = loadmodel->planes;
2476 hull->clip_mins[0] = -32;
2477 hull->clip_mins[1] = -32;
2478 hull->clip_mins[2] = -32;
2479 hull->clip_maxs[0] = 32;
2480 hull->clip_maxs[1] = 32;
2481 hull->clip_maxs[2] = 32;
2482 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
2484 hull = &loadmodel->hulls[3];
2485 hull->clipnodes = out;
2486 hull->firstclipnode = 0;
2487 hull->lastclipnode = count-1;
2488 hull->planes = loadmodel->planes;
2489 hull->clip_mins[0] = -16;
2490 hull->clip_mins[1] = -16;
2491 hull->clip_mins[2] = -18;
2492 hull->clip_maxs[0] = 16;
2493 hull->clip_maxs[1] = 16;
2494 hull->clip_maxs[2] = 18;
2495 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
2499 hull = &loadmodel->hulls[1];
2500 hull->clipnodes = out;
2501 hull->firstclipnode = 0;
2502 hull->lastclipnode = count-1;
2503 hull->planes = loadmodel->planes;
2504 hull->clip_mins[0] = -16;
2505 hull->clip_mins[1] = -16;
2506 hull->clip_mins[2] = -24;
2507 hull->clip_maxs[0] = 16;
2508 hull->clip_maxs[1] = 16;
2509 hull->clip_maxs[2] = 32;
2510 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
2512 hull = &loadmodel->hulls[2];
2513 hull->clipnodes = out;
2514 hull->firstclipnode = 0;
2515 hull->lastclipnode = count-1;
2516 hull->planes = loadmodel->planes;
2517 hull->clip_mins[0] = -32;
2518 hull->clip_mins[1] = -32;
2519 hull->clip_mins[2] = -24;
2520 hull->clip_maxs[0] = 32;
2521 hull->clip_maxs[1] = 32;
2522 hull->clip_maxs[2] = 64;
2523 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
2526 for (i=0 ; i<count ; i++, out++, in++)
2528 out->planenum = LittleLong(in->planenum);
2529 out->children[0] = LittleShort(in->children[0]);
2530 out->children[1] = LittleShort(in->children[1]);
2531 if (out->children[0] >= count || out->children[1] >= count)
2532 Host_Error("Corrupt clipping hull (out of range child)\n");
2540 Duplicate the drawing hull structure as a clipping hull
2543 static void Mod_MakeHull0 (void)
2550 hull = &loadmodel->hulls[0];
2552 in = loadmodel->nodes;
2553 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
2555 hull->clipnodes = out;
2556 hull->firstclipnode = 0;
2557 hull->lastclipnode = loadmodel->numnodes - 1;
2558 hull->planes = loadmodel->planes;
2560 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
2562 out->planenum = in->plane - loadmodel->planes;
2563 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
2564 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
2570 Mod_LoadMarksurfaces
2573 static void Mod_LoadMarksurfaces (lump_t *l)
2578 in = (void *)(mod_base + l->fileofs);
2579 if (l->filelen % sizeof(*in))
2580 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
2581 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
2582 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
2584 for (i = 0;i < loadmodel->nummarksurfaces;i++)
2586 j = (unsigned) LittleShort(in[i]);
2587 if (j >= loadmodel->numsurfaces)
2588 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
2589 loadmodel->marksurfaces[i] = j;
2598 static void Mod_LoadSurfedges (lump_t *l)
2603 in = (void *)(mod_base + l->fileofs);
2604 if (l->filelen % sizeof(*in))
2605 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
2606 loadmodel->numsurfedges = l->filelen / sizeof(*in);
2607 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
2609 for (i = 0;i < loadmodel->numsurfedges;i++)
2610 loadmodel->surfedges[i] = LittleLong (in[i]);
2619 static void Mod_LoadPlanes (lump_t *l)
2625 in = (void *)(mod_base + l->fileofs);
2626 if (l->filelen % sizeof(*in))
2627 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
2629 loadmodel->numplanes = l->filelen / sizeof(*in);
2630 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
2632 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
2634 out->normal[0] = LittleFloat (in->normal[0]);
2635 out->normal[1] = LittleFloat (in->normal[1]);
2636 out->normal[2] = LittleFloat (in->normal[2]);
2637 out->dist = LittleFloat (in->dist);
2643 #define MAX_POINTS_ON_WINDING 64
2649 double points[8][3]; // variable sized
2658 static winding_t *NewWinding (int points)
2663 if (points > MAX_POINTS_ON_WINDING)
2664 Sys_Error("NewWinding: too many points\n");
2666 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
2667 w = Mem_Alloc(loadmodel->mempool, size);
2668 memset (w, 0, size);
2673 static void FreeWinding (winding_t *w)
2683 static winding_t *BaseWindingForPlane (mplane_t *p)
2685 double org[3], vright[3], vup[3], normal[3];
2688 VectorCopy(p->normal, normal);
2689 VectorVectorsDouble(normal, vright, vup);
2691 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
2692 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
2694 // project a really big axis aligned box onto the plane
2697 VectorScale (p->normal, p->dist, org);
2699 VectorSubtract (org, vright, w->points[0]);
2700 VectorAdd (w->points[0], vup, w->points[0]);
2702 VectorAdd (org, vright, w->points[1]);
2703 VectorAdd (w->points[1], vup, w->points[1]);
2705 VectorAdd (org, vright, w->points[2]);
2706 VectorSubtract (w->points[2], vup, w->points[2]);
2708 VectorSubtract (org, vright, w->points[3]);
2709 VectorSubtract (w->points[3], vup, w->points[3]);
2720 Clips the winding to the plane, returning the new winding on the positive side
2721 Frees the input winding.
2722 If keepon is true, an exactly on-plane winding will be saved, otherwise
2723 it will be clipped away.
2726 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2728 double dists[MAX_POINTS_ON_WINDING + 1];
2729 int sides[MAX_POINTS_ON_WINDING + 1];
2738 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2740 // determine sides for each point
2741 for (i = 0;i < in->numpoints;i++)
2743 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2744 if (dot > ON_EPSILON)
2745 sides[i] = SIDE_FRONT;
2746 else if (dot < -ON_EPSILON)
2747 sides[i] = SIDE_BACK;
2752 sides[i] = sides[0];
2753 dists[i] = dists[0];
2755 if (keepon && !counts[0] && !counts[1])
2766 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2767 if (maxpts > MAX_POINTS_ON_WINDING)
2768 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2770 neww = NewWinding (maxpts);
2772 for (i = 0;i < in->numpoints;i++)
2774 if (neww->numpoints >= maxpts)
2775 Sys_Error ("ClipWinding: points exceeded estimate");
2779 if (sides[i] == SIDE_ON)
2781 VectorCopy (p1, neww->points[neww->numpoints]);
2786 if (sides[i] == SIDE_FRONT)
2788 VectorCopy (p1, neww->points[neww->numpoints]);
2792 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2795 // generate a split point
2796 p2 = in->points[(i+1)%in->numpoints];
2798 dot = dists[i] / (dists[i]-dists[i+1]);
2799 for (j = 0;j < 3;j++)
2800 { // avoid round off error when possible
2801 if (split->normal[j] == 1)
2802 mid[j] = split->dist;
2803 else if (split->normal[j] == -1)
2804 mid[j] = -split->dist;
2806 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2809 VectorCopy (mid, neww->points[neww->numpoints]);
2813 // free the original winding
2824 Divides a winding by a plane, producing one or two windings. The
2825 original winding is not damaged or freed. If only on one side, the
2826 returned winding will be the input winding. If on both sides, two
2827 new windings will be created.
2830 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2832 double dists[MAX_POINTS_ON_WINDING + 1];
2833 int sides[MAX_POINTS_ON_WINDING + 1];
2842 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2844 // determine sides for each point
2845 for (i = 0;i < in->numpoints;i++)
2847 dot = DotProduct (in->points[i], split->normal);
2850 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2851 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2852 else sides[i] = SIDE_ON;
2855 sides[i] = sides[0];
2856 dists[i] = dists[0];
2858 *front = *back = NULL;
2871 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2873 if (maxpts > MAX_POINTS_ON_WINDING)
2874 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2876 *front = f = NewWinding (maxpts);
2877 *back = b = NewWinding (maxpts);
2879 for (i = 0;i < in->numpoints;i++)
2881 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2882 Sys_Error ("DivideWinding: points exceeded estimate");
2886 if (sides[i] == SIDE_ON)
2888 VectorCopy (p1, f->points[f->numpoints]);
2890 VectorCopy (p1, b->points[b->numpoints]);
2895 if (sides[i] == SIDE_FRONT)
2897 VectorCopy (p1, f->points[f->numpoints]);
2900 else if (sides[i] == SIDE_BACK)
2902 VectorCopy (p1, b->points[b->numpoints]);
2906 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2909 // generate a split point
2910 p2 = in->points[(i+1)%in->numpoints];
2912 dot = dists[i] / (dists[i]-dists[i+1]);
2913 for (j = 0;j < 3;j++)
2914 { // avoid round off error when possible
2915 if (split->normal[j] == 1)
2916 mid[j] = split->dist;
2917 else if (split->normal[j] == -1)
2918 mid[j] = -split->dist;
2920 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2923 VectorCopy (mid, f->points[f->numpoints]);
2925 VectorCopy (mid, b->points[b->numpoints]);
2930 typedef struct portal_s
2933 mnode_t *nodes[2]; // [0] = front side of plane
2934 struct portal_s *next[2];
2936 struct portal_s *chain; // all portals are linked into a list
2940 static portal_t *portalchain;
2947 static portal_t *AllocPortal (void)
2950 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2951 p->chain = portalchain;
2956 static void FreePortal(portal_t *p)
2961 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2963 // calculate children first
2964 if (node->children[0]->contents >= 0)
2965 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2966 if (node->children[1]->contents >= 0)
2967 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2969 // make combined bounding box from children
2970 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2971 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2972 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2973 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2974 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2975 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2978 static void Mod_FinalizePortals(void)
2980 int i, j, numportals, numpoints;
2981 portal_t *p, *pnext;
2984 mleaf_t *leaf, *endleaf;
2987 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2988 leaf = loadmodel->leafs;
2989 endleaf = leaf + loadmodel->numleafs;
2990 for (;leaf < endleaf;leaf++)
2992 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2993 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
3000 for (i = 0;i < 2;i++)
3002 leaf = (mleaf_t *)p->nodes[i];
3004 for (j = 0;j < w->numpoints;j++)
3006 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
3007 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
3008 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
3009 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
3010 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
3011 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
3018 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
3020 // tally up portal and point counts
3026 // note: this check must match the one below or it will usually corrupt memory
3027 // 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
3028 if (p->winding && p->nodes[0] != p->nodes[1]
3029 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
3030 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
3033 numpoints += p->winding->numpoints * 2;
3037 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
3038 loadmodel->numportals = numportals;
3039 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
3040 loadmodel->numportalpoints = numpoints;
3041 // clear all leaf portal chains
3042 for (i = 0;i < loadmodel->numleafs;i++)
3043 loadmodel->leafs[i].portals = NULL;
3044 // process all portals in the global portal chain, while freeing them
3045 portal = loadmodel->portals;
3046 point = loadmodel->portalpoints;
3055 // note: this check must match the one above or it will usually corrupt memory
3056 // 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
3057 if (p->nodes[0] != p->nodes[1]
3058 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
3059 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
3061 // first make the back to front portal (forward portal)
3062 portal->points = point;
3063 portal->numpoints = p->winding->numpoints;
3064 portal->plane.dist = p->plane.dist;
3065 VectorCopy(p->plane.normal, portal->plane.normal);
3066 portal->here = (mleaf_t *)p->nodes[1];
3067 portal->past = (mleaf_t *)p->nodes[0];
3069 for (j = 0;j < portal->numpoints;j++)
3071 VectorCopy(p->winding->points[j], point->position);
3074 PlaneClassify(&portal->plane);
3076 // link into leaf's portal chain
3077 portal->next = portal->here->portals;
3078 portal->here->portals = portal;
3080 // advance to next portal
3083 // then make the front to back portal (backward portal)
3084 portal->points = point;
3085 portal->numpoints = p->winding->numpoints;
3086 portal->plane.dist = -p->plane.dist;
3087 VectorNegate(p->plane.normal, portal->plane.normal);
3088 portal->here = (mleaf_t *)p->nodes[0];
3089 portal->past = (mleaf_t *)p->nodes[1];
3091 for (j = portal->numpoints - 1;j >= 0;j--)
3093 VectorCopy(p->winding->points[j], point->position);
3096 PlaneClassify(&portal->plane);
3098 // link into leaf's portal chain
3099 portal->next = portal->here->portals;
3100 portal->here->portals = portal;
3102 // advance to next portal
3105 FreeWinding(p->winding);
3117 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
3120 Host_Error ("AddPortalToNodes: NULL front node");
3122 Host_Error ("AddPortalToNodes: NULL back node");
3123 if (p->nodes[0] || p->nodes[1])
3124 Host_Error ("AddPortalToNodes: already included");
3125 // 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
3127 p->nodes[0] = front;
3128 p->next[0] = (portal_t *)front->portals;
3129 front->portals = (mportal_t *)p;
3132 p->next[1] = (portal_t *)back->portals;
3133 back->portals = (mportal_t *)p;
3138 RemovePortalFromNode
3141 static void RemovePortalFromNodes(portal_t *portal)
3145 void **portalpointer;
3147 for (i = 0;i < 2;i++)
3149 node = portal->nodes[i];
3151 portalpointer = (void **) &node->portals;
3156 Host_Error ("RemovePortalFromNodes: portal not in leaf");
3160 if (portal->nodes[0] == node)
3162 *portalpointer = portal->next[0];
3163 portal->nodes[0] = NULL;
3165 else if (portal->nodes[1] == node)
3167 *portalpointer = portal->next[1];
3168 portal->nodes[1] = NULL;
3171 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
3175 if (t->nodes[0] == node)
3176 portalpointer = (void **) &t->next[0];
3177 else if (t->nodes[1] == node)
3178 portalpointer = (void **) &t->next[1];
3180 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
3185 static void Mod_RecursiveNodePortals (mnode_t *node)
3188 mnode_t *front, *back, *other_node;
3189 mplane_t clipplane, *plane;
3190 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
3191 winding_t *nodeportalwinding, *frontwinding, *backwinding;
3193 // if a leaf, we're done
3197 plane = node->plane;
3199 front = node->children[0];
3200 back = node->children[1];
3202 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
3204 // create the new portal by generating a polygon for the node plane,
3205 // and clipping it by all of the other portals (which came from nodes above this one)
3206 nodeportal = AllocPortal ();
3207 nodeportal->plane = *node->plane;
3209 nodeportalwinding = BaseWindingForPlane (node->plane);
3210 side = 0; // shut up compiler warning
3211 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
3213 clipplane = portal->plane;
3214 if (portal->nodes[0] == portal->nodes[1])
3215 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
3216 if (portal->nodes[0] == node)
3218 else if (portal->nodes[1] == node)
3220 clipplane.dist = -clipplane.dist;
3221 VectorNegate (clipplane.normal, clipplane.normal);
3225 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
3227 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
3228 if (!nodeportalwinding)
3230 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
3235 if (nodeportalwinding)
3237 // if the plane was not clipped on all sides, there was an error
3238 nodeportal->winding = nodeportalwinding;
3239 AddPortalToNodes (nodeportal, front, back);
3242 // split the portals of this node along this node's plane and assign them to the children of this node
3243 // (migrating the portals downward through the tree)
3244 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
3246 if (portal->nodes[0] == portal->nodes[1])
3247 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
3248 if (portal->nodes[0] == node)
3250 else if (portal->nodes[1] == node)
3253 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
3254 nextportal = portal->next[side];
3256 other_node = portal->nodes[!side];
3257 RemovePortalFromNodes (portal);
3259 // cut the portal into two portals, one on each side of the node plane
3260 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
3265 AddPortalToNodes (portal, back, other_node);
3267 AddPortalToNodes (portal, other_node, back);
3273 AddPortalToNodes (portal, front, other_node);
3275 AddPortalToNodes (portal, other_node, front);
3279 // the winding is split
3280 splitportal = AllocPortal ();
3281 temp = splitportal->chain;
3282 *splitportal = *portal;
3283 splitportal->chain = temp;
3284 splitportal->winding = backwinding;
3285 FreeWinding (portal->winding);
3286 portal->winding = frontwinding;
3290 AddPortalToNodes (portal, front, other_node);
3291 AddPortalToNodes (splitportal, back, other_node);
3295 AddPortalToNodes (portal, other_node, front);
3296 AddPortalToNodes (splitportal, other_node, back);
3300 Mod_RecursiveNodePortals(front);
3301 Mod_RecursiveNodePortals(back);
3305 static void Mod_MakePortals(void)
3308 Mod_RecursiveNodePortals (loadmodel->nodes);
3309 Mod_FinalizePortals();
3317 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
3318 extern void R_Model_Brush_Draw(entity_render_t *ent);
3319 //extern void R_Model_Brush_DrawFakeShadow(entity_render_t *ent);
3320 extern void R_Model_Brush_DrawDepth(entity_render_t *ent);
3321 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume);
3322 extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor);
3323 extern void R_Model_Brush_DrawOntoLight(entity_render_t *ent);
3324 void Mod_LoadBrushModel (model_t *mod, void *buffer)
3329 mempool_t *mainmempool;
3331 model_t *originalloadmodel;
3333 mod->type = mod_brush;
3335 header = (dheader_t *)buffer;
3337 i = LittleLong (header->version);
3338 if (i != BSPVERSION && i != 30)
3339 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
3340 mod->ishlbsp = i == 30;
3341 if (loadmodel->isworldmodel)
3343 Cvar_SetValue("halflifebsp", mod->ishlbsp);
3344 // until we get a texture for it...
3348 // swap all the lumps
3349 mod_base = (qbyte *)header;
3351 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
3352 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
3356 // store which lightmap format to use
3357 mod->lightmaprgba = r_lightmaprgba.integer;
3359 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
3360 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
3361 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
3362 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
3363 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
3364 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
3365 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
3366 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
3367 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
3368 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
3369 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
3370 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
3371 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
3372 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
3373 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
3378 mod->numframes = 2; // regular and alternate animation
3380 mainmempool = mod->mempool;
3381 loadname = mod->name;
3383 Mod_LoadLightList ();
3384 originalloadmodel = loadmodel;
3387 // set up the submodels (FIXME: this is confusing)
3389 for (i = 0;i < mod->numsubmodels;i++)
3392 float dist, modelyawradius, modelradius, *vec;
3395 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
3396 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
3400 bm = &mod->submodels[i];
3402 mod->hulls[0].firstclipnode = bm->headnode[0];
3403 for (j=1 ; j<MAX_MAP_HULLS ; j++)
3405 mod->hulls[j].firstclipnode = bm->headnode[j];
3406 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
3409 mod->firstmodelsurface = bm->firstface;
3410 mod->nummodelsurfaces = bm->numfaces;
3412 // this gets altered below if sky is used
3413 mod->DrawSky = NULL;
3414 mod->Draw = R_Model_Brush_Draw;
3415 mod->DrawFakeShadow = NULL;
3416 mod->DrawDepth = R_Model_Brush_DrawDepth;
3417 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
3418 mod->DrawLight = R_Model_Brush_DrawLight;
3419 mod->DrawOntoLight = R_Model_Brush_DrawOntoLight;
3420 if (mod->nummodelsurfaces)
3422 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
3423 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
3425 // we only need to have a drawsky function if it is used (usually only on world model)
3426 if (surf->texinfo->texture->shader == &Cshader_sky)
3427 mod->DrawSky = R_Model_Brush_DrawSky;
3428 for (k = 0;k < surf->numedges;k++)
3430 l = mod->surfedges[k + surf->firstedge];
3432 vec = mod->vertexes[mod->edges[l].v[0]].position;
3434 vec = mod->vertexes[mod->edges[-l].v[1]].position;
3435 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
3436 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
3437 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
3438 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
3439 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
3440 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
3441 dist = vec[0]*vec[0]+vec[1]*vec[1];
3442 if (modelyawradius < dist)
3443 modelyawradius = dist;
3444 dist += vec[2]*vec[2];
3445 if (modelradius < dist)
3449 modelyawradius = sqrt(modelyawradius);
3450 modelradius = sqrt(modelradius);
3451 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
3452 mod->yawmins[2] = mod->normalmins[2];
3453 mod->yawmaxs[2] = mod->normalmaxs[2];
3454 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
3455 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
3456 mod->radius = modelradius;
3457 mod->radius2 = modelradius * modelradius;
3458 // LordHavoc: build triangle meshs for entire model's geometry
3459 // (only used for shadow volumes)
3460 mod->shadowmesh = Mod_ShadowMesh_Begin(originalloadmodel->mempool);
3461 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
3462 if (surf->flags & SURF_CLIPSOLID)
3463 Mod_ShadowMesh_AddPolygon(originalloadmodel->mempool, mod->shadowmesh, surf->poly_numverts, surf->poly_verts);
3464 mod->shadowmesh = Mod_ShadowMesh_Finish(originalloadmodel->mempool, mod->shadowmesh);
3465 Mod_ShadowMesh_CalcBBox(mod->shadowmesh, mod->shadowmesh_mins, mod->shadowmesh_maxs, mod->shadowmesh_center, &mod->shadowmesh_radius);
3469 // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
3470 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
3471 VectorClear(mod->normalmins);
3472 VectorClear(mod->normalmaxs);
3473 VectorClear(mod->yawmins);
3474 VectorClear(mod->yawmaxs);
3475 VectorClear(mod->rotatedmins);
3476 VectorClear(mod->rotatedmaxs);
3479 mod->shadowmesh = NULL;
3482 mod->numleafs = bm->visleafs;
3484 // LordHavoc: only register submodels if it is the world
3485 // (prevents bsp models from replacing world submodels)
3486 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
3489 // duplicate the basic information
3490 sprintf (name, "*%i", i+1);
3491 loadmodel = Mod_FindName (name);
3493 strcpy (loadmodel->name, name);
3494 // textures and memory belong to the main model
3495 loadmodel->texturepool = NULL;
3496 loadmodel->mempool = NULL;
3501 loadmodel = originalloadmodel;
3502 Mod_ProcessLightList ();