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.
25 // note: model_shared.c sets up r_notexture, and r_surf_notexture
27 qbyte mod_novis[(MAX_MAP_LEAFS + 7)/ 8];
29 //cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"};
30 cvar_t halflifebsp = {0, "halflifebsp", "0"};
31 cvar_t r_novis = {0, "r_novis", "0"};
32 cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"};
33 cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
34 cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
35 cvar_t r_sortsurfaces = {0, "r_sortsurfaces", "0"};
42 void Mod_BrushInit (void)
44 // Cvar_RegisterVariable(&r_subdivide_size);
45 Cvar_RegisterVariable(&halflifebsp);
46 Cvar_RegisterVariable(&r_novis);
47 Cvar_RegisterVariable(&r_miplightmaps);
48 Cvar_RegisterVariable(&r_lightmaprgba);
49 Cvar_RegisterVariable(&r_nosurftextures);
50 Cvar_RegisterVariable(&r_sortsurfaces);
51 memset(mod_novis, 0xff, sizeof(mod_novis));
59 mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model)
66 Mod_CheckLoaded(model);
68 // LordHavoc: modified to start at first clip node,
69 // in other words: first node of the (sub)model
70 node = model->nodes + model->hulls[0].firstclipnode;
71 while (node->contents == 0)
72 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
74 return (mleaf_t *)node;
77 int Mod_PointContents (const vec3_t p, model_t *model)
82 return CONTENTS_EMPTY;
84 Mod_CheckLoaded(model);
86 // LordHavoc: modified to start at first clip node,
87 // in other words: first node of the (sub)model
88 node = model->nodes + model->hulls[0].firstclipnode;
89 while (node->contents == 0)
90 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
92 return ((mleaf_t *)node)->contents;
95 void Mod_FindNonSolidLocation(vec3_t pos, model_t *mod)
97 if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
98 pos[0]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
99 pos[0]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
101 pos[1]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
102 pos[1]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
104 pos[2]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
105 pos[2]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
115 static qbyte *Mod_DecompressVis (qbyte *in, model_t *model)
117 static qbyte decompressed[MAX_MAP_LEAFS/8];
122 row = (model->numleafs+7)>>3;
140 } while (out - decompressed < row);
145 qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
147 if (r_novis.integer || leaf == model->leafs || leaf->compressed_vis == NULL)
149 return Mod_DecompressVis (leaf->compressed_vis, model);
157 static void Mod_LoadTextures (lump_t *l)
159 int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs, incomplete;
161 texture_t *tx, *tx2, *anims[10], *altanims[10];
163 qbyte *data, *mtdata;
166 loadmodel->textures = NULL;
171 m = (dmiptexlump_t *)(mod_base + l->fileofs);
173 m->nummiptex = LittleLong (m->nummiptex);
175 // add two slots for notexture walls and notexture liquids
176 loadmodel->numtextures = m->nummiptex + 2;
177 loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(texture_t));
179 // fill out all slots with notexture
180 for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++)
183 strcpy(tx->name, "NO TEXTURE FOUND");
186 tx->skin.base = r_notexture;
187 tx->shader = &Cshader_wall_lightmap;
188 if (i == loadmodel->numtextures - 1)
190 tx->flags = SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
191 tx->shader = &Cshader_water;
193 tx->currentframe = tx;
196 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
198 // LordHavoc: mostly rewritten map texture loader
199 for (i = 0;i < m->nummiptex;i++)
201 dofs[i] = LittleLong(dofs[i]);
202 if (dofs[i] == -1 || r_nosurftextures.integer)
204 dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
206 // make sure name is no more than 15 characters
207 for (j = 0;dmiptex->name[j] && j < 15;j++)
208 name[j] = dmiptex->name[j];
211 mtwidth = LittleLong (dmiptex->width);
212 mtheight = LittleLong (dmiptex->height);
214 j = LittleLong (dmiptex->offsets[0]);
218 if (j < 40 || j + mtwidth * mtheight > l->filelen)
220 Con_Printf ("Texture \"%s\" in \"%s\"is corrupt or incomplete\n", dmiptex->name, loadmodel->name);
223 mtdata = (qbyte *)dmiptex + j;
226 if ((mtwidth & 15) || (mtheight & 15))
227 Con_Printf ("warning: texture \"%s\" in \"%s\" is not 16 aligned", dmiptex->name, loadmodel->name);
229 // LordHavoc: force all names to lowercase
230 for (j = 0;name[j];j++)
231 if (name[j] >= 'A' && name[j] <= 'Z')
232 name[j] += 'a' - 'A';
234 tx = loadmodel->textures + i;
235 strcpy(tx->name, name);
237 tx->height = mtheight;
241 sprintf(tx->name, "unnamed%i", i);
242 Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
245 // LordHavoc: HL sky textures are entirely different than quake
246 if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
248 if (loadmodel->isworldmodel)
250 data = loadimagepixels(tx->name, false, 0, 0);
253 if (image_width == 256 && image_height == 128)
261 Con_Printf ("Invalid replacement texture for sky \"%s\" in %\"%s\", must be 256x128 pixels\n", tx->name, loadmodel->name);
263 R_InitSky (mtdata, 1);
266 else if (mtdata != NULL)
267 R_InitSky (mtdata, 1);
272 if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true))
274 // did not find external texture, load it from the bsp or wad3
275 if (loadmodel->ishlbsp)
277 // internal texture overrides wad
278 qbyte *pixels, *freepixels;
279 pixels = freepixels = NULL;
281 pixels = W_ConvertWAD3Texture(dmiptex);
283 pixels = freepixels = W_GetTexture(tx->name);
286 tx->width = image_width;
287 tx->height = image_height;
288 tx->skin.base = tx->skin.merged = R_LoadTexture2D(loadmodel->texturepool, tx->name, image_width, image_height, pixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
291 Mem_Free(freepixels);
293 else if (mtdata) // texture included
294 Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height);
297 if (tx->skin.base == NULL)
302 tx->skin.base = r_notexture;
305 if (tx->name[0] == '*')
307 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
308 // LordHavoc: some turbulent textures should be fullbright and solid
309 if (!strncmp(tx->name,"*lava",5)
310 || !strncmp(tx->name,"*teleport",9)
311 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
312 tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
314 tx->flags |= SURF_WATERALPHA;
315 tx->shader = &Cshader_water;
317 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
319 tx->flags |= SURF_DRAWSKY;
320 tx->shader = &Cshader_sky;
324 tx->flags |= SURF_LIGHTMAP;
326 tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT;
327 tx->shader = &Cshader_wall_lightmap;
330 // start out with no animation
331 tx->currentframe = tx;
334 // sequence the animations
335 for (i = 0;i < m->nummiptex;i++)
337 tx = loadmodel->textures + i;
338 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
340 if (tx->anim_total[0] || tx->anim_total[1])
341 continue; // already sequenced
343 // find the number of frames in the animation
344 memset (anims, 0, sizeof(anims));
345 memset (altanims, 0, sizeof(altanims));
347 for (j = i;j < m->nummiptex;j++)
349 tx2 = loadmodel->textures + j;
350 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
354 if (num >= '0' && num <= '9')
355 anims[num - '0'] = tx2;
356 else if (num >= 'a' && num <= 'j')
357 altanims[num - 'a'] = tx2;
359 Con_Printf ("Bad animating texture %s\n", tx->name);
363 for (j = 0;j < 10;j++)
370 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
373 for (j = 0;j < max;j++)
377 Con_Printf ("Missing frame %i of %s\n", j, tx->name);
381 for (j = 0;j < altmax;j++)
385 Con_Printf ("Missing altframe %i of %s\n", j, tx->name);
394 // if there is no alternate animation, duplicate the primary
395 // animation into the alternate
397 for (k = 0;k < 10;k++)
398 altanims[k] = anims[k];
401 // link together the primary animation
402 for (j = 0;j < max;j++)
405 tx2->animated = true;
406 tx2->anim_total[0] = max;
407 tx2->anim_total[1] = altmax;
408 for (k = 0;k < 10;k++)
410 tx2->anim_frames[0][k] = anims[k];
411 tx2->anim_frames[1][k] = altanims[k];
415 // if there really is an alternate anim...
416 if (anims[0] != altanims[0])
418 // link together the alternate animation
419 for (j = 0;j < altmax;j++)
422 tx2->animated = true;
423 // the primary/alternate are reversed here
424 tx2->anim_total[0] = altmax;
425 tx2->anim_total[1] = max;
426 for (k = 0;k < 10;k++)
428 tx2->anim_frames[0][k] = altanims[k];
429 tx2->anim_frames[1][k] = anims[k];
441 static void Mod_LoadLighting (lump_t *l)
444 qbyte *in, *out, *data, d;
445 char litfilename[1024];
446 loadmodel->lightdata = NULL;
447 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
449 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
450 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
452 else // LordHavoc: bsp version 29 (normal white lighting)
454 // LordHavoc: hope is not lost yet, check for a .lit file to load
455 strcpy(litfilename, loadmodel->name);
456 COM_StripExtension(litfilename, litfilename);
457 strcat(litfilename, ".lit");
458 data = (qbyte*) COM_LoadFile (litfilename, false);
461 if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
463 i = LittleLong(((int *)data)[1]);
466 Con_DPrintf("loaded %s\n", litfilename);
467 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
468 memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
474 Con_Printf("Unknown .lit file version (%d)\n", i);
481 Con_Printf("Empty .lit file, ignoring\n");
483 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
487 // LordHavoc: oh well, expand the white lighting data
490 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
491 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
492 out = loadmodel->lightdata;
493 memcpy (in, mod_base + l->fileofs, l->filelen);
494 for (i = 0;i < l->filelen;i++)
504 void Mod_LoadLightList(void)
507 char lightsfilename[1024], *s, *t, *lightsstring;
510 strcpy(lightsfilename, loadmodel->name);
511 COM_StripExtension(lightsfilename, lightsfilename);
512 strcat(lightsfilename, ".lights");
513 s = lightsstring = (char *) COM_LoadFile (lightsfilename, false);
519 while (*s && *s != '\n')
523 Mem_Free(lightsstring);
524 Host_Error("lights file must end with a newline\n");
529 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
532 while (*s && n < numlights)
535 while (*s && *s != '\n')
539 Mem_Free(lightsstring);
540 Host_Error("misparsed lights file!\n");
542 e = loadmodel->lights + n;
544 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);
548 Mem_Free(lightsstring);
549 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);
556 Mem_Free(lightsstring);
557 Host_Error("misparsed lights file!\n");
559 loadmodel->numlights = numlights;
560 Mem_Free(lightsstring);
565 static int castshadowcount = 0;
566 void Mod_ProcessLightList(void)
568 int j, k, l, *mark, lnum;
576 for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++)
578 e->cullradius2 = DotProduct(e->light, e->light) / (e->falloff * e->falloff * 8192.0f * 8192.0f * 2.0f * 2.0f);// + 4096.0f;
579 if (e->cullradius2 > 4096.0f * 4096.0f)
580 e->cullradius2 = 4096.0f * 4096.0f;
581 e->cullradius = e->lightradius = sqrt(e->cullradius2);
582 leaf = Mod_PointInLeaf(e->origin, loadmodel);
583 if (leaf->compressed_vis)
584 pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel);
587 for (j = 0;j < loadmodel->numsurfaces;j++)
588 loadmodel->surfacevisframes[j] = -1;
589 for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++)
591 if (pvs[j >> 3] & (1 << (j & 7)))
593 for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++)
595 surf = loadmodel->surfaces + *mark;
596 if (surf->number != *mark)
597 Con_Printf("%d != %d\n", surf->number, *mark);
598 dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
599 if (surf->flags & SURF_PLANEBACK)
601 if (dist > 0 && dist < e->cullradius)
603 temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
604 temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
605 temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
606 if (DotProduct(temp, temp) < lightradius2)
607 loadmodel->surfacevisframes[*mark] = -2;
612 // build list of light receiving surfaces
614 for (j = 0;j < loadmodel->numsurfaces;j++)
615 if (loadmodel->surfacevisframes[j] == -2)
618 if (e->numsurfaces > 0)
620 e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
622 for (j = 0;j < loadmodel->numsurfaces;j++)
623 if (loadmodel->surfacevisframes[j] == -2)
624 e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j;
626 // find bounding box and sphere of lit surfaces
627 // (these will be used for creating a shape to clip the light)
629 for (j = 0;j < e->numsurfaces;j++)
631 surf = e->surfaces[j];
634 VectorCopy(surf->poly_verts, e->mins);
635 VectorCopy(surf->poly_verts, e->maxs);
637 for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
639 if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
640 if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
641 if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
642 VectorSubtract(v, e->origin, temp);
643 dist = DotProduct(temp, temp);
648 if (e->cullradius2 > radius2)
650 e->cullradius2 = radius2;
651 e->cullradius = sqrt(e->cullradius2);
653 if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
654 if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
655 if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
656 if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
657 if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
658 if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
659 // clip shadow volumes against eachother to remove unnecessary
660 // polygons (and sections of polygons)
662 //vec3_t polymins, polymaxs;
664 float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
665 float f, *v0, *v1, projectdistance;
667 e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024);
670 vec3_t outermins, outermaxs, innermins, innermaxs;
671 innermins[0] = e->mins[0] - 1;
672 innermins[1] = e->mins[1] - 1;
673 innermins[2] = e->mins[2] - 1;
674 innermaxs[0] = e->maxs[0] + 1;
675 innermaxs[1] = e->maxs[1] + 1;
676 innermaxs[2] = e->maxs[2] + 1;
677 outermins[0] = loadmodel->normalmins[0] - 1;
678 outermins[1] = loadmodel->normalmins[1] - 1;
679 outermins[2] = loadmodel->normalmins[2] - 1;
680 outermaxs[0] = loadmodel->normalmaxs[0] + 1;
681 outermaxs[1] = loadmodel->normalmaxs[1] + 1;
682 outermaxs[2] = loadmodel->normalmaxs[2] + 1;
683 // add bounding box around the whole shadow volume set,
684 // facing inward to limit light area, with an outer bounding box
685 // facing outward (this is needed by the shadow rendering method)
687 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
688 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
689 verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
690 verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
691 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
692 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
693 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
694 verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
695 verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
696 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
698 verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
699 verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
700 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
701 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
702 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
703 verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
704 verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
705 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
706 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
707 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
709 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
710 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
711 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
712 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
713 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
714 verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
715 verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
716 verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
717 verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
718 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
720 verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
721 verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
722 verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
723 verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
724 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
725 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
726 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
727 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
728 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
729 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
731 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
732 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2];
733 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2];
734 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
735 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
736 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
737 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2];
738 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2];
739 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
740 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
742 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2];
743 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
744 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
745 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2];
746 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
747 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2];
748 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
749 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
750 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2];
751 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
755 for (j = 0;j < e->numsurfaces;j++)
757 surf = e->surfaces[j];
758 if (surf->flags & SURF_SHADOWCAST)
759 surf->castshadow = castshadowcount;
761 for (j = 0;j < e->numsurfaces;j++)
763 surf = e->surfaces[j];
764 if (surf->castshadow != castshadowcount)
766 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
767 if (surf->flags & SURF_PLANEBACK)
769 projectdistance = e->lightradius;
770 if (maxverts < surf->poly_numverts)
772 maxverts = surf->poly_numverts;
775 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
777 // copy the original polygon, for the front cap of the volume
778 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
780 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
781 // project the original polygon, reversed, for the back cap of the volume
782 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
784 VectorSubtract(v0, e->origin, temp);
785 VectorNormalize(temp);
786 VectorMA(v0, projectdistance, temp, v1);
788 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
789 // project the shadow volume sides
790 for (l = surf->poly_numverts - 1, k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;l = k, k++, v0 = v1, v1 += 3)
792 if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount)
794 VectorCopy(v1, &verts[0]);
795 VectorCopy(v0, &verts[3]);
796 VectorCopy(v0, &verts[6]);
797 VectorCopy(v1, &verts[9]);
798 VectorSubtract(&verts[6], e->origin, temp);
799 VectorNormalize(temp);
800 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
801 VectorSubtract(&verts[9], e->origin, temp);
802 VectorNormalize(temp);
803 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
804 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
808 // build the triangle mesh
809 e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume);
813 for (mesh = e->shadowvolume;mesh;mesh = mesh->next)
814 l += mesh->numtriangles;
815 Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l);
828 static void Mod_LoadVisibility (lump_t *l)
830 loadmodel->visdata = NULL;
833 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
834 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
837 // used only for HalfLife maps
838 void Mod_ParseWadsFromEntityLump(const char *data)
840 char key[128], value[4096];
845 if (!COM_ParseToken(&data))
847 if (com_token[0] != '{')
851 if (!COM_ParseToken(&data))
853 if (com_token[0] == '}')
854 break; // end of worldspawn
855 if (com_token[0] == '_')
856 strcpy(key, com_token + 1);
858 strcpy(key, com_token);
859 while (key[strlen(key)-1] == ' ') // remove trailing spaces
860 key[strlen(key)-1] = 0;
861 if (!COM_ParseToken(&data))
863 strcpy(value, com_token);
864 if (!strcmp("wad", key)) // for HalfLife maps
866 if (loadmodel->ishlbsp)
869 for (i = 0;i < 4096;i++)
870 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
876 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
877 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
879 else if (value[i] == ';' || value[i] == 0)
883 strcpy(wadname, "textures/");
884 strcat(wadname, &value[j]);
885 W_LoadTextureWadFile (wadname, false);
902 static void Mod_LoadEntities (lump_t *l)
904 loadmodel->entities = NULL;
907 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
908 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
909 if (loadmodel->ishlbsp)
910 Mod_ParseWadsFromEntityLump(loadmodel->entities);
919 static void Mod_LoadVertexes (lump_t *l)
925 in = (void *)(mod_base + l->fileofs);
926 if (l->filelen % sizeof(*in))
927 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
928 count = l->filelen / sizeof(*in);
929 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
931 loadmodel->vertexes = out;
932 loadmodel->numvertexes = count;
934 for ( i=0 ; i<count ; i++, in++, out++)
936 out->position[0] = LittleFloat (in->point[0]);
937 out->position[1] = LittleFloat (in->point[1]);
938 out->position[2] = LittleFloat (in->point[2]);
947 static void Mod_LoadSubmodels (lump_t *l)
953 in = (void *)(mod_base + l->fileofs);
954 if (l->filelen % sizeof(*in))
955 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
956 count = l->filelen / sizeof(*in);
957 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
959 loadmodel->submodels = out;
960 loadmodel->numsubmodels = count;
962 for ( i=0 ; i<count ; i++, in++, out++)
964 for (j=0 ; j<3 ; j++)
966 // spread the mins / maxs by a pixel
967 out->mins[j] = LittleFloat (in->mins[j]) - 1;
968 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
969 out->origin[j] = LittleFloat (in->origin[j]);
971 for (j=0 ; j<MAX_MAP_HULLS ; j++)
972 out->headnode[j] = LittleLong (in->headnode[j]);
973 out->visleafs = LittleLong (in->visleafs);
974 out->firstface = LittleLong (in->firstface);
975 out->numfaces = LittleLong (in->numfaces);
984 static void Mod_LoadEdges (lump_t *l)
990 in = (void *)(mod_base + l->fileofs);
991 if (l->filelen % sizeof(*in))
992 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
993 count = l->filelen / sizeof(*in);
994 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
996 loadmodel->edges = out;
997 loadmodel->numedges = count;
999 for ( i=0 ; i<count ; i++, in++, out++)
1001 out->v[0] = (unsigned short)LittleShort(in->v[0]);
1002 out->v[1] = (unsigned short)LittleShort(in->v[1]);
1011 static void Mod_LoadTexinfo (lump_t *l)
1015 int i, j, k, count, miptex;
1017 in = (void *)(mod_base + l->fileofs);
1018 if (l->filelen % sizeof(*in))
1019 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1020 count = l->filelen / sizeof(*in);
1021 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1023 loadmodel->texinfo = out;
1024 loadmodel->numtexinfo = count;
1026 for (i = 0;i < count;i++, in++, out++)
1028 for (k = 0;k < 2;k++)
1029 for (j = 0;j < 4;j++)
1030 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
1032 miptex = LittleLong (in->miptex);
1033 out->flags = LittleLong (in->flags);
1035 out->texture = NULL;
1036 if (loadmodel->textures)
1038 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
1039 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
1041 out->texture = loadmodel->textures + miptex;
1043 if (out->flags & TEX_SPECIAL)
1045 // if texture chosen is NULL or the shader needs a lightmap,
1046 // force to notexture water shader
1047 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
1048 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
1052 // if texture chosen is NULL, force to notexture
1053 if (out->texture == NULL)
1054 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
1059 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1064 mins[0] = mins[1] = mins[2] = 9999;
1065 maxs[0] = maxs[1] = maxs[2] = -9999;
1067 for (i = 0;i < numverts;i++)
1069 for (j = 0;j < 3;j++, v++)
1080 #define MAX_SUBDIVPOLYTRIANGLES 4096
1081 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1083 static int subdivpolyverts, subdivpolytriangles;
1084 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1085 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1087 static int subdivpolylookupvert(vec3_t v)
1090 for (i = 0;i < subdivpolyverts;i++)
1091 if (subdivpolyvert[i][0] == v[0]
1092 && subdivpolyvert[i][1] == v[1]
1093 && subdivpolyvert[i][2] == v[2])
1095 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1096 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1097 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1098 return subdivpolyverts++;
1101 static void SubdividePolygon (int numverts, float *verts)
1103 int i, i1, i2, i3, f, b, c, p;
1104 vec3_t mins, maxs, front[256], back[256];
1105 float m, *pv, *cv, dist[256], frac;
1108 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1110 BoundPoly (numverts, verts, mins, maxs);
1112 for (i = 0;i < 3;i++)
1114 m = (mins[i] + maxs[i]) * 0.5;
1115 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1116 if (maxs[i] - m < 8)
1118 if (m - mins[i] < 8)
1122 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1123 dist[c] = cv[i] - m;
1126 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1130 VectorCopy (pv, front[f]);
1135 VectorCopy (pv, back[b]);
1138 if (dist[p] == 0 || dist[c] == 0)
1140 if ( (dist[p] > 0) != (dist[c] > 0) )
1143 frac = dist[p] / (dist[p] - dist[c]);
1144 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1145 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1146 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1152 SubdividePolygon (f, front[0]);
1153 SubdividePolygon (b, back[0]);
1157 i1 = subdivpolylookupvert(verts);
1158 i2 = subdivpolylookupvert(verts + 3);
1159 for (i = 2;i < numverts;i++)
1161 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1163 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1167 i3 = subdivpolylookupvert(verts + i * 3);
1168 subdivpolyindex[subdivpolytriangles][0] = i1;
1169 subdivpolyindex[subdivpolytriangles][1] = i2;
1170 subdivpolyindex[subdivpolytriangles][2] = i3;
1172 subdivpolytriangles++;
1178 Mod_GenerateWarpMesh
1180 Breaks a polygon up along axial 64 unit
1181 boundaries so that turbulent and sky warps
1182 can be done reasonably.
1185 void Mod_GenerateWarpMesh (msurface_t *surf)
1191 subdivpolytriangles = 0;
1192 subdivpolyverts = 0;
1193 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1194 if (subdivpolytriangles < 1)
1195 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1197 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1198 mesh->numverts = subdivpolyverts;
1199 mesh->numtriangles = subdivpolytriangles;
1200 mesh->vertex = (surfvertex_t *)(mesh + 1);
1201 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1202 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1204 for (i = 0;i < mesh->numtriangles;i++)
1205 for (j = 0;j < 3;j++)
1206 mesh->index[i*3+j] = subdivpolyindex[i][j];
1208 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1210 VectorCopy(subdivpolyvert[i], v->v);
1211 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1212 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1217 surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles)
1220 mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (4 + 4 + 4 + 4 + 4 + 4 + 4 + 1) * sizeof(float));
1221 mesh->numverts = numverts;
1222 mesh->numtriangles = numtriangles;
1223 mesh->verts = (float *)(mesh + 1);
1224 mesh->str = mesh->verts + mesh->numverts * 4;
1225 mesh->uvw = mesh->str + mesh->numverts * 4;
1226 mesh->abc = mesh->uvw + mesh->numverts * 4;
1227 mesh->svectors = (float *)(mesh->abc + mesh->numverts * 4);
1228 mesh->tvectors = mesh->svectors + mesh->numverts * 4;
1229 mesh->normals = mesh->tvectors + mesh->numverts * 4;
1230 mesh->lightmapoffsets = (int *)(mesh->normals + mesh->numverts * 4);
1231 mesh->index = mesh->lightmapoffsets + mesh->numverts;
1232 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
1236 void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
1238 int i, iu, iv, *index, smax, tmax;
1239 float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
1242 smax = surf->extents[0] >> 4;
1243 tmax = surf->extents[1] >> 4;
1247 surf->lightmaptexturestride = 0;
1248 surf->lightmaptexture = NULL;
1256 surf->flags |= SURF_LIGHTMAP;
1257 if (r_miplightmaps.integer)
1259 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1260 surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_PRECACHE, NULL);
1264 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1265 surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE, NULL);
1267 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1268 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1269 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1272 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1274 index = mesh->index;
1275 for (i = 0;i < mesh->numtriangles;i++)
1281 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1283 VectorCopy(surf->plane->normal, normal);
1284 if (surf->flags & SURF_PLANEBACK)
1285 VectorNegate(normal, normal);
1286 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1288 s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1289 t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1290 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1291 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1292 // LordHavoc: calc lightmap data offset for vertex lighting to use
1295 iu = bound(0, iu, smax);
1296 iv = bound(0, iv, tmax);
1297 u = u * uscale + ubase;
1298 v = v * vscale + vbase;
1300 mesh->verts[i * 4 + 0] = in[0];
1301 mesh->verts[i * 4 + 1] = in[1];
1302 mesh->verts[i * 4 + 2] = in[2];
1303 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1304 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1305 mesh->uvw[i * 4 + 0] = u;
1306 mesh->uvw[i * 4 + 1] = v;
1307 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1308 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1309 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
1311 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1314 void Mod_GenerateVertexMesh (msurface_t *surf)
1317 float *in, s, t, normal[3];
1320 surf->lightmaptexturestride = 0;
1321 surf->lightmaptexture = NULL;
1323 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1325 index = mesh->index;
1326 for (i = 0;i < mesh->numtriangles;i++)
1332 Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles);
1334 VectorCopy(surf->plane->normal, normal);
1335 if (surf->flags & SURF_PLANEBACK)
1336 VectorNegate(normal, normal);
1337 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1339 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
1340 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
1341 mesh->verts[i * 4 + 0] = in[0];
1342 mesh->verts[i * 4 + 1] = in[1];
1343 mesh->verts[i * 4 + 2] = in[2];
1344 mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width;
1345 mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height;
1346 mesh->uvw[i * 4 + 0] = 0;
1347 mesh->uvw[i * 4 + 1] = 0;
1348 mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f);
1349 mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f);
1351 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals);
1354 void Mod_GenerateSurfacePolygon (msurface_t *surf, int firstedge, int numedges)
1357 float *vec, *vert, mins[3], maxs[3], val, *v;
1360 // convert edges back to a normal polygon
1361 surf->poly_numverts = numedges;
1362 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * numedges);
1363 for (i = 0;i < numedges;i++)
1365 lindex = loadmodel->surfedges[firstedge + i];
1367 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1369 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1370 VectorCopy (vec, vert);
1374 // calculate polygon bounding box and center
1375 vert = surf->poly_verts;
1376 VectorCopy(vert, mins);
1377 VectorCopy(vert, maxs);
1379 for (i = 1;i < surf->poly_numverts;i++, vert += 3)
1381 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1382 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1383 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1385 VectorCopy(mins, surf->poly_mins);
1386 VectorCopy(maxs, surf->poly_maxs);
1387 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1388 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1389 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1391 // generate surface extents information
1392 tex = surf->texinfo;
1393 mins[0] = maxs[0] = DotProduct(surf->poly_verts, tex->vecs[0]) + tex->vecs[0][3];
1394 mins[1] = maxs[1] = DotProduct(surf->poly_verts, tex->vecs[1]) + tex->vecs[1][3];
1395 for (i = 1, v = surf->poly_verts + 3;i < surf->poly_numverts;i++, v += 3)
1397 for (j = 0;j < 2;j++)
1399 val = DotProduct(v, tex->vecs[j]) + tex->vecs[j][3];
1406 for (i = 0;i < 2;i++)
1408 surf->texturemins[i] = (int) floor(mins[i] / 16) * 16;
1409 surf->extents[i] = (int) ceil(maxs[i] / 16) * 16 - surf->texturemins[i];
1418 static void Mod_LoadFaces (lump_t *l)
1422 int i, count, surfnum, planenum, ssize, tsize, firstedge, numedges;
1424 in = (void *)(mod_base + l->fileofs);
1425 if (l->filelen % sizeof(*in))
1426 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1427 count = l->filelen / sizeof(*in);
1428 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1430 loadmodel->surfaces = out;
1431 loadmodel->numsurfaces = count;
1432 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1433 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1434 loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1436 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1438 out->number = surfnum;
1439 // FIXME: validate edges, texinfo, etc?
1440 firstedge = LittleLong(in->firstedge);
1441 numedges = LittleShort(in->numedges);
1442 if ((unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->numsurfedges)
1443 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->numsurfedges);
1445 i = LittleShort (in->texinfo);
1446 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1447 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1448 out->texinfo = loadmodel->texinfo + i;
1449 out->flags = out->texinfo->texture->flags;
1451 planenum = LittleShort(in->planenum);
1452 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1453 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1455 if (LittleShort(in->side))
1456 out->flags |= SURF_PLANEBACK;
1458 out->plane = loadmodel->planes + planenum;
1460 // clear lightmap (filled in later)
1461 out->lightmaptexture = NULL;
1463 // force lightmap upload on first time seeing the surface
1464 out->cached_dlight = true;
1466 Mod_GenerateSurfacePolygon(out, firstedge, numedges);
1468 ssize = (out->extents[0] >> 4) + 1;
1469 tsize = (out->extents[1] >> 4) + 1;
1472 for (i = 0;i < MAXLIGHTMAPS;i++)
1473 out->styles[i] = in->styles[i];
1474 i = LittleLong(in->lightofs);
1476 out->samples = NULL;
1477 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1478 out->samples = loadmodel->lightdata + i;
1479 else // LordHavoc: white lighting (bsp version 29)
1480 out->samples = loadmodel->lightdata + (i * 3);
1482 if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
1484 if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
1485 Host_Error ("Bad surface extents");
1486 Mod_GenerateWallMesh (out, false);
1487 // stainmap for permanent marks on walls
1488 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1490 memset(out->stainsamples, 255, ssize * tsize * 3);
1493 Mod_GenerateVertexMesh (out);
1502 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1504 node->parent = parent;
1505 if (node->contents < 0)
1507 Mod_SetParent (node->children[0], node);
1508 Mod_SetParent (node->children[1], node);
1516 static void Mod_LoadNodes (lump_t *l)
1522 in = (void *)(mod_base + l->fileofs);
1523 if (l->filelen % sizeof(*in))
1524 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1525 count = l->filelen / sizeof(*in);
1526 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1528 loadmodel->nodes = out;
1529 loadmodel->numnodes = count;
1531 for ( i=0 ; i<count ; i++, in++, out++)
1533 for (j=0 ; j<3 ; j++)
1535 out->mins[j] = LittleShort (in->mins[j]);
1536 out->maxs[j] = LittleShort (in->maxs[j]);
1539 p = LittleLong(in->planenum);
1540 out->plane = loadmodel->planes + p;
1542 out->firstsurface = LittleShort (in->firstface);
1543 out->numsurfaces = LittleShort (in->numfaces);
1545 for (j=0 ; j<2 ; j++)
1547 p = LittleShort (in->children[j]);
1549 out->children[j] = loadmodel->nodes + p;
1551 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1555 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1563 static void Mod_LoadLeafs (lump_t *l)
1569 in = (void *)(mod_base + l->fileofs);
1570 if (l->filelen % sizeof(*in))
1571 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1572 count = l->filelen / sizeof(*in);
1573 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1575 loadmodel->leafs = out;
1576 loadmodel->numleafs = count;
1578 for ( i=0 ; i<count ; i++, in++, out++)
1580 for (j=0 ; j<3 ; j++)
1582 out->mins[j] = LittleShort (in->mins[j]);
1583 out->maxs[j] = LittleShort (in->maxs[j]);
1586 p = LittleLong(in->contents);
1589 out->firstmarksurface = loadmodel->marksurfaces +
1590 LittleShort(in->firstmarksurface);
1591 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1593 p = LittleLong(in->visofs);
1595 out->compressed_vis = NULL;
1597 out->compressed_vis = loadmodel->visdata + p;
1599 for (j=0 ; j<4 ; j++)
1600 out->ambient_sound_level[j] = in->ambient_level[j];
1602 // FIXME: Insert caustics here
1611 static void Mod_LoadClipnodes (lump_t *l)
1613 dclipnode_t *in, *out;
1617 in = (void *)(mod_base + l->fileofs);
1618 if (l->filelen % sizeof(*in))
1619 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1620 count = l->filelen / sizeof(*in);
1621 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1623 loadmodel->clipnodes = out;
1624 loadmodel->numclipnodes = count;
1626 if (loadmodel->ishlbsp)
1628 hull = &loadmodel->hulls[1];
1629 hull->clipnodes = out;
1630 hull->firstclipnode = 0;
1631 hull->lastclipnode = count-1;
1632 hull->planes = loadmodel->planes;
1633 hull->clip_mins[0] = -16;
1634 hull->clip_mins[1] = -16;
1635 hull->clip_mins[2] = -36;
1636 hull->clip_maxs[0] = 16;
1637 hull->clip_maxs[1] = 16;
1638 hull->clip_maxs[2] = 36;
1639 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1641 hull = &loadmodel->hulls[2];
1642 hull->clipnodes = out;
1643 hull->firstclipnode = 0;
1644 hull->lastclipnode = count-1;
1645 hull->planes = loadmodel->planes;
1646 hull->clip_mins[0] = -32;
1647 hull->clip_mins[1] = -32;
1648 hull->clip_mins[2] = -32;
1649 hull->clip_maxs[0] = 32;
1650 hull->clip_maxs[1] = 32;
1651 hull->clip_maxs[2] = 32;
1652 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1654 hull = &loadmodel->hulls[3];
1655 hull->clipnodes = out;
1656 hull->firstclipnode = 0;
1657 hull->lastclipnode = count-1;
1658 hull->planes = loadmodel->planes;
1659 hull->clip_mins[0] = -16;
1660 hull->clip_mins[1] = -16;
1661 hull->clip_mins[2] = -18;
1662 hull->clip_maxs[0] = 16;
1663 hull->clip_maxs[1] = 16;
1664 hull->clip_maxs[2] = 18;
1665 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1669 hull = &loadmodel->hulls[1];
1670 hull->clipnodes = out;
1671 hull->firstclipnode = 0;
1672 hull->lastclipnode = count-1;
1673 hull->planes = loadmodel->planes;
1674 hull->clip_mins[0] = -16;
1675 hull->clip_mins[1] = -16;
1676 hull->clip_mins[2] = -24;
1677 hull->clip_maxs[0] = 16;
1678 hull->clip_maxs[1] = 16;
1679 hull->clip_maxs[2] = 32;
1680 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1682 hull = &loadmodel->hulls[2];
1683 hull->clipnodes = out;
1684 hull->firstclipnode = 0;
1685 hull->lastclipnode = count-1;
1686 hull->planes = loadmodel->planes;
1687 hull->clip_mins[0] = -32;
1688 hull->clip_mins[1] = -32;
1689 hull->clip_mins[2] = -24;
1690 hull->clip_maxs[0] = 32;
1691 hull->clip_maxs[1] = 32;
1692 hull->clip_maxs[2] = 64;
1693 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1696 for (i=0 ; i<count ; i++, out++, in++)
1698 out->planenum = LittleLong(in->planenum);
1699 out->children[0] = LittleShort(in->children[0]);
1700 out->children[1] = LittleShort(in->children[1]);
1701 if (out->children[0] >= count || out->children[1] >= count)
1702 Host_Error("Corrupt clipping hull (out of range child)\n");
1710 Duplicate the drawing hull structure as a clipping hull
1713 static void Mod_MakeHull0 (void)
1720 hull = &loadmodel->hulls[0];
1722 in = loadmodel->nodes;
1723 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1725 hull->clipnodes = out;
1726 hull->firstclipnode = 0;
1727 hull->lastclipnode = loadmodel->numnodes - 1;
1728 hull->planes = loadmodel->planes;
1730 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1732 out->planenum = in->plane - loadmodel->planes;
1733 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1734 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1740 Mod_LoadMarksurfaces
1743 static void Mod_LoadMarksurfaces (lump_t *l)
1748 in = (void *)(mod_base + l->fileofs);
1749 if (l->filelen % sizeof(*in))
1750 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1751 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1752 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1754 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1756 j = (unsigned) LittleShort(in[i]);
1757 if (j >= loadmodel->numsurfaces)
1758 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1759 loadmodel->marksurfaces[i] = j;
1768 static void Mod_LoadSurfedges (lump_t *l)
1773 in = (void *)(mod_base + l->fileofs);
1774 if (l->filelen % sizeof(*in))
1775 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1776 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1777 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1779 for (i = 0;i < loadmodel->numsurfedges;i++)
1780 loadmodel->surfedges[i] = LittleLong (in[i]);
1789 static void Mod_LoadPlanes (lump_t *l)
1795 in = (void *)(mod_base + l->fileofs);
1796 if (l->filelen % sizeof(*in))
1797 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1799 loadmodel->numplanes = l->filelen / sizeof(*in);
1800 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1802 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1804 out->normal[0] = LittleFloat (in->normal[0]);
1805 out->normal[1] = LittleFloat (in->normal[1]);
1806 out->normal[2] = LittleFloat (in->normal[2]);
1807 out->dist = LittleFloat (in->dist);
1813 #define MAX_POINTS_ON_WINDING 64
1819 double points[8][3]; // variable sized
1828 static winding_t *NewWinding (int points)
1833 if (points > MAX_POINTS_ON_WINDING)
1834 Sys_Error("NewWinding: too many points\n");
1836 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
1837 w = Mem_Alloc(loadmodel->mempool, size);
1838 memset (w, 0, size);
1843 static void FreeWinding (winding_t *w)
1853 static winding_t *BaseWindingForPlane (mplane_t *p)
1855 double org[3], vright[3], vup[3], normal[3];
1858 VectorCopy(p->normal, normal);
1859 VectorVectorsDouble(normal, vright, vup);
1861 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
1862 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
1864 // project a really big axis aligned box onto the plane
1867 VectorScale (p->normal, p->dist, org);
1869 VectorSubtract (org, vright, w->points[0]);
1870 VectorAdd (w->points[0], vup, w->points[0]);
1872 VectorAdd (org, vright, w->points[1]);
1873 VectorAdd (w->points[1], vup, w->points[1]);
1875 VectorAdd (org, vright, w->points[2]);
1876 VectorSubtract (w->points[2], vup, w->points[2]);
1878 VectorSubtract (org, vright, w->points[3]);
1879 VectorSubtract (w->points[3], vup, w->points[3]);
1890 Clips the winding to the plane, returning the new winding on the positive side
1891 Frees the input winding.
1892 If keepon is true, an exactly on-plane winding will be saved, otherwise
1893 it will be clipped away.
1896 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
1898 double dists[MAX_POINTS_ON_WINDING + 1];
1899 int sides[MAX_POINTS_ON_WINDING + 1];
1908 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1910 // determine sides for each point
1911 for (i = 0;i < in->numpoints;i++)
1913 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
1914 if (dot > ON_EPSILON)
1915 sides[i] = SIDE_FRONT;
1916 else if (dot < -ON_EPSILON)
1917 sides[i] = SIDE_BACK;
1922 sides[i] = sides[0];
1923 dists[i] = dists[0];
1925 if (keepon && !counts[0] && !counts[1])
1936 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1937 if (maxpts > MAX_POINTS_ON_WINDING)
1938 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1940 neww = NewWinding (maxpts);
1942 for (i = 0;i < in->numpoints;i++)
1944 if (neww->numpoints >= maxpts)
1945 Sys_Error ("ClipWinding: points exceeded estimate");
1949 if (sides[i] == SIDE_ON)
1951 VectorCopy (p1, neww->points[neww->numpoints]);
1956 if (sides[i] == SIDE_FRONT)
1958 VectorCopy (p1, neww->points[neww->numpoints]);
1962 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1965 // generate a split point
1966 p2 = in->points[(i+1)%in->numpoints];
1968 dot = dists[i] / (dists[i]-dists[i+1]);
1969 for (j = 0;j < 3;j++)
1970 { // avoid round off error when possible
1971 if (split->normal[j] == 1)
1972 mid[j] = split->dist;
1973 else if (split->normal[j] == -1)
1974 mid[j] = -split->dist;
1976 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1979 VectorCopy (mid, neww->points[neww->numpoints]);
1983 // free the original winding
1994 Divides a winding by a plane, producing one or two windings. The
1995 original winding is not damaged or freed. If only on one side, the
1996 returned winding will be the input winding. If on both sides, two
1997 new windings will be created.
2000 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2002 double dists[MAX_POINTS_ON_WINDING + 1];
2003 int sides[MAX_POINTS_ON_WINDING + 1];
2012 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2014 // determine sides for each point
2015 for (i = 0;i < in->numpoints;i++)
2017 dot = DotProduct (in->points[i], split->normal);
2020 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2021 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2022 else sides[i] = SIDE_ON;
2025 sides[i] = sides[0];
2026 dists[i] = dists[0];
2028 *front = *back = NULL;
2041 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2043 if (maxpts > MAX_POINTS_ON_WINDING)
2044 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2046 *front = f = NewWinding (maxpts);
2047 *back = b = NewWinding (maxpts);
2049 for (i = 0;i < in->numpoints;i++)
2051 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2052 Sys_Error ("DivideWinding: points exceeded estimate");
2056 if (sides[i] == SIDE_ON)
2058 VectorCopy (p1, f->points[f->numpoints]);
2060 VectorCopy (p1, b->points[b->numpoints]);
2065 if (sides[i] == SIDE_FRONT)
2067 VectorCopy (p1, f->points[f->numpoints]);
2070 else if (sides[i] == SIDE_BACK)
2072 VectorCopy (p1, b->points[b->numpoints]);
2076 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2079 // generate a split point
2080 p2 = in->points[(i+1)%in->numpoints];
2082 dot = dists[i] / (dists[i]-dists[i+1]);
2083 for (j = 0;j < 3;j++)
2084 { // avoid round off error when possible
2085 if (split->normal[j] == 1)
2086 mid[j] = split->dist;
2087 else if (split->normal[j] == -1)
2088 mid[j] = -split->dist;
2090 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2093 VectorCopy (mid, f->points[f->numpoints]);
2095 VectorCopy (mid, b->points[b->numpoints]);
2100 typedef struct portal_s
2103 mnode_t *nodes[2]; // [0] = front side of plane
2104 struct portal_s *next[2];
2106 struct portal_s *chain; // all portals are linked into a list
2110 static portal_t *portalchain;
2117 static portal_t *AllocPortal (void)
2120 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2121 p->chain = portalchain;
2126 static void FreePortal(portal_t *p)
2131 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2133 // calculate children first
2134 if (node->children[0]->contents >= 0)
2135 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2136 if (node->children[1]->contents >= 0)
2137 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2139 // make combined bounding box from children
2140 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2141 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2142 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2143 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2144 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2145 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2148 static void Mod_FinalizePortals(void)
2150 int i, j, numportals, numpoints;
2151 portal_t *p, *pnext;
2154 mleaf_t *leaf, *endleaf;
2157 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2158 leaf = loadmodel->leafs;
2159 endleaf = leaf + loadmodel->numleafs;
2160 for (;leaf < endleaf;leaf++)
2162 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2163 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2170 for (i = 0;i < 2;i++)
2172 leaf = (mleaf_t *)p->nodes[i];
2174 for (j = 0;j < w->numpoints;j++)
2176 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2177 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2178 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2179 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2180 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2181 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2188 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2190 // tally up portal and point counts
2196 // note: this check must match the one below or it will usually corrupt memory
2197 // 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
2198 if (p->winding && p->nodes[0] != p->nodes[1]
2199 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2200 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2203 numpoints += p->winding->numpoints * 2;
2207 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2208 loadmodel->numportals = numportals;
2209 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2210 loadmodel->numportalpoints = numpoints;
2211 // clear all leaf portal chains
2212 for (i = 0;i < loadmodel->numleafs;i++)
2213 loadmodel->leafs[i].portals = NULL;
2214 // process all portals in the global portal chain, while freeing them
2215 portal = loadmodel->portals;
2216 point = loadmodel->portalpoints;
2225 // note: this check must match the one above or it will usually corrupt memory
2226 // 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
2227 if (p->nodes[0] != p->nodes[1]
2228 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2229 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2231 // first make the back to front portal (forward portal)
2232 portal->points = point;
2233 portal->numpoints = p->winding->numpoints;
2234 portal->plane.dist = p->plane.dist;
2235 VectorCopy(p->plane.normal, portal->plane.normal);
2236 portal->here = (mleaf_t *)p->nodes[1];
2237 portal->past = (mleaf_t *)p->nodes[0];
2239 for (j = 0;j < portal->numpoints;j++)
2241 VectorCopy(p->winding->points[j], point->position);
2244 PlaneClassify(&portal->plane);
2246 // link into leaf's portal chain
2247 portal->next = portal->here->portals;
2248 portal->here->portals = portal;
2250 // advance to next portal
2253 // then make the front to back portal (backward portal)
2254 portal->points = point;
2255 portal->numpoints = p->winding->numpoints;
2256 portal->plane.dist = -p->plane.dist;
2257 VectorNegate(p->plane.normal, portal->plane.normal);
2258 portal->here = (mleaf_t *)p->nodes[0];
2259 portal->past = (mleaf_t *)p->nodes[1];
2261 for (j = portal->numpoints - 1;j >= 0;j--)
2263 VectorCopy(p->winding->points[j], point->position);
2266 PlaneClassify(&portal->plane);
2268 // link into leaf's portal chain
2269 portal->next = portal->here->portals;
2270 portal->here->portals = portal;
2272 // advance to next portal
2275 FreeWinding(p->winding);
2287 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2290 Host_Error ("AddPortalToNodes: NULL front node");
2292 Host_Error ("AddPortalToNodes: NULL back node");
2293 if (p->nodes[0] || p->nodes[1])
2294 Host_Error ("AddPortalToNodes: already included");
2295 // 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
2297 p->nodes[0] = front;
2298 p->next[0] = (portal_t *)front->portals;
2299 front->portals = (mportal_t *)p;
2302 p->next[1] = (portal_t *)back->portals;
2303 back->portals = (mportal_t *)p;
2308 RemovePortalFromNode
2311 static void RemovePortalFromNodes(portal_t *portal)
2315 void **portalpointer;
2317 for (i = 0;i < 2;i++)
2319 node = portal->nodes[i];
2321 portalpointer = (void **) &node->portals;
2326 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2330 if (portal->nodes[0] == node)
2332 *portalpointer = portal->next[0];
2333 portal->nodes[0] = NULL;
2335 else if (portal->nodes[1] == node)
2337 *portalpointer = portal->next[1];
2338 portal->nodes[1] = NULL;
2341 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2345 if (t->nodes[0] == node)
2346 portalpointer = (void **) &t->next[0];
2347 else if (t->nodes[1] == node)
2348 portalpointer = (void **) &t->next[1];
2350 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2355 static void Mod_RecursiveNodePortals (mnode_t *node)
2358 mnode_t *front, *back, *other_node;
2359 mplane_t clipplane, *plane;
2360 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2361 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2363 // if a leaf, we're done
2367 plane = node->plane;
2369 front = node->children[0];
2370 back = node->children[1];
2372 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2374 // create the new portal by generating a polygon for the node plane,
2375 // and clipping it by all of the other portals (which came from nodes above this one)
2376 nodeportal = AllocPortal ();
2377 nodeportal->plane = *node->plane;
2379 nodeportalwinding = BaseWindingForPlane (node->plane);
2380 side = 0; // shut up compiler warning
2381 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2383 clipplane = portal->plane;
2384 if (portal->nodes[0] == portal->nodes[1])
2385 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2386 if (portal->nodes[0] == node)
2388 else if (portal->nodes[1] == node)
2390 clipplane.dist = -clipplane.dist;
2391 VectorNegate (clipplane.normal, clipplane.normal);
2395 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2397 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2398 if (!nodeportalwinding)
2400 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2405 if (nodeportalwinding)
2407 // if the plane was not clipped on all sides, there was an error
2408 nodeportal->winding = nodeportalwinding;
2409 AddPortalToNodes (nodeportal, front, back);
2412 // split the portals of this node along this node's plane and assign them to the children of this node
2413 // (migrating the portals downward through the tree)
2414 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2416 if (portal->nodes[0] == portal->nodes[1])
2417 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2418 if (portal->nodes[0] == node)
2420 else if (portal->nodes[1] == node)
2423 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2424 nextportal = portal->next[side];
2426 other_node = portal->nodes[!side];
2427 RemovePortalFromNodes (portal);
2429 // cut the portal into two portals, one on each side of the node plane
2430 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2435 AddPortalToNodes (portal, back, other_node);
2437 AddPortalToNodes (portal, other_node, back);
2443 AddPortalToNodes (portal, front, other_node);
2445 AddPortalToNodes (portal, other_node, front);
2449 // the winding is split
2450 splitportal = AllocPortal ();
2451 temp = splitportal->chain;
2452 *splitportal = *portal;
2453 splitportal->chain = temp;
2454 splitportal->winding = backwinding;
2455 FreeWinding (portal->winding);
2456 portal->winding = frontwinding;
2460 AddPortalToNodes (portal, front, other_node);
2461 AddPortalToNodes (splitportal, back, other_node);
2465 AddPortalToNodes (portal, other_node, front);
2466 AddPortalToNodes (splitportal, other_node, back);
2470 Mod_RecursiveNodePortals(front);
2471 Mod_RecursiveNodePortals(back);
2475 static void Mod_MakePortals(void)
2478 Mod_RecursiveNodePortals (loadmodel->nodes);
2479 Mod_FinalizePortals();
2482 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2485 int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2486 msurface_t *surf, *s;
2487 float *v0, *v1, *v2, *v3;
2488 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2489 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2490 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2492 for (vertnum = surf->poly_numverts - 1, vertnum2 = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;vertnum2 < surf->poly_numverts;vertnum = vertnum2, vertnum2++, v0 = v1, v1 += 3)
2494 if (surf->neighborsurfaces[vertnum])
2496 surf->neighborsurfaces[vertnum] = NULL;
2497 for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2499 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2500 || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2501 || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2504 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2505 if (s->neighborsurfaces[vnum] == surf)
2507 if (vnum < s->poly_numverts)
2509 for (vnum = s->poly_numverts - 1, vnum2 = 0, v2 = s->poly_verts + (s->poly_numverts - 1) * 3, v3 = s->poly_verts;vnum2 < s->poly_numverts;vnum = vnum2, vnum2++, v2 = v3, v3 += 3)
2511 if (s->neighborsurfaces[vnum] == NULL
2512 && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2513 || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2515 surf->neighborsurfaces[vertnum] = s;
2516 s->neighborsurfaces[vnum] = surf;
2520 if (vnum < s->poly_numverts)
2528 void Mod_BuildLightmapUpdateChains(mempool_t *mempool, model_t *model)
2530 int i, j, stylecounts[256], totalcount, remapstyles[256];
2532 memset(stylecounts, 0, sizeof(stylecounts));
2533 for (i = 0;i < model->nummodelsurfaces;i++)
2535 surf = model->surfaces + model->firstmodelsurface + i;
2536 for (j = 0;j < MAXLIGHTMAPS;j++)
2537 stylecounts[surf->styles[j]]++;
2540 model->light_styles = 0;
2541 for (i = 0;i < 255;i++)
2545 remapstyles[i] = model->light_styles++;
2546 totalcount += stylecounts[i] + 1;
2551 model->light_style = Mem_Alloc(mempool, model->light_styles * sizeof(qbyte));
2552 model->light_stylevalue = Mem_Alloc(mempool, model->light_styles * sizeof(int));
2553 model->light_styleupdatechains = Mem_Alloc(mempool, model->light_styles * sizeof(msurface_t **));
2554 model->light_styleupdatechainsbuffer = Mem_Alloc(mempool, totalcount * sizeof(msurface_t *));
2555 model->light_styles = 0;
2556 for (i = 0;i < 255;i++)
2558 model->light_style[model->light_styles++] = i;
2560 for (i = 0;i < model->light_styles;i++)
2562 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2563 j += stylecounts[model->light_style[i]] + 1;
2565 for (i = 0;i < model->nummodelsurfaces;i++)
2567 surf = model->surfaces + model->firstmodelsurface + i;
2568 for (j = 0;j < MAXLIGHTMAPS;j++)
2569 if (surf->styles[j] != 255)
2570 *model->light_styleupdatechains[remapstyles[surf->styles[j]]]++ = surf;
2573 for (i = 0;i < model->light_styles;i++)
2575 *model->light_styleupdatechains[i] = NULL;
2576 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2577 j += stylecounts[model->light_style[i]] + 1;
2581 void Mod_BuildPVSTextureChains(model_t *model)
2584 for (i = 0;i < model->numtextures;i++)
2585 model->pvstexturechainslength[i] = 0;
2586 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2588 if (model->surfacepvsframes[j] == model->pvsframecount)
2590 model->pvssurflist[model->pvssurflistlength++] = j;
2591 model->pvstexturechainslength[model->surfaces[j].texinfo->texture->number]++;
2594 for (i = 0, j = 0;i < model->numtextures;i++)
2596 if (model->pvstexturechainslength[i])
2598 model->pvstexturechains[i] = model->pvstexturechainsbuffer + j;
2599 j += model->pvstexturechainslength[i] + 1;
2602 model->pvstexturechains[i] = NULL;
2604 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2605 if (model->surfacepvsframes[j] == model->pvsframecount)
2606 *model->pvstexturechains[model->surfaces[j].texinfo->texture->number]++ = model->surfaces + j;
2607 for (i = 0;i < model->numtextures;i++)
2609 if (model->pvstexturechainslength[i])
2611 *model->pvstexturechains[i] = NULL;
2612 model->pvstexturechains[i] -= model->pvstexturechainslength[i];
2622 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2623 extern void R_Model_Brush_Draw(entity_render_t *ent);
2624 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2625 extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor);
2626 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2631 mempool_t *mainmempool;
2633 model_t *originalloadmodel;
2634 float dist, modelyawradius, modelradius, *vec;
2638 mod->type = mod_brush;
2640 header = (dheader_t *)buffer;
2642 i = LittleLong (header->version);
2643 if (i != BSPVERSION && i != 30)
2644 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2645 mod->ishlbsp = i == 30;
2646 if (loadmodel->isworldmodel)
2648 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2649 // until we get a texture for it...
2653 // swap all the lumps
2654 mod_base = (qbyte *)header;
2656 for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
2657 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2661 // store which lightmap format to use
2662 mod->lightmaprgba = r_lightmaprgba.integer;
2664 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2665 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2666 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2667 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2668 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2669 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2670 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2671 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2672 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2673 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2674 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2675 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2676 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2677 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2678 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2683 mod->numframes = 2; // regular and alternate animation
2685 mainmempool = mod->mempool;
2686 loadname = mod->name;
2688 Mod_LoadLightList ();
2689 originalloadmodel = loadmodel;
2692 // set up the submodels (FIXME: this is confusing)
2694 for (i = 0;i < mod->numsubmodels;i++)
2696 bm = &mod->submodels[i];
2698 mod->hulls[0].firstclipnode = bm->headnode[0];
2699 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2701 mod->hulls[j].firstclipnode = bm->headnode[j];
2702 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2705 mod->firstmodelsurface = bm->firstface;
2706 mod->nummodelsurfaces = bm->numfaces;
2708 // this gets altered below if sky is used
2709 mod->DrawSky = NULL;
2710 mod->Draw = R_Model_Brush_Draw;
2711 mod->DrawFakeShadow = NULL;
2712 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2713 mod->DrawLight = R_Model_Brush_DrawLight;
2714 mod->pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t **));
2715 mod->pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool, (mod->nummodelsurfaces + mod->numtextures) * sizeof(msurface_t *));
2716 mod->pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(int));
2717 Mod_BuildPVSTextureChains(mod);
2718 Mod_BuildLightmapUpdateChains(originalloadmodel->mempool, mod);
2719 if (mod->nummodelsurfaces)
2721 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2722 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2723 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2726 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2728 // we only need to have a drawsky function if it is used (usually only on world model)
2729 if (surf->texinfo->texture->shader == &Cshader_sky)
2730 mod->DrawSky = R_Model_Brush_DrawSky;
2731 // calculate bounding shapes
2732 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
2734 for (k = 0, vec = mesh->verts;k < mesh->numverts;k++, vec += 4)
2736 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2737 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2738 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2739 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2740 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2741 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2742 dist = vec[0]*vec[0]+vec[1]*vec[1];
2743 if (modelyawradius < dist)
2744 modelyawradius = dist;
2745 dist += vec[2]*vec[2];
2746 if (modelradius < dist)
2751 modelyawradius = sqrt(modelyawradius);
2752 modelradius = sqrt(modelradius);
2753 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2754 mod->yawmins[2] = mod->normalmins[2];
2755 mod->yawmaxs[2] = mod->normalmaxs[2];
2756 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2757 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2758 mod->radius = modelradius;
2759 mod->radius2 = modelradius * modelradius;
2763 // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2764 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2766 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2768 mod->numleafs = bm->visleafs;
2770 // LordHavoc: only register submodels if it is the world
2771 // (prevents bsp models from replacing world submodels)
2772 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2775 // duplicate the basic information
2776 sprintf (name, "*%i", i+1);
2777 loadmodel = Mod_FindName (name);
2779 strcpy (loadmodel->name, name);
2780 // textures and memory belong to the main model
2781 loadmodel->texturepool = NULL;
2782 loadmodel->mempool = NULL;
2787 loadmodel = originalloadmodel;
2788 //Mod_ProcessLightList ();