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 byte mod_novis[(MAX_MAP_LEAFS + 7)/ 8];
25 cvar_t r_subdivide_size = {CVAR_SAVE, "r_subdivide_size", "128"};
26 cvar_t halflifebsp = {0, "halflifebsp", "0"};
27 cvar_t r_novis = {0, "r_novis", "0"};
28 cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"};
29 cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"};
30 cvar_t r_vertexsurfacesthreshold = {CVAR_SAVE, "r_vertexsurfacesthreshold", "48"};
37 void Mod_BrushInit (void)
39 Cvar_RegisterVariable(&r_subdivide_size);
40 Cvar_RegisterVariable(&halflifebsp);
41 Cvar_RegisterVariable(&r_novis);
42 Cvar_RegisterVariable(&r_miplightmaps);
43 Cvar_RegisterVariable(&r_lightmaprgba);
44 Cvar_RegisterVariable(&r_vertexsurfacesthreshold);
45 memset(mod_novis, 0xff, sizeof(mod_novis));
48 void Mod_Brush_SERAddEntity(void)
50 R_Clip_AddBox(currentrenderentity->mins, currentrenderentity->maxs, R_Entity_Callback, currentrenderentity, NULL);
58 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
62 Mod_CheckLoaded(model);
63 // if (!model || !model->nodes)
64 // Sys_Error ("Mod_PointInLeaf: bad model");
66 // LordHavoc: modified to start at first clip node,
67 // in other words: first node of the (sub)model
68 node = model->nodes + model->hulls[0].firstclipnode;
69 while (node->contents == 0)
70 node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist];
72 return (mleaf_t *)node;
75 void Mod_FindNonSolidLocation(vec3_t pos, model_t *mod)
77 if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
78 pos[0]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
79 pos[0]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
81 pos[1]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
82 pos[1]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
84 pos[2]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
85 pos[2]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return;
90 mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model)
96 if (!model || !model->nodes)
97 Sys_Error ("Mod_PointInLeaf: bad model");
102 if (node->contents < 0)
103 return (mleaf_t *)node;
105 d = DotProduct (p,plane->normal) - plane->dist;
107 node = node->children[0];
109 node = node->children[1];
112 return NULL; // never reached
121 static byte *Mod_DecompressVis (byte *in, model_t *model)
123 static byte decompressed[MAX_MAP_LEAFS/8];
128 row = (model->numleafs+7)>>3;
133 { // no vis info, so make all visible
158 } while (out - decompressed < row);
163 byte *Mod_LeafPVS (mleaf_t *leaf, model_t *model)
165 if (r_novis.integer || leaf == model->leafs || leaf->compressed_vis == NULL)
167 return Mod_DecompressVis (leaf->compressed_vis, model);
170 void Mod_SetupNoTexture(void)
175 for (y = 0;y < 16;y++)
177 for (x = 0;x < 16;x++)
179 if ((y < 8) ^ (x < 8))
196 memset(&loadmodel->notexture, 0, sizeof(texture_t));
197 strcpy(loadmodel->notexture.name, "notexture");
198 loadmodel->notexture.width = 16;
199 loadmodel->notexture.height = 16;
200 loadmodel->notexture.flags = 0;
201 loadmodel->notexture.texture = R_LoadTexture(loadmodel->texturepool, "notexture", 16, 16, &pix[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP);
209 static void Mod_LoadTextures (lump_t *l)
211 int i, j, k, num, max, altmax, mtwidth, mtheight, *dofs;
213 texture_t *tx, *tx2, *anims[10], *altanims[10];
215 byte *data, *mtdata, *data2;
218 Mod_SetupNoTexture();
222 loadmodel->textures = NULL;
226 m = (dmiptexlump_t *)(mod_base + l->fileofs);
228 m->nummiptex = LittleLong (m->nummiptex);
230 loadmodel->numtextures = m->nummiptex;
231 loadmodel->textures = Mem_Alloc(loadmodel->mempool, m->nummiptex * sizeof(*loadmodel->textures));
233 // just to work around bounds checking when debugging with it (array index out of bounds error thing)
235 for (i = 0;i < m->nummiptex;i++)
237 dofs[i] = LittleLong(dofs[i]);
240 dmiptex = (miptex_t *)((byte *)m + dofs[i]);
241 mtwidth = LittleLong (dmiptex->width);
242 mtheight = LittleLong (dmiptex->height);
244 j = LittleLong (dmiptex->offsets[0]);
248 if (j < 40 || j + mtwidth * mtheight > l->filelen)
249 Host_Error ("Texture %s is corrupt or incomplete\n", dmiptex->name);
250 mtdata = (byte *)dmiptex + j;
253 if ((mtwidth & 15) || (mtheight & 15))
254 Host_Error ("Texture %s is not 16 aligned", dmiptex->name);
255 // LordHavoc: rewriting the map texture loader for GLQuake
256 tx = Mem_Alloc(loadmodel->mempool, sizeof(texture_t));
257 memset(tx, 0, sizeof(texture_t));
259 tx->alternate_anims = NULL;
260 loadmodel->textures[i] = tx;
262 // LordHavoc: force all names to lowercase and make sure they are terminated while copying
263 for (j = 0;dmiptex->name[j] && j < 15;j++)
265 if (dmiptex->name[j] >= 'A' && dmiptex->name[j] <= 'Z')
266 tx->name[j] = dmiptex->name[j] + ('a' - 'A');
268 tx->name[j] = dmiptex->name[j];
275 Con_Printf("warning: unnamed texture in %s\n", loadmodel->name);
276 sprintf(tx->name, "unnamed%i", i);
280 tx->height = mtheight;
282 tx->glowtexture = NULL;
283 tx->fogtexture = NULL;
285 if (!loadmodel->ishlbsp && !strncmp(tx->name,"sky",3) && mtwidth == 256 && mtheight == 128) // LordHavoc: HL sky textures are entirely unrelated
287 data = loadimagepixels(tx->name, false, 0, 0);
290 if (image_width == 256 && image_height == 128)
292 if (loadmodel->isworldmodel)
299 Host_Error("Mod_LoadTextures: replacement sky image must be 256x128 pixels\n");
302 else if (loadmodel->isworldmodel)
303 R_InitSky (mtdata, 1);
305 else if ((tx->texture = loadtextureimagewithmask(loadmodel->texturepool, tx->name, 0, 0, false, true, true)))
307 tx->fogtexture = image_masktex;
308 strcpy(name, tx->name);
309 strcat(name, "_glow");
310 tx->glowtexture = loadtextureimage(loadmodel->texturepool, name, 0, 0, false, true, true);
314 if (loadmodel->ishlbsp)
316 if (mtdata && (data = W_ConvertWAD3Texture(dmiptex)))
319 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
320 if (R_TextureHasAlpha(tx->texture))
323 for (j = 0;j < image_width * image_height;j++)
324 data[j*4+0] = data[j*4+1] = data[j*4+2] = 255;
325 strcpy(name, tx->name);
326 strcat(name, "_fog");
327 tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
331 else if ((data = W_GetTexture(tx->name)))
333 // get the size from the wad texture
334 tx->width = image_width;
335 tx->height = image_height;
336 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
337 if (R_TextureHasAlpha(tx->texture))
340 for (j = 0;j < image_width * image_height;j++)
341 data[j*4+0] = data[j*4+1] = data[j*4+2] = 255;
342 strcpy(name, tx->name);
343 strcat(name, "_fog");
344 tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE);
352 tx->texture = loadmodel->notexture.texture;
357 if (mtdata) // texture included
362 if (r_fullbrights.value && tx->name[0] != '*')
364 for (j = 0;j < tx->width*tx->height;j++)
366 if (data[j] >= 224) // fullbright
375 data2 = Mem_Alloc(loadmodel->mempool, tx->width*tx->height);
376 for (j = 0;j < tx->width*tx->height;j++)
377 data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights
378 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
379 strcpy(name, tx->name);
380 strcat(name, "_glow");
381 for (j = 0;j < tx->width*tx->height;j++)
382 data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights
383 tx->glowtexture = R_LoadTexture (loadmodel->texturepool, name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
387 tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE);
389 else // no texture, and no external replacement texture was found
393 tx->texture = loadmodel->notexture.texture;
398 if (tx->name[0] == '*')
400 tx->flags |= (SURF_DRAWTURB | SURF_LIGHTBOTHSIDES);
401 // LordHavoc: some turbulent textures should be fullbright and solid
402 if (!strncmp(tx->name,"*lava",5)
403 || !strncmp(tx->name,"*teleport",9)
404 || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture
405 tx->flags |= (SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID);
407 else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y')
408 tx->flags |= (SURF_DRAWSKY | SURF_CLIPSOLID);
411 tx->flags |= SURF_LIGHTMAP;
412 if (!R_TextureHasAlpha(tx->texture))
413 tx->flags |= SURF_CLIPSOLID;
418 // sequence the animations
420 for (i = 0;i < m->nummiptex;i++)
422 tx = loadmodel->textures[i];
423 if (!tx || tx->name[0] != '+')
426 continue; // already sequenced
428 // find the number of frames in the animation
429 memset (anims, 0, sizeof(anims));
430 memset (altanims, 0, sizeof(altanims));
433 for (j = i;j < m->nummiptex;j++)
435 tx2 = loadmodel->textures[j];
436 if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2))
440 if (num >= '0' && num <= '9')
441 anims[num - '0'] = tx2;
442 else if (num >= 'a' && num <= 'j')
443 altanims[num - 'a'] = tx2;
445 Host_Error ("Bad animating texture %s", tx->name);
448 for (j = 0;j < 10;j++)
450 if (anims[j] != NULL)
452 if (altanims[j] != NULL)
456 // link them all together
457 for (j = 0;j < max;j++)
461 Host_Error ("Missing frame %i of %s", j, tx->name);
462 tx2->anim_total = max;
463 tx2->alternate_anims = altanims[0]; // NULL if there is no alternate
464 for (k = 0;k < 10;k++)
465 tx2->anim_frames[k] = anims[k];
468 for (j = 0;j < altmax;j++)
472 Host_Error ("Missing frame %i of %s", j, tx->name);
473 tx2->anim_total = altmax;
474 tx2->alternate_anims = anims[0]; // NULL if there is no alternate
475 for (k = 0;k < 10;k++)
476 tx2->anim_frames[k] = altanims[k];
486 static void Mod_LoadLighting (lump_t *l)
489 byte *in, *out, *data;
491 char litfilename[1024];
492 loadmodel->lightdata = NULL;
493 if (loadmodel->ishlbsp) // LordHavoc: load the colored lighting data straight
495 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen);
496 memcpy (loadmodel->lightdata, mod_base + l->fileofs, l->filelen);
498 else // LordHavoc: bsp version 29 (normal white lighting)
500 // LordHavoc: hope is not lost yet, check for a .lit file to load
501 strcpy(litfilename, loadmodel->name);
502 COM_StripExtension(litfilename, litfilename);
503 strcat(litfilename, ".lit");
504 data = (byte*) COM_LoadFile (litfilename, false);
507 if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T')
509 i = LittleLong(((int *)data)[1]);
512 Con_DPrintf("%s loaded", litfilename);
513 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8);
514 memcpy(loadmodel->lightdata, data + 8, loadsize - 8);
520 Con_Printf("Unknown .lit file version (%d)\n", i);
527 Con_Printf("Empty .lit file, ignoring\n");
529 Con_Printf("Corrupt .lit file (old version?), ignoring\n");
533 // LordHavoc: oh well, expand the white lighting data
536 loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, l->filelen*3);
537 in = loadmodel->lightdata + l->filelen*2; // place the file at the end, so it will not be overwritten until the very last write
538 out = loadmodel->lightdata;
539 memcpy (in, mod_base + l->fileofs, l->filelen);
540 for (i = 0;i < l->filelen;i++)
556 static void Mod_LoadVisibility (lump_t *l)
560 loadmodel->visdata = NULL;
563 loadmodel->visdata = Mem_Alloc(loadmodel->mempool, l->filelen);
564 memcpy (loadmodel->visdata, mod_base + l->fileofs, l->filelen);
567 // used only for HalfLife maps
568 void Mod_ParseWadsFromEntityLump(char *data)
570 char key[128], value[4096];
575 data = COM_Parse(data);
578 if (com_token[0] != '{')
582 data = COM_Parse(data);
585 if (com_token[0] == '}')
586 break; // end of worldspawn
587 if (com_token[0] == '_')
588 strcpy(key, com_token + 1);
590 strcpy(key, com_token);
591 while (key[strlen(key)-1] == ' ') // remove trailing spaces
592 key[strlen(key)-1] = 0;
593 data = COM_Parse(data);
596 strcpy(value, com_token);
597 if (!strcmp("wad", key)) // for HalfLife maps
599 if (loadmodel->ishlbsp)
602 for (i = 0;i < 4096;i++)
603 if (value[i] != ';' && value[i] != '\\' && value[i] != '/' && value[i] != ':')
609 // ignore path - the \\ check is for HalfLife... stupid windoze 'programmers'...
610 if (value[i] == '\\' || value[i] == '/' || value[i] == ':')
612 else if (value[i] == ';' || value[i] == 0)
616 strcpy(wadname, "textures/");
617 strcat(wadname, &value[j]);
618 W_LoadTextureWadFile (wadname, false);
635 static void Mod_LoadEntities (lump_t *l)
639 loadmodel->entities = NULL;
642 loadmodel->entities = Mem_Alloc(loadmodel->mempool, l->filelen);
643 memcpy (loadmodel->entities, mod_base + l->fileofs, l->filelen);
644 if (loadmodel->ishlbsp)
645 Mod_ParseWadsFromEntityLump(loadmodel->entities);
654 static void Mod_LoadVertexes (lump_t *l)
660 in = (void *)(mod_base + l->fileofs);
661 if (l->filelen % sizeof(*in))
662 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
663 count = l->filelen / sizeof(*in);
664 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
666 loadmodel->vertexes = out;
667 loadmodel->numvertexes = count;
669 for ( i=0 ; i<count ; i++, in++, out++)
671 out->position[0] = LittleFloat (in->point[0]);
672 out->position[1] = LittleFloat (in->point[1]);
673 out->position[2] = LittleFloat (in->point[2]);
682 static void Mod_LoadSubmodels (lump_t *l)
688 in = (void *)(mod_base + l->fileofs);
689 if (l->filelen % sizeof(*in))
690 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
691 count = l->filelen / sizeof(*in);
692 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
694 loadmodel->submodels = out;
695 loadmodel->numsubmodels = count;
697 for ( i=0 ; i<count ; i++, in++, out++)
699 for (j=0 ; j<3 ; j++)
701 // spread the mins / maxs by a pixel
702 out->mins[j] = LittleFloat (in->mins[j]) - 1;
703 out->maxs[j] = LittleFloat (in->maxs[j]) + 1;
704 out->origin[j] = LittleFloat (in->origin[j]);
706 for (j=0 ; j<MAX_MAP_HULLS ; j++)
707 out->headnode[j] = LittleLong (in->headnode[j]);
708 out->visleafs = LittleLong (in->visleafs);
709 out->firstface = LittleLong (in->firstface);
710 out->numfaces = LittleLong (in->numfaces);
719 static void Mod_LoadEdges (lump_t *l)
725 in = (void *)(mod_base + l->fileofs);
726 if (l->filelen % sizeof(*in))
727 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
728 count = l->filelen / sizeof(*in);
729 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
731 loadmodel->edges = out;
732 loadmodel->numedges = count;
734 for ( i=0 ; i<count ; i++, in++, out++)
736 out->v[0] = (unsigned short)LittleShort(in->v[0]);
737 out->v[1] = (unsigned short)LittleShort(in->v[1]);
746 static void Mod_LoadTexinfo (lump_t *l)
753 in = (void *)(mod_base + l->fileofs);
754 if (l->filelen % sizeof(*in))
755 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
756 count = l->filelen / sizeof(*in);
757 out = Mem_Alloc(loadmodel->mempool, count * sizeof(*out));
759 loadmodel->texinfo = out;
760 loadmodel->numtexinfo = count;
762 for (i = 0;i < count;i++, in++, out++)
764 for (k = 0;k < 2;k++)
765 for (j = 0;j < 4;j++)
766 out->vecs[k][j] = LittleFloat (in->vecs[k][j]);
768 miptex = LittleLong (in->miptex);
769 out->flags = LittleLong (in->flags);
771 if (!loadmodel->textures)
772 out->texture = &loadmodel->notexture;
776 Host_Error ("miptex < 0");
777 if (miptex >= loadmodel->numtextures)
778 Host_Error ("miptex >= loadmodel->numtextures");
779 out->texture = loadmodel->textures[miptex];
782 out->texture = &loadmodel->notexture;
790 Fills in s->texturemins[] and s->extents[]
793 static void CalcSurfaceExtents (msurface_t *s)
795 float mins[2], maxs[2], val;
799 int bmins[2], bmaxs[2];
801 mins[0] = mins[1] = 999999999;
802 maxs[0] = maxs[1] = -999999999;
806 for (i=0 ; i<s->numedges ; i++)
808 e = loadmodel->surfedges[s->firstedge+i];
810 v = &loadmodel->vertexes[loadmodel->edges[e].v[0]];
812 v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]];
814 for (j=0 ; j<2 ; j++)
816 val = v->position[0] * tex->vecs[j][0] +
817 v->position[1] * tex->vecs[j][1] +
818 v->position[2] * tex->vecs[j][2] +
827 for (i=0 ; i<2 ; i++)
829 bmins[i] = floor(mins[i]/16);
830 bmaxs[i] = ceil(maxs[i]/16);
832 s->texturemins[i] = bmins[i] * 16;
833 s->extents[i] = (bmaxs[i] - bmins[i]) * 16;
838 void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs)
843 mins[0] = mins[1] = mins[2] = 9999;
844 maxs[0] = maxs[1] = maxs[2] = -9999;
846 for (i = 0;i < numverts;i++)
848 for (j = 0;j < 3;j++, v++)
858 #define MAX_SUBDIVPOLYTRIANGLES 4096
859 #define MAX_SUBDIVPOLYVERTS (MAX_SUBDIVPOLYTRIANGLES * 3)
861 static int subdivpolyverts, subdivpolytriangles;
862 static int subdivpolyindex[MAX_SUBDIVPOLYTRIANGLES][3];
863 static float subdivpolyvert[MAX_SUBDIVPOLYVERTS][3];
865 static int subdivpolylookupvert(vec3_t v)
868 for (i = 0;i < subdivpolyverts;i++)
869 if (subdivpolyvert[i][0] == v[0]
870 && subdivpolyvert[i][1] == v[1]
871 && subdivpolyvert[i][2] == v[2])
873 if (subdivpolyverts >= MAX_SUBDIVPOLYVERTS)
874 Host_Error("SubDividePolygon: ran out of vertices in buffer, please increase your r_subdivide_size");
875 VectorCopy(v, subdivpolyvert[subdivpolyverts]);
876 return subdivpolyverts++;
879 static void SubdividePolygon (int numverts, float *verts)
881 int i, i1, i2, i3, f, b, c, p;
882 vec3_t mins, maxs, front[256], back[256];
883 float m, *pv, *cv, dist[256], frac;
886 Host_Error ("SubdividePolygon: ran out of verts in buffer");
888 BoundPoly (numverts, verts, mins, maxs);
890 for (i = 0;i < 3;i++)
892 m = (mins[i] + maxs[i]) * 0.5;
893 m = r_subdivide_size.value * floor (m/r_subdivide_size.value + 0.5);
900 for (cv = verts, c = 0;c < numverts;c++, cv += 3)
904 for (p = numverts - 1, c = 0, pv = verts + p * 3, cv = verts;c < numverts;p = c, c++, pv = cv, cv += 3)
908 VectorCopy (pv, front[f]);
913 VectorCopy (pv, back[b]);
916 if (dist[p] == 0 || dist[c] == 0)
918 if ( (dist[p] > 0) != (dist[c] > 0) )
921 frac = dist[p] / (dist[p] - dist[c]);
922 front[f][0] = back[b][0] = pv[0] + frac * (cv[0] - pv[0]);
923 front[f][1] = back[b][1] = pv[1] + frac * (cv[1] - pv[1]);
924 front[f][2] = back[b][2] = pv[2] + frac * (cv[2] - pv[2]);
930 SubdividePolygon (f, front[0]);
931 SubdividePolygon (b, back[0]);
935 i1 = subdivpolylookupvert(verts);
936 i2 = subdivpolylookupvert(verts + 3);
937 for (i = 2;i < numverts;i++)
939 if (subdivpolytriangles >= MAX_SUBDIVPOLYTRIANGLES)
941 Con_Printf("SubdividePolygon: ran out of triangles in buffer, please increase your r_subdivide_size\n");
945 i3 = subdivpolylookupvert(verts + i * 3);
946 subdivpolyindex[subdivpolytriangles][0] = i1;
947 subdivpolyindex[subdivpolytriangles][1] = i2;
948 subdivpolyindex[subdivpolytriangles][2] = i3;
950 subdivpolytriangles++;
958 Breaks a polygon up along axial 64 unit
959 boundaries so that turbulent and sky warps
960 can be done reasonably.
963 void Mod_GenerateWarpMesh (msurface_t *surf)
969 subdivpolytriangles = 0;
971 SubdividePolygon (surf->poly_numverts, surf->poly_verts);
974 mesh->numverts = subdivpolyverts;
975 mesh->numtriangles = subdivpolytriangles;
976 if (mesh->numtriangles < 1)
977 Host_Error("Mod_GenerateWarpMesh: no triangles?\n");
978 mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
979 mesh->vertex = (surfvertex_t *)((long) mesh->index + mesh->numtriangles * sizeof(int[3]));
980 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
982 for (i = 0;i < mesh->numtriangles;i++)
984 for (j = 0;j < 3;j++)
986 mesh->index[i*3+j] = subdivpolyindex[i][j];
987 //if (mesh->index[i] < 0 || mesh->index[i] >= mesh->numverts)
988 // Host_Error("Mod_GenerateWarpMesh: invalid index generated\n");
992 for (i = 0, v = mesh->vertex;i < subdivpolyverts;i++, v++)
994 VectorCopy(subdivpolyvert[i], v->v);
995 v->st[0] = DotProduct (v->v, surf->texinfo->vecs[0]);
996 v->st[1] = DotProduct (v->v, surf->texinfo->vecs[1]);
1000 void Mod_GenerateVertexLitMesh (msurface_t *surf)
1002 int i, is, it, *index, smax, tmax;
1007 //surf->flags |= SURF_LIGHTMAP;
1008 smax = surf->extents[0] >> 4;
1009 tmax = surf->extents[1] >> 4;
1010 surf->lightmaptexturestride = 0;
1011 surf->lightmaptexture = NULL;
1014 mesh->numverts = surf->poly_numverts;
1015 mesh->numtriangles = surf->poly_numverts - 2;
1016 mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
1017 mesh->vertex = (surfvertex_t *)((long) mesh->index + mesh->numtriangles * sizeof(int[3]));
1018 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1020 index = mesh->index;
1021 for (i = 0;i < mesh->numtriangles;i++)
1028 for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++)
1030 VectorCopy (in, out->v);
1032 s = DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1033 t = DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1035 out->st[0] = s / surf->texinfo->texture->width;
1036 out->st[1] = t / surf->texinfo->texture->height;
1038 s = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1039 t = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1041 // lightmap coordinates
1045 // LordHavoc: calc lightmap data offset for vertex lighting to use
1048 is = bound(0, is, smax);
1049 it = bound(0, it, tmax);
1050 out->lightmapoffset = ((it * (smax+1) + is) * 3);
1054 void Mod_GenerateLightmappedMesh (msurface_t *surf)
1056 int i, is, it, *index, smax, tmax;
1057 float *in, s, t, xbase, ybase, xscale, yscale;
1061 surf->flags |= SURF_LIGHTMAP;
1062 smax = surf->extents[0] >> 4;
1063 tmax = surf->extents[1] >> 4;
1064 if (r_miplightmaps.integer)
1066 surf->lightmaptexturestride = (surf->extents[0]>>4)+1;
1067 surf->lightmaptexture = R_ProceduralTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP/* | TEXF_PRECACHE*/, NULL, NULL, 0);
1071 surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0);
1072 surf->lightmaptexture = R_ProceduralTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT/* | TEXF_PRECACHE*/, NULL, NULL, 0);
1074 // surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, va("lightmap%08x", lightmapnum), surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE);
1075 // surf->lightmaptexture = R_LoadTexture(loadmodel->texturepool, va("lightmap%08x", lightmapnum), surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_PRECACHE);
1076 R_GetFragmentLocation(surf->lightmaptexture, NULL, NULL, &xbase, &ybase, &xscale, &yscale);
1077 xscale = (xscale - xbase) * 16.0 / ((surf->extents[0] & ~15) + 16);
1078 yscale = (yscale - ybase) * 16.0 / ((surf->extents[1] & ~15) + 16);
1081 mesh->numverts = surf->poly_numverts;
1082 mesh->numtriangles = surf->poly_numverts - 2;
1083 mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
1084 mesh->vertex = (surfvertex_t *)((long) mesh->index + mesh->numtriangles * sizeof(int[3]));
1085 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1087 index = mesh->index;
1088 for (i = 0;i < mesh->numtriangles;i++)
1095 for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++)
1097 VectorCopy (in, out->v);
1099 s = DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3];
1100 t = DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3];
1102 out->st[0] = s / surf->texinfo->texture->width;
1103 out->st[1] = t / surf->texinfo->texture->height;
1105 s = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0);
1106 t = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0);
1108 // lightmap coordinates
1109 out->uv[0] = s * xscale + xbase;
1110 out->uv[1] = t * yscale + ybase;
1112 // LordHavoc: calc lightmap data offset for vertex lighting to use
1115 is = bound(0, is, smax);
1116 it = bound(0, it, tmax);
1117 out->lightmapoffset = ((it * (smax+1) + is) * 3);
1121 void Mod_GenerateVertexMesh (msurface_t *surf)
1128 surf->lightmaptexturestride = 0;
1129 surf->lightmaptexture = NULL;
1132 mesh->numverts = surf->poly_numverts;
1133 mesh->numtriangles = surf->poly_numverts - 2;
1134 mesh->index = Mem_Alloc(loadmodel->mempool, mesh->numtriangles * sizeof(int[3]) + mesh->numverts * sizeof(surfvertex_t));
1135 mesh->vertex = (surfvertex_t *)((long) mesh->index + mesh->numtriangles * sizeof(int[3]));
1136 memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t));
1138 index = mesh->index;
1139 for (i = 0;i < mesh->numtriangles;i++)
1146 for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++)
1148 VectorCopy (in, out->v);
1149 out->st[0] = (DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) / surf->texinfo->texture->width;
1150 out->st[1] = (DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) / surf->texinfo->texture->height;
1154 void Mod_GenerateSurfacePolygon (msurface_t *surf)
1161 // convert edges back to a normal polygon
1162 surf->poly_numverts = surf->numedges;
1163 vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges);
1164 for (i = 0;i < surf->numedges;i++)
1166 lindex = loadmodel->surfedges[surf->firstedge + i];
1168 vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position;
1170 vec = loadmodel->vertexes[loadmodel->edges[-lindex].v[1]].position;
1171 VectorCopy (vec, vert);
1181 static void Mod_LoadFaces (lump_t *l)
1185 int i, count, surfnum;
1188 in = (void *)(mod_base + l->fileofs);
1189 if (l->filelen % sizeof(*in))
1190 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1191 count = l->filelen / sizeof(*in);
1192 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1194 loadmodel->surfaces = out;
1195 loadmodel->numsurfaces = count;
1197 for (surfnum = 0;surfnum < count;surfnum++, in++, out++)
1199 // FIXME: validate edges, texinfo, etc?
1200 out->firstedge = LittleLong(in->firstedge);
1201 out->numedges = LittleShort(in->numedges);
1203 out->texinfo = loadmodel->texinfo + LittleShort (in->texinfo);
1204 out->flags = out->texinfo->texture->flags;
1206 planenum = LittleShort(in->planenum);
1207 side = LittleShort(in->side);
1209 out->flags |= SURF_PLANEBACK;
1211 out->plane = loadmodel->planes + planenum;
1213 // clear lightmap (filled in later)
1214 out->lightmaptexture = NULL;
1216 // force lightmap upload on first time seeing the surface
1217 out->cached_dlight = true;
1218 out->cached_ambient = -1000;
1219 out->cached_lightscalebit = -1000;
1220 out->cached_light[0] = -1000;
1221 out->cached_light[1] = -1000;
1222 out->cached_light[2] = -1000;
1223 out->cached_light[3] = -1000;
1225 CalcSurfaceExtents (out);
1228 for (i = 0;i < MAXLIGHTMAPS;i++)
1229 out->styles[i] = in->styles[i];
1230 i = LittleLong(in->lightofs);
1232 out->samples = NULL;
1233 else if (loadmodel->ishlbsp) // LordHavoc: HalfLife map (bsp version 30)
1234 out->samples = loadmodel->lightdata + i;
1235 else // LordHavoc: white lighting (bsp version 29)
1236 out->samples = loadmodel->lightdata + (i * 3);
1238 Mod_GenerateSurfacePolygon(out);
1240 if (out->texinfo->texture->flags & SURF_DRAWSKY)
1242 out->shader = &Cshader_sky;
1243 out->samples = NULL;
1244 Mod_GenerateWarpMesh (out);
1248 if (out->texinfo->texture->flags & SURF_DRAWTURB)
1250 out->shader = &Cshader_water;
1252 for (i=0 ; i<2 ; i++)
1254 out->extents[i] = 16384*1024;
1255 out->texturemins[i] = -8192*1024;
1258 out->samples = NULL;
1259 Mod_GenerateWarpMesh (out);
1263 if (!R_TextureHasAlpha(out->texinfo->texture->texture))
1264 out->flags |= SURF_CLIPSOLID;
1265 if (out->texinfo->flags & TEX_SPECIAL)
1267 // qbsp couldn't find the texture for this surface, but it was either turb or sky... assume turb
1268 out->shader = &Cshader_water;
1269 out->samples = NULL;
1270 Mod_GenerateWarpMesh (out);
1272 else if ((out->extents[0]+1) > (256*16) || (out->extents[1]+1) > (256*16))
1274 Con_Printf ("Bad surface extents, converting to fullbright polygon");
1275 out->shader = &Cshader_wall_fullbright;
1276 out->samples = NULL;
1277 Mod_GenerateVertexMesh(out);
1279 else if (out->extents[0] < r_vertexsurfacesthreshold.integer && out->extents[1] < r_vertexsurfacesthreshold.integer)
1281 out->shader = &Cshader_wall_vertex;
1282 Mod_GenerateVertexLitMesh(out);
1286 out->shader = &Cshader_wall_lightmap;
1287 Mod_GenerateLightmappedMesh(out);
1292 static model_t *sortmodel;
1294 static int Mod_SurfaceQSortCompare(const void *voida, const void *voidb)
1296 const msurface_t *a, *b;
1297 a = *((const msurface_t **)voida);
1298 b = *((const msurface_t **)voidb);
1299 if (a->shader != b->shader)
1300 return (long) a->shader - (long) b->shader;
1301 if (a->texinfo->texture != b->texinfo->texture);
1302 return a->texinfo->texture - b->texinfo->texture;
1306 static void Mod_BrushSortedSurfaces(model_t *model, mempool_t *pool)
1310 sortmodel->modelsortedsurfaces = Mem_Alloc(pool, sortmodel->nummodelsurfaces * sizeof(msurface_t *));
1311 for (surfnum = 0;surfnum < sortmodel->nummodelsurfaces;surfnum++)
1312 sortmodel->modelsortedsurfaces[surfnum] = &sortmodel->surfaces[surfnum + sortmodel->firstmodelsurface];
1314 qsort(sortmodel->modelsortedsurfaces, sortmodel->nummodelsurfaces, sizeof(msurface_t *), Mod_SurfaceQSortCompare);
1323 static void Mod_SetParent (mnode_t *node, mnode_t *parent)
1325 node->parent = parent;
1326 if (node->contents < 0)
1328 Mod_SetParent (node->children[0], node);
1329 Mod_SetParent (node->children[1], node);
1337 static void Mod_LoadNodes (lump_t *l)
1343 in = (void *)(mod_base + l->fileofs);
1344 if (l->filelen % sizeof(*in))
1345 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1346 count = l->filelen / sizeof(*in);
1347 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1349 loadmodel->nodes = out;
1350 loadmodel->numnodes = count;
1352 for ( i=0 ; i<count ; i++, in++, out++)
1354 for (j=0 ; j<3 ; j++)
1356 out->mins[j] = LittleShort (in->mins[j]);
1357 out->maxs[j] = LittleShort (in->maxs[j]);
1360 p = LittleLong(in->planenum);
1361 out->plane = loadmodel->planes + p;
1363 out->firstsurface = LittleShort (in->firstface);
1364 out->numsurfaces = LittleShort (in->numfaces);
1366 for (j=0 ; j<2 ; j++)
1368 p = LittleShort (in->children[j]);
1370 out->children[j] = loadmodel->nodes + p;
1372 out->children[j] = (mnode_t *)(loadmodel->leafs + (-1 - p));
1376 Mod_SetParent (loadmodel->nodes, NULL); // sets nodes and leafs
1384 static void Mod_LoadLeafs (lump_t *l)
1390 in = (void *)(mod_base + l->fileofs);
1391 if (l->filelen % sizeof(*in))
1392 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1393 count = l->filelen / sizeof(*in);
1394 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1396 loadmodel->leafs = out;
1397 loadmodel->numleafs = count;
1399 for ( i=0 ; i<count ; i++, in++, out++)
1401 for (j=0 ; j<3 ; j++)
1403 out->mins[j] = LittleShort (in->mins[j]);
1404 out->maxs[j] = LittleShort (in->maxs[j]);
1407 p = LittleLong(in->contents);
1410 out->firstmarksurface = loadmodel->marksurfaces +
1411 LittleShort(in->firstmarksurface);
1412 out->nummarksurfaces = LittleShort(in->nummarksurfaces);
1414 p = LittleLong(in->visofs);
1416 out->compressed_vis = NULL;
1418 out->compressed_vis = loadmodel->visdata + p;
1420 for (j=0 ; j<4 ; j++)
1421 out->ambient_sound_level[j] = in->ambient_level[j];
1423 // gl underwater warp
1424 // LordHavoc: disabled underwater warping
1426 if (out->contents != CONTENTS_EMPTY)
1428 for (j=0 ; j<out->nummarksurfaces ; j++)
1429 out->firstmarksurface[j]->flags |= SURF_UNDERWATER;
1440 static void Mod_LoadClipnodes (lump_t *l)
1442 dclipnode_t *in, *out;
1446 in = (void *)(mod_base + l->fileofs);
1447 if (l->filelen % sizeof(*in))
1448 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1449 count = l->filelen / sizeof(*in);
1450 out = Mem_Alloc(loadmodel->mempool, count*sizeof(*out));
1452 loadmodel->clipnodes = out;
1453 loadmodel->numclipnodes = count;
1455 if (loadmodel->ishlbsp)
1457 hull = &loadmodel->hulls[1];
1458 hull->clipnodes = out;
1459 hull->firstclipnode = 0;
1460 hull->lastclipnode = count-1;
1461 hull->planes = loadmodel->planes;
1462 hull->clip_mins[0] = -16;
1463 hull->clip_mins[1] = -16;
1464 hull->clip_mins[2] = -36;
1465 hull->clip_maxs[0] = 16;
1466 hull->clip_maxs[1] = 16;
1467 hull->clip_maxs[2] = 36;
1469 hull = &loadmodel->hulls[2];
1470 hull->clipnodes = out;
1471 hull->firstclipnode = 0;
1472 hull->lastclipnode = count-1;
1473 hull->planes = loadmodel->planes;
1474 hull->clip_mins[0] = -32;
1475 hull->clip_mins[1] = -32;
1476 hull->clip_mins[2] = -32;
1477 hull->clip_maxs[0] = 32;
1478 hull->clip_maxs[1] = 32;
1479 hull->clip_maxs[2] = 32;
1481 hull = &loadmodel->hulls[3];
1482 hull->clipnodes = out;
1483 hull->firstclipnode = 0;
1484 hull->lastclipnode = count-1;
1485 hull->planes = loadmodel->planes;
1486 hull->clip_mins[0] = -16;
1487 hull->clip_mins[1] = -16;
1488 hull->clip_mins[2] = -18;
1489 hull->clip_maxs[0] = 16;
1490 hull->clip_maxs[1] = 16;
1491 hull->clip_maxs[2] = 18;
1495 hull = &loadmodel->hulls[1];
1496 hull->clipnodes = out;
1497 hull->firstclipnode = 0;
1498 hull->lastclipnode = count-1;
1499 hull->planes = loadmodel->planes;
1500 hull->clip_mins[0] = -16;
1501 hull->clip_mins[1] = -16;
1502 hull->clip_mins[2] = -24;
1503 hull->clip_maxs[0] = 16;
1504 hull->clip_maxs[1] = 16;
1505 hull->clip_maxs[2] = 32;
1507 hull = &loadmodel->hulls[2];
1508 hull->clipnodes = out;
1509 hull->firstclipnode = 0;
1510 hull->lastclipnode = count-1;
1511 hull->planes = loadmodel->planes;
1512 hull->clip_mins[0] = -32;
1513 hull->clip_mins[1] = -32;
1514 hull->clip_mins[2] = -24;
1515 hull->clip_maxs[0] = 32;
1516 hull->clip_maxs[1] = 32;
1517 hull->clip_maxs[2] = 64;
1520 for (i=0 ; i<count ; i++, out++, in++)
1522 out->planenum = LittleLong(in->planenum);
1523 out->children[0] = LittleShort(in->children[0]);
1524 out->children[1] = LittleShort(in->children[1]);
1525 if (out->children[0] >= count || out->children[1] >= count)
1526 Host_Error("Corrupt clipping hull (out of range child)\n");
1534 Duplicate the drawing hull structure as a clipping hull
1537 static void Mod_MakeHull0 (void)
1544 hull = &loadmodel->hulls[0];
1546 in = loadmodel->nodes;
1547 out = Mem_Alloc(loadmodel->mempool, loadmodel->numnodes * sizeof(dclipnode_t));
1549 hull->clipnodes = out;
1550 hull->firstclipnode = 0;
1551 hull->lastclipnode = loadmodel->numnodes - 1;
1552 hull->planes = loadmodel->planes;
1554 for (i = 0;i < loadmodel->numnodes;i++, out++, in++)
1556 out->planenum = in->plane - loadmodel->planes;
1557 out->children[0] = in->children[0]->contents < 0 ? in->children[0]->contents : in->children[0] - loadmodel->nodes;
1558 out->children[1] = in->children[1]->contents < 0 ? in->children[1]->contents : in->children[1] - loadmodel->nodes;
1564 Mod_LoadMarksurfaces
1567 static void Mod_LoadMarksurfaces (lump_t *l)
1572 in = (void *)(mod_base + l->fileofs);
1573 if (l->filelen % sizeof(*in))
1574 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1575 loadmodel->nummarksurfaces = l->filelen / sizeof(*in);
1576 loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(msurface_t *));
1578 for (i = 0;i < loadmodel->nummarksurfaces;i++)
1580 j = (unsigned) LittleShort(in[i]);
1581 if (j >= loadmodel->numsurfaces)
1582 Host_Error ("Mod_ParseMarksurfaces: bad surface number");
1583 loadmodel->marksurfaces[i] = loadmodel->surfaces + j;
1592 static void Mod_LoadSurfedges (lump_t *l)
1597 in = (void *)(mod_base + l->fileofs);
1598 if (l->filelen % sizeof(*in))
1599 Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name);
1600 loadmodel->numsurfedges = l->filelen / sizeof(*in);
1601 loadmodel->surfedges = Mem_Alloc(loadmodel->mempool, loadmodel->numsurfedges * sizeof(int));
1603 for (i = 0;i < loadmodel->numsurfedges;i++)
1604 loadmodel->surfedges[i] = LittleLong (in[i]);
1613 static void Mod_LoadPlanes (lump_t *l)
1619 in = (void *)(mod_base + l->fileofs);
1620 if (l->filelen % sizeof(*in))
1621 Host_Error ("MOD_LoadBmodel: funny lump size in %s", loadmodel->name);
1623 loadmodel->numplanes = l->filelen / sizeof(*in);
1624 loadmodel->planes = out = Mem_Alloc(loadmodel->mempool, loadmodel->numplanes * sizeof(*out));
1626 for (i = 0;i < loadmodel->numplanes;i++, in++, out++)
1628 out->normal[0] = LittleFloat (in->normal[0]);
1629 out->normal[1] = LittleFloat (in->normal[1]);
1630 out->normal[2] = LittleFloat (in->normal[2]);
1631 out->dist = LittleFloat (in->dist);
1633 // LordHavoc: recalculated by PlaneClassify, FIXME: validate type and report error if type does not match normal?
1634 // out->type = LittleLong (in->type);
1639 #define MAX_POINTS_ON_WINDING 64
1645 double points[8][3]; // variable sized
1654 static winding_t *NewWinding (int points)
1659 if (points > MAX_POINTS_ON_WINDING)
1660 Sys_Error("NewWinding: too many points\n");
1662 size = sizeof(winding_t) + sizeof(double[3]) * (points - 8);
1663 w = Mem_Alloc(loadmodel->mempool, size);
1664 memset (w, 0, size);
1669 static void FreeWinding (winding_t *w)
1679 static winding_t *BaseWindingForPlane (mplane_t *p)
1681 double org[3], vright[3], vup[3], normal[3];
1684 VectorCopy(p->normal, normal);
1685 VectorVectorsDouble(normal, vright, vup);
1687 VectorScale (vup, 1024.0*1024.0*1024.0, vup);
1688 VectorScale (vright, 1024.0*1024.0*1024.0, vright);
1690 // project a really big axis aligned box onto the plane
1693 VectorScale (p->normal, p->dist, org);
1695 VectorSubtract (org, vright, w->points[0]);
1696 VectorAdd (w->points[0], vup, w->points[0]);
1698 VectorAdd (org, vright, w->points[1]);
1699 VectorAdd (w->points[1], vup, w->points[1]);
1701 VectorAdd (org, vright, w->points[2]);
1702 VectorSubtract (w->points[2], vup, w->points[2]);
1704 VectorSubtract (org, vright, w->points[3]);
1705 VectorSubtract (w->points[3], vup, w->points[3]);
1716 Clips the winding to the plane, returning the new winding on the positive side
1717 Frees the input winding.
1718 If keepon is true, an exactly on-plane winding will be saved, otherwise
1719 it will be clipped away.
1722 static winding_t *ClipWinding (winding_t *in, mplane_t *split, int keepon)
1724 double dists[MAX_POINTS_ON_WINDING + 1];
1725 int sides[MAX_POINTS_ON_WINDING + 1];
1735 Mem_CheckSentinels(in);
1737 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1739 // determine sides for each point
1740 for (i = 0;i < in->numpoints;i++)
1742 dists[i] = dot = DotProduct (in->points[i], split->normal) - split->dist;
1743 if (dot > ON_EPSILON)
1744 sides[i] = SIDE_FRONT;
1745 else if (dot < -ON_EPSILON)
1746 sides[i] = SIDE_BACK;
1751 sides[i] = sides[0];
1752 dists[i] = dists[0];
1754 if (keepon && !counts[0] && !counts[1])
1765 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1766 if (maxpts > MAX_POINTS_ON_WINDING)
1767 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1769 neww = NewWinding (maxpts);
1771 for (i = 0;i < in->numpoints;i++)
1773 if (neww->numpoints >= maxpts)
1774 Sys_Error ("ClipWinding: points exceeded estimate");
1776 Mem_CheckSentinels(neww);
1780 if (sides[i] == SIDE_ON)
1782 VectorCopy (p1, neww->points[neww->numpoints]);
1784 Mem_CheckSentinels(neww);
1788 if (sides[i] == SIDE_FRONT)
1790 VectorCopy (p1, neww->points[neww->numpoints]);
1792 Mem_CheckSentinels(neww);
1795 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1798 // generate a split point
1799 p2 = in->points[(i+1)%in->numpoints];
1801 dot = dists[i] / (dists[i]-dists[i+1]);
1802 for (j = 0;j < 3;j++)
1803 { // avoid round off error when possible
1804 if (split->normal[j] == 1)
1805 mid[j] = split->dist;
1806 else if (split->normal[j] == -1)
1807 mid[j] = -split->dist;
1809 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1812 VectorCopy (mid, neww->points[neww->numpoints]);
1814 Mem_CheckSentinels(neww);
1817 // free the original winding
1821 Mem_CheckSentinels(neww);
1831 Divides a winding by a plane, producing one or two windings. The
1832 original winding is not damaged or freed. If only on one side, the
1833 returned winding will be the input winding. If on both sides, two
1834 new windings will be created.
1837 static void DivideWinding (winding_t *in, mplane_t *split, winding_t **front, winding_t **back)
1839 double dists[MAX_POINTS_ON_WINDING + 1];
1840 int sides[MAX_POINTS_ON_WINDING + 1];
1850 Mem_CheckSentinels(in);
1852 counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0;
1854 // determine sides for each point
1855 for (i = 0;i < in->numpoints;i++)
1857 dot = DotProduct (in->points[i], split->normal);
1860 if (dot > ON_EPSILON) sides[i] = SIDE_FRONT;
1861 else if (dot < -ON_EPSILON) sides[i] = SIDE_BACK;
1862 else sides[i] = SIDE_ON;
1865 sides[i] = sides[0];
1866 dists[i] = dists[0];
1868 *front = *back = NULL;
1881 maxpts = in->numpoints+4; // can't use counts[0]+2 because of fp grouping errors
1883 if (maxpts > MAX_POINTS_ON_WINDING)
1884 Sys_Error ("ClipWinding: maxpts > MAX_POINTS_ON_WINDING");
1886 *front = f = NewWinding (maxpts);
1887 *back = b = NewWinding (maxpts);
1889 for (i = 0;i < in->numpoints;i++)
1891 if (f->numpoints >= maxpts || b->numpoints >= maxpts)
1892 Sys_Error ("DivideWinding: points exceeded estimate");
1896 if (sides[i] == SIDE_ON)
1898 VectorCopy (p1, f->points[f->numpoints]);
1900 Mem_CheckSentinels(f);
1901 VectorCopy (p1, b->points[b->numpoints]);
1903 Mem_CheckSentinels(b);
1907 if (sides[i] == SIDE_FRONT)
1909 VectorCopy (p1, f->points[f->numpoints]);
1911 Mem_CheckSentinels(f);
1913 else if (sides[i] == SIDE_BACK)
1915 VectorCopy (p1, b->points[b->numpoints]);
1917 Mem_CheckSentinels(b);
1920 if (sides[i+1] == SIDE_ON || sides[i+1] == sides[i])
1923 // generate a split point
1924 p2 = in->points[(i+1)%in->numpoints];
1926 dot = dists[i] / (dists[i]-dists[i+1]);
1927 for (j = 0;j < 3;j++)
1928 { // avoid round off error when possible
1929 if (split->normal[j] == 1)
1930 mid[j] = split->dist;
1931 else if (split->normal[j] == -1)
1932 mid[j] = -split->dist;
1934 mid[j] = p1[j] + dot*(p2[j]-p1[j]);
1937 VectorCopy (mid, f->points[f->numpoints]);
1939 Mem_CheckSentinels(f);
1940 VectorCopy (mid, b->points[b->numpoints]);
1942 Mem_CheckSentinels(b);
1946 Mem_CheckSentinels(front);
1947 Mem_CheckSentinels(back);
1950 typedef struct portal_s
1953 mnode_t *nodes[2]; // [0] = front side of plane
1954 struct portal_s *next[2];
1956 struct portal_s *chain; // all portals are linked into a list
1960 static portal_t *portalchain;
1967 static portal_t *AllocPortal (void)
1970 p = Mem_Alloc(loadmodel->mempool, sizeof(portal_t));
1971 //memset(p, 0, sizeof(portal_t));
1972 p->chain = portalchain;
1977 static void FreePortal(portal_t *p)
1982 static void Mod_RecursiveRecalcNodeBBox(mnode_t *node)
1984 // calculate children first
1985 if (node->children[0]->contents >= 0)
1986 Mod_RecursiveRecalcNodeBBox(node->children[0]);
1987 if (node->children[1]->contents >= 0)
1988 Mod_RecursiveRecalcNodeBBox(node->children[1]);
1990 // make combined bounding box from children
1991 node->mins[0] = min(node->children[0]->mins[0], node->children[1]->mins[0]);
1992 node->mins[1] = min(node->children[0]->mins[1], node->children[1]->mins[1]);
1993 node->mins[2] = min(node->children[0]->mins[2], node->children[1]->mins[2]);
1994 node->maxs[0] = max(node->children[0]->maxs[0], node->children[1]->maxs[0]);
1995 node->maxs[1] = max(node->children[0]->maxs[1], node->children[1]->maxs[1]);
1996 node->maxs[2] = max(node->children[0]->maxs[2], node->children[1]->maxs[2]);
1999 static void Mod_FinalizePortals(void)
2001 int i, j, numportals, numpoints;
2002 portal_t *p, *pnext;
2005 mleaf_t *leaf, *endleaf;
2008 Mem_CheckSentinelsGlobal();
2010 // recalculate bounding boxes for all leafs (because qbsp is very sloppy)
2011 leaf = loadmodel->leafs;
2012 endleaf = leaf + loadmodel->numleafs;
2013 for (;leaf < endleaf;leaf++)
2015 VectorSet( 2000000000, 2000000000, 2000000000, leaf->mins);
2016 VectorSet(-2000000000, -2000000000, -2000000000, leaf->maxs);
2023 for (i = 0;i < 2;i++)
2025 leaf = (mleaf_t *)p->nodes[i];
2027 for (j = 0;j < w->numpoints;j++)
2029 if (leaf->mins[0] > w->points[j][0]) leaf->mins[0] = w->points[j][0];
2030 if (leaf->mins[1] > w->points[j][1]) leaf->mins[1] = w->points[j][1];
2031 if (leaf->mins[2] > w->points[j][2]) leaf->mins[2] = w->points[j][2];
2032 if (leaf->maxs[0] < w->points[j][0]) leaf->maxs[0] = w->points[j][0];
2033 if (leaf->maxs[1] < w->points[j][1]) leaf->maxs[1] = w->points[j][1];
2034 if (leaf->maxs[2] < w->points[j][2]) leaf->maxs[2] = w->points[j][2];
2041 Mod_RecursiveRecalcNodeBBox(loadmodel->nodes);
2043 Mem_CheckSentinelsGlobal();
2045 // tally up portal and point counts
2051 // note: this check must match the one below or it will usually corrupt memory
2052 // 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
2053 if (p->winding && p->nodes[0] != p->nodes[1]
2054 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2055 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2058 numpoints += p->winding->numpoints * 2;
2062 loadmodel->portals = Mem_Alloc(loadmodel->mempool, numportals * sizeof(mportal_t) + numpoints * sizeof(mvertex_t));
2063 loadmodel->numportals = numportals;
2064 loadmodel->portalpoints = (void *) ((long) loadmodel->portals + numportals * sizeof(mportal_t));
2065 loadmodel->numportalpoints = numpoints;
2066 // clear all leaf portal chains
2067 for (i = 0;i < loadmodel->numleafs;i++)
2068 loadmodel->leafs[i].portals = NULL;
2069 // process all portals in the global portal chain, while freeing them
2070 portal = loadmodel->portals;
2071 point = loadmodel->portalpoints;
2080 // note: this check must match the one above or it will usually corrupt memory
2081 // 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
2082 if (p->nodes[0] != p->nodes[1]
2083 && p->nodes[0]->contents != CONTENTS_SOLID && p->nodes[1]->contents != CONTENTS_SOLID
2084 && p->nodes[0]->contents != CONTENTS_SKY && p->nodes[1]->contents != CONTENTS_SKY)
2086 // first make the back to front portal (forward portal)
2087 portal->points = point;
2088 portal->numpoints = p->winding->numpoints;
2089 portal->plane.dist = p->plane.dist;
2090 VectorCopy(p->plane.normal, portal->plane.normal);
2091 portal->here = (mleaf_t *)p->nodes[1];
2092 portal->past = (mleaf_t *)p->nodes[0];
2094 for (j = 0;j < portal->numpoints;j++)
2096 VectorCopy(p->winding->points[j], point->position);
2099 PlaneClassify(&portal->plane);
2101 // link into leaf's portal chain
2102 portal->next = portal->here->portals;
2103 portal->here->portals = portal;
2105 // advance to next portal
2108 // then make the front to back portal (backward portal)
2109 portal->points = point;
2110 portal->numpoints = p->winding->numpoints;
2111 portal->plane.dist = -p->plane.dist;
2112 VectorNegate(p->plane.normal, portal->plane.normal);
2113 portal->here = (mleaf_t *)p->nodes[0];
2114 portal->past = (mleaf_t *)p->nodes[1];
2116 for (j = portal->numpoints - 1;j >= 0;j--)
2118 VectorCopy(p->winding->points[j], point->position);
2121 PlaneClassify(&portal->plane);
2123 // link into leaf's portal chain
2124 portal->next = portal->here->portals;
2125 portal->here->portals = portal;
2127 // advance to next portal
2130 FreeWinding(p->winding);
2136 Mem_CheckSentinelsGlobal();
2144 static void AddPortalToNodes (portal_t *p, mnode_t *front, mnode_t *back)
2147 Host_Error ("AddPortalToNodes: NULL front node");
2149 Host_Error ("AddPortalToNodes: NULL back node");
2150 if (p->nodes[0] || p->nodes[1])
2151 Host_Error ("AddPortalToNodes: already included");
2152 // 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
2154 p->nodes[0] = front;
2155 p->next[0] = (portal_t *)front->portals;
2156 front->portals = (mportal_t *)p;
2159 p->next[1] = (portal_t *)back->portals;
2160 back->portals = (mportal_t *)p;
2165 RemovePortalFromNode
2168 static void RemovePortalFromNodes(portal_t *portal)
2172 void **portalpointer;
2174 for (i = 0;i < 2;i++)
2176 node = portal->nodes[i];
2178 portalpointer = (void **) &node->portals;
2183 Host_Error ("RemovePortalFromNodes: portal not in leaf");
2187 if (portal->nodes[0] == node)
2189 *portalpointer = portal->next[0];
2190 portal->nodes[0] = NULL;
2192 else if (portal->nodes[1] == node)
2194 *portalpointer = portal->next[1];
2195 portal->nodes[1] = NULL;
2198 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2202 if (t->nodes[0] == node)
2203 portalpointer = (void **) &t->next[0];
2204 else if (t->nodes[1] == node)
2205 portalpointer = (void **) &t->next[1];
2207 Host_Error ("RemovePortalFromNodes: portal not bounding leaf");
2212 static void Mod_RecursiveNodePortals (mnode_t *node)
2215 mnode_t *front, *back, *other_node;
2216 mplane_t clipplane, *plane;
2217 portal_t *portal, *nextportal, *nodeportal, *splitportal, *temp;
2218 winding_t *nodeportalwinding, *frontwinding, *backwinding;
2220 // CheckLeafPortalConsistancy (node);
2222 // if a leaf, we're done
2226 plane = node->plane;
2228 front = node->children[0];
2229 back = node->children[1];
2231 Host_Error("Mod_RecursiveNodePortals: corrupt node hierarchy");
2233 // create the new portal by generating a polygon for the node plane,
2234 // and clipping it by all of the other portals (which came from nodes above this one)
2235 nodeportal = AllocPortal ();
2236 nodeportal->plane = *node->plane;
2238 nodeportalwinding = BaseWindingForPlane (node->plane);
2239 Mem_CheckSentinels(nodeportalwinding);
2240 side = 0; // shut up compiler warning
2241 for (portal = (portal_t *)node->portals;portal;portal = portal->next[side])
2243 clipplane = portal->plane;
2244 if (portal->nodes[0] == portal->nodes[1])
2245 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (1)");
2246 if (portal->nodes[0] == node)
2248 else if (portal->nodes[1] == node)
2250 clipplane.dist = -clipplane.dist;
2251 VectorNegate (clipplane.normal, clipplane.normal);
2255 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2257 nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true);
2258 if (!nodeportalwinding)
2260 printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n");
2265 if (nodeportalwinding)
2267 // if the plane was not clipped on all sides, there was an error
2268 nodeportal->winding = nodeportalwinding;
2269 AddPortalToNodes (nodeportal, front, back);
2272 // split the portals of this node along this node's plane and assign them to the children of this node
2273 // (migrating the portals downward through the tree)
2274 for (portal = (portal_t *)node->portals;portal;portal = nextportal)
2276 if (portal->nodes[0] == portal->nodes[1])
2277 Host_Error("Mod_RecursiveNodePortals: portal has same node on both sides (2)");
2278 if (portal->nodes[0] == node)
2280 else if (portal->nodes[1] == node)
2283 Host_Error ("Mod_RecursiveNodePortals: mislinked portal");
2284 nextportal = portal->next[side];
2286 other_node = portal->nodes[!side];
2287 RemovePortalFromNodes (portal);
2289 // cut the portal into two portals, one on each side of the node plane
2290 DivideWinding (portal->winding, plane, &frontwinding, &backwinding);
2295 AddPortalToNodes (portal, back, other_node);
2297 AddPortalToNodes (portal, other_node, back);
2303 AddPortalToNodes (portal, front, other_node);
2305 AddPortalToNodes (portal, other_node, front);
2309 // the winding is split
2310 splitportal = AllocPortal ();
2311 temp = splitportal->chain;
2312 *splitportal = *portal;
2313 splitportal->chain = temp;
2314 splitportal->winding = backwinding;
2315 FreeWinding (portal->winding);
2316 portal->winding = frontwinding;
2320 AddPortalToNodes (portal, front, other_node);
2321 AddPortalToNodes (splitportal, back, other_node);
2325 AddPortalToNodes (portal, other_node, front);
2326 AddPortalToNodes (splitportal, other_node, back);
2330 Mod_RecursiveNodePortals(front);
2331 Mod_RecursiveNodePortals(back);
2335 void Mod_MakeOutsidePortals(mnode_t *node)
2338 portal_t *p, *portals[6];
2339 mnode_t *outside_node;
2341 outside_node = Mem_Alloc(loadmodel->mempool, sizeof(mnode_t));
2342 outside_node->contents = CONTENTS_SOLID;
2343 outside_node->portals = NULL;
2345 for (i = 0;i < 3;i++)
2347 for (j = 0;j < 2;j++)
2349 portals[j*3 + i] = p = AllocPortal ();
2350 memset (&p->plane, 0, sizeof(mplane_t));
2351 p->plane.normal[i] = j ? -1 : 1;
2352 p->plane.dist = -65536;
2353 p->winding = BaseWindingForPlane (&p->plane);
2355 AddPortalToNodes (p, outside_node, node);
2357 AddPortalToNodes (p, node, outside_node);
2361 // clip the basewindings by all the other planes
2362 for (i = 0;i < 6;i++)
2364 for (j = 0;j < 6;j++)
2368 portals[i]->winding = ClipWinding (portals[i]->winding, &portals[j]->plane, true);
2374 static void Mod_MakePortals(void)
2376 // Con_Printf("building portals for %s\n", loadmodel->name);
2379 // Mod_MakeOutsidePortals (loadmodel->nodes);
2380 Mod_RecursiveNodePortals (loadmodel->nodes);
2381 Mod_FinalizePortals();
2389 void Mod_LoadBrushModel (model_t *mod, void *buffer)
2394 mempool_t *mainmempool;
2396 mod->type = mod_brush;
2398 header = (dheader_t *)buffer;
2400 i = LittleLong (header->version);
2401 if (i != BSPVERSION && i != 30)
2402 Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i or 30 (HalfLife))", mod->name, i, BSPVERSION);
2403 mod->ishlbsp = i == 30;
2404 if (loadmodel->isworldmodel)
2405 Cvar_SetValue("halflifebsp", mod->ishlbsp);
2407 // swap all the lumps
2408 mod_base = (byte *)header;
2410 for (i=0 ; i<sizeof(dheader_t)/4 ; i++)
2411 ((int *)header)[i] = LittleLong ( ((int *)header)[i]);
2415 // store which lightmap format to use
2416 mod->lightmaprgba = r_lightmaprgba.integer;
2418 // Mem_CheckSentinelsGlobal();
2419 // LordHavoc: had to move entity loading above everything to allow parsing various settings from worldspawn
2420 Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2421 // Mem_CheckSentinelsGlobal();
2422 Mod_LoadVertexes (&header->lumps[LUMP_VERTEXES]);
2423 // Mem_CheckSentinelsGlobal();
2424 Mod_LoadEdges (&header->lumps[LUMP_EDGES]);
2425 // Mem_CheckSentinelsGlobal();
2426 Mod_LoadSurfedges (&header->lumps[LUMP_SURFEDGES]);
2427 // Mem_CheckSentinelsGlobal();
2428 Mod_LoadTextures (&header->lumps[LUMP_TEXTURES]);
2429 // Mem_CheckSentinelsGlobal();
2430 Mod_LoadLighting (&header->lumps[LUMP_LIGHTING]);
2431 // Mem_CheckSentinelsGlobal();
2432 Mod_LoadPlanes (&header->lumps[LUMP_PLANES]);
2433 // Mem_CheckSentinelsGlobal();
2434 Mod_LoadTexinfo (&header->lumps[LUMP_TEXINFO]);
2435 // Mem_CheckSentinelsGlobal();
2436 Mod_LoadFaces (&header->lumps[LUMP_FACES]);
2437 // Mem_CheckSentinelsGlobal();
2438 Mod_LoadMarksurfaces (&header->lumps[LUMP_MARKSURFACES]);
2439 // Mem_CheckSentinelsGlobal();
2440 Mod_LoadVisibility (&header->lumps[LUMP_VISIBILITY]);
2441 // Mem_CheckSentinelsGlobal();
2442 Mod_LoadLeafs (&header->lumps[LUMP_LEAFS]);
2443 // Mem_CheckSentinelsGlobal();
2444 Mod_LoadNodes (&header->lumps[LUMP_NODES]);
2445 // Mem_CheckSentinelsGlobal();
2446 Mod_LoadClipnodes (&header->lumps[LUMP_CLIPNODES]);
2447 // Mem_CheckSentinelsGlobal();
2448 // Mod_LoadEntities (&header->lumps[LUMP_ENTITIES]);
2449 Mod_LoadSubmodels (&header->lumps[LUMP_MODELS]);
2450 // Mem_CheckSentinelsGlobal();
2453 // Mem_CheckSentinelsGlobal();
2455 // Mem_CheckSentinelsGlobal();
2457 mod->numframes = 2; // regular and alternate animation
2459 mainmempool = mod->mempool;
2462 // set up the submodels (FIXME: this is confusing)
2464 for (i = 0;i < mod->numsubmodels;i++)
2467 float dist, modelyawradius, modelradius, *vec;
2470 mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f;
2471 mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f;
2475 bm = &mod->submodels[i];
2477 mod->hulls[0].firstclipnode = bm->headnode[0];
2478 for (j=1 ; j<MAX_MAP_HULLS ; j++)
2480 mod->hulls[j].firstclipnode = bm->headnode[j];
2481 mod->hulls[j].lastclipnode = mod->numclipnodes - 1;
2484 mod->firstmodelsurface = bm->firstface;
2485 mod->nummodelsurfaces = bm->numfaces;
2487 mod->DrawSky = NULL;
2488 // LordHavoc: calculate bmodel bounding box rather than trusting what it says
2489 for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++)
2491 // we only need to have a drawsky function if it is used (usually only on world model)
2492 if (surf->shader == &Cshader_sky)
2493 mod->DrawSky = R_DrawBrushModelSky;
2494 for (k = 0;k < surf->numedges;k++)
2496 l = mod->surfedges[k + surf->firstedge];
2498 vec = mod->vertexes[mod->edges[l].v[0]].position;
2500 vec = mod->vertexes[mod->edges[-l].v[1]].position;
2501 if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0];
2502 if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1];
2503 if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2];
2504 if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0];
2505 if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1];
2506 if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2];
2507 dist = vec[0]*vec[0]+vec[1]*vec[1];
2508 if (modelyawradius < dist)
2509 modelyawradius = dist;
2510 dist += vec[2]*vec[2];
2511 if (modelradius < dist)
2515 modelyawradius = sqrt(modelyawradius);
2516 modelradius = sqrt(modelradius);
2517 mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius);
2518 mod->yawmins[2] = mod->normalmins[2];
2519 mod->yawmaxs[2] = mod->normalmaxs[2];
2520 mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius;
2521 mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius;
2522 // mod->modelradius = modelradius;
2524 // VectorCopy (bm->maxs, mod->maxs);
2525 // VectorCopy (bm->mins, mod->mins);
2527 // mod->radius = RadiusFromBounds (mod->mins, mod->maxs);
2529 mod->numleafs = bm->visleafs;
2531 mod->SERAddEntity = Mod_Brush_SERAddEntity;
2532 mod->Draw = R_DrawBrushModelNormal;
2533 mod->DrawShadow = NULL;
2535 Mod_BrushSortedSurfaces(mod, mainmempool);
2537 // LordHavoc: only register submodels if it is the world
2538 // (prevents bsp models from replacing world submodels)
2539 if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1))
2542 // duplicate the basic information
2543 sprintf (name, "*%i", i+1);
2544 loadmodel = Mod_FindName (name);
2546 strcpy (loadmodel->name, name);
2547 // textures and memory belong to the main model
2548 loadmodel->texturepool = NULL;
2549 loadmodel->mempool = NULL;
2553 // Mem_CheckSentinelsGlobal();