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;
713 // construct shadow volumes for each light
715 for (i = 0, e = loadmodel->lights;i < loadmodel->numlights;i++, e++)
717 FIXME FINISH THIS CODE!
728 static void Mod_LoadVisibility (lump_t *l)
730 loadmodel->visdata = NULL;
733 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
734 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
737 // used only for HalfLife maps
738 void Mod_ParseWadsFromEntityLump(const char *data)
740 char key[128], value[4096];
745 if (!COM_ParseToken(&data))
747 if (com_token[0] != '{')
751 if (!COM_ParseToken(&data))
753 if (com_token[0] == '}')
754 break; // end of worldspawn
755 if (com_token[0] == '_')
756 strcpy(key, com_token + 1);
758 strcpy(key, com_token);
759 while (key[strlen(key)-1] == ' ') // remove trailing spaces
760 key[strlen(key)-1] = 0;
761 if (!COM_ParseToken(&data))
763 strcpy(value, com_token);
764 if (!strcmp("wad", key)) // for HalfLife maps
766 if (loadmodel->ishlbsp)
769 for (i = 0;i < 4096;i++)
770 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
776 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
777 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
779 else if (value[i] == ';' || value[i] == 0)
783 strcpy(wadname, "textures/");
784 strcat(wadname, &value[j]);
785 W_LoadTextureWadFile (wadname, false);
802 static void Mod_LoadEntities (lump_t *l)
804 loadmodel->entities = NULL;
807 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
808 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
809 if (loadmodel->ishlbsp)
810 Mod_ParseWadsFromEntityLump(loadmodel->entities);
819 static void Mod_LoadVertexes (lump_t *l)
825 in = (void *)(mod_base + l->fileofs);
826 if (l->filelen % sizeof(*in))
827 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
828 count = l->filelen / sizeof(*in);
829 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
831 loadmodel->vertexes = out;
832 loadmodel->numvertexes = count;
834 for ( i=0 ; i<count ; i++, in++, out++)
836 out->position[0] = LittleFloat (in->point[0]);
837 out->position[1] = LittleFloat (in->point[1]);
838 out->position[2] = LittleFloat (in->point[2]);
847 static void Mod_LoadSubmodels (lump_t *l)
853 in = (void *)(mod_base + l->fileofs);
854 if (l->filelen % sizeof(*in))
855 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
856 count = l->filelen / sizeof(*in);
857 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
859 loadmodel->submodels = out;
860 loadmodel->numsubmodels = count;
862 for ( i=0 ; i<count ; i++, in++, out++)
864 for (j=0 ; j<3 ; j++)
866 // spread the mins / maxs by a pixel
867 out->mins[j] = LittleFloat (in->mins[j]) - 1;
868 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
869 out->origin[j] = LittleFloat (in->origin[j]);
871 for (j=0 ; j<MAX_MAP_HULLS ; j++)
872 out->headnode[j] = LittleLong (in->headnode[j]);
873 out->visleafs = LittleLong (in->visleafs);
874 out->firstface = LittleLong (in->firstface);
875 out->numfaces = LittleLong (in->numfaces);
884 static void Mod_LoadEdges (lump_t *l)
890 in = (void *)(mod_base + l->fileofs);
891 if (l->filelen % sizeof(*in))
892 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
893 count = l->filelen / sizeof(*in);
894 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
896 loadmodel->edges = out;
897 loadmodel->numedges = count;
899 for ( i=0 ; i<count ; i++, in++, out++)
901 out->v[0] = (unsigned short)LittleShort(in->v[0]);
902 out->v[1] = (unsigned short)LittleShort(in->v[1]);
911 static void Mod_LoadTexinfo (lump_t *l)
915 int i, j, k, count, miptex;
917 in = (void *)(mod_base + l->fileofs);
918 if (l->filelen % sizeof(*in))
919 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
920 count = l->filelen / sizeof(*in);
921 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
923 loadmodel->texinfo = out;
924 loadmodel->numtexinfo = count;
926 for (i = 0;i < count;i++, in++, out++)
928 for (k = 0;k < 2;k++)
929 for (j = 0;j < 4;j++)
930 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
932 miptex = LittleLong (in->miptex);
933 out->flags = LittleLong (in->flags);
936 if (loadmodel->textures)
938 if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures)
939 Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures);
941 out->texture = loadmodel->textures + miptex;
943 if (out->flags & TEX_SPECIAL)
945 // if texture chosen is NULL or the shader needs a lightmap,
946 // force to notexture water shader
947 if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP)
948 out->texture = loadmodel->textures + (loadmodel->numtextures - 1);
952 // if texture chosen is NULL, force to notexture
953 if (out->texture == NULL)
954 out->texture = loadmodel->textures + (loadmodel->numtextures - 2);
963 Fills in s->texturemins[] and s->extents[]
966 static void CalcSurfaceExtents (msurface_t *s)
968 float mins[2], maxs[2], val;
972 int bmins[2], bmaxs[2];
974 mins[0] = mins[1] = 999999999;
975 maxs[0] = maxs[1] = -999999999;
979 for (i=0 ; i<s->numedges ; i++)
981 e = loadmodel->surfedges[s->firstedge+i];
983 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
985 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
987 for (j=0 ; j<2 ; j++)
989 val = v->position[0] * tex->vecs[j][0] +
990 v->position[1] * tex->vecs[j][1] +
991 v->position[2] * tex->vecs[j][2] +
1000 for (i=0 ; i<2 ; i++)
1002 bmins[i] = floor(mins[i]/16);
1003 bmaxs[i] = ceil(maxs[i]/16);
1005 s->texturemins[i] = bmins[i] * 16;
1006 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
1011 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
1016 mins[0] = mins[1] = mins[2] = 9999;
1017 maxs[0] = maxs[1] = maxs[2] = -9999;
1019 for (i = 0;i < numverts;i++)
1021 for (j = 0;j < 3;j++, v++)
1032 #define MAX_SUBDIVPOLYTRIANGLES 4096
1033 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
1035 static int subdivpolyverts, subdivpolytriangles;
1036 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
1037 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
1039 static int subdivpolylookupvert(vec3_t v)
1042 for (i = 0;i < subdivpolyverts;i++)
1043 if (subdivpolyvert[i][0] == v[0]
1044 && subdivpolyvert[i][1] == v[1]
1045 && subdivpolyvert[i][2] == v[2])
1047 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
1048 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
1049 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
1050 return subdivpolyverts++;
1053 static void SubdividePolygon (int numverts, float *verts)
1055 int i, i1, i2, i3, f, b, c, p;
1056 vec3_t mins, maxs, front[256], back[256];
1057 float m, *pv, *cv, dist[256], frac;
1060 Host_Error ("SubdividePolygon: ran out of verts in buffer");
1062 BoundPoly (numverts, verts, mins, maxs);
1064 for (i = 0;i < 3;i++)
1066 m = (mins[i] + maxs[i]) * 0.5;
1067 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
1068 if (maxs[i] - m < 8)
1070 if (m - mins[i] < 8)
1074 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
1075 dist[c] = cv[i] - m;
1078 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
1082 VectorCopy (pv, front[f]);
1087 VectorCopy (pv, back[b]);
1090 if (dist[p] == 0 || dist[c] == 0)
1092 if ( (dist[p] > 0) != (dist[c] > 0) )
1095 frac = dist[p] / (dist[p] - dist[c]);
1096 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
1097 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
1098 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
1104 SubdividePolygon (f, front[0]);
1105 SubdividePolygon (b, back[0]);
1109 i1 = subdivpolylookupvert(verts);
1110 i2 = subdivpolylookupvert(verts + 3);
1111 for (i = 2;i < numverts;i++)
1113 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
1115 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
1119 i3 = subdivpolylookupvert(verts + i * 3);
1120 subdivpolyindex[subdivpolytriangles][0] = i1;
1121 subdivpolyindex[subdivpolytriangles][1] = i2;
1122 subdivpolyindex[subdivpolytriangles][2] = i3;
1124 subdivpolytriangles++;
1130 Mod_GenerateWarpMesh
1132 Breaks a polygon up along axial 64 unit
1133 boundaries so that turbulent and sky warps
1134 can be done reasonably.
1137 void Mod_GenerateWarpMesh (msurface_t *surf)
1143 subdivpolytriangles = 0;
1144 subdivpolyverts = 0;
1145 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
1146 if (subdivpolytriangles < 1)
1147 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
1149 surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + subdivpolytriangles * sizeof(int[3]) + subdivpolyverts * sizeof(surfvertex_t));
1150 mesh->numverts = subdivpolyverts;
1151 mesh->numtriangles = subdivpolytriangles;
1152 mesh->vertex = (surfvertex_t *)(mesh + 1);
1153 mesh->index = (int *)(mesh->vertex + mesh->numverts);
1154 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1156 for (i = 0;i < mesh->numtriangles;i++)
1157 for (j = 0;j < 3;j++)
1158 mesh->index[i*3+j] = subdivpolyindex[i][j];
1160 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
1162 VectorCopy(subdivpolyvert[i], v->v);
1163 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
1164 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1169 void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly)
1171 int i, iu, iv, *index, *n, smax, tmax;
1172 float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3];
1175 smax = surf->extents[0] >> 4;
1176 tmax = surf->extents[1] >> 4;
1180 surf->lightmaptexturestride = 0;
1181 surf->lightmaptexture = NULL;
1189 surf->flags |= SURF_LIGHTMAP;
1190 if (r_miplightmaps.integer)
1192 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1193 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);
1197 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1198 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);
1200 R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale);
1201 uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1202 vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1205 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));
1206 mesh->numverts = surf->poly_numverts;
1207 mesh->numtriangles = surf->poly_numverts - 2;
1208 mesh->verts = (float *)(mesh + 1);
1209 mesh->st = mesh->verts + mesh->numverts * 4;
1210 mesh->uv = mesh->st + mesh->numverts * 2;
1211 mesh->ab = mesh->uv + mesh->numverts * 2;
1212 mesh->lightmapoffsets = (int *)(mesh->ab + mesh->numverts * 2);
1213 mesh->index = mesh->lightmapoffsets + mesh->numverts;
1214 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
1215 mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3);
1217 index = mesh->index;
1218 n = mesh->triangleneighbors;
1219 for (i = 0;i < mesh->numtriangles;i++)
1229 VectorCopy(surf->plane->normal, normal);
1230 if (surf->flags & SURF_PLANEBACK)
1231 VectorNegate(normal, normal);
1232 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1234 s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1235 t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1236 u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1237 v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1238 // LordHavoc: calc lightmap data offset for vertex lighting to use
1241 iu = bound(0, iu, smax);
1242 iv = bound(0, iv, tmax);
1243 u = u * uscale + ubase;
1244 v = v * vscale + vbase;
1246 mesh->verts[i * 4 + 0] = in[0];
1247 mesh->verts[i * 4 + 1] = in[1];
1248 mesh->verts[i * 4 + 2] = in[2];
1249 mesh->st[i * 2 + 0] = s / surf->texinfo->texture->width;
1250 mesh->st[i * 2 + 1] = t / surf->texinfo->texture->height;
1251 mesh->uv[i * 2 + 0] = u;
1252 mesh->uv[i * 2 + 1] = v;
1253 mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f);
1254 mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f);
1255 mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3);
1256 mesh->normals[i * 3 + 0] = normal[0];
1257 mesh->normals[i * 3 + 1] = normal[1];
1258 mesh->normals[i * 3 + 2] = normal[2];
1262 void Mod_GenerateVertexMesh (msurface_t *surf)
1265 float *in, s, t, normal[3];
1268 surf->lightmaptexturestride = 0;
1269 surf->lightmaptexture = NULL;
1271 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));
1272 mesh->numverts = surf->poly_numverts;
1273 mesh->numtriangles = surf->poly_numverts - 2;
1274 mesh->verts = (float *)(mesh + 1);
1275 mesh->st = mesh->verts + mesh->numverts * 4;
1276 mesh->ab = mesh->st + mesh->numverts * 2;
1277 mesh->index = (int *)(mesh->ab + mesh->numverts * 2);
1278 mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3;
1279 mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3);
1281 index = mesh->index;
1282 n = mesh->triangleneighbors;
1283 for (i = 0;i < mesh->numtriangles;i++)
1293 VectorCopy(surf->plane->normal, normal);
1294 if (surf->flags & SURF_PLANEBACK)
1295 VectorNegate(normal, normal);
1296 for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3)
1298 s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]);
1299 t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]);
1300 mesh->verts[i * 4 + 0] = in[0];
1301 mesh->verts[i * 4 + 1] = in[1];
1302 mesh->verts[i * 4 + 2] = in[2];
1303 mesh->st[i * 2 + 0] = s / surf->texinfo->texture->width;
1304 mesh->st[i * 2 + 1] = t / surf->texinfo->texture->height;
1305 mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f);
1306 mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f);
1307 mesh->normals[i * 3 + 0] = normal[0];
1308 mesh->normals[i * 3 + 1] = normal[1];
1309 mesh->normals[i * 3 + 2] = normal[2];
1313 void Mod_GenerateSurfacePolygon (msurface_t *surf)
1316 float *vec, *vert, mins[3], maxs[3], temp[3], dist;
1318 // convert edges back to a normal polygon
1319 surf->poly_numverts = surf->numedges;
1320 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
1321 for (i = 0;i < surf->numedges;i++)
1323 lindex = loadmodel->surfedges[surf->firstedge + i];
1325 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1327 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1328 VectorCopy (vec, vert);
1331 vert = surf->poly_verts;
1332 VectorCopy(vert, mins);
1333 VectorCopy(vert, maxs);
1335 for (i = 1;i < surf->poly_numverts;i++)
1337 if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0];
1338 if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1];
1339 if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2];
1342 VectorCopy(mins, surf->poly_mins);
1343 VectorCopy(maxs, surf->poly_maxs);
1344 surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f;
1345 surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f;
1346 surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f;
1347 surf->poly_radius2 = 0;
1348 vert = surf->poly_verts;
1349 for (i = 0;i < surf->poly_numverts;i++)
1351 VectorSubtract(vert, surf->poly_center, temp);
1352 dist = DotProduct(temp, temp);
1353 if (surf->poly_radius2 < dist)
1354 surf->poly_radius2 = dist;
1357 surf->poly_radius = sqrt(surf->poly_radius2);
1365 static void Mod_LoadFaces (lump_t *l)
1369 int i, count, surfnum, planenum, ssize, tsize;
1371 in = (void *)(mod_base + l->fileofs);
1372 if (l->filelen % sizeof(*in))
1373 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1374 count = l->filelen / sizeof(*in);
1375 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1377 loadmodel->surfaces = out;
1378 loadmodel->numsurfaces = count;
1379 loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1380 loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int));
1382 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1384 out->number = surfnum;
1385 // FIXME: validate edges, texinfo, etc?
1386 out->firstedge = LittleLong(in->firstedge);
1387 out->numedges = LittleShort(in->numedges);
1388 if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges)
1389 Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges);
1391 i = LittleShort (in->texinfo);
1392 if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo)
1393 Host_Error("Mod_LoadFaces: invalid texinfo index %i (model has %i texinfos)\n", i, loadmodel->numtexinfo);
1394 out->texinfo = loadmodel->texinfo + i;
1395 out->flags = out->texinfo->texture->flags;
1397 planenum = LittleShort(in->planenum);
1398 if ((unsigned int) planenum >= (unsigned int) loadmodel->numplanes)
1399 Host_Error("Mod_LoadFaces: invalid plane index %i (model has %i planes)\n", planenum, loadmodel->numplanes);
1401 if (LittleShort(in->side))
1402 out->flags |= SURF_PLANEBACK;
1404 out->plane = loadmodel->planes + planenum;
1406 // clear lightmap (filled in later)
1407 out->lightmaptexture = NULL;
1409 // force lightmap upload on first time seeing the surface
1410 out->cached_dlight = true;
1412 CalcSurfaceExtents (out);
1414 ssize = (out->extents[0] >> 4) + 1;
1415 tsize = (out->extents[1] >> 4) + 1;
1418 for (i = 0;i < MAXLIGHTMAPS;i++)
1419 out->styles[i] = in->styles[i];
1420 i = LittleLong(in->lightofs);
1422 out->samples = NULL;
1423 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1424 out->samples = loadmodel->lightdata + i;
1425 else // LordHavoc: white lighting (bsp version 29)
1426 out->samples = loadmodel->lightdata + (i * 3);
1428 Mod_GenerateSurfacePolygon(out);
1429 if (out->texinfo->texture->shader == &Cshader_wall_lightmap)
1431 if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256))
1432 Host_Error ("Bad surface extents");
1433 Mod_GenerateWallMesh (out, false);
1434 // stainmap for permanent marks on walls
1435 out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3);
1437 memset(out->stainsamples, 255, ssize * tsize * 3);
1440 Mod_GenerateVertexMesh (out);
1449 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1451 node->parent = parent;
1452 if (node->contents < 0)
1454 Mod_SetParent (node->children[0], node);
1455 Mod_SetParent (node->children[1], node);
1463 static void Mod_LoadNodes (lump_t *l)
1469 in = (void *)(mod_base + l->fileofs);
1470 if (l->filelen % sizeof(*in))
1471 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1472 count = l->filelen / sizeof(*in);
1473 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1475 loadmodel->nodes = out;
1476 loadmodel->numnodes = count;
1478 for ( i=0 ; i<count ; i++, in++, out++)
1480 for (j=0 ; j<3 ; j++)
1482 out->mins[j] = LittleShort (in->mins[j]);
1483 out->maxs[j] = LittleShort (in->maxs[j]);
1486 p = LittleLong(in->planenum);
1487 out->plane = loadmodel->planes + p;
1489 out->firstsurface = LittleShort (in->firstface);
1490 out->numsurfaces = LittleShort (in->numfaces);
1492 for (j=0 ; j<2 ; j++)
1494 p = LittleShort (in->children[j]);
1496 out->children[j] = loadmodel->nodes + p;
1498 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1502 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1510 static void Mod_LoadLeafs (lump_t *l)
1516 in = (void *)(mod_base + l->fileofs);
1517 if (l->filelen % sizeof(*in))
1518 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1519 count = l->filelen / sizeof(*in);
1520 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1522 loadmodel->leafs = out;
1523 loadmodel->numleafs = count;
1525 for ( i=0 ; i<count ; i++, in++, out++)
1527 for (j=0 ; j<3 ; j++)
1529 out->mins[j] = LittleShort (in->mins[j]);
1530 out->maxs[j] = LittleShort (in->maxs[j]);
1533 p = LittleLong(in->contents);
1536 out->firstmarksurface = loadmodel->marksurfaces +
1537 LittleShort(in->firstmarksurface);
1538 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1540 p = LittleLong(in->visofs);
1542 out->compressed_vis = NULL;
1544 out->compressed_vis = loadmodel->visdata + p;
1546 for (j=0 ; j<4 ; j++)
1547 out->ambient_sound_level[j] = in->ambient_level[j];
1549 // FIXME: Insert caustics here
1558 static void Mod_LoadClipnodes (lump_t *l)
1560 dclipnode_t *in, *out;
1564 in = (void *)(mod_base + l->fileofs);
1565 if (l->filelen % sizeof(*in))
1566 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1567 count = l->filelen / sizeof(*in);
1568 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1570 loadmodel->clipnodes = out;
1571 loadmodel->numclipnodes = count;
1573 if (loadmodel->ishlbsp)
1575 hull = &loadmodel->hulls[1];
1576 hull->clipnodes = out;
1577 hull->firstclipnode = 0;
1578 hull->lastclipnode = count-1;
1579 hull->planes = loadmodel->planes;
1580 hull->clip_mins[0] = -16;
1581 hull->clip_mins[1] = -16;
1582 hull->clip_mins[2] = -36;
1583 hull->clip_maxs[0] = 16;
1584 hull->clip_maxs[1] = 16;
1585 hull->clip_maxs[2] = 36;
1586 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1588 hull = &loadmodel->hulls[2];
1589 hull->clipnodes = out;
1590 hull->firstclipnode = 0;
1591 hull->lastclipnode = count-1;
1592 hull->planes = loadmodel->planes;
1593 hull->clip_mins[0] = -32;
1594 hull->clip_mins[1] = -32;
1595 hull->clip_mins[2] = -32;
1596 hull->clip_maxs[0] = 32;
1597 hull->clip_maxs[1] = 32;
1598 hull->clip_maxs[2] = 32;
1599 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1601 hull = &loadmodel->hulls[3];
1602 hull->clipnodes = out;
1603 hull->firstclipnode = 0;
1604 hull->lastclipnode = count-1;
1605 hull->planes = loadmodel->planes;
1606 hull->clip_mins[0] = -16;
1607 hull->clip_mins[1] = -16;
1608 hull->clip_mins[2] = -18;
1609 hull->clip_maxs[0] = 16;
1610 hull->clip_maxs[1] = 16;
1611 hull->clip_maxs[2] = 18;
1612 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1616 hull = &loadmodel->hulls[1];
1617 hull->clipnodes = out;
1618 hull->firstclipnode = 0;
1619 hull->lastclipnode = count-1;
1620 hull->planes = loadmodel->planes;
1621 hull->clip_mins[0] = -16;
1622 hull->clip_mins[1] = -16;
1623 hull->clip_mins[2] = -24;
1624 hull->clip_maxs[0] = 16;
1625 hull->clip_maxs[1] = 16;
1626 hull->clip_maxs[2] = 32;
1627 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1629 hull = &loadmodel->hulls[2];
1630 hull->clipnodes = out;
1631 hull->firstclipnode = 0;
1632 hull->lastclipnode = count-1;
1633 hull->planes = loadmodel->planes;
1634 hull->clip_mins[0] = -32;
1635 hull->clip_mins[1] = -32;
1636 hull->clip_mins[2] = -24;
1637 hull->clip_maxs[0] = 32;
1638 hull->clip_maxs[1] = 32;
1639 hull->clip_maxs[2] = 64;
1640 VectorSubtract(hull->clip_maxs, hull->clip_mins, hull->clip_size);
1643 for (i=0 ; i<count ; i++, out++, in++)
1645 out->planenum = LittleLong(in->planenum);
1646 out->children[0] = LittleShort(in->children[0]);
1647 out->children[1] = LittleShort(in->children[1]);
1648 if (out->children[0] >= count || out->children[1] >= count)
1649 Host_Error("Corrupt clipping hull (out of range child)\n");
1657 Duplicate the drawing hull structure as a clipping hull
1660 static void Mod_MakeHull0 (void)
1667 hull = &loadmodel->hulls[0];
1669 in = loadmodel->nodes;
1670 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1672 hull->clipnodes = out;
1673 hull->firstclipnode = 0;
1674 hull->lastclipnode = loadmodel->numnodes - 1;
1675 hull->planes = loadmodel->planes;
1677 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1679 out->planenum = in->plane - loadmodel->planes;
1680 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1681 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1687 Mod_LoadMarksurfaces
1690 static void Mod_LoadMarksurfaces (lump_t *l)
1695 in = (void *)(mod_base + l->fileofs);
1696 if (l->filelen % sizeof(*in))
1697 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1698 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1699 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int));
1701 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1703 j = (unsigned) LittleShort(in[i]);
1704 if (j >= loadmodel->numsurfaces)
1705 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1706 loadmodel->marksurfaces[i] = j;
1715 static void Mod_LoadSurfedges (lump_t *l)
1720 in = (void *)(mod_base + l->fileofs);
1721 if (l->filelen % sizeof(*in))
1722 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1723 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1724 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1726 for (i = 0;i < loadmodel->numsurfedges;i++)
1727 loadmodel->surfedges[i] = LittleLong (in[i]);
1736 static void Mod_LoadPlanes (lump_t *l)
1742 in = (void *)(mod_base + l->fileofs);
1743 if (l->filelen % sizeof(*in))
1744 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1746 loadmodel->numplanes = l->filelen / sizeof(*in);
1747 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1749 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1751 out->normal[0] = LittleFloat (in->normal[0]);
1752 out->normal[1] = LittleFloat (in->normal[1]);
1753 out->normal[2] = LittleFloat (in->normal[2]);
1754 out->dist = LittleFloat (in->dist);
1760 #define MAX_POINTS_ON_WINDING 64
1766 double points[8][3]; // variable sized
1775 static winding_t *NewWinding (int points)
1780 if (points > MAX_POINTS_ON_WINDING)
1781 Sys_Error("NewWinding: too many points\n");
1783 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
1784 w = Mem_Alloc(loadmodel->mempool, size);
1785 memset (w, 0, size);
1790 static void FreeWinding (winding_t *w)
1800 static winding_t *BaseWindingForPlane (mplane_t *p)
1802 double org[3], vright[3], vup[3], normal[3];
1805 VectorCopy(p->normal, normal);
1806 VectorVectorsDouble(normal, vright, vup);
1808 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
1809 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
1811 // project a really big axis aligned box onto the plane
1814 VectorScale (p->normal, p->dist, org);
1816 VectorSubtract (org, vright, w->points[0]);
1817 VectorAdd (w->points[0], vup, w->points[0]);
1819 VectorAdd (org, vright, w->points[1]);
1820 VectorAdd (w->points[1], vup, w->points[1]);
1822 VectorAdd (org, vright, w->points[2]);
1823 VectorSubtract (w->points[2], vup, w->points[2]);
1825 VectorSubtract (org, vright, w->points[3]);
1826 VectorSubtract (w->points[3], vup, w->points[3]);
1837 Clips the winding to the plane, returning the new winding on the positive side
1838 Frees the input winding.
1839 If keepon is true, an exactly on-plane winding will be saved, otherwise
1840 it will be clipped away.
1843 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
1845 double dists[MAX_POINTS_ON_WINDING + 1];
1846 int sides[MAX_POINTS_ON_WINDING + 1];
1855 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1857 // determine sides for each point
1858 for (i = 0;i < in->numpoints;i++)
1860 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
1861 if (dot > ON_EPSILON)
1862 sides[i] = SIDE_FRONT;
1863 else if (dot < -ON_EPSILON)
1864 sides[i] = SIDE_BACK;
1869 sides[i] = sides[0];
1870 dists[i] = dists[0];
1872 if (keepon && !counts[0] && !counts[1])
1883 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1884 if (maxpts > MAX_POINTS_ON_WINDING)
1885 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1887 neww = NewWinding (maxpts);
1889 for (i = 0;i < in->numpoints;i++)
1891 if (neww->numpoints >= maxpts)
1892 Sys_Error ("ClipWinding: points exceeded estimate");
1896 if (sides[i] == SIDE_ON)
1898 VectorCopy (p1, neww->points[neww->numpoints]);
1903 if (sides[i] == SIDE_FRONT)
1905 VectorCopy (p1, neww->points[neww->numpoints]);
1909 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1912 // generate a split point
1913 p2 = in->points[(i+1)%in->numpoints];
1915 dot = dists[i] / (dists[i]-dists[i+1]);
1916 for (j = 0;j < 3;j++)
1917 { // avoid round off error when possible
1918 if (split->normal[j] == 1)
1919 mid[j] = split->dist;
1920 else if (split->normal[j] == -1)
1921 mid[j] = -split->dist;
1923 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1926 VectorCopy (mid, neww->points[neww->numpoints]);
1930 // free the original winding
1941 Divides a winding by a plane, producing one or two windings. The
1942 original winding is not damaged or freed. If only on one side, the
1943 returned winding will be the input winding. If on both sides, two
1944 new windings will be created.
1947 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
1949 double dists[MAX_POINTS_ON_WINDING + 1];
1950 int sides[MAX_POINTS_ON_WINDING + 1];
1959 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1961 // determine sides for each point
1962 for (i = 0;i < in->numpoints;i++)
1964 dot = DotProduct (in->points[i], split->normal);
1967 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
1968 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
1969 else sides[i] = SIDE_ON;
1972 sides[i] = sides[0];
1973 dists[i] = dists[0];
1975 *front = *back = NULL;
1988 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1990 if (maxpts > MAX_POINTS_ON_WINDING)
1991 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1993 *front = f = NewWinding (maxpts);
1994 *back = b = NewWinding (maxpts);
1996 for (i = 0;i < in->numpoints;i++)
1998 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
1999 Sys_Error ("DivideWinding: points exceeded estimate");
2003 if (sides[i] == SIDE_ON)
2005 VectorCopy (p1, f->points[f->numpoints]);
2007 VectorCopy (p1, b->points[b->numpoints]);
2012 if (sides[i] == SIDE_FRONT)
2014 VectorCopy (p1, f->points[f->numpoints]);
2017 else if (sides[i] == SIDE_BACK)
2019 VectorCopy (p1, b->points[b->numpoints]);
2023 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
2026 // generate a split point
2027 p2 = in->points[(i+1)%in->numpoints];
2029 dot = dists[i] / (dists[i]-dists[i+1]);
2030 for (j = 0;j < 3;j++)
2031 { // avoid round off error when possible
2032 if (split->normal[j] == 1)
2033 mid[j] = split->dist;
2034 else if (split->normal[j] == -1)
2035 mid[j] = -split->dist;
2037 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
2040 VectorCopy (mid, f->points[f->numpoints]);
2042 VectorCopy (mid, b->points[b->numpoints]);
2047 typedef struct portal_s
2050 mnode_t *nodes[2]; // [0] = front side of plane
2051 struct portal_s *next[2];
2053 struct portal_s *chain; // all portals are linked into a list
2057 static portal_t *portalchain;
2064 static portal_t *AllocPortal (void)
2067 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
2068 p->chain = portalchain;
2073 static void FreePortal(portal_t *p)
2078 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
2080 // calculate children first
2081 if (node->children[0]->contents >= 0)
2082 Mod_RecursiveRecalcNodeBBox(node->children[0]);
2083 if (node->children[1]->contents >= 0)
2084 Mod_RecursiveRecalcNodeBBox(node->children[1]);
2086 // make combined bounding box from children
2087 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
2088 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
2089 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
2090 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
2091 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
2092 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
2095 static void Mod_FinalizePortals(void)
2097 int i, j, numportals, numpoints;
2098 portal_t *p, *pnext;
2101 mleaf_t *leaf, *endleaf;
2104 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2105 leaf = loadmodel->leafs;
2106 endleaf = leaf + loadmodel->numleafs;
2107 for (;leaf < endleaf;leaf++)
2109 VectorSet(leaf->mins, 2000000000, 2000000000, 2000000000);
2110 VectorSet(leaf->maxs, -2000000000, -2000000000, -2000000000);
2117 for (i = 0;i < 2;i++)
2119 leaf = (mleaf_t *)p->nodes[i];
2121 for (j = 0;j < w->numpoints;j++)
2123 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2124 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2125 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2126 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2127 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2128 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2135 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2137 // tally up portal and point counts
2143 // note: this check must match the one below or it will usually corrupt memory
2144 // 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
2145 if (p->winding && p->nodes[0] != p->nodes[1]
2146 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2147 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2150 numpoints += p->winding->numpoints * 2;
2154 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2155 loadmodel->numportals = numportals;
2156 loadmodel->portalpoints = (void *) ((qbyte *) loadmodel->portals + numportals * sizeof(mportal_t));
2157 loadmodel->numportalpoints = numpoints;
2158 // clear all leaf portal chains
2159 for (i = 0;i < loadmodel->numleafs;i++)
2160 loadmodel->leafs[i].portals = NULL;
2161 // process all portals in the global portal chain, while freeing them
2162 portal = loadmodel->portals;
2163 point = loadmodel->portalpoints;
2172 // note: this check must match the one above or it will usually corrupt memory
2173 // 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
2174 if (p->nodes[0] != p->nodes[1]
2175 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2176 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2178 // first make the back to front portal (forward portal)
2179 portal->points = point;
2180 portal->numpoints = p->winding->numpoints;
2181 portal->plane.dist = p->plane.dist;
2182 VectorCopy(p->plane.normal, portal->plane.normal);
2183 portal->here = (mleaf_t *)p->nodes[1];
2184 portal->past = (mleaf_t *)p->nodes[0];
2186 for (j = 0;j < portal->numpoints;j++)
2188 VectorCopy(p->winding->points[j], point->position);
2191 PlaneClassify(&portal->plane);
2193 // link into leaf's portal chain
2194 portal->next = portal->here->portals;
2195 portal->here->portals = portal;
2197 // advance to next portal
2200 // then make the front to back portal (backward portal)
2201 portal->points = point;
2202 portal->numpoints = p->winding->numpoints;
2203 portal->plane.dist = -p->plane.dist;
2204 VectorNegate(p->plane.normal, portal->plane.normal);
2205 portal->here = (mleaf_t *)p->nodes[0];
2206 portal->past = (mleaf_t *)p->nodes[1];
2208 for (j = portal->numpoints - 1;j >= 0;j--)
2210 VectorCopy(p->winding->points[j], point->position);
2213 PlaneClassify(&portal->plane);
2215 // link into leaf's portal chain
2216 portal->next = portal->here->portals;
2217 portal->here->portals = portal;
2219 // advance to next portal
2222 FreeWinding(p->winding);
2234 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2237 Host_Error ("AddPortalToNodes: NULL front node");
2239 Host_Error ("AddPortalToNodes: NULL back node");
2240 if (p->nodes[0] || p->nodes[1])
2241 Host_Error ("AddPortalToNodes: already included");
2242 // 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
2244 p->nodes[0] = front;
2245 p->next[0] = (portal_t *)front->portals;
2246 front->portals = (mportal_t *)p;
2249 p->next[1] = (portal_t *)back->portals;
2250 back->portals = (mportal_t *)p;
2255 RemovePortalFromNode
2258 static void RemovePortalFromNodes(portal_t *portal)
2262 void **portalpointer;
2264 for (i = 0;i < 2;i++)
2266 node = portal->nodes[i];
2268 portalpointer = (void **) &node->portals;
2273 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2277 if (portal->nodes[0] == node)
2279 *portalpointer = portal->next[0];
2280 portal->nodes[0] = NULL;
2282 else if (portal->nodes[1] == node)
2284 *portalpointer = portal->next[1];
2285 portal->nodes[1] = NULL;
2288 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2292 if (t->nodes[0] == node)
2293 portalpointer = (void **) &t->next[0];
2294 else if (t->nodes[1] == node)
2295 portalpointer = (void **) &t->next[1];
2297 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2302 static void Mod_RecursiveNodePortals (mnode_t *node)
2305 mnode_t *front, *back, *other_node;
2306 mplane_t clipplane, *plane;
2307 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2308 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2310 // if a leaf, we're done
2314 plane = node->plane;
2316 front = node->children[0];
2317 back = node->children[1];
2319 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2321 // create the new portal by generating a polygon for the node plane,
2322 // and clipping it by all of the other portals (which came from nodes above this one)
2323 nodeportal = AllocPortal ();
2324 nodeportal->plane = *node->plane;
2326 nodeportalwinding = BaseWindingForPlane (node->plane);
2327 side = 0; // shut up compiler warning
2328 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2330 clipplane = portal->plane;
2331 if (portal->nodes[0] == portal->nodes[1])
2332 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2333 if (portal->nodes[0] == node)
2335 else if (portal->nodes[1] == node)
2337 clipplane.dist = -clipplane.dist;
2338 VectorNegate (clipplane.normal, clipplane.normal);
2342 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2344 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2345 if (!nodeportalwinding)
2347 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2352 if (nodeportalwinding)
2354 // if the plane was not clipped on all sides, there was an error
2355 nodeportal->winding = nodeportalwinding;
2356 AddPortalToNodes (nodeportal, front, back);
2359 // split the portals of this node along this node's plane and assign them to the children of this node
2360 // (migrating the portals downward through the tree)
2361 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2363 if (portal->nodes[0] == portal->nodes[1])
2364 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2365 if (portal->nodes[0] == node)
2367 else if (portal->nodes[1] == node)
2370 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2371 nextportal = portal->next[side];
2373 other_node = portal->nodes[!side];
2374 RemovePortalFromNodes (portal);
2376 // cut the portal into two portals, one on each side of the node plane
2377 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2382 AddPortalToNodes (portal, back, other_node);
2384 AddPortalToNodes (portal, other_node, back);
2390 AddPortalToNodes (portal, front, other_node);
2392 AddPortalToNodes (portal, other_node, front);
2396 // the winding is split
2397 splitportal = AllocPortal ();
2398 temp = splitportal->chain;
2399 *splitportal = *portal;
2400 splitportal->chain = temp;
2401 splitportal->winding = backwinding;
2402 FreeWinding (portal->winding);
2403 portal->winding = frontwinding;
2407 AddPortalToNodes (portal, front, other_node);
2408 AddPortalToNodes (splitportal, back, other_node);
2412 AddPortalToNodes (portal, other_node, front);
2413 AddPortalToNodes (splitportal, other_node, back);
2417 Mod_RecursiveNodePortals(front);
2418 Mod_RecursiveNodePortals(back);
2422 static void Mod_MakePortals(void)
2425 Mod_RecursiveNodePortals (loadmodel->nodes);
2426 Mod_FinalizePortals();
2434 extern void R_DrawBrushModelFakeShadow (entity_render_t *ent);
2435 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2440 mempool_t *mainmempool;
2442 model_t *originalloadmodel;
2444 mod->type = mod_brush;
2446 header = (dheader_t *)buffer;
2448 i = LittleLong (header->version);
2449 if (i != BSPVERSION && i != 30)
2450 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION);
2451 mod->ishlbsp = i == 30;
2452 if (loadmodel->isworldmodel)
2454 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2455 // until we get a texture for it...
2459 // swap all the lumps
2460 mod_base = (qbyte *)header;
2462 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
2463 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2467 // store which lightmap format to use
2468 mod->lightmaprgba = r_lightmaprgba.integer;
2470 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2471 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2472 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2473 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2474 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2475 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2476 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2477 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2478 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2479 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2480 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2481 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2482 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2483 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2484 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2489 mod->numframes = 2; // regular and alternate animation
2491 mainmempool = mod->mempool;
2492 loadname = mod->name;
2494 Mod_LoadLightList ();
2495 originalloadmodel = loadmodel;
2498 // set up the submodels (FIXME: this is confusing)
2500 for (i = 0;i < mod->numsubmodels;i++)
2503 float dist, modelyawradius, modelradius, *vec;
2506 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2507 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2511 bm = &mod->submodels[i];
2513 mod->hulls[0].firstclipnode = bm->headnode[0];
2514 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2516 mod->hulls[j].firstclipnode = bm->headnode[j];
2517 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2520 mod->firstmodelsurface = bm->firstface;
2521 mod->nummodelsurfaces = bm->numfaces;
2523 mod->DrawSky = NULL;
2524 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2525 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2527 // we only need to have a drawsky function if it is used (usually only on world model)
2528 if (surf->texinfo->texture->shader == &Cshader_sky)
2529 mod->DrawSky = R_DrawBrushModelSky;
2530 for (k = 0;k < surf->numedges;k++)
2532 l = mod->surfedges[k + surf->firstedge];
2534 vec = mod->vertexes[mod->edges[l].v[0]].position;
2536 vec = mod->vertexes[mod->edges[-l].v[1]].position;
2537 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2538 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2539 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2540 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2541 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2542 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2543 dist = vec[0]*vec[0]+vec[1]*vec[1];
2544 if (modelyawradius < dist)
2545 modelyawradius = dist;
2546 dist += vec[2]*vec[2];
2547 if (modelradius < dist)
2551 modelyawradius = sqrt(modelyawradius);
2552 modelradius = sqrt(modelradius);
2553 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2554 mod->yawmins[2] = mod->normalmins[2];
2555 mod->yawmaxs[2] = mod->normalmaxs[2];
2556 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2557 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2558 mod->radius = modelradius;
2559 mod->radius2 = modelradius * modelradius;
2560 // LordHavoc: check for empty submodels (lacrima.bsp has such a glitch)
2561 if (mod->normalmins[0] > mod->normalmaxs[0] || mod->normalmins[1] > mod->normalmaxs[1] || mod->normalmins[2] > mod->normalmaxs[2])
2563 Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname);
2564 VectorClear(mod->normalmins);
2565 VectorClear(mod->normalmaxs);
2566 VectorClear(mod->yawmins);
2567 VectorClear(mod->yawmaxs);
2568 VectorClear(mod->rotatedmins);
2569 VectorClear(mod->rotatedmaxs);
2574 mod->numleafs = bm->visleafs;
2576 mod->Draw = R_DrawBrushModelNormal;
2577 mod->DrawFakeShadow = R_DrawBrushModelFakeShadow;
2579 // LordHavoc: only register submodels if it is the world
2580 // (prevents bsp models from replacing world submodels)
2581 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2584 // duplicate the basic information
2585 sprintf (name, "*%i", i+1);
2586 loadmodel = Mod_FindName (name);
2588 strcpy (loadmodel->name, name);
2589 // textures and memory belong to the main model
2590 loadmodel->texturepool = NULL;
2591 loadmodel->mempool = NULL;
2596 loadmodel = originalloadmodel;
2597 Mod_ProcessLightList ();