// Ryzom - MMORPG Framework
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see .
#ifndef CL_LANDSCAPE_POLY_DRAWER_H
#define CL_LANDSCAPE_POLY_DRAWER_H
// Misc
#include "nel/misc/aabbox.h"
#include "nel/misc/polygon.h"
#include "nel/misc/singleton.h"
// 3D
#include "nel/3d/index_buffer.h"
#include "nel/3d/vertex_buffer.h"
//-----------------------------------------------------------------------------------------------------------
//---------------------------------------- CInitStencil -----------------------------------------------------
//-----------------------------------------------------------------------------------------------------------
// CInitStencil inherits from the abstract NEL class ILandscapePolyDrawingCallback, attribut of UScene.
// An instance of CInitStencil is initialized at the time of CLandscapePolyDrawer initialization
// and passed to current scene. Thus, when stencil operation must be modified in a NEL class,
// this instance is used with its callbacks without any NEL class knows CLandscapePolyDrawer class.
//-----------------------------------------------------------------------------------------------------------
class CInitStencil : public NL3D::ILandscapePolyDrawingCallback
{
public:
// This instance is passed to current scene as its ILandscapePolyDrawingCallback instance.
// (UScene::setLandscapePolyDrawingCallback is called)
void init();
private:
// from NL3D::ILandscapePolyDrawingCallback
// This method is called before landscape render to modify stencil operation.
// The eighth bit will be written with a 1 during next render. Thus we will differentiate stencil buffer parts
// which will support Shadow Volume algorithm (landscape) and the other parts (veget...)
virtual void beginPolyDrawing();
// from NL3D::ILandscapePolyDrawingCallback
// This method is called after landscape render and before veget render to modify back stencil operation.
// The eighth bit will be again written with a 0 during next render.
virtual void endPolyDrawing();
};
//-----------------------------------------------------------------------------------------------------------
//---------------------------------- CLandscapePolyDrawer ---------------------------------------------------
//-----------------------------------------------------------------------------------------------------------
// CLandscapePolyDrawer class manages display of a polygonal zones group, thanks to a Robust Shadow Volume algorithm.
// To avoid intersection between a shadow volume and the frustum, the "Far" plane of this one is pushed back
// to infinity during shadow volume display.
// To a best robustness and to join depth range [depthMin, depthMax] used in display of main scene, an epsilon
// factor is calculated to transpose Z buffer values from [depthMin, 1] to [depthMin, depthMax]
// while in [depthMin, 1] depth range is used during shadow volume display.
//-----------------------------------------------------------------------------------------------------------
class CLandscapePolyDrawer : public NLMISC::CSingleton
{
public:
// Constructor
CLandscapePolyDrawer();
// Destructor
~CLandscapePolyDrawer();
// At every frame, polygons list is intialized and filled with addPloy calls.
void addPoly(const NLMISC::CPolygon2D &poly, const NLMISC::CRGBA & color, const NLMISC::CAABBox & bBox);
// At every frame end, polygons list is released. This allows an easy management to dynamic destructions,
// addition or modifications of polygons.
void deletePolygons();
// Compute bbox of enclosed patch of a landscape from a delimiting 2D polygon.
static void computeBBoxFromPolygon(const NLMISC::CPolygon2D &poly2D, NLMISC::CAABBox &destBBox);
// Called to initialize ILandscapePolyDrawingCallback instance of current scene with _InitStencil attribut.
void initLandscapePolyDrawingCallback();
private:
// renderScene is called in main loop. It can called beginRenderLandscapePolyPart and renderLandscapePolyPart
// methods.
friend void beginRenderScene();
friend void drawRenderScene(bool wantTraversals, bool keepTraversals);
friend void endRenderScene(bool keepTraversals);
// Enable stencil test and initialize function and operation of stencil at the beginning of renderScene method,
// before opaque render of canopy and main scene parts.
// The eighth bit will be written with a 0 during next render to mark stencil buffer parts which will
// support Shadow Volume algorithm.
void beginRenderLandscapePolyPart();
// Render polygons after opaque render of canopy and main scene parts and before transparency parts render.
// ZFail algorithm is only applied to stencil buffer parts whose eighth bit is equal to 1
// (avoid to color vegetation)
void renderLandscapePolyPart();
// Build vertex and index buffer of the associated polygon when addPloy is called.
// Vertices coordinates aren't calculated immediately but in drawShadowVolume method,
// because they are calculated in camera location.
void buildShadowVolume(uint poly);
// Render shadow volume of a polygon (color and depth buffers updates are disable).
// This method is called twice durong the both passes of ZFail algorithm.
// Coordinates of shadow volume vertex buffer are calculated in first pass.
void drawShadowVolume(uint poly, bool firstPass);
// Render polygon by displaying a quad which covers all zone delimited by scissor test.
// This quad is applied only to stencil buffer parts whose 7 last bits aren't equal to 0,
// thus the polygon projection on lanscape is delimited.
void drawPolygon(uint poly);
// Setup an infinite frustum and a [0, 1] depth range in a way Z Buffer values coincide
// with those of main scene with the depth range of main scene.
void infiniteFrustum();
// Setup initial projection matrix and depth range
void finiteFrustum();
// Setup scissor delimitation for polygon
void setScissor(uint polyId);
// This callback allows to setup stencil operation before and after vegetables and shadow render,
// in order to separate them of landscape stencil buffer values.
CInitStencil * _InitStencil;
// Vectors of polygons and their respective barycenters, colors, bounding boxes,
// vertex and index buffers.
std::vector _Polygons;
std::vector _Barycenters;
std::vector _PolyColor;
std::vector _BBoxes;
std::vector _PolyVB;
std::vector _PolyIB;
// Quad used to display polygons on marked parts of stencil buffer.
NLMISC::CQuad _Shadow;
// Initial frustum used before shadow volumes display and stored to reset old values at the end of this display.
NL3D::CFrustum _FiniteFrustum;
// Max depth range used before shadow volumes display and stored to reset old values back at the end of this display.
float _MaxDepthRange;
// View matrix used before shadow volumes display and stored to reset old values at the end of this display.
NLMISC::CMatrix _OldViewMatrix;
};
#endif