Alternate light drawing

Not sure I like it too much, but this is a version where lights get
updated quicker.
alternate-lights
Peter Wortmann 2015-02-22 23:20:55 +01:00
parent d976a4b2a7
commit 88c33aa629
8 changed files with 92 additions and 55 deletions

View File

@ -11,16 +11,16 @@ uniform sampler2D lightTex;
//#define LIGHT_DEBUG
// At what point of light intensity we set the "darkness" point. This
// is to compensate for the fact that the engien "smoothes" the light
// is to compensate for the fact that the engine "smoothes" the light
// and therefore will often never arrive at 0 light intensity.
const float lightDarknessLevel = 8.0 / 256.0;
const float lightDarknessLevel = 2.0 / 256.0;
slice(texture+5)
{
#ifdef HAVE_LIGHT
// Query light texture
vec4 lightPx = texture2D(lightTex, lightCoord.st);
float lightBright = max(0.0, lightPx.x-lightDarknessLevel);
float lightBright = max(0.0, lightPx.a-lightDarknessLevel);
vec3 lightDir = extend_normal(vec2(1.0, 1.0) - lightPx.yz * 3.0);
#else
// When lighting is disabled, put a light source coming from the camera.

View File

@ -873,6 +873,7 @@ void C4LandscapeRenderGL::Draw(const C4TargetFacet &cgo, const C4FoWRegion *Ligh
// Choose the right shader depending on whether we have dynamic lighting or not
const C4Shader* shader = &Shader;
if (Light) shader = &ShaderLight;
if (!shader->Initialised()) return;
// Activate shader
C4ShaderCall ShaderCall(shader);

View File

@ -37,7 +37,8 @@ C4Shader *C4FoW::GetFramebufShader()
FramebufShader.AddTexCoord("texCoord");
FramebufShader.AddFragmentSlice(-1, "uniform sampler2D tex;");
FramebufShader.AddFragmentSlice(0,
"gl_FragColor = vec4(texture2D(tex, texCoord.st).rgb, 3.0f/4.0f);");
"vec4 old = texture2D(tex, texCoord.st);\n"
"gl_FragColor = vec4(old.rgb, old.a*15.0f/16.0f);");
const char *szUniforms[] = { "tex", NULL };
if (!FramebufShader.Init("framebuf", szUniforms)) {
FramebufShader.ClearSlices();

View File

@ -19,6 +19,7 @@
#include "C4FoWRegion.h"
#include "C4DrawGL.h"
bool C4FoW_Draw[5] = { true, true, true, true, true };
void C4FoWDrawLightTextureStrategy::Begin(int32_t passPar)
{
@ -26,13 +27,16 @@ void C4FoWDrawLightTextureStrategy::Begin(int32_t passPar)
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glBlendFunc(GL_ONE, GL_ONE);
// Set up blend equation, see C4FoWDrawLightTextureStrategy::DrawVertex
// for details.
if(pass == 0)
{
glBlendEquation( GL_FUNC_ADD );
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
}
else if(pass == 1)
{
glBlendFunc(GL_ONE, GL_ONE);
glBlendEquation(GL_FUNC_REVERSE_SUBTRACT);
}
@ -40,12 +44,39 @@ void C4FoWDrawLightTextureStrategy::Begin(int32_t passPar)
void C4FoWDrawLightTextureStrategy::End(int32_t pass)
{
glBlendEquation( GL_FUNC_ADD );
glBlendEquation(GL_FUNC_ADD);
}
void C4FoWDrawLightTextureStrategy::DrawVertex(float x, float y, bool shadeLight)
void C4FoWDrawLightTextureStrategy::DrawVertex(float x, float y, bool shadow)
{
if(pass == 0)
// Here's the master plan for updating the lights texture. We want to
//
// 1. sum up the normals, weighted by intensity
// 2. take over intensity maximum as new intensity
//
// where intensity is in the A channel and normals are in the GB channels.
// Normals are obviously meant to be though of as signed, though,
// so the equation we want would be something like
//
// A_new = max(A_old, A);
// G_new = BoundBy(G_old + G - 0.5, 0.0, 1.0);
// B_new = BoundBy(B_old + B - 0.5, 0.0, 1.0);
//
// It seems we can't get that directly though - glBlendFunc only talks
// about two operands. Even if we make two passes, we have to take
// care that that we don't over- or underflow in the intermediate pass.
//
// Therefore, we store G/1.5 instead of G, losing a bit of accuracy,
// but allowing us to formulate the following approximation without
// overflows:
//
// G_new = BoundBy(BoundBy(G_old + G / 1.5), 0.0, 1.0) - 0.5 / 1.5, 0.0, 1.0)
// B_new = BoundBy(BoundBy(B_old + B / 1.5), 0.0, 1.0) - 0.5 / 1.5, 0.0, 1.0)
if (pass > 0)
glColor4f(0.0f, 0.5f/1.5f, 0.5f/1.5f, 0.0f);
else if (shadow)
{
float dx = x - light->getX();
float dy = y - light->getY();
@ -53,13 +84,10 @@ void C4FoWDrawLightTextureStrategy::DrawVertex(float x, float y, bool shadeLight
float mult = Min(0.5f / light->getNormalSize(), 0.5f / dist);
float normX = Clamp(0.5f + dx * mult, 0.0f, 1.0f) / 1.5f;
float normY = Clamp(0.5f + dy * mult, 0.0f, 1.0f) / 1.5f;
if(shadeLight) glColor3f(0.5f, normX, normY);
else glColor3f(0.0f, 0.5f/1.5f, 0.5f/1.5f);
glColor4f(0.0f, normX, normY, 0.5f);
}
else
{
glColor3f(0.0f, 0.5f/1.5f, 0.5f/1.5f);
}
glColor4f(0.0f, 0.5f/1.5f, 0.5f/1.5f, 0.0f);
// global coords -> region coords
x += -region->getRegion().x;
@ -70,11 +98,13 @@ void C4FoWDrawLightTextureStrategy::DrawVertex(float x, float y, bool shadeLight
void C4FoWDrawLightTextureStrategy::DrawDarkVertex(float x, float y)
{
if (!C4FoW_Draw[phase]) return;
DrawVertex(x,y, false);
}
void C4FoWDrawLightTextureStrategy::DrawLightVertex(float x, float y)
{
if (!C4FoW_Draw[phase]) return;
DrawVertex(x,y, true);
}
@ -100,15 +130,28 @@ void C4FoWDrawWireframeStrategy::DrawVertex(float x, float y)
void C4FoWDrawWireframeStrategy::DrawDarkVertex(float x, float y)
{
if(!draw) return;
glColor3f(0.5f, 0.5f, 0.0f);
if (!C4FoW_Draw[phase]) return;
switch(phase)
{
case P_None: return;
case P_Fade: glColor3f(0.0f, 0.5f, 0.0f); break;
case P_Intermediate: glColor3f(0.0f, 0.0f, 0.5f); break;
default: assert(false); // only fade has dark vertices
}
DrawVertex(x, y);
}
void C4FoWDrawWireframeStrategy::DrawLightVertex(float x, float y)
{
if(!draw) return;
glColor3f(1.0f, 0.0f, 0.0f);
if (!C4FoW_Draw[phase]) return;
switch(phase)
{
case P_None: return;
case P_Fan: glColor3f(1.0f, 0.0f, 0.0f); break;
case P_FanMaxed: glColor3f(1.0f, 1.0f, 0.0f); break;
case P_Fade: glColor3f(0.0f, 1.0f, 0.0f); break;
case P_Intermediate: glColor3f(0.0f, 0.0f, 1.0f); break;
}
DrawVertex(x, y);
}

View File

@ -33,7 +33,17 @@ class C4FoWLight;
class C4FoWDrawStrategy
{
public:
virtual ~C4FoWDrawStrategy() {};
C4FoWDrawStrategy() : phase(P_None) {}
virtual ~C4FoWDrawStrategy() {}
// Drawing phases
enum DrawPhase {
P_None,
P_Fan,
P_FanMaxed,
P_Fade,
P_Intermediate
} phase;
/** Returns in how many rendering passes the light should be rendered */
virtual int32_t GetRequestedPasses() { return 1; };
@ -46,22 +56,22 @@ public:
virtual void DrawDarkVertex(float x, float y) = 0;
/** Called before rendering the inner triangle fan (the area with 100% light) */
virtual void BeginFan() { glBegin(GL_TRIANGLE_FAN); };
virtual void BeginFan() { glBegin(GL_TRIANGLE_FAN); phase = P_Fan; };
/** Called after rendering the inner triangle fan */
virtual void EndFan() { glEnd(); };
/** Called before rendering the triangle fan existnsion (100% light, maxed out normals) */
virtual void BeginFanMaxed() { glBegin(GL_QUADS); };
virtual void BeginFanMaxed() { glBegin(GL_QUADS); phase = P_FanMaxed; };
/** Called after rendering the inner triangle fan */
virtual void EndFanMaxed() { glEnd(); };
/** Called before rendering the quads in which the light fades out */
virtual void BeginFade() { glBegin(GL_QUADS); };
virtual void BeginFade() { glBegin(GL_QUADS); phase = P_Fade; };
/** Called after rendering the quads in which the light fades out */
virtual void EndFade() { glEnd(); };
/** Called before rendering the triangles that fill the space between the fadeout quads */
virtual void BeginIntermediateFade() { glBegin(GL_TRIANGLE_FAN); };
virtual void BeginIntermediateFade() { glBegin(GL_TRIANGLE_FAN); phase = P_Intermediate; };
/** Called after rendering the triangles that fill the space between the fadeout quads */
virtual void EndIntermediateFade() { glEnd(); };
};
@ -96,22 +106,19 @@ private:
class C4FoWDrawWireframeStrategy : public C4FoWDrawStrategy
{
public:
C4FoWDrawWireframeStrategy(const C4FoWLight* light, const C4TargetFacet *screen) : light(light), screen(screen), draw(true) {};
C4FoWDrawWireframeStrategy(const C4FoWLight* light, const C4TargetFacet *screen)
: light(light), screen(screen) {};
virtual void DrawLightVertex(float x, float y);
virtual void DrawDarkVertex(float x, float y);
virtual void Begin(int32_t pass);
virtual void End(int32_t pass);
virtual void BeginFan() { C4FoWDrawStrategy::BeginFan(); draw = false; };
virtual void EndFan() { C4FoWDrawStrategy::EndFan(); draw = true; };
private:
void DrawVertex(float x, float y);
const C4FoWLight* light;
const C4TargetFacet* screen;
bool draw;
};
#endif

View File

@ -28,7 +28,7 @@ C4FoWLight::C4FoWLight(C4Object *pObj)
iY(fixtoi(pObj->fix_y)),
iReach(pObj->lightRange),
iFadeout(pObj->lightFadeoutRange),
iSize(20),
iSize(20), gBright(0.5),
pNext(NULL),
pObj(pObj),
sections(4)
@ -111,26 +111,6 @@ void C4FoWLight::Render(C4FoWRegion *region, const C4TargetFacet *onScreen)
CalculateFanMaxed(triangles);
CalculateIntermediateFadeTriangles(triangles);
// Here's the master plan for updating the lights texture. We
// want to add intensity (R channel) as well as the normal (GB channels).
// Normals are obviously meant to be though of as signed, though,
// so the equation we want would be something like
//
// R_new = Clamp(R_old + R, 0.0, 1.0)
// G_new = Clamp(G_old + G - 0.5, 0.0, 1.0)
// B_new = Clamp(B_old + B - 0.5, 0.0, 1.0)
//
// It seems we can't get that directly though - glBlendFunc only talks
// about two operands. Even if we make two passes, we have to take
// care that that we don't over- or underflow in the intermediate pass.
//
// Therefore, we store G/1.5 instead of G, losing a bit of accuracy,
// but allowing us to formulate the following approximation without
// overflows:
//
// G_new = Clamp(Clamp(G_old + G / 1.5), 0.0, 1.0) - 0.5 / 1.5, 0.0, 1.0)
// B_new = Clamp(Clamp(B_old + B / 1.5), 0.0, 1.0) - 0.5 / 1.5, 0.0, 1.0)
C4FoWDrawStrategy* pen;
if (onScreen) pen = new C4FoWDrawWireframeStrategy(this, onScreen);
else pen = new C4FoWDrawLightTextureStrategy(this, region);

View File

@ -40,6 +40,7 @@ private:
int32_t iReach; // maximum length of beams
int32_t iFadeout; // number of pixels over which beams fade out
int32_t iSize; // size of the light source. Decides smoothness of shadows
float gBright; // brigtness of the light source. 1.0 is maximum.
C4FoWLight *pNext;
C4Object *pObj; // Associated object
@ -53,6 +54,7 @@ public:
int32_t getTotalReach() const { return iReach + iFadeout; }
int32_t getSize() const { return iSize; }
int32_t getNormalSize() const { return iSize * 2; }
float getBrightness() const { return gBright; }
C4FoWLight *getNext() const { return pNext; }
C4Object *getObj() const { return pObj; }

View File

@ -114,6 +114,11 @@ void C4FoWRegion::Render(const C4TargetFacet *pOnScreen)
return;
}
// Set up shader. If this one doesn't work, we're really in trouble.
C4Shader *pShader = pFoW->GetFramebufShader();
assert(pShader);
if (!pShader) return;
// Create & bind the frame buffer
pDraw->StorePrimaryClipper();
if(!BindFramebuf())
@ -133,7 +138,7 @@ void C4FoWRegion::Render(const C4TargetFacet *pOnScreen)
gluOrtho2D(0, getSurface()->Wdt, getSurface()->Hgt, 0);
// Clear texture contents
glClearColor(0.0f, 0.5f/1.5f, 0.5f/1.5f, 1.0f);
glClearColor(0.0f, 0.5f/1.5f, 0.5f/1.5f, 0.0f);
glClear(GL_COLOR_BUFFER_BIT);
// Render FoW to frame buffer object
@ -143,10 +148,6 @@ void C4FoWRegion::Render(const C4TargetFacet *pOnScreen)
// Copy over the old state
if (OldRegion.Wdt > 0) {
// Set up shader. If this one doesn't work, we're really in trouble.
C4Shader *pShader = pFoW->GetFramebufShader();
assert(pShader);
// How much the borders have moved
int dx0 = Region.x - OldRegion.x,
dy0 = Region.y - OldRegion.y,
@ -175,7 +176,8 @@ void C4FoWRegion::Render(const C4TargetFacet *pOnScreen)
Call.Start();
if (Call.AllocTexUnit(0, GL_TEXTURE_2D))
glBindTexture(GL_TEXTURE_2D, getBackSurface()->textures[0].texName);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
glBlendFunc(GL_ONE_MINUS_DST_ALPHA, GL_DST_ALPHA);
glBlendEquationSeparate(GL_FUNC_ADD, GL_MAX);
glBegin(GL_QUADS);
for (int i = 0; i < 4; i++)
{
@ -184,6 +186,7 @@ void C4FoWRegion::Render(const C4TargetFacet *pOnScreen)
}
glEnd();
Call.Finish();
glBlendEquation(GL_FUNC_ADD);
}
// Done!