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, *fogpixels;
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);
456 if (Image_CheckAlpha(pixels, image_width * image_height, true))
458 fogpixels = Mem_Alloc(tempmempool, image_width * image_height * 4);
459 for (j = 0;j < image_width * image_height * 4;j += 4)
461 fogpixels[j + 0] = 255;
462 fogpixels[j + 1] = 255;
463 fogpixels[j + 2] = 255;
464 fogpixels[j + 3] = pixels[j + 3];
466 tx->skin.fog = R_LoadTexture2D(loadmodel->texturepool, tx->name, image_width, image_height, pixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
471 Mem_Free(freepixels);
473 else if (mtdata) // texture included
474 Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_PRECACHE, false, true, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height);
477 if (tx->skin.base == NULL)
482 tx->skin.base = r_notexture;
485 if (tx->name[0] == '*')
487 // turb does not block movement
488 tx->flags &= ~SURF_SOLIDCLIP;
489 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
490 // LordHavoc: some turbulent textures should be fullbright and solid
491 if (!strncmp(tx->name,"*lava",5)
492 || !strncmp(tx->name,"*teleport",9)
493 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
494 tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
496 tx->flags |= SURF_WATERALPHA;
497 tx->shader = &Cshader_water;
499 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
501 tx->flags |= SURF_DRAWSKY;
502 tx->shader = &Cshader_sky;
506 tx->flags |= SURF_LIGHTMAP;
508 tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT;
509 tx->shader = &Cshader_wall_lightmap;
512 // start out with no animation
513 tx->currentframe = tx;
516 // sequence the animations
517 for (i = 0;i < m->nummiptex;i++)
519 tx = loadmodel->textures + i;
520 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
522 if (tx->anim_total[0] || tx->anim_total[1])
523 continue; // already sequenced
525 // find the number of frames in the animation
526 memset (anims, 0, sizeof(anims));
527 memset (altanims, 0, sizeof(altanims));
529 for (j = i;j < m->nummiptex;j++)
531 tx2 = loadmodel->textures + j;
532 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
536 if (num >= '0' && num <= '9')
537 anims[num - '0'] = tx2;
538 else if (num >= 'a' && num <= 'j')
539 altanims[num - 'a'] = tx2;
541 Con_Printf ("Bad animating texture %s\n", tx->name);
545 for (j = 0;j < 10;j++)
552 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
555 for (j = 0;j < max;j++)
559 Con_Printf ("Missing frame %i of %s\n", j, tx->name);
563 for (j = 0;j < altmax;j++)
567 Con_Printf ("Missing altframe %i of %s\n", j, tx->name);
576 // if there is no alternate animation, duplicate the primary
577 // animation into the alternate
579 for (k = 0;k < 10;k++)
580 altanims[k] = anims[k];
583 // link together the primary animation
584 for (j = 0;j < max;j++)
587 tx2->animated = true;
588 tx2->anim_total[0] = max;
589 tx2->anim_total[1] = altmax;
590 for (k = 0;k < 10;k++)
592 tx2->anim_frames[0][k] = anims[k];
593 tx2->anim_frames[1][k] = altanims[k];
597 // if there really is an alternate anim...
598 if (anims[0] != altanims[0])
600 // link together the alternate animation
601 for (j = 0;j < altmax;j++)
604 tx2->animated = true;
605 // the primary/alternate are reversed here
606 tx2->anim_total[0] = altmax;
607 tx2->anim_total[1] = max;
608 for (k = 0;k < 10;k++)
610 tx2->anim_frames[0][k] = altanims[k];
611 tx2->anim_frames[1][k] = anims[k];
623 static void Mod_LoadLighting (lump_t *l)
626 qbyte *in, *out, *data, d;
627 char litfilename[1024];
628 loadmodel->lightdata = NULL;
629 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
631 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
632 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
634 else // LordHavoc: bsp version 29 (normal white lighting)
636 // LordHavoc: hope is not lost yet, check for a .lit file to load
637 strcpy(litfilename, loadmodel->name);
638 FS_StripExtension(litfilename, litfilename);
639 strcat(litfilename, ".lit");
640 data = (qbyte*) FS_LoadFile (litfilename, false);
643 if (fs_filesize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
645 i = LittleLong(((int *)data)[1]);
648 Con_DPrintf("loaded %s\n", litfilename);
649 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, fs_filesize - 8);
650 memcpy(loadmodel->lightdata, data + 8, fs_filesize - 8);
656 Con_Printf("Unknown .lit file version (%d)\n", i);
662 if (fs_filesize == 8)
663 Con_Printf("Empty .lit file, ignoring\n");
665 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
669 // LordHavoc: oh well, expand the white lighting data
672 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
673 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
674 out = loadmodel->lightdata;
675 memcpy (in, mod_base + l->fileofs, l->filelen);
676 for (i = 0;i < l->filelen;i++)
686 void Mod_LoadLightList(void)
689 char lightsfilename[1024], *s, *t, *lightsstring;
692 strcpy(lightsfilename, loadmodel->name);
693 FS_StripExtension(lightsfilename, lightsfilename);
694 strcat(lightsfilename, ".lights");
695 s = lightsstring = (char *) FS_LoadFile (lightsfilename, false);
701 while (*s && *s != '\n')
705 Mem_Free(lightsstring);
706 Host_Error("lights file must end with a newline\n");
711 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
714 while (*s && n < numlights)
717 while (*s && *s != '\n')
721 Mem_Free(lightsstring);
722 Host_Error("misparsed lights file!\n");
724 e = loadmodel->lights + n;
726 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);
730 Mem_Free(lightsstring);
731 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);
738 Mem_Free(lightsstring);
739 Host_Error("misparsed lights file!\n");
741 loadmodel->numlights = numlights;
742 Mem_Free(lightsstring);
747 static int castshadowcount = 0;
748 void Mod_ProcessLightList(void)
750 int j, k, l, *mark, lnum;
758 for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++)
760 e->cullradius2 = DotProduct(e->light, e->light) / (e->falloff * e->falloff * 8192.0f * 8192.0f * 2.0f * 2.0f);// + 4096.0f;
761 if (e->cullradius2 > 4096.0f * 4096.0f)
762 e->cullradius2 = 4096.0f * 4096.0f;
763 e->cullradius = e->lightradius = sqrt(e->cullradius2);
764 leaf = Mod_PointInLeaf(e->origin, loadmodel);
765 if (leaf->compressed_vis)
766 pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel);
769 for (j = 0;j < loadmodel->numsurfaces;j++)
770 loadmodel->surfacevisframes[j] = -1;
771 for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++)
773 if (pvs[j >> 3] & (1 << (j & 7)))
775 for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++)
777 surf = loadmodel->surfaces + *mark;
778 if (surf->number != *mark)
779 Con_Printf("%d != %d\n", surf->number, *mark);
780 dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
781 if (surf->flags & SURF_PLANEBACK)
783 if (dist > 0 && dist < e->cullradius)
785 temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
786 temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
787 temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
788 if (DotProduct(temp, temp) < lightradius2)
789 loadmodel->surfacevisframes[*mark] = -2;
794 // build list of light receiving surfaces
796 for (j = 0;j < loadmodel->numsurfaces;j++)
797 if (loadmodel->surfacevisframes[j] == -2)
800 if (e->numsurfaces > 0)
802 e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
804 for (j = 0;j < loadmodel->numsurfaces;j++)
805 if (loadmodel->surfacevisframes[j] == -2)
806 e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j;
808 // find bounding box and sphere of lit surfaces
809 // (these will be used for creating a shape to clip the light)
811 for (j = 0;j < e->numsurfaces;j++)
813 surf = e->surfaces[j];
816 VectorCopy(surf->poly_verts, e->mins);
817 VectorCopy(surf->poly_verts, e->maxs);
819 for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
821 if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
822 if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
823 if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
824 VectorSubtract(v, e->origin, temp);
825 dist = DotProduct(temp, temp);
830 if (e->cullradius2 > radius2)
832 e->cullradius2 = radius2;
833 e->cullradius = sqrt(e->cullradius2);
835 if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
836 if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
837 if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
838 if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
839 if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
840 if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
841 // clip shadow volumes against eachother to remove unnecessary
842 // polygons (and sections of polygons)
844 //vec3_t polymins, polymaxs;
846 float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
847 float f, *v0, *v1, projectdistance;
849 e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024);
852 vec3_t outermins, outermaxs, innermins, innermaxs;
853 innermins[0] = e->mins[0] - 1;
854 innermins[1] = e->mins[1] - 1;
855 innermins[2] = e->mins[2] - 1;
856 innermaxs[0] = e->maxs[0] + 1;
857 innermaxs[1] = e->maxs[1] + 1;
858 innermaxs[2] = e->maxs[2] + 1;
859 outermins[0] = loadmodel->normalmins[0] - 1;
860 outermins[1] = loadmodel->normalmins[1] - 1;
861 outermins[2] = loadmodel->normalmins[2] - 1;
862 outermaxs[0] = loadmodel->normalmaxs[0] + 1;
863 outermaxs[1] = loadmodel->normalmaxs[1] + 1;
864 outermaxs[2] = loadmodel->normalmaxs[2] + 1;
865 // add bounding box around the whole shadow volume set,
866 // facing inward to limit light area, with an outer bounding box
867 // facing outward (this is needed by the shadow rendering method)
869 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
870 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
871 verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
872 verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
873 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
874 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
875 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
876 verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
877 verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
878 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
880 verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
881 verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
882 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
883 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
884 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
885 verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
886 verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
887 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
888 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
889 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
891 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
892 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
893 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
894 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
895 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
896 verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
897 verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
898 verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
899 verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
900 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
902 verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
903 verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
904 verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
905 verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
906 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
907 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
908 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
909 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
910 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
911 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
913 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
914 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2];
915 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2];
916 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
917 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
918 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
919 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2];
920 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2];
921 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
922 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
924 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2];
925 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
926 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
927 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2];
928 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
929 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2];
930 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
931 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
932 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2];
933 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
937 for (j = 0;j < e->numsurfaces;j++)
939 surf = e->surfaces[j];
940 if (surf->flags & SURF_SHADOWCAST)
941 surf->castshadow = castshadowcount;
943 for (j = 0;j < e->numsurfaces;j++)
945 surf = e->surfaces[j];
946 if (surf->castshadow != castshadowcount)
948 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
949 if (surf->flags & SURF_PLANEBACK)
951 projectdistance = e->lightradius;
952 if (maxverts < surf->poly_numverts)
954 maxverts = surf->poly_numverts;
957 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
959 // copy the original polygon, for the front cap of the volume
960 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
962 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
963 // project the original polygon, reversed, for the back cap of the volume
964 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
966 VectorSubtract(v0, e->origin, temp);
967 VectorNormalize(temp);
968 VectorMA(v0, projectdistance, temp, v1);
970 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
971 // project the shadow volume sides
972 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)
974 if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount)
976 VectorCopy(v1, &verts[0]);
977 VectorCopy(v0, &verts[3]);
978 VectorCopy(v0, &verts[6]);
979 VectorCopy(v1, &verts[9]);
980 VectorSubtract(&verts[6], e->origin, temp);
981 VectorNormalize(temp);
982 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
983 VectorSubtract(&verts[9], e->origin, temp);
984 VectorNormalize(temp);
985 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
986 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
990 // build the triangle mesh
991 e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume);
995 for (mesh = e->shadowvolume;mesh;mesh = mesh->next)
996 l += mesh->numtriangles;
997 Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l);
1010 static void Mod_LoadVisibility (lump_t *l)
1012 loadmodel->visdata = NULL;
1015 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
1016 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
1019 // used only for HalfLife maps
1020 void Mod_ParseWadsFromEntityLump(const char *data)
1022 char key[128], value[4096];
1027 if (!COM_ParseToken(&data))
1029 if (com_token[0] != '{')
1033 if (!COM_ParseToken(&data))
1035 if (com_token[0] == '}')
1036 break; // end of worldspawn
1037 if (com_token[0] == '_')
1038 strcpy(key, com_token + 1);
1040 strcpy(key, com_token);
1041 while (key[strlen(key)-1] == ' ') // remove trailing spaces
1042 key[strlen(key)-1] = 0;
1043 if (!COM_ParseToken(&data))
1045 strcpy(value, com_token);
1046 if (!strcmp("wad", key)) // for HalfLife maps
1048 if (loadmodel->ishlbsp)
1051 for (i = 0;i < 4096;i++)
1052 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
1058 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
1059 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
1061 else if (value[i] == ';' || value[i] == 0)
1065 strcpy(wadname, "textures/");
1066 strcat(wadname, &value[j]);
1067 W_LoadTextureWadFile (wadname, false);
1084 static void Mod_LoadEntities (lump_t *l)
1086 loadmodel->entities = NULL;
1089 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
1090 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
1091 if (loadmodel->ishlbsp)
1092 Mod_ParseWadsFromEntityLump(loadmodel->entities);
1101 static void Mod_LoadVertexes (lump_t *l)
1107 in = (void *)(mod_base + l->fileofs);
1108 if (l->filelen % sizeof(*in))
1109 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1110 count = l->filelen / sizeof(*in);
1111 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1113 loadmodel->vertexes = out;
1114 loadmodel->numvertexes = count;
1116 for ( i=0 ; i<count ; i++, in++, out++)
1118 out->position[0] = LittleFloat (in->point[0]);
1119 out->position[1] = LittleFloat (in->point[1]);
1120 out->position[2] = LittleFloat (in->point[2]);
1129 static void Mod_LoadSubmodels (lump_t *l)
1135 in = (void *)(mod_base + l->fileofs);
1136 if (l->filelen % sizeof(*in))
1137 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1138 count = l->filelen / sizeof(*in);
1139 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1141 loadmodel->submodels = out;
1142 loadmodel->numsubmodels = count;
1144 for ( i=0 ; i<count ; i++, in++, out++)
1146 for (j=0 ; j<3 ; j++)
1148 // spread the mins / maxs by a pixel
1149 out->mins[j] = LittleFloat (in->mins[j]) - 1;
1150 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
1151 out->origin[j] = LittleFloat (in->origin[j]);
1153 for (j=0 ; j<MAX_MAP_HULLS ; j++)
1154 out->headnode[j] = LittleLong (in->headnode[j]);
1155 out->visleafs = LittleLong (in->visleafs);
1156 out->firstface = LittleLong (in->firstface);
1157 out->numfaces = LittleLong (in->numfaces);
1166 static void Mod_LoadEdges (lump_t *l)
1172 in = (void *)(mod_base + l->fileofs);
1173 if (l->filelen % sizeof(*in))
1174 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1175 count = l->filelen / sizeof(*in);
1176 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1178 loadmodel->edges = out;
1179 loadmodel->numedges = count;
1181 for ( i=0 ; i<count ; i++, in++, out++)
1183 out->v[0] = (unsigned short)LittleShort(in->v[0]);
1184 out->v[1] = (unsigned short)LittleShort(in->v[1]);
1193 static void Mod_LoadTexinfo (lump_t *l)
1197 int i, j, k, count, miptex;
1199 in = (void *)(mod_base + l->fileofs);
1200 if (l->filelen % sizeof(*in))
1201 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1202 count = l->filelen / sizeof(*in);
1203 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1205 loadmodel->texinfo = out;
1206 loadmodel->numtexinfo = count;
1208 for (i = 0;i < count;i++, in++, out++)
1210 for (k = 0;k < 2;k++)
1211 for (j = 0;j < 4;j++)
1212 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
1214 miptex = LittleLong (in->miptex);
1215 out->flags = LittleLong (in->flags);
1217 out->texture = NULL;
1218 if (loadmodel->textures)
1220 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
1221 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
1223 out->texture = loadmodel->textures + miptex;
1225 if (out->flags & TEX_SPECIAL)
1227 // if texture chosen is NULL or the shader needs a lightmap,
1228 // force to notexture water shader
1229 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
1230 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
1234 // if texture chosen is NULL, force to notexture
1235 if (out->texture == NULL)
1236 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
1241 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1246 mins[0] = mins[1] = mins[2] = 9999;
1247 maxs[0] = maxs[1] = maxs[2] = -9999;
1249 for (i = 0;i < numverts;i++)
1251 for (j = 0;j < 3;j++, v++)
1262 #define MAX_SUBDIVPOLYTRIANGLES 4096
1263 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1265 static int subdivpolyverts, subdivpolytriangles;
1266 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1267 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1269 static int subdivpolylookupvert(vec3_t v)
1272 for (i = 0;i < subdivpolyverts;i++)
1273 if (subdivpolyvert[i][0] == v[0]
1274 && subdivpolyvert[i][1] == v[1]
1275 && subdivpolyvert[i][2] == v[2])
1277 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1278 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1279 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1280 return subdivpolyverts++;
1283 static void SubdividePolygon (int numverts, float *verts)
1285 int i, i1, i2, i3, f, b, c, p;
1286 vec3_t mins, maxs, front[256], back[256];
1287 float m, *pv, *cv, dist[256], frac;
1290 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1292 BoundPoly (numverts, verts, mins, maxs);
1294 for (i = 0;i < 3;i++)
1296 m = (mins[i] + maxs[i]) * 0.5;
1297 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1298 if (maxs[i] - m < 8)
1300 if (m - mins[i] < 8)
1304 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1305 dist[c] = cv[i] - m;
1308 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1312 VectorCopy (pv, front[f]);
1317 VectorCopy (pv, back[b]);
1320 if (dist[p] == 0 || dist[c] == 0)
1322 if ( (dist[p] > 0) != (dist[c] > 0) )
1325 frac = dist[p] / (dist[p] - dist[c]);
1326 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1327 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1328 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1334 SubdividePolygon (f, front[0]);
1335 SubdividePolygon (b, back[0]);
1339 i1 = subdivpolylookupvert(verts);
1340 i2 = subdivpolylookupvert(verts + 3);
1341 for (i = 2;i < numverts;i++)
1343 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1345 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1349 i3 = subdivpolylookupvert(verts + i * 3);
1350 subdivpolyindex[subdivpolytriangles][0] = i1;
1351 subdivpolyindex[subdivpolytriangles][1] = i2;
1352 subdivpolyindex[subdivpolytriangles][2] = i3;
1354 subdivpolytriangles++;
1360 Mod_GenerateWarpMesh
1362 Breaks a polygon up along axial 64 unit
1363 boundaries so that turbulent and sky warps
1364 can be done reasonably.
1367 void Mod_GenerateWarpMesh (msurface_t *surf)
1373 subdivpolytriangles = 0;
1374 subdivpolyverts = 0;
1375 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1376 if (subdivpolytriangles < 1)
1377 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1379 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1380 mesh->numverts = subdivpolyverts;
1381 mesh->numtriangles = subdivpolytriangles;
1382 mesh->vertex = (surfvertex_t *)(mesh + 1);
1383 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1384 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1386 for (i = 0;i < mesh->numtriangles;i++)
1387 for (j = 0;j < 3;j++)
1388 mesh->index[i*3+j] = subdivpolyindex[i][j];
1390 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1392 VectorCopy(subdivpolyvert[i], v->v);
1393 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1394 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1399 surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles)
1402 mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (3 + 2 + 2 + 2 + 3 + 3 + 3 + 1) * sizeof(float));
1403 mesh->numverts = numverts;
1404 mesh->numtriangles = numtriangles;
1405 mesh->vertex3f = (float *)(mesh + 1);
1406 mesh->texcoordtexture2f = mesh->vertex3f + mesh->numverts * 3;
1407 mesh->texcoordlightmap2f = mesh->texcoordtexture2f + mesh->numverts * 2;
1408 mesh->texcoorddetail2f = mesh->texcoordlightmap2f + mesh->numverts * 2;
1409 mesh->svector3f = (float *)(mesh->texcoorddetail2f + mesh->numverts * 2);
1410 mesh->tvector3f = mesh->svector3f + mesh->numverts * 3;
1411 mesh->normal3f = mesh->tvector3f + mesh->numverts * 3;
1412 mesh->lightmapoffsets = (int *)(mesh->normal3f + mesh->numverts * 3);
1413 mesh->element3i = mesh->lightmapoffsets + mesh->numverts;
1414 mesh->neighbor3i = mesh->element3i + mesh->numtriangles * 3;
1418 void Mod_GenerateSurfacePolygon (msurface_t *surf, int firstedge, int numedges)
1421 float *vec, *vert, mins[3], maxs[3], val, *v;
1424 // convert edges back to a normal polygon
1425 surf->poly_numverts = numedges;
1426 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * numedges);
1427 for (i = 0;i < numedges;i++)
1429 lindex = loadmodel->surfedges[firstedge + i];
1431 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1433 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1434 VectorCopy (vec, vert);
1438 // calculate polygon bounding box and center
1439 vert = surf->poly_verts;
1440 VectorCopy(vert, mins);
1441 VectorCopy(vert, maxs);
1443 for (i = 1;i < surf->poly_numverts;i++, vert += 3)
1445 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1446 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1447 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1449 VectorCopy(mins, surf->poly_mins);
1450 VectorCopy(maxs, surf->poly_maxs);
1451 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1452 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1453 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1455 // generate surface extents information
1456 tex = surf->texinfo;
1457 mins[0] = maxs[0] = DotProduct(surf->poly_verts, tex->vecs[0]) + tex->vecs[0][3];
1458 mins[1] = maxs[1] = DotProduct(surf->poly_verts, tex->vecs[1]) + tex->vecs[1][3];
1459 for (i = 1, v = surf->poly_verts + 3;i < surf->poly_numverts;i++, v += 3)
1461 for (j = 0;j < 2;j++)
1463 val = DotProduct(v, tex->vecs[j]) + tex->vecs[j][3];
1470 for (i = 0;i < 2;i++)
1472 surf->texturemins[i] = (int) floor(mins[i] / 16) * 16;
1473 surf->extents[i] = (int) ceil(maxs[i] / 16) * 16 - surf->texturemins[i];
1482 static void Mod_LoadFaces (lump_t *l)
1486 int i, count, surfnum, planenum, ssize, tsize, firstedge, numedges, totalverts, totaltris, totalmeshes;
1490 in = (void *)(mod_base + l->fileofs);
1491 if (l->filelen % sizeof(*in))
1492 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1493 count = l->filelen / sizeof(*in);
1494 loadmodel->surfaces = Mem_Alloc(loadmodel->mempool, count*sizeof(msurface_t));
1496 loadmodel->numsurfaces = count;
1497 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1498 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1499 loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1501 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++)
1503 surf->number = surfnum;
1504 // FIXME: validate edges, texinfo, etc?
1505 firstedge = LittleLong(in->firstedge);
1506 numedges = LittleShort(in->numedges);
1507 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)
1508 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->numsurfedges);
1509 i = LittleShort (in->texinfo);
1510 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1511 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1512 surf->texinfo = loadmodel->texinfo + i;
1513 surf->flags = surf->texinfo->texture->flags;
1515 planenum = LittleShort(in->planenum);
1516 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1517 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1519 if (LittleShort(in->side))
1520 surf->flags |= SURF_PLANEBACK;
1522 surf->plane = loadmodel->planes + planenum;
1524 // clear lightmap (filled in later)
1525 surf->lightmaptexture = NULL;
1527 // force lightmap upload on first time seeing the surface
1528 surf->cached_dlight = true;
1530 Mod_GenerateSurfacePolygon(surf, firstedge, numedges);
1532 ssize = (surf->extents[0] >> 4) + 1;
1533 tsize = (surf->extents[1] >> 4) + 1;
1536 for (i = 0;i < MAXLIGHTMAPS;i++)
1537 surf->styles[i] = in->styles[i];
1538 i = LittleLong(in->lightofs);
1540 surf->samples = NULL;
1541 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1542 surf->samples = loadmodel->lightdata + i;
1543 else // LordHavoc: white lighting (bsp version 29)
1544 surf->samples = loadmodel->lightdata + (i * 3);
1546 if (surf->texinfo->texture->shader == &Cshader_wall_lightmap)
1548 if ((surf->extents[0] >> 4) + 1 > (256) || (surf->extents[1] >> 4) + 1 > (256))
1549 Host_Error ("Bad surface extents");
1550 // stainmap for permanent marks on walls
1551 surf->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1553 memset(surf->stainsamples, 255, ssize * tsize * 3);
1557 loadmodel->entiremesh = Mod_AllocSurfMesh(totalverts, totaltris);
1558 loadmodel->surfmeshes = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) * totalmeshes);
1560 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++)
1562 mesh = surf->mesh = loadmodel->surfmeshes + totalmeshes;
1563 mesh->numverts = surf->poly_numverts;
1564 mesh->numtriangles = surf->poly_numverts - 2;
1565 mesh->vertex3f = loadmodel->entiremesh->vertex3f + totalverts * 3;
1566 mesh->texcoordtexture2f = loadmodel->entiremesh->texcoordtexture2f + totalverts * 2;
1567 mesh->texcoordlightmap2f = loadmodel->entiremesh->texcoordlightmap2f + totalverts * 2;
1568 mesh->texcoorddetail2f = loadmodel->entiremesh->texcoorddetail2f + totalverts * 2;
1569 mesh->svector3f = loadmodel->entiremesh->svector3f + totalverts * 3;
1570 mesh->tvector3f = loadmodel->entiremesh->tvector3f + totalverts * 3;
1571 mesh->normal3f = loadmodel->entiremesh->normal3f + totalverts * 3;
1572 mesh->lightmapoffsets = loadmodel->entiremesh->lightmapoffsets + totalverts;
1573 mesh->element3i = loadmodel->entiremesh->element3i + totaltris * 3;
1574 mesh->neighbor3i = loadmodel->entiremesh->neighbor3i + totaltris * 3;
1576 surf->lightmaptexturestride = 0;
1577 surf->lightmaptexture = NULL;
1579 for (i = 0;i < mesh->numverts;i++)
1581 mesh->vertex3f[i * 3 + 0] = surf->poly_verts[i * 3 + 0];
1582 mesh->vertex3f[i * 3 + 1] = surf->poly_verts[i * 3 + 1];
1583 mesh->vertex3f[i * 3 + 2] = surf->poly_verts[i * 3 + 2];
1584 s = DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1585 t = DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1586 mesh->texcoordtexture2f[i * 2 + 0] = s / surf->texinfo->texture->width;
1587 mesh->texcoordtexture2f[i * 2 + 1] = t / surf->texinfo->texture->height;
1588 mesh->texcoorddetail2f[i * 2 + 0] = s * (1.0f / 16.0f);
1589 mesh->texcoorddetail2f[i * 2 + 1] = t * (1.0f / 16.0f);
1590 mesh->texcoordlightmap2f[i * 2 + 0] = 0;
1591 mesh->texcoordlightmap2f[i * 2 + 1] = 0;
1592 mesh->lightmapoffsets[i] = 0;
1595 for (i = 0;i < mesh->numtriangles;i++)
1597 mesh->element3i[i * 3 + 0] = 0;
1598 mesh->element3i[i * 3 + 1] = i + 1;
1599 mesh->element3i[i * 3 + 2] = i + 2;
1602 Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1603 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->vertex3f, mesh->texcoordtexture2f, mesh->element3i, mesh->svector3f, mesh->tvector3f, mesh->normal3f);
1605 if (surf->texinfo->texture->shader == &Cshader_wall_lightmap)
1607 int i, iu, iv, smax, tmax;
1608 float u, v, ubase, vbase, uscale, vscale;
1610 smax = surf->extents[0] >> 4;
1611 tmax = surf->extents[1] >> 4;
1613 surf->flags |= SURF_LIGHTMAP;
1614 if (r_miplightmaps.integer)
1616 surf->lightmaptexturestride = smax+1;
1617 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);
1621 surf->lightmaptexturestride = R_CompatibleFragmentWidth(smax+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1622 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);
1624 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1625 uscale = (uscale - ubase) / (smax + 1);
1626 vscale = (vscale - vbase) / (tmax + 1);
1628 for (i = 0;i < mesh->numverts;i++)
1630 u = ((DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1631 v = ((DotProduct ((mesh->vertex3f + i * 3), surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1632 mesh->texcoordlightmap2f[i * 2 + 0] = u * uscale + ubase;
1633 mesh->texcoordlightmap2f[i * 2 + 1] = v * vscale + vbase;
1634 // LordHavoc: calc lightmap data offset for vertex lighting to use
1637 mesh->lightmapoffsets[i] = (bound(0, iv, tmax) * (smax+1) + bound(0, iu, smax)) * 3;
1648 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1650 node->parent = parent;
1651 if (node->contents < 0)
1653 Mod_SetParent (node->children[0], node);
1654 Mod_SetParent (node->children[1], node);
1662 static void Mod_LoadNodes (lump_t *l)
1668 in = (void *)(mod_base + l->fileofs);
1669 if (l->filelen % sizeof(*in))
1670 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1671 count = l->filelen / sizeof(*in);
1672 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1674 loadmodel->nodes = out;
1675 loadmodel->numnodes = count;
1677 for ( i=0 ; i<count ; i++, in++, out++)
1679 for (j=0 ; j<3 ; j++)
1681 out->mins[j] = LittleShort (in->mins[j]);
1682 out->maxs[j] = LittleShort (in->maxs[j]);
1685 p = LittleLong(in->planenum);
1686 out->plane = loadmodel->planes + p;
1688 out->firstsurface = LittleShort (in->firstface);
1689 out->numsurfaces = LittleShort (in->numfaces);
1691 for (j=0 ; j<2 ; j++)
1693 p = LittleShort (in->children[j]);
1695 out->children[j] = loadmodel->nodes + p;
1697 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1701 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1709 static void Mod_LoadLeafs (lump_t *l)
1715 in = (void *)(mod_base + l->fileofs);
1716 if (l->filelen % sizeof(*in))
1717 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1718 count = l->filelen / sizeof(*in);
1719 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1721 loadmodel->leafs = out;
1722 loadmodel->numleafs = count;
1724 for ( i=0 ; i<count ; i++, in++, out++)
1726 for (j=0 ; j<3 ; j++)
1728 out->mins[j] = LittleShort (in->mins[j]);
1729 out->maxs[j] = LittleShort (in->maxs[j]);
1732 p = LittleLong(in->contents);
1735 out->firstmarksurface = loadmodel->marksurfaces +
1736 LittleShort(in->firstmarksurface);
1737 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1739 p = LittleLong(in->visofs);
1741 out->compressed_vis = NULL;
1743 out->compressed_vis = loadmodel->visdata + p;
1745 for (j=0 ; j<4 ; j++)
1746 out->ambient_sound_level[j] = in->ambient_level[j];
1748 // FIXME: Insert caustics here
1757 static void Mod_LoadClipnodes (lump_t *l)
1759 dclipnode_t *in, *out;
1763 in = (void *)(mod_base + l->fileofs);
1764 if (l->filelen % sizeof(*in))
1765 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1766 count = l->filelen / sizeof(*in);
1767 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1769 loadmodel->clipnodes = out;
1770 loadmodel->numclipnodes = count;
1772 if (loadmodel->ishlbsp)
1774 hull = &loadmodel->hulls[1];
1775 hull->clipnodes = out;
1776 hull->firstclipnode = 0;
1777 hull->lastclipnode = count-1;
1778 hull->planes = loadmodel->planes;
1779 hull->clip_mins[0] = -16;
1780 hull->clip_mins[1] = -16;
1781 hull->clip_mins[2] = -36;
1782 hull->clip_maxs[0] = 16;
1783 hull->clip_maxs[1] = 16;
1784 hull->clip_maxs[2] = 36;
1785 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1787 hull = &loadmodel->hulls[2];
1788 hull->clipnodes = out;
1789 hull->firstclipnode = 0;
1790 hull->lastclipnode = count-1;
1791 hull->planes = loadmodel->planes;
1792 hull->clip_mins[0] = -32;
1793 hull->clip_mins[1] = -32;
1794 hull->clip_mins[2] = -32;
1795 hull->clip_maxs[0] = 32;
1796 hull->clip_maxs[1] = 32;
1797 hull->clip_maxs[2] = 32;
1798 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1800 hull = &loadmodel->hulls[3];
1801 hull->clipnodes = out;
1802 hull->firstclipnode = 0;
1803 hull->lastclipnode = count-1;
1804 hull->planes = loadmodel->planes;
1805 hull->clip_mins[0] = -16;
1806 hull->clip_mins[1] = -16;
1807 hull->clip_mins[2] = -18;
1808 hull->clip_maxs[0] = 16;
1809 hull->clip_maxs[1] = 16;
1810 hull->clip_maxs[2] = 18;
1811 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1815 hull = &loadmodel->hulls[1];
1816 hull->clipnodes = out;
1817 hull->firstclipnode = 0;
1818 hull->lastclipnode = count-1;
1819 hull->planes = loadmodel->planes;
1820 hull->clip_mins[0] = -16;
1821 hull->clip_mins[1] = -16;
1822 hull->clip_mins[2] = -24;
1823 hull->clip_maxs[0] = 16;
1824 hull->clip_maxs[1] = 16;
1825 hull->clip_maxs[2] = 32;
1826 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1828 hull = &loadmodel->hulls[2];
1829 hull->clipnodes = out;
1830 hull->firstclipnode = 0;
1831 hull->lastclipnode = count-1;
1832 hull->planes = loadmodel->planes;
1833 hull->clip_mins[0] = -32;
1834 hull->clip_mins[1] = -32;
1835 hull->clip_mins[2] = -24;
1836 hull->clip_maxs[0] = 32;
1837 hull->clip_maxs[1] = 32;
1838 hull->clip_maxs[2] = 64;
1839 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1842 for (i=0 ; i<count ; i++, out++, in++)
1844 out->planenum = LittleLong(in->planenum);
1845 out->children[0] = LittleShort(in->children[0]);
1846 out->children[1] = LittleShort(in->children[1]);
1847 if (out->children[0] >= count || out->children[1] >= count)
1848 Host_Error("Corrupt clipping hull (out of range child)\n");
1856 Duplicate the drawing hull structure as a clipping hull
1859 static void Mod_MakeHull0 (void)
1866 hull = &loadmodel->hulls[0];
1868 in = loadmodel->nodes;
1869 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1871 hull->clipnodes = out;
1872 hull->firstclipnode = 0;
1873 hull->lastclipnode = loadmodel->numnodes - 1;
1874 hull->planes = loadmodel->planes;
1876 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1878 out->planenum = in->plane - loadmodel->planes;
1879 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1880 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1886 Mod_LoadMarksurfaces
1889 static void Mod_LoadMarksurfaces (lump_t *l)
1894 in = (void *)(mod_base + l->fileofs);
1895 if (l->filelen % sizeof(*in))
1896 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1897 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1898 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1900 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1902 j = (unsigned) LittleShort(in[i]);
1903 if (j >= loadmodel->numsurfaces)
1904 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1905 loadmodel->marksurfaces[i] = j;
1914 static void Mod_LoadSurfedges (lump_t *l)
1919 in = (void *)(mod_base + l->fileofs);
1920 if (l->filelen % sizeof(*in))
1921 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1922 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1923 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1925 for (i = 0;i < loadmodel->numsurfedges;i++)
1926 loadmodel->surfedges[i] = LittleLong (in[i]);
1935 static void Mod_LoadPlanes (lump_t *l)
1941 in = (void *)(mod_base + l->fileofs);
1942 if (l->filelen % sizeof(*in))
1943 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1945 loadmodel->numplanes = l->filelen / sizeof(*in);
1946 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1948 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1950 out->normal[0] = LittleFloat (in->normal[0]);
1951 out->normal[1] = LittleFloat (in->normal[1]);
1952 out->normal[2] = LittleFloat (in->normal[2]);
1953 out->dist = LittleFloat (in->dist);
1959 #define MAX_POINTS_ON_WINDING 64
1965 double points[8][3]; // variable sized
1974 static winding_t *NewWinding (int points)
1979 if (points > MAX_POINTS_ON_WINDING)
1980 Sys_Error("NewWinding: too many points\n");
1982 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
1983 w = Mem_Alloc(loadmodel->mempool, size);
1984 memset (w, 0, size);
1989 static void FreeWinding (winding_t *w)
1999 static winding_t *BaseWindingForPlane (mplane_t *p)
2001 double org[3], vright[3], vup[3], normal[3];
2004 VectorCopy(p->normal, normal);
2005 VectorVectorsDouble(normal, vright, vup);
2007 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
2008 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
2010 // project a really big axis aligned box onto the plane
2013 VectorScale (p->normal, p->dist, org);
2015 VectorSubtract (org, vright, w->points[0]);
2016 VectorAdd (w->points[0], vup, w->points[0]);
2018 VectorAdd (org, vright, w->points[1]);
2019 VectorAdd (w->points[1], vup, w->points[1]);
2021 VectorAdd (org, vright, w->points[2]);
2022 VectorSubtract (w->points[2], vup, w->points[2]);
2024 VectorSubtract (org, vright, w->points[3]);
2025 VectorSubtract (w->points[3], vup, w->points[3]);
2036 Clips the winding to the plane, returning the new winding on the positive side
2037 Frees the input winding.
2038 If keepon is true, an exactly on-plane winding will be saved, otherwise
2039 it will be clipped away.
2042 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
2044 double dists[MAX_POINTS_ON_WINDING + 1];
2045 int sides[MAX_POINTS_ON_WINDING + 1];
2054 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2056 // determine sides for each point
2057 for (i = 0;i < in->numpoints;i++)
2059 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
2060 if (dot > ON_EPSILON)
2061 sides[i] = SIDE_FRONT;
2062 else if (dot < -ON_EPSILON)
2063 sides[i] = SIDE_BACK;
2068 sides[i] = sides[0];
2069 dists[i] = dists[0];
2071 if (keepon && !counts[0] && !counts[1])
2082 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2083 if (maxpts > MAX_POINTS_ON_WINDING)
2084 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2086 neww = NewWinding (maxpts);
2088 for (i = 0;i < in->numpoints;i++)
2090 if (neww->numpoints >= maxpts)
2091 Sys_Error ("ClipWinding: points exceeded estimate");
2095 if (sides[i] == SIDE_ON)
2097 VectorCopy (p1, neww->points[neww->numpoints]);
2102 if (sides[i] == SIDE_FRONT)
2104 VectorCopy (p1, neww->points[neww->numpoints]);
2108 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2111 // generate a split point
2112 p2 = in->points[(i+1)%in->numpoints];
2114 dot = dists[i] / (dists[i]-dists[i+1]);
2115 for (j = 0;j < 3;j++)
2116 { // avoid round off error when possible
2117 if (split->normal[j] == 1)
2118 mid[j] = split->dist;
2119 else if (split->normal[j] == -1)
2120 mid[j] = -split->dist;
2122 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2125 VectorCopy (mid, neww->points[neww->numpoints]);
2129 // free the original winding
2140 Divides a winding by a plane, producing one or two windings. The
2141 original winding is not damaged or freed. If only on one side, the
2142 returned winding will be the input winding. If on both sides, two
2143 new windings will be created.
2146 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2148 double dists[MAX_POINTS_ON_WINDING + 1];
2149 int sides[MAX_POINTS_ON_WINDING + 1];
2158 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2160 // determine sides for each point
2161 for (i = 0;i < in->numpoints;i++)
2163 dot = DotProduct (in->points[i], split->normal);
2166 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2167 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2168 else sides[i] = SIDE_ON;
2171 sides[i] = sides[0];
2172 dists[i] = dists[0];
2174 *front = *back = NULL;
2187 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2189 if (maxpts > MAX_POINTS_ON_WINDING)
2190 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2192 *front = f = NewWinding (maxpts);
2193 *back = b = NewWinding (maxpts);
2195 for (i = 0;i < in->numpoints;i++)
2197 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2198 Sys_Error ("DivideWinding: points exceeded estimate");
2202 if (sides[i] == SIDE_ON)
2204 VectorCopy (p1, f->points[f->numpoints]);
2206 VectorCopy (p1, b->points[b->numpoints]);
2211 if (sides[i] == SIDE_FRONT)
2213 VectorCopy (p1, f->points[f->numpoints]);
2216 else if (sides[i] == SIDE_BACK)
2218 VectorCopy (p1, b->points[b->numpoints]);
2222 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2225 // generate a split point
2226 p2 = in->points[(i+1)%in->numpoints];
2228 dot = dists[i] / (dists[i]-dists[i+1]);
2229 for (j = 0;j < 3;j++)
2230 { // avoid round off error when possible
2231 if (split->normal[j] == 1)
2232 mid[j] = split->dist;
2233 else if (split->normal[j] == -1)
2234 mid[j] = -split->dist;
2236 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2239 VectorCopy (mid, f->points[f->numpoints]);
2241 VectorCopy (mid, b->points[b->numpoints]);
2246 typedef struct portal_s
2249 mnode_t *nodes[2]; // [0] = front side of plane
2250 struct portal_s *next[2];
2252 struct portal_s *chain; // all portals are linked into a list
2256 static portal_t *portalchain;
2263 static portal_t *AllocPortal (void)
2266 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2267 p->chain = portalchain;
2272 static void FreePortal(portal_t *p)
2277 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2279 // calculate children first
2280 if (node->children[0]->contents >= 0)
2281 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2282 if (node->children[1]->contents >= 0)
2283 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2285 // make combined bounding box from children
2286 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2287 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2288 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2289 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2290 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2291 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2294 static void Mod_FinalizePortals(void)
2296 int i, j, numportals, numpoints;
2297 portal_t *p, *pnext;
2300 mleaf_t *leaf, *endleaf;
2303 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2304 leaf = loadmodel->leafs;
2305 endleaf = leaf + loadmodel->numleafs;
2306 for (;leaf < endleaf;leaf++)
2308 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2309 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2316 for (i = 0;i < 2;i++)
2318 leaf = (mleaf_t *)p->nodes[i];
2320 for (j = 0;j < w->numpoints;j++)
2322 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2323 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2324 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2325 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2326 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2327 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2334 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2336 // tally up portal and point counts
2342 // note: this check must match the one below or it will usually corrupt memory
2343 // 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
2344 if (p->winding && p->nodes[0] != p->nodes[1]
2345 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2346 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2349 numpoints += p->winding->numpoints * 2;
2353 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2354 loadmodel->numportals = numportals;
2355 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2356 loadmodel->numportalpoints = numpoints;
2357 // clear all leaf portal chains
2358 for (i = 0;i < loadmodel->numleafs;i++)
2359 loadmodel->leafs[i].portals = NULL;
2360 // process all portals in the global portal chain, while freeing them
2361 portal = loadmodel->portals;
2362 point = loadmodel->portalpoints;
2371 // note: this check must match the one above or it will usually corrupt memory
2372 // 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
2373 if (p->nodes[0] != p->nodes[1]
2374 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2375 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2377 // first make the back to front portal (forward portal)
2378 portal->points = point;
2379 portal->numpoints = p->winding->numpoints;
2380 portal->plane.dist = p->plane.dist;
2381 VectorCopy(p->plane.normal, portal->plane.normal);
2382 portal->here = (mleaf_t *)p->nodes[1];
2383 portal->past = (mleaf_t *)p->nodes[0];
2385 for (j = 0;j < portal->numpoints;j++)
2387 VectorCopy(p->winding->points[j], point->position);
2390 PlaneClassify(&portal->plane);
2392 // link into leaf's portal chain
2393 portal->next = portal->here->portals;
2394 portal->here->portals = portal;
2396 // advance to next portal
2399 // then make the front to back portal (backward portal)
2400 portal->points = point;
2401 portal->numpoints = p->winding->numpoints;
2402 portal->plane.dist = -p->plane.dist;
2403 VectorNegate(p->plane.normal, portal->plane.normal);
2404 portal->here = (mleaf_t *)p->nodes[0];
2405 portal->past = (mleaf_t *)p->nodes[1];
2407 for (j = portal->numpoints - 1;j >= 0;j--)
2409 VectorCopy(p->winding->points[j], point->position);
2412 PlaneClassify(&portal->plane);
2414 // link into leaf's portal chain
2415 portal->next = portal->here->portals;
2416 portal->here->portals = portal;
2418 // advance to next portal
2421 FreeWinding(p->winding);
2433 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2436 Host_Error ("AddPortalToNodes: NULL front node");
2438 Host_Error ("AddPortalToNodes: NULL back node");
2439 if (p->nodes[0] || p->nodes[1])
2440 Host_Error ("AddPortalToNodes: already included");
2441 // 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
2443 p->nodes[0] = front;
2444 p->next[0] = (portal_t *)front->portals;
2445 front->portals = (mportal_t *)p;
2448 p->next[1] = (portal_t *)back->portals;
2449 back->portals = (mportal_t *)p;
2454 RemovePortalFromNode
2457 static void RemovePortalFromNodes(portal_t *portal)
2461 void **portalpointer;
2463 for (i = 0;i < 2;i++)
2465 node = portal->nodes[i];
2467 portalpointer = (void **) &node->portals;
2472 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2476 if (portal->nodes[0] == node)
2478 *portalpointer = portal->next[0];
2479 portal->nodes[0] = NULL;
2481 else if (portal->nodes[1] == node)
2483 *portalpointer = portal->next[1];
2484 portal->nodes[1] = NULL;
2487 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2491 if (t->nodes[0] == node)
2492 portalpointer = (void **) &t->next[0];
2493 else if (t->nodes[1] == node)
2494 portalpointer = (void **) &t->next[1];
2496 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2501 static void Mod_RecursiveNodePortals (mnode_t *node)
2504 mnode_t *front, *back, *other_node;
2505 mplane_t clipplane, *plane;
2506 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2507 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2509 // if a leaf, we're done
2513 plane = node->plane;
2515 front = node->children[0];
2516 back = node->children[1];
2518 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2520 // create the new portal by generating a polygon for the node plane,
2521 // and clipping it by all of the other portals (which came from nodes above this one)
2522 nodeportal = AllocPortal ();
2523 nodeportal->plane = *node->plane;
2525 nodeportalwinding = BaseWindingForPlane (node->plane);
2526 side = 0; // shut up compiler warning
2527 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2529 clipplane = portal->plane;
2530 if (portal->nodes[0] == portal->nodes[1])
2531 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2532 if (portal->nodes[0] == node)
2534 else if (portal->nodes[1] == node)
2536 clipplane.dist = -clipplane.dist;
2537 VectorNegate (clipplane.normal, clipplane.normal);
2541 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2543 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2544 if (!nodeportalwinding)
2546 Con_Printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2551 if (nodeportalwinding)
2553 // if the plane was not clipped on all sides, there was an error
2554 nodeportal->winding = nodeportalwinding;
2555 AddPortalToNodes (nodeportal, front, back);
2558 // split the portals of this node along this node's plane and assign them to the children of this node
2559 // (migrating the portals downward through the tree)
2560 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2562 if (portal->nodes[0] == portal->nodes[1])
2563 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2564 if (portal->nodes[0] == node)
2566 else if (portal->nodes[1] == node)
2569 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2570 nextportal = portal->next[side];
2572 other_node = portal->nodes[!side];
2573 RemovePortalFromNodes (portal);
2575 // cut the portal into two portals, one on each side of the node plane
2576 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2581 AddPortalToNodes (portal, back, other_node);
2583 AddPortalToNodes (portal, other_node, back);
2589 AddPortalToNodes (portal, front, other_node);
2591 AddPortalToNodes (portal, other_node, front);
2595 // the winding is split
2596 splitportal = AllocPortal ();
2597 temp = splitportal->chain;
2598 *splitportal = *portal;
2599 splitportal->chain = temp;
2600 splitportal->winding = backwinding;
2601 FreeWinding (portal->winding);
2602 portal->winding = frontwinding;
2606 AddPortalToNodes (portal, front, other_node);
2607 AddPortalToNodes (splitportal, back, other_node);
2611 AddPortalToNodes (portal, other_node, front);
2612 AddPortalToNodes (splitportal, other_node, back);
2616 Mod_RecursiveNodePortals(front);
2617 Mod_RecursiveNodePortals(back);
2621 static void Mod_MakePortals(void)
2624 Mod_RecursiveNodePortals (loadmodel->nodes);
2625 Mod_FinalizePortals();
2628 static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2631 int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2632 msurface_t *surf, *s;
2633 float *v0, *v1, *v2, *v3;
2634 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2635 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2636 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2638 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)
2640 if (surf->neighborsurfaces[vertnum])
2642 surf->neighborsurfaces[vertnum] = NULL;
2643 for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2645 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2646 || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2647 || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2650 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2651 if (s->neighborsurfaces[vnum] == surf)
2653 if (vnum < s->poly_numverts)
2655 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)
2657 if (s->neighborsurfaces[vnum] == NULL
2658 && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2659 || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2661 surf->neighborsurfaces[vertnum] = s;
2662 s->neighborsurfaces[vnum] = surf;
2666 if (vnum < s->poly_numverts)
2674 void Mod_BuildLightmapUpdateChains(mempool_t *mempool, model_t *model)
2676 int i, j, stylecounts[256], totalcount, remapstyles[256];
2678 memset(stylecounts, 0, sizeof(stylecounts));
2679 for (i = 0;i < model->nummodelsurfaces;i++)
2681 surf = model->surfaces + model->firstmodelsurface + i;
2682 for (j = 0;j < MAXLIGHTMAPS;j++)
2683 stylecounts[surf->styles[j]]++;
2686 model->light_styles = 0;
2687 for (i = 0;i < 255;i++)
2691 remapstyles[i] = model->light_styles++;
2692 totalcount += stylecounts[i] + 1;
2697 model->light_style = Mem_Alloc(mempool, model->light_styles * sizeof(qbyte));
2698 model->light_stylevalue = Mem_Alloc(mempool, model->light_styles * sizeof(int));
2699 model->light_styleupdatechains = Mem_Alloc(mempool, model->light_styles * sizeof(msurface_t **));
2700 model->light_styleupdatechainsbuffer = Mem_Alloc(mempool, totalcount * sizeof(msurface_t *));
2701 model->light_styles = 0;
2702 for (i = 0;i < 255;i++)
2704 model->light_style[model->light_styles++] = i;
2706 for (i = 0;i < model->light_styles;i++)
2708 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2709 j += stylecounts[model->light_style[i]] + 1;
2711 for (i = 0;i < model->nummodelsurfaces;i++)
2713 surf = model->surfaces + model->firstmodelsurface + i;
2714 for (j = 0;j < MAXLIGHTMAPS;j++)
2715 if (surf->styles[j] != 255)
2716 *model->light_styleupdatechains[remapstyles[surf->styles[j]]]++ = surf;
2719 for (i = 0;i < model->light_styles;i++)
2721 *model->light_styleupdatechains[i] = NULL;
2722 model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j;
2723 j += stylecounts[model->light_style[i]] + 1;
2727 void Mod_BuildPVSTextureChains(model_t *model)
2730 for (i = 0;i < model->numtextures;i++)
2731 model->pvstexturechainslength[i] = 0;
2732 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2734 if (model->surfacepvsframes[j] == model->pvsframecount)
2736 model->pvssurflist[model->pvssurflistlength++] = j;
2737 model->pvstexturechainslength[model->surfaces[j].texinfo->texture->number]++;
2740 for (i = 0, j = 0;i < model->numtextures;i++)
2742 if (model->pvstexturechainslength[i])
2744 model->pvstexturechains[i] = model->pvstexturechainsbuffer + j;
2745 j += model->pvstexturechainslength[i] + 1;
2748 model->pvstexturechains[i] = NULL;
2750 for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++)
2751 if (model->surfacepvsframes[j] == model->pvsframecount)
2752 *model->pvstexturechains[model->surfaces[j].texinfo->texture->number]++ = model->surfaces + j;
2753 for (i = 0;i < model->numtextures;i++)
2755 if (model->pvstexturechainslength[i])
2757 *model->pvstexturechains[i] = NULL;
2758 model->pvstexturechains[i] -= model->pvstexturechainslength[i];
2768 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2769 extern void R_Model_Brush_Draw(entity_render_t *ent);
2770 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2771 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);
2772 void Mod_LoadBrushModelQ1orHL (model_t *mod, void *buffer)
2777 mempool_t *mainmempool;
2779 model_t *originalloadmodel;
2780 float dist, modelyawradius, modelradius, *vec;
2784 mod->type = mod_brush;
2786 header = (dheader_t *)buffer;
2788 i = LittleLong (header->version);
2789 if (i != BSPVERSION && i != 30)
2790 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2791 mod->ishlbsp = i == 30;
2792 if (loadmodel->isworldmodel)
2794 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2795 // until we get a texture for it...
2799 // swap all the lumps
2800 mod_base = (qbyte *)header;
2802 for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
2803 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2807 // store which lightmap format to use
2808 mod->lightmaprgba = r_lightmaprgba.integer;
2810 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2811 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2812 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2813 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2814 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2815 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2816 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2817 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2818 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2819 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2820 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2821 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2822 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2823 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2824 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2829 mod->numframes = 2; // regular and alternate animation
2831 mainmempool = mod->mempool;
2832 loadname = mod->name;
2834 Mod_LoadLightList ();
2835 originalloadmodel = loadmodel;
2838 // set up the submodels (FIXME: this is confusing)
2840 for (i = 0;i < mod->numsubmodels;i++)
2842 bm = &mod->submodels[i];
2844 mod->hulls[0].firstclipnode = bm->headnode[0];
2845 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2847 mod->hulls[j].firstclipnode = bm->headnode[j];
2848 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2851 mod->firstmodelsurface = bm->firstface;
2852 mod->nummodelsurfaces = bm->numfaces;
2854 // this gets altered below if sky is used
2855 mod->DrawSky = NULL;
2856 mod->Draw = R_Model_Brush_Draw;
2857 mod->DrawFakeShadow = NULL;
2858 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2859 mod->DrawLight = R_Model_Brush_DrawLight;
2860 mod->pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t **));
2861 mod->pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool, (mod->nummodelsurfaces + mod->numtextures) * sizeof(msurface_t *));
2862 mod->pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(int));
2863 Mod_BuildPVSTextureChains(mod);
2864 Mod_BuildLightmapUpdateChains(originalloadmodel->mempool, mod);
2865 if (mod->nummodelsurfaces)
2867 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2868 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2869 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2872 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2874 // we only need to have a drawsky function if it is used (usually only on world model)
2875 if (surf->texinfo->texture->shader == &Cshader_sky)
2876 mod->DrawSky = R_Model_Brush_DrawSky;
2877 // LordHavoc: submodels always clip, even if water
2878 if (mod->numsubmodels - 1)
2879 surf->flags |= SURF_SOLIDCLIP;
2880 // calculate bounding shapes
2881 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
2883 for (k = 0, vec = mesh->vertex3f;k < mesh->numverts;k++, vec += 3)
2885 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2886 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2887 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2888 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2889 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2890 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2891 dist = vec[0]*vec[0]+vec[1]*vec[1];
2892 if (modelyawradius < dist)
2893 modelyawradius = dist;
2894 dist += vec[2]*vec[2];
2895 if (modelradius < dist)
2900 modelyawradius = sqrt(modelyawradius);
2901 modelradius = sqrt(modelradius);
2902 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2903 mod->yawmins[2] = mod->normalmins[2];
2904 mod->yawmaxs[2] = mod->normalmaxs[2];
2905 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2906 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2907 mod->radius = modelradius;
2908 mod->radius2 = modelradius * modelradius;
2912 // LordHavoc: empty submodel (lacrima.bsp has such a glitch)
2913 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2915 Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool);
2917 mod->numleafs = bm->visleafs;
2919 // LordHavoc: only register submodels if it is the world
2920 // (prevents bsp models from replacing world submodels)
2921 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2924 // duplicate the basic information
2925 sprintf (name, "*%i", i+1);
2926 loadmodel = Mod_FindName (name);
2928 strcpy (loadmodel->name, name);
2929 // textures and memory belong to the main model
2930 loadmodel->texturepool = NULL;
2931 loadmodel->mempool = NULL;
2936 loadmodel = originalloadmodel;
2937 //Mod_ProcessLightList ();
2940 static void Mod_Q2LoadEntities (lump_t *l)
2944 static void Mod_Q2LoadPlanes (lump_t *l)
2951 in = (void *)(mod_base + l->fileofs);
2952 if (l->filelen % sizeof(*in))
2953 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
2954 count = l->filelen / sizeof(*in);
2955 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
2958 loadmodel->num = count;
2960 for (i = 0;i < count;i++, in++, out++)
2966 static void Mod_Q2LoadVertices (lump_t *l)
2973 in = (void *)(mod_base + l->fileofs);
2974 if (l->filelen % sizeof(*in))
2975 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
2976 count = l->filelen / sizeof(*in);
2977 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
2980 loadmodel->num = count;
2982 for (i = 0;i < count;i++, in++, out++)
2988 static void Mod_Q2LoadVisibility (lump_t *l)
2995 in = (void *)(mod_base + l->fileofs);
2996 if (l->filelen % sizeof(*in))
2997 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
2998 count = l->filelen / sizeof(*in);
2999 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3002 loadmodel->num = count;
3004 for (i = 0;i < count;i++, in++, out++)
3010 static void Mod_Q2LoadNodes (lump_t *l)
3017 in = (void *)(mod_base + l->fileofs);
3018 if (l->filelen % sizeof(*in))
3019 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3020 count = l->filelen / sizeof(*in);
3021 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3024 loadmodel->num = count;
3026 for (i = 0;i < count;i++, in++, out++)
3032 static void Mod_Q2LoadTexInfo (lump_t *l)
3039 in = (void *)(mod_base + l->fileofs);
3040 if (l->filelen % sizeof(*in))
3041 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3042 count = l->filelen / sizeof(*in);
3043 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3046 loadmodel->num = count;
3048 for (i = 0;i < count;i++, in++, out++)
3054 static void Mod_Q2LoadFaces (lump_t *l)
3061 in = (void *)(mod_base + l->fileofs);
3062 if (l->filelen % sizeof(*in))
3063 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3064 count = l->filelen / sizeof(*in);
3065 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3068 loadmodel->num = count;
3070 for (i = 0;i < count;i++, in++, out++)
3076 static void Mod_Q2LoadLighting (lump_t *l)
3083 in = (void *)(mod_base + l->fileofs);
3084 if (l->filelen % sizeof(*in))
3085 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3086 count = l->filelen / sizeof(*in);
3087 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3090 loadmodel->num = count;
3092 for (i = 0;i < count;i++, in++, out++)
3098 static void Mod_Q2LoadLeafs (lump_t *l)
3105 in = (void *)(mod_base + l->fileofs);
3106 if (l->filelen % sizeof(*in))
3107 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3108 count = l->filelen / sizeof(*in);
3109 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3112 loadmodel->num = count;
3114 for (i = 0;i < count;i++, in++, out++)
3120 static void Mod_Q2LoadLeafFaces (lump_t *l)
3127 in = (void *)(mod_base + l->fileofs);
3128 if (l->filelen % sizeof(*in))
3129 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3130 count = l->filelen / sizeof(*in);
3131 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3134 loadmodel->num = count;
3136 for (i = 0;i < count;i++, in++, out++)
3142 static void Mod_Q2LoadLeafBrushes (lump_t *l)
3149 in = (void *)(mod_base + l->fileofs);
3150 if (l->filelen % sizeof(*in))
3151 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3152 count = l->filelen / sizeof(*in);
3153 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3156 loadmodel->num = count;
3158 for (i = 0;i < count;i++, in++, out++)
3164 static void Mod_Q2LoadEdges (lump_t *l)
3171 in = (void *)(mod_base + l->fileofs);
3172 if (l->filelen % sizeof(*in))
3173 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3174 count = l->filelen / sizeof(*in);
3175 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3178 loadmodel->num = count;
3180 for (i = 0;i < count;i++, in++, out++)
3186 static void Mod_Q2LoadSurfEdges (lump_t *l)
3193 in = (void *)(mod_base + l->fileofs);
3194 if (l->filelen % sizeof(*in))
3195 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3196 count = l->filelen / sizeof(*in);
3197 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3200 loadmodel->num = count;
3202 for (i = 0;i < count;i++, in++, out++)
3208 static void Mod_Q2LoadBrushes (lump_t *l)
3215 in = (void *)(mod_base + l->fileofs);
3216 if (l->filelen % sizeof(*in))
3217 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3218 count = l->filelen / sizeof(*in);
3219 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3222 loadmodel->num = count;
3224 for (i = 0;i < count;i++, in++, out++)
3230 static void Mod_Q2LoadBrushSides (lump_t *l)
3237 in = (void *)(mod_base + l->fileofs);
3238 if (l->filelen % sizeof(*in))
3239 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3240 count = l->filelen / sizeof(*in);
3241 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3244 loadmodel->num = count;
3246 for (i = 0;i < count;i++, in++, out++)
3252 static void Mod_Q2LoadAreas (lump_t *l)
3259 in = (void *)(mod_base + l->fileofs);
3260 if (l->filelen % sizeof(*in))
3261 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3262 count = l->filelen / sizeof(*in);
3263 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3266 loadmodel->num = count;
3268 for (i = 0;i < count;i++, in++, out++)
3274 static void Mod_Q2LoadAreaPortals (lump_t *l)
3281 in = (void *)(mod_base + l->fileofs);
3282 if (l->filelen % sizeof(*in))
3283 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3284 count = l->filelen / sizeof(*in);
3285 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3288 loadmodel->num = count;
3290 for (i = 0;i < count;i++, in++, out++)
3296 static void Mod_Q2LoadModels (lump_t *l)
3303 in = (void *)(mod_base + l->fileofs);
3304 if (l->filelen % sizeof(*in))
3305 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
3306 count = l->filelen / sizeof(*in);
3307 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3310 loadmodel->num = count;
3312 for (i = 0;i < count;i++, in++, out++)
3318 void Mod_LoadBrushModelQ2 (model_t *mod, void *buffer)
3321 q2dheader_t *header;
3323 mod->type = mod_brushq2;
3325 header = (q2dheader_t *)buffer;
3327 i = LittleLong (header->version);
3328 if (i != Q2BSPVERSION)
3329 Host_Error ("Mod_LoadBrushModelQ2: %s has wrong version number (%i should be %i)", mod->name, i, BSPVERSION);
3330 mod->ishlbsp = false;
3331 if (loadmodel->isworldmodel)
3333 Cvar_SetValue("halflifebsp", mod->ishlbsp);
3334 // until we get a texture for it...
3338 mod_base = (qbyte *)header;
3340 // swap all the lumps
3341 for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
3342 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
3344 // store which lightmap format to use
3345 mod->lightmaprgba = r_lightmaprgba.integer;
3347 Mod_Q2LoadEntities(&header->lumps[Q2LUMP_ENTITIES]);
3348 Mod_Q2LoadPlanes(&header->lumps[Q2LUMP_PLANES]);
3349 Mod_Q2LoadVertices(&header->lumps[Q2LUMP_VERTEXES]);
3350 Mod_Q2LoadVisibility(&header->lumps[Q2LUMP_VISIBILITY]);
3351 Mod_Q2LoadNodes(&header->lumps[Q2LUMP_NODES]);
3352 Mod_Q2LoadTexInfo(&header->lumps[Q2LUMP_TEXINFO]);
3353 Mod_Q2LoadFaces(&header->lumps[Q2LUMP_FACES]);
3354 Mod_Q2LoadLighting(&header->lumps[Q2LUMP_LIGHTING]);
3355 Mod_Q2LoadLeafs(&header->lumps[Q2LUMP_LEAFS]);
3356 Mod_Q2LoadLeafFaces(&header->lumps[Q2LUMP_LEAFFACES]);
3357 Mod_Q2LoadLeafBrushes(&header->lumps[Q2LUMP_LEAFBRUSHES]);
3358 Mod_Q2LoadEdges(&header->lumps[Q2LUMP_EDGES]);
3359 Mod_Q2LoadSurfEdges(&header->lumps[Q2LUMP_SURFEDGES]);
3360 Mod_Q2LoadBrushes(&header->lumps[Q2LUMP_BRUSHES]);
3361 Mod_Q2LoadBrushSides(&header->lumps[Q2LUMP_BRUSHSIDES]);
3362 Mod_Q2LoadAreas(&header->lumps[Q2LUMP_AREAS]);
3363 Mod_Q2LoadAreaPortals(&header->lumps[Q2LUMP_AREAPORTALS]);
3364 // LordHavoc: must go last because this makes the submodels
3365 Mod_Q2LoadModels(&header->lumps[Q2LUMP_MODELS]);
3368 void Mod_LoadBrushModelQ3 (model_t *mod, void *buffer)
3370 Host_Error("Mod_LoadBrushModelQ3: not yet implemented\n");
3373 void Mod_LoadBrushModelIBSP (model_t *mod, void *buffer)
3375 int i = LittleLong(*((int *)buffer));
3377 Mod_LoadBrushModelQ3 (mod,buffer);
3379 Mod_LoadBrushModelQ2 (mod,buffer);
3381 Host_Error("Mod_LoadBrushModelIBSP: unknown/unsupported version %i\n", i);