X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=model_brush.c;h=5347384db691953d7fcd74c25b8fc60a1c89abbc;hp=5b7e7dd5979a918c5470921634123cdbf2fda7cf;hb=5fc5892a12b5e363a32ef7da5c2dc9cae5234f8f;hpb=bc8b80ee19f7a87e326fa765427d0c4e8dfe9940 diff --git a/model_brush.c b/model_brush.c index 5b7e7dd5..5347384d 100644 --- a/model_brush.c +++ b/model_brush.c @@ -19,6 +19,8 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" +#include "image.h" +#include "r_shadow.h" // note: model_shared.c sets up r_notexture, and r_surf_notexture @@ -29,7 +31,6 @@ cvar_t halflifebsp = {0, "halflifebsp", "0"}; cvar_t r_novis = {0, "r_novis", "0"}; cvar_t r_miplightmaps = {CVAR_SAVE, "r_miplightmaps", "0"}; cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"}; -cvar_t r_vertexsurfacesthreshold = {CVAR_SAVE, "r_vertexsurfacesthreshold", "0"}; cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"}; cvar_t r_sortsurfaces = {0, "r_sortsurfaces", "0"}; @@ -45,7 +46,6 @@ void Mod_BrushInit (void) Cvar_RegisterVariable(&r_novis); Cvar_RegisterVariable(&r_miplightmaps); Cvar_RegisterVariable(&r_lightmaprgba); - Cvar_RegisterVariable(&r_vertexsurfacesthreshold); Cvar_RegisterVariable(&r_nosurftextures); Cvar_RegisterVariable(&r_sortsurfaces); memset(mod_novis, 0xff, sizeof(mod_novis)); @@ -56,9 +56,12 @@ void Mod_BrushInit (void) Mod_PointInLeaf =============== */ -mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model) +mleaf_t *Mod_PointInLeaf (const vec3_t p, model_t *model) { - mnode_t *node; + mnode_t *node; + + if (model == NULL) + return NULL; Mod_CheckLoaded(model); @@ -71,20 +74,199 @@ mleaf_t *Mod_PointInLeaf (vec3_t p, model_t *model) return (mleaf_t *)node; } -void Mod_FindNonSolidLocation(vec3_t pos, model_t *mod) +int Mod_PointContents (const vec3_t p, model_t *model) { - if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; - pos[0]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; - pos[0]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; - pos[0]-=1; - pos[1]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; - pos[1]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; - pos[1]-=1; - pos[2]-=1;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; - pos[2]+=2;if (Mod_PointInLeaf(pos, mod)->contents != CONTENTS_SOLID) return; - pos[2]-=1; + mnode_t *node; + + if (model == NULL) + return CONTENTS_EMPTY; + + Mod_CheckLoaded(model); + + // LordHavoc: modified to start at first clip node, + // in other words: first node of the (sub)model + node = model->nodes + model->hulls[0].firstclipnode; + while (node->contents == 0) + node = node->children[(node->plane->type < 3 ? p[node->plane->type] : DotProduct (p,node->plane->normal)) < node->plane->dist]; + + return ((mleaf_t *)node)->contents; } +typedef struct findnonsolidlocationinfo_s +{ + vec3_t center; + vec_t radius; + vec3_t nudge; + vec_t bestdist; + model_t *model; +} +findnonsolidlocationinfo_t; + +#if 0 +extern cvar_t samelevel; +#endif +void Mod_FindNonSolidLocation_r_Leaf(findnonsolidlocationinfo_t *info, mleaf_t *leaf) +{ + int i, surfnum, k, *tri, *mark; + float dist, f, vert[3][3], edge[3][3], facenormal[3], edgenormal[3][3], point[3]; +#if 0 + float surfnormal[3]; +#endif + msurface_t *surf; + surfmesh_t *mesh; + for (surfnum = 0, mark = leaf->firstmarksurface;surfnum < leaf->nummarksurfaces;surfnum++, mark++) + { + surf = info->model->surfaces + *mark; + if (surf->flags & SURF_SOLIDCLIP) + { +#if 0 + VectorCopy(surf->plane->normal, surfnormal); + if (surf->flags & SURF_PLANEBACK) + VectorNegate(surfnormal, surfnormal); +#endif + for (mesh = surf->mesh;mesh;mesh = mesh->chain) + { + for (k = 0;k < mesh->numtriangles;k++) + { + tri = mesh->element3i + k * 3; + VectorCopy((mesh->vertex3f + tri[0] * 3), vert[0]); + VectorCopy((mesh->vertex3f + tri[1] * 3), vert[1]); + VectorCopy((mesh->vertex3f + tri[2] * 3), vert[2]); + VectorSubtract(vert[1], vert[0], edge[0]); + VectorSubtract(vert[2], vert[1], edge[1]); + CrossProduct(edge[1], edge[0], facenormal); + if (facenormal[0] || facenormal[1] || facenormal[2]) + { + VectorNormalize(facenormal); +#if 0 + if (VectorDistance(facenormal, surfnormal) > 0.01f) + Con_Printf("a2! %f %f %f != %f %f %f\n", facenormal[0], facenormal[1], facenormal[2], surfnormal[0], surfnormal[1], surfnormal[2]); +#endif + f = DotProduct(info->center, facenormal) - DotProduct(vert[0], facenormal); + if (f <= info->bestdist && f >= -info->bestdist) + { + VectorSubtract(vert[0], vert[2], edge[2]); + VectorNormalize(edge[0]); + VectorNormalize(edge[1]); + VectorNormalize(edge[2]); + CrossProduct(facenormal, edge[0], edgenormal[0]); + CrossProduct(facenormal, edge[1], edgenormal[1]); + CrossProduct(facenormal, edge[2], edgenormal[2]); +#if 0 + if (samelevel.integer & 1) + VectorNegate(edgenormal[0], edgenormal[0]); + if (samelevel.integer & 2) + VectorNegate(edgenormal[1], edgenormal[1]); + if (samelevel.integer & 4) + VectorNegate(edgenormal[2], edgenormal[2]); + for (i = 0;i < 3;i++) + if (DotProduct(vert[0], edgenormal[i]) > DotProduct(vert[i], edgenormal[i]) + 0.1f + || DotProduct(vert[1], edgenormal[i]) > DotProduct(vert[i], edgenormal[i]) + 0.1f + || DotProduct(vert[2], edgenormal[i]) > DotProduct(vert[i], edgenormal[i]) + 0.1f) + Con_Printf("a! %i : %f %f %f (%f %f %f)\n", i, edgenormal[i][0], edgenormal[i][1], edgenormal[i][2], facenormal[0], facenormal[1], facenormal[2]); +#endif + // face distance + if (DotProduct(info->center, edgenormal[0]) < DotProduct(vert[0], edgenormal[0]) + && DotProduct(info->center, edgenormal[1]) < DotProduct(vert[1], edgenormal[1]) + && DotProduct(info->center, edgenormal[2]) < DotProduct(vert[2], edgenormal[2])) + { + // we got lucky, the center is within the face + dist = DotProduct(info->center, facenormal) - DotProduct(vert[0], facenormal); + if (dist < 0) + { + dist = -dist; + if (info->bestdist > dist) + { + info->bestdist = dist; + VectorScale(facenormal, (info->radius - -dist), info->nudge); + } + } + else + { + if (info->bestdist > dist) + { + info->bestdist = dist; + VectorScale(facenormal, (info->radius - dist), info->nudge); + } + } + } + else + { + // check which edge or vertex the center is nearest + for (i = 0;i < 3;i++) + { + f = DotProduct(info->center, edge[i]); + if (f >= DotProduct(vert[0], edge[i]) + && f <= DotProduct(vert[1], edge[i])) + { + // on edge + VectorMA(info->center, -f, edge[i], point); + dist = sqrt(DotProduct(point, point)); + if (info->bestdist > dist) + { + info->bestdist = dist; + VectorScale(point, (info->radius / dist), info->nudge); + } + // skip both vertex checks + // (both are further away than this edge) + i++; + } + else + { + // not on edge, check first vertex of edge + VectorSubtract(info->center, vert[i], point); + dist = sqrt(DotProduct(point, point)); + if (info->bestdist > dist) + { + info->bestdist = dist; + VectorScale(point, (info->radius / dist), info->nudge); + } + } + } + } + } + } + } + } + } + } +} + +void Mod_FindNonSolidLocation_r(findnonsolidlocationinfo_t *info, mnode_t *node) +{ + if (node->contents) + { + if (((mleaf_t *)node)->nummarksurfaces) + Mod_FindNonSolidLocation_r_Leaf(info, (mleaf_t *)node); + } + else + { + float f = PlaneDiff(info->center, node->plane); + if (f >= -info->bestdist) + Mod_FindNonSolidLocation_r(info, node->children[0]); + if (f <= info->bestdist) + Mod_FindNonSolidLocation_r(info, node->children[1]); + } +} + +void Mod_FindNonSolidLocation(vec3_t in, vec3_t out, model_t *model, float radius) +{ + int i; + findnonsolidlocationinfo_t info; + VectorCopy(in, info.center); + info.radius = radius; + info.model = model; + i = 0; + do + { + VectorClear(info.nudge); + info.bestdist = radius; + Mod_FindNonSolidLocation_r(&info, model->nodes + model->hulls[0].firstclipnode); + VectorAdd(info.center, info.nudge, info.center); + } + while(info.bestdist < radius && ++i < 10); + VectorCopy(info.center, out); +} /* =================== @@ -139,7 +321,7 @@ static void Mod_LoadTextures (lump_t *l) miptex_t *dmiptex; texture_t *tx, *tx2, *anims[10], *altanims[10]; dmiptexlump_t *m; - qbyte *data, *mtdata, *data2; + qbyte *data, *mtdata; char name[256]; loadmodel->textures = NULL; @@ -153,17 +335,24 @@ static void Mod_LoadTextures (lump_t *l) // add two slots for notexture walls and notexture liquids loadmodel->numtextures = m->nummiptex + 2; - loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(*loadmodel->textures)); + loadmodel->textures = Mem_Alloc(loadmodel->mempool, loadmodel->numtextures * sizeof(texture_t)); // fill out all slots with notexture - for (i = 0;i < loadmodel->numtextures;i++) + for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++) { - loadmodel->textures[i] = tx = Mem_Alloc(loadmodel->mempool, sizeof(texture_t)); + tx->number = i; + strcpy(tx->name, "NO TEXTURE FOUND"); tx->width = 16; tx->height = 16; - tx->texture = r_notexture; + tx->skin.base = r_notexture; + tx->shader = &Cshader_wall_lightmap; + tx->flags = SURF_SOLIDCLIP; if (i == loadmodel->numtextures - 1) - tx->flags = SURF_DRAWTURB | SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID; + { + tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES; + tx->shader = &Cshader_water; + } + tx->currentframe = tx; } // just to work around bounds checking when debugging with it (array index out of bounds error thing) @@ -204,13 +393,10 @@ static void Mod_LoadTextures (lump_t *l) if (name[j] >= 'A' && name[j] <= 'Z') name[j] += 'a' - 'A'; - tx = loadmodel->textures[i]; + tx = loadmodel->textures + i; strcpy(tx->name, name); tx->width = mtwidth; tx->height = mtheight; - tx->texture = NULL; - tx->glowtexture = NULL; - tx->fogtexture = NULL; if (!tx->name[0]) { @@ -243,122 +429,76 @@ static void Mod_LoadTextures (lump_t *l) R_InitSky (mtdata, 1); } } - else if ((tx->texture = loadtextureimagewithmask(loadmodel->texturepool, tx->name, 0, 0, false, true, true))) - { - tx->fogtexture = image_masktex; - strcpy(name, tx->name); - strcat(name, "_glow"); - tx->glowtexture = loadtextureimage(loadmodel->texturepool, name, 0, 0, false, true, true); - } else { - if (loadmodel->ishlbsp) + if (!Mod_LoadSkinFrame(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, true)) { - if (mtdata && (data = W_ConvertWAD3Texture(dmiptex))) - { - // texture included - tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE); - if (R_TextureHasAlpha(tx->texture)) - { - // make mask texture - for (j = 0;j < image_width * image_height;j++) - data[j*4+0] = data[j*4+1] = data[j*4+2] = 255; - strcpy(name, tx->name); - strcat(name, "_fog"); - tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE); - } - Mem_Free(data); - } - else if ((data = W_GetTexture(tx->name))) + // did not find external texture, load it from the bsp or wad3 + if (loadmodel->ishlbsp) { - // get the size from the wad texture - tx->width = image_width; - tx->height = image_height; - tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE); - if (R_TextureHasAlpha(tx->texture)) + // internal texture overrides wad + qbyte *pixels, *freepixels; + pixels = freepixels = NULL; + if (mtdata) + pixels = W_ConvertWAD3Texture(dmiptex); + if (pixels == NULL) + pixels = freepixels = W_GetTexture(tx->name); + if (pixels != NULL) { - // make mask texture - for (j = 0;j < image_width * image_height;j++) - data[j*4+0] = data[j*4+1] = data[j*4+2] = 255; - strcpy(name, tx->name); - strcat(name, "_fog"); - tx->fogtexture = R_LoadTexture (loadmodel->texturepool, name, image_width, image_height, data, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE); + tx->width = image_width; + tx->height = image_height; + tx->skin.base = tx->skin.merged = R_LoadTexture2D(loadmodel->texturepool, tx->name, image_width, image_height, pixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL); } - Mem_Free(data); - } - else - { - tx->width = 16; - tx->height = 16; - tx->texture = r_notexture; - } - } - else - { - if (mtdata) // texture included - { - int fullbrights; - data = mtdata; - fullbrights = false; - if (r_fullbrights.value && tx->name[0] != '*') - { - for (j = 0;j < tx->width*tx->height;j++) - { - if (data[j] >= 224) // fullbright - { - fullbrights = true; - break; - } - } - } - if (fullbrights) - { - data2 = Mem_Alloc(loadmodel->mempool, tx->width*tx->height); - for (j = 0;j < tx->width*tx->height;j++) - data2[j] = data[j] >= 224 ? 0 : data[j]; // no fullbrights - tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE); - strcpy(name, tx->name); - strcat(name, "_glow"); - for (j = 0;j < tx->width*tx->height;j++) - data2[j] = data[j] >= 224 ? data[j] : 0; // only fullbrights - tx->glowtexture = R_LoadTexture (loadmodel->texturepool, name, tx->width, tx->height, data2, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE); - Mem_Free(data2); - } - else - tx->texture = R_LoadTexture (loadmodel->texturepool, tx->name, tx->width, tx->height, data, TEXTYPE_QPALETTE, TEXF_MIPMAP | TEXF_PRECACHE); - } - else // no texture, and no external replacement texture was found - { - tx->width = 16; - tx->height = 16; - tx->texture = r_notexture; + if (freepixels) + Mem_Free(freepixels); } + else if (mtdata) // texture included + Mod_LoadSkinFrame_Internal(&tx->skin, tx->name, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, false, true, tx->name[0] != '*' && r_fullbrights.integer, mtdata, tx->width, tx->height); } } + if (tx->skin.base == NULL) + { + // no texture found + tx->width = 16; + tx->height = 16; + tx->skin.base = r_notexture; + } if (tx->name[0] == '*') { - tx->flags |= (SURF_DRAWTURB | SURF_LIGHTBOTHSIDES); + // turb does not block movement + tx->flags &= ~SURF_SOLIDCLIP; + tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES; // LordHavoc: some turbulent textures should be fullbright and solid if (!strncmp(tx->name,"*lava",5) || !strncmp(tx->name,"*teleport",9) || !strncmp(tx->name,"*rift",5)) // Scourge of Armagon texture - tx->flags |= (SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA | SURF_CLIPSOLID); + tx->flags |= SURF_DRAWFULLBRIGHT | SURF_DRAWNOALPHA; + else + tx->flags |= SURF_WATERALPHA; + tx->shader = &Cshader_water; } else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y') - tx->flags |= (SURF_DRAWSKY | SURF_CLIPSOLID); + { + tx->flags |= SURF_DRAWSKY; + tx->shader = &Cshader_sky; + } else { tx->flags |= SURF_LIGHTMAP; - if (!R_TextureHasAlpha(tx->texture)) - tx->flags |= SURF_CLIPSOLID; + if (!tx->skin.fog) + tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT; + tx->shader = &Cshader_wall_lightmap; } + + // start out with no animation + tx->currentframe = tx; } // sequence the animations for (i = 0;i < m->nummiptex;i++) { - tx = loadmodel->textures[i]; + tx = loadmodel->textures + i; if (!tx || tx->name[0] != '+' || tx->name[1] == 0 || tx->name[2] == 0) continue; if (tx->anim_total[0] || tx->anim_total[1]) @@ -370,7 +510,7 @@ static void Mod_LoadTextures (lump_t *l) for (j = i;j < m->nummiptex;j++) { - tx2 = loadmodel->textures[j]; + tx2 = loadmodel->textures + j; if (!tx2 || tx2->name[0] != '+' || strcmp (tx2->name+2, tx->name+2)) continue; @@ -477,19 +617,19 @@ static void Mod_LoadLighting (lump_t *l) { // LordHavoc: hope is not lost yet, check for a .lit file to load strcpy(litfilename, loadmodel->name); - COM_StripExtension(litfilename, litfilename); + FS_StripExtension(litfilename, litfilename); strcat(litfilename, ".lit"); - data = (qbyte*) COM_LoadFile (litfilename, false); + data = (qbyte*) FS_LoadFile (litfilename, false); if (data) { - if (loadsize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') + if (fs_filesize > 8 && data[0] == 'Q' && data[1] == 'L' && data[2] == 'I' && data[3] == 'T') { i = LittleLong(((int *)data)[1]); if (i == 1) { - Con_DPrintf("%s loaded", litfilename); - loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8); - memcpy(loadmodel->lightdata, data + 8, loadsize - 8); + Con_DPrintf("loaded %s\n", litfilename); + loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, fs_filesize - 8); + memcpy(loadmodel->lightdata, data + 8, fs_filesize - 8); Mem_Free(data); return; } @@ -501,7 +641,7 @@ static void Mod_LoadLighting (lump_t *l) } else { - if (loadsize == 8) + if (fs_filesize == 8) Con_Printf("Empty .lit file, ignoring\n"); else Con_Printf("Corrupt .lit file (old version?), ignoring\n"); @@ -532,9 +672,9 @@ void Mod_LoadLightList(void) mlight_t *e; strcpy(lightsfilename, loadmodel->name); - COM_StripExtension(lightsfilename, lightsfilename); + FS_StripExtension(lightsfilename, lightsfilename); strcat(lightsfilename, ".lights"); - s = lightsstring = (char *) COM_LoadFile (lightsfilename, false); + s = lightsstring = (char *) FS_LoadFile (lightsfilename, false); if (s) { numlights = 0; @@ -570,7 +710,7 @@ void Mod_LoadLightList(void) if (a != 14) { Mem_Free(lightsstring); - Host_Error("invalid lights file, found %d parameters on line %i, should be 13 parameters (origin[0] origin[1] origin[2] falloff light[0] light[1] light[2] subtract spotdir[0] spotdir[1] spotdir[2] spotcone style)\n", a, n + 1); + 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); } s++; n++; @@ -585,6 +725,264 @@ void Mod_LoadLightList(void) } } +/* +static int castshadowcount = 0; +void Mod_ProcessLightList(void) +{ + int j, k, l, *mark, lnum; + mlight_t *e; + msurface_t *surf; + float dist; + mleaf_t *leaf; + qbyte *pvs; + vec3_t temp; + float *v, radius2; + for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++) + { + e->cullradius2 = DotProduct(e->light, e->light) / (e->falloff * e->falloff * 8192.0f * 8192.0f * 2.0f * 2.0f);// + 4096.0f; + if (e->cullradius2 > 4096.0f * 4096.0f) + e->cullradius2 = 4096.0f * 4096.0f; + e->cullradius = e->lightradius = sqrt(e->cullradius2); + leaf = Mod_PointInLeaf(e->origin, loadmodel); + if (leaf->compressed_vis) + pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel); + else + pvs = mod_novis; + for (j = 0;j < loadmodel->numsurfaces;j++) + loadmodel->surfacevisframes[j] = -1; + for (j = 0, leaf = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++, leaf++) + { + if (pvs[j >> 3] & (1 << (j & 7))) + { + for (k = 0, mark = leaf->firstmarksurface;k < leaf->nummarksurfaces;k++, mark++) + { + surf = loadmodel->surfaces + *mark; + if (surf->number != *mark) + Con_Printf("%d != %d\n", surf->number, *mark); + dist = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; + if (surf->flags & SURF_PLANEBACK) + dist = -dist; + if (dist > 0 && dist < e->cullradius) + { + temp[0] = bound(surf->poly_mins[0], e->origin[0], surf->poly_maxs[0]) - e->origin[0]; + temp[1] = bound(surf->poly_mins[1], e->origin[1], surf->poly_maxs[1]) - e->origin[1]; + temp[2] = bound(surf->poly_mins[2], e->origin[2], surf->poly_maxs[2]) - e->origin[2]; + if (DotProduct(temp, temp) < lightradius2) + loadmodel->surfacevisframes[*mark] = -2; + } + } + } + } + // build list of light receiving surfaces + e->numsurfaces = 0; + for (j = 0;j < loadmodel->numsurfaces;j++) + if (loadmodel->surfacevisframes[j] == -2) + e->numsurfaces++; + e->surfaces = NULL; + if (e->numsurfaces > 0) + { + e->surfaces = Mem_Alloc(loadmodel->mempool, sizeof(msurface_t *) * e->numsurfaces); + e->numsurfaces = 0; + for (j = 0;j < loadmodel->numsurfaces;j++) + if (loadmodel->surfacevisframes[j] == -2) + e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j; + } + // find bounding box and sphere of lit surfaces + // (these will be used for creating a shape to clip the light) + radius2 = 0; + for (j = 0;j < e->numsurfaces;j++) + { + surf = e->surfaces[j]; + if (j == 0) + { + VectorCopy(surf->poly_verts, e->mins); + VectorCopy(surf->poly_verts, e->maxs); + } + for (k = 0, v = surf->poly_verts;k < surf->poly_numverts;k++, v += 3) + { + if (e->mins[0] > v[0]) e->mins[0] = v[0];if (e->maxs[0] < v[0]) e->maxs[0] = v[0]; + if (e->mins[1] > v[1]) e->mins[1] = v[1];if (e->maxs[1] < v[1]) e->maxs[1] = v[1]; + if (e->mins[2] > v[2]) e->mins[2] = v[2];if (e->maxs[2] < v[2]) e->maxs[2] = v[2]; + VectorSubtract(v, e->origin, temp); + dist = DotProduct(temp, temp); + if (radius2 < dist) + radius2 = dist; + } + } + if (e->cullradius2 > radius2) + { + e->cullradius2 = radius2; + e->cullradius = sqrt(e->cullradius2); + } + if (e->mins[0] < e->origin[0] - e->lightradius) e->mins[0] = e->origin[0] - e->lightradius; + if (e->maxs[0] > e->origin[0] + e->lightradius) e->maxs[0] = e->origin[0] + e->lightradius; + if (e->mins[1] < e->origin[1] - e->lightradius) e->mins[1] = e->origin[1] - e->lightradius; + if (e->maxs[1] > e->origin[1] + e->lightradius) e->maxs[1] = e->origin[1] + e->lightradius; + if (e->mins[2] < e->origin[2] - e->lightradius) e->mins[2] = e->origin[2] - e->lightradius; + if (e->maxs[2] > e->origin[2] + e->lightradius) e->maxs[2] = e->origin[2] + e->lightradius; + // clip shadow volumes against eachother to remove unnecessary + // polygons (and sections of polygons) + { + //vec3_t polymins, polymaxs; + int maxverts = 4; + float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); + float f, *v0, *v1, projectdistance; + + e->shadowvolume = Mod_ShadowMesh_Begin(loadmodel->mempool, 1024); +#if 0 + { + vec3_t outermins, outermaxs, innermins, innermaxs; + innermins[0] = e->mins[0] - 1; + innermins[1] = e->mins[1] - 1; + innermins[2] = e->mins[2] - 1; + innermaxs[0] = e->maxs[0] + 1; + innermaxs[1] = e->maxs[1] + 1; + innermaxs[2] = e->maxs[2] + 1; + outermins[0] = loadmodel->normalmins[0] - 1; + outermins[1] = loadmodel->normalmins[1] - 1; + outermins[2] = loadmodel->normalmins[2] - 1; + outermaxs[0] = loadmodel->normalmaxs[0] + 1; + outermaxs[1] = loadmodel->normalmaxs[1] + 1; + outermaxs[2] = loadmodel->normalmaxs[2] + 1; + // add bounding box around the whole shadow volume set, + // facing inward to limit light area, with an outer bounding box + // facing outward (this is needed by the shadow rendering method) + // X major + verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2]; + verts[ 6] = innermaxs[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2]; + verts[ 9] = innermaxs[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2]; + verts[ 6] = outermaxs[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2]; + verts[ 9] = outermaxs[0];verts[10] = outermins[1];verts[11] = outermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + // X minor + verts[ 0] = innermins[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermins[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2]; + verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2]; + verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + verts[ 0] = outermins[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermins[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2]; + verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2]; + verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + // Y major + verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermins[2]; + verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermins[2]; + verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + verts[ 0] = outermins[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermins[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2]; + verts[ 6] = outermaxs[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2]; + verts[ 9] = outermaxs[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + // Y minor + verts[ 0] = innermins[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermins[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2]; + verts[ 6] = innermaxs[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2]; + verts[ 9] = innermaxs[0];verts[10] = innermins[1];verts[11] = innermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermins[2]; + verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermins[2]; + verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + // Z major + verts[ 0] = innermaxs[0];verts[ 1] = innermins[1];verts[ 2] = innermaxs[2]; + verts[ 3] = innermaxs[0];verts[ 4] = innermaxs[1];verts[ 5] = innermaxs[2]; + verts[ 6] = innermins[0];verts[ 7] = innermaxs[1];verts[ 8] = innermaxs[2]; + verts[ 9] = innermins[0];verts[10] = innermins[1];verts[11] = innermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + verts[ 0] = outermaxs[0];verts[ 1] = outermaxs[1];verts[ 2] = outermaxs[2]; + verts[ 3] = outermaxs[0];verts[ 4] = outermins[1];verts[ 5] = outermaxs[2]; + verts[ 6] = outermins[0];verts[ 7] = outermins[1];verts[ 8] = outermaxs[2]; + verts[ 9] = outermins[0];verts[10] = outermaxs[1];verts[11] = outermaxs[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + // Z minor + verts[ 0] = innermaxs[0];verts[ 1] = innermaxs[1];verts[ 2] = innermins[2]; + verts[ 3] = innermaxs[0];verts[ 4] = innermins[1];verts[ 5] = innermins[2]; + verts[ 6] = innermins[0];verts[ 7] = innermins[1];verts[ 8] = innermins[2]; + verts[ 9] = innermins[0];verts[10] = innermaxs[1];verts[11] = innermins[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + verts[ 0] = outermaxs[0];verts[ 1] = outermins[1];verts[ 2] = outermins[2]; + verts[ 3] = outermaxs[0];verts[ 4] = outermaxs[1];verts[ 5] = outermins[2]; + verts[ 6] = outermins[0];verts[ 7] = outermaxs[1];verts[ 8] = outermins[2]; + verts[ 9] = outermins[0];verts[10] = outermins[1];verts[11] = outermins[2]; + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + } +#endif + castshadowcount++; + for (j = 0;j < e->numsurfaces;j++) + { + surf = e->surfaces[j]; + if (surf->flags & SURF_SHADOWCAST) + surf->castshadow = castshadowcount; + } + for (j = 0;j < e->numsurfaces;j++) + { + surf = e->surfaces[j]; + if (surf->castshadow != castshadowcount) + continue; + f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; + if (surf->flags & SURF_PLANEBACK) + f = -f; + projectdistance = e->lightradius; + if (maxverts < surf->poly_numverts) + { + maxverts = surf->poly_numverts; + if (verts) + Mem_Free(verts); + verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); + } + // copy the original polygon, for the front cap of the volume + for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3) + VectorCopy(v0, v1); + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts); + // project the original polygon, reversed, for the back cap of the volume + for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = verts;k < surf->poly_numverts;k++, v0 -= 3, v1 += 3) + { + VectorSubtract(v0, e->origin, temp); + VectorNormalize(temp); + VectorMA(v0, projectdistance, temp, v1); + } + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, surf->poly_numverts, verts); + // project the shadow volume sides + for (l = surf->poly_numverts - 1, k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;l = k, k++, v0 = v1, v1 += 3) + { + if (!surf->neighborsurfaces[l] || surf->neighborsurfaces[l]->castshadow != castshadowcount) + { + VectorCopy(v1, &verts[0]); + VectorCopy(v0, &verts[3]); + VectorCopy(v0, &verts[6]); + VectorCopy(v1, &verts[9]); + VectorSubtract(&verts[6], e->origin, temp); + VectorNormalize(temp); + VectorMA(&verts[6], projectdistance, temp, &verts[6]); + VectorSubtract(&verts[9], e->origin, temp); + VectorNormalize(temp); + VectorMA(&verts[9], projectdistance, temp, &verts[9]); + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); + } + } + } + // build the triangle mesh + e->shadowvolume = Mod_ShadowMesh_Finish(loadmodel->mempool, e->shadowvolume); + { + shadowmesh_t *mesh; + l = 0; + for (mesh = e->shadowvolume;mesh;mesh = mesh->next) + l += mesh->numtriangles; + Con_Printf("light %i shadow volume built containing %i triangles\n", lnum, l); + } + } + } +} +*/ + /* ================= @@ -601,22 +999,20 @@ static void Mod_LoadVisibility (lump_t *l) } // used only for HalfLife maps -void Mod_ParseWadsFromEntityLump(char *data) +void Mod_ParseWadsFromEntityLump(const char *data) { char key[128], value[4096]; char wadname[128]; int i, j, k; if (!data) return; - data = COM_Parse(data); - if (!data) + if (!COM_ParseToken(&data)) return; // error if (com_token[0] != '{') return; // error while (1) { - data = COM_Parse(data); - if (!data) + if (!COM_ParseToken(&data)) return; // error if (com_token[0] == '}') break; // end of worldspawn @@ -626,8 +1022,7 @@ void Mod_ParseWadsFromEntityLump(char *data) strcpy(key, com_token); while (key[strlen(key)-1] == ' ') // remove trailing spaces key[strlen(key)-1] = 0; - data = COM_Parse(data); - if (!data) + if (!COM_ParseToken(&data)) return; // error strcpy(value, com_token); if (!strcmp("wad", key)) // for HalfLife maps @@ -807,71 +1202,24 @@ static void Mod_LoadTexinfo (lump_t *l) if ((unsigned int) miptex >= (unsigned int) loadmodel->numtextures) Con_Printf ("error in model \"%s\": invalid miptex index %i (of %i)\n", loadmodel->name, miptex, loadmodel->numtextures); else - out->texture = loadmodel->textures[miptex]; + out->texture = loadmodel->textures + miptex; } - if (out->texture == NULL) + if (out->flags & TEX_SPECIAL) { - // choose either the liquid notexture, or the normal notexture - if (out->flags & TEX_SPECIAL) - out->texture = loadmodel->textures[loadmodel->numtextures - 1]; - else - out->texture = loadmodel->textures[loadmodel->numtextures - 2]; + // if texture chosen is NULL or the shader needs a lightmap, + // force to notexture water shader + if (out->texture == NULL || out->texture->shader->flags & SHADERFLAGS_NEEDLIGHTMAP) + out->texture = loadmodel->textures + (loadmodel->numtextures - 1); } - } -} - -/* -================ -CalcSurfaceExtents - -Fills in s->texturemins[] and s->extents[] -================ -*/ -static void CalcSurfaceExtents (msurface_t *s) -{ - float mins[2], maxs[2], val; - int i,j, e; - mvertex_t *v; - mtexinfo_t *tex; - int bmins[2], bmaxs[2]; - - mins[0] = mins[1] = 999999999; - maxs[0] = maxs[1] = -999999999; - - tex = s->texinfo; - - for (i=0 ; inumedges ; i++) - { - e = loadmodel->surfedges[s->firstedge+i]; - if (e >= 0) - v = &loadmodel->vertexes[loadmodel->edges[e].v[0]]; else - v = &loadmodel->vertexes[loadmodel->edges[-e].v[1]]; - - for (j=0 ; j<2 ; j++) { - val = v->position[0] * tex->vecs[j][0] + - v->position[1] * tex->vecs[j][1] + - v->position[2] * tex->vecs[j][2] + - tex->vecs[j][3]; - if (val < mins[j]) - mins[j] = val; - if (val > maxs[j]) - maxs[j] = val; + // if texture chosen is NULL, force to notexture + if (out->texture == NULL) + out->texture = loadmodel->textures + (loadmodel->numtextures - 2); } } - - for (i=0 ; i<2 ; i++) - { - bmins[i] = floor(mins[i]/16); - bmaxs[i] = ceil(maxs[i]/16); - - s->texturemins[i] = bmins[i] * 16; - s->extents[i] = (bmaxs[i] - bmins[i]) * 16; - } } - void BoundPoly (int numverts, float *verts, vec3_t mins, vec3_t maxs) { int i, j; @@ -1030,170 +1378,155 @@ void Mod_GenerateWarpMesh (msurface_t *surf) } #endif -void Mod_GenerateVertexLitMesh (msurface_t *surf) +surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles) { - int i, is, it, *index, smax, tmax; - float *in, s, t; - surfvertex_t *out; - surfmesh_t *mesh; - - smax = surf->extents[0] >> 4; - tmax = surf->extents[1] >> 4; - surf->lightmaptexturestride = 0; - surf->lightmaptexture = NULL; - - surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * sizeof(surfvertex_t)); - mesh->numverts = surf->poly_numverts; - mesh->numtriangles = surf->poly_numverts - 2; - mesh->vertex = (surfvertex_t *)(mesh + 1); - mesh->index = (int *)(mesh->vertex + mesh->numverts); - memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t)); - - index = mesh->index; - for (i = 0;i < mesh->numtriangles;i++) - { - *index++ = 0; - *index++ = i + 1; - *index++ = i + 2; - } - - for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++) - { - VectorCopy (in, out->v); - - s = DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]; - t = DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]; - - out->st[0] = s / surf->texinfo->texture->width; - out->st[1] = t / surf->texinfo->texture->height; - - s = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0); - t = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0); - - // lightmap coordinates - out->uv[0] = 0; - out->uv[1] = 0; - - // LordHavoc: calc lightmap data offset for vertex lighting to use - is = (int) s; - it = (int) t; - is = bound(0, is, smax); - it = bound(0, it, tmax); - out->lightmapoffset = ((it * (smax+1) + is) * 3); - } + surfmesh_t *mesh; + mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (3 + 2 + 2 + 2 + 3 + 3 + 3 + 1) * sizeof(float)); + mesh->numverts = numverts; + mesh->numtriangles = numtriangles; + mesh->vertex3f = (float *)(mesh + 1); + mesh->texcoordtexture2f = mesh->vertex3f + mesh->numverts * 3; + mesh->texcoordlightmap2f = mesh->texcoordtexture2f + mesh->numverts * 2; + mesh->texcoorddetail2f = mesh->texcoordlightmap2f + mesh->numverts * 2; + mesh->svector3f = (float *)(mesh->texcoorddetail2f + mesh->numverts * 2); + mesh->tvector3f = mesh->svector3f + mesh->numverts * 3; + mesh->normal3f = mesh->tvector3f + mesh->numverts * 3; + mesh->lightmapoffsets = (int *)(mesh->normal3f + mesh->numverts * 3); + mesh->element3i = mesh->lightmapoffsets + mesh->numverts; + mesh->neighbor3i = mesh->element3i + mesh->numtriangles * 3; + return mesh; } -void Mod_GenerateLightmappedMesh (msurface_t *surf) +void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) { - int i, is, it, *index, smax, tmax; - float *in, s, t, xbase, ybase, xscale, yscale; - surfvertex_t *out; - surfmesh_t *mesh; + int i, iu, iv, *index, smax, tmax; + float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3]; + surfmesh_t *mesh; - surf->flags |= SURF_LIGHTMAP; smax = surf->extents[0] >> 4; tmax = surf->extents[1] >> 4; - if (r_miplightmaps.integer) + + if (vertexonly) { - surf->lightmaptexturestride = (surf->extents[0]>>4)+1; - 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); + surf->lightmaptexturestride = 0; + surf->lightmaptexture = NULL; + uscale = 0; + vscale = 0; + ubase = 0; + vbase = 0; } else { - surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0); - 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); + surf->flags |= SURF_LIGHTMAP; + if (r_miplightmaps.integer) + { + surf->lightmaptexturestride = (surf->extents[0]>>4)+1; + surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_MIPMAP | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL); + } + else + { + surf->lightmaptexturestride = R_CompatibleFragmentWidth((surf->extents[0]>>4)+1, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, 0); + surf->lightmaptexture = R_LoadTexture2D(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_FORCELINEAR | TEXF_PRECACHE, NULL); + } + R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &ubase, &vbase, &uscale, &vscale); + uscale = (uscale - ubase) * 16.0 / ((surf->extents[0] & ~15) + 16); + vscale = (vscale - vbase) * 16.0 / ((surf->extents[1] & ~15) + 16); } - R_FragmentLocation(surf->lightmaptexture, NULL, NULL, &xbase, &ybase, &xscale, &yscale); - xscale = (xscale - xbase) * 16.0 / ((surf->extents[0] & ~15) + 16); - yscale = (yscale - ybase) * 16.0 / ((surf->extents[1] & ~15) + 16); - surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * sizeof(surfvertex_t)); - mesh->numverts = surf->poly_numverts; - mesh->numtriangles = surf->poly_numverts - 2; - mesh->vertex = (surfvertex_t *)(mesh + 1); - mesh->index = (int *)(mesh->vertex + mesh->numverts); - memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t)); + surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2); - index = mesh->index; + index = mesh->element3i; for (i = 0;i < mesh->numtriangles;i++) { *index++ = 0; *index++ = i + 1; *index++ = i + 2; } + Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles); - for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++) + VectorCopy(surf->plane->normal, normal); + if (surf->flags & SURF_PLANEBACK) + VectorNegate(normal, normal); + for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3) { - VectorCopy (in, out->v); - - s = DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]; - t = DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]; - - out->st[0] = s / surf->texinfo->texture->width; - out->st[1] = t / surf->texinfo->texture->height; - - s = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0); - t = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0); - - // lightmap coordinates - out->uv[0] = s * xscale + xbase; - out->uv[1] = t * yscale + ybase; - + s = DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]; + t = DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]; + u = (s + 8 - surf->texturemins[0]) * (1.0 / 16.0); + v = (t + 8 - surf->texturemins[1]) * (1.0 / 16.0); // LordHavoc: calc lightmap data offset for vertex lighting to use - is = (int) s; - it = (int) t; - is = bound(0, is, smax); - it = bound(0, it, tmax); - out->lightmapoffset = ((it * (smax+1) + is) * 3); + iu = (int) u; + iv = (int) v; + iu = bound(0, iu, smax); + iv = bound(0, iv, tmax); + u = u * uscale + ubase; + v = v * vscale + vbase; + + mesh->vertex3f[i * 3 + 0] = in[0]; + mesh->vertex3f[i * 3 + 1] = in[1]; + mesh->vertex3f[i * 3 + 2] = in[2]; + mesh->texcoordtexture2f[i * 2 + 0] = s / surf->texinfo->texture->width; + mesh->texcoordtexture2f[i * 2 + 1] = t / surf->texinfo->texture->height; + mesh->texcoordlightmap2f[i * 2 + 0] = u; + mesh->texcoordlightmap2f[i * 2 + 1] = v; + mesh->texcoorddetail2f[i * 2 + 0] = s * (1.0f / 16.0f); + mesh->texcoorddetail2f[i * 2 + 1] = t * (1.0f / 16.0f); + mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3); } + Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->vertex3f, mesh->texcoordtexture2f, mesh->element3i, mesh->svector3f, mesh->tvector3f, mesh->normal3f); } void Mod_GenerateVertexMesh (msurface_t *surf) { - int i, *index; - float *in; - surfvertex_t *out; - surfmesh_t *mesh; + int i, *index; + float *in, s, t, normal[3]; + surfmesh_t *mesh; surf->lightmaptexturestride = 0; surf->lightmaptexture = NULL; - surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[3]) + surf->poly_numverts * sizeof(surfvertex_t)); - mesh->numverts = surf->poly_numverts; - mesh->numtriangles = surf->poly_numverts - 2; - mesh->vertex = (surfvertex_t *)(mesh + 1); - mesh->index = (int *)(mesh->vertex + mesh->numverts); - memset(mesh->vertex, 0, mesh->numverts * sizeof(surfvertex_t)); + surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2); - index = mesh->index; + index = mesh->element3i; for (i = 0;i < mesh->numtriangles;i++) { *index++ = 0; *index++ = i + 1; *index++ = i + 2; } + Mod_BuildTriangleNeighbors(mesh->neighbor3i, mesh->element3i, mesh->numtriangles); - for (i = 0, in = surf->poly_verts, out = mesh->vertex;i < mesh->numverts;i++, in += 3, out++) + VectorCopy(surf->plane->normal, normal); + if (surf->flags & SURF_PLANEBACK) + VectorNegate(normal, normal); + for (i = 0, in = surf->poly_verts;i < mesh->numverts;i++, in += 3) { - VectorCopy (in, out->v); - out->st[0] = (DotProduct (out->v, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]) / surf->texinfo->texture->width; - out->st[1] = (DotProduct (out->v, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]) / surf->texinfo->texture->height; + s = (DotProduct (in, surf->texinfo->vecs[0]) + surf->texinfo->vecs[0][3]); + t = (DotProduct (in, surf->texinfo->vecs[1]) + surf->texinfo->vecs[1][3]); + mesh->vertex3f[i * 3 + 0] = in[0]; + mesh->vertex3f[i * 3 + 1] = in[1]; + mesh->vertex3f[i * 3 + 2] = in[2]; + mesh->texcoordtexture2f[i * 2 + 0] = s / surf->texinfo->texture->width; + mesh->texcoordtexture2f[i * 2 + 1] = t / surf->texinfo->texture->height; + mesh->texcoordlightmap2f[i * 2 + 0] = 0; + mesh->texcoordlightmap2f[i * 2 + 1] = 0; + mesh->texcoorddetail2f[i * 2 + 0] = s * (1.0f / 16.0f); + mesh->texcoorddetail2f[i * 2 + 1] = t * (1.0f / 16.0f); } + Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->vertex3f, mesh->texcoordtexture2f, mesh->element3i, mesh->svector3f, mesh->tvector3f, mesh->normal3f); } -void Mod_GenerateSurfacePolygon (msurface_t *surf) +void Mod_GenerateSurfacePolygon (msurface_t *surf, int firstedge, int numedges) { - float *vert; - int i; - int lindex; - float *vec; + int i, lindex, j; + float *vec, *vert, mins[3], maxs[3], val, *v; + mtexinfo_t *tex; // convert edges back to a normal polygon - surf->poly_numverts = surf->numedges; - vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * surf->numedges); - for (i = 0;i < surf->numedges;i++) + surf->poly_numverts = numedges; + vert = surf->poly_verts = Mem_Alloc(loadmodel->mempool, sizeof(float[3]) * numedges); + for (i = 0;i < numedges;i++) { - lindex = loadmodel->surfedges[surf->firstedge + i]; + lindex = loadmodel->surfedges[firstedge + i]; if (lindex > 0) vec = loadmodel->vertexes[loadmodel->edges[lindex].v[0]].position; else @@ -1201,54 +1534,43 @@ void Mod_GenerateSurfacePolygon (msurface_t *surf) VectorCopy (vec, vert); vert += 3; } -} -static void Mod_SplitSurfMeshIfTooBig(msurface_t *s) -{ - int j, base, tricount, newvertexcount, *index, *vertexremap; - surfmesh_t *newmesh, *oldmesh, *firstmesh; - if (s->mesh->numtriangles > 1000) - { - vertexremap = Mem_Alloc(tempmempool, s->mesh->numverts * sizeof(int)); - base = 0; - oldmesh = NULL; - firstmesh = NULL; - newmesh = NULL; - while (base < s->mesh->numtriangles) - { - tricount = s->mesh->numtriangles - base; - if (tricount > 1000) - tricount = 1000; - index = s->mesh->index + base * 3; - base += tricount; - - newvertexcount = 0; - memset(vertexremap, -1, s->mesh->numverts * sizeof(int)); - for (j = 0;j < tricount * 3;j++) - if (vertexremap[index[j]] < 0) - vertexremap[index[j]] = newvertexcount++; - - newmesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + newvertexcount * sizeof(surfvertex_t) + tricount * sizeof(int[3])); - newmesh->chain = NULL; - newmesh->numverts = newvertexcount; - newmesh->numtriangles = tricount; - newmesh->vertex = (surfvertex_t *)(newmesh + 1); - newmesh->index = (int *)(newmesh->vertex + newvertexcount); - for (j = 0;j < tricount * 3;j++) - { - newmesh->index[j] = vertexremap[index[j]]; - // yes this copies the same vertex multiple times in many cases... but that's ok... - memcpy(&newmesh->vertex[newmesh->index[j]], &s->mesh->vertex[index[j]], sizeof(surfvertex_t)); - } - if (oldmesh) - oldmesh->chain = newmesh; - else - firstmesh = newmesh; - oldmesh = newmesh; + // calculate polygon bounding box and center + vert = surf->poly_verts; + VectorCopy(vert, mins); + VectorCopy(vert, maxs); + vert += 3; + for (i = 1;i < surf->poly_numverts;i++, vert += 3) + { + if (mins[0] > vert[0]) mins[0] = vert[0];if (maxs[0] < vert[0]) maxs[0] = vert[0]; + if (mins[1] > vert[1]) mins[1] = vert[1];if (maxs[1] < vert[1]) maxs[1] = vert[1]; + if (mins[2] > vert[2]) mins[2] = vert[2];if (maxs[2] < vert[2]) maxs[2] = vert[2]; + } + VectorCopy(mins, surf->poly_mins); + VectorCopy(maxs, surf->poly_maxs); + surf->poly_center[0] = (mins[0] + maxs[0]) * 0.5f; + surf->poly_center[1] = (mins[1] + maxs[1]) * 0.5f; + surf->poly_center[2] = (mins[2] + maxs[2]) * 0.5f; + + // generate surface extents information + tex = surf->texinfo; + mins[0] = maxs[0] = DotProduct(surf->poly_verts, tex->vecs[0]) + tex->vecs[0][3]; + mins[1] = maxs[1] = DotProduct(surf->poly_verts, tex->vecs[1]) + tex->vecs[1][3]; + for (i = 1, v = surf->poly_verts + 3;i < surf->poly_numverts;i++, v += 3) + { + for (j = 0;j < 2;j++) + { + val = DotProduct(v, tex->vecs[j]) + tex->vecs[j][3]; + if (mins[j] > val) + mins[j] = val; + if (maxs[j] < val) + maxs[j] = val; } - Mem_Free(vertexremap); - Mem_Free(s->mesh); - s->mesh = firstmesh; + } + for (i = 0;i < 2;i++) + { + surf->texturemins[i] = (int) floor(mins[i] / 16) * 16; + surf->extents[i] = (int) ceil(maxs[i] / 16) * 16 - surf->texturemins[i]; } } @@ -1261,7 +1583,7 @@ static void Mod_LoadFaces (lump_t *l) { dface_t *in; msurface_t *out; - int i, count, surfnum, planenum, ssize, tsize; + int i, count, surfnum, planenum, ssize, tsize, firstedge, numedges; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) @@ -1271,14 +1593,18 @@ static void Mod_LoadFaces (lump_t *l) loadmodel->surfaces = out; loadmodel->numsurfaces = count; + loadmodel->surfacevisframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int)); + loadmodel->surfacepvsframes = Mem_Alloc(loadmodel->mempool, count * sizeof(int)); + loadmodel->pvssurflist = Mem_Alloc(loadmodel->mempool, count * sizeof(int)); for (surfnum = 0;surfnum < count;surfnum++, in++, out++) { + out->number = surfnum; // FIXME: validate edges, texinfo, etc? - out->firstedge = LittleLong(in->firstedge); - out->numedges = LittleShort(in->numedges); - if ((unsigned int) out->firstedge + (unsigned int) out->numedges > (unsigned int) loadmodel->numsurfedges) - Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", out->firstedge, out->numedges, loadmodel->numsurfedges); + firstedge = LittleLong(in->firstedge); + numedges = LittleShort(in->numedges); + if ((unsigned int) firstedge + (unsigned int) numedges > (unsigned int) loadmodel->numsurfedges) + Host_Error("Mod_LoadFaces: invalid edge range (firstedge %i, numedges %i, model edges %i)\n", firstedge, numedges, loadmodel->numsurfedges); i = LittleShort (in->texinfo); if ((unsigned int) i >= (unsigned int) loadmodel->numtexinfo) @@ -1300,10 +1626,8 @@ static void Mod_LoadFaces (lump_t *l) // force lightmap upload on first time seeing the surface out->cached_dlight = true; - out->cached_ambient = -1000; - out->cached_lightscalebit = -1000; - CalcSurfaceExtents (out); + Mod_GenerateSurfacePolygon(out, firstedge, numedges); ssize = (out->extents[0] >> 4) + 1; tsize = (out->extents[1] >> 4) + 1; @@ -1319,88 +1643,21 @@ static void Mod_LoadFaces (lump_t *l) else // LordHavoc: white lighting (bsp version 29) out->samples = loadmodel->lightdata + (i * 3); - Mod_GenerateSurfacePolygon(out); - - if (out->texinfo->texture->flags & SURF_DRAWSKY) + if (out->texinfo->texture->shader == &Cshader_wall_lightmap) { - out->shader = &Cshader_sky; - out->samples = NULL; - Mod_GenerateVertexMesh (out); - } - else if (out->texinfo->texture->flags & SURF_DRAWTURB) - { - out->shader = &Cshader_water; - out->samples = NULL; - Mod_GenerateVertexMesh (out); + if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256)) + Host_Error ("Bad surface extents"); + Mod_GenerateWallMesh (out, false); + // stainmap for permanent marks on walls + out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3); + // clear to white + memset(out->stainsamples, 255, ssize * tsize * 3); } else - { - if (!R_TextureHasAlpha(out->texinfo->texture->texture)) - out->flags |= SURF_CLIPSOLID; - if (out->texinfo->flags & TEX_SPECIAL) - { - // qbsp couldn't find the texture for this surface, but it was either turb or sky... assume turb - out->shader = &Cshader_water; - out->shader = &Cshader_water; - out->samples = NULL; - Mod_GenerateVertexMesh (out); - } - else if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256)) - { - Con_Printf ("Bad surface extents, converting to fullbright polygon"); - out->shader = &Cshader_wall_fullbright; - out->samples = NULL; - Mod_GenerateVertexMesh(out); - } - else - { - // stainmap for permanent marks on walls - out->stainsamples = Mem_Alloc(loadmodel->mempool, ssize * tsize * 3); - // clear to white - memset(out->stainsamples, 255, ssize * tsize * 3); - if (out->extents[0] < r_vertexsurfacesthreshold.integer && out->extents[1] < r_vertexsurfacesthreshold.integer) - { - out->shader = &Cshader_wall_vertex; - Mod_GenerateVertexLitMesh(out); - } - else - { - out->shader = &Cshader_wall_lightmap; - Mod_GenerateLightmappedMesh(out); - } - } - } - Mod_SplitSurfMeshIfTooBig(out); + Mod_GenerateVertexMesh (out); } } -static model_t *sortmodel; - -static int Mod_SurfaceQSortCompare(const void *voida, const void *voidb) -{ - const msurface_t *a, *b; - a = *((const msurface_t **)voida); - b = *((const msurface_t **)voidb); - if (a->shader != b->shader) - return (qbyte *) a->shader - (qbyte *) b->shader; - if (a->texinfo->texture != b->texinfo->texture); - return a->texinfo->texture - b->texinfo->texture; - return 0; -} - -static void Mod_BrushSortedSurfaces(model_t *model, mempool_t *pool) -{ - int surfnum; - sortmodel = model; - sortmodel->modelsortedsurfaces = Mem_Alloc(pool, sortmodel->nummodelsurfaces * sizeof(msurface_t *)); - for (surfnum = 0;surfnum < sortmodel->nummodelsurfaces;surfnum++) - sortmodel->modelsortedsurfaces[surfnum] = &sortmodel->surfaces[surfnum + sortmodel->firstmodelsurface]; - - if (r_sortsurfaces.integer) - qsort(sortmodel->modelsortedsurfaces, sortmodel->nummodelsurfaces, sizeof(msurface_t *), Mod_SurfaceQSortCompare); -} - - /* ================= Mod_SetParent @@ -1649,21 +1906,21 @@ Mod_LoadMarksurfaces */ static void Mod_LoadMarksurfaces (lump_t *l) { - int i, j; - short *in; + int i, j; + short *in; in = (void *)(mod_base + l->fileofs); if (l->filelen % sizeof(*in)) Host_Error ("MOD_LoadBmodel: funny lump size in %s",loadmodel->name); loadmodel->nummarksurfaces = l->filelen / sizeof(*in); - loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(msurface_t *)); + loadmodel->marksurfaces = Mem_Alloc(loadmodel->mempool, loadmodel->nummarksurfaces * sizeof(int)); for (i = 0;i < loadmodel->nummarksurfaces;i++) { j = (unsigned) LittleShort(in[i]); if (j >= loadmodel->numsurfaces) Host_Error ("Mod_ParseMarksurfaces: bad surface number"); - loadmodel->marksurfaces[i] = loadmodel->surfaces + j; + loadmodel->marksurfaces[i] = j; } } @@ -2304,7 +2561,7 @@ static void Mod_RecursiveNodePortals (mnode_t *node) nodeportalwinding = ClipWinding (nodeportalwinding, &clipplane, true); if (!nodeportalwinding) { - printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n"); + Con_Printf ("Mod_RecursiveNodePortals: WARNING: new portal was clipped away\n"); break; } } @@ -2386,18 +2643,161 @@ static void Mod_MakePortals(void) Mod_FinalizePortals(); } +static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool) +{ +#if 0 + int surfnum, vertnum, vertnum2, snum, vnum, vnum2; + msurface_t *surf, *s; + float *v0, *v1, *v2, *v3; + for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++) + surf->neighborsurfaces = Mem_Alloc(mempool, surf->poly_numverts * sizeof(msurface_t *)); + for (surf = surfaces, surfnum = 0;surfnum < numsurfaces;surf++, surfnum++) + { + for (vertnum = surf->poly_numverts - 1, vertnum2 = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;vertnum2 < surf->poly_numverts;vertnum = vertnum2, vertnum2++, v0 = v1, v1 += 3) + { + if (surf->neighborsurfaces[vertnum]) + continue; + surf->neighborsurfaces[vertnum] = NULL; + for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++) + { + if (s->poly_mins[0] > (surf->poly_maxs[0] + 1) || s->poly_maxs[0] < (surf->poly_mins[0] - 1) + || s->poly_mins[1] > (surf->poly_maxs[1] + 1) || s->poly_maxs[1] < (surf->poly_mins[1] - 1) + || s->poly_mins[2] > (surf->poly_maxs[2] + 1) || s->poly_maxs[2] < (surf->poly_mins[2] - 1) + || s == surf) + continue; + for (vnum = 0;vnum < s->poly_numverts;vnum++) + if (s->neighborsurfaces[vnum] == surf) + break; + if (vnum < s->poly_numverts) + continue; + for (vnum = s->poly_numverts - 1, vnum2 = 0, v2 = s->poly_verts + (s->poly_numverts - 1) * 3, v3 = s->poly_verts;vnum2 < s->poly_numverts;vnum = vnum2, vnum2++, v2 = v3, v3 += 3) + { + if (s->neighborsurfaces[vnum] == NULL + && ((v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2]) + || (v1[0] == v2[0] && v1[1] == v2[1] && v1[2] == v2[2] && v0[0] == v3[0] && v0[1] == v3[1] && v0[2] == v3[2]))) + { + surf->neighborsurfaces[vertnum] = s; + s->neighborsurfaces[vnum] = surf; + break; + } + } + if (vnum < s->poly_numverts) + break; + } + } + } +#endif +} + +void Mod_BuildLightmapUpdateChains(mempool_t *mempool, model_t *model) +{ + int i, j, stylecounts[256], totalcount, remapstyles[256]; + msurface_t *surf; + memset(stylecounts, 0, sizeof(stylecounts)); + for (i = 0;i < model->nummodelsurfaces;i++) + { + surf = model->surfaces + model->firstmodelsurface + i; + for (j = 0;j < MAXLIGHTMAPS;j++) + stylecounts[surf->styles[j]]++; + } + totalcount = 0; + model->light_styles = 0; + for (i = 0;i < 255;i++) + { + if (stylecounts[i]) + { + remapstyles[i] = model->light_styles++; + totalcount += stylecounts[i] + 1; + } + } + if (!totalcount) + return; + model->light_style = Mem_Alloc(mempool, model->light_styles * sizeof(qbyte)); + model->light_stylevalue = Mem_Alloc(mempool, model->light_styles * sizeof(int)); + model->light_styleupdatechains = Mem_Alloc(mempool, model->light_styles * sizeof(msurface_t **)); + model->light_styleupdatechainsbuffer = Mem_Alloc(mempool, totalcount * sizeof(msurface_t *)); + model->light_styles = 0; + for (i = 0;i < 255;i++) + if (stylecounts[i]) + model->light_style[model->light_styles++] = i; + j = 0; + for (i = 0;i < model->light_styles;i++) + { + model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j; + j += stylecounts[model->light_style[i]] + 1; + } + for (i = 0;i < model->nummodelsurfaces;i++) + { + surf = model->surfaces + model->firstmodelsurface + i; + for (j = 0;j < MAXLIGHTMAPS;j++) + if (surf->styles[j] != 255) + *model->light_styleupdatechains[remapstyles[surf->styles[j]]]++ = surf; + } + j = 0; + for (i = 0;i < model->light_styles;i++) + { + *model->light_styleupdatechains[i] = NULL; + model->light_styleupdatechains[i] = model->light_styleupdatechainsbuffer + j; + j += stylecounts[model->light_style[i]] + 1; + } +} + +void Mod_BuildPVSTextureChains(model_t *model) +{ + int i, j; + for (i = 0;i < model->numtextures;i++) + model->pvstexturechainslength[i] = 0; + for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++) + { + if (model->surfacepvsframes[j] == model->pvsframecount) + { + model->pvssurflist[model->pvssurflistlength++] = j; + model->pvstexturechainslength[model->surfaces[j].texinfo->texture->number]++; + } + } + for (i = 0, j = 0;i < model->numtextures;i++) + { + if (model->pvstexturechainslength[i]) + { + model->pvstexturechains[i] = model->pvstexturechainsbuffer + j; + j += model->pvstexturechainslength[i] + 1; + } + else + model->pvstexturechains[i] = NULL; + } + for (i = 0, j = model->firstmodelsurface;i < model->nummodelsurfaces;i++, j++) + if (model->surfacepvsframes[j] == model->pvsframecount) + *model->pvstexturechains[model->surfaces[j].texinfo->texture->number]++ = model->surfaces + j; + for (i = 0;i < model->numtextures;i++) + { + if (model->pvstexturechainslength[i]) + { + *model->pvstexturechains[i] = NULL; + model->pvstexturechains[i] -= model->pvstexturechainslength[i]; + } + } +} + /* ================= Mod_LoadBrushModel ================= */ +extern void R_Model_Brush_DrawSky(entity_render_t *ent); +extern void R_Model_Brush_Draw(entity_render_t *ent); +extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius); +extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, vec3_t relativeeyeorigin, float lightradius, float *lightcolor, const matrix4x4_t *matrix_modeltofilter, const matrix4x4_t *matrix_modeltoattenuationxyz, const matrix4x4_t *matrix_modeltoattenuationz); void Mod_LoadBrushModel (model_t *mod, void *buffer) { - int i, j; - dheader_t *header; - dmodel_t *bm; - mempool_t *mainmempool; - char *loadname; + int i, j, k; + dheader_t *header; + dmodel_t *bm; + mempool_t *mainmempool; + char *loadname; + model_t *originalloadmodel; + float dist, modelyawradius, modelradius, *vec; + msurface_t *surf; + surfmesh_t *mesh; mod->type = mod_brush; @@ -2408,12 +2808,16 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) Host_Error ("Mod_LoadBrushModel: %s has wrong version number (%i should be %i (Quake) or 30 (HalfLife))", mod->name, i, BSPVERSION); mod->ishlbsp = i == 30; if (loadmodel->isworldmodel) + { Cvar_SetValue("halflifebsp", mod->ishlbsp); + // until we get a texture for it... + R_ResetQuakeSky(); + } // swap all the lumps mod_base = (qbyte *)header; - for (i=0 ; iname; Mod_LoadLightList (); + originalloadmodel = loadmodel; // // set up the submodels (FIXME: this is confusing) // for (i = 0;i < mod->numsubmodels;i++) { - int k, l; - float dist, modelyawradius, modelradius, *vec; - msurface_t *surf; - - mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f; - mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f; - modelyawradius = 0; - modelradius = 0; - bm = &mod->submodels[i]; mod->hulls[0].firstclipnode = bm->headnode[0]; @@ -2473,60 +2869,71 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) mod->firstmodelsurface = bm->firstface; mod->nummodelsurfaces = bm->numfaces; + // this gets altered below if sky is used mod->DrawSky = NULL; - // LordHavoc: calculate bmodel bounding box rather than trusting what it says - for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++) + mod->Draw = R_Model_Brush_Draw; + mod->DrawFakeShadow = NULL; + mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume; + mod->DrawLight = R_Model_Brush_DrawLight; + mod->pvstexturechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t **)); + mod->pvstexturechainsbuffer = Mem_Alloc(originalloadmodel->mempool, (mod->nummodelsurfaces + mod->numtextures) * sizeof(msurface_t *)); + mod->pvstexturechainslength = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(int)); + Mod_BuildPVSTextureChains(mod); + Mod_BuildLightmapUpdateChains(originalloadmodel->mempool, mod); + if (mod->nummodelsurfaces) { - // we only need to have a drawsky function if it is used (usually only on world model) - if (surf->shader == &Cshader_sky) - mod->DrawSky = R_DrawBrushModelSky; - for (k = 0;k < surf->numedges;k++) + // LordHavoc: calculate bmodel bounding box rather than trusting what it says + mod->normalmins[0] = mod->normalmins[1] = mod->normalmins[2] = 1000000000.0f; + mod->normalmaxs[0] = mod->normalmaxs[1] = mod->normalmaxs[2] = -1000000000.0f; + modelyawradius = 0; + modelradius = 0; + for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++) { - l = mod->surfedges[k + surf->firstedge]; - if (l > 0) - vec = mod->vertexes[mod->edges[l].v[0]].position; - else - vec = mod->vertexes[mod->edges[-l].v[1]].position; - if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0]; - if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1]; - if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2]; - if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0]; - if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1]; - if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2]; - dist = vec[0]*vec[0]+vec[1]*vec[1]; - if (modelyawradius < dist) - modelyawradius = dist; - dist += vec[2]*vec[2]; - if (modelradius < dist) - modelradius = dist; + // we only need to have a drawsky function if it is used (usually only on world model) + if (surf->texinfo->texture->shader == &Cshader_sky) + mod->DrawSky = R_Model_Brush_DrawSky; + // LordHavoc: submodels always clip, even if water + if (mod->numsubmodels - 1) + surf->flags |= SURF_SOLIDCLIP; + // calculate bounding shapes + for (mesh = surf->mesh;mesh;mesh = mesh->chain) + { + for (k = 0, vec = mesh->vertex3f;k < mesh->numverts;k++, vec += 3) + { + if (mod->normalmins[0] > vec[0]) mod->normalmins[0] = vec[0]; + if (mod->normalmins[1] > vec[1]) mod->normalmins[1] = vec[1]; + if (mod->normalmins[2] > vec[2]) mod->normalmins[2] = vec[2]; + if (mod->normalmaxs[0] < vec[0]) mod->normalmaxs[0] = vec[0]; + if (mod->normalmaxs[1] < vec[1]) mod->normalmaxs[1] = vec[1]; + if (mod->normalmaxs[2] < vec[2]) mod->normalmaxs[2] = vec[2]; + dist = vec[0]*vec[0]+vec[1]*vec[1]; + if (modelyawradius < dist) + modelyawradius = dist; + dist += vec[2]*vec[2]; + if (modelradius < dist) + modelradius = dist; + } + } } + modelyawradius = sqrt(modelyawradius); + modelradius = sqrt(modelradius); + mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius); + mod->yawmins[2] = mod->normalmins[2]; + mod->yawmaxs[2] = mod->normalmaxs[2]; + mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius; + mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius; + mod->radius = modelradius; + mod->radius2 = modelradius * modelradius; } - modelyawradius = sqrt(modelyawradius); - modelradius = sqrt(modelradius); - mod->yawmins[0] = mod->yawmins[1] = -(mod->yawmaxs[0] = mod->yawmaxs[1] = modelyawradius); - mod->yawmins[2] = mod->normalmins[2]; - mod->yawmaxs[2] = mod->normalmaxs[2]; - mod->rotatedmins[0] = mod->rotatedmins[1] = mod->rotatedmins[2] = -modelradius; - mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius; - // LordHavoc: check for empty submodels (lacrima.bsp has such a glitch) - if (mod->normalmins[0] > mod->normalmaxs[0] || mod->normalmins[1] > mod->normalmaxs[1] || mod->normalmins[2] > mod->normalmaxs[2]) + else { + // LordHavoc: empty submodel (lacrima.bsp has such a glitch) Con_Printf("warning: empty submodel *%i in %s\n", i+1, loadname); - VectorClear(mod->normalmins); - VectorClear(mod->normalmaxs); - VectorClear(mod->yawmins); - VectorClear(mod->yawmaxs); - VectorClear(mod->rotatedmins); - VectorClear(mod->rotatedmaxs); } + Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool); mod->numleafs = bm->visleafs; - mod->Draw = R_DrawBrushModelNormal; - mod->DrawShadow = NULL; - - Mod_BrushSortedSurfaces(mod, mainmempool); - // LordHavoc: only register submodels if it is the world // (prevents bsp models from replacing world submodels) if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1)) @@ -2543,5 +2950,8 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) mod = loadmodel; } } + + loadmodel = originalloadmodel; + //Mod_ProcessLightList (); }