X-Git-Url: http://git.xonotic.org/?a=blobdiff_plain;f=model_brush.c;h=c91368de3b2bfd2ca61507ac877135cbcc7e3e5c;hb=fabdca42b48cc4acf214c06adda9814e5cce8577;hp=44bb23ffca98aa5fac17d5c399e1aa70f0ba8bf2;hpb=8fd8e96110f501587d3331139e694f54e4f32c9f;p=xonotic%2Fdarkplaces.git diff --git a/model_brush.c b/model_brush.c index 44bb23ff..c91368de 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; @@ -290,6 +296,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,98 +329,161 @@ 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) + { + 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) { - if (mtdata && (data = W_ConvertWAD3Texture(dmiptex))) + 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 < tx->width*tx->height;j++) + if (((qbyte *)&palette_onlyfullbrights[mtdata[j]])[3] > 0) // fullbright + break; + if (j < 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] == '*') { @@ -416,6 +493,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') @@ -427,11 +506,13 @@ static void Mod_LoadTextures (lump_t *l) { tx->flags |= SURF_LIGHTMAP; if (!tx->fogtexture) - tx->flags |= SURF_CLIPSOLID; + tx->flags |= SURF_SHADOWCAST | SURF_SHADOWLIGHT; tx->shader = &Cshader_wall_lightmap; } - tx->detailtexture = detailtextures[i % NUM_DETAILTEXTURES]; + // start out with no animation + tx->currentframe[0] = tx; + tx->currentframe[1] = tx; } // sequence the animations @@ -1115,6 +1196,37 @@ void Mod_ShadowBrush_AddPolygon(mempool_t *mempool, svbrush_t *brush, int numver memcpy(poly->verts, verts, numverts * sizeof(float[3])); } +void Mod_ShadowBrush_AddPolygonI(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); + VectorNegate(normal, normal); + dist = -dist; + + 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; + for (i = 0, v0 = verts + (numverts - 1) * 3, v1 = poly->verts;i < numverts;i++, v0 -= 3, v1 += 3) + VectorCopy(v0, v1); +} + void Mod_ShadowBrush_EndBrush(svworld_t *world, svbrush_t *brush) { int i; @@ -1187,10 +1299,10 @@ void Mod_ProcessLightList(void) qbyte *pvs; 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);// + 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); @@ -1229,6 +1341,7 @@ void Mod_ProcessLightList(void) if (loadmodel->surfacevisframes[j] == -2) e->surfaces[e->numsurfaces++] = loadmodel->surfaces + j; } +#if 1 { // find bounding box and sphere of lit surfaces // (these will be used for creating a shape to clip the light) @@ -1253,25 +1366,37 @@ void Mod_ProcessLightList(void) radius2 = dist; } } - /* if (e->cullradius2 > radius2) { e->cullradius2 = radius2; e->cullradius = sqrt(e->cullradius2); } - */ } +#endif +#if 1 + e->mins[0] = e->origin[0] - e->cullradius; + e->maxs[0] = e->origin[0] + e->cullradius; + e->mins[1] = e->origin[1] - e->cullradius; + e->maxs[1] = e->origin[1] + e->cullradius; + e->mins[2] = e->origin[2] - e->cullradius; + e->maxs[2] = e->origin[2] + e->cullradius; +#endif #if 1 // clip shadow volumes against eachother to remove unnecessary // polygons (and sections of polygons) { - vec3_t temp, outermins, outermaxs, innermins, innermaxs; + vec3_t temp; + //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; + svworld = Mod_ShadowBrush_NewWorld(loadmodel->mempool); +#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,57 +1409,6 @@ 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_CLIPSOLID)) - 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) @@ -1416,6 +1490,113 @@ void Mod_ProcessLightList(void) 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); + } +#endif +#define SHADOWCASTFRONT 1 +#if SHADOWCASTFRONT + for (j = 0;j < e->numsurfaces;j++) + { + surf = e->surfaces[j]; +#else + for (j = 0, surf = loadmodel->surfaces + loadmodel->firstmodelsurface;j < loadmodel->nummodelsurfaces;j++, surf++) + { +#endif + if (!(surf->flags & SURF_CLIPSOLID)) + continue; + f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; + if (surf->flags & SURF_PLANEBACK) + f = -f; +#if SHADOWCASTFRONT + projectdistance = e->cullradius - f; +#else + projectdistance = e->cullradius + f; +#endif + 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; + /* + VectorCopy(surf->poly_verts, polymins); + VectorCopy(surf->poly_verts, polymaxs); + for (k = 0, v0 = surf->poly_verts;k < surf->poly_numverts;k++, v0 += 3) + { + if (polymins[0] > v0[0]) polymins[0] = v0[0];if (polymaxs[0] < v0[0]) polymaxs[0] = v0[0]; + if (polymins[1] > v0[1]) polymins[1] = v0[1];if (polymaxs[1] < v0[1]) polymaxs[1] = v0[1]; + if (polymins[2] > v0[2]) polymins[2] = v0[2];if (polymaxs[2] < v0[2]) polymaxs[2] = v0[2]; + } + if (polymins[0] > e->maxs[0] || polymaxs[0] < e->mins[0] + || polymins[1] > e->maxs[1] || polymaxs[1] < e->mins[1] + || polymins[2] > e->maxs[2] || polymaxs[2] < e->mins[2]) + 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); +#if SHADOWCASTFRONT + // 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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 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_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(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_ShadowBrush_AddPolygon(loadmodel->mempool, svbrush, 4, verts); + } +#else + // 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); + } +#endif + Mod_ShadowBrush_EndBrush(svworld, svbrush); + } // clip away hidden polygons Mod_ShadowBrush_ProcessWorld(loadmodel->mempool, svworld); // build the triangle mesh @@ -1442,7 +1623,7 @@ void Mod_ProcessLightList(void) #if 1 for (j = 0, surf = loadmodel->surfaces + loadmodel->firstmodelsurface;j < loadmodel->nummodelsurfaces;j++, surf++) { - if (!(surf->flags & SURF_CLIPSOLID)) + if (!(surf->flags & SURF_SHADOWCAST)) continue; /* if (surf->poly_maxs[0] < e->mins[0] @@ -1541,7 +1722,7 @@ void Mod_ProcessLightList(void) for (j = 0;j < e->numsurfaces;j++) { surf = e->surfaces[j]; - if (!(surf->flags & SURF_CLIPSOLID)) + if (!(surf->flags & SURF_SHADOWCAST)) continue; f = DotProduct(e->origin, surf->plane->normal) - surf->plane->dist; if (surf->flags & SURF_PLANEBACK) @@ -2055,6 +2236,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 +2279,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_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 + 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 +2329,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 +2342,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,12 +2365,12 @@ 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) @@ -3309,6 +3489,40 @@ static void Mod_MakePortals(void) Mod_FinalizePortals(); } +static void Mod_BuildSurfaceNeighbors (msurface_t *surfaces, int numsurfaces, mempool_t *mempool) +{ + #if 0 + int surfnum, vertnum, snum, vnum; + 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 (vertnum = 0;vertnum < surf->poly_numverts;vertnum++) + { + v0 = surf->poly_verts + ((vertnum + 1) % surf->poly_numverts) * 3; + v1 = surf->poly_verts + vertnum * 3; + surf->neighborsurfaces[vertnum] = NULL; + for (s = surfaces, snum = 0;snum < numsurfaces;s++, snum++) + { + if (s == surf) + continue; + for (vnum = 0, v2 = s->poly_verts + (s->poly_numverts - 1) * 3, v3 = s->poly_verts;vnum < s->poly_numverts;vnum++, v2 = v3, v3 += 3) + { + if (v0[0] == v2[0] && v0[1] == v2[1] && v0[2] == v2[2] && v1[0] == v3[0] && v1[1] == v3[1] && v1[2] == v3[2]) + { + surf->neighborsurfaces[vertnum] = s; + break; + } + } + if (vnum < s->poly_numverts) + break; + } + } + } + #endif +} + /* ================= Mod_LoadBrushModel @@ -3316,11 +3530,8 @@ 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 lightradius2, float lightdistbias, float lightsubtract, float *lightcolor); void Mod_LoadBrushModel (model_t *mod, void *buffer) { int i, j; @@ -3413,10 +3624,9 @@ 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->texturesurfacechains = Mem_Alloc(originalloadmodel->mempool, mod->numtextures * sizeof(msurface_t *)); if (mod->nummodelsurfaces) { // LordHavoc: calculate bmodel bounding box rather than trusting what it says @@ -3425,6 +3635,10 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) // 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; + // link into texture chain + surf->texturechain = mod->texturesurfacechains[surf->texinfo->texture - mod->textures]; + mod->texturesurfacechains[surf->texinfo->texture - mod->textures] = surf; + // calculate bounding shapes for (k = 0;k < surf->numedges;k++) { l = mod->surfedges[k + surf->firstedge]; @@ -3459,7 +3673,7 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) // (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_CLIPSOLID) + 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); @@ -3478,6 +3692,7 @@ void Mod_LoadBrushModel (model_t *mod, void *buffer) mod->radius2 = 0; mod->shadowmesh = NULL; } + Mod_BuildSurfaceNeighbors(mod->surfaces + mod->firstmodelsurface, mod->nummodelsurfaces, originalloadmodel->mempool); mod->numleafs = bm->visleafs;