openclonk/src/landscape/fow/C4FoWDrawStrategy.h

191 lines
5.6 KiB
C++

/*
* OpenClonk, http://www.openclonk.org
*
* Copyright (c) 2014-2016, 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.
*/
#ifndef C4FOWDRAWSTRATEGY_H
#define C4FOWDRAWSTRATEGY_H
#include "C4ForbidLibraryCompilation.h"
#ifndef USE_CONSOLE
#include "graphics/C4DrawGL.h"
#include "graphics/C4Shader.h"
#include <list>
class C4FoWRegion;
class C4TargetFacet;
class C4FoWLight;
/** This class decomposes Triangle fans and quads into individual triangles.
* This is used to so that all FoW elements can be drawn as triangles in a
* single glDrawElements call. */
class C4FoWDrawTriangulator
{
public:
C4FoWDrawTriangulator();
void Fan();
void Quads();
void AddVertex();
void Reset();
const unsigned int* GetIndices() const { return &indices[0]; }
unsigned int GetNIndices() const { return indices.size(); }
private:
void FinishPrimitive();
enum Mode {
M_Fan,
M_Quads
};
std::vector<unsigned int> indices; // TODO should be GLuint?
unsigned int begin_vertices;
unsigned int cur_vertices;
Mode mode;
};
/** A C4FoWDrawStrategy is a connector to OpenGL calls used to draw the light.
C4FoWLight tells this class which part of the light should be drawn now
and subsequently pushes the vertices with the information whether a vertex
is light or dark.
This class is an abstract base class, it is up to the implementing classes
to actually draw anything here.*/
class C4FoWDrawStrategy
{
public:
C4FoWDrawStrategy() : phase(P_None) {}
virtual ~C4FoWDrawStrategy() {}
// Drawing phases
enum DrawPhase {
P_None,
P_Fan,
P_FanMaxed,
P_Fade,
P_Intermediate
} phase;
/** Called before each rendering pass */
virtual void Begin(const C4FoWRegion* region) = 0;
/** Called after each rendering pass */
/* TODO: shaders should be created in drawstrategy, but: make sure
* there is only one shader per class
* (static? but then when to clean up?). */
virtual void End(const StdProjectionMatrix&, const C4Shader& renderShader, const C4Shader& directionalRenderShader) { triangulator.Reset(); }
virtual void DrawLightVertex(float x, float y) { triangulator.AddVertex(); }
virtual void DrawDarkVertex(float x, float y) { triangulator.AddVertex(); }
/** Called before rendering the inner triangle fan (the area with 100% light) */
virtual void BeginFan() { triangulator.Fan(); phase = P_Fan; };
/** Called after rendering the inner triangle fan */
virtual void EndFan() { };
/** Called before rendering the triangle fan existnsion (100% light, maxed out normals) */
virtual void BeginFanMaxed() { triangulator.Quads(); phase = P_FanMaxed; };
/** Called after rendering the inner triangle fan */
virtual void EndFanMaxed() { };
/** Called before rendering the quads in which the light fades out */
virtual void BeginFade() { triangulator.Quads(); phase = P_Fade; };
/** Called after rendering the quads in which the light fades out */
virtual void EndFade() { };
/** Called before rendering the triangles that fill the space between the fadeout quads */
virtual void BeginIntermediateFade() { triangulator.Fan(); phase = P_Intermediate; };
/** Called after rendering the triangles that fill the space between the fadeout quads */
virtual void EndIntermediateFade() { };
protected:
C4FoWDrawTriangulator triangulator;
};
/** This draw strategy is the default draw strategy that draws the light
onto the given region. */
class C4FoWDrawLightTextureStrategy : public C4FoWDrawStrategy
{
public:
C4FoWDrawLightTextureStrategy(const C4FoWLight* light);
virtual ~C4FoWDrawLightTextureStrategy();
virtual void DrawLightVertex(float x, float y);
virtual void DrawDarkVertex(float x, float y);
virtual void Begin(const C4FoWRegion* region);
virtual void End(const StdProjectionMatrix&, const C4Shader& renderShader, const C4Shader& directionalRenderShader);
private:
void DrawVertex(float x, float y, bool shadeLight);
static const float C4FoWSmooth;
const C4FoWLight* light;
const C4FoWRegion* region;
struct Vertex {
float x, y; // position in upper half of texture
float r1, g1, b1, a1; // color for first pass
float r2, g2, b2, a2; // color for second pass
float r3, g3, b3, a3; // color for third pass
};
GLuint bo[2];
std::vector<Vertex> vertices;
unsigned int vbo_size;
unsigned int ibo_size;
unsigned int vaoids[3]; // Three VAOs for the three passes
};
/** This draw strategy is the debug draw strategy (press Ctrl+F7,...) that
draws a wireframe of the light triangles (except the inner fan, but you can
change that in the code below) directly onto the screen. */
class C4FoWDrawWireframeStrategy : public C4FoWDrawStrategy
{
public:
C4FoWDrawWireframeStrategy(const C4FoWLight* light, const C4TargetFacet *screen);
virtual ~C4FoWDrawWireframeStrategy();
// : light(light), screen(screen), vbo(0) {};
virtual void DrawLightVertex(float x, float y);
virtual void DrawDarkVertex(float x, float y);
virtual void Begin(const C4FoWRegion* region);
virtual void End(const StdProjectionMatrix&, const C4Shader& renderShader, const C4Shader& directionalRenderShader);
private:
struct Vertex {
float x, y;
float r, g, b, a;
};
void DrawVertex(Vertex& vertex);
const C4FoWLight* light;
const C4TargetFacet* screen;
GLuint bo[2];
GLuint ibo;
std::vector<Vertex> vertices;
unsigned int vbo_size;
unsigned int ibo_size;
unsigned int vaoid;
};
#endif
#endif