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_q1bsp_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"};
37 void Mod_BrushInit(void)
39 // Cvar_RegisterVariable(&r_subdivide_size);
40 Cvar_RegisterVariable(&halflifebsp);
41 Cvar_RegisterVariable(&r_novis);
42 Cvar_RegisterVariable(&r_miplightmaps);
43 Cvar_RegisterVariable(&r_lightmaprgba);
44 Cvar_RegisterVariable(&r_nosurftextures);
45 Cvar_RegisterVariable(&r_sortsurfaces);
46 memset(mod_q1bsp_novis, 0xff, sizeof(mod_q1bsp_novis));
49 static mleaf_t *Mod_Q1BSP_PointInLeaf(model_t *model, const vec3_t p)
56 Mod_CheckLoaded(model);
58 // LordHavoc: modified to start at first clip node,
59 // in other words: first node of the (sub)model
60 node = model->brushq1.nodes + model->brushq1.hulls[0].firstclipnode;
61 while (node->contents == 0)
62 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist];
64 return (mleaf_t *)node;
67 static int Mod_Q1BSP_PointContents(model_t *model, const vec3_t p)
72 return CONTENTS_EMPTY;
74 Mod_CheckLoaded(model);
76 // LordHavoc: modified to start at first clip node,
77 // in other words: first node of the (sub)model
78 node = model->brushq1.nodes + model->brushq1.hulls[0].firstclipnode;
79 while (node->contents == 0)
80 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct(p,node->plane->normal)) < node->plane->dist];
82 return ((mleaf_t *)node)->contents;
85 typedef struct findnonsolidlocationinfo_s
93 findnonsolidlocationinfo_t;
96 extern cvar_t samelevel;
98 static void Mod_Q1BSP_FindNonSolidLocation_r_Leaf(findnonsolidlocationinfo_t *info, mleaf_t *leaf)
100 int i, surfnum, k, *tri, *mark;
101 float dist, f, vert[3][3], edge[3][3], facenormal[3], edgenormal[3][3], point[3];
107 for (surfnum = 0, mark = leaf->firstmarksurface;surfnum < leaf->nummarksurfaces;surfnum++, mark++)
109 surf = info->model->brushq1.surfaces + *mark;
110 if (surf->flags & SURF_SOLIDCLIP)
113 VectorCopy(surf->plane->normal, surfnormal);
114 if (surf->flags & SURF_PLANEBACK)
115 VectorNegate(surfnormal, surfnormal);
117 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
119 for (k = 0;k < mesh->numtriangles;k++)
121 tri = mesh->element3i + k * 3;
122 VectorCopy((mesh->vertex3f + tri[0] * 3), vert[0]);
123 VectorCopy((mesh->vertex3f + tri[1] * 3), vert[1]);
124 VectorCopy((mesh->vertex3f + tri[2] * 3), vert[2]);
125 VectorSubtract(vert[1], vert[0], edge[0]);
126 VectorSubtract(vert[2], vert[1], edge[1]);
127 CrossProduct(edge[1], edge[0], facenormal);
128 if (facenormal[0] || facenormal[1] || facenormal[2])
130 VectorNormalize(facenormal);
132 if (VectorDistance(facenormal, surfnormal) > 0.01f)
133 Con_Printf("a2! %f %f %f != %f %f %f\n", facenormal[0], facenormal[1], facenormal[2], surfnormal[0], surfnormal[1], surfnormal[2]);
135 f = DotProduct(info->center, facenormal) - DotProduct(vert[0], facenormal);
136 if (f <= info->bestdist && f >= -info->bestdist)
138 VectorSubtract(vert[0], vert[2], edge[2]);
139 VectorNormalize(edge[0]);
140 VectorNormalize(edge[1]);
141 VectorNormalize(edge[2]);
142 CrossProduct(facenormal, edge[0], edgenormal[0]);
143 CrossProduct(facenormal, edge[1], edgenormal[1]);
144 CrossProduct(facenormal, edge[2], edgenormal[2]);
146 if (samelevel.integer & 1)
147 VectorNegate(edgenormal[0], edgenormal[0]);
148 if (samelevel.integer & 2)
149 VectorNegate(edgenormal[1], edgenormal[1]);
150 if (samelevel.integer & 4)
151 VectorNegate(edgenormal[2], edgenormal[2]);
152 for (i = 0;i < 3;i++)
153 if (DotProduct(vert[0], edgenormal[i]) > DotProduct(vert[i], edgenormal[i]) + 0.1f
154 || DotProduct(vert[1], edgenormal[i]) > DotProduct(vert[i], edgenormal[i]) + 0.1f
155 || DotProduct(vert[2], edgenormal[i]) > DotProduct(vert[i], edgenormal[i]) + 0.1f)
156 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]);
159 if (DotProduct(info->center, edgenormal[0]) < DotProduct(vert[0], edgenormal[0])
160 && DotProduct(info->center, edgenormal[1]) < DotProduct(vert[1], edgenormal[1])
161 && DotProduct(info->center, edgenormal[2]) < DotProduct(vert[2], edgenormal[2]))
163 // we got lucky, the center is within the face
164 dist = DotProduct(info->center, facenormal) - DotProduct(vert[0], facenormal);
168 if (info->bestdist > dist)
170 info->bestdist = dist;
171 VectorScale(facenormal, (info->radius - -dist), info->nudge);
176 if (info->bestdist > dist)
178 info->bestdist = dist;
179 VectorScale(facenormal, (info->radius - dist), info->nudge);
185 // check which edge or vertex the center is nearest
186 for (i = 0;i < 3;i++)
188 f = DotProduct(info->center, edge[i]);
189 if (f >= DotProduct(vert[0], edge[i])
190 && f <= DotProduct(vert[1], edge[i]))
193 VectorMA(info->center, -f, edge[i], point);
194 dist = sqrt(DotProduct(point, point));
195 if (info->bestdist > dist)
197 info->bestdist = dist;
198 VectorScale(point, (info->radius / dist), info->nudge);
200 // skip both vertex checks
201 // (both are further away than this edge)
206 // not on edge, check first vertex of edge
207 VectorSubtract(info->center, vert[i], point);
208 dist = sqrt(DotProduct(point, point));
209 if (info->bestdist > dist)
211 info->bestdist = dist;
212 VectorScale(point, (info->radius / dist), info->nudge);
225 static void Mod_Q1BSP_FindNonSolidLocation_r(findnonsolidlocationinfo_t *info, mnode_t *node)
229 if (((mleaf_t *)node)->nummarksurfaces)
230 Mod_Q1BSP_FindNonSolidLocation_r_Leaf(info, (mleaf_t *)node);
234 float f = PlaneDiff(info->center, node->plane);
235 if (f >= -info->bestdist)
236 Mod_Q1BSP_FindNonSolidLocation_r(info, node->children[0]);
237 if (f <= info->bestdist)
238 Mod_Q1BSP_FindNonSolidLocation_r(info, node->children[1]);
242 static void Mod_Q1BSP_FindNonSolidLocation(model_t *model, const vec3_t in, vec3_t out, float radius)
245 findnonsolidlocationinfo_t info;
251 VectorCopy(in, info.center);
252 info.radius = radius;
257 VectorClear(info.nudge);
258 info.bestdist = radius;
259 Mod_Q1BSP_FindNonSolidLocation_r(&info, model->brushq1.nodes + model->brushq1.hulls[0].firstclipnode);
260 VectorAdd(info.center, info.nudge, info.center);
262 while (info.bestdist < radius && ++i < 10);
263 VectorCopy(info.center, out);
266 static qbyte *Mod_Q1BSP_DecompressVis(model_t *model, qbyte *in)
268 static qbyte decompressed[MAX_MAP_LEAFS/8];
273 row = (model->brushq1.numleafs+7)>>3;
291 } while (out - decompressed < row);
296 static qbyte *Mod_Q1BSP_LeafPVS(model_t *model, mleaf_t *leaf)
298 if (r_novis.integer || leaf == model->brushq1.leafs || leaf->compressed_vis == NULL)
299 return mod_q1bsp_novis;
300 return Mod_Q1BSP_DecompressVis(model, leaf->compressed_vis);
303 static void Mod_Q1BSP_LoadTextures(lump_t *l)
305 int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs, incomplete;
307 texture_t *tx, *tx2, *anims[10], *altanims[10];
309 qbyte *data, *mtdata;
312 loadmodel->brushq1.textures = NULL;
317 m = (dmiptexlump_t *)(mod_base + l->fileofs);
319 m->nummiptex = LittleLong (m->nummiptex);
321 // add two slots for notexture walls and notexture liquids
322 loadmodel->brushq1.numtextures = m->nummiptex + 2;
323 loadmodel->brushq1.textures = Mem_Alloc(loadmodel->mempool, loadmodel->brushq1.numtextures * sizeof(texture_t));
325 // fill out all slots with notexture
326 for (i = 0, tx = loadmodel->brushq1.textures;i < loadmodel->brushq1.numtextures;i++, tx++)
329 strcpy(tx->name, "NO TEXTURE FOUND");
332 tx->skin.base = r_notexture;
333 tx->shader = &Cshader_wall_lightmap;
334 tx->flags = SURF_SOLIDCLIP;
335 if (i == loadmodel->brushq1.numtextures - 1)
337 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
338 tx->shader = &Cshader_water;
340 tx->currentframe = tx;
343 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
345 // LordHavoc: mostly rewritten map texture loader
346 for (i = 0;i < m->nummiptex;i++)
348 dofs[i] = LittleLong(dofs[i]);
349 if (dofs[i] == -1 || r_nosurftextures.integer)
351 dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
353 // make sure name is no more than 15 characters
354 for (j = 0;dmiptex->name[j] && j < 15;j++)
355 name[j] = dmiptex->name[j];
358 mtwidth = LittleLong(dmiptex->width);
359 mtheight = LittleLong(dmiptex->height);
361 j = LittleLong(dmiptex->offsets[0]);
365 if (j < 40 || j + mtwidth * mtheight > l->filelen)
367 Con_Printf("Texture \"%s\" in \"%s\"is corrupt or incomplete\n", dmiptex->name, loadmodel->name);
370 mtdata = (qbyte *)dmiptex + j;
373 if ((mtwidth & 15) || (mtheight & 15))
374 Con_Printf("warning: texture \"%s\" in \"%s\" is not 16 aligned", dmiptex->name, loadmodel->name);
376 // LordHavoc: force all names to lowercase
377 for (j = 0;name[j];j++)
378 if (name[j] >= 'A' && name[j] <= 'Z')
379 name[j] += 'a' - 'A';
381 tx = loadmodel->brushq1.textures + i;
382 strcpy(tx->name, name);
384 tx->height = mtheight;
388 sprintf(tx->name, "unnamed%i", i);
389 Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
392 // LordHavoc: HL sky textures are entirely different than quake
393 if (!loadmodel->brushq1.ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
395 if (loadmodel->isworldmodel)
397 data = loadimagepixels(tx->name, false, 0, 0);
400 if (image_width == 256 && image_height == 128)
408 Con_Printf("Invalid replacement texture for sky \"%s\" in %\"%s\", must be 256x128 pixels\n", tx->name, loadmodel->name);
410 R_InitSky(mtdata, 1);
413 else if (mtdata != NULL)
414 R_InitSky(mtdata, 1);
419 if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true))
421 // did not find external texture, load it from the bsp or wad3
422 if (loadmodel->brushq1.ishlbsp)
424 // internal texture overrides wad
425 qbyte *pixels, *freepixels, *fogpixels;
426 pixels = freepixels = NULL;
428 pixels = W_ConvertWAD3Texture(dmiptex);
430 pixels = freepixels = W_GetTexture(tx->name);
433 tx->width = image_width;
434 tx->height = image_height;
435 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);
436 if (Image_CheckAlpha(pixels, image_width * image_height, true))
438 fogpixels = Mem_Alloc(tempmempool, image_width * image_height * 4);
439 for (j = 0;j < image_width * image_height * 4;j += 4)
441 fogpixels[j + 0] = 255;
442 fogpixels[j + 1] = 255;
443 fogpixels[j + 2] = 255;
444 fogpixels[j + 3] = pixels[j + 3];
446 tx->skin.fog = R_LoadTexture2D(loadmodel->texturepool, tx->name, image_width, image_height, pixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL);
451 Mem_Free(freepixels);
453 else if (mtdata) // texture included
454 Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_PRECACHE, false, true, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height);
457 if (tx->skin.base == NULL)
462 tx->skin.base = r_notexture;
465 if (tx->name[0] == '*')
467 // turb does not block movement
468 tx->flags &= ~SURF_SOLIDCLIP;
469 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
470 // LordHavoc: some turbulent textures should be fullbright and solid
471 if (!strncmp(tx->name,"*lava",5)
472 || !strncmp(tx->name,"*teleport",9)
473 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
474 tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
476 tx->flags |= SURF_WATERALPHA;
477 tx->shader = &Cshader_water;
479 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
481 tx->flags |= SURF_DRAWSKY;
482 tx->shader = &Cshader_sky;
486 tx->flags |= SURF_LIGHTMAP;
488 tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT;
489 tx->shader = &Cshader_wall_lightmap;
492 // start out with no animation
493 tx->currentframe = tx;
496 // sequence the animations
497 for (i = 0;i < m->nummiptex;i++)
499 tx = loadmodel->brushq1.textures + i;
500 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
502 if (tx->anim_total[0] || tx->anim_total[1])
503 continue; // already sequenced
505 // find the number of frames in the animation
506 memset(anims, 0, sizeof(anims));
507 memset(altanims, 0, sizeof(altanims));
509 for (j = i;j < m->nummiptex;j++)
511 tx2 = loadmodel->brushq1.textures + j;
512 if (!tx2 || tx2->name[0] != '+' || strcmp(tx2->name+2, tx->name+2))
516 if (num >= '0' && num <= '9')
517 anims[num - '0'] = tx2;
518 else if (num >= 'a' && num <= 'j')
519 altanims[num - 'a'] = tx2;
521 Con_Printf("Bad animating texture %s\n", tx->name);
525 for (j = 0;j < 10;j++)
532 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
535 for (j = 0;j < max;j++)
539 Con_Printf("Missing frame %i of %s\n", j, tx->name);
543 for (j = 0;j < altmax;j++)
547 Con_Printf("Missing altframe %i of %s\n", j, tx->name);
556 // if there is no alternate animation, duplicate the primary
557 // animation into the alternate
559 for (k = 0;k < 10;k++)
560 altanims[k] = anims[k];
563 // link together the primary animation
564 for (j = 0;j < max;j++)
567 tx2->animated = true;
568 tx2->anim_total[0] = max;
569 tx2->anim_total[1] = altmax;
570 for (k = 0;k < 10;k++)
572 tx2->anim_frames[0][k] = anims[k];
573 tx2->anim_frames[1][k] = altanims[k];
577 // if there really is an alternate anim...
578 if (anims[0] != altanims[0])
580 // link together the alternate animation
581 for (j = 0;j < altmax;j++)
584 tx2->animated = true;
585 // the primary/alternate are reversed here
586 tx2->anim_total[0] = altmax;
587 tx2->anim_total[1] = max;
588 for (k = 0;k < 10;k++)
590 tx2->anim_frames[0][k] = altanims[k];
591 tx2->anim_frames[1][k] = anims[k];
598 static void Mod_Q1BSP_LoadLighting(lump_t *l)
601 qbyte *in, *out, *data, d;
602 char litfilename[1024];
603 loadmodel->brushq1.lightdata = NULL;
604 if (loadmodel->brushq1.ishlbsp) // LordHavoc: load the colored lighting data straight
606 loadmodel->brushq1.lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
607 memcpy(loadmodel->brushq1.lightdata, mod_base + l->fileofs, l->filelen);
609 else // LordHavoc: bsp version 29 (normal white lighting)
611 // LordHavoc: hope is not lost yet, check for a .lit file to load
612 strcpy(litfilename, loadmodel->name);
613 FS_StripExtension(litfilename, litfilename);
614 strcat(litfilename, ".lit");
615 data = (qbyte*) FS_LoadFile(litfilename, false);
618 if (fs_filesize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
620 i = LittleLong(((int *)data)[1]);
623 Con_DPrintf("loaded %s\n", litfilename);
624 loadmodel->brushq1.lightdata = Mem_Alloc(loadmodel->mempool, fs_filesize - 8);
625 memcpy(loadmodel->brushq1.lightdata, data + 8, fs_filesize - 8);
631 Con_Printf("Unknown .lit file version (%d)\n", i);
637 if (fs_filesize == 8)
638 Con_Printf("Empty .lit file, ignoring\n");
640 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
644 // LordHavoc: oh well, expand the white lighting data
647 loadmodel->brushq1.lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
648 in = loadmodel->brushq1.lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
649 out = loadmodel->brushq1.lightdata;
650 memcpy(in, mod_base + l->fileofs, l->filelen);
651 for (i = 0;i < l->filelen;i++)
661 static void Mod_Q1BSP_LoadLightList(void)
664 char lightsfilename[1024], *s, *t, *lightsstring;
667 strcpy(lightsfilename, loadmodel->name);
668 FS_StripExtension(lightsfilename, lightsfilename);
669 strcat(lightsfilename, ".lights");
670 s = lightsstring = (char *) FS_LoadFile(lightsfilename, false);
676 while (*s && *s != '\n')
680 Mem_Free(lightsstring);
681 Host_Error("lights file must end with a newline\n");
686 loadmodel->brushq1.lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
689 while (*s && n < numlights)
692 while (*s && *s != '\n')
696 Mem_Free(lightsstring);
697 Host_Error("misparsed lights file!\n");
699 e = loadmodel->brushq1.lights + n;
701 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);
705 Mem_Free(lightsstring);
706 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);
713 Mem_Free(lightsstring);
714 Host_Error("misparsed lights file!\n");
716 loadmodel->brushq1.numlights = numlights;
717 Mem_Free(lightsstring);
722 static int castshadowcount = 0;
723 static void Mod_Q1BSP_ProcessLightList(void)
725 int j, k, l, *mark, lnum;
733 for (lnum = 0, e = loadmodel->brushq1.lights;lnum < loadmodel->brushq1.numlights;lnum++, e++)
735 e->cullradius2 = DotProduct(e->light, e->light) / (e->falloff * e->falloff * 8192.0f * 8192.0f * 2.0f * 2.0f);// + 4096.0f;
736 if (e->cullradius2 > 4096.0f * 4096.0f)
737 e->cullradius2 = 4096.0f * 4096.0f;
738 e->cullradius = e->lightradius = sqrt(e->cullradius2);
739 leaf = Mod_Q1BSP_PointInLeaf(e->origin, loadmodel);
740 if (leaf->compressed_vis)
741 pvs = Mod_Q1BSP_DecompressVis(leaf->compressed_vis, loadmodel);
743 pvs = mod_q1bsp_novis;
744 for (j = 0;j < loadmodel->brushq1.numsurfaces;j++)
745 loadmodel->brushq1.surfacevisframes[j] = -1;
746 for (j = 0, leaf = loadmodel->brushq1.leafs + 1;j < loadmodel->brushq1.numleafs - 1;j++, leaf++)
748 if (pvs[j >> 3] & (1 << (j & 7)))
750 for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++)
752 surf = loadmodel->brushq1.surfaces + *mark;
753 if (surf->number != *mark)
754 Con_Printf("%d != %d\n", surf->number, *mark);
755 dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
756 if (surf->flags & SURF_PLANEBACK)
758 if (dist > 0 && dist < e->cullradius)
760 temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0];
761 temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1];
762 temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2];
763 if (DotProduct(temp, temp) < lightradius2)
764 loadmodel->brushq1.surfacevisframes[*mark] = -2;
769 // build list of light receiving surfaces
771 for (j = 0;j < loadmodel->brushq1.numsurfaces;j++)
772 if (loadmodel->brushq1.surfacevisframes[j] == -2)
775 if (e->numsurfaces > 0)
777 e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
779 for (j = 0;j < loadmodel->brushq1.numsurfaces;j++)
780 if (loadmodel->brushq1.surfacevisframes[j] == -2)
781 e->surfaces[e->numsurfaces++] = loadmodel->brushq1.surfaces + j;
783 // find bounding box and sphere of lit surfaces
784 // (these will be used for creating a shape to clip the light)
786 for (j = 0;j < e->numsurfaces;j++)
788 surf = e->surfaces[j];
791 VectorCopy(surf->poly_verts, e->mins);
792 VectorCopy(surf->poly_verts, e->maxs);
794 for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3)
796 if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0];
797 if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1];
798 if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2];
799 VectorSubtract(v, e->origin, temp);
800 dist = DotProduct(temp, temp);
805 if (e->cullradius2 > radius2)
807 e->cullradius2 = radius2;
808 e->cullradius = sqrt(e->cullradius2);
810 if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius;
811 if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius;
812 if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius;
813 if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius;
814 if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius;
815 if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius;
816 // clip shadow volumes against eachother to remove unnecessary
817 // polygons(and sections of polygons)
819 //vec3_t polymins, polymaxs;
821 float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
822 float f, *v0, *v1, projectdistance;
824 e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024);
827 vec3_t outermins, outermaxs, innermins, innermaxs;
828 innermins[0] = e->mins[0] - 1;
829 innermins[1] = e->mins[1] - 1;
830 innermins[2] = e->mins[2] - 1;
831 innermaxs[0] = e->maxs[0] + 1;
832 innermaxs[1] = e->maxs[1] + 1;
833 innermaxs[2] = e->maxs[2] + 1;
834 outermins[0] = loadmodel->normalmins[0] - 1;
835 outermins[1] = loadmodel->normalmins[1] - 1;
836 outermins[2] = loadmodel->normalmins[2] - 1;
837 outermaxs[0] = loadmodel->normalmaxs[0] + 1;
838 outermaxs[1] = loadmodel->normalmaxs[1] + 1;
839 outermaxs[2] = loadmodel->normalmaxs[2] + 1;
840 // add bounding box around the whole shadow volume set,
841 // facing inward to limit light area, with an outer bounding box
842 // facing outward (this is needed by the shadow rendering method)
844 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
845 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
846 verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
847 verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
848 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
849 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
850 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
851 verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
852 verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
853 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
855 verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
856 verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
857 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
858 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
859 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
860 verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
861 verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
862 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
863 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
864 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
866 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2];
867 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2];
868 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2];
869 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2];
870 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
871 verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
872 verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
873 verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
874 verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
875 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
877 verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
878 verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
879 verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
880 verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
881 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
882 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2];
883 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2];
884 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2];
885 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2];
886 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
888 verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2];
889 verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2];
890 verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2];
891 verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2];
892 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
893 verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2];
894 verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2];
895 verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2];
896 verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2];
897 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
899 verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2];
900 verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2];
901 verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2];
902 verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2];
903 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
904 verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2];
905 verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2];
906 verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2];
907 verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2];
908 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
912 for (j = 0;j < e->numsurfaces;j++)
914 surf = e->surfaces[j];
915 if (surf->flags & SURF_SHADOWCAST)
916 surf->castshadow = castshadowcount;
918 for (j = 0;j < e->numsurfaces;j++)
920 surf = e->surfaces[j];
921 if (surf->castshadow != castshadowcount)
923 f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
924 if (surf->flags & SURF_PLANEBACK)
926 projectdistance = e->lightradius;
927 if (maxverts < surf->poly_numverts)
929 maxverts = surf->poly_numverts;
932 verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3]));
934 // copy the original polygon, for the front cap of the volume
935 for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3)
937 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
938 // project the original polygon, reversed, for the back cap of the volume
939 for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3)
941 VectorSubtract(v0, e->origin, temp);
942 VectorNormalize(temp);
943 VectorMA(v0, projectdistance, temp, v1);
945 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts);
946 // project the shadow volume sides
947 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)
949 if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount)
951 VectorCopy(v1, &verts[0]);
952 VectorCopy(v0, &verts[3]);
953 VectorCopy(v0, &verts[6]);
954 VectorCopy(v1, &verts[9]);
955 VectorSubtract(&verts[6], e->origin, temp);
956 VectorNormalize(temp);
957 VectorMA(&verts[6], projectdistance, temp, &verts[6]);
958 VectorSubtract(&verts[9], e->origin, temp);
959 VectorNormalize(temp);
960 VectorMA(&verts[9], projectdistance, temp, &verts[9]);
961 Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts);
965 // build the triangle mesh
966 e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume);
970 for (mesh = e->shadowvolume;mesh;mesh = mesh->next)
971 l += mesh->numtriangles;
972 Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l);
980 static void Mod_Q1BSP_LoadVisibility(lump_t *l)
982 loadmodel->brushq1.visdata = NULL;
985 loadmodel->brushq1.visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
986 memcpy(loadmodel->brushq1.visdata, mod_base + l->fileofs, l->filelen);
989 // used only for HalfLife maps
990 static void Mod_Q1BSP_ParseWadsFromEntityLump(const char *data)
992 char key[128], value[4096];
997 if (!COM_ParseToken(&data))
999 if (com_token[0] != '{')
1003 if (!COM_ParseToken(&data))
1005 if (com_token[0] == '}')
1006 break; // end of worldspawn
1007 if (com_token[0] == '_')
1008 strcpy(key, com_token + 1);
1010 strcpy(key, com_token);
1011 while (key[strlen(key)-1] == ' ') // remove trailing spaces
1012 key[strlen(key)-1] = 0;
1013 if (!COM_ParseToken(&data))
1015 strcpy(value, com_token);
1016 if (!strcmp("wad", key)) // for HalfLife maps
1018 if (loadmodel->brushq1.ishlbsp)
1021 for (i = 0;i < 4096;i++)
1022 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
1028 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
1029 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
1031 else if (value[i] == ';' || value[i] == 0)
1035 strcpy(wadname, "textures/");
1036 strcat(wadname, &value[j]);
1037 W_LoadTextureWadFile(wadname, false);
1049 static void Mod_Q1BSP_LoadEntities(lump_t *l)
1051 loadmodel->brush.entities = NULL;
1054 loadmodel->brush.entities = Mem_Alloc(loadmodel->mempool, l->filelen);
1055 memcpy(loadmodel->brush.entities, mod_base + l->fileofs, l->filelen);
1056 if (loadmodel->brushq1.ishlbsp)
1057 Mod_Q1BSP_ParseWadsFromEntityLump(loadmodel->brush.entities);
1061 static void Mod_Q1BSP_LoadVertexes(lump_t *l)
1067 in = (void *)(mod_base + l->fileofs);
1068 if (l->filelen % sizeof(*in))
1069 Host_Error("Mod_Q1BSP_LoadVertexes: funny lump size in %s",loadmodel->name);
1070 count = l->filelen / sizeof(*in);
1071 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1073 loadmodel->brushq1.vertexes = out;
1074 loadmodel->brushq1.numvertexes = count;
1076 for ( i=0 ; i<count ; i++, in++, out++)
1078 out->position[0] = LittleFloat(in->point[0]);
1079 out->position[1] = LittleFloat(in->point[1]);
1080 out->position[2] = LittleFloat(in->point[2]);
1084 static void Mod_Q1BSP_LoadSubmodels(lump_t *l)
1090 in = (void *)(mod_base + l->fileofs);
1091 if (l->filelen % sizeof(*in))
1092 Host_Error("Mod_Q1BSP_LoadSubmodels: funny lump size in %s",loadmodel->name);
1093 count = l->filelen / sizeof(*in);
1094 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1096 loadmodel->brushq1.submodels = out;
1097 loadmodel->brushq1.numsubmodels = count;
1099 for ( i=0 ; i<count ; i++, in++, out++)
1101 for (j=0 ; j<3 ; j++)
1103 // spread the mins / maxs by a pixel
1104 out->mins[j] = LittleFloat(in->mins[j]) - 1;
1105 out->maxs[j] = LittleFloat(in->maxs[j]) + 1;
1106 out->origin[j] = LittleFloat(in->origin[j]);
1108 for (j=0 ; j<MAX_MAP_HULLS ; j++)
1109 out->headnode[j] = LittleLong(in->headnode[j]);
1110 out->visleafs = LittleLong(in->visleafs);
1111 out->firstface = LittleLong(in->firstface);
1112 out->numfaces = LittleLong(in->numfaces);
1116 static void Mod_Q1BSP_LoadEdges(lump_t *l)
1122 in = (void *)(mod_base + l->fileofs);
1123 if (l->filelen % sizeof(*in))
1124 Host_Error("Mod_Q1BSP_LoadEdges: funny lump size in %s",loadmodel->name);
1125 count = l->filelen / sizeof(*in);
1126 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1128 loadmodel->brushq1.edges = out;
1129 loadmodel->brushq1.numedges = count;
1131 for ( i=0 ; i<count ; i++, in++, out++)
1133 out->v[0] = (unsigned short)LittleShort(in->v[0]);
1134 out->v[1] = (unsigned short)LittleShort(in->v[1]);
1138 static void Mod_Q1BSP_LoadTexinfo(lump_t *l)
1142 int i, j, k, count, miptex;
1144 in = (void *)(mod_base + l->fileofs);
1145 if (l->filelen % sizeof(*in))
1146 Host_Error("Mod_Q1BSP_LoadTexinfo: funny lump size in %s",loadmodel->name);
1147 count = l->filelen / sizeof(*in);
1148 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
1150 loadmodel->brushq1.texinfo = out;
1151 loadmodel->brushq1.numtexinfo = count;
1153 for (i = 0;i < count;i++, in++, out++)
1155 for (k = 0;k < 2;k++)
1156 for (j = 0;j < 4;j++)
1157 out->vecs[k][j] = LittleFloat(in->vecs[k][j]);
1159 miptex = LittleLong(in->miptex);
1160 out->flags = LittleLong(in->flags);
1162 out->texture = NULL;
1163 if (loadmodel->brushq1.textures)
1165 if ((unsigned int) miptex >= (unsigned int) loadmodel->brushq1.numtextures)
1166 Con_Printf("error in model \"%s\": invalid miptex index %i(of %i)\n", loadmodel->name, miptex, loadmodel->brushq1.numtextures);
1168 out->texture = loadmodel->brushq1.textures + miptex;
1170 if (out->flags & TEX_SPECIAL)
1172 // if texture chosen is NULL or the shader needs a lightmap,
1173 // force to notexture water shader
1174 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
1175 out->texture = loadmodel->brushq1.textures + (loadmodel->brushq1.numtextures - 1);
1179 // if texture chosen is NULL, force to notexture
1180 if (out->texture == NULL)
1181 out->texture = loadmodel->brushq1.textures + (loadmodel->brushq1.numtextures - 2);
1187 void BoundPoly(int numverts, float *verts, vec3_t mins, vec3_t maxs)
1192 mins[0] = mins[1] = mins[2] = 9999;
1193 maxs[0] = maxs[1] = maxs[2] = -9999;
1195 for (i = 0;i < numverts;i++)
1197 for (j = 0;j < 3;j++, v++)
1207 #define MAX_SUBDIVPOLYTRIANGLES 4096
1208 #define MAX_SUBDIVPOLYVERTS(MAX_SUBDIVPOLYTRIANGLES * 3)
1210 static int subdivpolyverts, subdivpolytriangles;
1211 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1212 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1214 static int subdivpolylookupvert(vec3_t v)
1217 for (i = 0;i < subdivpolyverts;i++)
1218 if (subdivpolyvert[i][0] == v[0]
1219 && subdivpolyvert[i][1] == v[1]
1220 && subdivpolyvert[i][2] == v[2])
1222 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1223 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1224 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1225 return subdivpolyverts++;
1228 static void SubdividePolygon(int numverts, float *verts)
1230 int i, i1, i2, i3, f, b, c, p;
1231 vec3_t mins, maxs, front[256], back[256];
1232 float m, *pv, *cv, dist[256], frac;
1235 Host_Error("SubdividePolygon: ran out of verts in buffer");
1237 BoundPoly(numverts, verts, mins, maxs);
1239 for (i = 0;i < 3;i++)
1241 m = (mins[i] + maxs[i]) * 0.5;
1242 m = r_subdivide_size.value * floor(m/r_subdivide_size.value + 0.5);
1243 if (maxs[i] - m < 8)
1245 if (m - mins[i] < 8)
1249 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1250 dist[c] = cv[i] - m;
1253 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1257 VectorCopy(pv, front[f]);
1262 VectorCopy(pv, back[b]);
1265 if (dist[p] == 0 || dist[c] == 0)
1267 if ((dist[p] > 0) != (dist[c] > 0) )
1270 frac = dist[p] / (dist[p] - dist[c]);
1271 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1272 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1273 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1279 SubdividePolygon(f, front[0]);
1280 SubdividePolygon(b, back[0]);
1284 i1 = subdivpolylookupvert(verts);
1285 i2 = subdivpolylookupvert(verts + 3);
1286 for (i = 2;i < numverts;i++)
1288 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1290 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1294 i3 = subdivpolylookupvert(verts + i * 3);
1295 subdivpolyindex[subdivpolytriangles][0] = i1;
1296 subdivpolyindex[subdivpolytriangles][1] = i2;
1297 subdivpolyindex[subdivpolytriangles][2] = i3;
1299 subdivpolytriangles++;
1303 //Breaks a polygon up along axial 64 unit
1304 //boundaries so that turbulent and sky warps
1305 //can be done reasonably.
1306 static void Mod_Q1BSP_GenerateWarpMesh(msurface_t *surf)
1312 subdivpolytriangles = 0;
1313 subdivpolyverts = 0;
1314 SubdividePolygon(surf->poly_numverts, surf->poly_verts);
1315 if (subdivpolytriangles < 1)
1316 Host_Error("Mod_Q1BSP_GenerateWarpMesh: no triangles?\n");
1318 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1319 mesh->numverts = subdivpolyverts;
1320 mesh->numtriangles = subdivpolytriangles;
1321 mesh->vertex = (surfvertex_t *)(mesh + 1);
1322 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1323 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1325 for (i = 0;i < mesh->numtriangles;i++)
1326 for (j = 0;j < 3;j++)
1327 mesh->index[i*3+j] = subdivpolyindex[i][j];
1329 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1331 VectorCopy(subdivpolyvert[i], v->v);
1332 v->st[0] = DotProduct(v->v, surf->texinfo->vecs[0]);
1333 v->st[1] = DotProduct(v->v, surf->texinfo->vecs[1]);
1338 static surfmesh_t *Mod_Q1BSP_AllocSurfMesh(int numverts, int numtriangles)
1341 mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (3 + 2 + 2 + 2 + 3 + 3 + 3 + 1) * sizeof(float));
1342 mesh->numverts = numverts;
1343 mesh->numtriangles = numtriangles;
1344 mesh->vertex3f = (float *)(mesh + 1);
1345 mesh->texcoordtexture2f = mesh->vertex3f + mesh->numverts * 3;
1346 mesh->texcoordlightmap2f = mesh->texcoordtexture2f + mesh->numverts * 2;
1347 mesh->texcoorddetail2f = mesh->texcoordlightmap2f + mesh->numverts * 2;
1348 mesh->svector3f = (float *)(mesh->texcoorddetail2f + mesh->numverts * 2);
1349 mesh->tvector3f = mesh->svector3f + mesh->numverts * 3;
1350 mesh->normal3f = mesh->tvector3f + mesh->numverts * 3;
1351 mesh->lightmapoffsets = (int *)(mesh->normal3f + mesh->numverts * 3);
1352 mesh->element3i = mesh->lightmapoffsets + mesh->numverts;
1353 mesh->neighbor3i = mesh->element3i + mesh->numtriangles * 3;
1357 static void Mod_Q1BSP_GenerateSurfacePolygon(msurface_t *surf, int firstedge, int numedges)
1360 float *vec, *vert, mins[3], maxs[3], val, *v;
1363 // convert edges back to a normal polygon
1364 surf->poly_numverts = numedges;
1365 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * numedges);
1366 for (i = 0;i < numedges;i++)
1368 lindex = loadmodel->brushq1.surfedges[firstedge + i];
1370 vec = loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[lindex].v[0]].position;
1372 vec = loadmodel->brushq1.vertexes[loadmodel->brushq1.edges[-lindex].v[1]].position;
1373 VectorCopy(vec, vert);
1377 // calculate polygon bounding box and center
1378 vert = surf->poly_verts;
1379 VectorCopy(vert, mins);
1380 VectorCopy(vert, maxs);
1382 for (i = 1;i < surf->poly_numverts;i++, vert += 3)
1384 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1385 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1386 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1388 VectorCopy(mins, surf->poly_mins);
1389 VectorCopy(maxs, surf->poly_maxs);
1390 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1391 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1392 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1394 // generate surface extents information
1395 tex = surf->texinfo;
1396 mins[0] = maxs[0] = DotProduct(surf->poly_verts, tex->vecs[0]) + tex->vecs[0][3];
1397 mins[1] = maxs[1] = DotProduct(surf->poly_verts, tex->vecs[1]) + tex->vecs[1][3];
1398 for (i = 1, v = surf->poly_verts + 3;i < surf->poly_numverts;i++, v += 3)
1400 for (j = 0;j < 2;j++)
1402 val = DotProduct(v, tex->vecs[j]) + tex->vecs[j][3];
1409 for (i = 0;i < 2;i++)
1411 surf->texturemins[i] = (int) floor(mins[i] / 16) * 16;
1412 surf->extents[i] = (int) ceil(maxs[i] / 16) * 16 - surf->texturemins[i];
1416 static void Mod_Q1BSP_LoadFaces(lump_t *l)
1420 int i, count, surfnum, planenum, ssize, tsize, firstedge, numedges, totalverts, totaltris, totalmeshes;
1424 in = (void *)(mod_base + l->fileofs);
1425 if (l->filelen % sizeof(*in))
1426 Host_Error("Mod_Q1BSP_LoadFaces: funny lump size in %s",loadmodel->name);
1427 count = l->filelen / sizeof(*in);
1428 loadmodel->brushq1.surfaces = Mem_Alloc(loadmodel->mempool, count*sizeof(msurface_t));
1430 loadmodel->brushq1.numsurfaces = count;
1431 loadmodel->brushq1.surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1432 loadmodel->brushq1.surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1433 loadmodel->brushq1.pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1435 for (surfnum = 0, surf = loadmodel->brushq1.surfaces, totalverts = 0, totaltris = 0, totalmeshes = 0;surfnum < count;surfnum++, totalverts += surf->poly_numverts, totaltris += surf->poly_numverts - 2, totalmeshes++, in++, surf++)
1437 surf->number = surfnum;
1438 // FIXME: validate edges, texinfo, etc?
1439 firstedge = LittleLong(in->firstedge);
1440 numedges = LittleShort(in->numedges);
1441 if ((unsigned int) firstedge > (unsigned int) loadmodel->brushq1.numsurfedges || (unsigned int) numedges > (unsigned int) loadmodel->brushq1.numsurfedges || (unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->brushq1.numsurfedges)
1442 Host_Error("Mod_Q1BSP_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->brushq1.numsurfedges);
1443 i = LittleShort(in->texinfo);
1444 if ((unsigned int) i >= (unsigned int) loadmodel->brushq1.numtexinfo)
1445 Host_Error("Mod_Q1BSP_LoadFaces: invalid texinfo index %i(model has %i texinfos)\n", i, loadmodel->brushq1.numtexinfo);
1446 surf->texinfo = loadmodel->brushq1.texinfo + i;
1447 surf->flags = surf->texinfo->texture->flags;
1449 planenum = LittleShort(in->planenum);
1450 if ((unsigned int) planenum >= (unsigned int) loadmodel->brushq1.numplanes)
1451 Host_Error("Mod_Q1BSP_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->brushq1.numplanes);
1453 if (LittleShort(in->side))
1454 surf->flags |= SURF_PLANEBACK;
1456 surf->plane = loadmodel->brushq1.planes + planenum;
1458 // clear lightmap (filled in later)
1459 surf->lightmaptexture = NULL;
1461 // force lightmap upload on first time seeing the surface
1462 surf->cached_dlight = true;
1464 Mod_Q1BSP_GenerateSurfacePolygon(surf, firstedge, numedges);
1466 ssize = (surf->extents[0] >> 4) + 1;
1467 tsize = (surf->extents[1] >> 4) + 1;
1470 for (i = 0;i < MAXLIGHTMAPS;i++)
1471 surf->styles[i] = in->styles[i];
1472 i = LittleLong(in->lightofs);
1474 surf->samples = NULL;
1475 else if (loadmodel->brushq1.ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1476 surf->samples = loadmodel->brushq1.lightdata + i;
1477 else // LordHavoc: white lighting (bsp version 29)
1478 surf->samples = loadmodel->brushq1.lightdata + (i * 3);
1480 if (surf->texinfo->texture->shader == &Cshader_wall_lightmap)
1482 if ((surf->extents[0] >> 4) + 1 > (256) || (surf->extents[1] >> 4) + 1 > (256))
1483 Host_Error("Bad surface extents");
1484 // stainmap for permanent marks on walls
1485 surf->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1487 memset(surf->stainsamples, 255, ssize * tsize * 3);
1491 loadmodel->brushq1.entiremesh = Mod_Q1BSP_AllocSurfMesh(totalverts, totaltris);
1492 loadmodel->brushq1.surfmeshes = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) * totalmeshes);
1494 for (surfnum = 0, surf = loadmodel->brushq1.surfaces, totalverts = 0, totaltris = 0, totalmeshes = 0;surfnum < count;surfnum++, totalverts += surf->poly_numverts, totaltris += surf->poly_numverts - 2, totalmeshes++, surf++)
1496 mesh = surf->mesh = loadmodel->brushq1.surfmeshes + totalmeshes;
1497 mesh->numverts = surf->poly_numverts;
1498 mesh->numtriangles = surf->poly_numverts - 2;
1499 mesh->vertex3f = loadmodel->brushq1.entiremesh->vertex3f + totalverts * 3;
1500 mesh->texcoordtexture2f = loadmodel->brushq1.entiremesh->texcoordtexture2f + totalverts * 2;
1501 mesh->texcoordlightmap2f = loadmodel->brushq1.entiremesh->texcoordlightmap2f + totalverts * 2;
1502 mesh->texcoorddetail2f = loadmodel->brushq1.entiremesh->texcoorddetail2f + totalverts * 2;
1503 mesh->svector3f = loadmodel->brushq1.entiremesh->svector3f + totalverts * 3;
1504 mesh->tvector3f = loadmodel->brushq1.entiremesh->tvector3f + totalverts * 3;
1505 mesh->normal3f = loadmodel->brushq1.entiremesh->normal3f + totalverts * 3;
1506 mesh->lightmapoffsets = loadmodel->brushq1.entiremesh->lightmapoffsets + totalverts;
1507 mesh->element3i = loadmodel->brushq1.entiremesh->element3i + totaltris * 3;
1508 mesh->neighbor3i = loadmodel->brushq1.entiremesh->neighbor3i + totaltris * 3;
1510 surf->lightmaptexturestride = 0;
1511 surf->lightmaptexture = NULL;
1513 for (i = 0;i < mesh->numverts;i++)
1515 mesh->vertex3f[i * 3 + 0] = surf->poly_verts[i * 3 + 0];
1516 mesh->vertex3f[i * 3 + 1] = surf->poly_verts[i * 3 + 1];
1517 mesh->vertex3f[i * 3 + 2] = surf->poly_verts[i * 3 + 2];
1518 s = DotProduct((mesh->vertex3f + i * 3), surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1519 t = DotProduct((mesh->vertex3f + i * 3), surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1520 mesh->texcoordtexture2f[i * 2 + 0] = s / surf->texinfo->texture->width;
1521 mesh->texcoordtexture2f[i * 2 + 1] = t / surf->texinfo->texture->height;
1522 mesh->texcoorddetail2f[i * 2 + 0] = s * (1.0f / 16.0f);
1523 mesh->texcoorddetail2f[i * 2 + 1] = t * (1.0f / 16.0f);
1524 mesh->texcoordlightmap2f[i * 2 + 0] = 0;
1525 mesh->texcoordlightmap2f[i * 2 + 1] = 0;
1526 mesh->lightmapoffsets[i] = 0;
1529 for (i = 0;i < mesh->numtriangles;i++)
1531 mesh->element3i[i * 3 + 0] = 0;
1532 mesh->element3i[i * 3 + 1] = i + 1;
1533 mesh->element3i[i * 3 + 2] = i + 2;
1536 Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles);
1537 Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->vertex3f, mesh->texcoordtexture2f, mesh->element3i, mesh->svector3f, mesh->tvector3f, mesh->normal3f);
1539 if (surf->texinfo->texture->shader == &Cshader_wall_lightmap)
1541 int i, iu, iv, smax, tmax;
1542 float u, v, ubase, vbase, uscale, vscale;
1544 smax = surf->extents[0] >> 4;
1545 tmax = surf->extents[1] >> 4;
1547 surf->flags |= SURF_LIGHTMAP;
1548 if (r_miplightmaps.integer)
1550 surf->lightmaptexturestride = smax+1;
1551 surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
1555 surf->lightmaptexturestride = R_CompatibleFragmentWidth(smax+1, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1556 surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->brushq1.lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL);
1558 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1559 uscale = (uscale - ubase) / (smax + 1);
1560 vscale = (vscale - vbase) / (tmax + 1);
1562 for (i = 0;i < mesh->numverts;i++)
1564 u = ((DotProduct((mesh->vertex3f + i * 3), surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1565 v = ((DotProduct((mesh->vertex3f + i * 3), surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1566 mesh->texcoordlightmap2f[i * 2 + 0] = u * uscale + ubase;
1567 mesh->texcoordlightmap2f[i * 2 + 1] = v * vscale + vbase;
1568 // LordHavoc: calc lightmap data offset for vertex lighting to use
1571 mesh->lightmapoffsets[i] = (bound(0, iv, tmax) * (smax+1) + bound(0, iu, smax)) * 3;
1577 static void Mod_Q1BSP_SetParent(mnode_t *node, mnode_t *parent)
1579 node->parent = parent;
1580 if (node->contents < 0)
1582 Mod_Q1BSP_SetParent(node->children[0], node);
1583 Mod_Q1BSP_SetParent(node->children[1], node);
1586 static void Mod_Q1BSP_LoadNodes(lump_t *l)
1592 in = (void *)(mod_base + l->fileofs);
1593 if (l->filelen % sizeof(*in))
1594 Host_Error("Mod_Q1BSP_LoadNodes: funny lump size in %s",loadmodel->name);
1595 count = l->filelen / sizeof(*in);
1596 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1598 loadmodel->brushq1.nodes = out;
1599 loadmodel->brushq1.numnodes = count;
1601 for ( i=0 ; i<count ; i++, in++, out++)
1603 for (j=0 ; j<3 ; j++)
1605 out->mins[j] = LittleShort(in->mins[j]);
1606 out->maxs[j] = LittleShort(in->maxs[j]);
1609 p = LittleLong(in->planenum);
1610 out->plane = loadmodel->brushq1.planes + p;
1612 out->firstsurface = LittleShort(in->firstface);
1613 out->numsurfaces = LittleShort(in->numfaces);
1615 for (j=0 ; j<2 ; j++)
1617 p = LittleShort(in->children[j]);
1619 out->children[j] = loadmodel->brushq1.nodes + p;
1621 out->children[j] = (mnode_t *)(loadmodel->brushq1.leafs + (-1 - p));
1625 Mod_Q1BSP_SetParent(loadmodel->brushq1.nodes, NULL); // sets nodes and leafs
1628 static void Mod_Q1BSP_LoadLeafs(lump_t *l)
1634 in = (void *)(mod_base + l->fileofs);
1635 if (l->filelen % sizeof(*in))
1636 Host_Error("Mod_Q1BSP_LoadLeafs: funny lump size in %s",loadmodel->name);
1637 count = l->filelen / sizeof(*in);
1638 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1640 loadmodel->brushq1.leafs = out;
1641 loadmodel->brushq1.numleafs = count;
1643 for ( i=0 ; i<count ; i++, in++, out++)
1645 for (j=0 ; j<3 ; j++)
1647 out->mins[j] = LittleShort(in->mins[j]);
1648 out->maxs[j] = LittleShort(in->maxs[j]);
1651 p = LittleLong(in->contents);
1654 out->firstmarksurface = loadmodel->brushq1.marksurfaces +
1655 LittleShort(in->firstmarksurface);
1656 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1658 p = LittleLong(in->visofs);
1660 out->compressed_vis = NULL;
1662 out->compressed_vis = loadmodel->brushq1.visdata + p;
1664 for (j=0 ; j<4 ; j++)
1665 out->ambient_sound_level[j] = in->ambient_level[j];
1667 // FIXME: Insert caustics here
1671 static void Mod_Q1BSP_LoadClipnodes(lump_t *l)
1673 dclipnode_t *in, *out;
1677 in = (void *)(mod_base + l->fileofs);
1678 if (l->filelen % sizeof(*in))
1679 Host_Error("Mod_Q1BSP_LoadClipnodes: funny lump size in %s",loadmodel->name);
1680 count = l->filelen / sizeof(*in);
1681 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1683 loadmodel->brushq1.clipnodes = out;
1684 loadmodel->brushq1.numclipnodes = count;
1686 if (loadmodel->brushq1.ishlbsp)
1688 hull = &loadmodel->brushq1.hulls[1];
1689 hull->clipnodes = out;
1690 hull->firstclipnode = 0;
1691 hull->lastclipnode = count-1;
1692 hull->planes = loadmodel->brushq1.planes;
1693 hull->clip_mins[0] = -16;
1694 hull->clip_mins[1] = -16;
1695 hull->clip_mins[2] = -36;
1696 hull->clip_maxs[0] = 16;
1697 hull->clip_maxs[1] = 16;
1698 hull->clip_maxs[2] = 36;
1699 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1701 hull = &loadmodel->brushq1.hulls[2];
1702 hull->clipnodes = out;
1703 hull->firstclipnode = 0;
1704 hull->lastclipnode = count-1;
1705 hull->planes = loadmodel->brushq1.planes;
1706 hull->clip_mins[0] = -32;
1707 hull->clip_mins[1] = -32;
1708 hull->clip_mins[2] = -32;
1709 hull->clip_maxs[0] = 32;
1710 hull->clip_maxs[1] = 32;
1711 hull->clip_maxs[2] = 32;
1712 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1714 hull = &loadmodel->brushq1.hulls[3];
1715 hull->clipnodes = out;
1716 hull->firstclipnode = 0;
1717 hull->lastclipnode = count-1;
1718 hull->planes = loadmodel->brushq1.planes;
1719 hull->clip_mins[0] = -16;
1720 hull->clip_mins[1] = -16;
1721 hull->clip_mins[2] = -18;
1722 hull->clip_maxs[0] = 16;
1723 hull->clip_maxs[1] = 16;
1724 hull->clip_maxs[2] = 18;
1725 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1729 hull = &loadmodel->brushq1.hulls[1];
1730 hull->clipnodes = out;
1731 hull->firstclipnode = 0;
1732 hull->lastclipnode = count-1;
1733 hull->planes = loadmodel->brushq1.planes;
1734 hull->clip_mins[0] = -16;
1735 hull->clip_mins[1] = -16;
1736 hull->clip_mins[2] = -24;
1737 hull->clip_maxs[0] = 16;
1738 hull->clip_maxs[1] = 16;
1739 hull->clip_maxs[2] = 32;
1740 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1742 hull = &loadmodel->brushq1.hulls[2];
1743 hull->clipnodes = out;
1744 hull->firstclipnode = 0;
1745 hull->lastclipnode = count-1;
1746 hull->planes = loadmodel->brushq1.planes;
1747 hull->clip_mins[0] = -32;
1748 hull->clip_mins[1] = -32;
1749 hull->clip_mins[2] = -24;
1750 hull->clip_maxs[0] = 32;
1751 hull->clip_maxs[1] = 32;
1752 hull->clip_maxs[2] = 64;
1753 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1756 for (i=0 ; i<count ; i++, out++, in++)
1758 out->planenum = LittleLong(in->planenum);
1759 out->children[0] = LittleShort(in->children[0]);
1760 out->children[1] = LittleShort(in->children[1]);
1761 if (out->children[0] >= count || out->children[1] >= count)
1762 Host_Error("Corrupt clipping hull(out of range child)\n");
1766 //Duplicate the drawing hull structure as a clipping hull
1767 static void Mod_Q1BSP_MakeHull0(void)
1774 hull = &loadmodel->brushq1.hulls[0];
1776 in = loadmodel->brushq1.nodes;
1777 out = Mem_Alloc(loadmodel->mempool, loadmodel->brushq1.numnodes * sizeof(dclipnode_t));
1779 hull->clipnodes = out;
1780 hull->firstclipnode = 0;
1781 hull->lastclipnode = loadmodel->brushq1.numnodes - 1;
1782 hull->planes = loadmodel->brushq1.planes;
1784 for (i = 0;i < loadmodel->brushq1.numnodes;i++, out++, in++)
1786 out->planenum = in->plane - loadmodel->brushq1.planes;
1787 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->brushq1.nodes;
1788 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->brushq1.nodes;
1792 static void Mod_Q1BSP_LoadMarksurfaces(lump_t *l)
1797 in = (void *)(mod_base + l->fileofs);
1798 if (l->filelen % sizeof(*in))
1799 Host_Error("Mod_Q1BSP_LoadMarksurfaces: funny lump size in %s",loadmodel->name);
1800 loadmodel->brushq1.nummarksurfaces = l->filelen / sizeof(*in);
1801 loadmodel->brushq1.marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->brushq1.nummarksurfaces * sizeof(int));
1803 for (i = 0;i < loadmodel->brushq1.nummarksurfaces;i++)
1805 j = (unsigned) LittleShort(in[i]);
1806 if (j >= loadmodel->brushq1.numsurfaces)
1807 Host_Error("Mod_Q1BSP_LoadMarksurfaces: bad surface number");
1808 loadmodel->brushq1.marksurfaces[i] = j;
1812 static void Mod_Q1BSP_LoadSurfedges(lump_t *l)
1817 in = (void *)(mod_base + l->fileofs);
1818 if (l->filelen % sizeof(*in))
1819 Host_Error("Mod_Q1BSP_LoadSurfedges: funny lump size in %s",loadmodel->name);
1820 loadmodel->brushq1.numsurfedges = l->filelen / sizeof(*in);
1821 loadmodel->brushq1.surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->brushq1.numsurfedges * sizeof(int));
1823 for (i = 0;i < loadmodel->brushq1.numsurfedges;i++)
1824 loadmodel->brushq1.surfedges[i] = LittleLong(in[i]);
1828 static void Mod_Q1BSP_LoadPlanes(lump_t *l)
1834 in = (void *)(mod_base + l->fileofs);
1835 if (l->filelen % sizeof(*in))
1836 Host_Error("Mod_Q1BSP_LoadPlanes: funny lump size in %s", loadmodel->name);
1838 loadmodel->brushq1.numplanes = l->filelen / sizeof(*in);
1839 loadmodel->brushq1.planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->brushq1.numplanes * sizeof(*out));
1841 for (i = 0;i < loadmodel->brushq1.numplanes;i++, in++, out++)
1843 out->normal[0] = LittleFloat(in->normal[0]);
1844 out->normal[1] = LittleFloat(in->normal[1]);
1845 out->normal[2] = LittleFloat(in->normal[2]);
1846 out->dist = LittleFloat(in->dist);
1852 #define MAX_POINTS_ON_WINDING 64
1858 double points[8][3]; // variable sized
1867 static winding_t *NewWinding(int points)
1872 if (points > MAX_POINTS_ON_WINDING)
1873 Sys_Error("NewWinding: too many points\n");
1875 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
1876 w = Mem_Alloc(loadmodel->mempool, size);
1882 static void FreeWinding(winding_t *w)
1892 static winding_t *BaseWindingForPlane(mplane_t *p)
1894 double org[3], vright[3], vup[3], normal[3];
1897 VectorCopy(p->normal, normal);
1898 VectorVectorsDouble(normal, vright, vup);
1900 VectorScale(vup, 1024.0*1024.0*1024.0, vup);
1901 VectorScale(vright, 1024.0*1024.0*1024.0, vright);
1903 // project a really big axis aligned box onto the plane
1906 VectorScale(p->normal, p->dist, org);
1908 VectorSubtract(org, vright, w->points[0]);
1909 VectorAdd(w->points[0], vup, w->points[0]);
1911 VectorAdd(org, vright, w->points[1]);
1912 VectorAdd(w->points[1], vup, w->points[1]);
1914 VectorAdd(org, vright, w->points[2]);
1915 VectorSubtract(w->points[2], vup, w->points[2]);
1917 VectorSubtract(org, vright, w->points[3]);
1918 VectorSubtract(w->points[3], vup, w->points[3]);
1929 Clips the winding to the plane, returning the new winding on the positive side
1930 Frees the input winding.
1931 If keepon is true, an exactly on-plane winding will be saved, otherwise
1932 it will be clipped away.
1935 static winding_t *ClipWinding(winding_t *in, mplane_t *split, int keepon)
1937 double dists[MAX_POINTS_ON_WINDING + 1];
1938 int sides[MAX_POINTS_ON_WINDING + 1];
1947 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1949 // determine sides for each point
1950 for (i = 0;i < in->numpoints;i++)
1952 dists[i] = dot = DotProduct(in->points[i], split->normal) - split->dist;
1953 if (dot > ON_EPSILON)
1954 sides[i] = SIDE_FRONT;
1955 else if (dot < -ON_EPSILON)
1956 sides[i] = SIDE_BACK;
1961 sides[i] = sides[0];
1962 dists[i] = dists[0];
1964 if (keepon && !counts[0] && !counts[1])
1975 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1976 if (maxpts > MAX_POINTS_ON_WINDING)
1977 Sys_Error("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1979 neww = NewWinding(maxpts);
1981 for (i = 0;i < in->numpoints;i++)
1983 if (neww->numpoints >= maxpts)
1984 Sys_Error("ClipWinding: points exceeded estimate");
1988 if (sides[i] == SIDE_ON)
1990 VectorCopy(p1, neww->points[neww->numpoints]);
1995 if (sides[i] == SIDE_FRONT)
1997 VectorCopy(p1, neww->points[neww->numpoints]);
2001 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2004 // generate a split point
2005 p2 = in->points[(i+1)%in->numpoints];
2007 dot = dists[i] / (dists[i]-dists[i+1]);
2008 for (j = 0;j < 3;j++)
2009 { // avoid round off error when possible
2010 if (split->normal[j] == 1)
2011 mid[j] = split->dist;
2012 else if (split->normal[j] == -1)
2013 mid[j] = -split->dist;
2015 mid[j] = p1[j] + dot* (p2[j]-p1[j]);
2018 VectorCopy(mid, neww->points[neww->numpoints]);
2022 // free the original winding
2033 Divides a winding by a plane, producing one or two windings. The
2034 original winding is not damaged or freed. If only on one side, the
2035 returned winding will be the input winding. If on both sides, two
2036 new windings will be created.
2039 static void DivideWinding(winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
2041 double dists[MAX_POINTS_ON_WINDING + 1];
2042 int sides[MAX_POINTS_ON_WINDING + 1];
2051 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
2053 // determine sides for each point
2054 for (i = 0;i < in->numpoints;i++)
2056 dot = DotProduct(in->points[i], split->normal);
2059 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
2060 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
2061 else sides[i] = SIDE_ON;
2064 sides[i] = sides[0];
2065 dists[i] = dists[0];
2067 *front = *back = NULL;
2080 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
2082 if (maxpts > MAX_POINTS_ON_WINDING)
2083 Sys_Error("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
2085 *front = f = NewWinding(maxpts);
2086 *back = b = NewWinding(maxpts);
2088 for (i = 0;i < in->numpoints;i++)
2090 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
2091 Sys_Error("DivideWinding: points exceeded estimate");
2095 if (sides[i] == SIDE_ON)
2097 VectorCopy(p1, f->points[f->numpoints]);
2099 VectorCopy(p1, b->points[b->numpoints]);
2104 if (sides[i] == SIDE_FRONT)
2106 VectorCopy(p1, f->points[f->numpoints]);
2109 else if (sides[i] == SIDE_BACK)
2111 VectorCopy(p1, b->points[b->numpoints]);
2115 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2118 // generate a split point
2119 p2 = in->points[(i+1)%in->numpoints];
2121 dot = dists[i] / (dists[i]-dists[i+1]);
2122 for (j = 0;j < 3;j++)
2123 { // avoid round off error when possible
2124 if (split->normal[j] == 1)
2125 mid[j] = split->dist;
2126 else if (split->normal[j] == -1)
2127 mid[j] = -split->dist;
2129 mid[j] = p1[j] + dot* (p2[j]-p1[j]);
2132 VectorCopy(mid, f->points[f->numpoints]);
2134 VectorCopy(mid, b->points[b->numpoints]);
2139 typedef struct portal_s
2142 mnode_t *nodes[2]; // [0] = front side of plane
2143 struct portal_s *next[2];
2145 struct portal_s *chain; // all portals are linked into a list
2149 static portal_t *portalchain;
2156 static portal_t *AllocPortal(void)
2159 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2160 p->chain = portalchain;
2165 static void FreePortal(portal_t *p)
2170 static void Mod_Q1BSP_RecursiveRecalcNodeBBox(mnode_t *node)
2172 // calculate children first
2173 if (node->children[0]->contents >= 0)
2174 Mod_Q1BSP_RecursiveRecalcNodeBBox(node->children[0]);
2175 if (node->children[1]->contents >= 0)
2176 Mod_Q1BSP_RecursiveRecalcNodeBBox(node->children[1]);
2178 // make combined bounding box from children
2179 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2180 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2181 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2182 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2183 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2184 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2187 static void Mod_Q1BSP_FinalizePortals(void)
2189 int i, j, numportals, numpoints;
2190 portal_t *p, *pnext;
2193 mleaf_t *leaf, *endleaf;
2196 // recalculate bounding boxes for all leafs(because qbsp is very sloppy)
2197 leaf = loadmodel->brushq1.leafs;
2198 endleaf = leaf + loadmodel->brushq1.numleafs;
2199 for (;leaf < endleaf;leaf++)
2201 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2202 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2209 for (i = 0;i < 2;i++)
2211 leaf = (mleaf_t *)p->nodes[i];
2213 for (j = 0;j < w->numpoints;j++)
2215 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2216 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2217 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2218 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2219 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2220 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2227 Mod_Q1BSP_RecursiveRecalcNodeBBox(loadmodel->brushq1.nodes);
2229 // tally up portal and point counts
2235 // note: this check must match the one below or it will usually corrupt memory
2236 // 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
2237 if (p->winding && p->nodes[0] != p->nodes[1]
2238 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2239 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2242 numpoints += p->winding->numpoints * 2;
2246 loadmodel->brushq1.portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2247 loadmodel->brushq1.numportals = numportals;
2248 loadmodel->brushq1.portalpoints = (void *)((qbyte *) loadmodel->brushq1.portals + numportals * sizeof(mportal_t));
2249 loadmodel->brushq1.numportalpoints = numpoints;
2250 // clear all leaf portal chains
2251 for (i = 0;i < loadmodel->brushq1.numleafs;i++)
2252 loadmodel->brushq1.leafs[i].portals = NULL;
2253 // process all portals in the global portal chain, while freeing them
2254 portal = loadmodel->brushq1.portals;
2255 point = loadmodel->brushq1.portalpoints;
2264 // note: this check must match the one above or it will usually corrupt memory
2265 // 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
2266 if (p->nodes[0] != p->nodes[1]
2267 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2268 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2270 // first make the back to front portal(forward portal)
2271 portal->points = point;
2272 portal->numpoints = p->winding->numpoints;
2273 portal->plane.dist = p->plane.dist;
2274 VectorCopy(p->plane.normal, portal->plane.normal);
2275 portal->here = (mleaf_t *)p->nodes[1];
2276 portal->past = (mleaf_t *)p->nodes[0];
2278 for (j = 0;j < portal->numpoints;j++)
2280 VectorCopy(p->winding->points[j], point->position);
2283 PlaneClassify(&portal->plane);
2285 // link into leaf's portal chain
2286 portal->next = portal->here->portals;
2287 portal->here->portals = portal;
2289 // advance to next portal
2292 // then make the front to back portal(backward portal)
2293 portal->points = point;
2294 portal->numpoints = p->winding->numpoints;
2295 portal->plane.dist = -p->plane.dist;
2296 VectorNegate(p->plane.normal, portal->plane.normal);
2297 portal->here = (mleaf_t *)p->nodes[0];
2298 portal->past = (mleaf_t *)p->nodes[1];
2300 for (j = portal->numpoints - 1;j >= 0;j--)
2302 VectorCopy(p->winding->points[j], point->position);
2305 PlaneClassify(&portal->plane);
2307 // link into leaf's portal chain
2308 portal->next = portal->here->portals;
2309 portal->here->portals = portal;
2311 // advance to next portal
2314 FreeWinding(p->winding);
2326 static void AddPortalToNodes(portal_t *p, mnode_t *front, mnode_t *back)
2329 Host_Error("AddPortalToNodes: NULL front node");
2331 Host_Error("AddPortalToNodes: NULL back node");
2332 if (p->nodes[0] || p->nodes[1])
2333 Host_Error("AddPortalToNodes: already included");
2334 // 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
2336 p->nodes[0] = front;
2337 p->next[0] = (portal_t *)front->portals;
2338 front->portals = (mportal_t *)p;
2341 p->next[1] = (portal_t *)back->portals;
2342 back->portals = (mportal_t *)p;
2347 RemovePortalFromNode
2350 static void RemovePortalFromNodes(portal_t *portal)
2354 void **portalpointer;
2356 for (i = 0;i < 2;i++)
2358 node = portal->nodes[i];
2360 portalpointer = (void **) &node->portals;
2365 Host_Error("RemovePortalFromNodes: portal not in leaf");
2369 if (portal->nodes[0] == node)
2371 *portalpointer = portal->next[0];
2372 portal->nodes[0] = NULL;
2374 else if (portal->nodes[1] == node)
2376 *portalpointer = portal->next[1];
2377 portal->nodes[1] = NULL;
2380 Host_Error("RemovePortalFromNodes: portal not bounding leaf");
2384 if (t->nodes[0] == node)
2385 portalpointer = (void **) &t->next[0];
2386 else if (t->nodes[1] == node)
2387 portalpointer = (void **) &t->next[1];
2389 Host_Error("RemovePortalFromNodes: portal not bounding leaf");
2394 static void Mod_Q1BSP_RecursiveNodePortals(mnode_t *node)
2397 mnode_t *front, *back, *other_node;
2398 mplane_t clipplane, *plane;
2399 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2400 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2402 // if a leaf, we're done
2406 plane = node->plane;
2408 front = node->children[0];
2409 back = node->children[1];
2411 Host_Error("Mod_Q1BSP_RecursiveNodePortals: corrupt node hierarchy");
2413 // create the new portal by generating a polygon for the node plane,
2414 // and clipping it by all of the other portals(which came from nodes above this one)
2415 nodeportal = AllocPortal();
2416 nodeportal->plane = *node->plane;
2418 nodeportalwinding = BaseWindingForPlane(node->plane);
2419 side = 0; // shut up compiler warning
2420 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2422 clipplane = portal->plane;
2423 if (portal->nodes[0] == portal->nodes[1])
2424 Host_Error("Mod_Q1BSP_RecursiveNodePortals: portal has same node on both sides(1)");
2425 if (portal->nodes[0] == node)
2427 else if (portal->nodes[1] == node)
2429 clipplane.dist = -clipplane.dist;
2430 VectorNegate(clipplane.normal, clipplane.normal);
2434 Host_Error("Mod_Q1BSP_RecursiveNodePortals: mislinked portal");
2436 nodeportalwinding = ClipWinding(nodeportalwinding, &clipplane, true);
2437 if (!nodeportalwinding)
2439 Con_Printf("Mod_Q1BSP_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2444 if (nodeportalwinding)
2446 // if the plane was not clipped on all sides, there was an error
2447 nodeportal->winding = nodeportalwinding;
2448 AddPortalToNodes(nodeportal, front, back);
2451 // split the portals of this node along this node's plane and assign them to the children of this node
2452 // (migrating the portals downward through the tree)
2453 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2455 if (portal->nodes[0] == portal->nodes[1])
2456 Host_Error("Mod_Q1BSP_RecursiveNodePortals: portal has same node on both sides(2)");
2457 if (portal->nodes[0] == node)
2459 else if (portal->nodes[1] == node)
2462 Host_Error("Mod_Q1BSP_RecursiveNodePortals: mislinked portal");
2463 nextportal = portal->next[side];
2465 other_node = portal->nodes[!side];
2466 RemovePortalFromNodes(portal);
2468 // cut the portal into two portals, one on each side of the node plane
2469 DivideWinding(portal->winding, plane, &frontwinding, &backwinding);
2474 AddPortalToNodes(portal, back, other_node);
2476 AddPortalToNodes(portal, other_node, back);
2482 AddPortalToNodes(portal, front, other_node);
2484 AddPortalToNodes(portal, other_node, front);
2488 // the winding is split
2489 splitportal = AllocPortal();
2490 temp = splitportal->chain;
2491 *splitportal = *portal;
2492 splitportal->chain = temp;
2493 splitportal->winding = backwinding;
2494 FreeWinding(portal->winding);
2495 portal->winding = frontwinding;
2499 AddPortalToNodes(portal, front, other_node);
2500 AddPortalToNodes(splitportal, back, other_node);
2504 AddPortalToNodes(portal, other_node, front);
2505 AddPortalToNodes(splitportal, other_node, back);
2509 Mod_Q1BSP_RecursiveNodePortals(front);
2510 Mod_Q1BSP_RecursiveNodePortals(back);
2514 static void Mod_Q1BSP_MakePortals(void)
2517 Mod_Q1BSP_RecursiveNodePortals(loadmodel->brushq1.nodes);
2518 Mod_Q1BSP_FinalizePortals();
2521 static void Mod_Q1BSP_BuildSurfaceNeighbors(msurface_t *surfaces, int numsurfaces, mempool_t *mempool)
2524 int surfnum, vertnum, vertnum2, snum, vnum, vnum2;
2525 msurface_t *surf, *s;
2526 float *v0, *v1, *v2, *v3;
2527 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2528 surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *));
2529 for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++)
2531 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)
2533 if (surf->neighborsurfaces[vertnum])
2535 surf->neighborsurfaces[vertnum] = NULL;
2536 for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++)
2538 if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1)
2539 || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1)
2540 || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1)
2543 for (vnum = 0;vnum < s->poly_numverts;vnum++)
2544 if (s->neighborsurfaces[vnum] == surf)
2546 if (vnum < s->poly_numverts)
2548 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)
2550 if (s->neighborsurfaces[vnum] == NULL
2551 && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2])
2552 || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2])))
2554 surf->neighborsurfaces[vertnum] = s;
2555 s->neighborsurfaces[vnum] = surf;
2559 if (vnum < s->poly_numverts)
2567 static void Mod_Q1BSP_BuildLightmapUpdateChains(mempool_t *mempool, model_t *model)
2569 int i, j, stylecounts[256], totalcount, remapstyles[256];
2571 memset(stylecounts, 0, sizeof(stylecounts));
2572 for (i = 0;i < model->brushq1.nummodelsurfaces;i++)
2574 surf = model->brushq1.surfaces + model->brushq1.firstmodelsurface + i;
2575 for (j = 0;j < MAXLIGHTMAPS;j++)
2576 stylecounts[surf->styles[j]]++;
2579 model->brushq1.light_styles = 0;
2580 for (i = 0;i < 255;i++)
2584 remapstyles[i] = model->brushq1.light_styles++;
2585 totalcount += stylecounts[i] + 1;
2590 model->brushq1.light_style = Mem_Alloc(mempool, model->brushq1.light_styles * sizeof(qbyte));
2591 model->brushq1.light_stylevalue = Mem_Alloc(mempool, model->brushq1.light_styles * sizeof(int));
2592 model->brushq1.light_styleupdatechains = Mem_Alloc(mempool, model->brushq1.light_styles * sizeof(msurface_t **));
2593 model->brushq1.light_styleupdatechainsbuffer = Mem_Alloc(mempool, totalcount * sizeof(msurface_t *));
2594 model->brushq1.light_styles = 0;
2595 for (i = 0;i < 255;i++)
2597 model->brushq1.light_style[model->brushq1.light_styles++] = i;
2599 for (i = 0;i < model->brushq1.light_styles;i++)
2601 model->brushq1.light_styleupdatechains[i] = model->brushq1.light_styleupdatechainsbuffer + j;
2602 j += stylecounts[model->brushq1.light_style[i]] + 1;
2604 for (i = 0;i < model->brushq1.nummodelsurfaces;i++)
2606 surf = model->brushq1.surfaces + model->brushq1.firstmodelsurface + i;
2607 for (j = 0;j < MAXLIGHTMAPS;j++)
2608 if (surf->styles[j] != 255)
2609 *model->brushq1.light_styleupdatechains[remapstyles[surf->styles[j]]]++ = surf;
2612 for (i = 0;i < model->brushq1.light_styles;i++)
2614 *model->brushq1.light_styleupdatechains[i] = NULL;
2615 model->brushq1.light_styleupdatechains[i] = model->brushq1.light_styleupdatechainsbuffer + j;
2616 j += stylecounts[model->brushq1.light_style[i]] + 1;
2620 static void Mod_Q1BSP_BuildPVSTextureChains(model_t *model)
2623 for (i = 0;i < model->brushq1.numtextures;i++)
2624 model->brushq1.pvstexturechainslength[i] = 0;
2625 for (i = 0, j = model->brushq1.firstmodelsurface;i < model->brushq1.nummodelsurfaces;i++, j++)
2627 if (model->brushq1.surfacepvsframes[j] == model->brushq1.pvsframecount)
2629 model->brushq1.pvssurflist[model->brushq1.pvssurflistlength++] = j;
2630 model->brushq1.pvstexturechainslength[model->brushq1.surfaces[j].texinfo->texture->number]++;
2633 for (i = 0, j = 0;i < model->brushq1.numtextures;i++)
2635 if (model->brushq1.pvstexturechainslength[i])
2637 model->brushq1.pvstexturechains[i] = model->brushq1.pvstexturechainsbuffer + j;
2638 j += model->brushq1.pvstexturechainslength[i] + 1;
2641 model->brushq1.pvstexturechains[i] = NULL;
2643 for (i = 0, j = model->brushq1.firstmodelsurface;i < model->brushq1.nummodelsurfaces;i++, j++)
2644 if (model->brushq1.surfacepvsframes[j] == model->brushq1.pvsframecount)
2645 *model->brushq1.pvstexturechains[model->brushq1.surfaces[j].texinfo->texture->number]++ = model->brushq1.surfaces + j;
2646 for (i = 0;i < model->brushq1.numtextures;i++)
2648 if (model->brushq1.pvstexturechainslength[i])
2650 *model->brushq1.pvstexturechains[i] = NULL;
2651 model->brushq1.pvstexturechains[i] -= model->brushq1.pvstexturechainslength[i];
2656 extern void R_Model_Brush_DrawSky(entity_render_t *ent);
2657 extern void R_Model_Brush_Draw(entity_render_t *ent);
2658 extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius);
2659 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);
2660 void Mod_Q1BSP_Load(model_t *mod, void *buffer)
2665 mempool_t *mainmempool;
2667 model_t *originalloadmodel;
2668 float dist, modelyawradius, modelradius, *vec;
2672 mod->type = mod_brush;
2674 header = (dheader_t *)buffer;
2676 i = LittleLong(header->version);
2677 if (i != BSPVERSION && i != 30)
2678 Host_Error("Mod_Q1BSP_Load: %s has wrong version number(%i should be %i(Quake) or 30(HalfLife))", mod->name, i, BSPVERSION);
2679 mod->brushq1.ishlbsp = i == 30;
2681 mod->brushq1.FindNonSolidLocation = Mod_Q1BSP_FindNonSolidLocation;
2682 mod->brushq1.PointInLeaf = Mod_Q1BSP_PointInLeaf;
2683 mod->brushq1.PointContents = Mod_Q1BSP_PointContents;
2684 mod->brushq1.LeafPVS = Mod_Q1BSP_LeafPVS;
2685 mod->brushq1.BuildPVSTextureChains = Mod_Q1BSP_BuildPVSTextureChains;
2687 if (loadmodel->isworldmodel)
2689 Cvar_SetValue("halflifebsp", mod->brushq1.ishlbsp);
2690 // until we get a texture for it...
2694 // swap all the lumps
2695 mod_base = (qbyte *)header;
2697 for (i = 0;i < (int) sizeof(dheader_t) / 4;i++)
2698 ((int *)header)[i] = LittleLong(((int *)header)[i]);
2702 // store which lightmap format to use
2703 mod->brushq1.lightmaprgba = r_lightmaprgba.integer;
2705 Mod_Q1BSP_LoadEntities(&header->lumps[LUMP_ENTITIES]);
2706 Mod_Q1BSP_LoadVertexes(&header->lumps[LUMP_VERTEXES]);
2707 Mod_Q1BSP_LoadEdges(&header->lumps[LUMP_EDGES]);
2708 Mod_Q1BSP_LoadSurfedges(&header->lumps[LUMP_SURFEDGES]);
2709 Mod_Q1BSP_LoadTextures(&header->lumps[LUMP_TEXTURES]);
2710 Mod_Q1BSP_LoadLighting(&header->lumps[LUMP_LIGHTING]);
2711 Mod_Q1BSP_LoadPlanes(&header->lumps[LUMP_PLANES]);
2712 Mod_Q1BSP_LoadTexinfo(&header->lumps[LUMP_TEXINFO]);
2713 Mod_Q1BSP_LoadFaces(&header->lumps[LUMP_FACES]);
2714 Mod_Q1BSP_LoadMarksurfaces(&header->lumps[LUMP_MARKSURFACES]);
2715 Mod_Q1BSP_LoadVisibility(&header->lumps[LUMP_VISIBILITY]);
2716 Mod_Q1BSP_LoadLeafs(&header->lumps[LUMP_LEAFS]);
2717 Mod_Q1BSP_LoadNodes(&header->lumps[LUMP_NODES]);
2718 Mod_Q1BSP_LoadClipnodes(&header->lumps[LUMP_CLIPNODES]);
2719 Mod_Q1BSP_LoadSubmodels(&header->lumps[LUMP_MODELS]);
2721 Mod_Q1BSP_MakeHull0();
2722 Mod_Q1BSP_MakePortals();
2724 mod->numframes = 2; // regular and alternate animation
2726 mainmempool = mod->mempool;
2727 loadname = mod->name;
2729 Mod_Q1BSP_LoadLightList();
2730 originalloadmodel = loadmodel;
2733 // set up the submodels(FIXME: this is confusing)
2735 for (i = 0;i < mod->brushq1.numsubmodels;i++)
2737 bm = &mod->brushq1.submodels[i];
2739 mod->brushq1.hulls[0].firstclipnode = bm->headnode[0];
2740 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2742 mod->brushq1.hulls[j].firstclipnode = bm->headnode[j];
2743 mod->brushq1.hulls[j].lastclipnode = mod->brushq1.numclipnodes - 1;
2746 mod->brushq1.firstmodelsurface = bm->firstface;
2747 mod->brushq1.nummodelsurfaces = bm->numfaces;
2749 // this gets altered below if sky is used
2750 mod->DrawSky = NULL;
2751 mod->Draw = R_Model_Brush_Draw;
2752 mod->DrawFakeShadow = NULL;
2753 mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume;
2754 mod->DrawLight = R_Model_Brush_DrawLight;
2755 mod->brushq1.pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->brushq1.numtextures * sizeof(msurface_t **));
2756 mod->brushq1.pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool,(mod->brushq1.nummodelsurfaces + mod->brushq1.numtextures) * sizeof(msurface_t *));
2757 mod->brushq1.pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->brushq1.numtextures * sizeof(int));
2758 Mod_Q1BSP_BuildPVSTextureChains(mod);
2759 Mod_Q1BSP_BuildLightmapUpdateChains(originalloadmodel->mempool, mod);
2760 if (mod->brushq1.nummodelsurfaces)
2762 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2763 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2764 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2767 for (j = 0, surf = &mod->brushq1.surfaces[mod->brushq1.firstmodelsurface];j < mod->brushq1.nummodelsurfaces;j++, surf++)
2769 // we only need to have a drawsky function if it is used(usually only on world model)
2770 if (surf->texinfo->texture->shader == &Cshader_sky)
2771 mod->DrawSky = R_Model_Brush_DrawSky;
2772 // LordHavoc: submodels always clip, even if water
2773 if (mod->brushq1.numsubmodels - 1)
2774 surf->flags |= SURF_SOLIDCLIP;
2775 // calculate bounding shapes
2776 for (mesh = surf->mesh;mesh;mesh = mesh->chain)
2778 for (k = 0, vec = mesh->vertex3f;k < mesh->numverts;k++, vec += 3)
2780 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2781 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2782 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2783 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2784 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2785 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2786 dist = vec[0]*vec[0]+vec[1]*vec[1];
2787 if (modelyawradius < dist)
2788 modelyawradius = dist;
2789 dist += vec[2]*vec[2];
2790 if (modelradius < dist)
2795 modelyawradius = sqrt(modelyawradius);
2796 modelradius = sqrt(modelradius);
2797 mod->yawmins[0] = mod->yawmins[1] = - (mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2798 mod->yawmins[2] = mod->normalmins[2];
2799 mod->yawmaxs[2] = mod->normalmaxs[2];
2800 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2801 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2802 mod->radius = modelradius;
2803 mod->radius2 = modelradius * modelradius;
2807 // LordHavoc: empty submodel(lacrima.bsp has such a glitch)
2808 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2810 Mod_Q1BSP_BuildSurfaceNeighbors(mod->brushq1.surfaces + mod->brushq1.firstmodelsurface, mod->brushq1.nummodelsurfaces, originalloadmodel->mempool);
2812 mod->brushq1.numleafs = bm->visleafs;
2814 // LordHavoc: only register submodels if it is the world
2815 // (prevents bsp models from replacing world submodels)
2816 if (loadmodel->isworldmodel && i < (mod->brushq1.numsubmodels - 1))
2819 // duplicate the basic information
2820 sprintf(name, "*%i", i+1);
2821 loadmodel = Mod_FindName(name);
2823 strcpy(loadmodel->name, name);
2824 // textures and memory belong to the main model
2825 loadmodel->texturepool = NULL;
2826 loadmodel->mempool = NULL;
2831 loadmodel = originalloadmodel;
2832 //Mod_Q1BSP_ProcessLightList();
2835 static void Mod_Q2BSP_LoadEntities(lump_t *l)
2839 static void Mod_Q2BSP_LoadPlanes(lump_t *l)
2846 in = (void *)(mod_base + l->fileofs);
2847 if (l->filelen % sizeof(*in))
2848 Host_Error("Mod_Q2BSP_LoadPlanes: funny lump size in %s",loadmodel->name);
2849 count = l->filelen / sizeof(*in);
2850 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
2853 loadmodel->num = count;
2855 for (i = 0;i < count;i++, in++, out++)
2861 static void Mod_Q2BSP_LoadVertices(lump_t *l)
2868 in = (void *)(mod_base + l->fileofs);
2869 if (l->filelen % sizeof(*in))
2870 Host_Error("Mod_Q2BSP_LoadVertices: funny lump size in %s",loadmodel->name);
2871 count = l->filelen / sizeof(*in);
2872 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
2875 loadmodel->num = count;
2877 for (i = 0;i < count;i++, in++, out++)
2883 static void Mod_Q2BSP_LoadVisibility(lump_t *l)
2890 in = (void *)(mod_base + l->fileofs);
2891 if (l->filelen % sizeof(*in))
2892 Host_Error("Mod_Q2BSP_LoadVisibility: funny lump size in %s",loadmodel->name);
2893 count = l->filelen / sizeof(*in);
2894 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
2897 loadmodel->num = count;
2899 for (i = 0;i < count;i++, in++, out++)
2905 static void Mod_Q2BSP_LoadNodes(lump_t *l)
2912 in = (void *)(mod_base + l->fileofs);
2913 if (l->filelen % sizeof(*in))
2914 Host_Error("Mod_Q2BSP_LoadNodes: funny lump size in %s",loadmodel->name);
2915 count = l->filelen / sizeof(*in);
2916 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
2919 loadmodel->num = count;
2921 for (i = 0;i < count;i++, in++, out++)
2927 static void Mod_Q2BSP_LoadTexInfo(lump_t *l)
2934 in = (void *)(mod_base + l->fileofs);
2935 if (l->filelen % sizeof(*in))
2936 Host_Error("Mod_Q2BSP_LoadTexInfo: funny lump size in %s",loadmodel->name);
2937 count = l->filelen / sizeof(*in);
2938 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
2941 loadmodel->num = count;
2943 for (i = 0;i < count;i++, in++, out++)
2949 static void Mod_Q2BSP_LoadFaces(lump_t *l)
2956 in = (void *)(mod_base + l->fileofs);
2957 if (l->filelen % sizeof(*in))
2958 Host_Error("Mod_Q2BSP_LoadFaces: funny lump size in %s",loadmodel->name);
2959 count = l->filelen / sizeof(*in);
2960 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
2963 loadmodel->num = count;
2965 for (i = 0;i < count;i++, in++, out++)
2971 static void Mod_Q2BSP_LoadLighting(lump_t *l)
2978 in = (void *)(mod_base + l->fileofs);
2979 if (l->filelen % sizeof(*in))
2980 Host_Error("Mod_Q2BSP_LoadLighting: funny lump size in %s",loadmodel->name);
2981 count = l->filelen / sizeof(*in);
2982 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
2985 loadmodel->num = count;
2987 for (i = 0;i < count;i++, in++, out++)
2993 static void Mod_Q2BSP_LoadLeafs(lump_t *l)
3000 in = (void *)(mod_base + l->fileofs);
3001 if (l->filelen % sizeof(*in))
3002 Host_Error("Mod_Q2BSP_LoadLeafs: funny lump size in %s",loadmodel->name);
3003 count = l->filelen / sizeof(*in);
3004 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3007 loadmodel->num = count;
3009 for (i = 0;i < count;i++, in++, out++)
3015 static void Mod_Q2BSP_LoadLeafFaces(lump_t *l)
3022 in = (void *)(mod_base + l->fileofs);
3023 if (l->filelen % sizeof(*in))
3024 Host_Error("Mod_Q2BSP_LoadLeafFaces: funny lump size in %s",loadmodel->name);
3025 count = l->filelen / sizeof(*in);
3026 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3029 loadmodel->num = count;
3031 for (i = 0;i < count;i++, in++, out++)
3037 static void Mod_Q2BSP_LoadLeafBrushes(lump_t *l)
3044 in = (void *)(mod_base + l->fileofs);
3045 if (l->filelen % sizeof(*in))
3046 Host_Error("Mod_Q2BSP_LoadLeafBrushes: funny lump size in %s",loadmodel->name);
3047 count = l->filelen / sizeof(*in);
3048 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3051 loadmodel->num = count;
3053 for (i = 0;i < count;i++, in++, out++)
3059 static void Mod_Q2BSP_LoadEdges(lump_t *l)
3066 in = (void *)(mod_base + l->fileofs);
3067 if (l->filelen % sizeof(*in))
3068 Host_Error("Mod_Q2BSP_LoadEdges: funny lump size in %s",loadmodel->name);
3069 count = l->filelen / sizeof(*in);
3070 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3073 loadmodel->num = count;
3075 for (i = 0;i < count;i++, in++, out++)
3081 static void Mod_Q2BSP_LoadSurfEdges(lump_t *l)
3088 in = (void *)(mod_base + l->fileofs);
3089 if (l->filelen % sizeof(*in))
3090 Host_Error("Mod_Q2BSP_LoadSurfEdges: funny lump size in %s",loadmodel->name);
3091 count = l->filelen / sizeof(*in);
3092 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3095 loadmodel->num = count;
3097 for (i = 0;i < count;i++, in++, out++)
3103 static void Mod_Q2BSP_LoadBrushes(lump_t *l)
3110 in = (void *)(mod_base + l->fileofs);
3111 if (l->filelen % sizeof(*in))
3112 Host_Error("Mod_Q2BSP_LoadBrushes: funny lump size in %s",loadmodel->name);
3113 count = l->filelen / sizeof(*in);
3114 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3117 loadmodel->num = count;
3119 for (i = 0;i < count;i++, in++, out++)
3125 static void Mod_Q2BSP_LoadBrushSides(lump_t *l)
3132 in = (void *)(mod_base + l->fileofs);
3133 if (l->filelen % sizeof(*in))
3134 Host_Error("Mod_Q2BSP_LoadBrushSides: funny lump size in %s",loadmodel->name);
3135 count = l->filelen / sizeof(*in);
3136 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3139 loadmodel->num = count;
3141 for (i = 0;i < count;i++, in++, out++)
3147 static void Mod_Q2BSP_LoadAreas(lump_t *l)
3154 in = (void *)(mod_base + l->fileofs);
3155 if (l->filelen % sizeof(*in))
3156 Host_Error("Mod_Q2BSP_LoadAreas: funny lump size in %s",loadmodel->name);
3157 count = l->filelen / sizeof(*in);
3158 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3161 loadmodel->num = count;
3163 for (i = 0;i < count;i++, in++, out++)
3169 static void Mod_Q2BSP_LoadAreaPortals(lump_t *l)
3176 in = (void *)(mod_base + l->fileofs);
3177 if (l->filelen % sizeof(*in))
3178 Host_Error("Mod_Q2BSP_LoadAreaPortals: funny lump size in %s",loadmodel->name);
3179 count = l->filelen / sizeof(*in);
3180 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3183 loadmodel->num = count;
3185 for (i = 0;i < count;i++, in++, out++)
3191 static void Mod_Q2BSP_LoadModels(lump_t *l)
3198 in = (void *)(mod_base + l->fileofs);
3199 if (l->filelen % sizeof(*in))
3200 Host_Error("Mod_Q2BSP_LoadModels: funny lump size in %s",loadmodel->name);
3201 count = l->filelen / sizeof(*in);
3202 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3205 loadmodel->num = count;
3207 for (i = 0;i < count;i++, in++, out++)
3213 void Mod_Q2BSP_Load(model_t *mod, void *buffer)
3216 q2dheader_t *header;
3218 Host_Error("Mod_Q2BSP_Load: not yet implemented\n");
3220 mod->type = mod_brushq2;
3222 header = (q2dheader_t *)buffer;
3224 i = LittleLong(header->version);
3225 if (i != Q2BSPVERSION)
3226 Host_Error("Mod_Q2BSP_Load: %s has wrong version number (%i, should be %i)", mod->name, i, Q2BSPVERSION);
3227 mod->brushq1.ishlbsp = false;
3228 if (loadmodel->isworldmodel)
3230 Cvar_SetValue("halflifebsp", mod->brushq1.ishlbsp);
3231 // until we get a texture for it...
3235 mod_base = (qbyte *)header;
3237 // swap all the lumps
3238 for (i = 0;i < (int) sizeof(*header) / 4;i++)
3239 ((int *)header)[i] = LittleLong(((int *)header)[i]);
3241 // store which lightmap format to use
3242 mod->brushq1.lightmaprgba = r_lightmaprgba.integer;
3244 Mod_Q2BSP_LoadEntities(&header->lumps[Q2LUMP_ENTITIES]);
3245 Mod_Q2BSP_LoadPlanes(&header->lumps[Q2LUMP_PLANES]);
3246 Mod_Q2BSP_LoadVertices(&header->lumps[Q2LUMP_VERTEXES]);
3247 Mod_Q2BSP_LoadVisibility(&header->lumps[Q2LUMP_VISIBILITY]);
3248 Mod_Q2BSP_LoadNodes(&header->lumps[Q2LUMP_NODES]);
3249 Mod_Q2BSP_LoadTexInfo(&header->lumps[Q2LUMP_TEXINFO]);
3250 Mod_Q2BSP_LoadFaces(&header->lumps[Q2LUMP_FACES]);
3251 Mod_Q2BSP_LoadLighting(&header->lumps[Q2LUMP_LIGHTING]);
3252 Mod_Q2BSP_LoadLeafs(&header->lumps[Q2LUMP_LEAFS]);
3253 Mod_Q2BSP_LoadLeafFaces(&header->lumps[Q2LUMP_LEAFFACES]);
3254 Mod_Q2BSP_LoadLeafBrushes(&header->lumps[Q2LUMP_LEAFBRUSHES]);
3255 Mod_Q2BSP_LoadEdges(&header->lumps[Q2LUMP_EDGES]);
3256 Mod_Q2BSP_LoadSurfEdges(&header->lumps[Q2LUMP_SURFEDGES]);
3257 Mod_Q2BSP_LoadBrushes(&header->lumps[Q2LUMP_BRUSHES]);
3258 Mod_Q2BSP_LoadBrushSides(&header->lumps[Q2LUMP_BRUSHSIDES]);
3259 Mod_Q2BSP_LoadAreas(&header->lumps[Q2LUMP_AREAS]);
3260 Mod_Q2BSP_LoadAreaPortals(&header->lumps[Q2LUMP_AREAPORTALS]);
3261 // LordHavoc: must go last because this makes the submodels
3262 Mod_Q2BSP_LoadModels(&header->lumps[Q2LUMP_MODELS]);
3265 static void Mod_Q3BSP_LoadEntities(lump_t *l)
3269 loadmodel->brush.entities = Mem_Alloc(loadmodel->mempool, l->filelen);
3270 memcpy(loadmodel->brush.entities, mod_base + l->fileofs, l->filelen);
3273 static void Mod_Q3BSP_LoadTextures(lump_t *l)
3280 in = (void *)(mod_base + l->fileofs);
3281 if (l->filelen % sizeof(*in))
3282 Host_Error("Mod_Q3BSP_LoadTextures: funny lump size in %s",loadmodel->name);
3283 count = l->filelen / sizeof(*in);
3284 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3287 loadmodel->num = count;
3289 for (i = 0;i < count;i++, in++, out++)
3295 static void Mod_Q3BSP_LoadPlanes(lump_t *l)
3302 in = (void *)(mod_base + l->fileofs);
3303 if (l->filelen % sizeof(*in))
3304 Host_Error("Mod_Q3BSP_LoadPlanes: funny lump size in %s",loadmodel->name);
3305 count = l->filelen / sizeof(*in);
3306 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3309 loadmodel->num = count;
3311 for (i = 0;i < count;i++, in++, out++)
3317 static void Mod_Q3BSP_LoadNodes(lump_t *l)
3324 in = (void *)(mod_base + l->fileofs);
3325 if (l->filelen % sizeof(*in))
3326 Host_Error("Mod_Q3BSP_LoadNodes: funny lump size in %s",loadmodel->name);
3327 count = l->filelen / sizeof(*in);
3328 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3331 loadmodel->num = count;
3333 for (i = 0;i < count;i++, in++, out++)
3339 static void Mod_Q3BSP_LoadLeafs(lump_t *l)
3346 in = (void *)(mod_base + l->fileofs);
3347 if (l->filelen % sizeof(*in))
3348 Host_Error("Mod_Q3BSP_LoadLeafs: funny lump size in %s",loadmodel->name);
3349 count = l->filelen / sizeof(*in);
3350 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3353 loadmodel->num = count;
3355 for (i = 0;i < count;i++, in++, out++)
3361 static void Mod_Q3BSP_LoadLeafFaces(lump_t *l)
3368 in = (void *)(mod_base + l->fileofs);
3369 if (l->filelen % sizeof(*in))
3370 Host_Error("Mod_Q3BSP_LoadLeafFaces: funny lump size in %s",loadmodel->name);
3371 count = l->filelen / sizeof(*in);
3372 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3375 loadmodel->num = count;
3377 for (i = 0;i < count;i++, in++, out++)
3383 static void Mod_Q3BSP_LoadLeafBrushes(lump_t *l)
3390 in = (void *)(mod_base + l->fileofs);
3391 if (l->filelen % sizeof(*in))
3392 Host_Error("Mod_Q3BSP_LoadLeafBrushes: funny lump size in %s",loadmodel->name);
3393 count = l->filelen / sizeof(*in);
3394 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3397 loadmodel->num = count;
3399 for (i = 0;i < count;i++, in++, out++)
3405 static void Mod_Q3BSP_LoadModels(lump_t *l)
3412 in = (void *)(mod_base + l->fileofs);
3413 if (l->filelen % sizeof(*in))
3414 Host_Error("Mod_Q3BSP_LoadModels: funny lump size in %s",loadmodel->name);
3415 count = l->filelen / sizeof(*in);
3416 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3419 loadmodel->num = count;
3421 for (i = 0;i < count;i++, in++, out++)
3427 static void Mod_Q3BSP_LoadBrushes(lump_t *l)
3434 in = (void *)(mod_base + l->fileofs);
3435 if (l->filelen % sizeof(*in))
3436 Host_Error("Mod_Q3BSP_LoadBrushes: funny lump size in %s",loadmodel->name);
3437 count = l->filelen / sizeof(*in);
3438 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3441 loadmodel->num = count;
3443 for (i = 0;i < count;i++, in++, out++)
3449 static void Mod_Q3BSP_LoadBrushSides(lump_t *l)
3456 in = (void *)(mod_base + l->fileofs);
3457 if (l->filelen % sizeof(*in))
3458 Host_Error("Mod_Q3BSP_LoadBrushSides: funny lump size in %s",loadmodel->name);
3459 count = l->filelen / sizeof(*in);
3460 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3463 loadmodel->num = count;
3465 for (i = 0;i < count;i++, in++, out++)
3471 static void Mod_Q3BSP_LoadVertices(lump_t *l)
3478 in = (void *)(mod_base + l->fileofs);
3479 if (l->filelen % sizeof(*in))
3480 Host_Error("Mod_Q3BSP_LoadVertices: funny lump size in %s",loadmodel->name);
3481 count = l->filelen / sizeof(*in);
3482 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3485 loadmodel->num = count;
3487 for (i = 0;i < count;i++, in++, out++)
3493 static void Mod_Q3BSP_LoadTriangles(lump_t *l)
3500 in = (void *)(mod_base + l->fileofs);
3501 if (l->filelen % sizeof(*in))
3502 Host_Error("Mod_Q3BSP_LoadTriangles: funny lump size in %s",loadmodel->name);
3503 count = l->filelen / sizeof(*in);
3504 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3507 loadmodel->num = count;
3509 for (i = 0;i < count;i++, in++, out++)
3515 static void Mod_Q3BSP_LoadEffects(lump_t *l)
3522 in = (void *)(mod_base + l->fileofs);
3523 if (l->filelen % sizeof(*in))
3524 Host_Error("Mod_Q3BSP_LoadEffects: funny lump size in %s",loadmodel->name);
3525 count = l->filelen / sizeof(*in);
3526 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3529 loadmodel->num = count;
3531 for (i = 0;i < count;i++, in++, out++)
3537 static void Mod_Q3BSP_LoadFaces(lump_t *l)
3544 in = (void *)(mod_base + l->fileofs);
3545 if (l->filelen % sizeof(*in))
3546 Host_Error("Mod_Q3BSP_LoadFaces: funny lump size in %s",loadmodel->name);
3547 count = l->filelen / sizeof(*in);
3548 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3551 loadmodel->num = count;
3553 for (i = 0;i < count;i++, in++, out++)
3559 static void Mod_Q3BSP_LoadLightmaps(lump_t *l)
3566 in = (void *)(mod_base + l->fileofs);
3567 if (l->filelen % sizeof(*in))
3568 Host_Error("Mod_Q3BSP_LoadLightmaps: funny lump size in %s",loadmodel->name);
3569 count = l->filelen / sizeof(*in);
3570 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3573 loadmodel->num = count;
3575 for (i = 0;i < count;i++, in++, out++)
3581 static void Mod_Q3BSP_LoadLightGrid(lump_t *l)
3588 in = (void *)(mod_base + l->fileofs);
3589 if (l->filelen % sizeof(*in))
3590 Host_Error("Mod_Q3BSP_LoadLightGrid: funny lump size in %s",loadmodel->name);
3591 count = l->filelen / sizeof(*in);
3592 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3595 loadmodel->num = count;
3597 for (i = 0;i < count;i++, in++, out++)
3603 static void Mod_Q3BSP_LoadPVS(lump_t *l)
3610 in = (void *)(mod_base + l->fileofs);
3611 if (l->filelen % sizeof(*in))
3612 Host_Error("Mod_Q3BSP_LoadPVS: funny lump size in %s",loadmodel->name);
3613 count = l->filelen / sizeof(*in);
3614 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
3617 loadmodel->num = count;
3619 for (i = 0;i < count;i++, in++, out++)
3625 void Mod_Q3BSP_Load(model_t *mod, void *buffer)
3628 q3dheader_t *header;
3629 Host_Error("Mod_Q3BSP_Load: not yet implemented\n");
3631 mod->type = mod_brushq2;
3633 header = (q3dheader_t *)buffer;
3635 i = LittleLong(header->version);
3636 if (i != Q3BSPVERSION)
3637 Host_Error("Mod_Q3BSP_Load: %s has wrong version number (%i, should be %i)", mod->name, i, Q3BSPVERSION);
3638 if (loadmodel->isworldmodel)
3640 Cvar_SetValue("halflifebsp", false);
3641 // until we get a texture for it...
3645 mod_base = (qbyte *)header;
3647 // swap all the lumps
3648 for (i = 0;i < (int) sizeof(*header) / 4;i++)
3649 ((int *)header)[i] = LittleLong(((int *)header)[i]);
3651 Mod_Q3BSP_LoadEntities(&header->lumps[Q3LUMP_ENTITIES]);
3652 Mod_Q3BSP_LoadTextures(&header->lumps[Q3LUMP_TEXTURES]);
3653 Mod_Q3BSP_LoadPlanes(&header->lumps[Q3LUMP_PLANES]);
3654 Mod_Q3BSP_LoadNodes(&header->lumps[Q3LUMP_NODES]);
3655 Mod_Q3BSP_LoadBrushSides(&header->lumps[Q3LUMP_BRUSHSIDES]);
3656 Mod_Q3BSP_LoadBrushes(&header->lumps[Q3LUMP_BRUSHES]);
3657 Mod_Q3BSP_LoadEffects(&header->lumps[Q3LUMP_EFFECTS]);
3658 Mod_Q3BSP_LoadVertices(&header->lumps[Q3LUMP_VERTICES]);
3659 Mod_Q3BSP_LoadTriangles(&header->lumps[Q3LUMP_TRIANGLES]);
3660 Mod_Q3BSP_LoadLightmaps(&header->lumps[Q3LUMP_LIGHTMAPS]);
3661 Mod_Q3BSP_LoadFaces(&header->lumps[Q3LUMP_FACES]);
3662 Mod_Q3BSP_LoadModels(&header->lumps[Q3LUMP_MODELS]);
3663 Mod_Q3BSP_LoadLeafBrushes(&header->lumps[Q3LUMP_LEAFBRUSHES]);
3664 Mod_Q3BSP_LoadLeafFaces(&header->lumps[Q3LUMP_LEAFFACES]);
3665 Mod_Q3BSP_LoadLeafs(&header->lumps[Q3LUMP_LEAFS]);
3666 Mod_Q3BSP_LoadLightGrid(&header->lumps[Q3LUMP_LIGHTGRID]);
3667 Mod_Q3BSP_LoadPVS(&header->lumps[Q3LUMP_PVS]);
3670 void Mod_IBSP_Load(model_t *mod, void *buffer)
3672 int i = LittleLong(* ((int *)buffer));
3673 if (i == Q3BSPVERSION)
3674 Mod_Q3BSP_Load(mod,buffer);
3675 else if (i == Q2BSPVERSION)
3676 Mod_Q2BSP_Load(mod,buffer);
3678 Host_Error("Mod_IBSP_Load: unknown/unsupported version %i\n", i);
3681 void Mod_MAP_Load(model_t *mod, void *buffer)
3683 Host_Error("Mod_MAP_Load: not yet implemented\n");