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;
261 VectorCopy(in, info.center);
262 info.radius = radius;
267 VectorClear(info.nudge);
268 info.bestdist = radius;
269 Mod_FindNonSolidLocation_r(&info, model->nodes + model->hulls[0].firstclipnode);
270 VectorAdd(info.center, info.nudge, info.center);
272 while(info.bestdist < radius && ++i < 10);
273 VectorCopy(info.center, out);
281 static qbyte *Mod_DecompressVis (qbyte *in, model_t *model)
283 static qbyte decompressed[MAX_MAP_LEAFS/8];
288 row = (model->numleafs+7)>>3;
306 } while (out - decompressed < row);
311 qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
313 if (r_novis.integer || leaf == model->leafs || leaf->compressed_vis == NULL)
315 return Mod_DecompressVis (leaf->compressed_vis, model);
323 static void Mod_LoadTextures (lump_t *l)
325 int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs, incomplete;
327 texture_t *tx, *tx2, *anims[10], *altanims[10];
329 qbyte *data, *mtdata;
332 loadmodel->textures = NULL;
337 m = (dmiptexlump_t *)(mod_base + l->fileofs);
339 m->nummiptex = LittleLong (m->nummiptex);
341 // add two slots for notexture walls and notexture liquids
342 loadmodel->numtextures = m->nummiptex + 2;
343 loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(texture_t));
345 // fill out all slots with notexture
346 for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++)
349 strcpy(tx->name, "NO TEXTURE FOUND");
352 tx->skin.base = r_notexture;
353 tx->shader = &Cshader_wall_lightmap;
354 tx->flags = SURF_SOLIDCLIP;
355 if (i == loadmodel->numtextures - 1)
357 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
358 tx->shader = &Cshader_water;
360 tx->currentframe = tx;
363 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
365 // LordHavoc: mostly rewritten map texture loader
366 for (i = 0;i < m->nummiptex;i++)
368 dofs[i] = LittleLong(dofs[i]);
369 if (dofs[i] == -1 || r_nosurftextures.integer)
371 dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
373 // make sure name is no more than 15 characters
374 for (j = 0;dmiptex->name[j] && j < 15;j++)
375 name[j] = dmiptex->name[j];
378 mtwidth = LittleLong (dmiptex->width);
379 mtheight = LittleLong (dmiptex->height);
381 j = LittleLong (dmiptex->offsets[0]);
385 if (j < 40 || j + mtwidth * mtheight > l->filelen)
387 Con_Printf ("Texture \"%s\" in \"%s\"is corrupt or incomplete\n", dmiptex->name, loadmodel->name);
390 mtdata = (qbyte *)dmiptex + j;
393 if ((mtwidth & 15) || (mtheight & 15))
394 Con_Printf ("warning: texture \"%s\" in \"%s\" is not 16 aligned", dmiptex->name, loadmodel->name);
396 // LordHavoc: force all names to lowercase
397 for (j = 0;name[j];j++)
398 if (name[j] >= 'A' && name[j] <= 'Z')
399 name[j] += 'a' - 'A';
401 tx = loadmodel->textures + i;
402 strcpy(tx->name, name);
404 tx->height = mtheight;
408 sprintf(tx->name, "unnamed%i", i);
409 Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
412 // LordHavoc: HL sky textures are entirely different than quake
413 if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
415 if (loadmodel->isworldmodel)
417 data = loadimagepixels(tx->name, false, 0, 0);
420 if (image_width == 256 && image_height == 128)
428 Con_Printf ("Invalid replacement texture for sky \"%s\" in %\"%s\", must be 256x128 pixels\n", tx->name, loadmodel->name);
430 R_InitSky (mtdata, 1);
433 else if (mtdata != NULL)
434 R_InitSky (mtdata, 1);
439 if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true))
441 // did not find external texture, load it from the bsp or wad3
442 if (loadmodel->ishlbsp)
444 // internal texture overrides wad
445 qbyte *pixels, *freepixels;
446 pixels = freepixels = NULL;
448 pixels = W_ConvertWAD3Texture(dmiptex);
450 pixels = freepixels = W_GetTexture(tx->name);
453 tx->width = image_width;
454 tx->height = image_height;
455 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);
458 Mem_Free(freepixels);
460 else if (mtdata) // texture included
461 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);
464 if (tx->skin.base == NULL)
469 tx->skin.base = r_notexture;
472 if (tx->name[0] == '*')
474 // turb does not block movement
475 tx->flags &= ~SURF_SOLIDCLIP;
476 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
477 // LordHavoc: some turbulent textures should be fullbright and solid
478 if (!strncmp(tx->name,"*lava",5)
479 || !strncmp(tx->name,"*teleport",9)
480 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
481 tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
483 tx->flags |= SURF_WATERALPHA;
484 tx->shader = &Cshader_water;
486 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
488 tx->flags |= SURF_DRAWSKY;
489 tx->shader = &Cshader_sky;
493 tx->flags |= SURF_LIGHTMAP;
495 tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT;
496 tx->shader = &Cshader_wall_lightmap;
499 // start out with no animation
500 tx->currentframe = tx;
503 // sequence the animations
504 for (i = 0;i < m->nummiptex;i++)
506 tx = loadmodel->textures + i;
507 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
509 if (tx->anim_total[0] || tx->anim_total[1])
510 continue; // already sequenced
512 // find the number of frames in the animation
513 memset (anims, 0, sizeof(anims));
514 memset (altanims, 0, sizeof(altanims));
516 for (j = i;j < m->nummiptex;j++)
518 tx2 = loadmodel->textures + j;
519 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
523 if (num >= '0' && num <= '9')
524 anims[num - '0'] = tx2;
525 else if (num >= 'a' && num <= 'j')
526 altanims[num - 'a'] = tx2;
528 Con_Printf ("Bad animating texture %s\n", tx->name);
532 for (j = 0;j < 10;j++)
539 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
542 for (j = 0;j < max;j++)
546 Con_Printf ("Missing frame %i of %s\n", j, tx->name);
550 for (j = 0;j < altmax;j++)
554 Con_Printf ("Missing altframe %i of %s\n", j, tx->name);
563 // if there is no alternate animation, duplicate the primary
564 // animation into the alternate
566 for (k = 0;k < 10;k++)
567 altanims[k] = anims[k];
570 // link together the primary animation
571 for (j = 0;j < max;j++)
574 tx2->animated = true;
575 tx2->anim_total[0] = max;
576 tx2->anim_total[1] = altmax;
577 for (k = 0;k < 10;k++)
579 tx2->anim_frames[0][k] = anims[k];
580 tx2->anim_frames[1][k] = altanims[k];
584 // if there really is an alternate anim...
585 if (anims[0] != altanims[0])
587 // link together the alternate animation
588 for (j = 0;j < altmax;j++)
591 tx2->animated = true;
592 // the primary/alternate are reversed here
593 tx2->anim_total[0] = altmax;
594 tx2->anim_total[1] = max;
595 for (k = 0;k < 10;k++)
597 tx2->anim_frames[0][k] = altanims[k];
598 tx2->anim_frames[1][k] = anims[k];
610 static void Mod_LoadLighting (lump_t *l)
613 qbyte *in, *out, *data, d;
614 char litfilename[1024];
615 loadmodel->lightdata = NULL;
616 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
618 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
619 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
621 else // LordHavoc: bsp version 29 (normal white lighting)
623 // LordHavoc: hope is not lost yet, check for a .lit file to load
624 strcpy(litfilename, loadmodel->name);
625 FS_StripExtension(litfilename, litfilename);
626 strcat(litfilename, ".lit");
627 data = (qbyte*) FS_LoadFile (litfilename, false);
630 if (fs_filesize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
632 i = LittleLong(((int *)data)[1]);
635 Con_DPrintf("loaded %s\n", litfilename);
636 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, fs_filesize - 8);
637 memcpy(loadmodel->lightdata, data + 8, fs_filesize - 8);
643 Con_Printf("Unknown .lit file version (%d)\n", i);
649 if (fs_filesize == 8)
650 Con_Printf("Empty .lit file, ignoring\n");
652 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
656 // LordHavoc: oh well, expand the white lighting data
659 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
660 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
661 out = loadmodel->lightdata;
662 memcpy (in, mod_base + l->fileofs, l->filelen);
663 for (i = 0;i < l->filelen;i++)
673 void Mod_LoadLightList(void)
676 char lightsfilename[1024], *s, *t, *lightsstring;
679 strcpy(lightsfilename, loadmodel->name);
680 FS_StripExtension(lightsfilename, lightsfilename);
681 strcat(lightsfilename, ".lights");
682 s = lightsstring = (char *) FS_LoadFile (lightsfilename, false);
688 while (*s && *s != '\n')
692 Mem_Free(lightsstring);
693 Host_Error("lights file must end with a newline\n");
698 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
701 while (*s && n < numlights)
704 while (*s && *s != '\n')
708 Mem_Free(lightsstring);
709 Host_Error("misparsed lights file!\n");
711 e = loadmodel->lights + n;
713 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);
717 Mem_Free(lightsstring);
718 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);
725 Mem_Free(lightsstring);
726 Host_Error("misparsed lights file!\n");
728 loadmodel->numlights = numlights;
729 Mem_Free(lightsstring);
734 static int castshadowcount = 0;
735 void Mod_ProcessLightList(void)
737 int j, k, l, *mark, lnum;
745 for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++)
747 e->cullradius2 = DotProduct(e->light, e->light) / (e->falloff * e->falloff * 8192.0f * 8192.0f * 2.0f * 2.0f);// + 4096.0f;
748 if (e->cullradius2 > 4096.0f * 4096.0f)
749 e->cullradius2 = 4096.0f * 4096.0f;
750 e->cullradius = e->lightradius = sqrt(e->cullradius2);
751 leaf = Mod_PointInLeaf(e->origin, loadmodel);
752 if (leaf->compressed_vis)
753 pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel);
756 for (j = 0;j < loadmodel->numsurfaces;j++)
757 loadmodel->surfacevisframes[j] = -1;
758 for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++)
760 if (pvs[j >> 3] & (1 << (j & 7)))
762 for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++)
764 surf = loadmodel->surfaces + *mark;
765 if (surf->number != *mark)
766 Con_Printf("%d != %d\n", surf->number, *mark);
767 dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
768 if (surf->flags & SURF_PLANEBACK)
770 if (dist > 0 && dist < e->cullradius)
772 temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
773 temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
774 temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
775 if (DotProduct(temp, temp) < lightradius2)
776 loadmodel->surfacevisframes[*mark] = -2;
781 // build list of light receiving surfaces
783 for (j = 0;j < loadmodel->numsurfaces;j++)
784 if (loadmodel->surfacevisframes[j] == -2)
787 if (e->numsurfaces > 0)
789 e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
791 for (j = 0;j < loadmodel->numsurfaces;j++)
792 if (loadmodel->surfacevisframes[j] == -2)
793 e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j;
795 // find bounding box and sphere of lit surfaces
796 // (these will be used for creating a shape to clip the light)
798 for (j = 0;j < e->numsurfaces;j++)
800 surf = e->surfaces[j];
803 VectorCopy(surf->poly_verts, e->mins);
804 VectorCopy(surf->poly_verts, e->maxs);
806 for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
808 if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
809 if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
810 if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
811 VectorSubtract(v, e->origin, temp);
812 dist = DotProduct(temp, temp);
817 if (e->cullradius2 > radius2)
819 e->cullradius2 = radius2;
820 e->cullradius = sqrt(e->cullradius2);
822 if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
823 if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
824 if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
825 if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
826 if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
827 if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
828 // clip shadow volumes against eachother to remove unnecessary
829 // polygons (and sections of polygons)
831 //vec3_t polymins, polymaxs;
833 float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
834 float f, *v0, *v1, projectdistance;
836 e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024);
839 vec3_t outermins, outermaxs, innermins, innermaxs;
840 innermins[0] = e->mins[0] - 1;
841 innermins[1] = e->mins[1] - 1;
842 innermins[2] = e->mins[2] - 1;
843 innermaxs[0] = e->maxs[0] + 1;
844 innermaxs[1] = e->maxs[1] + 1;
845 innermaxs[2] = e->maxs[2] + 1;
846 outermins[0] = loadmodel->normalmins[0] - 1;
847 outermins[1] = loadmodel->normalmins[1] - 1;
848 outermins[2] = loadmodel->normalmins[2] - 1;
849 outermaxs[0] = loadmodel->normalmaxs[0] + 1;
850 outermaxs[1] = loadmodel->normalmaxs[1] + 1;
851 outermaxs[2] = loadmodel->normalmaxs[2] + 1;
852 // add bounding box around the whole shadow volume set,
853 // facing inward to limit light area, with an outer bounding box
854 // facing outward (this is needed by the shadow rendering method)
856 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
857 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
858 verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
859 verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
860 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
861 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
862 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
863 verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
864 verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
865 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
867 verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
868 verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
869 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
870 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
871 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
872 verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
873 verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
874 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
875 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
876 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
878 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
879 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
880 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
881 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
882 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
883 verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
884 verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
885 verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
886 verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
887 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
889 verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
890 verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
891 verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
892 verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
893 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
894 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
895 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
896 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
897 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
898 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
900 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
901 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2];
902 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2];
903 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
904 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
905 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
906 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2];
907 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2];
908 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
909 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
911 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2];
912 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
913 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
914 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2];
915 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
916 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2];
917 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
918 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
919 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2];
920 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
924 for (j = 0;j < e->numsurfaces;j++)
926 surf = e->surfaces[j];
927 if (surf->flags & SURF_SHADOWCAST)
928 surf->castshadow = castshadowcount;
930 for (j = 0;j < e->numsurfaces;j++)
932 surf = e->surfaces[j];
933 if (surf->castshadow != castshadowcount)
935 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
936 if (surf->flags & SURF_PLANEBACK)
938 projectdistance = e->lightradius;
939 if (maxverts < surf->poly_numverts)
941 maxverts = surf->poly_numverts;
944 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
946 // copy the original polygon, for the front cap of the volume
947 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
949 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
950 // project the original polygon, reversed, for the back cap of the volume
951 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
953 VectorSubtract(v0, e->origin, temp);
954 VectorNormalize(temp);
955 VectorMA(v0, projectdistance, temp, v1);
957 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
958 // project the shadow volume sides
959 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)
961 if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount)
963 VectorCopy(v1, &verts[0]);
964 VectorCopy(v0, &verts[3]);
965 VectorCopy(v0, &verts[6]);
966 VectorCopy(v1, &verts[9]);
967 VectorSubtract(&verts[6], e->origin, temp);
968 VectorNormalize(temp);
969 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
970 VectorSubtract(&verts[9], e->origin, temp);
971 VectorNormalize(temp);
972 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
973 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
977 // build the triangle mesh
978 e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume);
982 for (mesh = e->shadowvolume;mesh;mesh = mesh->next)
983 l += mesh->numtriangles;
984 Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l);
997 static void Mod_LoadVisibility (lump_t *l)
999 loadmodel->visdata = NULL;
1002 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
1003 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
1006 // used only for HalfLife maps
1007 void Mod_ParseWadsFromEntityLump(const char *data)
1009 char key[128], value[4096];
1014 if (!COM_ParseToken(&data))
1016 if (com_token[0] != '{')
1020 if (!COM_ParseToken(&data))
1022 if (com_token[0] == '}')
1023 break; // end of worldspawn
1024 if (com_token[0] == '_')
1025 strcpy(key, com_token + 1);
1027 strcpy(key, com_token);
1028 while (key[strlen(key)-1] == ' ') // remove trailing spaces
1029 key[strlen(key)-1] = 0;
1030 if (!COM_ParseToken(&data))
1032 strcpy(value, com_token);
1033 if (!strcmp("wad", key)) // for HalfLife maps
1035 if (loadmodel->ishlbsp)
1038 for (i = 0;i < 4096;i++)
1039 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
1045 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
1046 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
1048 else if (value[i] == ';' || value[i] == 0)
1052 strcpy(wadname, "textures/");
1053 strcat(wadname, &value[j]);
1054 W_LoadTextureWadFile (wadname, false);
1071 static void Mod_LoadEntities (lump_t *l)
1073 loadmodel->entities = NULL;
1076 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
1077 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
1078 if (loadmodel->ishlbsp)
1079 Mod_ParseWadsFromEntityLump(loadmodel->entities);
1088 static void Mod_LoadVertexes (lump_t *l)
1094 in = (void *)(mod_base + l->fileofs);
1095 if (l->filelen % sizeof(*in))
1096 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1097 count = l->filelen / sizeof(*in);
1098 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1100 loadmodel->vertexes = out;
1101 loadmodel->numvertexes = count;
1103 for ( i=0 ; i<count ; i++, in++, out++)
1105 out->position[0] = LittleFloat (in->point[0]);
1106 out->position[1] = LittleFloat (in->point[1]);
1107 out->position[2] = LittleFloat (in->point[2]);
1116 static void Mod_LoadSubmodels (lump_t *l)
1122 in = (void *)(mod_base + l->fileofs);
1123 if (l->filelen % sizeof(*in))
1124 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1125 count = l->filelen / sizeof(*in);
1126 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1128 loadmodel->submodels = out;
1129 loadmodel->numsubmodels = count;
1131 for ( i=0 ; i<count ; i++, in++, out++)
1133 for (j=0 ; j<3 ; j++)
1135 // spread the mins / maxs by a pixel
1136 out->mins[j] = LittleFloat (in->mins[j]) - 1;
1137 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
1138 out->origin[j] = LittleFloat (in->origin[j]);
1140 for (j=0 ; j<MAX_MAP_HULLS ; j++)
1141 out->headnode[j] = LittleLong (in->headnode[j]);
1142 out->visleafs = LittleLong (in->visleafs);
1143 out->firstface = LittleLong (in->firstface);
1144 out->numfaces = LittleLong (in->numfaces);
1153 static void Mod_LoadEdges (lump_t *l)
1159 in = (void *)(mod_base + l->fileofs);
1160 if (l->filelen % sizeof(*in))
1161 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1162 count = l->filelen / sizeof(*in);
1163 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1165 loadmodel->edges = out;
1166 loadmodel->numedges = count;
1168 for ( i=0 ; i<count ; i++, in++, out++)
1170 out->v[0] = (unsigned short)LittleShort(in->v[0]);
1171 out->v[1] = (unsigned short)LittleShort(in->v[1]);
1180 static void Mod_LoadTexinfo (lump_t *l)
1184 int i, j, k, count, miptex;
1186 in = (void *)(mod_base + l->fileofs);
1187 if (l->filelen % sizeof(*in))
1188 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1189 count = l->filelen / sizeof(*in);
1190 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1192 loadmodel->texinfo = out;
1193 loadmodel->numtexinfo = count;
1195 for (i = 0;i < count;i++, in++, out++)
1197 for (k = 0;k < 2;k++)
1198 for (j = 0;j < 4;j++)
1199 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
1201 miptex = LittleLong (in->miptex);
1202 out->flags = LittleLong (in->flags);
1204 out->texture = NULL;
1205 if (loadmodel->textures)
1207 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
1208 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
1210 out->texture = loadmodel->textures + miptex;
1212 if (out->flags & TEX_SPECIAL)
1214 // if texture chosen is NULL or the shader needs a lightmap,
1215 // force to notexture water shader
1216 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
1217 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
1221 // if texture chosen is NULL, force to notexture
1222 if (out->texture == NULL)
1223 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
1228 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1233 mins[0] = mins[1] = mins[2] = 9999;
1234 maxs[0] = maxs[1] = maxs[2] = -9999;
1236 for (i = 0;i < numverts;i++)
1238 for (j = 0;j < 3;j++, v++)
1249 #define MAX_SUBDIVPOLYTRIANGLES 4096
1250 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1252 static int subdivpolyverts, subdivpolytriangles;
1253 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1254 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1256 static int subdivpolylookupvert(vec3_t v)
1259 for (i = 0;i < subdivpolyverts;i++)
1260 if (subdivpolyvert[i][0] == v[0]
1261 && subdivpolyvert[i][1] == v[1]
1262 && subdivpolyvert[i][2] == v[2])
1264 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1265 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1266 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1267 return subdivpolyverts++;
1270 static void SubdividePolygon (int numverts, float *verts)
1272 int i, i1, i2, i3, f, b, c, p;
1273 vec3_t mins, maxs, front[256], back[256];
1274 float m, *pv, *cv, dist[256], frac;
1277 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1279 BoundPoly (numverts, verts, mins, maxs);
1281 for (i = 0;i < 3;i++)
1283 m = (mins[i] + maxs[i]) * 0.5;
1284 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1285 if (maxs[i] - m < 8)
1287 if (m - mins[i] < 8)
1291 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1292 dist[c] = cv[i] - m;
1295 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1299 VectorCopy (pv, front[f]);
1304 VectorCopy (pv, back[b]);
1307 if (dist[p] == 0 || dist[c] == 0)
1309 if ( (dist[p] > 0) != (dist[c] > 0) )
1312 frac = dist[p] / (dist[p] - dist[c]);
1313 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1314 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1315 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1321 SubdividePolygon (f, front[0]);
1322 SubdividePolygon (b, back[0]);
1326 i1 = subdivpolylookupvert(verts);
1327 i2 = subdivpolylookupvert(verts + 3);
1328 for (i = 2;i < numverts;i++)
1330 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1332 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1336 i3 = subdivpolylookupvert(verts + i * 3);
1337 subdivpolyindex[subdivpolytriangles][0] = i1;
1338 subdivpolyindex[subdivpolytriangles][1] = i2;
1339 subdivpolyindex[subdivpolytriangles][2] = i3;
1341 subdivpolytriangles++;
1347 Mod_GenerateWarpMesh
1349 Breaks a polygon up along axial 64 unit
1350 boundaries so that turbulent and sky warps
1351 can be done reasonably.
1354 void Mod_GenerateWarpMesh (msurface_t *surf)
1360 subdivpolytriangles = 0;
1361 subdivpolyverts = 0;
1362 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1363 if (subdivpolytriangles < 1)
1364 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1366 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1367 mesh->numverts = subdivpolyverts;
1368 mesh->numtriangles = subdivpolytriangles;
1369 mesh->vertex = (surfvertex_t *)(mesh + 1);
1370 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1371 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1373 for (i = 0;i < mesh->numtriangles;i++)
1374 for (j = 0;j < 3;j++)
1375 mesh->index[i*3+j] = subdivpolyindex[i][j];
1377 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1379 VectorCopy(subdivpolyvert[i], v->v);
1380 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1381 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1386 surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles)
1389 mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (3 + 2 + 2 + 2 + 3 + 3 + 3 + 1) * sizeof(float));
1390 mesh->numverts = numverts;
1391 mesh->numtriangles = numtriangles;
1392 mesh->vertex3f = (float *)(mesh + 1);
1393 mesh->texcoordtexture2f = mesh->vertex3f + mesh->numverts * 3;
1394 mesh->texcoordlightmap2f = mesh->texcoordtexture2f + mesh->numverts * 2;
1395 mesh->texcoorddetail2f = mesh->texcoordlightmap2f + mesh->numverts * 2;
1396 mesh->svector3f = (float *)(mesh->texcoorddetail2f + mesh->numverts * 2);
1397 mesh->tvector3f = mesh->svector3f + mesh->numverts * 3;
1398 mesh->normal3f = mesh->tvector3f + mesh->numverts * 3;
1399 mesh->lightmapoffsets = (int *)(mesh->normal3f + mesh->numverts * 3);
1400 mesh->element3i = mesh->lightmapoffsets + mesh->numverts;
1401 mesh->neighbor3i = mesh->element3i + mesh->numtriangles * 3;
1405 void Mod_GenerateSurfacePolygon (msurface_t *surf, int firstedge, int numedges)
1408 float *vec, *vert, mins[3], maxs[3], val, *v;
1411 // convert edges back to a normal polygon
1412 surf->poly_numverts = numedges;
1413 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * numedges);
1414 for (i = 0;i < numedges;i++)
1416 lindex = loadmodel->surfedges[firstedge + i];
1418 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1420 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1421 VectorCopy (vec, vert);
1425 // calculate polygon bounding box and center
1426 vert = surf->poly_verts;
1427 VectorCopy(vert, mins);
1428 VectorCopy(vert, maxs);
1430 for (i = 1;i < surf->poly_numverts;i++, vert += 3)
1432 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1433 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1434 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1436 VectorCopy(mins, surf->poly_mins);
1437 VectorCopy(maxs, surf->poly_maxs);
1438 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1439 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1440 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1442 // generate surface extents information
1443 tex = surf->texinfo;
1444 mins[0] = maxs[0] = DotProduct(surf->poly_verts, tex->vecs[0]) + tex->vecs[0][3];
1445 mins[1] = maxs[1] = DotProduct(surf->poly_verts, tex->vecs[1]) + tex->vecs[1][3];
1446 for (i = 1, v = surf->poly_verts + 3;i < surf->poly_numverts;i++, v += 3)
1448 for (j = 0;j < 2;j++)
1450 val = DotProduct(v, tex->vecs[j]) + tex->vecs[j][3];
1457 for (i = 0;i < 2;i++)
1459 surf->texturemins[i] = (int) floor(mins[i] / 16) * 16;
1460 surf->extents[i] = (int) ceil(maxs[i] / 16) * 16 - surf->texturemins[i];
1469 static void Mod_LoadFaces (lump_t *l)
1473 int i, count, surfnum, planenum, ssize, tsize, firstedge, numedges, totalverts, totaltris, totalmeshes;
1477 in = (void *)(mod_base + l->fileofs);
1478 if (l->filelen % sizeof(*in))
1479 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1480 count = l->filelen / sizeof(*in);
1481 loadmodel->surfaces = Mem_Alloc(loadmodel->mempool, count*sizeof(msurface_t));
1483 loadmodel->numsurfaces = count;
1484 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1485 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1486 loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1488 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++)
1490 surf->number = surfnum;
1491 // FIXME: validate edges, texinfo, etc?
1492 firstedge = LittleLong(in->firstedge);
1493 numedges = LittleShort(in->numedges);
1494 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)
1495 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->numsurfedges);
1496 i = LittleShort (in->texinfo);
1497 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1498 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1499 surf->texinfo = loadmodel->texinfo + i;
1500 surf->flags = surf->texinfo->texture->flags;
1502 planenum = LittleShort(in->planenum);
1503 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1504 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1506 if (LittleShort(in->side))
1507 surf->flags |= SURF_PLANEBACK;
1509 surf->plane = loadmodel->planes + planenum;
1511 // clear lightmap (filled in later)
1512 surf->lightmaptexture = NULL;
1514 // force lightmap upload on first time seeing the surface
1515 surf->cached_dlight = true;
1517 Mod_GenerateSurfacePolygon(surf, firstedge, numedges);
1519 ssize = (surf->extents[0] >> 4) + 1;
1520 tsize = (surf->extents[1] >> 4) + 1;
1523 for (i = 0;i < MAXLIGHTMAPS;i++)
1524 surf->styles[i] = in->styles[i];
1525 i = LittleLong(in->lightofs);
1527 surf->samples = NULL;
1528 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1529 surf->samples = loadmodel->lightdata + i;
1530 else // LordHavoc: white lighting (bsp version 29)
1531 surf->samples = loadmodel->lightdata + (i * 3);
1533 if (surf->texinfo->texture->shader == &Cshader_wall_lightmap)
1535 if ((surf->extents[0] >> 4) + 1 > (256) || (surf->extents[1] >> 4) + 1 > (256))
1536 Host_Error ("Bad surface extents");
1537 // stainmap for permanent marks on walls
1538 surf->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1540 memset(surf->stainsamples, 255, ssize * tsize * 3);
1544 loadmodel->entiremesh = Mod_AllocSurfMesh(totalverts, totaltris);
1545 loadmodel->surfmeshes = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) * totalmeshes);
1547 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++)
1549 mesh = surf->mesh = loadmodel->surfmeshes + totalmeshes;
1550 mesh->numverts = surf->poly_numverts;
1551 mesh->numtriangles = surf->poly_numverts - 2;
1552 mesh->vertex3f = loadmodel->entiremesh->vertex3f + totalverts * 3;
1553 mesh->texcoordtexture2f = loadmodel->entiremesh->texcoordtexture2f + totalverts * 2;
1554 mesh->texcoordlightmap2f = loadmodel->entiremesh->texcoordlightmap2f + totalverts * 2;
1555 mesh->texcoorddetail2f = loadmodel->entiremesh->texcoorddetail2f + totalverts * 2;
1556 mesh->svector3f = loadmodel->entiremesh->svector3f + totalverts * 3;
1557 mesh->tvector3f = loadmodel->entiremesh->tvector3f + totalverts * 3;
1558 mesh->normal3f = loadmodel->entiremesh->normal3f + totalverts * 3;
1559 mesh->lightmapoffsets = loadmodel->entiremesh->lightmapoffsets + totalverts;
1560 mesh->element3i = loadmodel->entiremesh->element3i + totaltris * 3;
1561 mesh->neighbor3i = loadmodel->entiremesh->neighbor3i + totaltris * 3;
1563 surf->lightmaptexturestride = 0;
1564 surf->lightmaptexture = NULL;
1566 for (i = 0;i < mesh->numverts;i++)
1568 mesh->vertex3f[i * 3 + 0] = surf->poly_verts[i * 3 + 0];
1569 mesh->vertex3f[i * 3 + 1] = surf->poly_verts[i * 3 + 1];
1570 mesh->vertex3f[i * 3 + 2] = surf->poly_verts[i * 3 + 2];
1571 s = DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1572 t = DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1573 mesh->texcoordtexture2f[i * 2 + 0] = s / surf->texinfo->texture->width;
1574 mesh->texcoordtexture2f[i * 2 + 1] = t / surf->texinfo->texture->height;
1575 mesh->texcoorddetail2f[i * 2 + 0] = s * (1.0f / 16.0f);
1576 mesh->texcoorddetail2f[i * 2 + 1] = t * (1.0f / 16.0f);
1577 mesh->texcoordlightmap2f[i * 2 + 0] = 0;
1578 mesh->texcoordlightmap2f[i * 2 + 1] = 0;
1579 mesh->lightmapoffsets[i] = 0;
1582 for (i = 0;i < mesh->numtriangles;i++)
1584 mesh->element3i[i * 3 + 0] = 0;
1585 mesh->element3i[i * 3 + 1] = i + 1;
1586 mesh->element3i[i * 3 + 2] = i + 2;
1589 Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1590 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->vertex3f, mesh->texcoordtexture2f, mesh->element3i, mesh->svector3f, mesh->tvector3f, mesh->normal3f);
1592 if (surf->texinfo->texture->shader == &Cshader_wall_lightmap)
1594 int i, iu, iv, smax, tmax;
1595 float u, v, ubase, vbase, uscale, vscale;
1597 smax = surf->extents[0] >> 4;
1598 tmax = surf->extents[1] >> 4;
1600 surf->flags |= SURF_LIGHTMAP;
1601 if (r_miplightmaps.integer)
1603 surf->lightmaptexturestride = smax+1;
1604 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);
1608 surf->lightmaptexturestride = R_CompatibleFragmentWidth(smax+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1609 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);
1611 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1612 uscale = (uscale - ubase) / (smax + 1);
1613 vscale = (vscale - vbase) / (tmax + 1);
1615 for (i = 0;i < mesh->numverts;i++)
1617 u = ((DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1618 v = ((DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1619 mesh->texcoordlightmap2f[i * 2 + 0] = u * uscale + ubase;
1620 mesh->texcoordlightmap2f[i * 2 + 1] = v * vscale + vbase;
1621 // LordHavoc: calc lightmap data offset for vertex lighting to use
1624 mesh->lightmapoffsets[i] = (bound(0, iv, tmax) * (smax+1) + bound(0, iu, smax)) * 3;
1635 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1637 node->parent = parent;
1638 if (node->contents < 0)
1640 Mod_SetParent (node->children[0], node);
1641 Mod_SetParent (node->children[1], node);
1649 static void Mod_LoadNodes (lump_t *l)
1655 in = (void *)(mod_base + l->fileofs);
1656 if (l->filelen % sizeof(*in))
1657 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1658 count = l->filelen / sizeof(*in);
1659 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1661 loadmodel->nodes = out;
1662 loadmodel->numnodes = count;
1664 for ( i=0 ; i<count ; i++, in++, out++)
1666 for (j=0 ; j<3 ; j++)
1668 out->mins[j] = LittleShort (in->mins[j]);
1669 out->maxs[j] = LittleShort (in->maxs[j]);
1672 p = LittleLong(in->planenum);
1673 out->plane = loadmodel->planes + p;
1675 out->firstsurface = LittleShort (in->firstface);
1676 out->numsurfaces = LittleShort (in->numfaces);
1678 for (j=0 ; j<2 ; j++)
1680 p = LittleShort (in->children[j]);
1682 out->children[j] = loadmodel->nodes + p;
1684 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1688 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1696 static void Mod_LoadLeafs (lump_t *l)
1702 in = (void *)(mod_base + l->fileofs);
1703 if (l->filelen % sizeof(*in))
1704 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1705 count = l->filelen / sizeof(*in);
1706 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1708 loadmodel->leafs = out;
1709 loadmodel->numleafs = count;
1711 for ( i=0 ; i<count ; i++, in++, out++)
1713 for (j=0 ; j<3 ; j++)
1715 out->mins[j] = LittleShort (in->mins[j]);
1716 out->maxs[j] = LittleShort (in->maxs[j]);
1719 p = LittleLong(in->contents);
1722 out->firstmarksurface = loadmodel->marksurfaces +
1723 LittleShort(in->firstmarksurface);
1724 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1726 p = LittleLong(in->visofs);
1728 out->compressed_vis = NULL;
1730 out->compressed_vis = loadmodel->visdata + p;
1732 for (j=0 ; j<4 ; j++)
1733 out->ambient_sound_level[j] = in->ambient_level[j];
1735 // FIXME: Insert caustics here
1744 static void Mod_LoadClipnodes (lump_t *l)
1746 dclipnode_t *in, *out;
1750 in = (void *)(mod_base + l->fileofs);
1751 if (l->filelen % sizeof(*in))
1752 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1753 count = l->filelen / sizeof(*in);
1754 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1756 loadmodel->clipnodes = out;
1757 loadmodel->numclipnodes = count;
1759 if (loadmodel->ishlbsp)
1761 hull = &loadmodel->hulls[1];
1762 hull->clipnodes = out;
1763 hull->firstclipnode = 0;
1764 hull->lastclipnode = count-1;
1765 hull->planes = loadmodel->planes;
1766 hull->clip_mins[0] = -16;
1767 hull->clip_mins[1] = -16;
1768 hull->clip_mins[2] = -36;
1769 hull->clip_maxs[0] = 16;
1770 hull->clip_maxs[1] = 16;
1771 hull->clip_maxs[2] = 36;
1772 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1774 hull = &loadmodel->hulls[2];
1775 hull->clipnodes = out;
1776 hull->firstclipnode = 0;
1777 hull->lastclipnode = count-1;
1778 hull->planes = loadmodel->planes;
1779 hull->clip_mins[0] = -32;
1780 hull->clip_mins[1] = -32;
1781 hull->clip_mins[2] = -32;
1782 hull->clip_maxs[0] = 32;
1783 hull->clip_maxs[1] = 32;
1784 hull->clip_maxs[2] = 32;
1785 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1787 hull = &loadmodel->hulls[3];
1788 hull->clipnodes = out;
1789 hull->firstclipnode = 0;
1790 hull->lastclipnode = count-1;
1791 hull->planes = loadmodel->planes;
1792 hull->clip_mins[0] = -16;
1793 hull->clip_mins[1] = -16;
1794 hull->clip_mins[2] = -18;
1795 hull->clip_maxs[0] = 16;
1796 hull->clip_maxs[1] = 16;
1797 hull->clip_maxs[2] = 18;
1798 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1802 hull = &loadmodel->hulls[1];
1803 hull->clipnodes = out;
1804 hull->firstclipnode = 0;
1805 hull->lastclipnode = count-1;
1806 hull->planes = loadmodel->planes;
1807 hull->clip_mins[0] = -16;
1808 hull->clip_mins[1] = -16;
1809 hull->clip_mins[2] = -24;
1810 hull->clip_maxs[0] = 16;
1811 hull->clip_maxs[1] = 16;
1812 hull->clip_maxs[2] = 32;
1813 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1815 hull = &loadmodel->hulls[2];
1816 hull->clipnodes = out;
1817 hull->firstclipnode = 0;
1818 hull->lastclipnode = count-1;
1819 hull->planes = loadmodel->planes;
1820 hull->clip_mins[0] = -32;
1821 hull->clip_mins[1] = -32;
1822 hull->clip_mins[2] = -24;
1823 hull->clip_maxs[0] = 32;
1824 hull->clip_maxs[1] = 32;
1825 hull->clip_maxs[2] = 64;
1826 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1829 for (i=0 ; i<count ; i++, out++, in++)
1831 out->planenum = LittleLong(in->planenum);
1832 out->children[0] = LittleShort(in->children[0]);
1833 out->children[1] = LittleShort(in->children[1]);
1834 if (out->children[0] >= count || out->children[1] >= count)
1835 Host_Error("Corrupt clipping hull (out of range child)\n");
1843 Duplicate the drawing hull structure as a clipping hull
1846 static void Mod_MakeHull0 (void)
1853 hull = &loadmodel->hulls[0];
1855 in = loadmodel->nodes;
1856 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1858 hull->clipnodes = out;
1859 hull->firstclipnode = 0;
1860 hull->lastclipnode = loadmodel->numnodes - 1;
1861 hull->planes = loadmodel->planes;
1863 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1865 out->planenum = in->plane - loadmodel->planes;
1866 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1867 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1873 Mod_LoadMarksurfaces
1876 static void Mod_LoadMarksurfaces (lump_t *l)
1881 in = (void *)(mod_base + l->fileofs);
1882 if (l->filelen % sizeof(*in))
1883 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1884 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1885 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1887 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1889 j = (unsigned) LittleShort(in[i]);
1890 if (j >= loadmodel->numsurfaces)
1891 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1892 loadmodel->marksurfaces[i] = j;
1901 static void Mod_LoadSurfedges (lump_t *l)
1906 in = (void *)(mod_base + l->fileofs);
1907 if (l->filelen % sizeof(*in))
1908 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1909 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1910 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1912 for (i = 0;i < loadmodel->numsurfedges;i++)
1913 loadmodel->surfedges[i] = LittleLong (in[i]);
1922 static void Mod_LoadPlanes (lump_t *l)
1928 in = (void *)(mod_base + l->fileofs);
1929 if (l->filelen % sizeof(*in))
1930 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1932 loadmodel->numplanes = l->filelen / sizeof(*in);
1933 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1935 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1937 out->normal[0] = LittleFloat (in->normal[0]);
1938 out->normal[1] = LittleFloat (in->normal[1]);
1939 out->normal[2] = LittleFloat (in->normal[2]);
1940 out->dist = LittleFloat (in->dist);
1946 #define MAX_POINTS_ON_WINDING 64
1952 double points[8][3]; // variable sized
1961 static winding_t *NewWinding (int points)
1966 if (points > MAX_POINTS_ON_WINDING)
1967 Sys_Error("NewWinding: too many points\n");
1969 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
1970 w = Mem_Alloc(loadmodel->mempool, size);
1971 memset (w, 0, size);
1976 static void FreeWinding (winding_t *w)
1986 static winding_t *BaseWindingForPlane (mplane_t *p)
1988 double org[3], vright[3], vup[3], normal[3];
1991 VectorCopy(p->normal, normal);
1992 VectorVectorsDouble(normal, vright, vup);
1994 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
1995 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
1997 // project a really big axis aligned box onto the plane
2000 VectorScale (p->normal, p->dist, org);
2002 VectorSubtract (org, vright, w->points[0]);
2003 VectorAdd (w->points[0], vup, w->points[0]);
2005 VectorAdd (org, vright, w->points[1]);
2006 VectorAdd (w->points[1], vup, w->points[1]);
2008 VectorAdd (org, vright, w->points[2]);
2009 VectorSubtract (w->points[2], vup, w->points[2]);
2011 VectorSubtract (org, vright, w->points[3]);
2012 VectorSubtract (w->points[3], vup, w->points[3]);
2023 Clips the winding to the plane, returning the new winding on the positive side
2024 Frees the input winding.
2025 If keepon is true, an exactly on-plane winding will be saved, otherwise
2026 it will be clipped away.
2029 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2031 double dists[MAX_POINTS_ON_WINDING + 1];
2032 int sides[MAX_POINTS_ON_WINDING + 1];
2041 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2043 // determine sides for each point
2044 for (i = 0;i < in->numpoints;i++)
2046 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2047 if (dot > ON_EPSILON)
2048 sides[i] = SIDE_FRONT;
2049 else if (dot < -ON_EPSILON)
2050 sides[i] = SIDE_BACK;
2055 sides[i] = sides[0];
2056 dists[i] = dists[0];
2058 if (keepon && !counts[0] && !counts[1])
2069 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2070 if (maxpts > MAX_POINTS_ON_WINDING)
2071 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2073 neww = NewWinding (maxpts);
2075 for (i = 0;i < in->numpoints;i++)
2077 if (neww->numpoints >= maxpts)
2078 Sys_Error ("ClipWinding: points exceeded estimate");
2082 if (sides[i] == SIDE_ON)
2084 VectorCopy (p1, neww->points[neww->numpoints]);
2089 if (sides[i] == SIDE_FRONT)
2091 VectorCopy (p1, neww->points[neww->numpoints]);
2095 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2098 // generate a split point
2099 p2 = in->points[(i+1)%in->numpoints];
2101 dot = dists[i] / (dists[i]-dists[i+1]);
2102 for (j = 0;j < 3;j++)
2103 { // avoid round off error when possible
2104 if (split->normal[j] == 1)
2105 mid[j] = split->dist;
2106 else if (split->normal[j] == -1)
2107 mid[j] = -split->dist;
2109 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2112 VectorCopy (mid, neww->points[neww->numpoints]);
2116 // free the original winding
2127 Divides a winding by a plane, producing one or two windings. The
2128 original winding is not damaged or freed. If only on one side, the
2129 returned winding will be the input winding. If on both sides, two
2130 new windings will be created.
2133 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2135 double dists[MAX_POINTS_ON_WINDING + 1];
2136 int sides[MAX_POINTS_ON_WINDING + 1];
2145 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2147 // determine sides for each point
2148 for (i = 0;i < in->numpoints;i++)
2150 dot = DotProduct (in->points[i], split->normal);
2153 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2154 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2155 else sides[i] = SIDE_ON;
2158 sides[i] = sides[0];
2159 dists[i] = dists[0];
2161 *front = *back = NULL;
2174 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2176 if (maxpts > MAX_POINTS_ON_WINDING)
2177 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2179 *front = f = NewWinding (maxpts);
2180 *back = b = NewWinding (maxpts);
2182 for (i = 0;i < in->numpoints;i++)
2184 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2185 Sys_Error ("DivideWinding: points exceeded estimate");
2189 if (sides[i] == SIDE_ON)
2191 VectorCopy (p1, f->points[f->numpoints]);
2193 VectorCopy (p1, b->points[b->numpoints]);
2198 if (sides[i] == SIDE_FRONT)
2200 VectorCopy (p1, f->points[f->numpoints]);
2203 else if (sides[i] == SIDE_BACK)
2205 VectorCopy (p1, b->points[b->numpoints]);
2209 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2212 // generate a split point
2213 p2 = in->points[(i+1)%in->numpoints];
2215 dot = dists[i] / (dists[i]-dists[i+1]);
2216 for (j = 0;j < 3;j++)
2217 { // avoid round off error when possible
2218 if (split->normal[j] == 1)
2219 mid[j] = split->dist;
2220 else if (split->normal[j] == -1)
2221 mid[j] = -split->dist;
2223 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2226 VectorCopy (mid, f->points[f->numpoints]);
2228 VectorCopy (mid, b->points[b->numpoints]);
2233 typedef struct portal_s
2236 mnode_t *nodes[2]; // [0] = front side of plane
2237 struct portal_s *next[2];
2239 struct portal_s *chain; // all portals are linked into a list
2243 static portal_t *portalchain;
2250 static portal_t *AllocPortal (void)
2253 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2254 p->chain = portalchain;
2259 static void FreePortal(portal_t *p)
2264 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2266 // calculate children first
2267 if (node->children[0]->contents >= 0)
2268 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2269 if (node->children[1]->contents >= 0)
2270 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2272 // make combined bounding box from children
2273 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2274 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2275 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2276 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2277 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2278 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2281 static void Mod_FinalizePortals(void)
2283 int i, j, numportals, numpoints;
2284 portal_t *p, *pnext;
2287 mleaf_t *leaf, *endleaf;
2290 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2291 leaf = loadmodel->leafs;
2292 endleaf = leaf + loadmodel->numleafs;
2293 for (;leaf < endleaf;leaf++)
2295 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2296 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2303 for (i = 0;i < 2;i++)
2305 leaf = (mleaf_t *)p->nodes[i];
2307 for (j = 0;j < w->numpoints;j++)
2309 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2310 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2311 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2312 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2313 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2314 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2321 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2323 // tally up portal and point counts
2329 // note: this check must match the one below or it will usually corrupt memory
2330 // 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
2331 if (p->winding && p->nodes[0] != p->nodes[1]
2332 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2333 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2336 numpoints += p->winding->numpoints * 2;
2340 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2341 loadmodel->numportals = numportals;
2342 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2343 loadmodel->numportalpoints = numpoints;
2344 // clear all leaf portal chains
2345 for (i = 0;i < loadmodel->numleafs;i++)
2346 loadmodel->leafs[i].portals = NULL;
2347 // process all portals in the global portal chain, while freeing them
2348 portal = loadmodel->portals;
2349 point = loadmodel->portalpoints;
2358 // note: this check must match the one above or it will usually corrupt memory
2359 // 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
2360 if (p->nodes[0] != p->nodes[1]
2361 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2362 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2364 // first make the back to front portal (forward portal)
2365 portal->points = point;
2366 portal->numpoints = p->winding->numpoints;
2367 portal->plane.dist = p->plane.dist;
2368 VectorCopy(p->plane.normal, portal->plane.normal);
2369 portal->here = (mleaf_t *)p->nodes[1];
2370 portal->past = (mleaf_t *)p->nodes[0];
2372 for (j = 0;j < portal->numpoints;j++)
2374 VectorCopy(p->winding->points[j], point->position);
2377 PlaneClassify(&portal->plane);
2379 // link into leaf's portal chain
2380 portal->next = portal->here->portals;
2381 portal->here->portals = portal;
2383 // advance to next portal
2386 // then make the front to back portal (backward portal)
2387 portal->points = point;
2388 portal->numpoints = p->winding->numpoints;
2389 portal->plane.dist = -p->plane.dist;
2390 VectorNegate(p->plane.normal, portal->plane.normal);
2391 portal->here = (mleaf_t *)p->nodes[0];
2392 portal->past = (mleaf_t *)p->nodes[1];
2394 for (j = portal->numpoints - 1;j >= 0;j--)
2396 VectorCopy(p->winding->points[j], point->position);
2399 PlaneClassify(&portal->plane);
2401 // link into leaf's portal chain
2402 portal->next = portal->here->portals;
2403 portal->here->portals = portal;
2405 // advance to next portal
2408 FreeWinding(p->winding);
2420 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2423 Host_Error ("AddPortalToNodes: NULL front node");
2425 Host_Error ("AddPortalToNodes: NULL back node");
2426 if (p->nodes[0] || p->nodes[1])
2427 Host_Error ("AddPortalToNodes: already included");
2428 // 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
2430 p->nodes[0] = front;
2431 p->next[0] = (portal_t *)front->portals;
2432 front->portals = (mportal_t *)p;
2435 p->next[1] = (portal_t *)back->portals;
2436 back->portals = (mportal_t *)p;
2441 RemovePortalFromNode
2444 static void RemovePortalFromNodes(portal_t *portal)
2448 void **portalpointer;
2450 for (i = 0;i < 2;i++)
2452 node = portal->nodes[i];
2454 portalpointer = (void **) &node->portals;
2459 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2463 if (portal->nodes[0] == node)
2465 *portalpointer = portal->next[0];
2466 portal->nodes[0] = NULL;
2468 else if (portal->nodes[1] == node)
2470 *portalpointer = portal->next[1];
2471 portal->nodes[1] = NULL;
2474 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2478 if (t->nodes[0] == node)
2479 portalpointer = (void **) &t->next[0];
2480 else if (t->nodes[1] == node)
2481 portalpointer = (void **) &t->next[1];
2483 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2488 static void Mod_RecursiveNodePortals (mnode_t *node)
2491 mnode_t *front, *back, *other_node;
2492 mplane_t clipplane, *plane;
2493 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2494 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2496 // if a leaf, we're done
2500 plane = node->plane;
2502 front = node->children[0];
2503 back = node->children[1];
2505 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2507 // create the new portal by generating a polygon for the node plane,
2508 // and clipping it by all of the other portals (which came from nodes above this one)
2509 nodeportal = AllocPortal ();
2510 nodeportal->plane = *node->plane;
2512 nodeportalwinding = BaseWindingForPlane (node->plane);
2513 side = 0; // shut up compiler warning
2514 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2516 clipplane = portal->plane;
2517 if (portal->nodes[0] == portal->nodes[1])
2518 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2519 if (portal->nodes[0] == node)
2521 else if (portal->nodes[1] == node)
2523 clipplane.dist = -clipplane.dist;
2524 VectorNegate (clipplane.normal, clipplane.normal);
2528 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2530 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2531 if (!nodeportalwinding)
2533 Con_Printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2538 if (nodeportalwinding)
2540 // if the plane was not clipped on all sides, there was an error
2541 nodeportal->winding = nodeportalwinding;
2542 AddPortalToNodes (nodeportal, front, back);
2545 // split the portals of this node along this node's plane and assign them to the children of this node
2546 // (migrating the portals downward through the tree)
2547 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2549 if (portal->nodes[0] == portal->nodes[1])
2550 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2551 if (portal->nodes[0] == node)
2553 else if (portal->nodes[1] == node)
2556 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2557 nextportal = portal->next[side];
2559 other_node = portal->nodes[!side];
2560 RemovePortalFromNodes (portal);
2562 // cut the portal into two portals, one on each side of the node plane
2563 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2568 AddPortalToNodes (portal, back, other_node);
2570 AddPortalToNodes (portal, other_node, back);
2576 AddPortalToNodes (portal, front, other_node);
2578 AddPortalToNodes (portal, other_node, front);
2582 // the winding is split
2583 splitportal = AllocPortal ();
2584 temp = splitportal->chain;
2585 *splitportal = *portal;
2586 splitportal->chain = temp;
2587 splitportal->winding = backwinding;
2588 FreeWinding (portal->winding);
2589 portal->winding = frontwinding;
2593 AddPortalToNodes (portal, front, other_node);
2594 AddPortalToNodes (splitportal, back, other_node);
2598 AddPortalToNodes (portal, other_node, front);
2599 AddPortalToNodes (splitportal, other_node, back);
2603 Mod_RecursiveNodePortals(front);
2604 Mod_RecursiveNodePortals(back);
2608 static void Mod_MakePortals(void)
2611 Mod_RecursiveNodePortals (loadmodel->nodes);
2612 Mod_FinalizePortals();
2615 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2618 int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2619 msurface_t *surf, *s;
2620 float *v0, *v1, *v2, *v3;
2621 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2622 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2623 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2625 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)
2627 if (surf->neighborsurfaces[vertnum])
2629 surf->neighborsurfaces[vertnum] = NULL;
2630 for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2632 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2633 || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2634 || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2637 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2638 if (s->neighborsurfaces[vnum] == surf)
2640 if (vnum < s->poly_numverts)
2642 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)
2644 if (s->neighborsurfaces[vnum] == NULL
2645 && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2646 || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2648 surf->neighborsurfaces[vertnum] = s;
2649 s->neighborsurfaces[vnum] = surf;
2653 if (vnum < s->poly_numverts)
2661 void Mod_BuildLightmapUpdateChains(mempool_t *mempool, model_t *model)
2663 int i, j, stylecounts[256], totalcount, remapstyles[256];
2665 memset(stylecounts, 0, sizeof(stylecounts));
2666 for (i = 0;i < model->nummodelsurfaces;i++)
2668 surf = model->surfaces + model->firstmodelsurface + i;
2669 for (j = 0;j < MAXLIGHTMAPS;j++)
2670 stylecounts[surf->styles[j]]++;
2673 model->light_styles = 0;
2674 for (i = 0;i < 255;i++)
2678 remapstyles[i] = model->light_styles++;
2679 totalcount += stylecounts[i] + 1;
2684 model->light_style = Mem_Alloc(mempool, model->light_styles * sizeof(qbyte));
2685 model->light_stylevalue = Mem_Alloc(mempool, model->light_styles * sizeof(int));
2686 model->light_styleupdatechains = Mem_Alloc(mempool, model->light_styles * sizeof(msurface_t **));
2687 model->light_styleupdatechainsbuffer = Mem_Alloc(mempool, totalcount * sizeof(msurface_t *));
2688 model->light_styles = 0;
2689 for (i = 0;i < 255;i++)
2691 model->light_style[model->light_styles++] = i;
2693 for (i = 0;i < model->light_styles;i++)
2695 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2696 j += stylecounts[model->light_style[i]] + 1;
2698 for (i = 0;i < model->nummodelsurfaces;i++)
2700 surf = model->surfaces + model->firstmodelsurface + i;
2701 for (j = 0;j < MAXLIGHTMAPS;j++)
2702 if (surf->styles[j] != 255)
2703 *model->light_styleupdatechains[remapstyles[surf->styles[j]]]++ = surf;
2706 for (i = 0;i < model->light_styles;i++)
2708 *model->light_styleupdatechains[i] = NULL;
2709 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2710 j += stylecounts[model->light_style[i]] + 1;
2714 void Mod_BuildPVSTextureChains(model_t *model)
2717 for (i = 0;i < model->numtextures;i++)
2718 model->pvstexturechainslength[i] = 0;
2719 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2721 if (model->surfacepvsframes[j] == model->pvsframecount)
2723 model->pvssurflist[model->pvssurflistlength++] = j;
2724 model->pvstexturechainslength[model->surfaces[j].texinfo->texture->number]++;
2727 for (i = 0, j = 0;i < model->numtextures;i++)
2729 if (model->pvstexturechainslength[i])
2731 model->pvstexturechains[i] = model->pvstexturechainsbuffer + j;
2732 j += model->pvstexturechainslength[i] + 1;
2735 model->pvstexturechains[i] = NULL;
2737 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2738 if (model->surfacepvsframes[j] == model->pvsframecount)
2739 *model->pvstexturechains[model->surfaces[j].texinfo->texture->number]++ = model->surfaces + j;
2740 for (i = 0;i < model->numtextures;i++)
2742 if (model->pvstexturechainslength[i])
2744 *model->pvstexturechains[i] = NULL;
2745 model->pvstexturechains[i] -= model->pvstexturechainslength[i];
2755 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2756 extern void R_Model_Brush_Draw(entity_render_t *ent);
2757 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2758 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);
2759 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2764 mempool_t *mainmempool;
2766 model_t *originalloadmodel;
2767 float dist, modelyawradius, modelradius, *vec;
2771 mod->type = mod_brush;
2773 header = (dheader_t *)buffer;
2775 i = LittleLong (header->version);
2776 if (i != BSPVERSION && i != 30)
2777 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2778 mod->ishlbsp = i == 30;
2779 if (loadmodel->isworldmodel)
2781 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2782 // until we get a texture for it...
2786 // swap all the lumps
2787 mod_base = (qbyte *)header;
2789 for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
2790 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2794 // store which lightmap format to use
2795 mod->lightmaprgba = r_lightmaprgba.integer;
2797 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2798 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2799 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2800 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2801 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2802 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2803 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2804 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2805 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2806 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2807 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2808 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2809 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2810 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2811 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2816 mod->numframes = 2; // regular and alternate animation
2818 mainmempool = mod->mempool;
2819 loadname = mod->name;
2821 Mod_LoadLightList ();
2822 originalloadmodel = loadmodel;
2825 // set up the submodels (FIXME: this is confusing)
2827 for (i = 0;i < mod->numsubmodels;i++)
2829 bm = &mod->submodels[i];
2831 mod->hulls[0].firstclipnode = bm->headnode[0];
2832 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2834 mod->hulls[j].firstclipnode = bm->headnode[j];
2835 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2838 mod->firstmodelsurface = bm->firstface;
2839 mod->nummodelsurfaces = bm->numfaces;
2841 // this gets altered below if sky is used
2842 mod->DrawSky = NULL;
2843 mod->Draw = R_Model_Brush_Draw;
2844 mod->DrawFakeShadow = NULL;
2845 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2846 mod->DrawLight = R_Model_Brush_DrawLight;
2847 mod->pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t **));
2848 mod->pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool, (mod->nummodelsurfaces + mod->numtextures) * sizeof(msurface_t *));
2849 mod->pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(int));
2850 Mod_BuildPVSTextureChains(mod);
2851 Mod_BuildLightmapUpdateChains(originalloadmodel->mempool, mod);
2852 if (mod->nummodelsurfaces)
2854 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2855 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2856 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2859 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2861 // we only need to have a drawsky function if it is used (usually only on world model)
2862 if (surf->texinfo->texture->shader == &Cshader_sky)
2863 mod->DrawSky = R_Model_Brush_DrawSky;
2864 // LordHavoc: submodels always clip, even if water
2865 if (mod->numsubmodels - 1)
2866 surf->flags |= SURF_SOLIDCLIP;
2867 // calculate bounding shapes
2868 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
2870 for (k = 0, vec = mesh->vertex3f;k < mesh->numverts;k++, vec += 3)
2872 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2873 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2874 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2875 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2876 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2877 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2878 dist = vec[0]*vec[0]+vec[1]*vec[1];
2879 if (modelyawradius < dist)
2880 modelyawradius = dist;
2881 dist += vec[2]*vec[2];
2882 if (modelradius < dist)
2887 modelyawradius = sqrt(modelyawradius);
2888 modelradius = sqrt(modelradius);
2889 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2890 mod->yawmins[2] = mod->normalmins[2];
2891 mod->yawmaxs[2] = mod->normalmaxs[2];
2892 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2893 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2894 mod->radius = modelradius;
2895 mod->radius2 = modelradius * modelradius;
2899 // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2900 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2902 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2904 mod->numleafs = bm->visleafs;
2906 // LordHavoc: only register submodels if it is the world
2907 // (prevents bsp models from replacing world submodels)
2908 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2911 // duplicate the basic information
2912 sprintf (name, "*%i", i+1);
2913 loadmodel = Mod_FindName (name);
2915 strcpy (loadmodel->name, name);
2916 // textures and memory belong to the main model
2917 loadmodel->texturepool = NULL;
2918 loadmodel->mempool = NULL;
2923 loadmodel = originalloadmodel;
2924 //Mod_ProcessLightList ();