openclonk/src/landscape/fow/C4FoWDrawStrategy.cpp

158 lines
4.1 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2014-2015, The OpenClonk Team and contributors
*
* Distributed under the terms of the ISC license; see accompanying file
* "COPYING" for details.
*
* "Clonk" is a registered trademark of Matthes Bender, used with permission.
* See accompanying file "TRADEMARK" for details.
*
* To redistribute this file separately, substitute the full license texts
* for the above references.
*/
#include "C4Include.h"
#ifndef USE_CONSOLE
#include "C4FoWDrawStrategy.h"
#include "C4FoWLight.h"
#include "C4FoWRegion.h"
#include "C4DrawGL.h"
void C4FoWDrawLightTextureStrategy::Begin(int32_t passPar)
{
pass = passPar;
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
// Set up blend equation, see C4FoWDrawLightTextureStrategy::DrawVertex
// for details.
if(pass == 0)
{
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);
}
}
void C4FoWDrawLightTextureStrategy::End(int32_t pass)
{
glBlendEquation( GL_FUNC_ADD );
}
void C4FoWDrawLightTextureStrategy::DrawVertex(float x, float y, bool shadow)
{
// 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)
glColor3f(0.0f, 0.5f/1.5f, 0.5f/1.5f);
else if (shadow)
{
float dx = x - light->getX();
float dy = y - light->getY();
float dist = sqrt(dx*dx+dy*dy);
float bright = light->getBrightness();
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;
glColor3f(bright, normX, normY);
}
else
glColor3f(0.0f, 0.5f/1.5f, 0.5f/1.5f);
// global coords -> region coords
x += -region->getRegion().x;
y += -region->getRegion().y;
glVertex2f(x,y);
}
void C4FoWDrawLightTextureStrategy::DrawDarkVertex(float x, float y)
{
DrawVertex(x,y, false);
}
void C4FoWDrawLightTextureStrategy::DrawLightVertex(float x, float y)
{
DrawVertex(x,y, true);
}
void C4FoWDrawWireframeStrategy::Begin(int32_t pass)
{
glPolygonMode( GL_FRONT_AND_BACK, GL_LINE );
}
void C4FoWDrawWireframeStrategy::End(int32_t pass)
{
glPolygonMode( GL_FRONT_AND_BACK, GL_FILL );
glBlendEquation( GL_FUNC_ADD );
}
void C4FoWDrawWireframeStrategy::DrawVertex(float x, float y)
{
// global coords -> screen pos and zoom
x += screen->X - screen->TargetX;
y += screen->Y - screen->TargetY;
pGL->ApplyZoom(x,y);
glVertex2f(x,y);
}
void C4FoWDrawWireframeStrategy::DrawDarkVertex(float x, float y)
{
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)
{
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);
}
#endif