From 88c33aa6294e57dc70e9e992d6afe099fe8d0cf8 Mon Sep 17 00:00:00 2001 From: Peter Wortmann Date: Sun, 22 Feb 2015 23:20:55 +0100 Subject: [PATCH] Alternate light drawing Not sure I like it too much, but this is a version where lights get updated quicker. --- planet/Graphics.ocg/LightShader.glsl | 6 +-- src/landscape/C4LandscapeRender.cpp | 1 + src/landscape/fow/C4FoW.cpp | 3 +- src/landscape/fow/C4FoWDrawStrategy.cpp | 71 ++++++++++++++++++++----- src/landscape/fow/C4FoWDrawStrategy.h | 27 ++++++---- src/landscape/fow/C4FoWLight.cpp | 22 +------- src/landscape/fow/C4FoWLight.h | 2 + src/landscape/fow/C4FoWRegion.cpp | 15 +++--- 8 files changed, 92 insertions(+), 55 deletions(-) diff --git a/planet/Graphics.ocg/LightShader.glsl b/planet/Graphics.ocg/LightShader.glsl index 8d33ed10a..0cfd82c7f 100644 --- a/planet/Graphics.ocg/LightShader.glsl +++ b/planet/Graphics.ocg/LightShader.glsl @@ -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. diff --git a/src/landscape/C4LandscapeRender.cpp b/src/landscape/C4LandscapeRender.cpp index b5a412fcb..86cd69765 100644 --- a/src/landscape/C4LandscapeRender.cpp +++ b/src/landscape/C4LandscapeRender.cpp @@ -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); diff --git a/src/landscape/fow/C4FoW.cpp b/src/landscape/fow/C4FoW.cpp index 1dcddb629..5c57ad475 100644 --- a/src/landscape/fow/C4FoW.cpp +++ b/src/landscape/fow/C4FoW.cpp @@ -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(); diff --git a/src/landscape/fow/C4FoWDrawStrategy.cpp b/src/landscape/fow/C4FoWDrawStrategy.cpp index d66e458e0..ccb946d5b 100644 --- a/src/landscape/fow/C4FoWDrawStrategy.cpp +++ b/src/landscape/fow/C4FoWDrawStrategy.cpp @@ -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); } diff --git a/src/landscape/fow/C4FoWDrawStrategy.h b/src/landscape/fow/C4FoWDrawStrategy.h index 35f7bba70..feb051261 100644 --- a/src/landscape/fow/C4FoWDrawStrategy.h +++ b/src/landscape/fow/C4FoWDrawStrategy.h @@ -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 diff --git a/src/landscape/fow/C4FoWLight.cpp b/src/landscape/fow/C4FoWLight.cpp index 223aeb525..8becfea13 100644 --- a/src/landscape/fow/C4FoWLight.cpp +++ b/src/landscape/fow/C4FoWLight.cpp @@ -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); diff --git a/src/landscape/fow/C4FoWLight.h b/src/landscape/fow/C4FoWLight.h index 4b2dd6ef9..13ad58efa 100644 --- a/src/landscape/fow/C4FoWLight.h +++ b/src/landscape/fow/C4FoWLight.h @@ -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; } diff --git a/src/landscape/fow/C4FoWRegion.cpp b/src/landscape/fow/C4FoWRegion.cpp index 25434ae43..50dfd044b 100644 --- a/src/landscape/fow/C4FoWRegion.cpp +++ b/src/landscape/fow/C4FoWRegion.cpp @@ -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!