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 typedef struct findnonsolidlocationinfo_s
103 findnonsolidlocationinfo_t;
106 extern cvar_t samelevel;
108 void Mod_FindNonSolidLocation_r_Leaf(findnonsolidlocationinfo_t *info, mleaf_t *leaf)
110 int i, surfnum, k, *tri, *mark;
111 float dist, f, vert[3][3], edge[3][3], facenormal[3], edgenormal[3][3], point[3];
117 for (surfnum = 0, mark = leaf->firstmarksurface;surfnum < leaf->nummarksurfaces;surfnum++, mark++)
119 surf = info->model->surfaces + *mark;
120 if (surf->flags & SURF_SOLIDCLIP)
123 VectorCopy(surf->plane->normal, surfnormal);
124 if (surf->flags & SURF_PLANEBACK)
125 VectorNegate(surfnormal, surfnormal);
127 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
129 for (k = 0;k < mesh->numtriangles;k++)
131 tri = mesh->element3i + k * 3;
132 VectorCopy((mesh->vertex3f + tri[0] * 3), vert[0]);
133 VectorCopy((mesh->vertex3f + tri[1] * 3), vert[1]);
134 VectorCopy((mesh->vertex3f + tri[2] * 3), vert[2]);
135 VectorSubtract(vert[1], vert[0], edge[0]);
136 VectorSubtract(vert[2], vert[1], edge[1]);
137 CrossProduct(edge[1], edge[0], facenormal);
138 if (facenormal[0] || facenormal[1] || facenormal[2])
140 VectorNormalize(facenormal);
142 if (VectorDistance(facenormal, surfnormal) > 0.01f)
143 Con_Printf("a2! %f %f %f != %f %f %f\n", facenormal[0], facenormal[1], facenormal[2], surfnormal[0], surfnormal[1], surfnormal[2]);
145 f = DotProduct(info->center, facenormal) - DotProduct(vert[0], facenormal);
146 if (f <= info->bestdist && f >= -info->bestdist)
148 VectorSubtract(vert[0], vert[2], edge[2]);
149 VectorNormalize(edge[0]);
150 VectorNormalize(edge[1]);
151 VectorNormalize(edge[2]);
152 CrossProduct(facenormal, edge[0], edgenormal[0]);
153 CrossProduct(facenormal, edge[1], edgenormal[1]);
154 CrossProduct(facenormal, edge[2], edgenormal[2]);
156 if (samelevel.integer & 1)
157 VectorNegate(edgenormal[0], edgenormal[0]);
158 if (samelevel.integer & 2)
159 VectorNegate(edgenormal[1], edgenormal[1]);
160 if (samelevel.integer & 4)
161 VectorNegate(edgenormal[2], edgenormal[2]);
162 for (i = 0;i < 3;i++)
163 if (DotProduct(vert[0], edgenormal[i]) > DotProduct(vert[i], edgenormal[i]) + 0.1f
164 || DotProduct(vert[1], edgenormal[i]) > DotProduct(vert[i], edgenormal[i]) + 0.1f
165 || DotProduct(vert[2], edgenormal[i]) > DotProduct(vert[i], edgenormal[i]) + 0.1f)
166 Con_Printf("a! %i : %f %f %f (%f %f %f)\n", i, edgenormal[i][0], edgenormal[i][1], edgenormal[i][2], facenormal[0], facenormal[1], facenormal[2]);
169 if (DotProduct(info->center, edgenormal[0]) < DotProduct(vert[0], edgenormal[0])
170 && DotProduct(info->center, edgenormal[1]) < DotProduct(vert[1], edgenormal[1])
171 && DotProduct(info->center, edgenormal[2]) < DotProduct(vert[2], edgenormal[2]))
173 // we got lucky, the center is within the face
174 dist = DotProduct(info->center, facenormal) - DotProduct(vert[0], facenormal);
178 if (info->bestdist > dist)
180 info->bestdist = dist;
181 VectorScale(facenormal, (info->radius - -dist), info->nudge);
186 if (info->bestdist > dist)
188 info->bestdist = dist;
189 VectorScale(facenormal, (info->radius - dist), info->nudge);
195 // check which edge or vertex the center is nearest
196 for (i = 0;i < 3;i++)
198 f = DotProduct(info->center, edge[i]);
199 if (f >= DotProduct(vert[0], edge[i])
200 && f <= DotProduct(vert[1], edge[i]))
203 VectorMA(info->center, -f, edge[i], point);
204 dist = sqrt(DotProduct(point, point));
205 if (info->bestdist > dist)
207 info->bestdist = dist;
208 VectorScale(point, (info->radius / dist), info->nudge);
210 // skip both vertex checks
211 // (both are further away than this edge)
216 // not on edge, check first vertex of edge
217 VectorSubtract(info->center, vert[i], point);
218 dist = sqrt(DotProduct(point, point));
219 if (info->bestdist > dist)
221 info->bestdist = dist;
222 VectorScale(point, (info->radius / dist), info->nudge);
235 void Mod_FindNonSolidLocation_r(findnonsolidlocationinfo_t *info, mnode_t *node)
239 if (((mleaf_t *)node)->nummarksurfaces)
240 Mod_FindNonSolidLocation_r_Leaf(info, (mleaf_t *)node);
244 float f = PlaneDiff(info->center, node->plane);
245 if (f >= -info->bestdist)
246 Mod_FindNonSolidLocation_r(info, node->children[0]);
247 if (f <= info->bestdist)
248 Mod_FindNonSolidLocation_r(info, node->children[1]);
252 void Mod_FindNonSolidLocation(vec3_t in, vec3_t out, model_t *model, float radius)
255 findnonsolidlocationinfo_t info;
256 VectorCopy(in, info.center);
257 info.radius = radius;
262 VectorClear(info.nudge);
263 info.bestdist = radius;
264 Mod_FindNonSolidLocation_r(&info, model->nodes + model->hulls[0].firstclipnode);
265 VectorAdd(info.center, info.nudge, info.center);
267 while(info.bestdist < radius && ++i < 10);
268 VectorCopy(info.center, out);
276 static qbyte *Mod_DecompressVis (qbyte *in, model_t *model)
278 static qbyte decompressed[MAX_MAP_LEAFS/8];
283 row = (model->numleafs+7)>>3;
301 } while (out - decompressed < row);
306 qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
308 if (r_novis.integer || leaf == model->leafs || leaf->compressed_vis == NULL)
310 return Mod_DecompressVis (leaf->compressed_vis, model);
318 static void Mod_LoadTextures (lump_t *l)
320 int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs, incomplete;
322 texture_t *tx, *tx2, *anims[10], *altanims[10];
324 qbyte *data, *mtdata;
327 loadmodel->textures = NULL;
332 m = (dmiptexlump_t *)(mod_base + l->fileofs);
334 m->nummiptex = LittleLong (m->nummiptex);
336 // add two slots for notexture walls and notexture liquids
337 loadmodel->numtextures = m->nummiptex + 2;
338 loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(texture_t));
340 // fill out all slots with notexture
341 for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++)
344 strcpy(tx->name, "NO TEXTURE FOUND");
347 tx->skin.base = r_notexture;
348 tx->shader = &Cshader_wall_lightmap;
349 tx->flags = SURF_SOLIDCLIP;
350 if (i == loadmodel->numtextures - 1)
352 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
353 tx->shader = &Cshader_water;
355 tx->currentframe = tx;
358 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
360 // LordHavoc: mostly rewritten map texture loader
361 for (i = 0;i < m->nummiptex;i++)
363 dofs[i] = LittleLong(dofs[i]);
364 if (dofs[i] == -1 || r_nosurftextures.integer)
366 dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
368 // make sure name is no more than 15 characters
369 for (j = 0;dmiptex->name[j] && j < 15;j++)
370 name[j] = dmiptex->name[j];
373 mtwidth = LittleLong (dmiptex->width);
374 mtheight = LittleLong (dmiptex->height);
376 j = LittleLong (dmiptex->offsets[0]);
380 if (j < 40 || j + mtwidth * mtheight > l->filelen)
382 Con_Printf ("Texture \"%s\" in \"%s\"is corrupt or incomplete\n", dmiptex->name, loadmodel->name);
385 mtdata = (qbyte *)dmiptex + j;
388 if ((mtwidth & 15) || (mtheight & 15))
389 Con_Printf ("warning: texture \"%s\" in \"%s\" is not 16 aligned", dmiptex->name, loadmodel->name);
391 // LordHavoc: force all names to lowercase
392 for (j = 0;name[j];j++)
393 if (name[j] >= 'A' && name[j] <= 'Z')
394 name[j] += 'a' - 'A';
396 tx = loadmodel->textures + i;
397 strcpy(tx->name, name);
399 tx->height = mtheight;
403 sprintf(tx->name, "unnamed%i", i);
404 Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
407 // LordHavoc: HL sky textures are entirely different than quake
408 if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
410 if (loadmodel->isworldmodel)
412 data = loadimagepixels(tx->name, false, 0, 0);
415 if (image_width == 256 && image_height == 128)
423 Con_Printf ("Invalid replacement texture for sky \"%s\" in %\"%s\", must be 256x128 pixels\n", tx->name, loadmodel->name);
425 R_InitSky (mtdata, 1);
428 else if (mtdata != NULL)
429 R_InitSky (mtdata, 1);
434 if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true))
436 // did not find external texture, load it from the bsp or wad3
437 if (loadmodel->ishlbsp)
439 // internal texture overrides wad
440 qbyte *pixels, *freepixels;
441 pixels = freepixels = NULL;
443 pixels = W_ConvertWAD3Texture(dmiptex);
445 pixels = freepixels = W_GetTexture(tx->name);
448 tx->width = image_width;
449 tx->height = image_height;
450 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);
453 Mem_Free(freepixels);
455 else if (mtdata) // texture included
456 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);
459 if (tx->skin.base == NULL)
464 tx->skin.base = r_notexture;
467 if (tx->name[0] == '*')
469 // turb does not block movement
470 tx->flags &= ~SURF_SOLIDCLIP;
471 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
472 // LordHavoc: some turbulent textures should be fullbright and solid
473 if (!strncmp(tx->name,"*lava",5)
474 || !strncmp(tx->name,"*teleport",9)
475 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
476 tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
478 tx->flags |= SURF_WATERALPHA;
479 tx->shader = &Cshader_water;
481 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
483 tx->flags |= SURF_DRAWSKY;
484 tx->shader = &Cshader_sky;
488 tx->flags |= SURF_LIGHTMAP;
490 tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT;
491 tx->shader = &Cshader_wall_lightmap;
494 // start out with no animation
495 tx->currentframe = tx;
498 // sequence the animations
499 for (i = 0;i < m->nummiptex;i++)
501 tx = loadmodel->textures + i;
502 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
504 if (tx->anim_total[0] || tx->anim_total[1])
505 continue; // already sequenced
507 // find the number of frames in the animation
508 memset (anims, 0, sizeof(anims));
509 memset (altanims, 0, sizeof(altanims));
511 for (j = i;j < m->nummiptex;j++)
513 tx2 = loadmodel->textures + j;
514 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
518 if (num >= '0' && num <= '9')
519 anims[num - '0'] = tx2;
520 else if (num >= 'a' && num <= 'j')
521 altanims[num - 'a'] = tx2;
523 Con_Printf ("Bad animating texture %s\n", tx->name);
527 for (j = 0;j < 10;j++)
534 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
537 for (j = 0;j < max;j++)
541 Con_Printf ("Missing frame %i of %s\n", j, tx->name);
545 for (j = 0;j < altmax;j++)
549 Con_Printf ("Missing altframe %i of %s\n", j, tx->name);
558 // if there is no alternate animation, duplicate the primary
559 // animation into the alternate
561 for (k = 0;k < 10;k++)
562 altanims[k] = anims[k];
565 // link together the primary animation
566 for (j = 0;j < max;j++)
569 tx2->animated = true;
570 tx2->anim_total[0] = max;
571 tx2->anim_total[1] = altmax;
572 for (k = 0;k < 10;k++)
574 tx2->anim_frames[0][k] = anims[k];
575 tx2->anim_frames[1][k] = altanims[k];
579 // if there really is an alternate anim...
580 if (anims[0] != altanims[0])
582 // link together the alternate animation
583 for (j = 0;j < altmax;j++)
586 tx2->animated = true;
587 // the primary/alternate are reversed here
588 tx2->anim_total[0] = altmax;
589 tx2->anim_total[1] = max;
590 for (k = 0;k < 10;k++)
592 tx2->anim_frames[0][k] = altanims[k];
593 tx2->anim_frames[1][k] = anims[k];
605 static void Mod_LoadLighting (lump_t *l)
608 qbyte *in, *out, *data, d;
609 char litfilename[1024];
610 loadmodel->lightdata = NULL;
611 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
613 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
614 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
616 else // LordHavoc: bsp version 29 (normal white lighting)
618 // LordHavoc: hope is not lost yet, check for a .lit file to load
619 strcpy(litfilename, loadmodel->name);
620 FS_StripExtension(litfilename, litfilename);
621 strcat(litfilename, ".lit");
622 data = (qbyte*) FS_LoadFile (litfilename, false);
625 if (fs_filesize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
627 i = LittleLong(((int *)data)[1]);
630 Con_DPrintf("loaded %s\n", litfilename);
631 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, fs_filesize - 8);
632 memcpy(loadmodel->lightdata, data + 8, fs_filesize - 8);
638 Con_Printf("Unknown .lit file version (%d)\n", i);
644 if (fs_filesize == 8)
645 Con_Printf("Empty .lit file, ignoring\n");
647 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
651 // LordHavoc: oh well, expand the white lighting data
654 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
655 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
656 out = loadmodel->lightdata;
657 memcpy (in, mod_base + l->fileofs, l->filelen);
658 for (i = 0;i < l->filelen;i++)
668 void Mod_LoadLightList(void)
671 char lightsfilename[1024], *s, *t, *lightsstring;
674 strcpy(lightsfilename, loadmodel->name);
675 FS_StripExtension(lightsfilename, lightsfilename);
676 strcat(lightsfilename, ".lights");
677 s = lightsstring = (char *) FS_LoadFile (lightsfilename, false);
683 while (*s && *s != '\n')
687 Mem_Free(lightsstring);
688 Host_Error("lights file must end with a newline\n");
693 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
696 while (*s && n < numlights)
699 while (*s && *s != '\n')
703 Mem_Free(lightsstring);
704 Host_Error("misparsed lights file!\n");
706 e = loadmodel->lights + n;
708 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);
712 Mem_Free(lightsstring);
713 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);
720 Mem_Free(lightsstring);
721 Host_Error("misparsed lights file!\n");
723 loadmodel->numlights = numlights;
724 Mem_Free(lightsstring);
729 static int castshadowcount = 0;
730 void Mod_ProcessLightList(void)
732 int j, k, l, *mark, lnum;
740 for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++)
742 e->cullradius2 = DotProduct(e->light, e->light) / (e->falloff * e->falloff * 8192.0f * 8192.0f * 2.0f * 2.0f);// + 4096.0f;
743 if (e->cullradius2 > 4096.0f * 4096.0f)
744 e->cullradius2 = 4096.0f * 4096.0f;
745 e->cullradius = e->lightradius = sqrt(e->cullradius2);
746 leaf = Mod_PointInLeaf(e->origin, loadmodel);
747 if (leaf->compressed_vis)
748 pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel);
751 for (j = 0;j < loadmodel->numsurfaces;j++)
752 loadmodel->surfacevisframes[j] = -1;
753 for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++)
755 if (pvs[j >> 3] & (1 << (j & 7)))
757 for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++)
759 surf = loadmodel->surfaces + *mark;
760 if (surf->number != *mark)
761 Con_Printf("%d != %d\n", surf->number, *mark);
762 dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
763 if (surf->flags & SURF_PLANEBACK)
765 if (dist > 0 && dist < e->cullradius)
767 temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
768 temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
769 temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
770 if (DotProduct(temp, temp) < lightradius2)
771 loadmodel->surfacevisframes[*mark] = -2;
776 // build list of light receiving surfaces
778 for (j = 0;j < loadmodel->numsurfaces;j++)
779 if (loadmodel->surfacevisframes[j] == -2)
782 if (e->numsurfaces > 0)
784 e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
786 for (j = 0;j < loadmodel->numsurfaces;j++)
787 if (loadmodel->surfacevisframes[j] == -2)
788 e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j;
790 // find bounding box and sphere of lit surfaces
791 // (these will be used for creating a shape to clip the light)
793 for (j = 0;j < e->numsurfaces;j++)
795 surf = e->surfaces[j];
798 VectorCopy(surf->poly_verts, e->mins);
799 VectorCopy(surf->poly_verts, e->maxs);
801 for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
803 if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
804 if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
805 if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
806 VectorSubtract(v, e->origin, temp);
807 dist = DotProduct(temp, temp);
812 if (e->cullradius2 > radius2)
814 e->cullradius2 = radius2;
815 e->cullradius = sqrt(e->cullradius2);
817 if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
818 if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
819 if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
820 if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
821 if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
822 if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
823 // clip shadow volumes against eachother to remove unnecessary
824 // polygons (and sections of polygons)
826 //vec3_t polymins, polymaxs;
828 float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
829 float f, *v0, *v1, projectdistance;
831 e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024);
834 vec3_t outermins, outermaxs, innermins, innermaxs;
835 innermins[0] = e->mins[0] - 1;
836 innermins[1] = e->mins[1] - 1;
837 innermins[2] = e->mins[2] - 1;
838 innermaxs[0] = e->maxs[0] + 1;
839 innermaxs[1] = e->maxs[1] + 1;
840 innermaxs[2] = e->maxs[2] + 1;
841 outermins[0] = loadmodel->normalmins[0] - 1;
842 outermins[1] = loadmodel->normalmins[1] - 1;
843 outermins[2] = loadmodel->normalmins[2] - 1;
844 outermaxs[0] = loadmodel->normalmaxs[0] + 1;
845 outermaxs[1] = loadmodel->normalmaxs[1] + 1;
846 outermaxs[2] = loadmodel->normalmaxs[2] + 1;
847 // add bounding box around the whole shadow volume set,
848 // facing inward to limit light area, with an outer bounding box
849 // facing outward (this is needed by the shadow rendering method)
851 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
852 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
853 verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
854 verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
855 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
856 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
857 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
858 verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
859 verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
860 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
862 verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
863 verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
864 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
865 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
866 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
867 verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
868 verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
869 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
870 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
871 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
873 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
874 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
875 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
876 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
877 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
878 verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
879 verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
880 verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
881 verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
882 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
884 verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
885 verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
886 verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
887 verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
888 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
889 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
890 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
891 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
892 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
893 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
895 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
896 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2];
897 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2];
898 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
899 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
900 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
901 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2];
902 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2];
903 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
904 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
906 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2];
907 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
908 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
909 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2];
910 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
911 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2];
912 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
913 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
914 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2];
915 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
919 for (j = 0;j < e->numsurfaces;j++)
921 surf = e->surfaces[j];
922 if (surf->flags & SURF_SHADOWCAST)
923 surf->castshadow = castshadowcount;
925 for (j = 0;j < e->numsurfaces;j++)
927 surf = e->surfaces[j];
928 if (surf->castshadow != castshadowcount)
930 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
931 if (surf->flags & SURF_PLANEBACK)
933 projectdistance = e->lightradius;
934 if (maxverts < surf->poly_numverts)
936 maxverts = surf->poly_numverts;
939 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
941 // copy the original polygon, for the front cap of the volume
942 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
944 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
945 // project the original polygon, reversed, for the back cap of the volume
946 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
948 VectorSubtract(v0, e->origin, temp);
949 VectorNormalize(temp);
950 VectorMA(v0, projectdistance, temp, v1);
952 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
953 // project the shadow volume sides
954 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)
956 if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount)
958 VectorCopy(v1, &verts[0]);
959 VectorCopy(v0, &verts[3]);
960 VectorCopy(v0, &verts[6]);
961 VectorCopy(v1, &verts[9]);
962 VectorSubtract(&verts[6], e->origin, temp);
963 VectorNormalize(temp);
964 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
965 VectorSubtract(&verts[9], e->origin, temp);
966 VectorNormalize(temp);
967 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
968 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
972 // build the triangle mesh
973 e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume);
977 for (mesh = e->shadowvolume;mesh;mesh = mesh->next)
978 l += mesh->numtriangles;
979 Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l);
992 static void Mod_LoadVisibility (lump_t *l)
994 loadmodel->visdata = NULL;
997 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
998 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
1001 // used only for HalfLife maps
1002 void Mod_ParseWadsFromEntityLump(const char *data)
1004 char key[128], value[4096];
1009 if (!COM_ParseToken(&data))
1011 if (com_token[0] != '{')
1015 if (!COM_ParseToken(&data))
1017 if (com_token[0] == '}')
1018 break; // end of worldspawn
1019 if (com_token[0] == '_')
1020 strcpy(key, com_token + 1);
1022 strcpy(key, com_token);
1023 while (key[strlen(key)-1] == ' ') // remove trailing spaces
1024 key[strlen(key)-1] = 0;
1025 if (!COM_ParseToken(&data))
1027 strcpy(value, com_token);
1028 if (!strcmp("wad", key)) // for HalfLife maps
1030 if (loadmodel->ishlbsp)
1033 for (i = 0;i < 4096;i++)
1034 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
1040 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
1041 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
1043 else if (value[i] == ';' || value[i] == 0)
1047 strcpy(wadname, "textures/");
1048 strcat(wadname, &value[j]);
1049 W_LoadTextureWadFile (wadname, false);
1066 static void Mod_LoadEntities (lump_t *l)
1068 loadmodel->entities = NULL;
1071 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
1072 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
1073 if (loadmodel->ishlbsp)
1074 Mod_ParseWadsFromEntityLump(loadmodel->entities);
1083 static void Mod_LoadVertexes (lump_t *l)
1089 in = (void *)(mod_base + l->fileofs);
1090 if (l->filelen % sizeof(*in))
1091 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1092 count = l->filelen / sizeof(*in);
1093 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1095 loadmodel->vertexes = out;
1096 loadmodel->numvertexes = count;
1098 for ( i=0 ; i<count ; i++, in++, out++)
1100 out->position[0] = LittleFloat (in->point[0]);
1101 out->position[1] = LittleFloat (in->point[1]);
1102 out->position[2] = LittleFloat (in->point[2]);
1111 static void Mod_LoadSubmodels (lump_t *l)
1117 in = (void *)(mod_base + l->fileofs);
1118 if (l->filelen % sizeof(*in))
1119 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1120 count = l->filelen / sizeof(*in);
1121 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1123 loadmodel->submodels = out;
1124 loadmodel->numsubmodels = count;
1126 for ( i=0 ; i<count ; i++, in++, out++)
1128 for (j=0 ; j<3 ; j++)
1130 // spread the mins / maxs by a pixel
1131 out->mins[j] = LittleFloat (in->mins[j]) - 1;
1132 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
1133 out->origin[j] = LittleFloat (in->origin[j]);
1135 for (j=0 ; j<MAX_MAP_HULLS ; j++)
1136 out->headnode[j] = LittleLong (in->headnode[j]);
1137 out->visleafs = LittleLong (in->visleafs);
1138 out->firstface = LittleLong (in->firstface);
1139 out->numfaces = LittleLong (in->numfaces);
1148 static void Mod_LoadEdges (lump_t *l)
1154 in = (void *)(mod_base + l->fileofs);
1155 if (l->filelen % sizeof(*in))
1156 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1157 count = l->filelen / sizeof(*in);
1158 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1160 loadmodel->edges = out;
1161 loadmodel->numedges = count;
1163 for ( i=0 ; i<count ; i++, in++, out++)
1165 out->v[0] = (unsigned short)LittleShort(in->v[0]);
1166 out->v[1] = (unsigned short)LittleShort(in->v[1]);
1175 static void Mod_LoadTexinfo (lump_t *l)
1179 int i, j, k, count, miptex;
1181 in = (void *)(mod_base + l->fileofs);
1182 if (l->filelen % sizeof(*in))
1183 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1184 count = l->filelen / sizeof(*in);
1185 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1187 loadmodel->texinfo = out;
1188 loadmodel->numtexinfo = count;
1190 for (i = 0;i < count;i++, in++, out++)
1192 for (k = 0;k < 2;k++)
1193 for (j = 0;j < 4;j++)
1194 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
1196 miptex = LittleLong (in->miptex);
1197 out->flags = LittleLong (in->flags);
1199 out->texture = NULL;
1200 if (loadmodel->textures)
1202 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
1203 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
1205 out->texture = loadmodel->textures + miptex;
1207 if (out->flags & TEX_SPECIAL)
1209 // if texture chosen is NULL or the shader needs a lightmap,
1210 // force to notexture water shader
1211 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
1212 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
1216 // if texture chosen is NULL, force to notexture
1217 if (out->texture == NULL)
1218 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
1223 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1228 mins[0] = mins[1] = mins[2] = 9999;
1229 maxs[0] = maxs[1] = maxs[2] = -9999;
1231 for (i = 0;i < numverts;i++)
1233 for (j = 0;j < 3;j++, v++)
1244 #define MAX_SUBDIVPOLYTRIANGLES 4096
1245 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1247 static int subdivpolyverts, subdivpolytriangles;
1248 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1249 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1251 static int subdivpolylookupvert(vec3_t v)
1254 for (i = 0;i < subdivpolyverts;i++)
1255 if (subdivpolyvert[i][0] == v[0]
1256 && subdivpolyvert[i][1] == v[1]
1257 && subdivpolyvert[i][2] == v[2])
1259 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1260 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1261 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1262 return subdivpolyverts++;
1265 static void SubdividePolygon (int numverts, float *verts)
1267 int i, i1, i2, i3, f, b, c, p;
1268 vec3_t mins, maxs, front[256], back[256];
1269 float m, *pv, *cv, dist[256], frac;
1272 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1274 BoundPoly (numverts, verts, mins, maxs);
1276 for (i = 0;i < 3;i++)
1278 m = (mins[i] + maxs[i]) * 0.5;
1279 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1280 if (maxs[i] - m < 8)
1282 if (m - mins[i] < 8)
1286 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1287 dist[c] = cv[i] - m;
1290 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1294 VectorCopy (pv, front[f]);
1299 VectorCopy (pv, back[b]);
1302 if (dist[p] == 0 || dist[c] == 0)
1304 if ( (dist[p] > 0) != (dist[c] > 0) )
1307 frac = dist[p] / (dist[p] - dist[c]);
1308 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1309 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1310 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1316 SubdividePolygon (f, front[0]);
1317 SubdividePolygon (b, back[0]);
1321 i1 = subdivpolylookupvert(verts);
1322 i2 = subdivpolylookupvert(verts + 3);
1323 for (i = 2;i < numverts;i++)
1325 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1327 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1331 i3 = subdivpolylookupvert(verts + i * 3);
1332 subdivpolyindex[subdivpolytriangles][0] = i1;
1333 subdivpolyindex[subdivpolytriangles][1] = i2;
1334 subdivpolyindex[subdivpolytriangles][2] = i3;
1336 subdivpolytriangles++;
1342 Mod_GenerateWarpMesh
1344 Breaks a polygon up along axial 64 unit
1345 boundaries so that turbulent and sky warps
1346 can be done reasonably.
1349 void Mod_GenerateWarpMesh (msurface_t *surf)
1355 subdivpolytriangles = 0;
1356 subdivpolyverts = 0;
1357 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1358 if (subdivpolytriangles < 1)
1359 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1361 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1362 mesh->numverts = subdivpolyverts;
1363 mesh->numtriangles = subdivpolytriangles;
1364 mesh->vertex = (surfvertex_t *)(mesh + 1);
1365 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1366 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1368 for (i = 0;i < mesh->numtriangles;i++)
1369 for (j = 0;j < 3;j++)
1370 mesh->index[i*3+j] = subdivpolyindex[i][j];
1372 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1374 VectorCopy(subdivpolyvert[i], v->v);
1375 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1376 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1381 surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles)
1384 mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (3 + 2 + 2 + 2 + 3 + 3 + 3 + 1) * sizeof(float));
1385 mesh->numverts = numverts;
1386 mesh->numtriangles = numtriangles;
1387 mesh->vertex3f = (float *)(mesh + 1);
1388 mesh->texcoordtexture2f = mesh->vertex3f + mesh->numverts * 3;
1389 mesh->texcoordlightmap2f = mesh->texcoordtexture2f + mesh->numverts * 2;
1390 mesh->texcoorddetail2f = mesh->texcoordlightmap2f + mesh->numverts * 2;
1391 mesh->svector3f = (float *)(mesh->texcoorddetail2f + mesh->numverts * 2);
1392 mesh->tvector3f = mesh->svector3f + mesh->numverts * 3;
1393 mesh->normal3f = mesh->tvector3f + mesh->numverts * 3;
1394 mesh->lightmapoffsets = (int *)(mesh->normal3f + mesh->numverts * 3);
1395 mesh->element3i = mesh->lightmapoffsets + mesh->numverts;
1396 mesh->neighbor3i = mesh->element3i + mesh->numtriangles * 3;
1400 void Mod_GenerateSurfacePolygon (msurface_t *surf, int firstedge, int numedges)
1403 float *vec, *vert, mins[3], maxs[3], val, *v;
1406 // convert edges back to a normal polygon
1407 surf->poly_numverts = numedges;
1408 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * numedges);
1409 for (i = 0;i < numedges;i++)
1411 lindex = loadmodel->surfedges[firstedge + i];
1413 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1415 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1416 VectorCopy (vec, vert);
1420 // calculate polygon bounding box and center
1421 vert = surf->poly_verts;
1422 VectorCopy(vert, mins);
1423 VectorCopy(vert, maxs);
1425 for (i = 1;i < surf->poly_numverts;i++, vert += 3)
1427 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1428 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1429 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1431 VectorCopy(mins, surf->poly_mins);
1432 VectorCopy(maxs, surf->poly_maxs);
1433 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1434 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1435 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1437 // generate surface extents information
1438 tex = surf->texinfo;
1439 mins[0] = maxs[0] = DotProduct(surf->poly_verts, tex->vecs[0]) + tex->vecs[0][3];
1440 mins[1] = maxs[1] = DotProduct(surf->poly_verts, tex->vecs[1]) + tex->vecs[1][3];
1441 for (i = 1, v = surf->poly_verts + 3;i < surf->poly_numverts;i++, v += 3)
1443 for (j = 0;j < 2;j++)
1445 val = DotProduct(v, tex->vecs[j]) + tex->vecs[j][3];
1452 for (i = 0;i < 2;i++)
1454 surf->texturemins[i] = (int) floor(mins[i] / 16) * 16;
1455 surf->extents[i] = (int) ceil(maxs[i] / 16) * 16 - surf->texturemins[i];
1464 static void Mod_LoadFaces (lump_t *l)
1468 int i, count, surfnum, planenum, ssize, tsize, firstedge, numedges, totalverts, totaltris, totalmeshes;
1472 in = (void *)(mod_base + l->fileofs);
1473 if (l->filelen % sizeof(*in))
1474 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1475 count = l->filelen / sizeof(*in);
1476 loadmodel->surfaces = Mem_Alloc(loadmodel->mempool, count*sizeof(msurface_t));
1478 loadmodel->numsurfaces = count;
1479 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1480 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1481 loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1483 for (surfnum = 0, surf = loadmodel->surfaces, totalverts = 0, totaltris = 0, totalmeshes = 0;surfnum < count;surfnum++, totalverts += surf->poly_numverts, totaltris += surf->poly_numverts - 2, totalmeshes++, in++, surf++)
1485 surf->number = surfnum;
1486 // FIXME: validate edges, texinfo, etc?
1487 firstedge = LittleLong(in->firstedge);
1488 numedges = LittleShort(in->numedges);
1489 if ((unsigned int) firstedge > (unsigned int) loadmodel->numsurfedges || (unsigned int) numedges > (unsigned int) loadmodel->numsurfedges || (unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->numsurfedges)
1490 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->numsurfedges);
1491 i = LittleShort (in->texinfo);
1492 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1493 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1494 surf->texinfo = loadmodel->texinfo + i;
1495 surf->flags = surf->texinfo->texture->flags;
1497 planenum = LittleShort(in->planenum);
1498 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1499 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1501 if (LittleShort(in->side))
1502 surf->flags |= SURF_PLANEBACK;
1504 surf->plane = loadmodel->planes + planenum;
1506 // clear lightmap (filled in later)
1507 surf->lightmaptexture = NULL;
1509 // force lightmap upload on first time seeing the surface
1510 surf->cached_dlight = true;
1512 Mod_GenerateSurfacePolygon(surf, firstedge, numedges);
1514 ssize = (surf->extents[0] >> 4) + 1;
1515 tsize = (surf->extents[1] >> 4) + 1;
1518 for (i = 0;i < MAXLIGHTMAPS;i++)
1519 surf->styles[i] = in->styles[i];
1520 i = LittleLong(in->lightofs);
1522 surf->samples = NULL;
1523 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1524 surf->samples = loadmodel->lightdata + i;
1525 else // LordHavoc: white lighting (bsp version 29)
1526 surf->samples = loadmodel->lightdata + (i * 3);
1528 if (surf->texinfo->texture->shader == &Cshader_wall_lightmap)
1530 if ((surf->extents[0] >> 4) + 1 > (256) || (surf->extents[1] >> 4) + 1 > (256))
1531 Host_Error ("Bad surface extents");
1532 // stainmap for permanent marks on walls
1533 surf->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1535 memset(surf->stainsamples, 255, ssize * tsize * 3);
1539 loadmodel->entiremesh = Mod_AllocSurfMesh(totalverts, totaltris);
1540 loadmodel->surfmeshes = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) * totalmeshes);
1542 for (surfnum = 0, surf = loadmodel->surfaces, totalverts = 0, totaltris = 0, totalmeshes = 0;surfnum < count;surfnum++, totalverts += surf->poly_numverts, totaltris += surf->poly_numverts - 2, totalmeshes++, surf++)
1544 mesh = surf->mesh = loadmodel->surfmeshes + totalmeshes;
1545 mesh->numverts = surf->poly_numverts;
1546 mesh->numtriangles = surf->poly_numverts - 2;
1547 mesh->vertex3f = loadmodel->entiremesh->vertex3f + totalverts * 3;
1548 mesh->texcoordtexture2f = loadmodel->entiremesh->texcoordtexture2f + totalverts * 2;
1549 mesh->texcoordlightmap2f = loadmodel->entiremesh->texcoordlightmap2f + totalverts * 2;
1550 mesh->texcoorddetail2f = loadmodel->entiremesh->texcoorddetail2f + totalverts * 2;
1551 mesh->svector3f = loadmodel->entiremesh->svector3f + totalverts * 3;
1552 mesh->tvector3f = loadmodel->entiremesh->tvector3f + totalverts * 3;
1553 mesh->normal3f = loadmodel->entiremesh->normal3f + totalverts * 3;
1554 mesh->lightmapoffsets = loadmodel->entiremesh->lightmapoffsets + totalverts;
1555 mesh->element3i = loadmodel->entiremesh->element3i + totaltris * 3;
1556 mesh->neighbor3i = loadmodel->entiremesh->neighbor3i + totaltris * 3;
1558 surf->lightmaptexturestride = 0;
1559 surf->lightmaptexture = NULL;
1561 for (i = 0;i < mesh->numverts;i++)
1563 mesh->vertex3f[i * 3 + 0] = surf->poly_verts[i * 3 + 0];
1564 mesh->vertex3f[i * 3 + 1] = surf->poly_verts[i * 3 + 1];
1565 mesh->vertex3f[i * 3 + 2] = surf->poly_verts[i * 3 + 2];
1566 s = DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1567 t = DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1568 mesh->texcoordtexture2f[i * 2 + 0] = s / surf->texinfo->texture->width;
1569 mesh->texcoordtexture2f[i * 2 + 1] = t / surf->texinfo->texture->height;
1570 mesh->texcoorddetail2f[i * 2 + 0] = s * (1.0f / 16.0f);
1571 mesh->texcoorddetail2f[i * 2 + 1] = t * (1.0f / 16.0f);
1572 mesh->texcoordlightmap2f[i * 2 + 0] = 0;
1573 mesh->texcoordlightmap2f[i * 2 + 1] = 0;
1574 mesh->lightmapoffsets[i] = 0;
1577 for (i = 0;i < mesh->numtriangles;i++)
1579 mesh->element3i[i * 3 + 0] = 0;
1580 mesh->element3i[i * 3 + 1] = i + 1;
1581 mesh->element3i[i * 3 + 2] = i + 2;
1584 Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1585 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->vertex3f, mesh->texcoordtexture2f, mesh->element3i, mesh->svector3f, mesh->tvector3f, mesh->normal3f);
1587 if (surf->texinfo->texture->shader == &Cshader_wall_lightmap)
1589 int i, iu, iv, smax, tmax;
1590 float u, v, ubase, vbase, uscale, vscale;
1592 smax = surf->extents[0] >> 4;
1593 tmax = surf->extents[1] >> 4;
1595 surf->flags |= SURF_LIGHTMAP;
1596 if (r_miplightmaps.integer)
1598 surf->lightmaptexturestride = smax+1;
1599 surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
1603 surf->lightmaptexturestride = R_CompatibleFragmentWidth(smax+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1604 surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
1606 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1607 uscale = (uscale - ubase) / (smax + 1);
1608 vscale = (vscale - vbase) / (tmax + 1);
1610 for (i = 0;i < mesh->numverts;i++)
1612 u = ((DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1613 v = ((DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1614 mesh->texcoordlightmap2f[i * 2 + 0] = u * uscale + ubase;
1615 mesh->texcoordlightmap2f[i * 2 + 1] = v * vscale + vbase;
1616 // LordHavoc: calc lightmap data offset for vertex lighting to use
1619 mesh->lightmapoffsets[i] = (bound(0, iv, tmax) * (smax+1) + bound(0, iu, smax)) * 3;
1630 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1632 node->parent = parent;
1633 if (node->contents < 0)
1635 Mod_SetParent (node->children[0], node);
1636 Mod_SetParent (node->children[1], node);
1644 static void Mod_LoadNodes (lump_t *l)
1650 in = (void *)(mod_base + l->fileofs);
1651 if (l->filelen % sizeof(*in))
1652 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1653 count = l->filelen / sizeof(*in);
1654 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1656 loadmodel->nodes = out;
1657 loadmodel->numnodes = count;
1659 for ( i=0 ; i<count ; i++, in++, out++)
1661 for (j=0 ; j<3 ; j++)
1663 out->mins[j] = LittleShort (in->mins[j]);
1664 out->maxs[j] = LittleShort (in->maxs[j]);
1667 p = LittleLong(in->planenum);
1668 out->plane = loadmodel->planes + p;
1670 out->firstsurface = LittleShort (in->firstface);
1671 out->numsurfaces = LittleShort (in->numfaces);
1673 for (j=0 ; j<2 ; j++)
1675 p = LittleShort (in->children[j]);
1677 out->children[j] = loadmodel->nodes + p;
1679 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1683 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1691 static void Mod_LoadLeafs (lump_t *l)
1697 in = (void *)(mod_base + l->fileofs);
1698 if (l->filelen % sizeof(*in))
1699 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1700 count = l->filelen / sizeof(*in);
1701 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1703 loadmodel->leafs = out;
1704 loadmodel->numleafs = count;
1706 for ( i=0 ; i<count ; i++, in++, out++)
1708 for (j=0 ; j<3 ; j++)
1710 out->mins[j] = LittleShort (in->mins[j]);
1711 out->maxs[j] = LittleShort (in->maxs[j]);
1714 p = LittleLong(in->contents);
1717 out->firstmarksurface = loadmodel->marksurfaces +
1718 LittleShort(in->firstmarksurface);
1719 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1721 p = LittleLong(in->visofs);
1723 out->compressed_vis = NULL;
1725 out->compressed_vis = loadmodel->visdata + p;
1727 for (j=0 ; j<4 ; j++)
1728 out->ambient_sound_level[j] = in->ambient_level[j];
1730 // FIXME: Insert caustics here
1739 static void Mod_LoadClipnodes (lump_t *l)
1741 dclipnode_t *in, *out;
1745 in = (void *)(mod_base + l->fileofs);
1746 if (l->filelen % sizeof(*in))
1747 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1748 count = l->filelen / sizeof(*in);
1749 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1751 loadmodel->clipnodes = out;
1752 loadmodel->numclipnodes = count;
1754 if (loadmodel->ishlbsp)
1756 hull = &loadmodel->hulls[1];
1757 hull->clipnodes = out;
1758 hull->firstclipnode = 0;
1759 hull->lastclipnode = count-1;
1760 hull->planes = loadmodel->planes;
1761 hull->clip_mins[0] = -16;
1762 hull->clip_mins[1] = -16;
1763 hull->clip_mins[2] = -36;
1764 hull->clip_maxs[0] = 16;
1765 hull->clip_maxs[1] = 16;
1766 hull->clip_maxs[2] = 36;
1767 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1769 hull = &loadmodel->hulls[2];
1770 hull->clipnodes = out;
1771 hull->firstclipnode = 0;
1772 hull->lastclipnode = count-1;
1773 hull->planes = loadmodel->planes;
1774 hull->clip_mins[0] = -32;
1775 hull->clip_mins[1] = -32;
1776 hull->clip_mins[2] = -32;
1777 hull->clip_maxs[0] = 32;
1778 hull->clip_maxs[1] = 32;
1779 hull->clip_maxs[2] = 32;
1780 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1782 hull = &loadmodel->hulls[3];
1783 hull->clipnodes = out;
1784 hull->firstclipnode = 0;
1785 hull->lastclipnode = count-1;
1786 hull->planes = loadmodel->planes;
1787 hull->clip_mins[0] = -16;
1788 hull->clip_mins[1] = -16;
1789 hull->clip_mins[2] = -18;
1790 hull->clip_maxs[0] = 16;
1791 hull->clip_maxs[1] = 16;
1792 hull->clip_maxs[2] = 18;
1793 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1797 hull = &loadmodel->hulls[1];
1798 hull->clipnodes = out;
1799 hull->firstclipnode = 0;
1800 hull->lastclipnode = count-1;
1801 hull->planes = loadmodel->planes;
1802 hull->clip_mins[0] = -16;
1803 hull->clip_mins[1] = -16;
1804 hull->clip_mins[2] = -24;
1805 hull->clip_maxs[0] = 16;
1806 hull->clip_maxs[1] = 16;
1807 hull->clip_maxs[2] = 32;
1808 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1810 hull = &loadmodel->hulls[2];
1811 hull->clipnodes = out;
1812 hull->firstclipnode = 0;
1813 hull->lastclipnode = count-1;
1814 hull->planes = loadmodel->planes;
1815 hull->clip_mins[0] = -32;
1816 hull->clip_mins[1] = -32;
1817 hull->clip_mins[2] = -24;
1818 hull->clip_maxs[0] = 32;
1819 hull->clip_maxs[1] = 32;
1820 hull->clip_maxs[2] = 64;
1821 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1824 for (i=0 ; i<count ; i++, out++, in++)
1826 out->planenum = LittleLong(in->planenum);
1827 out->children[0] = LittleShort(in->children[0]);
1828 out->children[1] = LittleShort(in->children[1]);
1829 if (out->children[0] >= count || out->children[1] >= count)
1830 Host_Error("Corrupt clipping hull (out of range child)\n");
1838 Duplicate the drawing hull structure as a clipping hull
1841 static void Mod_MakeHull0 (void)
1848 hull = &loadmodel->hulls[0];
1850 in = loadmodel->nodes;
1851 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1853 hull->clipnodes = out;
1854 hull->firstclipnode = 0;
1855 hull->lastclipnode = loadmodel->numnodes - 1;
1856 hull->planes = loadmodel->planes;
1858 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1860 out->planenum = in->plane - loadmodel->planes;
1861 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1862 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1868 Mod_LoadMarksurfaces
1871 static void Mod_LoadMarksurfaces (lump_t *l)
1876 in = (void *)(mod_base + l->fileofs);
1877 if (l->filelen % sizeof(*in))
1878 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1879 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1880 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1882 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1884 j = (unsigned) LittleShort(in[i]);
1885 if (j >= loadmodel->numsurfaces)
1886 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1887 loadmodel->marksurfaces[i] = j;
1896 static void Mod_LoadSurfedges (lump_t *l)
1901 in = (void *)(mod_base + l->fileofs);
1902 if (l->filelen % sizeof(*in))
1903 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1904 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1905 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1907 for (i = 0;i < loadmodel->numsurfedges;i++)
1908 loadmodel->surfedges[i] = LittleLong (in[i]);
1917 static void Mod_LoadPlanes (lump_t *l)
1923 in = (void *)(mod_base + l->fileofs);
1924 if (l->filelen % sizeof(*in))
1925 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1927 loadmodel->numplanes = l->filelen / sizeof(*in);
1928 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1930 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1932 out->normal[0] = LittleFloat (in->normal[0]);
1933 out->normal[1] = LittleFloat (in->normal[1]);
1934 out->normal[2] = LittleFloat (in->normal[2]);
1935 out->dist = LittleFloat (in->dist);
1941 #define MAX_POINTS_ON_WINDING 64
1947 double points[8][3]; // variable sized
1956 static winding_t *NewWinding (int points)
1961 if (points > MAX_POINTS_ON_WINDING)
1962 Sys_Error("NewWinding: too many points\n");
1964 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
1965 w = Mem_Alloc(loadmodel->mempool, size);
1966 memset (w, 0, size);
1971 static void FreeWinding (winding_t *w)
1981 static winding_t *BaseWindingForPlane (mplane_t *p)
1983 double org[3], vright[3], vup[3], normal[3];
1986 VectorCopy(p->normal, normal);
1987 VectorVectorsDouble(normal, vright, vup);
1989 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
1990 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
1992 // project a really big axis aligned box onto the plane
1995 VectorScale (p->normal, p->dist, org);
1997 VectorSubtract (org, vright, w->points[0]);
1998 VectorAdd (w->points[0], vup, w->points[0]);
2000 VectorAdd (org, vright, w->points[1]);
2001 VectorAdd (w->points[1], vup, w->points[1]);
2003 VectorAdd (org, vright, w->points[2]);
2004 VectorSubtract (w->points[2], vup, w->points[2]);
2006 VectorSubtract (org, vright, w->points[3]);
2007 VectorSubtract (w->points[3], vup, w->points[3]);
2018 Clips the winding to the plane, returning the new winding on the positive side
2019 Frees the input winding.
2020 If keepon is true, an exactly on-plane winding will be saved, otherwise
2021 it will be clipped away.
2024 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2026 double dists[MAX_POINTS_ON_WINDING + 1];
2027 int sides[MAX_POINTS_ON_WINDING + 1];
2036 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2038 // determine sides for each point
2039 for (i = 0;i < in->numpoints;i++)
2041 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2042 if (dot > ON_EPSILON)
2043 sides[i] = SIDE_FRONT;
2044 else if (dot < -ON_EPSILON)
2045 sides[i] = SIDE_BACK;
2050 sides[i] = sides[0];
2051 dists[i] = dists[0];
2053 if (keepon && !counts[0] && !counts[1])
2064 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2065 if (maxpts > MAX_POINTS_ON_WINDING)
2066 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2068 neww = NewWinding (maxpts);
2070 for (i = 0;i < in->numpoints;i++)
2072 if (neww->numpoints >= maxpts)
2073 Sys_Error ("ClipWinding: points exceeded estimate");
2077 if (sides[i] == SIDE_ON)
2079 VectorCopy (p1, neww->points[neww->numpoints]);
2084 if (sides[i] == SIDE_FRONT)
2086 VectorCopy (p1, neww->points[neww->numpoints]);
2090 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2093 // generate a split point
2094 p2 = in->points[(i+1)%in->numpoints];
2096 dot = dists[i] / (dists[i]-dists[i+1]);
2097 for (j = 0;j < 3;j++)
2098 { // avoid round off error when possible
2099 if (split->normal[j] == 1)
2100 mid[j] = split->dist;
2101 else if (split->normal[j] == -1)
2102 mid[j] = -split->dist;
2104 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2107 VectorCopy (mid, neww->points[neww->numpoints]);
2111 // free the original winding
2122 Divides a winding by a plane, producing one or two windings. The
2123 original winding is not damaged or freed. If only on one side, the
2124 returned winding will be the input winding. If on both sides, two
2125 new windings will be created.
2128 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2130 double dists[MAX_POINTS_ON_WINDING + 1];
2131 int sides[MAX_POINTS_ON_WINDING + 1];
2140 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2142 // determine sides for each point
2143 for (i = 0;i < in->numpoints;i++)
2145 dot = DotProduct (in->points[i], split->normal);
2148 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2149 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2150 else sides[i] = SIDE_ON;
2153 sides[i] = sides[0];
2154 dists[i] = dists[0];
2156 *front = *back = NULL;
2169 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2171 if (maxpts > MAX_POINTS_ON_WINDING)
2172 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2174 *front = f = NewWinding (maxpts);
2175 *back = b = NewWinding (maxpts);
2177 for (i = 0;i < in->numpoints;i++)
2179 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2180 Sys_Error ("DivideWinding: points exceeded estimate");
2184 if (sides[i] == SIDE_ON)
2186 VectorCopy (p1, f->points[f->numpoints]);
2188 VectorCopy (p1, b->points[b->numpoints]);
2193 if (sides[i] == SIDE_FRONT)
2195 VectorCopy (p1, f->points[f->numpoints]);
2198 else if (sides[i] == SIDE_BACK)
2200 VectorCopy (p1, b->points[b->numpoints]);
2204 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2207 // generate a split point
2208 p2 = in->points[(i+1)%in->numpoints];
2210 dot = dists[i] / (dists[i]-dists[i+1]);
2211 for (j = 0;j < 3;j++)
2212 { // avoid round off error when possible
2213 if (split->normal[j] == 1)
2214 mid[j] = split->dist;
2215 else if (split->normal[j] == -1)
2216 mid[j] = -split->dist;
2218 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2221 VectorCopy (mid, f->points[f->numpoints]);
2223 VectorCopy (mid, b->points[b->numpoints]);
2228 typedef struct portal_s
2231 mnode_t *nodes[2]; // [0] = front side of plane
2232 struct portal_s *next[2];
2234 struct portal_s *chain; // all portals are linked into a list
2238 static portal_t *portalchain;
2245 static portal_t *AllocPortal (void)
2248 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2249 p->chain = portalchain;
2254 static void FreePortal(portal_t *p)
2259 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2261 // calculate children first
2262 if (node->children[0]->contents >= 0)
2263 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2264 if (node->children[1]->contents >= 0)
2265 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2267 // make combined bounding box from children
2268 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2269 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2270 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2271 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2272 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2273 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2276 static void Mod_FinalizePortals(void)
2278 int i, j, numportals, numpoints;
2279 portal_t *p, *pnext;
2282 mleaf_t *leaf, *endleaf;
2285 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2286 leaf = loadmodel->leafs;
2287 endleaf = leaf + loadmodel->numleafs;
2288 for (;leaf < endleaf;leaf++)
2290 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2291 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2298 for (i = 0;i < 2;i++)
2300 leaf = (mleaf_t *)p->nodes[i];
2302 for (j = 0;j < w->numpoints;j++)
2304 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2305 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2306 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2307 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2308 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2309 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2316 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2318 // tally up portal and point counts
2324 // note: this check must match the one below or it will usually corrupt memory
2325 // 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
2326 if (p->winding && p->nodes[0] != p->nodes[1]
2327 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2328 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2331 numpoints += p->winding->numpoints * 2;
2335 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2336 loadmodel->numportals = numportals;
2337 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2338 loadmodel->numportalpoints = numpoints;
2339 // clear all leaf portal chains
2340 for (i = 0;i < loadmodel->numleafs;i++)
2341 loadmodel->leafs[i].portals = NULL;
2342 // process all portals in the global portal chain, while freeing them
2343 portal = loadmodel->portals;
2344 point = loadmodel->portalpoints;
2353 // note: this check must match the one above or it will usually corrupt memory
2354 // 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
2355 if (p->nodes[0] != p->nodes[1]
2356 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2357 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2359 // first make the back to front portal (forward portal)
2360 portal->points = point;
2361 portal->numpoints = p->winding->numpoints;
2362 portal->plane.dist = p->plane.dist;
2363 VectorCopy(p->plane.normal, portal->plane.normal);
2364 portal->here = (mleaf_t *)p->nodes[1];
2365 portal->past = (mleaf_t *)p->nodes[0];
2367 for (j = 0;j < portal->numpoints;j++)
2369 VectorCopy(p->winding->points[j], point->position);
2372 PlaneClassify(&portal->plane);
2374 // link into leaf's portal chain
2375 portal->next = portal->here->portals;
2376 portal->here->portals = portal;
2378 // advance to next portal
2381 // then make the front to back portal (backward portal)
2382 portal->points = point;
2383 portal->numpoints = p->winding->numpoints;
2384 portal->plane.dist = -p->plane.dist;
2385 VectorNegate(p->plane.normal, portal->plane.normal);
2386 portal->here = (mleaf_t *)p->nodes[0];
2387 portal->past = (mleaf_t *)p->nodes[1];
2389 for (j = portal->numpoints - 1;j >= 0;j--)
2391 VectorCopy(p->winding->points[j], point->position);
2394 PlaneClassify(&portal->plane);
2396 // link into leaf's portal chain
2397 portal->next = portal->here->portals;
2398 portal->here->portals = portal;
2400 // advance to next portal
2403 FreeWinding(p->winding);
2415 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2418 Host_Error ("AddPortalToNodes: NULL front node");
2420 Host_Error ("AddPortalToNodes: NULL back node");
2421 if (p->nodes[0] || p->nodes[1])
2422 Host_Error ("AddPortalToNodes: already included");
2423 // 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
2425 p->nodes[0] = front;
2426 p->next[0] = (portal_t *)front->portals;
2427 front->portals = (mportal_t *)p;
2430 p->next[1] = (portal_t *)back->portals;
2431 back->portals = (mportal_t *)p;
2436 RemovePortalFromNode
2439 static void RemovePortalFromNodes(portal_t *portal)
2443 void **portalpointer;
2445 for (i = 0;i < 2;i++)
2447 node = portal->nodes[i];
2449 portalpointer = (void **) &node->portals;
2454 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2458 if (portal->nodes[0] == node)
2460 *portalpointer = portal->next[0];
2461 portal->nodes[0] = NULL;
2463 else if (portal->nodes[1] == node)
2465 *portalpointer = portal->next[1];
2466 portal->nodes[1] = NULL;
2469 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2473 if (t->nodes[0] == node)
2474 portalpointer = (void **) &t->next[0];
2475 else if (t->nodes[1] == node)
2476 portalpointer = (void **) &t->next[1];
2478 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2483 static void Mod_RecursiveNodePortals (mnode_t *node)
2486 mnode_t *front, *back, *other_node;
2487 mplane_t clipplane, *plane;
2488 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2489 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2491 // if a leaf, we're done
2495 plane = node->plane;
2497 front = node->children[0];
2498 back = node->children[1];
2500 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2502 // create the new portal by generating a polygon for the node plane,
2503 // and clipping it by all of the other portals (which came from nodes above this one)
2504 nodeportal = AllocPortal ();
2505 nodeportal->plane = *node->plane;
2507 nodeportalwinding = BaseWindingForPlane (node->plane);
2508 side = 0; // shut up compiler warning
2509 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2511 clipplane = portal->plane;
2512 if (portal->nodes[0] == portal->nodes[1])
2513 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2514 if (portal->nodes[0] == node)
2516 else if (portal->nodes[1] == node)
2518 clipplane.dist = -clipplane.dist;
2519 VectorNegate (clipplane.normal, clipplane.normal);
2523 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2525 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2526 if (!nodeportalwinding)
2528 Con_Printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2533 if (nodeportalwinding)
2535 // if the plane was not clipped on all sides, there was an error
2536 nodeportal->winding = nodeportalwinding;
2537 AddPortalToNodes (nodeportal, front, back);
2540 // split the portals of this node along this node's plane and assign them to the children of this node
2541 // (migrating the portals downward through the tree)
2542 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2544 if (portal->nodes[0] == portal->nodes[1])
2545 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2546 if (portal->nodes[0] == node)
2548 else if (portal->nodes[1] == node)
2551 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2552 nextportal = portal->next[side];
2554 other_node = portal->nodes[!side];
2555 RemovePortalFromNodes (portal);
2557 // cut the portal into two portals, one on each side of the node plane
2558 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2563 AddPortalToNodes (portal, back, other_node);
2565 AddPortalToNodes (portal, other_node, back);
2571 AddPortalToNodes (portal, front, other_node);
2573 AddPortalToNodes (portal, other_node, front);
2577 // the winding is split
2578 splitportal = AllocPortal ();
2579 temp = splitportal->chain;
2580 *splitportal = *portal;
2581 splitportal->chain = temp;
2582 splitportal->winding = backwinding;
2583 FreeWinding (portal->winding);
2584 portal->winding = frontwinding;
2588 AddPortalToNodes (portal, front, other_node);
2589 AddPortalToNodes (splitportal, back, other_node);
2593 AddPortalToNodes (portal, other_node, front);
2594 AddPortalToNodes (splitportal, other_node, back);
2598 Mod_RecursiveNodePortals(front);
2599 Mod_RecursiveNodePortals(back);
2603 static void Mod_MakePortals(void)
2606 Mod_RecursiveNodePortals (loadmodel->nodes);
2607 Mod_FinalizePortals();
2610 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2613 int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2614 msurface_t *surf, *s;
2615 float *v0, *v1, *v2, *v3;
2616 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2617 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2618 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2620 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)
2622 if (surf->neighborsurfaces[vertnum])
2624 surf->neighborsurfaces[vertnum] = NULL;
2625 for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2627 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2628 || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2629 || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2632 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2633 if (s->neighborsurfaces[vnum] == surf)
2635 if (vnum < s->poly_numverts)
2637 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)
2639 if (s->neighborsurfaces[vnum] == NULL
2640 && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2641 || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2643 surf->neighborsurfaces[vertnum] = s;
2644 s->neighborsurfaces[vnum] = surf;
2648 if (vnum < s->poly_numverts)
2656 void Mod_BuildLightmapUpdateChains(mempool_t *mempool, model_t *model)
2658 int i, j, stylecounts[256], totalcount, remapstyles[256];
2660 memset(stylecounts, 0, sizeof(stylecounts));
2661 for (i = 0;i < model->nummodelsurfaces;i++)
2663 surf = model->surfaces + model->firstmodelsurface + i;
2664 for (j = 0;j < MAXLIGHTMAPS;j++)
2665 stylecounts[surf->styles[j]]++;
2668 model->light_styles = 0;
2669 for (i = 0;i < 255;i++)
2673 remapstyles[i] = model->light_styles++;
2674 totalcount += stylecounts[i] + 1;
2679 model->light_style = Mem_Alloc(mempool, model->light_styles * sizeof(qbyte));
2680 model->light_stylevalue = Mem_Alloc(mempool, model->light_styles * sizeof(int));
2681 model->light_styleupdatechains = Mem_Alloc(mempool, model->light_styles * sizeof(msurface_t **));
2682 model->light_styleupdatechainsbuffer = Mem_Alloc(mempool, totalcount * sizeof(msurface_t *));
2683 model->light_styles = 0;
2684 for (i = 0;i < 255;i++)
2686 model->light_style[model->light_styles++] = i;
2688 for (i = 0;i < model->light_styles;i++)
2690 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2691 j += stylecounts[model->light_style[i]] + 1;
2693 for (i = 0;i < model->nummodelsurfaces;i++)
2695 surf = model->surfaces + model->firstmodelsurface + i;
2696 for (j = 0;j < MAXLIGHTMAPS;j++)
2697 if (surf->styles[j] != 255)
2698 *model->light_styleupdatechains[remapstyles[surf->styles[j]]]++ = surf;
2701 for (i = 0;i < model->light_styles;i++)
2703 *model->light_styleupdatechains[i] = NULL;
2704 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2705 j += stylecounts[model->light_style[i]] + 1;
2709 void Mod_BuildPVSTextureChains(model_t *model)
2712 for (i = 0;i < model->numtextures;i++)
2713 model->pvstexturechainslength[i] = 0;
2714 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2716 if (model->surfacepvsframes[j] == model->pvsframecount)
2718 model->pvssurflist[model->pvssurflistlength++] = j;
2719 model->pvstexturechainslength[model->surfaces[j].texinfo->texture->number]++;
2722 for (i = 0, j = 0;i < model->numtextures;i++)
2724 if (model->pvstexturechainslength[i])
2726 model->pvstexturechains[i] = model->pvstexturechainsbuffer + j;
2727 j += model->pvstexturechainslength[i] + 1;
2730 model->pvstexturechains[i] = NULL;
2732 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2733 if (model->surfacepvsframes[j] == model->pvsframecount)
2734 *model->pvstexturechains[model->surfaces[j].texinfo->texture->number]++ = model->surfaces + j;
2735 for (i = 0;i < model->numtextures;i++)
2737 if (model->pvstexturechainslength[i])
2739 *model->pvstexturechains[i] = NULL;
2740 model->pvstexturechains[i] -= model->pvstexturechainslength[i];
2750 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2751 extern void R_Model_Brush_Draw(entity_render_t *ent);
2752 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2753 extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz);
2754 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2759 mempool_t *mainmempool;
2761 model_t *originalloadmodel;
2762 float dist, modelyawradius, modelradius, *vec;
2766 mod->type = mod_brush;
2768 header = (dheader_t *)buffer;
2770 i = LittleLong (header->version);
2771 if (i != BSPVERSION && i != 30)
2772 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2773 mod->ishlbsp = i == 30;
2774 if (loadmodel->isworldmodel)
2776 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2777 // until we get a texture for it...
2781 // swap all the lumps
2782 mod_base = (qbyte *)header;
2784 for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
2785 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2789 // store which lightmap format to use
2790 mod->lightmaprgba = r_lightmaprgba.integer;
2792 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2793 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2794 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2795 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2796 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2797 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2798 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2799 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2800 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2801 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2802 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2803 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2804 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2805 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2806 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2811 mod->numframes = 2; // regular and alternate animation
2813 mainmempool = mod->mempool;
2814 loadname = mod->name;
2816 Mod_LoadLightList ();
2817 originalloadmodel = loadmodel;
2820 // set up the submodels (FIXME: this is confusing)
2822 for (i = 0;i < mod->numsubmodels;i++)
2824 bm = &mod->submodels[i];
2826 mod->hulls[0].firstclipnode = bm->headnode[0];
2827 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2829 mod->hulls[j].firstclipnode = bm->headnode[j];
2830 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2833 mod->firstmodelsurface = bm->firstface;
2834 mod->nummodelsurfaces = bm->numfaces;
2836 // this gets altered below if sky is used
2837 mod->DrawSky = NULL;
2838 mod->Draw = R_Model_Brush_Draw;
2839 mod->DrawFakeShadow = NULL;
2840 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2841 mod->DrawLight = R_Model_Brush_DrawLight;
2842 mod->pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t **));
2843 mod->pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool, (mod->nummodelsurfaces + mod->numtextures) * sizeof(msurface_t *));
2844 mod->pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(int));
2845 Mod_BuildPVSTextureChains(mod);
2846 Mod_BuildLightmapUpdateChains(originalloadmodel->mempool, mod);
2847 if (mod->nummodelsurfaces)
2849 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2850 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2851 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2854 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2856 // we only need to have a drawsky function if it is used (usually only on world model)
2857 if (surf->texinfo->texture->shader == &Cshader_sky)
2858 mod->DrawSky = R_Model_Brush_DrawSky;
2859 // LordHavoc: submodels always clip, even if water
2860 if (mod->numsubmodels - 1)
2861 surf->flags |= SURF_SOLIDCLIP;
2862 // calculate bounding shapes
2863 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
2865 for (k = 0, vec = mesh->vertex3f;k < mesh->numverts;k++, vec += 3)
2867 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2868 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2869 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2870 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2871 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2872 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2873 dist = vec[0]*vec[0]+vec[1]*vec[1];
2874 if (modelyawradius < dist)
2875 modelyawradius = dist;
2876 dist += vec[2]*vec[2];
2877 if (modelradius < dist)
2882 modelyawradius = sqrt(modelyawradius);
2883 modelradius = sqrt(modelradius);
2884 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2885 mod->yawmins[2] = mod->normalmins[2];
2886 mod->yawmaxs[2] = mod->normalmaxs[2];
2887 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2888 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2889 mod->radius = modelradius;
2890 mod->radius2 = modelradius * modelradius;
2894 // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2895 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2897 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2899 mod->numleafs = bm->visleafs;
2901 // LordHavoc: only register submodels if it is the world
2902 // (prevents bsp models from replacing world submodels)
2903 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2906 // duplicate the basic information
2907 sprintf (name, "*%i", i+1);
2908 loadmodel = Mod_FindName (name);
2910 strcpy (loadmodel->name, name);
2911 // textures and memory belong to the main model
2912 loadmodel->texturepool = NULL;
2913 loadmodel->mempool = NULL;
2918 loadmodel = originalloadmodel;
2919 //Mod_ProcessLightList ();