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_GenerateWallMesh (msurface_t *surf, int vertexonly)
1402 int i, iu, iv, *index, smax, tmax;
1403 float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
1406 smax = surf->extents[0] >> 4;
1407 tmax = surf->extents[1] >> 4;
1411 surf->lightmaptexturestride = 0;
1412 surf->lightmaptexture = NULL;
1420 surf->flags |= SURF_LIGHTMAP;
1421 if (r_miplightmaps.integer)
1423 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1424 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);
1428 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1429 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);
1431 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1432 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1433 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1436 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1438 index = mesh->element3i;
1439 for (i = 0;i < mesh->numtriangles;i++)
1445 Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1447 VectorCopy(surf->plane->normal, normal);
1448 if (surf->flags & SURF_PLANEBACK)
1449 VectorNegate(normal, normal);
1450 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1452 s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1453 t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1454 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1455 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1456 // LordHavoc: calc lightmap data offset for vertex lighting to use
1459 iu = bound(0, iu, smax);
1460 iv = bound(0, iv, tmax);
1461 u = u * uscale + ubase;
1462 v = v * vscale + vbase;
1464 mesh->vertex3f[i * 3 + 0] = in[0];
1465 mesh->vertex3f[i * 3 + 1] = in[1];
1466 mesh->vertex3f[i * 3 + 2] = in[2];
1467 mesh->texcoordtexture2f[i * 2 + 0] = s / surf->texinfo->texture->width;
1468 mesh->texcoordtexture2f[i * 2 + 1] = t / surf->texinfo->texture->height;
1469 mesh->texcoordlightmap2f[i * 2 + 0] = u;
1470 mesh->texcoordlightmap2f[i * 2 + 1] = v;
1471 mesh->texcoorddetail2f[i * 2 + 0] = s * (1.0f / 16.0f);
1472 mesh->texcoorddetail2f[i * 2 + 1] = t * (1.0f / 16.0f);
1473 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
1475 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->vertex3f, mesh->texcoordtexture2f, mesh->element3i, mesh->svector3f, mesh->tvector3f, mesh->normal3f);
1478 void Mod_GenerateVertexMesh (msurface_t *surf)
1481 float *in, s, t, normal[3];
1484 surf->lightmaptexturestride = 0;
1485 surf->lightmaptexture = NULL;
1487 surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2);
1489 index = mesh->element3i;
1490 for (i = 0;i < mesh->numtriangles;i++)
1496 Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1498 VectorCopy(surf->plane->normal, normal);
1499 if (surf->flags & SURF_PLANEBACK)
1500 VectorNegate(normal, normal);
1501 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1503 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
1504 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
1505 mesh->vertex3f[i * 3 + 0] = in[0];
1506 mesh->vertex3f[i * 3 + 1] = in[1];
1507 mesh->vertex3f[i * 3 + 2] = in[2];
1508 mesh->texcoordtexture2f[i * 2 + 0] = s / surf->texinfo->texture->width;
1509 mesh->texcoordtexture2f[i * 2 + 1] = t / surf->texinfo->texture->height;
1510 mesh->texcoordlightmap2f[i * 2 + 0] = 0;
1511 mesh->texcoordlightmap2f[i * 2 + 1] = 0;
1512 mesh->texcoorddetail2f[i * 2 + 0] = s * (1.0f / 16.0f);
1513 mesh->texcoorddetail2f[i * 2 + 1] = t * (1.0f / 16.0f);
1515 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->vertex3f, mesh->texcoordtexture2f, mesh->element3i, mesh->svector3f, mesh->tvector3f, mesh->normal3f);
1518 void Mod_GenerateSurfacePolygon (msurface_t *surf, int firstedge, int numedges)
1521 float *vec, *vert, mins[3], maxs[3], val, *v;
1524 // convert edges back to a normal polygon
1525 surf->poly_numverts = numedges;
1526 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * numedges);
1527 for (i = 0;i < numedges;i++)
1529 lindex = loadmodel->surfedges[firstedge + i];
1531 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1533 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1534 VectorCopy (vec, vert);
1538 // calculate polygon bounding box and center
1539 vert = surf->poly_verts;
1540 VectorCopy(vert, mins);
1541 VectorCopy(vert, maxs);
1543 for (i = 1;i < surf->poly_numverts;i++, vert += 3)
1545 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1546 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1547 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1549 VectorCopy(mins, surf->poly_mins);
1550 VectorCopy(maxs, surf->poly_maxs);
1551 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1552 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1553 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1555 // generate surface extents information
1556 tex = surf->texinfo;
1557 mins[0] = maxs[0] = DotProduct(surf->poly_verts, tex->vecs[0]) + tex->vecs[0][3];
1558 mins[1] = maxs[1] = DotProduct(surf->poly_verts, tex->vecs[1]) + tex->vecs[1][3];
1559 for (i = 1, v = surf->poly_verts + 3;i < surf->poly_numverts;i++, v += 3)
1561 for (j = 0;j < 2;j++)
1563 val = DotProduct(v, tex->vecs[j]) + tex->vecs[j][3];
1570 for (i = 0;i < 2;i++)
1572 surf->texturemins[i] = (int) floor(mins[i] / 16) * 16;
1573 surf->extents[i] = (int) ceil(maxs[i] / 16) * 16 - surf->texturemins[i];
1582 static void Mod_LoadFaces (lump_t *l)
1586 int i, count, surfnum, planenum, ssize, tsize, firstedge, numedges;
1588 in = (void *)(mod_base + l->fileofs);
1589 if (l->filelen % sizeof(*in))
1590 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1591 count = l->filelen / sizeof(*in);
1592 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1594 loadmodel->surfaces = out;
1595 loadmodel->numsurfaces = count;
1596 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1597 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1598 loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1600 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1602 out->number = surfnum;
1603 // FIXME: validate edges, texinfo, etc?
1604 firstedge = LittleLong(in->firstedge);
1605 numedges = LittleShort(in->numedges);
1606 if ((unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->numsurfedges)
1607 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->numsurfedges);
1609 i = LittleShort (in->texinfo);
1610 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1611 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1612 out->texinfo = loadmodel->texinfo + i;
1613 out->flags = out->texinfo->texture->flags;
1615 planenum = LittleShort(in->planenum);
1616 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1617 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1619 if (LittleShort(in->side))
1620 out->flags |= SURF_PLANEBACK;
1622 out->plane = loadmodel->planes + planenum;
1624 // clear lightmap (filled in later)
1625 out->lightmaptexture = NULL;
1627 // force lightmap upload on first time seeing the surface
1628 out->cached_dlight = true;
1630 Mod_GenerateSurfacePolygon(out, firstedge, numedges);
1632 ssize = (out->extents[0] >> 4) + 1;
1633 tsize = (out->extents[1] >> 4) + 1;
1636 for (i = 0;i < MAXLIGHTMAPS;i++)
1637 out->styles[i] = in->styles[i];
1638 i = LittleLong(in->lightofs);
1640 out->samples = NULL;
1641 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1642 out->samples = loadmodel->lightdata + i;
1643 else // LordHavoc: white lighting (bsp version 29)
1644 out->samples = loadmodel->lightdata + (i * 3);
1646 if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
1648 if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
1649 Host_Error ("Bad surface extents");
1650 Mod_GenerateWallMesh (out, false);
1651 // stainmap for permanent marks on walls
1652 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1654 memset(out->stainsamples, 255, ssize * tsize * 3);
1657 Mod_GenerateVertexMesh (out);
1666 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1668 node->parent = parent;
1669 if (node->contents < 0)
1671 Mod_SetParent (node->children[0], node);
1672 Mod_SetParent (node->children[1], node);
1680 static void Mod_LoadNodes (lump_t *l)
1686 in = (void *)(mod_base + l->fileofs);
1687 if (l->filelen % sizeof(*in))
1688 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1689 count = l->filelen / sizeof(*in);
1690 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1692 loadmodel->nodes = out;
1693 loadmodel->numnodes = count;
1695 for ( i=0 ; i<count ; i++, in++, out++)
1697 for (j=0 ; j<3 ; j++)
1699 out->mins[j] = LittleShort (in->mins[j]);
1700 out->maxs[j] = LittleShort (in->maxs[j]);
1703 p = LittleLong(in->planenum);
1704 out->plane = loadmodel->planes + p;
1706 out->firstsurface = LittleShort (in->firstface);
1707 out->numsurfaces = LittleShort (in->numfaces);
1709 for (j=0 ; j<2 ; j++)
1711 p = LittleShort (in->children[j]);
1713 out->children[j] = loadmodel->nodes + p;
1715 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1719 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1727 static void Mod_LoadLeafs (lump_t *l)
1733 in = (void *)(mod_base + l->fileofs);
1734 if (l->filelen % sizeof(*in))
1735 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1736 count = l->filelen / sizeof(*in);
1737 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1739 loadmodel->leafs = out;
1740 loadmodel->numleafs = count;
1742 for ( i=0 ; i<count ; i++, in++, out++)
1744 for (j=0 ; j<3 ; j++)
1746 out->mins[j] = LittleShort (in->mins[j]);
1747 out->maxs[j] = LittleShort (in->maxs[j]);
1750 p = LittleLong(in->contents);
1753 out->firstmarksurface = loadmodel->marksurfaces +
1754 LittleShort(in->firstmarksurface);
1755 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1757 p = LittleLong(in->visofs);
1759 out->compressed_vis = NULL;
1761 out->compressed_vis = loadmodel->visdata + p;
1763 for (j=0 ; j<4 ; j++)
1764 out->ambient_sound_level[j] = in->ambient_level[j];
1766 // FIXME: Insert caustics here
1775 static void Mod_LoadClipnodes (lump_t *l)
1777 dclipnode_t *in, *out;
1781 in = (void *)(mod_base + l->fileofs);
1782 if (l->filelen % sizeof(*in))
1783 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1784 count = l->filelen / sizeof(*in);
1785 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1787 loadmodel->clipnodes = out;
1788 loadmodel->numclipnodes = count;
1790 if (loadmodel->ishlbsp)
1792 hull = &loadmodel->hulls[1];
1793 hull->clipnodes = out;
1794 hull->firstclipnode = 0;
1795 hull->lastclipnode = count-1;
1796 hull->planes = loadmodel->planes;
1797 hull->clip_mins[0] = -16;
1798 hull->clip_mins[1] = -16;
1799 hull->clip_mins[2] = -36;
1800 hull->clip_maxs[0] = 16;
1801 hull->clip_maxs[1] = 16;
1802 hull->clip_maxs[2] = 36;
1803 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1805 hull = &loadmodel->hulls[2];
1806 hull->clipnodes = out;
1807 hull->firstclipnode = 0;
1808 hull->lastclipnode = count-1;
1809 hull->planes = loadmodel->planes;
1810 hull->clip_mins[0] = -32;
1811 hull->clip_mins[1] = -32;
1812 hull->clip_mins[2] = -32;
1813 hull->clip_maxs[0] = 32;
1814 hull->clip_maxs[1] = 32;
1815 hull->clip_maxs[2] = 32;
1816 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1818 hull = &loadmodel->hulls[3];
1819 hull->clipnodes = out;
1820 hull->firstclipnode = 0;
1821 hull->lastclipnode = count-1;
1822 hull->planes = loadmodel->planes;
1823 hull->clip_mins[0] = -16;
1824 hull->clip_mins[1] = -16;
1825 hull->clip_mins[2] = -18;
1826 hull->clip_maxs[0] = 16;
1827 hull->clip_maxs[1] = 16;
1828 hull->clip_maxs[2] = 18;
1829 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1833 hull = &loadmodel->hulls[1];
1834 hull->clipnodes = out;
1835 hull->firstclipnode = 0;
1836 hull->lastclipnode = count-1;
1837 hull->planes = loadmodel->planes;
1838 hull->clip_mins[0] = -16;
1839 hull->clip_mins[1] = -16;
1840 hull->clip_mins[2] = -24;
1841 hull->clip_maxs[0] = 16;
1842 hull->clip_maxs[1] = 16;
1843 hull->clip_maxs[2] = 32;
1844 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1846 hull = &loadmodel->hulls[2];
1847 hull->clipnodes = out;
1848 hull->firstclipnode = 0;
1849 hull->lastclipnode = count-1;
1850 hull->planes = loadmodel->planes;
1851 hull->clip_mins[0] = -32;
1852 hull->clip_mins[1] = -32;
1853 hull->clip_mins[2] = -24;
1854 hull->clip_maxs[0] = 32;
1855 hull->clip_maxs[1] = 32;
1856 hull->clip_maxs[2] = 64;
1857 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1860 for (i=0 ; i<count ; i++, out++, in++)
1862 out->planenum = LittleLong(in->planenum);
1863 out->children[0] = LittleShort(in->children[0]);
1864 out->children[1] = LittleShort(in->children[1]);
1865 if (out->children[0] >= count || out->children[1] >= count)
1866 Host_Error("Corrupt clipping hull (out of range child)\n");
1874 Duplicate the drawing hull structure as a clipping hull
1877 static void Mod_MakeHull0 (void)
1884 hull = &loadmodel->hulls[0];
1886 in = loadmodel->nodes;
1887 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1889 hull->clipnodes = out;
1890 hull->firstclipnode = 0;
1891 hull->lastclipnode = loadmodel->numnodes - 1;
1892 hull->planes = loadmodel->planes;
1894 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1896 out->planenum = in->plane - loadmodel->planes;
1897 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1898 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1904 Mod_LoadMarksurfaces
1907 static void Mod_LoadMarksurfaces (lump_t *l)
1912 in = (void *)(mod_base + l->fileofs);
1913 if (l->filelen % sizeof(*in))
1914 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1915 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1916 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1918 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1920 j = (unsigned) LittleShort(in[i]);
1921 if (j >= loadmodel->numsurfaces)
1922 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1923 loadmodel->marksurfaces[i] = j;
1932 static void Mod_LoadSurfedges (lump_t *l)
1937 in = (void *)(mod_base + l->fileofs);
1938 if (l->filelen % sizeof(*in))
1939 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1940 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1941 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1943 for (i = 0;i < loadmodel->numsurfedges;i++)
1944 loadmodel->surfedges[i] = LittleLong (in[i]);
1953 static void Mod_LoadPlanes (lump_t *l)
1959 in = (void *)(mod_base + l->fileofs);
1960 if (l->filelen % sizeof(*in))
1961 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1963 loadmodel->numplanes = l->filelen / sizeof(*in);
1964 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1966 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1968 out->normal[0] = LittleFloat (in->normal[0]);
1969 out->normal[1] = LittleFloat (in->normal[1]);
1970 out->normal[2] = LittleFloat (in->normal[2]);
1971 out->dist = LittleFloat (in->dist);
1977 #define MAX_POINTS_ON_WINDING 64
1983 double points[8][3]; // variable sized
1992 static winding_t *NewWinding (int points)
1997 if (points > MAX_POINTS_ON_WINDING)
1998 Sys_Error("NewWinding: too many points\n");
2000 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
2001 w = Mem_Alloc(loadmodel->mempool, size);
2002 memset (w, 0, size);
2007 static void FreeWinding (winding_t *w)
2017 static winding_t *BaseWindingForPlane (mplane_t *p)
2019 double org[3], vright[3], vup[3], normal[3];
2022 VectorCopy(p->normal, normal);
2023 VectorVectorsDouble(normal, vright, vup);
2025 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
2026 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
2028 // project a really big axis aligned box onto the plane
2031 VectorScale (p->normal, p->dist, org);
2033 VectorSubtract (org, vright, w->points[0]);
2034 VectorAdd (w->points[0], vup, w->points[0]);
2036 VectorAdd (org, vright, w->points[1]);
2037 VectorAdd (w->points[1], vup, w->points[1]);
2039 VectorAdd (org, vright, w->points[2]);
2040 VectorSubtract (w->points[2], vup, w->points[2]);
2042 VectorSubtract (org, vright, w->points[3]);
2043 VectorSubtract (w->points[3], vup, w->points[3]);
2054 Clips the winding to the plane, returning the new winding on the positive side
2055 Frees the input winding.
2056 If keepon is true, an exactly on-plane winding will be saved, otherwise
2057 it will be clipped away.
2060 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2062 double dists[MAX_POINTS_ON_WINDING + 1];
2063 int sides[MAX_POINTS_ON_WINDING + 1];
2072 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2074 // determine sides for each point
2075 for (i = 0;i < in->numpoints;i++)
2077 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2078 if (dot > ON_EPSILON)
2079 sides[i] = SIDE_FRONT;
2080 else if (dot < -ON_EPSILON)
2081 sides[i] = SIDE_BACK;
2086 sides[i] = sides[0];
2087 dists[i] = dists[0];
2089 if (keepon && !counts[0] && !counts[1])
2100 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2101 if (maxpts > MAX_POINTS_ON_WINDING)
2102 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2104 neww = NewWinding (maxpts);
2106 for (i = 0;i < in->numpoints;i++)
2108 if (neww->numpoints >= maxpts)
2109 Sys_Error ("ClipWinding: points exceeded estimate");
2113 if (sides[i] == SIDE_ON)
2115 VectorCopy (p1, neww->points[neww->numpoints]);
2120 if (sides[i] == SIDE_FRONT)
2122 VectorCopy (p1, neww->points[neww->numpoints]);
2126 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2129 // generate a split point
2130 p2 = in->points[(i+1)%in->numpoints];
2132 dot = dists[i] / (dists[i]-dists[i+1]);
2133 for (j = 0;j < 3;j++)
2134 { // avoid round off error when possible
2135 if (split->normal[j] == 1)
2136 mid[j] = split->dist;
2137 else if (split->normal[j] == -1)
2138 mid[j] = -split->dist;
2140 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2143 VectorCopy (mid, neww->points[neww->numpoints]);
2147 // free the original winding
2158 Divides a winding by a plane, producing one or two windings. The
2159 original winding is not damaged or freed. If only on one side, the
2160 returned winding will be the input winding. If on both sides, two
2161 new windings will be created.
2164 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2166 double dists[MAX_POINTS_ON_WINDING + 1];
2167 int sides[MAX_POINTS_ON_WINDING + 1];
2176 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2178 // determine sides for each point
2179 for (i = 0;i < in->numpoints;i++)
2181 dot = DotProduct (in->points[i], split->normal);
2184 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2185 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2186 else sides[i] = SIDE_ON;
2189 sides[i] = sides[0];
2190 dists[i] = dists[0];
2192 *front = *back = NULL;
2205 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2207 if (maxpts > MAX_POINTS_ON_WINDING)
2208 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2210 *front = f = NewWinding (maxpts);
2211 *back = b = NewWinding (maxpts);
2213 for (i = 0;i < in->numpoints;i++)
2215 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2216 Sys_Error ("DivideWinding: points exceeded estimate");
2220 if (sides[i] == SIDE_ON)
2222 VectorCopy (p1, f->points[f->numpoints]);
2224 VectorCopy (p1, b->points[b->numpoints]);
2229 if (sides[i] == SIDE_FRONT)
2231 VectorCopy (p1, f->points[f->numpoints]);
2234 else if (sides[i] == SIDE_BACK)
2236 VectorCopy (p1, b->points[b->numpoints]);
2240 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2243 // generate a split point
2244 p2 = in->points[(i+1)%in->numpoints];
2246 dot = dists[i] / (dists[i]-dists[i+1]);
2247 for (j = 0;j < 3;j++)
2248 { // avoid round off error when possible
2249 if (split->normal[j] == 1)
2250 mid[j] = split->dist;
2251 else if (split->normal[j] == -1)
2252 mid[j] = -split->dist;
2254 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2257 VectorCopy (mid, f->points[f->numpoints]);
2259 VectorCopy (mid, b->points[b->numpoints]);
2264 typedef struct portal_s
2267 mnode_t *nodes[2]; // [0] = front side of plane
2268 struct portal_s *next[2];
2270 struct portal_s *chain; // all portals are linked into a list
2274 static portal_t *portalchain;
2281 static portal_t *AllocPortal (void)
2284 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2285 p->chain = portalchain;
2290 static void FreePortal(portal_t *p)
2295 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2297 // calculate children first
2298 if (node->children[0]->contents >= 0)
2299 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2300 if (node->children[1]->contents >= 0)
2301 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2303 // make combined bounding box from children
2304 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2305 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2306 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2307 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2308 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2309 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2312 static void Mod_FinalizePortals(void)
2314 int i, j, numportals, numpoints;
2315 portal_t *p, *pnext;
2318 mleaf_t *leaf, *endleaf;
2321 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2322 leaf = loadmodel->leafs;
2323 endleaf = leaf + loadmodel->numleafs;
2324 for (;leaf < endleaf;leaf++)
2326 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2327 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2334 for (i = 0;i < 2;i++)
2336 leaf = (mleaf_t *)p->nodes[i];
2338 for (j = 0;j < w->numpoints;j++)
2340 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2341 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2342 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2343 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2344 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2345 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2352 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2354 // tally up portal and point counts
2360 // note: this check must match the one below or it will usually corrupt memory
2361 // 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
2362 if (p->winding && p->nodes[0] != p->nodes[1]
2363 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2364 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2367 numpoints += p->winding->numpoints * 2;
2371 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2372 loadmodel->numportals = numportals;
2373 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2374 loadmodel->numportalpoints = numpoints;
2375 // clear all leaf portal chains
2376 for (i = 0;i < loadmodel->numleafs;i++)
2377 loadmodel->leafs[i].portals = NULL;
2378 // process all portals in the global portal chain, while freeing them
2379 portal = loadmodel->portals;
2380 point = loadmodel->portalpoints;
2389 // note: this check must match the one above or it will usually corrupt memory
2390 // 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
2391 if (p->nodes[0] != p->nodes[1]
2392 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2393 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2395 // first make the back to front portal (forward portal)
2396 portal->points = point;
2397 portal->numpoints = p->winding->numpoints;
2398 portal->plane.dist = p->plane.dist;
2399 VectorCopy(p->plane.normal, portal->plane.normal);
2400 portal->here = (mleaf_t *)p->nodes[1];
2401 portal->past = (mleaf_t *)p->nodes[0];
2403 for (j = 0;j < portal->numpoints;j++)
2405 VectorCopy(p->winding->points[j], point->position);
2408 PlaneClassify(&portal->plane);
2410 // link into leaf's portal chain
2411 portal->next = portal->here->portals;
2412 portal->here->portals = portal;
2414 // advance to next portal
2417 // then make the front to back portal (backward portal)
2418 portal->points = point;
2419 portal->numpoints = p->winding->numpoints;
2420 portal->plane.dist = -p->plane.dist;
2421 VectorNegate(p->plane.normal, portal->plane.normal);
2422 portal->here = (mleaf_t *)p->nodes[0];
2423 portal->past = (mleaf_t *)p->nodes[1];
2425 for (j = portal->numpoints - 1;j >= 0;j--)
2427 VectorCopy(p->winding->points[j], point->position);
2430 PlaneClassify(&portal->plane);
2432 // link into leaf's portal chain
2433 portal->next = portal->here->portals;
2434 portal->here->portals = portal;
2436 // advance to next portal
2439 FreeWinding(p->winding);
2451 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2454 Host_Error ("AddPortalToNodes: NULL front node");
2456 Host_Error ("AddPortalToNodes: NULL back node");
2457 if (p->nodes[0] || p->nodes[1])
2458 Host_Error ("AddPortalToNodes: already included");
2459 // 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
2461 p->nodes[0] = front;
2462 p->next[0] = (portal_t *)front->portals;
2463 front->portals = (mportal_t *)p;
2466 p->next[1] = (portal_t *)back->portals;
2467 back->portals = (mportal_t *)p;
2472 RemovePortalFromNode
2475 static void RemovePortalFromNodes(portal_t *portal)
2479 void **portalpointer;
2481 for (i = 0;i < 2;i++)
2483 node = portal->nodes[i];
2485 portalpointer = (void **) &node->portals;
2490 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2494 if (portal->nodes[0] == node)
2496 *portalpointer = portal->next[0];
2497 portal->nodes[0] = NULL;
2499 else if (portal->nodes[1] == node)
2501 *portalpointer = portal->next[1];
2502 portal->nodes[1] = NULL;
2505 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2509 if (t->nodes[0] == node)
2510 portalpointer = (void **) &t->next[0];
2511 else if (t->nodes[1] == node)
2512 portalpointer = (void **) &t->next[1];
2514 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2519 static void Mod_RecursiveNodePortals (mnode_t *node)
2522 mnode_t *front, *back, *other_node;
2523 mplane_t clipplane, *plane;
2524 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2525 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2527 // if a leaf, we're done
2531 plane = node->plane;
2533 front = node->children[0];
2534 back = node->children[1];
2536 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2538 // create the new portal by generating a polygon for the node plane,
2539 // and clipping it by all of the other portals (which came from nodes above this one)
2540 nodeportal = AllocPortal ();
2541 nodeportal->plane = *node->plane;
2543 nodeportalwinding = BaseWindingForPlane (node->plane);
2544 side = 0; // shut up compiler warning
2545 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2547 clipplane = portal->plane;
2548 if (portal->nodes[0] == portal->nodes[1])
2549 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2550 if (portal->nodes[0] == node)
2552 else if (portal->nodes[1] == node)
2554 clipplane.dist = -clipplane.dist;
2555 VectorNegate (clipplane.normal, clipplane.normal);
2559 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2561 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2562 if (!nodeportalwinding)
2564 Con_Printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2569 if (nodeportalwinding)
2571 // if the plane was not clipped on all sides, there was an error
2572 nodeportal->winding = nodeportalwinding;
2573 AddPortalToNodes (nodeportal, front, back);
2576 // split the portals of this node along this node's plane and assign them to the children of this node
2577 // (migrating the portals downward through the tree)
2578 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2580 if (portal->nodes[0] == portal->nodes[1])
2581 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2582 if (portal->nodes[0] == node)
2584 else if (portal->nodes[1] == node)
2587 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2588 nextportal = portal->next[side];
2590 other_node = portal->nodes[!side];
2591 RemovePortalFromNodes (portal);
2593 // cut the portal into two portals, one on each side of the node plane
2594 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2599 AddPortalToNodes (portal, back, other_node);
2601 AddPortalToNodes (portal, other_node, back);
2607 AddPortalToNodes (portal, front, other_node);
2609 AddPortalToNodes (portal, other_node, front);
2613 // the winding is split
2614 splitportal = AllocPortal ();
2615 temp = splitportal->chain;
2616 *splitportal = *portal;
2617 splitportal->chain = temp;
2618 splitportal->winding = backwinding;
2619 FreeWinding (portal->winding);
2620 portal->winding = frontwinding;
2624 AddPortalToNodes (portal, front, other_node);
2625 AddPortalToNodes (splitportal, back, other_node);
2629 AddPortalToNodes (portal, other_node, front);
2630 AddPortalToNodes (splitportal, other_node, back);
2634 Mod_RecursiveNodePortals(front);
2635 Mod_RecursiveNodePortals(back);
2639 static void Mod_MakePortals(void)
2642 Mod_RecursiveNodePortals (loadmodel->nodes);
2643 Mod_FinalizePortals();
2646 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2649 int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2650 msurface_t *surf, *s;
2651 float *v0, *v1, *v2, *v3;
2652 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2653 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2654 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2656 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)
2658 if (surf->neighborsurfaces[vertnum])
2660 surf->neighborsurfaces[vertnum] = NULL;
2661 for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2663 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2664 || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2665 || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2668 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2669 if (s->neighborsurfaces[vnum] == surf)
2671 if (vnum < s->poly_numverts)
2673 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)
2675 if (s->neighborsurfaces[vnum] == NULL
2676 && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2677 || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2679 surf->neighborsurfaces[vertnum] = s;
2680 s->neighborsurfaces[vnum] = surf;
2684 if (vnum < s->poly_numverts)
2692 void Mod_BuildLightmapUpdateChains(mempool_t *mempool, model_t *model)
2694 int i, j, stylecounts[256], totalcount, remapstyles[256];
2696 memset(stylecounts, 0, sizeof(stylecounts));
2697 for (i = 0;i < model->nummodelsurfaces;i++)
2699 surf = model->surfaces + model->firstmodelsurface + i;
2700 for (j = 0;j < MAXLIGHTMAPS;j++)
2701 stylecounts[surf->styles[j]]++;
2704 model->light_styles = 0;
2705 for (i = 0;i < 255;i++)
2709 remapstyles[i] = model->light_styles++;
2710 totalcount += stylecounts[i] + 1;
2715 model->light_style = Mem_Alloc(mempool, model->light_styles * sizeof(qbyte));
2716 model->light_stylevalue = Mem_Alloc(mempool, model->light_styles * sizeof(int));
2717 model->light_styleupdatechains = Mem_Alloc(mempool, model->light_styles * sizeof(msurface_t **));
2718 model->light_styleupdatechainsbuffer = Mem_Alloc(mempool, totalcount * sizeof(msurface_t *));
2719 model->light_styles = 0;
2720 for (i = 0;i < 255;i++)
2722 model->light_style[model->light_styles++] = i;
2724 for (i = 0;i < model->light_styles;i++)
2726 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2727 j += stylecounts[model->light_style[i]] + 1;
2729 for (i = 0;i < model->nummodelsurfaces;i++)
2731 surf = model->surfaces + model->firstmodelsurface + i;
2732 for (j = 0;j < MAXLIGHTMAPS;j++)
2733 if (surf->styles[j] != 255)
2734 *model->light_styleupdatechains[remapstyles[surf->styles[j]]]++ = surf;
2737 for (i = 0;i < model->light_styles;i++)
2739 *model->light_styleupdatechains[i] = NULL;
2740 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2741 j += stylecounts[model->light_style[i]] + 1;
2745 void Mod_BuildPVSTextureChains(model_t *model)
2748 for (i = 0;i < model->numtextures;i++)
2749 model->pvstexturechainslength[i] = 0;
2750 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2752 if (model->surfacepvsframes[j] == model->pvsframecount)
2754 model->pvssurflist[model->pvssurflistlength++] = j;
2755 model->pvstexturechainslength[model->surfaces[j].texinfo->texture->number]++;
2758 for (i = 0, j = 0;i < model->numtextures;i++)
2760 if (model->pvstexturechainslength[i])
2762 model->pvstexturechains[i] = model->pvstexturechainsbuffer + j;
2763 j += model->pvstexturechainslength[i] + 1;
2766 model->pvstexturechains[i] = NULL;
2768 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2769 if (model->surfacepvsframes[j] == model->pvsframecount)
2770 *model->pvstexturechains[model->surfaces[j].texinfo->texture->number]++ = model->surfaces + j;
2771 for (i = 0;i < model->numtextures;i++)
2773 if (model->pvstexturechainslength[i])
2775 *model->pvstexturechains[i] = NULL;
2776 model->pvstexturechains[i] -= model->pvstexturechainslength[i];
2786 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2787 extern void R_Model_Brush_Draw(entity_render_t *ent);
2788 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2789 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);
2790 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2795 mempool_t *mainmempool;
2797 model_t *originalloadmodel;
2798 float dist, modelyawradius, modelradius, *vec;
2802 mod->type = mod_brush;
2804 header = (dheader_t *)buffer;
2806 i = LittleLong (header->version);
2807 if (i != BSPVERSION && i != 30)
2808 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2809 mod->ishlbsp = i == 30;
2810 if (loadmodel->isworldmodel)
2812 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2813 // until we get a texture for it...
2817 // swap all the lumps
2818 mod_base = (qbyte *)header;
2820 for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
2821 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2825 // store which lightmap format to use
2826 mod->lightmaprgba = r_lightmaprgba.integer;
2828 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2829 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2830 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2831 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2832 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2833 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2834 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2835 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2836 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2837 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2838 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2839 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2840 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2841 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2842 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2847 mod->numframes = 2; // regular and alternate animation
2849 mainmempool = mod->mempool;
2850 loadname = mod->name;
2852 Mod_LoadLightList ();
2853 originalloadmodel = loadmodel;
2856 // set up the submodels (FIXME: this is confusing)
2858 for (i = 0;i < mod->numsubmodels;i++)
2860 bm = &mod->submodels[i];
2862 mod->hulls[0].firstclipnode = bm->headnode[0];
2863 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2865 mod->hulls[j].firstclipnode = bm->headnode[j];
2866 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2869 mod->firstmodelsurface = bm->firstface;
2870 mod->nummodelsurfaces = bm->numfaces;
2872 // this gets altered below if sky is used
2873 mod->DrawSky = NULL;
2874 mod->Draw = R_Model_Brush_Draw;
2875 mod->DrawFakeShadow = NULL;
2876 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2877 mod->DrawLight = R_Model_Brush_DrawLight;
2878 mod->pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t **));
2879 mod->pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool, (mod->nummodelsurfaces + mod->numtextures) * sizeof(msurface_t *));
2880 mod->pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(int));
2881 Mod_BuildPVSTextureChains(mod);
2882 Mod_BuildLightmapUpdateChains(originalloadmodel->mempool, mod);
2883 if (mod->nummodelsurfaces)
2885 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2886 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2887 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2890 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2892 // we only need to have a drawsky function if it is used (usually only on world model)
2893 if (surf->texinfo->texture->shader == &Cshader_sky)
2894 mod->DrawSky = R_Model_Brush_DrawSky;
2895 // LordHavoc: submodels always clip, even if water
2896 if (mod->numsubmodels - 1)
2897 surf->flags |= SURF_SOLIDCLIP;
2898 // calculate bounding shapes
2899 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
2901 for (k = 0, vec = mesh->vertex3f;k < mesh->numverts;k++, vec += 3)
2903 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2904 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2905 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2906 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2907 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2908 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2909 dist = vec[0]*vec[0]+vec[1]*vec[1];
2910 if (modelyawradius < dist)
2911 modelyawradius = dist;
2912 dist += vec[2]*vec[2];
2913 if (modelradius < dist)
2918 modelyawradius = sqrt(modelyawradius);
2919 modelradius = sqrt(modelradius);
2920 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2921 mod->yawmins[2] = mod->normalmins[2];
2922 mod->yawmaxs[2] = mod->normalmaxs[2];
2923 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2924 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2925 mod->radius = modelradius;
2926 mod->radius2 = modelradius * modelradius;
2930 // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2931 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2933 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2935 mod->numleafs = bm->visleafs;
2937 // LordHavoc: only register submodels if it is the world
2938 // (prevents bsp models from replacing world submodels)
2939 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2942 // duplicate the basic information
2943 sprintf (name, "*%i", i+1);
2944 loadmodel = Mod_FindName (name);
2946 strcpy (loadmodel->name, name);
2947 // textures and memory belong to the main model
2948 loadmodel->texturepool = NULL;
2949 loadmodel->mempool = NULL;
2954 loadmodel = originalloadmodel;
2955 //Mod_ProcessLightList ();