X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=model_brush.c;h=5e74ea4d237a40a8e7e3455ff0c084f112a35d2c;hp=a499fd4c0f40384e3f516c03fcb06435939d24f2;hb=f7c977317897310bddfd6f32e179a79e2c1caa14;hpb=0842f5b47e27ebfc2b143387732d71f159ae3b40 diff --git a/model_brush.c b/model_brush.c index a499fd4c..5e74ea4d 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 @@ -32,10 +34,6 @@ cvar_t r_lightmaprgba = {0, "r_lightmaprgba", "1"}; cvar_t r_nosurftextures = {0, "r_nosurftextures", "0"}; cvar_t r_sortsurfaces = {0, "r_sortsurfaces", "0"}; -#define NUM_DETAILTEXTURES 1 -static rtexture_t *detailtextures[NUM_DETAILTEXTURES]; -static rtexturepool_t *detailtexturepool; - /* =============== Mod_BrushInit @@ -53,55 +51,6 @@ void Mod_BrushInit (void) memset(mod_novis, 0xff, sizeof(mod_novis)); } -void Mod_BrushStartup (void) -{ - int i, x, y, light; - float vc[3], vx[3], vy[3], vn[3], lightdir[3]; -#define DETAILRESOLUTION 256 - qbyte data[DETAILRESOLUTION][DETAILRESOLUTION][4], noise[DETAILRESOLUTION][DETAILRESOLUTION]; - detailtexturepool = R_AllocTexturePool(); - lightdir[0] = 0.5; - lightdir[1] = 1; - lightdir[2] = -0.25; - VectorNormalize(lightdir); - for (i = 0;i < NUM_DETAILTEXTURES;i++) - { - fractalnoise(&noise[0][0], DETAILRESOLUTION, DETAILRESOLUTION >> 4); - for (y = 0;y < DETAILRESOLUTION;y++) - { - for (x = 0;x < DETAILRESOLUTION;x++) - { - vc[0] = x; - vc[1] = y; - vc[2] = noise[y][x] * (1.0f / 32.0f); - vx[0] = x + 1; - vx[1] = y; - vx[2] = noise[y][(x + 1) % DETAILRESOLUTION] * (1.0f / 32.0f); - vy[0] = x; - vy[1] = y + 1; - vy[2] = noise[(y + 1) % DETAILRESOLUTION][x] * (1.0f / 32.0f); - VectorSubtract(vx, vc, vx); - VectorSubtract(vy, vc, vy); - CrossProduct(vx, vy, vn); - VectorNormalize(vn); - light = 128 - DotProduct(vn, lightdir) * 128; - light = bound(0, light, 255); - data[y][x][0] = data[y][x][1] = data[y][x][2] = light; - data[y][x][3] = 255; - } - } - detailtextures[i] = R_LoadTexture(detailtexturepool, va("detailtexture%i", i), DETAILRESOLUTION, DETAILRESOLUTION, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE); - } -} - -void Mod_BrushShutdown (void) -{ - int i; - for (i = 0;i < NUM_DETAILTEXTURES;i++) - R_FreeTexture(detailtextures[i]); - R_FreeTexturePool(&detailtexturepool); -} - /* =============== Mod_PointInLeaf @@ -143,20 +92,181 @@ int Mod_PointContents (const vec3_t p, model_t *model) return ((mleaf_t *)node)->contents; } -void Mod_FindNonSolidLocation(vec3_t pos, model_t *mod) +typedef struct findnonsolidlocationinfo_s { - if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; - pos[0]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; - pos[0]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; - pos[0]-=1; - pos[1]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; - pos[1]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; - pos[1]-=1; - pos[2]-=1;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; - pos[2]+=2;if (Mod_PointContents(pos, mod) != CONTENTS_SOLID) return; - pos[2]-=1; + 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->index + k * 3; + VectorCopy((mesh->verts + tri[0] * 4), vert[0]); + VectorCopy((mesh->verts + tri[1] * 4), vert[1]); + VectorCopy((mesh->verts + tri[2] * 4), 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); +} /* =================== @@ -211,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; @@ -230,15 +340,19 @@ static void Mod_LoadTextures (lump_t *l) // fill out all slots with notexture for (i = 0, tx = loadmodel->textures;i < loadmodel->numtextures;i++, tx++) { + 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_LIGHTBOTHSIDES; + 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) @@ -315,107 +429,53 @@ 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] == '*') { + // 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; + else + tx->flags |= SURF_WATERALPHA; tx->shader = &Cshader_water; } else if (tx->name[0] == 's' && tx->name[1] == 'k' && tx->name[2] == 'y') @@ -426,12 +486,13 @@ static void Mod_LoadTextures (lump_t *l) else { tx->flags |= SURF_LIGHTMAP; - if (!tx->fogtexture) + if (!tx->skin.fog) tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT; tx->shader = &Cshader_wall_lightmap; } - tx->detailtexture = detailtextures[i % NUM_DETAILTEXTURES]; + // start out with no animation + tx->currentframe = tx; } // sequence the animations @@ -566,7 +627,7 @@ static void Mod_LoadLighting (lump_t *l) i = LittleLong(((int *)data)[1]); if (i == 1) { - Con_DPrintf("%s loaded", litfilename); + Con_DPrintf("loaded %s\n", litfilename); loadmodel->lightdata = Mem_Alloc(loadmodel->mempool, loadsize - 8); memcpy(loadmodel->lightdata, data + 8, loadsize - 8); Mem_Free(data); @@ -664,533 +725,24 @@ void Mod_LoadLightList(void) } } - - /* -// svbspmesh_t is in model_brush.h - -typedef struct svbsppolygon_s -{ - struct svbsppolygon_s *next; - int numverts; - float *verts; - float normal[3], dist; -} -svbsppolygon_t; - -typedef struct svbspnode_s -{ - // true if this is a leaf (has no children), not a node - int isleaf; - // (shared) parent node - struct svbspnode_s *parent; - // (leaf) dark or lit leaf - int dark; - // (leaf) polygons bounding this leaf - svbsppolygon_t *polygons; - // (node) children - struct svbspnode_s *children[2]; - // (node) splitting plane - float normal[3], dist; -} -svbspnode_t; - -svbspnode_t *Mod_SVBSP_AllocNode(svbspnode_t *parent, svbspnode_t *child0, svbspnode_t *child1, float *normal, float dist) -{ - svbspnode_t *node; - node = Mem_Alloc(loadmodel->mempool, sizeof(svbspnode_t)); - node->parent = parent; - node->children[0] = child0; - node->children[1] = child1; - VectorCopy(normal, node->normal); - node->dist = dist; - return node; -} - -svbspnode_t *Mod_SVBSP_AllocLeaf(svbspnode_t *parent, int dark) -{ - svbspnode_t *leaf; - leaf = Mem_Alloc(loadmodel->mempool, sizeof(svbspnode_t)); - leaf->isleaf = true; - leaf->parent = parent; - leaf->dark = dark; - return leaf; -} - -svbspnode_t *Mod_SVBSP_NewTree(void) -{ - return Mod_SVBSP_AllocLeaf(NULL, false); -} - -void Mod_SVBSP_FreeTree(svbspnode_t *node) -{ - if (!node->isleaf) - { - Mod_SVBSP_FreeTree(node->children[0]); - Mod_SVBSP_FreeTree(node->children[1]); - } - Mem_Free(node); -} - -void Mod_SVBSP_RecursiveAddPolygon(svbspnode_t *node, int numverts, float *verts, float *normal, float dist, int constructmode) -{ - int i, j, numvertsfront, numvertsback, maxverts, counts[3]; - float *vertsfront, *vertsback, *v, d, temp[3]; - float dists[4096]; - qbyte sides[4096]; - svbsppolygon_t *poly; - if (node->isleaf) - { - if (constructmode == 0) - { - // construct tree structure - node->isleaf = false; - node->children[0] = Mod_SVBSP_AllocLeaf(node, false); - node->children[1] = Mod_SVBSP_AllocLeaf(node, false); - VectorCopy(normal, node->normal); - node->dist = dist; - } - else if (constructmode == 1) - { - // mark dark leafs - node->dark = true; - } - else - { - // link polygons into lit leafs only (this is the optimization) - if (!node->dark) - { - poly = Mem_Alloc(loadmodel->mempool, sizeof(svbsppolygon_t) + numverts * sizeof(float[3])); - poly->numverts = numverts; - poly->verts = (float *)(poly + 1); - VectorCopy(normal, poly->normal); - poly->dist = dist; - memcpy(poly->verts, verts, numverts * sizeof(float[3])); - poly->next = node->polygons; - node->polygons = poly; - } - } - } - else - { - counts[SIDE_FRONT] = counts[SIDE_BACK] = counts[SIDE_ON] = 0; - for (i = 0, v = verts;i < numverts;i++, v += 3) - { - dists[i] = DotProduct(v, node->normal) - node->dist; - if (dists[i] >= 0.1) - sides[i] = SIDE_FRONT; - else if (dists[i] <= -0.1) - sides[i] = SIDE_BACK; - else - sides[i] = SIDE_ON; - counts[sides[i]]++; - } - if (counts[SIDE_FRONT] && counts[SIDE_BACK]) - { - // some front, some back... sliced - numvertsfront = 0; - numvertsback = 0; - // this is excessive, but nice for safety... - maxverts = numverts + 4; - vertsfront = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); - vertsback = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); - for (i = 0, j = numverts - 1;i < numverts;j = i, i++) - { - if (sides[j] == SIDE_FRONT) - { - VectorCopy(&verts[j * 3], &vertsfront[numvertsfront * 3]); - numvertsfront++; - if (sides[i] == SIDE_BACK) - { - d = dists[j] / (dists[j] - dists[i]); - VectorSubtract(&verts[i * 3], &verts[j * 3], temp); - VectorMA(&verts[j * 3], d, temp, temp); - VectorCopy(temp, &vertsfront[numvertsfront * 3]); - VectorCopy(temp, &vertsback[numvertsback * 3]); - numvertsfront++; - numvertsback++; - } - } - else if (sides[j] == SIDE_BACK) - { - VectorCopy(&verts[j * 3], &vertsback[numvertsback * 3]); - numvertsback++; - if (sides[i] == SIDE_FRONT) - { - d = dists[j] / (dists[j] - dists[i]); - VectorSubtract(&verts[i * 3], &verts[j * 3], temp); - VectorMA(&verts[j * 3], d, temp, temp); - VectorCopy(temp, &vertsfront[numvertsfront * 3]); - VectorCopy(temp, &vertsback[numvertsback * 3]); - numvertsfront++; - numvertsback++; - } - } - else - { - VectorCopy(&verts[j * 3], &vertsfront[numvertsfront * 3]); - VectorCopy(&verts[j * 3], &vertsback[numvertsback * 3]); - numvertsfront++; - numvertsback++; - } - } - Mod_SVBSP_RecursiveAddPolygon(node->children[1], numvertsfront, vertsfront, normal, dist, constructmode); - Mod_SVBSP_RecursiveAddPolygon(node->children[0], numvertsback, vertsback, normal, dist, constructmode); - Mem_Free(vertsfront); - Mem_Free(vertsback); - } - else if (counts[SIDE_BACK]) - Mod_SVBSP_RecursiveAddPolygon(node->children[0], numverts, verts, normal, dist, constructmode); - else if (counts[SIDE_FRONT]) - Mod_SVBSP_RecursiveAddPolygon(node->children[1], numverts, verts, normal, dist, constructmode); - else - { - // mode 0 is constructing tree, don't make unnecessary splits - if (constructmode == 1) - { - // marking dark leafs - // send it down the side it is not facing - Mod_SVBSP_RecursiveAddPolygon(node->children[DotProduct(node->normal, normal) < 0], numverts, verts, normal, dist, constructmode); - } - else if (constructmode == 2) - { - // linking polygons into lit leafs only - // send it down the side it is facing - Mod_SVBSP_RecursiveAddPolygon(node->children[DotProduct(node->normal, normal) >= 0], numverts, verts, normal, dist, constructmode); - } - } - } -} - -int svbsp_count_nodes; -int svbsp_count_leafs; -int svbsp_count_polygons; -int svbsp_count_darkleafs; -int svbsp_count_originalpolygons; -int svbsp_count_meshs; -int svbsp_count_triangles; -int svbsp_count_vertices; - -void Mod_SVBSP_AddPolygon(svbspnode_t *root, int numverts, float *verts, int constructmode, float *test, int linenumber) -{ - int i; - float normal[3], dist, dir0[3], dir1[3], *v0, *v1, *v2; - svbsp_count_originalpolygons++; - for (i = 0, v0 = verts + (numverts - 2) * 3, v1 = verts + (numverts - 1) * 3, v2 = verts;i < numverts;i++, v0 = v1, v1 = v2, v2 += 3) - { - VectorSubtract(v0, v1, dir0); - VectorSubtract(v2, v1, dir1); - CrossProduct(dir0, dir1, normal); - if (DotProduct(normal, normal) >= 0.1) - break; - } - if (i == numverts) - return; - VectorNormalize(normal); - dist = DotProduct(verts, normal); - if (test && DotProduct(test, normal) > dist + 0.1) - Con_Printf("%i %f %f %f %f : %f %f %f %f\n", linenumber, normal[0], normal[1], normal[2], dist, test[0], test[1], test[2], DotProduct(test, normal)); - Mod_SVBSP_RecursiveAddPolygon(root, numverts, verts, normal, dist, constructmode); -} - -void Mod_SVBSP_RecursiveGatherStats(svbspnode_t *node) -{ - svbsppolygon_t *poly; - for (poly = node->polygons;poly;poly = poly->next) - svbsp_count_polygons++; - if (node->isleaf) - { - svbsp_count_leafs++; - if (node->dark) - svbsp_count_darkleafs++; - } - else - { - svbsp_count_nodes++; - Mod_SVBSP_RecursiveGatherStats(node->children[0]); - Mod_SVBSP_RecursiveGatherStats(node->children[1]); - } -} - -svbspmesh_t *Mod_SVBSP_AllocMesh(int maxverts) -{ - svbspmesh_t *mesh; - mesh = Mem_Alloc(loadmodel->mempool, sizeof(svbspmesh_t) + maxverts * sizeof(float[4]) + maxverts * sizeof(int[3])); - mesh->maxverts = maxverts; - mesh->maxtriangles = maxverts; - mesh->numverts = 0; - mesh->numtriangles = 0; - mesh->verts = (float *)(mesh + 1); - mesh->elements = (int *)(mesh->verts + mesh->maxverts * 4); - return mesh; -} - -svbspmesh_t *Mod_SVBSP_ReAllocMesh(svbspmesh_t *oldmesh) -{ - svbspmesh_t *newmesh; - newmesh = Mem_Alloc(loadmodel->mempool, sizeof(svbspmesh_t) + oldmesh->numverts * sizeof(float[4]) + oldmesh->numtriangles * sizeof(int[3])); - newmesh->maxverts = newmesh->numverts = oldmesh->numverts; - newmesh->maxtriangles = newmesh->numtriangles = oldmesh->numtriangles; - newmesh->verts = (float *)(newmesh + 1); - newmesh->elements = (int *)(newmesh->verts + newmesh->maxverts * 4); - memcpy(newmesh->verts, oldmesh->verts, newmesh->numverts * sizeof(float[4])); - memcpy(newmesh->elements, oldmesh->elements, newmesh->numtriangles * sizeof(int[3])); - return newmesh; -} - -void Mod_SVBSP_RecursiveBuildTriangleMeshs(svbspmesh_t *firstmesh, svbspnode_t *node) -{ - svbsppolygon_t *poly; - svbspmesh_t *mesh; - int i, j, k; - float *v, *m, temp[3]; - if (node->isleaf) - { - for (poly = node->polygons;poly;poly = poly->next) - { - mesh = firstmesh; - while (poly->numverts + mesh->numverts > mesh->maxverts || (poly->numverts - 2) + mesh->numtriangles > mesh->maxtriangles) - { - if (mesh->next == NULL) - mesh->next = Mod_SVBSP_AllocMesh(max(1000, poly->numverts)); - mesh = mesh->next; - } - for (i = 0, v = poly->verts;i < poly->numverts - 2;i++, v += 3) - { - for (k = 0;k < 3;k++) - { - if (k == 0) - v = poly->verts; - else if (k == 1) - v = poly->verts + (i + 1) * 3; - else if (k == 2) - v = poly->verts + (i + 2) * 3; - for (j = 0, m = mesh->verts;j < mesh->numverts;j++, m += 4) - { - VectorSubtract(v, m, temp); - if (DotProduct(temp, temp) < 0.1) - break; - } - if (j == mesh->numverts) - { - mesh->numverts++; - VectorCopy(v, m); - } - mesh->elements[mesh->numtriangles * 3 + k] = j; - } - mesh->numtriangles++; - } - } - } - else - { - Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, node->children[0]); - Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, node->children[1]); - } -} - -svbspmesh_t *Mod_SVBSP_BuildTriangleMeshs(svbspnode_t *root, vec3_t mins, vec3_t maxs) -{ - svbspmesh_t *firstmesh, *mesh, *newmesh, *nextmesh; - int i; - float *v; - firstmesh = Mod_SVBSP_AllocMesh(1000); - Mod_SVBSP_RecursiveBuildTriangleMeshs(firstmesh, root); - // reallocate meshs to conserve space - for (mesh = firstmesh, firstmesh = NULL;mesh;mesh = nextmesh) - { - svbsp_count_meshs++; - svbsp_count_triangles += mesh->numtriangles; - svbsp_count_vertices += mesh->numverts; - - // calculate bbox - if (firstmesh == NULL) - { - VectorCopy(mesh->verts, mins); - VectorCopy(mesh->verts, maxs); - } - for (i = 0, v = mesh->verts;i < mesh->numverts;i++, v += 4) - { - if (mins[0] > v[0]) mins[0] = v[0];if (maxs[0] < v[0]) maxs[0] = v[0]; - if (mins[1] > v[1]) mins[1] = v[1];if (maxs[1] < v[1]) maxs[1] = v[1]; - if (mins[2] > v[2]) mins[2] = v[2];if (maxs[2] < v[2]) maxs[2] = v[2]; - } - - nextmesh = mesh->next; - newmesh = Mod_SVBSP_ReAllocMesh(mesh); - newmesh->next = firstmesh; - firstmesh = newmesh; - Mem_Free(mesh); - } - return firstmesh; -} - -void Mod_SVBSP_FreeTriangleMeshs(svbspmesh_t *mesh) -{ - svbspmesh_t *nextmesh; - for (;mesh;mesh = nextmesh) - { - nextmesh = mesh->next; - Mem_Free(mesh); - } -} -*/ - -typedef struct svpolygon_s -{ - struct svpolygon_s *next; - int maxverts; - int numverts; - float *verts; - float normal[3], dist; -} -svpolygon_t; - -typedef struct svbrush_s -{ - struct svbrush_s *next; - svpolygon_t *polygons; - vec3_t mins, maxs; -} -svbrush_t; - -typedef struct svworld_s -{ - svbrush_t *brushs; -} -svworld_t; - -svworld_t *Mod_ShadowBrush_NewWorld(mempool_t *mempool) -{ - return Mem_Alloc(mempool, sizeof(svworld_t)); -} - -void Mod_ShadowBrush_FreeWorld(svworld_t *world) -{ - svbrush_t *brush, *brushnext; - svpolygon_t *poly, *polynext; - for (brush = world->brushs;brush;brush = brushnext) - { - brushnext = brush->next; - for (poly = brush->polygons;poly;poly = polynext) - { - polynext = poly->next; - Mem_Free(poly); - } - Mem_Free(brush); - } - Mem_Free(world); -} - -svbrush_t *Mod_ShadowBrush_BeginBrush(mempool_t *mempool) -{ - return Mem_Alloc(mempool, sizeof(svbrush_t)); -} - -void Mod_ShadowBrush_AddPolygon(mempool_t *mempool, svbrush_t *brush, int numverts, float *verts) -{ - int i; - float normal[3], dist, dir0[3], dir1[3], *v0, *v1, *v2; - svpolygon_t *poly; - for (i = 0, v0 = verts + (numverts - 2) * 3, v1 = verts + (numverts - 1) * 3, v2 = verts;i < numverts;i++, v0 = v1, v1 = v2, v2 += 3) - { - VectorSubtract(v0, v1, dir0); - VectorSubtract(v2, v1, dir1); - CrossProduct(dir0, dir1, normal); - if (DotProduct(normal, normal) >= 0.1) - break; - } - if (i == numverts) - return; - VectorNormalize(normal); - dist = DotProduct(verts, normal); - - poly = Mem_Alloc(mempool, sizeof(svpolygon_t) + numverts * sizeof(float[3])); - poly->numverts = numverts; - poly->verts = (float *)(poly + 1); - VectorCopy(normal, poly->normal); - poly->dist = dist; - poly->next = brush->polygons; - brush->polygons = poly; - memcpy(poly->verts, verts, numverts * sizeof(float[3])); -} - -void Mod_ShadowBrush_EndBrush(svworld_t *world, svbrush_t *brush) -{ - int i; - float *v; - svpolygon_t *poly; - if (!brush->polygons) - { - Mem_Free(brush); - return; - } - brush->next = world->brushs; - world->brushs = brush; - VectorCopy(brush->polygons->verts, brush->mins); - VectorCopy(brush->polygons->verts, brush->maxs); - for (poly = brush->polygons;poly;poly = poly->next) - { - for (i = 0, v = poly->verts;i < poly->numverts;i++, v += 3) - { - if (brush->mins[0] > v[0]) brush->mins[0] = v[0];if (brush->maxs[0] < v[0]) brush->maxs[0] = v[0]; - if (brush->mins[1] > v[1]) brush->mins[1] = v[1];if (brush->maxs[1] < v[1]) brush->maxs[1] = v[1]; - if (brush->mins[2] > v[2]) brush->mins[2] = v[2];if (brush->maxs[2] < v[2]) brush->maxs[2] = v[2]; - } - } -} - -void Mod_ShadowBrush_ProcessWorld(mempool_t *mempool, svworld_t *world) -{ - /* - for (clipbrush = world->brushs;clipbrush;clipbrush = clipbrush->next) - { - for (brush = world->brushs;brush;brush = brush->next) - { - if (brush != clipbrush - && brush->mins[0] <= clipbrush->maxs[0] - && brush->maxs[0] >= clipbrush->mins[0] - && brush->mins[1] <= clipbrush->maxs[1] - && brush->maxs[1] >= clipbrush->mins[1] - && brush->mins[2] <= clipbrush->maxs[2] - && brush->maxs[2] >= clipbrush->mins[2]) - continue; - for (poly = brush->polygons;poly;poly = poly->next) - { - - } - } - } - */ -} - -shadowmesh_t *Mod_ShadowBrush_BuildMeshs(mempool_t *mempool, svworld_t *world) -{ - shadowmesh_t *mesh; - svbrush_t *brush; - svpolygon_t *poly; - mesh = Mod_ShadowMesh_Begin(mempool); - for (brush = world->brushs;brush;brush = brush->next) - for (poly = brush->polygons;poly;poly = poly->next) - Mod_ShadowMesh_AddPolygon(mempool, mesh, poly->numverts, poly->verts); - mesh = Mod_ShadowMesh_Finish(mempool, mesh); - return mesh; -} - +static int castshadowcount = 0; void Mod_ProcessLightList(void) { - int j, k, *mark, lnum; + 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);// + 4096.0f; + 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 = sqrt(e->cullradius2); + e->cullradius = e->lightradius = sqrt(e->cullradius2); leaf = Mod_PointInLeaf(e->origin, loadmodel); if (leaf->compressed_vis) pvs = Mod_DecompressVis (leaf->compressed_vis, loadmodel); @@ -1211,7 +763,13 @@ void Mod_ProcessLightList(void) if (surf->flags & SURF_PLANEBACK) dist = -dist; if (dist > 0 && dist < e->cullradius) - loadmodel->surfacevisframes[*mark] = -2; + { + 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; + } } } } @@ -1229,10 +787,8 @@ void Mod_ProcessLightList(void) 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) - float *v, temp[3], radius2; radius2 = 0; for (j = 0;j < e->numsurfaces;j++) { @@ -1253,25 +809,29 @@ void Mod_ProcessLightList(void) radius2 = dist; } } - /* if (e->cullradius2 > radius2) { e->cullradius2 = radius2; e->cullradius = sqrt(e->cullradius2); } - */ - } -#if 1 + 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 temp, outermins, outermaxs, innermins, innermaxs; + //vec3_t polymins, polymaxs; int maxverts = 4; float *verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); float f, *v0, *v1, projectdistance; - svworld_t *svworld; - svbrush_t *svbrush; + 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; @@ -1284,295 +844,116 @@ void Mod_ProcessLightList(void) outermaxs[0] = loadmodel->normalmaxs[0] + 1; outermaxs[1] = loadmodel->normalmaxs[1] + 1; outermaxs[2] = loadmodel->normalmaxs[2] + 1; - svworld = Mod_ShadowBrush_NewWorld(loadmodel->mempool); - for (j = 0, surf = loadmodel->surfaces + loadmodel->firstmodelsurface;j < loadmodel->nummodelsurfaces;j++, surf++) - { - if (!(surf->flags & SURF_SHADOWCAST)) - continue; - f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; - if (surf->flags & SURF_PLANEBACK) - f = -f; - projectdistance = e->cullradius + f; - if (projectdistance < 0.1 || projectdistance > e->cullradius) - continue; - VectorSubtract(e->origin, surf->poly_center, temp); - if (DotProduct(temp, temp) > (surf->poly_radius2 + e->cullradius2)) - continue; - if (maxverts < surf->poly_numverts) - { - maxverts = surf->poly_numverts; - if (verts) - Mem_Free(verts); - verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); - } - svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); - // copy the original polygon, reversed, for the front 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) - VectorCopy(v0, v1); - Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, surf->poly_numverts, verts); - // project the original polygon, for the back cap of the volume - for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3) - { - VectorSubtract(v0, e->origin, temp); - VectorNormalize(temp); - VectorMA(v0, projectdistance, temp, v1); - } - Mod_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, surf->poly_numverts, verts); - // project the shadow volume sides - for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;k++, v0 = v1, v1 += 3) - { - VectorCopy(v0, &verts[0]); - VectorCopy(v1, &verts[3]); - VectorCopy(v1, &verts[6]); - VectorCopy(v0, &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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); - } - Mod_ShadowBrush_EndBrush(svworld, svbrush); - } // 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 - svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); - Mod_ShadowBrush_EndBrush(svworld, svbrush); + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); // X minor - svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); - Mod_ShadowBrush_EndBrush(svworld, svbrush); + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); // Y major - svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); - Mod_ShadowBrush_EndBrush(svworld, svbrush); + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); // Y minor - svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); - Mod_ShadowBrush_EndBrush(svworld, svbrush); + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); // Z major - svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); - Mod_ShadowBrush_EndBrush(svworld, svbrush); + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); // Z minor - svbrush = Mod_ShadowBrush_BeginBrush(loadmodel->mempool); 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); - Mod_ShadowBrush_EndBrush(svworld, svbrush); - // clip away hidden polygons - Mod_ShadowBrush_ProcessWorld(loadmodel->mempool, svworld); - // build the triangle mesh - e->shadowvolume = Mod_ShadowBrush_BuildMeshs(loadmodel->mempool, svworld); - Mod_ShadowBrush_FreeWorld(svworld); - } -#elif 0 - // build svbsp (shadow volume bsp) - { - int maxverts = 0, constructmode; - float *verts = NULL, projectdistance, *v0, *v1, f, temp[3]; - svbspnode_t *svbsproot; - svbsproot = Mod_SVBSP_NewTree(); - // we do this in three stages: - // 1. construct the svbsp structure - // 2. mark which leafs are dark (shadow) - // 3. link polygons into only leafs that are not dark - // this results in polygons that are only on the outside of the - // shadow volume, removing polygons that are inside the shadow - // volume (which waste time) - for (constructmode = 0;constructmode < 3;constructmode++) + 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++) { - svbsp_count_originalpolygons = 0; -#if 1 - for (j = 0, surf = loadmodel->surfaces + loadmodel->firstmodelsurface;j < loadmodel->nummodelsurfaces;j++, surf++) + 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) { - if (!(surf->flags & SURF_SHADOWCAST)) - continue; - /* - if (surf->poly_maxs[0] < e->mins[0] - || surf->poly_mins[0] > e->maxs[0] - || surf->poly_maxs[1] < e->mins[1] - || surf->poly_mins[1] > e->maxs[1] - || surf->poly_maxs[2] < e->mins[2] - || surf->poly_mins[2] > e->maxs[2]) - continue; - */ - f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; - if (surf->flags & SURF_PLANEBACK) - f = -f; - projectdistance = e->cullradius + f; - if (projectdistance < 0.1 || projectdistance > e->cullradius) - continue; - /* - // find the nearest vertex of the projected volume - for (k = 0, v0 = surf->poly_verts;k < surf->poly_numverts;k++, v0 += 3) - { - VectorSubtract(v0, e->origin, temp); - VectorNormalize(temp); - if (maxdist00 > v0[0] - e->origin[0]) maxdist00 = v0[0] - e->origin[0]; - if (maxdist01 < e->origin[0] - v0[0]) maxdist01 = e->origin[0] - v0[0]; - if (maxdist10 > v0[1] - e->origin[1]) maxdist10 = v0[1] - e->origin[1]; - if (maxdist11 < e->origin[1] - v0[1]) maxdist11 = e->origin[1] - v0[1]; - if (maxdist20 > v0[2] - e->origin[2]) maxdist20 = v0[2] - e->origin[2]; - if (maxdist21 < e->origin[2] - v0[2]) maxdist21 = e->origin[2] - v0[2]; - dist = - - dist = DotProduct(temp, temp); - if (bestdist > dist) - { - bestdist = dist; - VectorCopy(temp, bestvec); - } - } - projectdistance = e->cullradius - sqrt(bestdist); - if (projectdistance < 0.1) - continue; - for (k = 0, v0 = surf->poly_verts;k < surf->poly_numverts;k++, v0 += 3) - { - VectorNormalize(temp); - if (temp[0] > 0) - { - dist = (e->maxs[0] - e->origin[0]) / temp[0]; - if (maxdist > - } - else if (temp[0] < 0) - dist = (e->mins[0] - e->origin[0]) / temp[0]; - dist = - VectorMA(v0, projectdistance, temp, temp); - dist = (temp[0] - VectorSubtract(temp, e->origin, - } - */ - VectorSubtract(e->origin, surf->poly_center, temp); - if (DotProduct(temp, temp) > (surf->poly_radius2 + e->cullradius2)) - continue; - 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, reversed, for the front 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) - VectorCopy(v0, v1); - Mod_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__); - // project the original polygon, for the back cap of the volume - for (k = 0, v0 = surf->poly_verts, v1 = verts;k < surf->poly_numverts;k++, v0 += 3, v1 += 3) - { - VectorSubtract(v0, e->origin, temp); - VectorNormalize(temp); - VectorMA(v0, projectdistance, temp, v1); - } - Mod_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__); - // project the shadow volume sides - for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;k++, v0 = v1, v1 += 3) - { - VectorCopy(v0, &verts[0]); - VectorCopy(v1, &verts[3]); - VectorCopy(v1, &verts[6]); - VectorCopy(v0, &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_SVBSP_AddPolygon(svbsproot, 4, verts, constructmode, surf->poly_center, __LINE__); - } + maxverts = surf->poly_numverts; + if (verts) + Mem_Free(verts); + verts = Mem_Alloc(loadmodel->mempool, maxverts * sizeof(float[3])); } -#else - for (j = 0;j < e->numsurfaces;j++) + // 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) { - surf = e->surfaces[j]; - if (!(surf->flags & SURF_SHADOWCAST)) - continue; - f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; - if (surf->flags & SURF_PLANEBACK) - f = -f; - projectdistance = e->cullradius - f; - if (projectdistance < 0.1 || projectdistance > e->cullradius) - continue; - VectorSubtract(e->origin, surf->poly_center, temp); - if (DotProduct(temp, temp) > (surf->poly_radius2 + e->cullradius2)) - continue; - 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_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__); - // 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_SVBSP_AddPolygon(svbsproot, surf->poly_numverts, verts, constructmode, surf->poly_center, __LINE__); - // project the shadow volume sides - for (k = 0, v0 = surf->poly_verts + (surf->poly_numverts - 1) * 3, v1 = surf->poly_verts;k < surf->poly_numverts;k++, v0 = v1, 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]); @@ -1584,29 +965,23 @@ void Mod_ProcessLightList(void) VectorSubtract(&verts[9], e->origin, temp); VectorNormalize(temp); VectorMA(&verts[9], projectdistance, temp, &verts[9]); - Mod_SVBSP_AddPolygon(svbsproot, 4, verts, constructmode, surf->poly_center, __LINE__); + Mod_ShadowMesh_AddPolygon(loadmodel->mempool, e->shadowvolume, 4, verts); } } -#endif } - if (verts) - Mem_Free(verts); - - svbsp_count_nodes = 0; - svbsp_count_leafs = 0; - svbsp_count_polygons = 0; - svbsp_count_darkleafs = 0; - svbsp_count_meshs = 0; - svbsp_count_triangles = 0; - svbsp_count_vertices = 0; - e->shadowvolume = Mod_SVBSP_BuildTriangleMeshs(svbsproot, e->shadowvolumemins, e->shadowvolumemaxs); - Mod_SVBSP_RecursiveGatherStats(svbsproot); - Mod_SVBSP_FreeTree(svbsproot); - Con_Printf("light %d (radius %d) has %d surfaces, svbsp contains %d nodes, %d leafs, %d are dark (%d%%), %d original polygons, %d polygons stored (%d%%), %d meshs %d vertices %d triangles\n", lnum, (int)e->cullradius, e->numsurfaces, svbsp_count_nodes, svbsp_count_leafs, svbsp_count_darkleafs, svbsp_count_leafs ? (100 * svbsp_count_darkleafs / svbsp_count_leafs) : 0, svbsp_count_originalpolygons, svbsp_count_polygons, svbsp_count_originalpolygons ? (100 * svbsp_count_polygons / svbsp_count_originalpolygons) : 0, svbsp_count_meshs, svbsp_count_triangles, svbsp_count_vertices); + // 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); + } } -#endif } } +*/ /* @@ -1845,58 +1220,6 @@ static void Mod_LoadTexinfo (lump_t *l) } } -/* -================ -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; - } - } - - 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; @@ -2055,6 +1378,25 @@ void Mod_GenerateWarpMesh (msurface_t *surf) } #endif +surfmesh_t *Mod_AllocSurfMesh(int numverts, int numtriangles) +{ + surfmesh_t *mesh; + mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + numtriangles * sizeof(int[6]) + numverts * (4 + 4 + 4 + 4 + 4 + 4 + 4 + 1) * sizeof(float)); + mesh->numverts = numverts; + mesh->numtriangles = numtriangles; + mesh->verts = (float *)(mesh + 1); + mesh->str = mesh->verts + mesh->numverts * 4; + mesh->uvw = mesh->str + mesh->numverts * 4; + mesh->abc = mesh->uvw + mesh->numverts * 4; + mesh->svectors = (float *)(mesh->abc + mesh->numverts * 4); + mesh->tvectors = mesh->svectors + mesh->numverts * 4; + mesh->normals = mesh->tvectors + mesh->numverts * 4; + mesh->lightmapoffsets = (int *)(mesh->normals + mesh->numverts * 4); + mesh->index = mesh->lightmapoffsets + mesh->numverts; + mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3; + return mesh; +} + void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) { int i, iu, iv, *index, smax, tmax; @@ -2079,29 +1421,19 @@ void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) if (r_miplightmaps.integer) { 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->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_LoadTexture(loadmodel->texturepool, NULL, surf->lightmaptexturestride, (surf->extents[1]>>4)+1, NULL, loadmodel->lightmaprgba ? TEXTYPE_RGBA : TEXTYPE_RGB, TEXF_FRAGMENT | TEXF_PRECACHE); + 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); } - surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[6]) + surf->poly_numverts * (4 + 4 + 4 + 4 + 1 + 3) * sizeof(float)); - mesh->numverts = surf->poly_numverts; - mesh->numtriangles = surf->poly_numverts - 2; - mesh->verts = (float *)(mesh + 1); - mesh->str = mesh->verts + mesh->numverts * 4; - mesh->uvw = mesh->str + mesh->numverts * 4; - mesh->abc = mesh->uvw + mesh->numverts * 4; - mesh->lightmapoffsets = (int *)(mesh->abc + mesh->numverts * 4); - mesh->index = mesh->lightmapoffsets + mesh->numverts; - mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3; - mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3); + surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2); index = mesh->index; for (i = 0;i < mesh->numtriangles;i++) @@ -2139,10 +1471,8 @@ void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f); mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f); mesh->lightmapoffsets[i] = ((iv * (smax+1) + iu) * 3); - mesh->normals[i * 3 + 0] = normal[0]; - mesh->normals[i * 3 + 1] = normal[1]; - mesh->normals[i * 3 + 2] = normal[2]; } + Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals); } void Mod_GenerateVertexMesh (msurface_t *surf) @@ -2154,15 +1484,7 @@ void Mod_GenerateVertexMesh (msurface_t *surf) surf->lightmaptexturestride = 0; surf->lightmaptexture = NULL; - surf->mesh = mesh = Mem_Alloc(loadmodel->mempool, sizeof(surfmesh_t) + (surf->poly_numverts - 2) * sizeof(int[6]) + surf->poly_numverts * (4 + 4 + 4 + 3) * sizeof(float)); - mesh->numverts = surf->poly_numverts; - mesh->numtriangles = surf->poly_numverts - 2; - mesh->verts = (float *)(mesh + 1); - mesh->str = mesh->verts + mesh->numverts * 4; - mesh->abc = mesh->str + mesh->numverts * 4; - mesh->index = (int *)(mesh->abc + mesh->numverts * 4); - mesh->triangleneighbors = mesh->index + mesh->numtriangles * 3; - mesh->normals = (float *)(mesh->triangleneighbors + mesh->numtriangles * 3); + surf->mesh = mesh = Mod_AllocSurfMesh(surf->poly_numverts, surf->poly_numverts - 2); index = mesh->index; for (i = 0;i < mesh->numtriangles;i++) @@ -2185,25 +1507,26 @@ void Mod_GenerateVertexMesh (msurface_t *surf) mesh->verts[i * 4 + 2] = in[2]; mesh->str[i * 4 + 0] = s / surf->texinfo->texture->width; mesh->str[i * 4 + 1] = t / surf->texinfo->texture->height; + mesh->uvw[i * 4 + 0] = 0; + mesh->uvw[i * 4 + 1] = 0; mesh->abc[i * 4 + 0] = s * (1.0f / 16.0f); mesh->abc[i * 4 + 1] = t * (1.0f / 16.0f); - mesh->normals[i * 3 + 0] = normal[0]; - mesh->normals[i * 3 + 1] = normal[1]; - mesh->normals[i * 3 + 2] = normal[2]; } + Mod_BuildTextureVectorsAndNormals(mesh->numverts, mesh->numtriangles, mesh->verts, mesh->str, mesh->index, mesh->svectors, mesh->tvectors, mesh->normals); } -void Mod_GenerateSurfacePolygon (msurface_t *surf) +void Mod_GenerateSurfacePolygon (msurface_t *surf, int firstedge, int numedges) { - int i, lindex; - float *vec, *vert, mins[3], maxs[3], temp[3], dist; + 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 @@ -2211,33 +1534,44 @@ void Mod_GenerateSurfacePolygon (msurface_t *surf) VectorCopy (vec, vert); vert += 3; } + + // 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++) + 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]; - vert += 3; } 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; - surf->poly_radius2 = 0; - vert = surf->poly_verts; - for (i = 0;i < surf->poly_numverts;i++) + + // 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) { - VectorSubtract(vert, surf->poly_center, temp); - dist = DotProduct(temp, temp); - if (surf->poly_radius2 < dist) - surf->poly_radius2 = dist; - vert += 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; + } + } + 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]; } - surf->poly_radius = sqrt(surf->poly_radius2); } /* @@ -2249,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)) @@ -2261,15 +1595,16 @@ static void Mod_LoadFaces (lump_t *l) 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) @@ -2292,7 +1627,7 @@ static void Mod_LoadFaces (lump_t *l) // force lightmap upload on first time seeing the surface out->cached_dlight = true; - CalcSurfaceExtents (out); + Mod_GenerateSurfacePolygon(out, firstedge, numedges); ssize = (out->extents[0] >> 4) + 1; tsize = (out->extents[1] >> 4) + 1; @@ -2308,7 +1643,6 @@ 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->shader == &Cshader_wall_lightmap) { if ((out->extents[0] >> 4) + 1 > (256) || (out->extents[1] >> 4) + 1 > (256)) @@ -3227,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; } } @@ -3309,6 +2643,141 @@ 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 @@ -3316,19 +2785,19 @@ 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_DrawFakeShadow(entity_render_t *ent); -extern void R_Model_Brush_DrawDepth(entity_render_t *ent); -extern void R_Model_Brush_DrawShadowVolume(entity_render_t *ent, vec3_t relativelightorigin, float lightradius, int visiblevolume); -extern void R_Model_Brush_DrawLight(entity_render_t *ent, vec3_t relativelightorigin, float lightradius2, float lightdistbias, float lightsubtract, float *lightcolor); -extern void R_Model_Brush_DrawOntoLight(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; - model_t *originalloadmodel; + 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; @@ -3348,7 +2817,7 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) // swap all the lumps mod_base = (qbyte *)header; - for (i=0 ; inumsubmodels;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]; @@ -3413,37 +2873,46 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) mod->DrawSky = NULL; mod->Draw = R_Model_Brush_Draw; mod->DrawFakeShadow = NULL; - mod->DrawDepth = R_Model_Brush_DrawDepth; mod->DrawShadowVolume = R_Model_Brush_DrawShadowVolume; mod->DrawLight = R_Model_Brush_DrawLight; - mod->DrawOntoLight = R_Model_Brush_DrawOntoLight; + 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) { // 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++) { // 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; - for (k = 0;k < surf->numedges;k++) + // 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) { - 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; + for (k = 0, vec = mesh->verts;k < mesh->numverts;k++, vec += 4) + { + 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); @@ -3455,29 +2924,13 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) mod->rotatedmaxs[0] = mod->rotatedmaxs[1] = mod->rotatedmaxs[2] = modelradius; mod->radius = modelradius; mod->radius2 = modelradius * modelradius; - // LordHavoc: build triangle meshs for entire model's geometry - // (only used for shadow volumes) - mod->shadowmesh = Mod_ShadowMesh_Begin(originalloadmodel->mempool); - for (j = 0, surf = &mod->surfaces[mod->firstmodelsurface];j < mod->nummodelsurfaces;j++, surf++) - if (surf->flags & SURF_SHADOWCAST) - Mod_ShadowMesh_AddPolygon(originalloadmodel->mempool, mod->shadowmesh, surf->poly_numverts, surf->poly_verts); - mod->shadowmesh = Mod_ShadowMesh_Finish(originalloadmodel->mempool, mod->shadowmesh); - Mod_ShadowMesh_CalcBBox(mod->shadowmesh, mod->shadowmesh_mins, mod->shadowmesh_maxs, mod->shadowmesh_center, &mod->shadowmesh_radius); } 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->radius = 0; - mod->radius2 = 0; - mod->shadowmesh = NULL; } + Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool); mod->numleafs = bm->visleafs; @@ -3499,6 +2952,6 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) } loadmodel = originalloadmodel; - Mod_ProcessLightList (); + //Mod_ProcessLightList (); }