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.
23 // note: model_shared.c sets up r_notexture, and r_surf_notexture
25 qbyte mod_novis[(MAX_MAP_LEAFS + 7)/ 8];
27 //cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"};
28 cvar_t halflifebsp = {0, "halflifebsp", "0"};
29 cvar_t r_novis = {0, "r_novis", "0"};
30 cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"};
31 cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
32 cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"};
33 cvar_t r_sortsurfaces = {0, "r_sortsurfaces", "0"};
35 #define NUM_DETAILTEXTURES 1
36 static rtexture_t *detailtextures[NUM_DETAILTEXTURES];
37 static rtexturepool_t *detailtexturepool;
44 void Mod_BrushInit (void)
46 // Cvar_RegisterVariable(&r_subdivide_size);
47 Cvar_RegisterVariable(&halflifebsp);
48 Cvar_RegisterVariable(&r_novis);
49 Cvar_RegisterVariable(&r_miplightmaps);
50 Cvar_RegisterVariable(&r_lightmaprgba);
51 Cvar_RegisterVariable(&r_nosurftextures);
52 Cvar_RegisterVariable(&r_sortsurfaces);
53 memset(mod_novis, 0xff, sizeof(mod_novis));
56 void Mod_BrushStartup (void)
59 float vc[3], vx[3], vy[3], vn[3], lightdir[3];
60 #define DETAILRESOLUTION 256
61 qbyte data[DETAILRESOLUTION][DETAILRESOLUTION][4], noise[DETAILRESOLUTION][DETAILRESOLUTION];
62 detailtexturepool = R_AllocTexturePool();
66 VectorNormalize(lightdir);
67 for (i = 0;i < NUM_DETAILTEXTURES;i++)
69 fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4);
70 for (y = 0;y < DETAILRESOLUTION;y++)
72 for (x = 0;x < DETAILRESOLUTION;x++)
76 vc[2] = noise[y][x] * (1.0f / 32.0f);
79 vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f);
82 vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f);
83 VectorSubtract(vx, vc, vx);
84 VectorSubtract(vy, vc, vy);
85 CrossProduct(vx, vy, vn);
87 light = 128 - DotProduct(vn, lightdir) * 128;
88 light = bound(0, light, 255);
89 data[y][x][0] = data[y][x][1] = data[y][x][2] = light;
93 detailtextures[i] = R_LoadTexture(detailtexturepool, va("detailtexture%i", i), DETAILRESOLUTION, DETAILRESOLUTION, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE);
97 void Mod_BrushShutdown (void)
100 for (i = 0;i < NUM_DETAILTEXTURES;i++)
101 R_FreeTexture(detailtextures[i]);
102 R_FreeTexturePool(&detailtexturepool);
110 mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model)
117 Mod_CheckLoaded(model);
119 // LordHavoc: modified to start at first clip node,
120 // in other words: first node of the (sub)model
121 node = model->nodes + model->hulls[0].firstclipnode;
122 while (node->contents == 0)
123 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
125 return (mleaf_t *)node;
128 int Mod_PointContents (const vec3_t p, model_t *model)
133 return CONTENTS_EMPTY;
135 Mod_CheckLoaded(model);
137 // LordHavoc: modified to start at first clip node,
138 // in other words: first node of the (sub)model
139 node = model->nodes + model->hulls[0].firstclipnode;
140 while (node->contents == 0)
141 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
143 return ((mleaf_t *)node)->contents;
146 void Mod_FindNonSolidLocation(vec3_t pos, model_t *mod)
148 if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
149 pos[0]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
150 pos[0]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
152 pos[1]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
153 pos[1]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
155 pos[2]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
156 pos[2]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return;
166 static qbyte *Mod_DecompressVis (qbyte *in, model_t *model)
168 static qbyte decompressed[MAX_MAP_LEAFS/8];
173 row = (model->numleafs+7)>>3;
191 } while (out - decompressed < row);
196 qbyte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
198 if (r_novis.integer || leaf == model->leafs || leaf->compressed_vis == NULL)
200 return Mod_DecompressVis (leaf->compressed_vis, model);
208 static void Mod_LoadTextures (lump_t *l)
210 int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs, incomplete;
212 texture_t *tx, *tx2, *anims[10], *altanims[10];
214 qbyte *data, *mtdata, *data2;
217 loadmodel->textures = NULL;
222 m = (dmiptexlump_t *)(mod_base + l->fileofs);
224 m->nummiptex = LittleLong (m->nummiptex);
226 // add two slots for notexture walls and notexture liquids
227 loadmodel->numtextures = m->nummiptex + 2;
228 loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(texture_t));
230 // fill out all slots with notexture
231 for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++)
235 tx->texture = r_notexture;
236 tx->shader = &Cshader_wall_lightmap;
237 if (i == loadmodel->numtextures - 1)
239 tx->flags = SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
240 tx->shader = &Cshader_water;
244 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
246 // LordHavoc: mostly rewritten map texture loader
247 for (i = 0;i < m->nummiptex;i++)
249 dofs[i] = LittleLong(dofs[i]);
250 if (dofs[i] == -1 || r_nosurftextures.integer)
252 dmiptex = (miptex_t *)((qbyte *)m + dofs[i]);
254 // make sure name is no more than 15 characters
255 for (j = 0;dmiptex->name[j] && j < 15;j++)
256 name[j] = dmiptex->name[j];
259 mtwidth = LittleLong (dmiptex->width);
260 mtheight = LittleLong (dmiptex->height);
262 j = LittleLong (dmiptex->offsets[0]);
266 if (j < 40 || j + mtwidth * mtheight > l->filelen)
268 Con_Printf ("Texture \"%s\" in \"%s\"is corrupt or incomplete\n", dmiptex->name, loadmodel->name);
271 mtdata = (qbyte *)dmiptex + j;
274 if ((mtwidth & 15) || (mtheight & 15))
275 Con_Printf ("warning: texture \"%s\" in \"%s\" is not 16 aligned", dmiptex->name, loadmodel->name);
277 // LordHavoc: force all names to lowercase
278 for (j = 0;name[j];j++)
279 if (name[j] >= 'A' && name[j] <= 'Z')
280 name[j] += 'a' - 'A';
282 tx = loadmodel->textures + i;
283 strcpy(tx->name, name);
285 tx->height = mtheight;
289 sprintf(tx->name, "unnamed%i", i);
290 Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name);
293 // LordHavoc: HL sky textures are entirely different than quake
294 if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128)
296 if (loadmodel->isworldmodel)
298 data = loadimagepixels(tx->name, false, 0, 0);
301 if (image_width == 256 && image_height == 128)
309 Con_Printf ("Invalid replacement texture for sky \"%s\" in %\"%s\", must be 256x128 pixels\n", tx->name, loadmodel->name);
311 R_InitSky (mtdata, 1);
314 else if (mtdata != NULL)
315 R_InitSky (mtdata, 1);
318 else if ((tx->texture = loadtextureimagewithmask(loadmodel->texturepool, tx->name, 0, 0, false, true, true)))
320 tx->fogtexture = image_masktex;
321 strcpy(name, tx->name);
322 strcat(name, "_glow");
323 tx->glowtexture = loadtextureimage(loadmodel->texturepool, name, 0, 0, false, true, true);
327 if (loadmodel->ishlbsp)
329 if (mtdata && (data = W_ConvertWAD3Texture(dmiptex)))
332 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
333 if (R_TextureHasAlpha(tx->texture))
336 for (j = 0;j < image_width * image_height;j++)
337 data[j*4+0] = data[j*4+1] = data[j*4+2] = 255;
338 strcpy(name, tx->name);
339 strcat(name, "_fog");
340 tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
344 else if ((data = W_GetTexture(tx->name)))
346 // get the size from the wad texture
347 tx->width = image_width;
348 tx->height = image_height;
349 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
350 if (R_TextureHasAlpha(tx->texture))
353 for (j = 0;j < image_width * image_height;j++)
354 data[j*4+0] = data[j*4+1] = data[j*4+2] = 255;
355 strcpy(name, tx->name);
356 strcat(name, "_fog");
357 tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
365 tx->texture = r_notexture;
370 if (mtdata) // texture included
375 if (r_fullbrights.value && tx->name[0] != '*')
377 for (j = 0;j < tx->width*tx->height;j++)
379 if (data[j] >= 224) // fullbright
388 data2 = Mem_Alloc(loadmodel->mempool, tx->width*tx->height);
389 for (j = 0;j < tx->width*tx->height;j++)
390 data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights
391 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
392 strcpy(name, tx->name);
393 strcat(name, "_glow");
394 for (j = 0;j < tx->width*tx->height;j++)
395 data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights
396 tx->glowtexture = R_LoadTexture (loadmodel->texturepool, name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
400 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
402 else // no texture, and no external replacement texture was found
406 tx->texture = r_notexture;
411 if (tx->name[0] == '*')
413 tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES;
414 // LordHavoc: some turbulent textures should be fullbright and solid
415 if (!strncmp(tx->name,"*lava",5)
416 || !strncmp(tx->name,"*teleport",9)
417 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
418 tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA;
419 tx->shader = &Cshader_water;
421 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
423 tx->flags |= SURF_DRAWSKY;
424 tx->shader = &Cshader_sky;
428 tx->flags |= SURF_LIGHTMAP;
429 tx->shader = &Cshader_wall_lightmap;
432 tx->detailtexture = detailtextures[i % NUM_DETAILTEXTURES];
435 // sequence the animations
436 for (i = 0;i < m->nummiptex;i++)
438 tx = loadmodel->textures + i;
439 if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0)
441 if (tx->anim_total[0] || tx->anim_total[1])
442 continue; // already sequenced
444 // find the number of frames in the animation
445 memset (anims, 0, sizeof(anims));
446 memset (altanims, 0, sizeof(altanims));
448 for (j = i;j < m->nummiptex;j++)
450 tx2 = loadmodel->textures + j;
451 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
455 if (num >= '0' && num <= '9')
456 anims[num - '0'] = tx2;
457 else if (num >= 'a' && num <= 'j')
458 altanims[num - 'a'] = tx2;
460 Con_Printf ("Bad animating texture %s\n", tx->name);
464 for (j = 0;j < 10;j++)
471 //Con_Printf("linking animation %s (%i:%i frames)\n\n", tx->name, max, altmax);
474 for (j = 0;j < max;j++)
478 Con_Printf ("Missing frame %i of %s\n", j, tx->name);
482 for (j = 0;j < altmax;j++)
486 Con_Printf ("Missing altframe %i of %s\n", j, tx->name);
495 // if there is no alternate animation, duplicate the primary
496 // animation into the alternate
498 for (k = 0;k < 10;k++)
499 altanims[k] = anims[k];
502 // link together the primary animation
503 for (j = 0;j < max;j++)
506 tx2->animated = true;
507 tx2->anim_total[0] = max;
508 tx2->anim_total[1] = altmax;
509 for (k = 0;k < 10;k++)
511 tx2->anim_frames[0][k] = anims[k];
512 tx2->anim_frames[1][k] = altanims[k];
516 // if there really is an alternate anim...
517 if (anims[0] != altanims[0])
519 // link together the alternate animation
520 for (j = 0;j < altmax;j++)
523 tx2->animated = true;
524 // the primary/alternate are reversed here
525 tx2->anim_total[0] = altmax;
526 tx2->anim_total[1] = max;
527 for (k = 0;k < 10;k++)
529 tx2->anim_frames[0][k] = altanims[k];
530 tx2->anim_frames[1][k] = anims[k];
542 static void Mod_LoadLighting (lump_t *l)
545 qbyte *in, *out, *data, d;
546 char litfilename[1024];
547 loadmodel->lightdata = NULL;
548 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
550 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
551 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
553 else // LordHavoc: bsp version 29 (normal white lighting)
555 // LordHavoc: hope is not lost yet, check for a .lit file to load
556 strcpy(litfilename, loadmodel->name);
557 COM_StripExtension(litfilename, litfilename);
558 strcat(litfilename, ".lit");
559 data = (qbyte*) COM_LoadFile (litfilename, false);
562 if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
564 i = LittleLong(((int *)data)[1]);
567 Con_DPrintf("%s loaded", litfilename);
568 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
569 memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
575 Con_Printf("Unknown .lit file version (%d)\n", i);
582 Con_Printf("Empty .lit file, ignoring\n");
584 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
588 // LordHavoc: oh well, expand the white lighting data
591 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
592 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
593 out = loadmodel->lightdata;
594 memcpy (in, mod_base + l->fileofs, l->filelen);
595 for (i = 0;i < l->filelen;i++)
605 void Mod_LoadLightList(void)
608 char lightsfilename[1024], *s, *t, *lightsstring;
611 strcpy(lightsfilename, loadmodel->name);
612 COM_StripExtension(lightsfilename, lightsfilename);
613 strcat(lightsfilename, ".lights");
614 s = lightsstring = (char *) COM_LoadFile (lightsfilename, false);
620 while (*s && *s != '\n')
624 Mem_Free(lightsstring);
625 Host_Error("lights file must end with a newline\n");
630 loadmodel->lights = Mem_Alloc(loadmodel->mempool, numlights * sizeof(mlight_t));
633 while (*s && n < numlights)
636 while (*s && *s != '\n')
640 Mem_Free(lightsstring);
641 Host_Error("misparsed lights file!\n");
643 e = loadmodel->lights + n;
645 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);
649 Mem_Free(lightsstring);
650 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);
657 Mem_Free(lightsstring);
658 Host_Error("misparsed lights file!\n");
660 loadmodel->numlights = numlights;
661 Mem_Free(lightsstring);
665 void Mod_ProcessLightList(void)
673 for (i = 0, e = loadmodel->lights;i < loadmodel->numlights;i++, e++)
675 e->cullradius2 = DotProduct(e->light, e->light) * (1.0f / (8192.0f * 8192.0f)) / (e->falloff * e->falloff) + 4096.0f;
676 if (e->cullradius2 > 4096.0f * 4096.0f)
677 e->cullradius2 = 4096.0f * 4096.0f;
678 e->cullradius = sqrt(e->cullradius2);
679 l = Mod_PointInLeaf(e->origin, loadmodel);
680 if (l->compressed_vis)
681 pvs = Mod_DecompressVis (l->compressed_vis, loadmodel);
684 for (j = 0, l = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++)
686 if (pvs[j >> 3] & (1 << (j & 7)))
688 for (k = 0, mark = l->firstmarksurface;k < l->nummarksurfaces;k++, mark++)
690 surf = loadmodel->surfaces + *mark;
691 dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist;
692 if (surf->flags & SURF_PLANEBACK)
694 if (dist > 0 && dist < e->cullradius)
695 loadmodel->surfacevisframes[j] = i - 1000000;
700 for (j = 0;j < loadmodel->nummodelsurfaces;j++)
701 if (loadmodel->surfacevisframes[j] == i - 1000000)
704 if (e->numsurfaces > 0)
706 e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces);
708 for (j = 0;j < loadmodel->nummodelsurfaces;j++)
709 if (loadmodel->surfacevisframes[j] == i - 1000000)
710 e->surfaces[e->numsurfaces++] = loadmodel->surfaces + loadmodel->firstmodelsurface + j;
721 static void Mod_LoadVisibility (lump_t *l)
723 loadmodel->visdata = NULL;
726 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
727 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
730 // used only for HalfLife maps
731 void Mod_ParseWadsFromEntityLump(const char *data)
733 char key[128], value[4096];
738 if (!COM_ParseToken(&data))
740 if (com_token[0] != '{')
744 if (!COM_ParseToken(&data))
746 if (com_token[0] == '}')
747 break; // end of worldspawn
748 if (com_token[0] == '_')
749 strcpy(key, com_token + 1);
751 strcpy(key, com_token);
752 while (key[strlen(key)-1] == ' ') // remove trailing spaces
753 key[strlen(key)-1] = 0;
754 if (!COM_ParseToken(&data))
756 strcpy(value, com_token);
757 if (!strcmp("wad", key)) // for HalfLife maps
759 if (loadmodel->ishlbsp)
762 for (i = 0;i < 4096;i++)
763 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
769 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
770 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
772 else if (value[i] == ';' || value[i] == 0)
776 strcpy(wadname, "textures/");
777 strcat(wadname, &value[j]);
778 W_LoadTextureWadFile (wadname, false);
795 static void Mod_LoadEntities (lump_t *l)
797 loadmodel->entities = NULL;
800 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
801 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
802 if (loadmodel->ishlbsp)
803 Mod_ParseWadsFromEntityLump(loadmodel->entities);
812 static void Mod_LoadVertexes (lump_t *l)
818 in = (void *)(mod_base + l->fileofs);
819 if (l->filelen % sizeof(*in))
820 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
821 count = l->filelen / sizeof(*in);
822 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
824 loadmodel->vertexes = out;
825 loadmodel->numvertexes = count;
827 for ( i=0 ; i<count ; i++, in++, out++)
829 out->position[0] = LittleFloat (in->point[0]);
830 out->position[1] = LittleFloat (in->point[1]);
831 out->position[2] = LittleFloat (in->point[2]);
840 static void Mod_LoadSubmodels (lump_t *l)
846 in = (void *)(mod_base + l->fileofs);
847 if (l->filelen % sizeof(*in))
848 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
849 count = l->filelen / sizeof(*in);
850 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
852 loadmodel->submodels = out;
853 loadmodel->numsubmodels = count;
855 for ( i=0 ; i<count ; i++, in++, out++)
857 for (j=0 ; j<3 ; j++)
859 // spread the mins / maxs by a pixel
860 out->mins[j] = LittleFloat (in->mins[j]) - 1;
861 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
862 out->origin[j] = LittleFloat (in->origin[j]);
864 for (j=0 ; j<MAX_MAP_HULLS ; j++)
865 out->headnode[j] = LittleLong (in->headnode[j]);
866 out->visleafs = LittleLong (in->visleafs);
867 out->firstface = LittleLong (in->firstface);
868 out->numfaces = LittleLong (in->numfaces);
877 static void Mod_LoadEdges (lump_t *l)
883 in = (void *)(mod_base + l->fileofs);
884 if (l->filelen % sizeof(*in))
885 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
886 count = l->filelen / sizeof(*in);
887 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
889 loadmodel->edges = out;
890 loadmodel->numedges = count;
892 for ( i=0 ; i<count ; i++, in++, out++)
894 out->v[0] = (unsigned short)LittleShort(in->v[0]);
895 out->v[1] = (unsigned short)LittleShort(in->v[1]);
904 static void Mod_LoadTexinfo (lump_t *l)
908 int i, j, k, count, miptex;
910 in = (void *)(mod_base + l->fileofs);
911 if (l->filelen % sizeof(*in))
912 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
913 count = l->filelen / sizeof(*in);
914 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
916 loadmodel->texinfo = out;
917 loadmodel->numtexinfo = count;
919 for (i = 0;i < count;i++, in++, out++)
921 for (k = 0;k < 2;k++)
922 for (j = 0;j < 4;j++)
923 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
925 miptex = LittleLong (in->miptex);
926 out->flags = LittleLong (in->flags);
929 if (loadmodel->textures)
931 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
932 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
934 out->texture = loadmodel->textures + miptex;
936 if (out->flags & TEX_SPECIAL)
938 // if texture chosen is NULL or the shader needs a lightmap,
939 // force to notexture water shader
940 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
941 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
945 // if texture chosen is NULL, force to notexture
946 if (out->texture == NULL)
947 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
956 Fills in s->texturemins[] and s->extents[]
959 static void CalcSurfaceExtents (msurface_t *s)
961 float mins[2], maxs[2], val;
965 int bmins[2], bmaxs[2];
967 mins[0] = mins[1] = 999999999;
968 maxs[0] = maxs[1] = -999999999;
972 for (i=0 ; i<s->numedges ; i++)
974 e = loadmodel->surfedges[s->firstedge+i];
976 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
978 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
980 for (j=0 ; j<2 ; j++)
982 val = v->position[0] * tex->vecs[j][0] +
983 v->position[1] * tex->vecs[j][1] +
984 v->position[2] * tex->vecs[j][2] +
993 for (i=0 ; i<2 ; i++)
995 bmins[i] = floor(mins[i]/16);
996 bmaxs[i] = ceil(maxs[i]/16);
998 s->texturemins[i] = bmins[i] * 16;
999 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
1004 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1009 mins[0] = mins[1] = mins[2] = 9999;
1010 maxs[0] = maxs[1] = maxs[2] = -9999;
1012 for (i = 0;i < numverts;i++)
1014 for (j = 0;j < 3;j++, v++)
1025 #define MAX_SUBDIVPOLYTRIANGLES 4096
1026 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1028 static int subdivpolyverts, subdivpolytriangles;
1029 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1030 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1032 static int subdivpolylookupvert(vec3_t v)
1035 for (i = 0;i < subdivpolyverts;i++)
1036 if (subdivpolyvert[i][0] == v[0]
1037 && subdivpolyvert[i][1] == v[1]
1038 && subdivpolyvert[i][2] == v[2])
1040 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1041 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1042 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1043 return subdivpolyverts++;
1046 static void SubdividePolygon (int numverts, float *verts)
1048 int i, i1, i2, i3, f, b, c, p;
1049 vec3_t mins, maxs, front[256], back[256];
1050 float m, *pv, *cv, dist[256], frac;
1053 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1055 BoundPoly (numverts, verts, mins, maxs);
1057 for (i = 0;i < 3;i++)
1059 m = (mins[i] + maxs[i]) * 0.5;
1060 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1061 if (maxs[i] - m < 8)
1063 if (m - mins[i] < 8)
1067 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1068 dist[c] = cv[i] - m;
1071 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1075 VectorCopy (pv, front[f]);
1080 VectorCopy (pv, back[b]);
1083 if (dist[p] == 0 || dist[c] == 0)
1085 if ( (dist[p] > 0) != (dist[c] > 0) )
1088 frac = dist[p] / (dist[p] - dist[c]);
1089 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1090 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1091 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1097 SubdividePolygon (f, front[0]);
1098 SubdividePolygon (b, back[0]);
1102 i1 = subdivpolylookupvert(verts);
1103 i2 = subdivpolylookupvert(verts + 3);
1104 for (i = 2;i < numverts;i++)
1106 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1108 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1112 i3 = subdivpolylookupvert(verts + i * 3);
1113 subdivpolyindex[subdivpolytriangles][0] = i1;
1114 subdivpolyindex[subdivpolytriangles][1] = i2;
1115 subdivpolyindex[subdivpolytriangles][2] = i3;
1117 subdivpolytriangles++;
1123 Mod_GenerateWarpMesh
1125 Breaks a polygon up along axial 64 unit
1126 boundaries so that turbulent and sky warps
1127 can be done reasonably.
1130 void Mod_GenerateWarpMesh (msurface_t *surf)
1136 subdivpolytriangles = 0;
1137 subdivpolyverts = 0;
1138 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1139 if (subdivpolytriangles < 1)
1140 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1142 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1143 mesh->numverts = subdivpolyverts;
1144 mesh->numtriangles = subdivpolytriangles;
1145 mesh->vertex = (surfvertex_t *)(mesh + 1);
1146 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1147 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1149 for (i = 0;i < mesh->numtriangles;i++)
1150 for (j = 0;j < 3;j++)
1151 mesh->index[i*3+j] = subdivpolyindex[i][j];
1153 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1155 VectorCopy(subdivpolyvert[i], v->v);
1156 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1157 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1162 void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
1164 int i, iu, iv, *index, *n, smax, tmax;
1165 float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
1168 smax = surf->extents[0] >> 4;
1169 tmax = surf->extents[1] >> 4;
1173 surf->lightmaptexturestride = 0;
1174 surf->lightmaptexture = NULL;
1182 surf->flags |= SURF_LIGHTMAP;
1183 if (r_miplightmaps.integer)
1185 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1186 surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_PRECACHE);
1190 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1191 surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE);
1193 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1194 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1195 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1198 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[6]) + surf->poly_numverts * (4 + 2 + 2 + 2 + 1 + 3) * sizeof(float));
1199 mesh->numverts = surf->poly_numverts;
1200 mesh->numtriangles = surf->poly_numverts - 2;
1201 mesh->verts = (float *)(mesh + 1);
1202 mesh->st = mesh->verts + mesh->numverts * 4;
1203 mesh->uv = mesh->st + mesh->numverts * 2;
1204 mesh->ab = mesh->uv + mesh->numverts * 2;
1205 mesh->lightmapoffsets = (int *)(mesh->ab + mesh->numverts * 2);
1206 mesh->index = mesh->lightmapoffsets + mesh->numverts;
1207 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
1208 mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3);
1210 index = mesh->index;
1211 n = mesh->triangleneighbors;
1212 for (i = 0;i < mesh->numtriangles;i++)
1222 VectorCopy(surf->plane->normal, normal);
1223 if (surf->flags & SURF_PLANEBACK)
1224 VectorNegate(normal, normal);
1225 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1227 s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1228 t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1229 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1230 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1231 // LordHavoc: calc lightmap data offset for vertex lighting to use
1234 iu = bound(0, iu, smax);
1235 iv = bound(0, iv, tmax);
1236 u = u * uscale + ubase;
1237 v = v * vscale + vbase;
1239 mesh->verts[i * 4 + 0] = in[0];
1240 mesh->verts[i * 4 + 1] = in[1];
1241 mesh->verts[i * 4 + 2] = in[2];
1242 mesh->st[i * 2 + 0] = s / surf->texinfo->texture->width;
1243 mesh->st[i * 2 + 1] = t / surf->texinfo->texture->height;
1244 mesh->uv[i * 2 + 0] = u;
1245 mesh->uv[i * 2 + 1] = v;
1246 mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f);
1247 mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f);
1248 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
1249 mesh->normals[i * 3 + 0] = normal[0];
1250 mesh->normals[i * 3 + 1] = normal[1];
1251 mesh->normals[i * 3 + 2] = normal[2];
1255 void Mod_GenerateVertexMesh (msurface_t *surf)
1258 float *in, s, t, normal[3];
1261 surf->lightmaptexturestride = 0;
1262 surf->lightmaptexture = NULL;
1264 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[6]) + surf->poly_numverts * (4 + 2 + 2 + 3) * sizeof(float));
1265 mesh->numverts = surf->poly_numverts;
1266 mesh->numtriangles = surf->poly_numverts - 2;
1267 mesh->verts = (float *)(mesh + 1);
1268 mesh->st = mesh->verts + mesh->numverts * 4;
1269 mesh->ab = mesh->st + mesh->numverts * 2;
1270 mesh->index = (int *)(mesh->ab + mesh->numverts * 2);
1271 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
1272 mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3);
1274 index = mesh->index;
1275 n = mesh->triangleneighbors;
1276 for (i = 0;i < mesh->numtriangles;i++)
1286 VectorCopy(surf->plane->normal, normal);
1287 if (surf->flags & SURF_PLANEBACK)
1288 VectorNegate(normal, normal);
1289 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1291 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
1292 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
1293 mesh->verts[i * 4 + 0] = in[0];
1294 mesh->verts[i * 4 + 1] = in[1];
1295 mesh->verts[i * 4 + 2] = in[2];
1296 mesh->st[i * 2 + 0] = s / surf->texinfo->texture->width;
1297 mesh->st[i * 2 + 1] = t / surf->texinfo->texture->height;
1298 mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f);
1299 mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f);
1300 mesh->normals[i * 3 + 0] = normal[0];
1301 mesh->normals[i * 3 + 1] = normal[1];
1302 mesh->normals[i * 3 + 2] = normal[2];
1306 void Mod_GenerateSurfacePolygon (msurface_t *surf)
1309 float *vec, *vert, mins[3], maxs[3], temp[3], dist;
1311 // convert edges back to a normal polygon
1312 surf->poly_numverts = surf->numedges;
1313 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
1314 for (i = 0;i < surf->numedges;i++)
1316 lindex = loadmodel->surfedges[surf->firstedge + i];
1318 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1320 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1321 VectorCopy (vec, vert);
1324 vert = surf->poly_verts;
1325 VectorCopy(vert, mins);
1326 VectorCopy(vert, maxs);
1328 for (i = 1;i < surf->poly_numverts;i++)
1330 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1331 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1332 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1335 VectorCopy(mins, surf->poly_mins);
1336 VectorCopy(maxs, surf->poly_maxs);
1337 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1338 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1339 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1340 surf->poly_radius2 = 0;
1341 vert = surf->poly_verts;
1342 for (i = 0;i < surf->poly_numverts;i++)
1344 VectorSubtract(vert, surf->poly_center, temp);
1345 dist = DotProduct(temp, temp);
1346 if (surf->poly_radius2 < dist)
1347 surf->poly_radius2 = dist;
1350 surf->poly_radius = sqrt(surf->poly_radius2);
1358 static void Mod_LoadFaces (lump_t *l)
1362 int i, count, surfnum, planenum, ssize, tsize;
1364 in = (void *)(mod_base + l->fileofs);
1365 if (l->filelen % sizeof(*in))
1366 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1367 count = l->filelen / sizeof(*in);
1368 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1370 loadmodel->surfaces = out;
1371 loadmodel->numsurfaces = count;
1372 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1373 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1375 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1377 out->number = surfnum;
1378 // FIXME: validate edges, texinfo, etc?
1379 out->firstedge = LittleLong(in->firstedge);
1380 out->numedges = LittleShort(in->numedges);
1381 if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges)
1382 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges);
1384 i = LittleShort (in->texinfo);
1385 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1386 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1387 out->texinfo = loadmodel->texinfo + i;
1388 out->flags = out->texinfo->texture->flags;
1390 planenum = LittleShort(in->planenum);
1391 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1392 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1394 if (LittleShort(in->side))
1395 out->flags |= SURF_PLANEBACK;
1397 out->plane = loadmodel->planes + planenum;
1399 // clear lightmap (filled in later)
1400 out->lightmaptexture = NULL;
1402 // force lightmap upload on first time seeing the surface
1403 out->cached_dlight = true;
1405 CalcSurfaceExtents (out);
1407 ssize = (out->extents[0] >> 4) + 1;
1408 tsize = (out->extents[1] >> 4) + 1;
1411 for (i = 0;i < MAXLIGHTMAPS;i++)
1412 out->styles[i] = in->styles[i];
1413 i = LittleLong(in->lightofs);
1415 out->samples = NULL;
1416 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1417 out->samples = loadmodel->lightdata + i;
1418 else // LordHavoc: white lighting (bsp version 29)
1419 out->samples = loadmodel->lightdata + (i * 3);
1421 Mod_GenerateSurfacePolygon(out);
1422 if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
1424 if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
1425 Host_Error ("Bad surface extents");
1426 Mod_GenerateWallMesh (out, false);
1427 // stainmap for permanent marks on walls
1428 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1430 memset(out->stainsamples, 255, ssize * tsize * 3);
1433 Mod_GenerateVertexMesh (out);
1442 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1444 node->parent = parent;
1445 if (node->contents < 0)
1447 Mod_SetParent (node->children[0], node);
1448 Mod_SetParent (node->children[1], node);
1456 static void Mod_LoadNodes (lump_t *l)
1462 in = (void *)(mod_base + l->fileofs);
1463 if (l->filelen % sizeof(*in))
1464 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1465 count = l->filelen / sizeof(*in);
1466 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1468 loadmodel->nodes = out;
1469 loadmodel->numnodes = count;
1471 for ( i=0 ; i<count ; i++, in++, out++)
1473 for (j=0 ; j<3 ; j++)
1475 out->mins[j] = LittleShort (in->mins[j]);
1476 out->maxs[j] = LittleShort (in->maxs[j]);
1479 p = LittleLong(in->planenum);
1480 out->plane = loadmodel->planes + p;
1482 out->firstsurface = LittleShort (in->firstface);
1483 out->numsurfaces = LittleShort (in->numfaces);
1485 for (j=0 ; j<2 ; j++)
1487 p = LittleShort (in->children[j]);
1489 out->children[j] = loadmodel->nodes + p;
1491 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1495 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1503 static void Mod_LoadLeafs (lump_t *l)
1509 in = (void *)(mod_base + l->fileofs);
1510 if (l->filelen % sizeof(*in))
1511 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1512 count = l->filelen / sizeof(*in);
1513 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1515 loadmodel->leafs = out;
1516 loadmodel->numleafs = count;
1518 for ( i=0 ; i<count ; i++, in++, out++)
1520 for (j=0 ; j<3 ; j++)
1522 out->mins[j] = LittleShort (in->mins[j]);
1523 out->maxs[j] = LittleShort (in->maxs[j]);
1526 p = LittleLong(in->contents);
1529 out->firstmarksurface = loadmodel->marksurfaces +
1530 LittleShort(in->firstmarksurface);
1531 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1533 p = LittleLong(in->visofs);
1535 out->compressed_vis = NULL;
1537 out->compressed_vis = loadmodel->visdata + p;
1539 for (j=0 ; j<4 ; j++)
1540 out->ambient_sound_level[j] = in->ambient_level[j];
1542 // FIXME: Insert caustics here
1551 static void Mod_LoadClipnodes (lump_t *l)
1553 dclipnode_t *in, *out;
1557 in = (void *)(mod_base + l->fileofs);
1558 if (l->filelen % sizeof(*in))
1559 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1560 count = l->filelen / sizeof(*in);
1561 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1563 loadmodel->clipnodes = out;
1564 loadmodel->numclipnodes = count;
1566 if (loadmodel->ishlbsp)
1568 hull = &loadmodel->hulls[1];
1569 hull->clipnodes = out;
1570 hull->firstclipnode = 0;
1571 hull->lastclipnode = count-1;
1572 hull->planes = loadmodel->planes;
1573 hull->clip_mins[0] = -16;
1574 hull->clip_mins[1] = -16;
1575 hull->clip_mins[2] = -36;
1576 hull->clip_maxs[0] = 16;
1577 hull->clip_maxs[1] = 16;
1578 hull->clip_maxs[2] = 36;
1579 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1581 hull = &loadmodel->hulls[2];
1582 hull->clipnodes = out;
1583 hull->firstclipnode = 0;
1584 hull->lastclipnode = count-1;
1585 hull->planes = loadmodel->planes;
1586 hull->clip_mins[0] = -32;
1587 hull->clip_mins[1] = -32;
1588 hull->clip_mins[2] = -32;
1589 hull->clip_maxs[0] = 32;
1590 hull->clip_maxs[1] = 32;
1591 hull->clip_maxs[2] = 32;
1592 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1594 hull = &loadmodel->hulls[3];
1595 hull->clipnodes = out;
1596 hull->firstclipnode = 0;
1597 hull->lastclipnode = count-1;
1598 hull->planes = loadmodel->planes;
1599 hull->clip_mins[0] = -16;
1600 hull->clip_mins[1] = -16;
1601 hull->clip_mins[2] = -18;
1602 hull->clip_maxs[0] = 16;
1603 hull->clip_maxs[1] = 16;
1604 hull->clip_maxs[2] = 18;
1605 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1609 hull = &loadmodel->hulls[1];
1610 hull->clipnodes = out;
1611 hull->firstclipnode = 0;
1612 hull->lastclipnode = count-1;
1613 hull->planes = loadmodel->planes;
1614 hull->clip_mins[0] = -16;
1615 hull->clip_mins[1] = -16;
1616 hull->clip_mins[2] = -24;
1617 hull->clip_maxs[0] = 16;
1618 hull->clip_maxs[1] = 16;
1619 hull->clip_maxs[2] = 32;
1620 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1622 hull = &loadmodel->hulls[2];
1623 hull->clipnodes = out;
1624 hull->firstclipnode = 0;
1625 hull->lastclipnode = count-1;
1626 hull->planes = loadmodel->planes;
1627 hull->clip_mins[0] = -32;
1628 hull->clip_mins[1] = -32;
1629 hull->clip_mins[2] = -24;
1630 hull->clip_maxs[0] = 32;
1631 hull->clip_maxs[1] = 32;
1632 hull->clip_maxs[2] = 64;
1633 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1636 for (i=0 ; i<count ; i++, out++, in++)
1638 out->planenum = LittleLong(in->planenum);
1639 out->children[0] = LittleShort(in->children[0]);
1640 out->children[1] = LittleShort(in->children[1]);
1641 if (out->children[0] >= count || out->children[1] >= count)
1642 Host_Error("Corrupt clipping hull (out of range child)\n");
1650 Duplicate the drawing hull structure as a clipping hull
1653 static void Mod_MakeHull0 (void)
1660 hull = &loadmodel->hulls[0];
1662 in = loadmodel->nodes;
1663 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1665 hull->clipnodes = out;
1666 hull->firstclipnode = 0;
1667 hull->lastclipnode = loadmodel->numnodes - 1;
1668 hull->planes = loadmodel->planes;
1670 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1672 out->planenum = in->plane - loadmodel->planes;
1673 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1674 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1680 Mod_LoadMarksurfaces
1683 static void Mod_LoadMarksurfaces (lump_t *l)
1688 in = (void *)(mod_base + l->fileofs);
1689 if (l->filelen % sizeof(*in))
1690 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1691 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1692 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1694 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1696 j = (unsigned) LittleShort(in[i]);
1697 if (j >= loadmodel->numsurfaces)
1698 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1699 loadmodel->marksurfaces[i] = j;
1708 static void Mod_LoadSurfedges (lump_t *l)
1713 in = (void *)(mod_base + l->fileofs);
1714 if (l->filelen % sizeof(*in))
1715 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1716 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1717 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1719 for (i = 0;i < loadmodel->numsurfedges;i++)
1720 loadmodel->surfedges[i] = LittleLong (in[i]);
1729 static void Mod_LoadPlanes (lump_t *l)
1735 in = (void *)(mod_base + l->fileofs);
1736 if (l->filelen % sizeof(*in))
1737 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1739 loadmodel->numplanes = l->filelen / sizeof(*in);
1740 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1742 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1744 out->normal[0] = LittleFloat (in->normal[0]);
1745 out->normal[1] = LittleFloat (in->normal[1]);
1746 out->normal[2] = LittleFloat (in->normal[2]);
1747 out->dist = LittleFloat (in->dist);
1753 #define MAX_POINTS_ON_WINDING 64
1759 double points[8][3]; // variable sized
1768 static winding_t *NewWinding (int points)
1773 if (points > MAX_POINTS_ON_WINDING)
1774 Sys_Error("NewWinding: too many points\n");
1776 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
1777 w = Mem_Alloc(loadmodel->mempool, size);
1778 memset (w, 0, size);
1783 static void FreeWinding (winding_t *w)
1793 static winding_t *BaseWindingForPlane (mplane_t *p)
1795 double org[3], vright[3], vup[3], normal[3];
1798 VectorCopy(p->normal, normal);
1799 VectorVectorsDouble(normal, vright, vup);
1801 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
1802 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
1804 // project a really big axis aligned box onto the plane
1807 VectorScale (p->normal, p->dist, org);
1809 VectorSubtract (org, vright, w->points[0]);
1810 VectorAdd (w->points[0], vup, w->points[0]);
1812 VectorAdd (org, vright, w->points[1]);
1813 VectorAdd (w->points[1], vup, w->points[1]);
1815 VectorAdd (org, vright, w->points[2]);
1816 VectorSubtract (w->points[2], vup, w->points[2]);
1818 VectorSubtract (org, vright, w->points[3]);
1819 VectorSubtract (w->points[3], vup, w->points[3]);
1830 Clips the winding to the plane, returning the new winding on the positive side
1831 Frees the input winding.
1832 If keepon is true, an exactly on-plane winding will be saved, otherwise
1833 it will be clipped away.
1836 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
1838 double dists[MAX_POINTS_ON_WINDING + 1];
1839 int sides[MAX_POINTS_ON_WINDING + 1];
1848 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1850 // determine sides for each point
1851 for (i = 0;i < in->numpoints;i++)
1853 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
1854 if (dot > ON_EPSILON)
1855 sides[i] = SIDE_FRONT;
1856 else if (dot < -ON_EPSILON)
1857 sides[i] = SIDE_BACK;
1862 sides[i] = sides[0];
1863 dists[i] = dists[0];
1865 if (keepon && !counts[0] && !counts[1])
1876 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1877 if (maxpts > MAX_POINTS_ON_WINDING)
1878 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1880 neww = NewWinding (maxpts);
1882 for (i = 0;i < in->numpoints;i++)
1884 if (neww->numpoints >= maxpts)
1885 Sys_Error ("ClipWinding: points exceeded estimate");
1889 if (sides[i] == SIDE_ON)
1891 VectorCopy (p1, neww->points[neww->numpoints]);
1896 if (sides[i] == SIDE_FRONT)
1898 VectorCopy (p1, neww->points[neww->numpoints]);
1902 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1905 // generate a split point
1906 p2 = in->points[(i+1)%in->numpoints];
1908 dot = dists[i] / (dists[i]-dists[i+1]);
1909 for (j = 0;j < 3;j++)
1910 { // avoid round off error when possible
1911 if (split->normal[j] == 1)
1912 mid[j] = split->dist;
1913 else if (split->normal[j] == -1)
1914 mid[j] = -split->dist;
1916 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1919 VectorCopy (mid, neww->points[neww->numpoints]);
1923 // free the original winding
1934 Divides a winding by a plane, producing one or two windings. The
1935 original winding is not damaged or freed. If only on one side, the
1936 returned winding will be the input winding. If on both sides, two
1937 new windings will be created.
1940 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
1942 double dists[MAX_POINTS_ON_WINDING + 1];
1943 int sides[MAX_POINTS_ON_WINDING + 1];
1952 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1954 // determine sides for each point
1955 for (i = 0;i < in->numpoints;i++)
1957 dot = DotProduct (in->points[i], split->normal);
1960 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
1961 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
1962 else sides[i] = SIDE_ON;
1965 sides[i] = sides[0];
1966 dists[i] = dists[0];
1968 *front = *back = NULL;
1981 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1983 if (maxpts > MAX_POINTS_ON_WINDING)
1984 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1986 *front = f = NewWinding (maxpts);
1987 *back = b = NewWinding (maxpts);
1989 for (i = 0;i < in->numpoints;i++)
1991 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
1992 Sys_Error ("DivideWinding: points exceeded estimate");
1996 if (sides[i] == SIDE_ON)
1998 VectorCopy (p1, f->points[f->numpoints]);
2000 VectorCopy (p1, b->points[b->numpoints]);
2005 if (sides[i] == SIDE_FRONT)
2007 VectorCopy (p1, f->points[f->numpoints]);
2010 else if (sides[i] == SIDE_BACK)
2012 VectorCopy (p1, b->points[b->numpoints]);
2016 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2019 // generate a split point
2020 p2 = in->points[(i+1)%in->numpoints];
2022 dot = dists[i] / (dists[i]-dists[i+1]);
2023 for (j = 0;j < 3;j++)
2024 { // avoid round off error when possible
2025 if (split->normal[j] == 1)
2026 mid[j] = split->dist;
2027 else if (split->normal[j] == -1)
2028 mid[j] = -split->dist;
2030 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2033 VectorCopy (mid, f->points[f->numpoints]);
2035 VectorCopy (mid, b->points[b->numpoints]);
2040 typedef struct portal_s
2043 mnode_t *nodes[2]; // [0] = front side of plane
2044 struct portal_s *next[2];
2046 struct portal_s *chain; // all portals are linked into a list
2050 static portal_t *portalchain;
2057 static portal_t *AllocPortal (void)
2060 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2061 p->chain = portalchain;
2066 static void FreePortal(portal_t *p)
2071 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2073 // calculate children first
2074 if (node->children[0]->contents >= 0)
2075 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2076 if (node->children[1]->contents >= 0)
2077 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2079 // make combined bounding box from children
2080 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2081 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2082 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2083 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2084 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2085 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2088 static void Mod_FinalizePortals(void)
2090 int i, j, numportals, numpoints;
2091 portal_t *p, *pnext;
2094 mleaf_t *leaf, *endleaf;
2097 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2098 leaf = loadmodel->leafs;
2099 endleaf = leaf + loadmodel->numleafs;
2100 for (;leaf < endleaf;leaf++)
2102 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2103 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2110 for (i = 0;i < 2;i++)
2112 leaf = (mleaf_t *)p->nodes[i];
2114 for (j = 0;j < w->numpoints;j++)
2116 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2117 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2118 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2119 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2120 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2121 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2128 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2130 // tally up portal and point counts
2136 // note: this check must match the one below or it will usually corrupt memory
2137 // 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
2138 if (p->winding && p->nodes[0] != p->nodes[1]
2139 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2140 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2143 numpoints += p->winding->numpoints * 2;
2147 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2148 loadmodel->numportals = numportals;
2149 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2150 loadmodel->numportalpoints = numpoints;
2151 // clear all leaf portal chains
2152 for (i = 0;i < loadmodel->numleafs;i++)
2153 loadmodel->leafs[i].portals = NULL;
2154 // process all portals in the global portal chain, while freeing them
2155 portal = loadmodel->portals;
2156 point = loadmodel->portalpoints;
2165 // note: this check must match the one above or it will usually corrupt memory
2166 // 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
2167 if (p->nodes[0] != p->nodes[1]
2168 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2169 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2171 // first make the back to front portal (forward portal)
2172 portal->points = point;
2173 portal->numpoints = p->winding->numpoints;
2174 portal->plane.dist = p->plane.dist;
2175 VectorCopy(p->plane.normal, portal->plane.normal);
2176 portal->here = (mleaf_t *)p->nodes[1];
2177 portal->past = (mleaf_t *)p->nodes[0];
2179 for (j = 0;j < portal->numpoints;j++)
2181 VectorCopy(p->winding->points[j], point->position);
2184 PlaneClassify(&portal->plane);
2186 // link into leaf's portal chain
2187 portal->next = portal->here->portals;
2188 portal->here->portals = portal;
2190 // advance to next portal
2193 // then make the front to back portal (backward portal)
2194 portal->points = point;
2195 portal->numpoints = p->winding->numpoints;
2196 portal->plane.dist = -p->plane.dist;
2197 VectorNegate(p->plane.normal, portal->plane.normal);
2198 portal->here = (mleaf_t *)p->nodes[0];
2199 portal->past = (mleaf_t *)p->nodes[1];
2201 for (j = portal->numpoints - 1;j >= 0;j--)
2203 VectorCopy(p->winding->points[j], point->position);
2206 PlaneClassify(&portal->plane);
2208 // link into leaf's portal chain
2209 portal->next = portal->here->portals;
2210 portal->here->portals = portal;
2212 // advance to next portal
2215 FreeWinding(p->winding);
2227 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2230 Host_Error ("AddPortalToNodes: NULL front node");
2232 Host_Error ("AddPortalToNodes: NULL back node");
2233 if (p->nodes[0] || p->nodes[1])
2234 Host_Error ("AddPortalToNodes: already included");
2235 // 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
2237 p->nodes[0] = front;
2238 p->next[0] = (portal_t *)front->portals;
2239 front->portals = (mportal_t *)p;
2242 p->next[1] = (portal_t *)back->portals;
2243 back->portals = (mportal_t *)p;
2248 RemovePortalFromNode
2251 static void RemovePortalFromNodes(portal_t *portal)
2255 void **portalpointer;
2257 for (i = 0;i < 2;i++)
2259 node = portal->nodes[i];
2261 portalpointer = (void **) &node->portals;
2266 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2270 if (portal->nodes[0] == node)
2272 *portalpointer = portal->next[0];
2273 portal->nodes[0] = NULL;
2275 else if (portal->nodes[1] == node)
2277 *portalpointer = portal->next[1];
2278 portal->nodes[1] = NULL;
2281 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2285 if (t->nodes[0] == node)
2286 portalpointer = (void **) &t->next[0];
2287 else if (t->nodes[1] == node)
2288 portalpointer = (void **) &t->next[1];
2290 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2295 static void Mod_RecursiveNodePortals (mnode_t *node)
2298 mnode_t *front, *back, *other_node;
2299 mplane_t clipplane, *plane;
2300 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2301 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2303 // if a leaf, we're done
2307 plane = node->plane;
2309 front = node->children[0];
2310 back = node->children[1];
2312 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2314 // create the new portal by generating a polygon for the node plane,
2315 // and clipping it by all of the other portals (which came from nodes above this one)
2316 nodeportal = AllocPortal ();
2317 nodeportal->plane = *node->plane;
2319 nodeportalwinding = BaseWindingForPlane (node->plane);
2320 side = 0; // shut up compiler warning
2321 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2323 clipplane = portal->plane;
2324 if (portal->nodes[0] == portal->nodes[1])
2325 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2326 if (portal->nodes[0] == node)
2328 else if (portal->nodes[1] == node)
2330 clipplane.dist = -clipplane.dist;
2331 VectorNegate (clipplane.normal, clipplane.normal);
2335 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2337 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2338 if (!nodeportalwinding)
2340 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2345 if (nodeportalwinding)
2347 // if the plane was not clipped on all sides, there was an error
2348 nodeportal->winding = nodeportalwinding;
2349 AddPortalToNodes (nodeportal, front, back);
2352 // split the portals of this node along this node's plane and assign them to the children of this node
2353 // (migrating the portals downward through the tree)
2354 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2356 if (portal->nodes[0] == portal->nodes[1])
2357 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2358 if (portal->nodes[0] == node)
2360 else if (portal->nodes[1] == node)
2363 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2364 nextportal = portal->next[side];
2366 other_node = portal->nodes[!side];
2367 RemovePortalFromNodes (portal);
2369 // cut the portal into two portals, one on each side of the node plane
2370 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2375 AddPortalToNodes (portal, back, other_node);
2377 AddPortalToNodes (portal, other_node, back);
2383 AddPortalToNodes (portal, front, other_node);
2385 AddPortalToNodes (portal, other_node, front);
2389 // the winding is split
2390 splitportal = AllocPortal ();
2391 temp = splitportal->chain;
2392 *splitportal = *portal;
2393 splitportal->chain = temp;
2394 splitportal->winding = backwinding;
2395 FreeWinding (portal->winding);
2396 portal->winding = frontwinding;
2400 AddPortalToNodes (portal, front, other_node);
2401 AddPortalToNodes (splitportal, back, other_node);
2405 AddPortalToNodes (portal, other_node, front);
2406 AddPortalToNodes (splitportal, other_node, back);
2410 Mod_RecursiveNodePortals(front);
2411 Mod_RecursiveNodePortals(back);
2415 static void Mod_MakePortals(void)
2418 Mod_RecursiveNodePortals (loadmodel->nodes);
2419 Mod_FinalizePortals();
2427 extern void R_DrawBrushModelFakeShadow (entity_render_t *ent);
2428 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2433 mempool_t *mainmempool;
2435 model_t *originalloadmodel;
2437 mod->type = mod_brush;
2439 header = (dheader_t *)buffer;
2441 i = LittleLong (header->version);
2442 if (i != BSPVERSION && i != 30)
2443 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2444 mod->ishlbsp = i == 30;
2445 if (loadmodel->isworldmodel)
2447 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2448 // until we get a texture for it...
2452 // swap all the lumps
2453 mod_base = (qbyte *)header;
2455 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
2456 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2460 // store which lightmap format to use
2461 mod->lightmaprgba = r_lightmaprgba.integer;
2463 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2464 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2465 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2466 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2467 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2468 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2469 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2470 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2471 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2472 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2473 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2474 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2475 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2476 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2477 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2482 mod->numframes = 2; // regular and alternate animation
2484 mainmempool = mod->mempool;
2485 loadname = mod->name;
2487 Mod_LoadLightList ();
2488 originalloadmodel = loadmodel;
2491 // set up the submodels (FIXME: this is confusing)
2493 for (i = 0;i < mod->numsubmodels;i++)
2496 float dist, modelyawradius, modelradius, *vec;
2499 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2500 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2504 bm = &mod->submodels[i];
2506 mod->hulls[0].firstclipnode = bm->headnode[0];
2507 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2509 mod->hulls[j].firstclipnode = bm->headnode[j];
2510 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2513 mod->firstmodelsurface = bm->firstface;
2514 mod->nummodelsurfaces = bm->numfaces;
2516 mod->DrawSky = NULL;
2517 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2518 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2520 // we only need to have a drawsky function if it is used (usually only on world model)
2521 if (surf->texinfo->texture->shader == &Cshader_sky)
2522 mod->DrawSky = R_DrawBrushModelSky;
2523 for (k = 0;k < surf->numedges;k++)
2525 l = mod->surfedges[k + surf->firstedge];
2527 vec = mod->vertexes[mod->edges[l].v[0]].position;
2529 vec = mod->vertexes[mod->edges[-l].v[1]].position;
2530 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2531 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2532 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2533 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2534 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2535 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2536 dist = vec[0]*vec[0]+vec[1]*vec[1];
2537 if (modelyawradius < dist)
2538 modelyawradius = dist;
2539 dist += vec[2]*vec[2];
2540 if (modelradius < dist)
2544 modelyawradius = sqrt(modelyawradius);
2545 modelradius = sqrt(modelradius);
2546 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2547 mod->yawmins[2] = mod->normalmins[2];
2548 mod->yawmaxs[2] = mod->normalmaxs[2];
2549 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2550 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2551 mod->radius = modelradius;
2552 mod->radius2 = modelradius * modelradius;
2553 // LordHavoc: check for empty submodels (lacrima.bsp has such a glitch)
2554 if (mod->normalmins[0] > mod->normalmaxs[0] || mod->normalmins[1] > mod->normalmaxs[1] || mod->normalmins[2] > mod->normalmaxs[2])
2556 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2557 VectorClear(mod->normalmins);
2558 VectorClear(mod->normalmaxs);
2559 VectorClear(mod->yawmins);
2560 VectorClear(mod->yawmaxs);
2561 VectorClear(mod->rotatedmins);
2562 VectorClear(mod->rotatedmaxs);
2567 mod->numleafs = bm->visleafs;
2569 mod->Draw = R_DrawBrushModelNormal;
2570 mod->DrawFakeShadow = R_DrawBrushModelFakeShadow;
2572 // LordHavoc: only register submodels if it is the world
2573 // (prevents bsp models from replacing world submodels)
2574 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2577 // duplicate the basic information
2578 sprintf (name, "*%i", i+1);
2579 loadmodel = Mod_FindName (name);
2581 strcpy (loadmodel->name, name);
2582 // textures and memory belong to the main model
2583 loadmodel->texturepool = NULL;
2584 loadmodel->mempool = NULL;
2589 loadmodel = originalloadmodel;
2590 Mod_ProcessLightList ();