diff --git a/doomsday/engine/api/dd_share.h b/doomsday/engine/api/dd_share.h index ac3b0d8b41..d2c973328b 100644 --- a/doomsday/engine/api/dd_share.h +++ b/doomsday/engine/api/dd_share.h @@ -314,6 +314,10 @@ extern "C" { DD_GRAVITY, DD_PSPRITE_OFFSET_X, // 10x DD_PSPRITE_OFFSET_Y, // 10x + DD_TORCH_RED, + DD_TORCH_GREEN, + DD_TORCH_BLUE, + DD_TORCH_ADDITIVE }; // Bounding box coordinates. diff --git a/doomsday/engine/portable/include/rend_list.h b/doomsday/engine/portable/include/rend_list.h index 74414cf1c3..f61067d564 100644 --- a/doomsday/engine/portable/include/rend_list.h +++ b/doomsday/engine/portable/include/rend_list.h @@ -43,8 +43,10 @@ extern int renderWireframe; extern int useMultiTexLights; extern int useMultiTexDetails; -extern float rend_light_wall_angle; +extern float rendLightWallAngle; extern float detailFactor, detailScale; +extern int torchAdditive; +extern float torchColor[]; void RL_Register(void); void RL_Init(void); diff --git a/doomsday/engine/portable/src/dd_main.c b/doomsday/engine/portable/src/dd_main.c index 76017a667c..0735748a41 100644 --- a/doomsday/engine/portable/src/dd_main.c +++ b/doomsday/engine/portable/src/dd_main.c @@ -1079,6 +1079,17 @@ void* DD_GetVariable(int ddvalue) case DD_GRAVITY: return &mapGravity; + case DD_TORCH_RED: + return &torchColor[CR]; + + case DD_TORCH_GREEN: + return &torchColor[CG]; + + case DD_TORCH_BLUE: + return &torchColor[CB]; + + case DD_TORCH_ADDITIVE: + return &torchAdditive; #ifdef WIN32 case DD_WINDOW_HANDLE: return Sys_GetWindowHandle(windowIDX); @@ -1176,6 +1187,22 @@ void DD_SetVariable(int ddvalue, void *parm) pspOffset[VY] = *(float*) parm; return; + case DD_TORCH_RED: + torchColor[CR] = MINMAX_OF(0, *((float*) parm), 1); + return; + + case DD_TORCH_GREEN: + torchColor[CG] = MINMAX_OF(0, *((float*) parm), 1); + return; + + case DD_TORCH_BLUE: + torchColor[CB] = MINMAX_OF(0, *((float*) parm), 1); + return; + + case DD_TORCH_ADDITIVE: + torchAdditive = (*(int*) parm)? true : false; + break; + default: break; } diff --git a/doomsday/engine/portable/src/rend_bias.c b/doomsday/engine/portable/src/rend_bias.c index 97d945496e..7af5924d05 100644 --- a/doomsday/engine/portable/src/rend_bias.c +++ b/doomsday/engine/portable/src/rend_bias.c @@ -840,9 +840,6 @@ void SB_RendPoly(struct rendpoly_s *poly, float sectorLightLevel, uint i; boolean forced; - if(!useBias) - return; - // Apply sectorlight bias. Note: Distance darkening is not used // with bias lights. if(sectorLightLevel > biasMin && biasMax > biasMin) diff --git a/doomsday/engine/portable/src/rend_list.c b/doomsday/engine/portable/src/rend_list.c index 3e87b57fdb..26b7535e19 100644 --- a/doomsday/engine/portable/src/rend_list.c +++ b/doomsday/engine/portable/src/rend_list.c @@ -230,7 +230,7 @@ int useMultiTexLights = true; int useMultiTexDetails = true; // Intensity of angle-based wall lighting. -float rend_light_wall_angle = 1; +float rendLightWallAngle = 1; // Rendering parameters for detail textures. float detailFactor = .5f; @@ -238,6 +238,9 @@ float detailFactor = .5f; //float detailMaxDist = 256; float detailScale = 4; +float torchColor[3] = {1, 1, 1}; +int torchAdditive = true; + // PRIVATE DATA DEFINITIONS ------------------------------------------------ /** @@ -366,6 +369,30 @@ static void addMaskedPoly(rendpoly_t *poly) } } +static float wallAngleLightlevelOffset(const rendpoly_t *poly) +{ + if(!poly->isWall || !(rendLightWallAngle > 0)) + return 0; + + // Do a lighting adjustment based on orientation. + return (1.0f / 255.0f) * + ((poly->vertices[2].pos[VY] - + poly->vertices[0].pos[VY]) / poly->wall->length * 18 * + rendLightWallAngle); +} + +static float distAttenuateLightLevel(float distToViewer, float lightLevel) +{ + float real, minimum; + + real = lightLevel - (distToViewer - 32) / maxLightDist * (1 - lightLevel); + minimum = lightLevel * lightLevel + (lightLevel - .63f) / 2; + if(real < minimum) + real = minimum; // Clamp it. + + return real; +} + /** * Color distance attenuation, extraLight, fixedcolormap. * "Torchlight" is white, regardless of the original RGB. @@ -375,14 +402,14 @@ static void addMaskedPoly(rendpoly_t *poly) * calculated if needed, depending on the properties of * the rendpoly to be lit, for each vertex seperately. */ -void RL_VertexColors(rendpoly_t *poly, float lightlevel, - float distanceOverride, const float *rgb, float alpha) +void RL_VertexColors(rendpoly_t *poly, float lightLevel, + float distanceOverride, const float sufColor[3], + float alpha) { - int i, num; - float light, real, minimum; - float dist; - rendpoly_vertex_t *vtx; - boolean usewhite; + int i, num; + float lightVal, dist = distanceOverride; + float rgb[3]; + rendpoly_vertex_t *vtx; // Check for special case exceptions. if(poly->flags & (RPF_SKY_MASK|RPF_LIGHT|RPF_SHADOW)) @@ -390,81 +417,64 @@ void RL_VertexColors(rendpoly_t *poly, float lightlevel, return; // Don't need per-vertex lighting. } - if(poly->isWall && rend_light_wall_angle && !useBias) // A quad? - { - // Do a lighting adjustment based on orientation. - lightlevel += (1.0f / 255.0f) * - ((poly->vertices[2].pos[VY] - - poly->vertices[0].pos[VY]) / poly->wall->length * 18 * - rend_light_wall_angle); - if(lightlevel < 0) - lightlevel = 0; - if(lightlevel > 1) - lightlevel = 1; - } - - if(lightlevel < 0) - light = 1; // Full bright. - else - light = lightlevel; + lightLevel += wallAngleLightlevelOffset(poly); + lightLevel = MINMAX_OF(0, lightLevel, 1); num = poly->numVertices; for(i = 0, vtx = poly->vertices; i < num; ++i, vtx++) { - usewhite = false; - - if(distanceOverride > 0) - dist = distanceOverride; + // If this is a glowing surface, boost the light level up. + if(poly->flags & RPF_GLOW) + { + vtx->color.rgba[CR] = vtx->color.rgba[CG] = + vtx->color.rgba[CB] = 255; + } else - dist = Rend_PointDist2D(vtx->pos); + { + if(!(distanceOverride > 0)) + dist = Rend_PointDist2D(vtx->pos); - real = light - (dist - 32) / maxLightDist * (1 - light); - minimum = light * light + (light - .63f) / 2; - if(real < minimum) - real = minimum; // Clamp it. + // Apply distance attenuation. + lightVal = distAttenuateLightLevel(dist, lightLevel); - // Add extra light. - real += extraLight / 16.0f; + // Add extra light. + lightVal += extraLight / 16.0f; - // Check for torch. - if(viewPlayer->fixedColorMap) - { - // Colormap 1 is the brightest. I'm guessing 16 would be - // the darkest. - int ll = 16 - viewPlayer->fixedColorMap; - float d = (1024 - dist) / 512.0f; - float newmin = d * ll / 15.0f; + // Mix with the surface color. + rgb[CR] = lightVal * sufColor[CR]; + rgb[CG] = lightVal * sufColor[CG]; + rgb[CB] = lightVal * sufColor[CB]; - if(real < newmin) + // Check for torch. + if(viewPlayer->fixedColorMap && dist < 1024) { - real = newmin; - usewhite = true; // \fixme Do some linear blending. - } - } - - // If this is a glowing surface, boost the light up. - if(poly->flags & RPF_GLOW) - real = 1; + // Colormap 1 is the brightest. I'm guessing 16 would be + // the darkest. + int ll = 16 - viewPlayer->fixedColorMap; + float d = (1024 - dist) / 1024.0f * ll / 15.0f; - // Clamp the final light. - if(real < 0) - real = 0; - if(real > 1) - real = 1; + if(torchAdditive) + { + rgb[CR] += d * torchColor[CR]; + rgb[CG] += d * torchColor[CG]; + rgb[CB] += d * torchColor[CB]; + } + else + { + rgb[CR] += d * ((rgb[CR] * torchColor[CR]) - rgb[CR]); + rgb[CG] += d * ((rgb[CG] * torchColor[CG]) - rgb[CG]); + rgb[CB] += d * ((rgb[CB] * torchColor[CB]) - rgb[CB]); + } + } - if(usewhite) - { - vtx->color.rgba[0] = vtx->color.rgba[1] = vtx->color.rgba[2] = - (DGLubyte) (0xff * real); - } - else - { - vtx->color.rgba[0] = (DGLubyte) (255 * rgb[0] * real); - vtx->color.rgba[1] = (DGLubyte) (255 * rgb[1] * real); - vtx->color.rgba[2] = (DGLubyte) (255 * rgb[2] * real); + // Set final color. + vtx->color.rgba[CR] = (DGLubyte) (255 * MINMAX_OF(0, rgb[CR], 1)); + vtx->color.rgba[CG] = (DGLubyte) (255 * MINMAX_OF(0, rgb[CG], 1)); + vtx->color.rgba[CB] = (DGLubyte) (255 * MINMAX_OF(0, rgb[CB], 1)); } - vtx->color.rgba[3] = (DGLubyte) (255 * alpha); + // Set final alpha. + vtx->color.rgba[CA] = (DGLubyte) (255 * MINMAX_OF(0, alpha, 1)); } } diff --git a/doomsday/engine/portable/src/rend_main.c b/doomsday/engine/portable/src/rend_main.c index ea621ef881..29d7ee9fb8 100644 --- a/doomsday/engine/portable/src/rend_main.c +++ b/doomsday/engine/portable/src/rend_main.c @@ -168,7 +168,7 @@ void Rend_Register(void) Rend_CalcLightRangeModMatrix); C_VAR_INT2("rend-light-sky", &rendSkyLight, 0, 0, 1, LG_MarkAllForUpdate); - C_VAR_FLOAT("rend-light-wall-angle", &rend_light_wall_angle, CVF_NO_MAX, + C_VAR_FLOAT("rend-light-wall-angle", &rendLightWallAngle, CVF_NO_MAX, 0, 0); C_VAR_INT("rend-dev-light-modmatrix", &debugLightModMatrix, CVF_NO_ARCHIVE, 0, 1); @@ -1029,9 +1029,12 @@ static void doRenderPlane(rendpoly_t *poly, sector_t *polySector, else poly->lightListIdx = DL_ProcessSubSectorPlane(subsector, plane->planeID); - // Do BIAS lighting for this poly. - SB_RendPoly(poly, subsector->sector->lightLevel, plane->illumination, - &plane->tracker, plane->affected, subIndex); + if(useBias) + { + // Do BIAS lighting for this poly. + SB_RendPoly(poly, subsector->sector->lightLevel, plane->illumination, + &plane->tracker, plane->affected, subIndex); + } // Smooth Texture Animation? if(flags & RPF2_BLEND) @@ -1285,7 +1288,6 @@ static boolean renderSegSection(seg_t *seg, segsection_t section, surface_t *sur { const float *topColor = NULL; const float *bottomColor = NULL; - uint lightListIdx; float sectorLightLevel = Rend_SectorLight(frontsec); // Check for neighborhood division? @@ -1294,7 +1296,8 @@ static boolean renderSegSection(seg_t *seg, segsection_t section, surface_t *sur getColorsForSegSection(sideFlags, section, &bottomColor, &topColor); - lightListIdx = + // Dynamic lights. + quad->lightListIdx = DL_ProcessSegSection(seg, vL_ZBottom, vL_ZTop, (quad->flags & RPF_MASKED)? true:false); @@ -1303,29 +1306,31 @@ static boolean renderSegSection(seg_t *seg, segsection_t section, surface_t *sur quad->flags |= RPF_GLOW; // Surface color/light. - RL_VertexColors(quad, sectorLightLevel, -1, topColor, alpha); - - // Bottom color (if different from top)? - if(bottomColor != NULL) + if(useBias) + { + // Do BIAS lighting for this poly. + SB_RendPoly(quad, sectorLightLevel, seg->illum[section], + &seg->tracker[section], seg->affected, + GET_SEG_IDX(seg)); + } + else { - uint i; + RL_VertexColors(quad, sectorLightLevel, -1, topColor, alpha); - for(i = 0; i < 4; i += 2) + // Bottom color (if different from top)? + if(bottomColor != NULL) { - quad->vertices[i].color.rgba[0] = (DGLubyte) (255 * bottomColor[0]); - quad->vertices[i].color.rgba[1] = (DGLubyte) (255 * bottomColor[1]); - quad->vertices[i].color.rgba[2] = (DGLubyte) (255 * bottomColor[2]); + uint i; + + for(i = 0; i < 4; i += 2) + { + quad->vertices[i].color.rgba[0] = (DGLubyte) (255 * bottomColor[0]); + quad->vertices[i].color.rgba[1] = (DGLubyte) (255 * bottomColor[1]); + quad->vertices[i].color.rgba[2] = (DGLubyte) (255 * bottomColor[2]); + } } } - // Dynamic lights. - quad->lightListIdx = lightListIdx; - - // Do BIAS lighting for this poly. - SB_RendPoly(quad, sectorLightLevel, seg->illum[section], - &seg->tracker[section], seg->affected, - GET_SEG_IDX(seg)); - // Smooth Texture Animation? if(tempflags & RPF2_BLEND) polyTexBlend(quad, surface->material);