forked from Mirrors/openclonk
Compare commits
1 Commits
master
...
alternate-
Author | SHA1 | Date |
---|---|---|
Peter Wortmann | 88c33aa629 |
|
@ -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.
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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();
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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);
|
||||
|
|
|
@ -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; }
|
||||
|
||||
|
|
|
@ -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!
|
||||
|
|
Loading…
Reference in New Issue