X-Git-Url: http://de.git.xonotic.org/?p=xonotic%2Fdarkplaces.git;a=blobdiff_plain;f=model_brush.c;h=4959d8c32887cb48585abe14b9c9e5a6625e5177;hp=28347fc6b84307829a686c88169238d8a354afa4;hb=621aa311fc1ba61437e1d91229782dc3e81d70c0;hpb=6d6bb0a8d9e2cb7ad6e156584304b4fd621eac3e diff --git a/model_brush.c b/model_brush.c index 28347fc6..4959d8c3 100644 --- a/model_brush.c +++ b/model_brush.c @@ -19,6 +19,7 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #include "quakedef.h" +#include "image.h" // note: model_shared.c sets up r_notexture, and r_surf_notexture @@ -90,7 +91,7 @@ void Mod_BrushStartup (void) 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); + detailtextures[i] = R_LoadTexture2D(detailtexturepool, va("detailtexture%i", i), DETAILRESOLUTION, DETAILRESOLUTION, &data[0][0][0], TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_PRECACHE, NULL); } } @@ -211,8 +212,13 @@ 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]; + qbyte *basepixels, *bumppixels, *nmappixels, *glosspixels, *glowpixels, *maskpixels; + int basepixels_width, basepixels_height, bumppixels_width, bumppixels_height; + int nmappixels_width, nmappixels_height, glosspixels_width, glosspixels_height; + int glowpixels_width, glowpixels_height, maskpixels_width, maskpixels_height; + rtexture_t *detailtexture; loadmodel->textures = NULL; @@ -230,6 +236,7 @@ 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; tx->width = 16; tx->height = 16; tx->texture = r_notexture; @@ -239,6 +246,7 @@ static void Mod_LoadTextures (lump_t *l) 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) @@ -290,6 +298,14 @@ static void Mod_LoadTextures (lump_t *l) Con_Printf("warning: unnamed texture in %s, renaming to %s\n", loadmodel->name, tx->name); } + basepixels = NULL;basepixels_width = 0;basepixels_height = 0; + bumppixels = NULL;bumppixels_width = 0;bumppixels_height = 0; + nmappixels = NULL;nmappixels_width = 0;nmappixels_height = 0; + glosspixels = NULL;glosspixels_width = 0;glosspixels_height = 0; + glowpixels = NULL;glowpixels_width = 0;glowpixels_height = 0; + maskpixels = NULL;maskpixels_width = 0;maskpixels_height = 0; + detailtexture = NULL; + // LordHavoc: HL sky textures are entirely different than quake if (!loadmodel->ishlbsp && !strncmp(tx->name, "sky", 3) && mtwidth == 256 && mtheight == 128) { @@ -315,99 +331,162 @@ 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 ((basepixels = loadimagepixels(tx->name, false, 0, 0)) != NULL) { - if (mtdata && (data = W_ConvertWAD3Texture(dmiptex))) + basepixels_width = image_width; + basepixels_height = image_height; + } + // _luma is supported for tenebrae compatibility + // (I think it's a very stupid name, but oh well) + if ((glowpixels = loadimagepixels(va("%s_glow", tx->name), false, 0, 0)) != NULL + || (glowpixels = loadimagepixels(va("%s_luma", tx->name), false, 0, 0)) != NULL) + { + glowpixels_width = image_width; + glowpixels_height = image_height; + } + if ((bumppixels = loadimagepixels(va("%s_bump", tx->name), false, 0, 0)) != NULL) + { + bumppixels_width = image_width; + bumppixels_height = image_height; + } + if ((glosspixels = loadimagepixels(va("%s_gloss", tx->name), false, 0, 0)) != NULL) + { + glosspixels_width = image_width; + glosspixels_height = image_height; + } + if (!basepixels) + { + if (loadmodel->ishlbsp) { - // 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)) + // internal texture overrides wad + if (mtdata && (basepixels = W_ConvertWAD3Texture(dmiptex)) != 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); + basepixels_width = image_width; + basepixels_height = image_height; } - Mem_Free(data); - } - else if ((data = W_GetTexture(tx->name))) - { - // 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)) + else if ((basepixels = W_GetTexture(tx->name)) != 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); + // get the size from the wad texture + tx->width = basepixels_width = image_width; + tx->height = basepixels_height = image_height; } - 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] != '*') + if (mtdata) // texture included { - for (j = 0;j < tx->width*tx->height;j++) + if (r_fullbrights.integer && tx->name[0] != '*') { - if (data[j] >= 224) // fullbright + basepixels_width = tx->width; + basepixels_height = tx->height; + basepixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4); + Image_Copy8bitRGBA(mtdata, basepixels, basepixels_width * basepixels_height, palette_nofullbrights); + if (!glowpixels) { - fullbrights = true; - break; + for (j = 0;j < (int)(tx->width*tx->height);j++) + if (((qbyte *)&palette_onlyfullbrights[mtdata[j]])[3] > 0) // fullbright + break; + if (j < (int)(tx->width * tx->height)) + { + glowpixels_width = tx->width; + glowpixels_height = tx->height; + glowpixels = Mem_Alloc(loadmodel->mempool, glowpixels_width * glowpixels_height * 4); + Image_Copy8bitRGBA(mtdata, glowpixels, glowpixels_width * glowpixels_height, palette_onlyfullbrights); + } } } + else + { + basepixels_width = tx->width; + basepixels_height = tx->height; + basepixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4); + Image_Copy8bitRGBA(mtdata, basepixels, tx->width * tx->height, palette_complete); + } } - 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 + } + } + + if (basepixels) + { + for (j = 3;j < basepixels_width * basepixels_height * 4;j += 4) + if (basepixels[j] < 255) + break; + if (j < basepixels_width * basepixels_height * 4) + { + maskpixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4); + maskpixels_width = basepixels_width; + maskpixels_height = basepixels_height; + for (j = 0;j < basepixels_width * basepixels_height * 4;j += 4) { - tx->width = 16; - tx->height = 16; - tx->texture = r_notexture; + maskpixels[j+0] = 255; + maskpixels[j+1] = 255; + maskpixels[j+2] = 255; + maskpixels[j+3] = basepixels[j+3]; } } + + if (!bumppixels) + { + bumppixels = Mem_Alloc(loadmodel->mempool, basepixels_width * basepixels_height * 4); + bumppixels_width = basepixels_width; + bumppixels_height = basepixels_height; + memcpy(bumppixels, basepixels, bumppixels_width * bumppixels_height * 4); + } + + if (!nmappixels && bumppixels) + { + nmappixels = Mem_Alloc(loadmodel->mempool, bumppixels_width * bumppixels_height * 4); + nmappixels_width = bumppixels_width; + nmappixels_height = bumppixels_height; + Image_HeightmapToNormalmap(bumppixels, nmappixels, nmappixels_width, nmappixels_height, false, 1); + } + } + + if (!detailtexture) + detailtexture = detailtextures[i % NUM_DETAILTEXTURES]; + + if (basepixels) + { + tx->texture = R_LoadTexture2D (loadmodel->texturepool, tx->name, basepixels_width, basepixels_height, basepixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL); + if (nmappixels) + tx->nmaptexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_nmap", tx->name), basepixels_width, basepixels_height, nmappixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL); + if (glosspixels) + tx->glosstexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_gloss", tx->name), glosspixels_width, glosspixels_height, glosspixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL); + if (glowpixels) + tx->glowtexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_glow", tx->name), glowpixels_width, glowpixels_height, glowpixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL); + if (maskpixels) + tx->fogtexture = R_LoadTexture2D (loadmodel->texturepool, va("%s_mask", tx->name), maskpixels_width, maskpixels_height, maskpixels, TEXTYPE_RGBA, TEXF_MIPMAP | TEXF_ALPHA | TEXF_PRECACHE, NULL); + tx->detailtexture = detailtexture; + } + else + { + // no texture found + tx->width = 16; + tx->height = 16; + tx->texture = r_notexture; + tx->nmaptexture = NULL; + tx->glosstexture = NULL; + tx->glowtexture = NULL; + tx->fogtexture = NULL; + tx->detailtexture = NULL; } + if (basepixels) + Mem_Free(basepixels); + if (bumppixels) + Mem_Free(bumppixels); + if (nmappixels) + Mem_Free(nmappixels); + if (glosspixels) + Mem_Free(glosspixels); + if (glowpixels) + Mem_Free(glowpixels); + if (maskpixels) + Mem_Free(maskpixels); + if (tx->name[0] == '*') { tx->flags |= SURF_DRAWTURB | SURF_LIGHTBOTHSIDES; @@ -416,6 +495,8 @@ static void Mod_LoadTextures (lump_t *l) || !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,10 +507,13 @@ static void Mod_LoadTextures (lump_t *l) else { tx->flags |= SURF_LIGHTMAP; + if (!tx->fogtexture) + 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 @@ -662,62 +746,263 @@ void Mod_LoadLightList(void) } } +/* +static int castshadowcount = 0; void Mod_ProcessLightList(void) { - int i, j, k, *mark; + int j, k, l, *mark, lnum; mlight_t *e; msurface_t *surf; float dist; - mleaf_t *l; + mleaf_t *leaf; qbyte *pvs; - for (i = 0, e = loadmodel->lights;i < loadmodel->numlights;i++, e++) + vec3_t temp; + float *v, radius2; + for (lnum = 0, e = loadmodel->lights;lnum < loadmodel->numlights;lnum++, e++) { - e->cullradius2 = DotProduct(e->light, e->light) * (1.0f / (8192.0f * 8192.0f)) / (e->falloff * e->falloff) + 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); - l = Mod_PointInLeaf(e->origin, loadmodel); - if (l->compressed_vis) - pvs = Mod_DecompressVis (l->compressed_vis, loadmodel); + 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, l = loadmodel->leafs + 1;j < loadmodel->numleafs - 1;j++) + 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 = l->firstmarksurface;k < l->nummarksurfaces;k++, mark++) + 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) - loadmodel->surfacevisframes[j] = i - 1000000; + { + 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->nummodelsurfaces;j++) - if (loadmodel->surfacevisframes[j] == i - 1000000) + 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->nummodelsurfaces;j++) - if (loadmodel->surfacevisframes[j] == i - 1000000) - e->surfaces[e->numsurfaces++] = loadmodel->surfaces + loadmodel->firstmodelsurface + j; + 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); + } } } - // construct shadow volumes for each light - /* - for (i = 0, e = loadmodel->lights;i < loadmodel->numlights;i++, e++) - { - FIXME FINISH THIS CODE! - } - */ } +*/ /* @@ -956,58 +1241,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; @@ -1166,9 +1399,28 @@ 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, *n, smax, tmax; + int i, iu, iv, *index, smax, tmax; float *in, s, t, u, v, ubase, vbase, uscale, vscale, normal[3]; surfmesh_t *mesh; @@ -1190,41 +1442,28 @@ 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_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_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 + 2 + 2 + 2 + 1 + 3) * sizeof(float)); - mesh->numverts = surf->poly_numverts; - mesh->numtriangles = surf->poly_numverts - 2; - mesh->verts = (float *)(mesh + 1); - mesh->st = mesh->verts + mesh->numverts * 4; - mesh->uv = mesh->st + mesh->numverts * 2; - mesh->ab = mesh->uv + mesh->numverts * 2; - mesh->lightmapoffsets = (int *)(mesh->ab + mesh->numverts * 2); - 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; - n = mesh->triangleneighbors; for (i = 0;i < mesh->numtriangles;i++) { *index++ = 0; *index++ = i + 1; *index++ = i + 2; - *n++ = i - 1; - *n++ = -1; - *n++ = i + 1; } + Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles); VectorCopy(surf->plane->normal, normal); if (surf->flags & SURF_PLANEBACK) @@ -1246,49 +1485,36 @@ void Mod_GenerateWallMesh (msurface_t *surf, int vertexonly) mesh->verts[i * 4 + 0] = in[0]; mesh->verts[i * 4 + 1] = in[1]; mesh->verts[i * 4 + 2] = in[2]; - mesh->st[i * 2 + 0] = s / surf->texinfo->texture->width; - mesh->st[i * 2 + 1] = t / surf->texinfo->texture->height; - mesh->uv[i * 2 + 0] = u; - mesh->uv[i * 2 + 1] = v; - mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f); - mesh->ab[i * 2 + 1] = t * (1.0f / 16.0f); + 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] = u; + mesh->uvw[i * 4 + 1] = v; + 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) { - int i, *index, *n; + 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[6]) + surf->poly_numverts * (4 + 2 + 2 + 3) * sizeof(float)); - mesh->numverts = surf->poly_numverts; - mesh->numtriangles = surf->poly_numverts - 2; - mesh->verts = (float *)(mesh + 1); - mesh->st = mesh->verts + mesh->numverts * 4; - mesh->ab = mesh->st + mesh->numverts * 2; - mesh->index = (int *)(mesh->ab + mesh->numverts * 2); - 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; - n = mesh->triangleneighbors; for (i = 0;i < mesh->numtriangles;i++) { *index++ = 0; *index++ = i + 1; *index++ = i + 2; - *n++ = -1; - *n++ = -1; - *n++ = i + 1; } + Mod_BuildTriangleNeighbors(mesh->triangleneighbors, mesh->index, mesh->numtriangles); VectorCopy(surf->plane->normal, normal); if (surf->flags & SURF_PLANEBACK) @@ -1300,27 +1526,28 @@ void Mod_GenerateVertexMesh (msurface_t *surf) mesh->verts[i * 4 + 0] = in[0]; mesh->verts[i * 4 + 1] = in[1]; mesh->verts[i * 4 + 2] = in[2]; - mesh->st[i * 2 + 0] = s / surf->texinfo->texture->width; - mesh->st[i * 2 + 1] = t / surf->texinfo->texture->height; - mesh->ab[i * 2 + 0] = s * (1.0f / 16.0f); - mesh->ab[i * 2 + 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]; + 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); } + 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 @@ -1328,33 +1555,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); } /* @@ -1366,7 +1604,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)) @@ -1378,15 +1616,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) @@ -1409,7 +1648,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; @@ -1425,7 +1664,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)) @@ -2426,20 +2664,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_DrawBrushModelFakeShadow (entity_render_t *ent); +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); 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; @@ -2459,7 +2838,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]; @@ -2520,62 +2890,68 @@ 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->texinfo->texture->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; + // calculate bounding shapes + for (mesh = surf->mesh;mesh;mesh = mesh->chain) + { + 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); + 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; - mod->radius = modelradius; - mod->radius2 = modelradius * 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->radius = 0; - mod->radius2 = 0; } + Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool); mod->numleafs = bm->visleafs; - mod->Draw = R_DrawBrushModelNormal; - mod->DrawFakeShadow = R_DrawBrushModelFakeShadow; - // LordHavoc: only register submodels if it is the world // (prevents bsp models from replacing world submodels) if (loadmodel->isworldmodel && i < (mod->numsubmodels - 1)) @@ -2594,6 +2970,6 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) } loadmodel = originalloadmodel; - Mod_ProcessLightList (); + //Mod_ProcessLightList (); }