mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-11-24 16:16:14 +00:00
1033 lines
35 KiB
C++
1033 lines
35 KiB
C++
// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
|
|
// 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 <http://www.gnu.org/licenses/>.
|
|
|
|
#ifndef NL_LANDSCAPE_H
|
|
#define NL_LANDSCAPE_H
|
|
|
|
|
|
#include "nel/misc/types_nl.h"
|
|
#include "nel/misc/class_id.h"
|
|
#include "nel/misc/smart_ptr.h"
|
|
#include "nel/misc/triangle.h"
|
|
#include "nel/3d/zone.h"
|
|
#include "nel/3d/tile_bank.h"
|
|
#include "nel/3d/patch_rdr_pass.h"
|
|
#include "nel/3d/vertex_buffer.h"
|
|
#include "nel/3d/index_buffer.h"
|
|
#include "nel/3d/material.h"
|
|
#include "nel/3d/tile_far_bank.h"
|
|
#include "nel/3d/texture_near.h"
|
|
#include "nel/3d/quad_grid.h"
|
|
#include "nel/misc/block_memory.h"
|
|
#include "nel/3d/landscapevb_allocator.h"
|
|
#include "nel/3d/landscape_face_vector_manager.h"
|
|
#include "nel/3d/tess_face_priority_list.h"
|
|
#include "nel/3d/point_light_influence.h"
|
|
#include "nel/3d/shadow_poly_receiver.h"
|
|
|
|
#include <map>
|
|
|
|
#define NL_MAX_SIZE_OF_TEXTURE_EDGE_SHIFT (NL_MAX_TILES_BY_PATCH_EDGE_SHIFT+NL_NUM_PIXELS_ON_FAR_TILE_EDGE_SHIFT)
|
|
#define NL_MAX_SIZE_OF_TEXTURE_EDGE (1<<NL_MAX_SIZE_OF_TEXTURE_EDGE_SHIFT) // Size max of a far texture edge in pixel
|
|
|
|
|
|
namespace NL3D
|
|
{
|
|
|
|
|
|
class CHeightMap;
|
|
class CTileNoiseMap;
|
|
class CVegetableManager;
|
|
class CVegetable;
|
|
class CTileVegetableDesc;
|
|
class CScene;
|
|
class CTextureFar;
|
|
class CTextureDLM;
|
|
class CPatchDLMContextList;
|
|
class CShadowMap;
|
|
|
|
using NLMISC::Exception;
|
|
using NLMISC::CTriangle;
|
|
using NLMISC::CBlockMemory;
|
|
|
|
// ***************************************************************************
|
|
// The maximum amount of different tiles in world.
|
|
const sint NbTilesMax= 65536;
|
|
// Size of a CTextureNear. 256 by default (works everywhere).
|
|
// Texures must be square, because of uvscalebias...
|
|
const sint TextureNearSize= 512;
|
|
const sint NbTileLightMapByLine= TextureNearSize/NL_TILE_LIGHTMAP_SIZE;
|
|
const sint NbTileLightMapByTexture= NbTileLightMapByLine*NbTileLightMapByLine;
|
|
|
|
|
|
|
|
// ***************************************************************************
|
|
/**
|
|
* A landscape bind exception.
|
|
* \author Lionel Berenguier
|
|
* \author Nevrax France
|
|
* \date 2001
|
|
*/
|
|
struct EBadBind : public Exception
|
|
{
|
|
private:
|
|
mutable std::string _Output;
|
|
|
|
public:
|
|
struct CBindError
|
|
{
|
|
CBindError(sint z, sint p) {ZoneId= z; PatchId= p;}
|
|
sint ZoneId;
|
|
sint PatchId;
|
|
};
|
|
|
|
|
|
// The result list of bind errors.
|
|
std::list<CBindError> BindErrors;
|
|
|
|
public:
|
|
EBadBind() {}
|
|
~EBadBind() throw () {}
|
|
virtual const char *what() const throw();
|
|
|
|
};
|
|
|
|
|
|
struct ULandscapeTileCallback;
|
|
|
|
// ***************************************************************************
|
|
/**
|
|
* A landscape. Use CZone to build zone, and use landscape to dynamically add/remove them, for render.
|
|
*
|
|
* Limits:
|
|
* - 65535 zones max in whole world (16 bits ZoneId ).
|
|
* - 65535 patchs max by zone.
|
|
* - patch order 2x2 minimum.
|
|
* - patch order 16x16 maximum.
|
|
* - connectivity on a edge: 1/1, 1/2, or 1/4.
|
|
* - connectivity on a edge of a zone: 1/1 only.
|
|
* - The value of Noise amplitude is global and cannot go over 1 meter (+- 1m).
|
|
* Sorry, this is a FIXED (for ever) value which should NEVER change (because of Gfx database).
|
|
*
|
|
* If you use the tiles mapped on the patches, load the near bank file (.bank) and the far bank file (.farbank)
|
|
* by seralizing TileBank and TileFarBank with those files. Then call initTileBanks.
|
|
*
|
|
* \author Lionel Berenguier
|
|
* \author Nevrax France
|
|
* \date 2000
|
|
*/
|
|
class CLandscape : public NLMISC::CRefCount
|
|
{
|
|
public:
|
|
// The bank of tiles information. Each time you change the bank, you should call CLandscape::initTileBanks();
|
|
CTileBank TileBank;
|
|
CTileFarBank TileFarBank;
|
|
class CLandscapeModel *OwnerModel;
|
|
|
|
public:
|
|
|
|
/// Constructor
|
|
CLandscape();
|
|
/// Destructor. clear().
|
|
virtual ~CLandscape();
|
|
|
|
|
|
/// \name Init/Build.
|
|
// @{
|
|
/// init the landscape VBuffers, texture cache etc...
|
|
void init();
|
|
|
|
/** Add a zone which should be builded (or loaded), but not compiled. CLandscape compile it.
|
|
* The contents of newZone are copied into the landscape.
|
|
* \param newZone the new zone.
|
|
* \return true if OK, false otherwise. As example, Fail if newZone is already connected.
|
|
*/
|
|
bool addZone(const CZone &newZone);
|
|
|
|
/** remove a zone by its unique Id.
|
|
* The zone is release()-ed (disconnected), then deleted.
|
|
* \param zoneId the zone to be removed.
|
|
* \return true if OK, false otherwise. As example, Fail if zone is not connected.
|
|
*/
|
|
bool removeZone(uint16 zoneId);
|
|
|
|
/// Disconnect, and Delete all zones.
|
|
void clear();
|
|
|
|
/// Verify the binding of patchs of all zones. throw EBadBind if error.
|
|
void checkBinds() throw(EBadBind);
|
|
/// Verify the binding of patchs of one zone. throw EBadBind if error. nop if zone not loaded.
|
|
void checkBinds(uint16 zoneId) throw(EBadBind);
|
|
|
|
/**
|
|
* Build tileBank. Call this after loading the near and far tile banks.
|
|
*
|
|
* \return true if ok, false else. If false, far texture will be desactived.
|
|
*/
|
|
bool initTileBanks ();
|
|
// @}
|
|
|
|
|
|
/// \name Landscape Parameters.
|
|
// @{
|
|
/// Set tile near distance. Default 50.f. maximized to length of Far alpha transition).
|
|
void setTileNear (float tileNear);
|
|
/// Get tile near distance.
|
|
float getTileNear () const {return _TileDistNear;}
|
|
/// Set threshold for subdivsion quality. The lower is threshold, the more the landscape is subdivided. Default: 0.001.
|
|
void setThreshold (float thre);
|
|
/// Get threshold.
|
|
float getThreshold () const {return _Threshold;}
|
|
void setRefineMode(bool enabled) {_RefineMode= enabled;}
|
|
bool getRefineMode() const {return _RefineMode;}
|
|
/// Set Maximum Tile subdivision. Valid values must be in [0..4] (assert). Default is 0 (for now :) ).
|
|
void setTileMaxSubdivision (uint tileDiv);
|
|
/// Get Maximum Tile subdivision.
|
|
uint getTileMaxSubdivision ();
|
|
|
|
/// Enable the noise or not. NB: only new tesselation computed is modified, so you should call it only at init time.
|
|
void setNoiseMode(bool enabled);
|
|
bool getNoiseMode() const;
|
|
|
|
// invalidate all the tiles (force the tiles callbakc to be called again)
|
|
void invalidateAllTiles();
|
|
|
|
// Store it by landscape, and not only globally in CLandscapeGlobals statics.
|
|
// @}
|
|
|
|
|
|
/// \name Render methods.
|
|
// @{
|
|
/**
|
|
* A driver is needed for VB allocation. The VB will be allocated only the first time the landscape is clipped.
|
|
* Because no VB are created for invisible patchs.
|
|
* call setDriver() before any clip().
|
|
*/
|
|
void setDriver(IDriver *drv);
|
|
/** Clip the landscape according to frustum.
|
|
* Planes must be normalized.
|
|
*/
|
|
void clip(const CVector &refineCenter, const std::vector<CPlane> &pyramid);
|
|
/** Refine/Geomorph the tesselation of the landscape.
|
|
*/
|
|
void refine(const CVector &refineCenter);
|
|
/** Render the landscape.
|
|
* A more precise clip is made on TessBlocks. pyramid should be the same as one passed to clip().
|
|
* For optimisation, this pyramid should contains only the Left/Right and Top/Bottom clip planes, in this order.
|
|
* \param refineCenter should be the position of the camera
|
|
* \param frontVector should be the J vector of the camera
|
|
*/
|
|
void render(const CVector &refineCenter, const CVector &frontVector, const CPlane pyramid[NL3D_TESSBLOCK_NUM_CLIP_PLANE], bool doTileAddPass=false);
|
|
|
|
/// Refine/Geomorph ALL the tesselation of the landscape, from the view point refineCenter. Even if !RefineMode.
|
|
void refineAll(const CVector &refineCenter);
|
|
/// This is especially for Pacs. exlude a patch to be refineAll()ed.
|
|
void excludePatchFromRefineAll(sint zoneId, uint patch, bool exclude);
|
|
|
|
|
|
/** This is especially for Pacs. Each Vertex->EndPos which is not a corner of a patch
|
|
* is set to the mean of its 2 shared Patchs.
|
|
* NB: Works with special cases of rectangular patchs and binded patchs.
|
|
*/
|
|
void averageTesselationVertices();
|
|
|
|
// Profile at Current landscape state (nlinfos)
|
|
void profileRender();
|
|
|
|
// Get the Last refine pos setuped at refine();
|
|
const CVector &getOldRefineCenter() const {return _OldRefineCenter;}
|
|
|
|
// @}
|
|
|
|
|
|
/// \name Collision methods.
|
|
// @{
|
|
/** Build the set of faces of landscape, which are IN a bbox. Useful for collisions.
|
|
* The faces are builded at Tile level (2m*2m).
|
|
* \param bbox the bbox where faces are searched.
|
|
* \param faces the result of the build.
|
|
* \param faceSplit if true, Only faces which are IN or partialy IN the bbox are returned. Else the clipping is done
|
|
* on patch level. Worst, but faster.
|
|
*/
|
|
void buildCollideFaces(const CAABBoxExt &bbox, std::vector<CTriangle> &faces, bool faceSplit);
|
|
/** Build the set of faces of landscape, from a certain patch. Useful for collisions. Triangles are built first in S
|
|
* then T order. There is two triangles by tiles. So the number of triangles for a patch is 2*OrderS*OrderT.
|
|
*/
|
|
void buildCollideFaces(sint zoneId, sint patch, std::vector<CTriangle> &faces);
|
|
|
|
/** method relatively identical than buildCollideFaces(bbox....). Differences below:
|
|
* NB: this method use first a quadgrid to locate patchs of interest, then for each patch, it uses a
|
|
* convex hull subdivion to search in O(logn) what part of the patch to insert.
|
|
* \param bbox the bbox to test against. NB: you should modify your bbox according to heighfield.
|
|
* \param triangles array to be filled (array first cleared, then elements added).
|
|
* \param tileTessLevel 0,1 or 2 size of the triangles (2*2m, 1*1m or 0.5*0.5m). Level of subdivision of a tile.
|
|
*/
|
|
void buildTrianglesInBBox(const CAABBox &bbox, std::vector<CTrianglePatch> &triangles, uint8 tileTessLevel);
|
|
|
|
|
|
/** Same as buildTrianglesInBBox(), but fill blockId instead of raw triangles.
|
|
* NB: this method use first a quadgrid to locate patchs of interest, then for each patch, it uses a
|
|
* convex hull subdivion to search in O(logn) what part of the patch to insert.
|
|
* \param bbox the bbox to test against. NB: you should modify your bbox according to heighfield.
|
|
* \param paBlockIds array to be filled (no clear performed, elements added).
|
|
*/
|
|
void buildPatchBlocksInBBox(const CAABBox &bbox, std::vector<CPatchBlockIdent> &paBlockIds);
|
|
/** Fill a CPatchQuadBlock, from its required PatchId.
|
|
* nlassert(PatchId size is less than NL_PATCH_BLOCK_MAX_QUAD)
|
|
*/
|
|
void fillPatchQuadBlock(CPatchQuadBlock &quadBlock) const;
|
|
|
|
|
|
/** From the current tesselation of a patch of landscape, and a UV in this patch, return tesselated position.
|
|
* NB: return Null if patch not found.
|
|
*/
|
|
CVector getTesselatedPos(const CPatchIdent &patchId, const CUV &uv) const;
|
|
|
|
|
|
/** From the current tesselation of landscape, build the list of leaves faces.
|
|
* Warning: ptrs are only valid between 2 tesselation (2 calls of Scene::render() or 2 calls of refine*() etc...)
|
|
*/
|
|
void getTessellationLeaves(std::vector<const CTessFace*> &leaves) const;
|
|
|
|
/** Get the camera 3rd person collision against the TileFaces (ie only under approx 50 m)
|
|
* return a [0,1] value. 0 => collision at start. 1 => no collision.
|
|
* \param radius is the radius of the 'cylinder'
|
|
* \param cone if true, the object tested is a cone (radius goes to end)
|
|
*/
|
|
float getCameraCollision(const CVector &start, const CVector &end, float radius, bool cone);
|
|
|
|
/** Get the ray collision against the TileFaces (ie only under approx 50 m)
|
|
* return a [0,1] value. 0 => collision at start. 1 => no collision.
|
|
*/
|
|
float getRayCollision(const CVector &start, const CVector &end);
|
|
|
|
// @}
|
|
|
|
|
|
|
|
/// \name Accessors.
|
|
// @{
|
|
/** Get a zone pointer.
|
|
*
|
|
* \param zoneId the zone of the update.
|
|
* \return Return a zone pointer. NULL if the zone doesn't exist or isn't loaded.
|
|
*/
|
|
CZone* getZone (sint zoneId);
|
|
/** Get a zone pointer.
|
|
*
|
|
* \param zoneId the zone of the update.
|
|
* \return Return a zone pointer. NULL if the zone doesn't exist or isn't loaded.
|
|
*/
|
|
const CZone* getZone (sint zoneId) const;
|
|
/** Return list of zone loaded.
|
|
*/
|
|
void getZoneList(std::vector<uint16> &zoneIds) const;
|
|
/// From an Id, return the name of the zone, in the form "150_EM", without extension.
|
|
static void buildZoneName(sint zoneId, std::string &zoneName);
|
|
// @}
|
|
|
|
|
|
/// \name Tile mgt.
|
|
// @{
|
|
/// Force a range of tiles to be loaded in the driver...
|
|
void flushTiles(IDriver *drv, uint32 tileStart, uint32 nbTiles);
|
|
/** Force a range of tiles to be unloaded. You should call changePatchTextureAndColor() on all patch
|
|
* or ensure that all zones are deleted.
|
|
*/
|
|
void releaseTiles(uint32 tileStart, uint32 nbTiles);
|
|
/// Delete All tiles. All zones must be deleted before (nlassert)
|
|
void releaseAllTiles();
|
|
|
|
/// Return the texture for a tile Id. Useful for Tile edition.
|
|
NLMISC::CSmartPtr<ITexture> getTileTexture(uint16 tileId, CTile::TBitmap bitmapType, CVector &uvScaleBias);
|
|
|
|
/// Return the tile element for a patch at specific UV. Useful for getting surface data. Return NULL if not found.
|
|
CTileElement *getTileElement(const CPatchIdent &patchId, const CUV &uv);
|
|
// @}
|
|
|
|
/// \name Lighting.
|
|
// @{
|
|
/**
|
|
* Setup the light color use for static illumination.
|
|
*
|
|
* \param diffuse is the color of the diffuse componante of the lighting.
|
|
* \param ambiant is the color of the ambiante componante of the lighting.
|
|
* \param multiply is the multiply factor. Final color is (diffuse*multiply*shading+ambiant*(1.0-shading))
|
|
*/
|
|
void setupStaticLight (const CRGBA &diffuse, const CRGBA &ambiant, float multiply);
|
|
/**
|
|
* Get the light color by shading table.
|
|
*
|
|
* \return a CRGBA[256] array. It give the static light color for a shading value.
|
|
*/
|
|
const CRGBA* getStaticLight () const
|
|
{
|
|
return _LightValue;
|
|
}
|
|
|
|
|
|
/**
|
|
* Setup the equivalent material diffuse component used for both Static and Dynamic PointLights.
|
|
* Default is White.
|
|
*/
|
|
void setPointLightDiffuseMaterial(CRGBA diffuse);
|
|
/**
|
|
* \see setPointLightDiffuseMaterial
|
|
*/
|
|
CRGBA getPointLightDiffuseMaterial () const
|
|
{
|
|
return _PointLightDiffuseMaterial;
|
|
}
|
|
|
|
|
|
/**
|
|
* Enable automatic near lightmap computing. use setupStaticLight().
|
|
* Default is disabled.
|
|
* NB: calling this method won't flush all texture near already computed.
|
|
*/
|
|
void enableAutomaticLighting(bool enable);
|
|
/**
|
|
* For automatic near lightmap computing (if enabled): setup the lightdir
|
|
*
|
|
* \param lightDir is the direction of the light vector used for the lighting. NB: the vector is normalized.
|
|
*/
|
|
void setupAutomaticLightDir(const CVector &lightDir);
|
|
/// return true if AutomaticLighting is enabled.
|
|
bool getAutomaticLighting() const {return _AutomaticLighting;}
|
|
/// return the light direction setuped in enableAutomaticLighting().
|
|
const CVector &getAutomaticLightDir() const {return _AutomaticLightDir;}
|
|
|
|
|
|
/** This method remove all PointLights in all Zones, and hence reset TileLightInfluences.
|
|
*/
|
|
void removeAllPointLights();
|
|
|
|
|
|
/// update the Light factor for all pointLights in All zones, according to scene LightGroups and AnimatedLights.
|
|
void setPointLightFactor(const CScene &scene);
|
|
|
|
|
|
// To init lightmap information
|
|
void initAnimatedLightIndex(const CScene &scene);
|
|
|
|
|
|
// @}
|
|
|
|
|
|
/// \name HeightField DeltaZ.
|
|
// @{
|
|
/// return the HeightField DeltaZ for the 2D position. (0,0,dZ) is returned.
|
|
CVector getHeightFieldDeltaZ(float x, float y) const;
|
|
/** set the HeightField data. NB: take lot of place in memory.
|
|
* only one is possible. You should setup this heightfield around the zones which will be loaded.
|
|
* It is applied only when a zone is loaded, so you should setup it 2km around the user, each time you move too far
|
|
* from a previous place (eg 160m from last setup).
|
|
*/
|
|
void setHeightField(const CHeightMap &hf);
|
|
// @}
|
|
|
|
|
|
/// Micro-Vegetation.
|
|
// @{
|
|
|
|
/** init the vegetable layer models in the CScene (see CVegetableManager).
|
|
* NB: MOT stuff (called by CLandscapeModel), don't use it.
|
|
*/
|
|
void createVegetableBlendLayersModels(CScene *scene);
|
|
|
|
/** set the vegetable manager Time (in seconds)
|
|
* NB: MOT stuff (called by CLandscapeModel), don't use it.
|
|
*/
|
|
void setVegetableTime(double time);
|
|
|
|
/** set the vegetable manager System Time (in seconds) for update lighting
|
|
* NB: MOT stuff (called by CLandscapeModel), don't use it.
|
|
*/
|
|
void setVegetableUpdateLightingTime(double time);
|
|
|
|
|
|
/** enable the vegetable management in landscape. Valid only if VertexShader is OK.
|
|
* if true, register TileBank vegetables Shape to manager.
|
|
*/
|
|
void enableVegetable(bool enable);
|
|
|
|
/** return if the vegetable management is actually activated:
|
|
* actually return _VerexShaderOk && _VegetableEnabled.
|
|
*/
|
|
bool isVegetableActive() const;
|
|
|
|
/** load a texture for the vegetable, lookup in CPath
|
|
*/
|
|
void loadVegetableTexture(const std::string &textureFileName);
|
|
|
|
/** setup lighting ambient and diffuse for vegetable.
|
|
*/
|
|
void setupVegetableLighting(const CRGBA &ambient, const CRGBA &diffuse, const CVector &directionalLight);
|
|
|
|
/** set the vegetable Wind for animation.
|
|
* All thoses variables may be modified each frame without penalty.
|
|
*
|
|
* \param windDir is the direction of the wind. NB: only XY direction is kept.
|
|
* \param windFreq is the frequency for the animation (speed)
|
|
* \param windPower is the power of the wind, and is a factor (0..1) of Bend
|
|
* \param windBendMin is a value in (0..1) which indicate how much the vegetables are bended at minimum
|
|
* (for very powerfull wind)
|
|
*/
|
|
void setVegetableWind(const CVector &windDir, float windFreq, float windPower, float windBendMin);
|
|
|
|
|
|
/** return the number of faces displayed in Driver with the vegetable manager.
|
|
* Out CPrimitiveProfile::NTriangles displayed by vegetable part is returned.
|
|
*/
|
|
uint getNumVegetableFaceRendered() const;
|
|
|
|
|
|
/** set the frequency of Vegetable lighting update. If freq==1, ALL lighted igs are updated each second.
|
|
* e.g: if 1/20, then every 20 seconds, all Igs are updated.
|
|
* If you set 0, no update will be done at all (this is the default setup!!).
|
|
*/
|
|
void setVegetableUpdateLightingFrequency(float freq);
|
|
|
|
|
|
/** Debug purpose only : setup the colors of the patch of all the currently loaded zones
|
|
* so that it shows which tiles have vegetable disabled, or are above, below water.
|
|
* User provides a table with 4 colors for each state :
|
|
* color 0 = above water
|
|
* color 1 = underwater
|
|
* color 2 = intersect water
|
|
* color 3 = vegetable disabled
|
|
*/
|
|
void setupColorsFromTileFlags(const NLMISC::CRGBA colors[4]);
|
|
|
|
/** Set a density ratio [0, 1] to possibly reduce the amount of micro vegetable drawn. Default to 1
|
|
*/
|
|
void setVegetableDensity(float density);
|
|
|
|
/** Get the density ratio [0, 1] of micro vegetable drawn. Default to 1
|
|
*/
|
|
float getVegetableDensity() const;
|
|
|
|
// @}
|
|
|
|
|
|
/// \name Lightmap get interface.
|
|
// @{
|
|
|
|
/// Get the lumel under the position. return 255 if invalid patchId.
|
|
uint8 getLumel(const CPatchIdent &patchId, const CUV &uv) const;
|
|
|
|
/// Append lights under the position to pointLightList. Do nothing if invalid patchId.
|
|
void appendTileLightInfluences(const CPatchIdent &patchId, const CUV &uv,
|
|
std::vector<CPointLightInfluence> &pointLightList) const;
|
|
|
|
// @}
|
|
|
|
|
|
/// \name Precision ZBuffer mgt.
|
|
// @{
|
|
|
|
/** Set the ModelPosition (for Precision ZBuffer purpose). NB: the model Pos may be floor-ed
|
|
* (for greater float precision). Should be setup to the camera position each frame.
|
|
*
|
|
* NB: if vertexProgram is used, it is as faster as before (because of geomorph done each frame,
|
|
* and because of VP MAD instruction).
|
|
* NB: if vertexProgram is not used, it is a little slower, because of the substraction.
|
|
*/
|
|
void setPZBModelPosition(const CVector &pos);
|
|
|
|
/** \see setPZBModelPosition()
|
|
*/
|
|
const CVector &getPZBModelPosition() const {return _PZBModelPosition;}
|
|
|
|
// @}
|
|
|
|
|
|
/// \name UpdateLighting management
|
|
// @{
|
|
|
|
/** update the lighting of patch, within a certain amount of time.
|
|
* called by CLandscapeModel
|
|
*/
|
|
void updateLighting(double time);
|
|
|
|
/** set the frequency of lighting update. If freq==1, ALL patchs are updated each second.
|
|
* e.g: if 1/20, then every 20 seconds, all patchs are updated.
|
|
* If you set 0, no update will be done at all (this is the default setup!!).
|
|
*/
|
|
void setUpdateLightingFrequency(float freq);
|
|
|
|
/** update the lighting of ALL patch (slow method). NB: work even if UpdateLightingFrequency==0
|
|
* Additionaly, vegetables are also ALL updated.
|
|
*/
|
|
void updateLightingAll();
|
|
|
|
|
|
// @}
|
|
|
|
|
|
/// \name Dynamic Lighting management
|
|
// @{
|
|
|
|
/** Compute dynamic lightmaps
|
|
* \param pls list of pointLigths to influence landscape
|
|
*/
|
|
void computeDynamicLighting(const std::vector<CPointLight*> &pls);
|
|
|
|
/** For bench only. return approximate ammount of memory taken by dynamic lightmap in RAM.
|
|
* This is sizeof(global Texture in RAM) + all patchDLMContext.
|
|
* NB: not so slow, but do not call in final release.
|
|
*/
|
|
uint getDynamicLightingMemoryLoad() const;
|
|
|
|
/** Set PointLight Max Attenuation End landscape support. Every pointLight AttEnd is clamped to this value.
|
|
* Default is 30.f.
|
|
*/
|
|
void setDynamicLightingMaxAttEnd(float maxAttEnd);
|
|
|
|
/** see setDynamicLightingMaxAttEnd()
|
|
*/
|
|
float getDynamicLightingMaxAttEnd() const {return _DLMMaxAttEnd;}
|
|
|
|
/** For Vegetable Dynamic ligthing only: this is an approximate color of all vegetables.
|
|
* Default is (180, 180, 180).
|
|
*/
|
|
void setDLMGlobalVegetableColor(CRGBA gvc);
|
|
|
|
/** see setDLMGlobalVegetableColor()
|
|
*/
|
|
CRGBA getDLMGlobalVegetableColor() const {return _DLMGlobalVegetableColor;}
|
|
|
|
// @}
|
|
|
|
|
|
/// \name Dynamic ShadowMap
|
|
// @{
|
|
void receiveShadowMap(IDriver *drv, CShadowMap *shadowMap, const CVector &casterPos, const CMaterial &shadowMat, const CVector &pzb);
|
|
// @}
|
|
|
|
|
|
/// \name Tile added/removed callback
|
|
// @{
|
|
void addTileCallback(ULandscapeTileCallback *cb);
|
|
void removeTileCallback(ULandscapeTileCallback *cb);
|
|
bool isTileCallback(ULandscapeTileCallback *cb) const;
|
|
const std::vector<ULandscapeTileCallback *> &getTileCallbacks() const { return _TileCallbacks; }
|
|
// @}
|
|
|
|
// lockBuffers(), called by updateGlobalsAndLockBuffers().
|
|
void lockBuffers ();
|
|
// unlockBuffers. This is the END call for updateGlobalsAndLockBuffers().
|
|
void unlockBuffers (bool force = false);
|
|
// Check if buffers are locked
|
|
bool isLocked() const { return _LockCount != 0; }
|
|
|
|
// for advanced use (decal rendering)
|
|
CShadowPolyReceiver &getShadowPolyReceiver() { return _ShadowPolyReceiver; }
|
|
|
|
// modify ZBuffer test of landscape material
|
|
virtual void setZFunc(CMaterial::ZFunc val);
|
|
|
|
|
|
// ********************************
|
|
private:
|
|
// Private part used by CTessFace / CPatch / CZone.
|
|
friend class CTessFace;
|
|
friend class CPatch;
|
|
friend class CZone;
|
|
|
|
std::vector<ULandscapeTileCallback *> _TileCallbacks;
|
|
|
|
/// \name Allocators.
|
|
// @{
|
|
|
|
CBlockMemory<CTessFace> TessFaceAllocator;
|
|
CBlockMemory<CTessVertex> TessVertexAllocator;
|
|
CBlockMemory<CTessNearVertex> TessNearVertexAllocator;
|
|
CBlockMemory<CTessFarVertex> TessFarVertexAllocator;
|
|
CBlockMemory<CTileMaterial> TileMaterialAllocator;
|
|
CBlockMemory<CTileFace> TileFaceAllocator;
|
|
|
|
CTessFace *newTessFace();
|
|
CTessVertex *newTessVertex();
|
|
CTessNearVertex *newTessNearVertex();
|
|
CTessFarVertex *newTessFarVertex();
|
|
CTileMaterial *newTileMaterial();
|
|
CTileFace *newTileFace();
|
|
|
|
void deleteTessFace(CTessFace *f);
|
|
void deleteTessVertex(CTessVertex *v);
|
|
void deleteTessNearVertex(CTessNearVertex *v);
|
|
void deleteTessFarVertex(CTessFarVertex *v);
|
|
void deleteTileMaterial(CTileMaterial *tm);
|
|
void deleteTileFace(CTileFace *tf);
|
|
|
|
// Allocator of FaceVector for allocation of packed triangles indices.
|
|
CLandscapeFaceVectorManager _FaceVectorManager;
|
|
// This is not a valid TessBlock. But it is used as a Root for modification list.
|
|
// Can't use a ptr, because of ~CTessBlock().
|
|
CTessBlock _TessBlockModificationRoot;
|
|
// @}
|
|
|
|
|
|
// Return the render pass for a far texture here.
|
|
CPatchRdrPass *getFarRenderPass(CPatch* pPatch, uint farIndex, float& far1UScale, float& far1VScale, float& far1UBias, float& far1VBias, bool& bRot);
|
|
// Free the render pass for a far texture here.
|
|
void freeFarRenderPass (CPatch* pPatch, CPatchRdrPass* pass, uint farIndex);
|
|
// Return the render pass for a tile Id, and a patch Lightmap.
|
|
CPatchRdrPass *getTileRenderPass(uint16 tileId, bool additiveRdrPass);
|
|
// Return the UvScaleBias for a tile Id. uv.z has the scale info. uv.x has the BiasU, and uv.y has the BiasV.
|
|
// if bitmap type is CTile::alpha, Return also the additionla rot for alpha (else 0).
|
|
void getTileUvScaleBiasRot(uint16 tileId, CTile::TBitmap bitmapType, CVector &uvScaleBias, uint8 &rotAlpha);
|
|
|
|
// release Far render pass/reset Tile/Far render. Delete also VB, and FaceVectors
|
|
void resetRenderFarAndDeleteVBFV();
|
|
/// For changing TileMaxSubdivision. force tesselation to be under tile.
|
|
void forceMergeAtTileLevel();
|
|
|
|
// Update globals value to CTessFace, and lock Buffers if possible.
|
|
void updateGlobalsAndLockBuffers (const CVector &refineCenter);
|
|
// update TheFaceVector for which the faces may have been modified during refine(), refineAll() etc....
|
|
void updateTessBlocksFaceVector();
|
|
|
|
|
|
// System: update UL links, but don't call _TextureFars.erase()
|
|
void clearFarRenderPass (CPatchRdrPass* pass);
|
|
|
|
|
|
private:
|
|
TZoneMap Zones;
|
|
|
|
// Parameters.
|
|
float _TileDistNear;
|
|
float _Threshold;
|
|
bool _RefineMode;
|
|
float _FarTransition;
|
|
uint _TileMaxSubdivision;
|
|
// For VertexProgram. true if change has occured in threshold since the last render().
|
|
float _VPThresholdChange;
|
|
|
|
/// \name VertexBuffer mgt.
|
|
// @{
|
|
CRefPtr<IDriver> _Driver;
|
|
CLandscapeVBAllocator _Far0VB;
|
|
CLandscapeVBAllocator _Far1VB;
|
|
CLandscapeVBAllocator _TileVB;
|
|
uint _LockCount; // Lock counter
|
|
// True if we can compute Geomorph and Alpha with VertexShader.
|
|
bool _VertexShaderOk;
|
|
// For CZone::refreshTesselationGeometry().
|
|
bool _RenderMustRefillVB;
|
|
// @}
|
|
|
|
|
|
// Tiles Types.
|
|
//=============
|
|
// Texture Map. Use a RefPtr because TileTextureMap must not reference the object, but the ptr.
|
|
typedef NLMISC::CRefPtr<ITexture> RPTexture;
|
|
typedef std::map<std::string, RPTexture> TTileTextureMap;
|
|
typedef TTileTextureMap::iterator ItTileTextureMap;
|
|
// RdrPass Set.
|
|
typedef std::set<CPatchRdrPass> TTileRdrPassSet;
|
|
typedef TTileRdrPassSet::iterator ItTileRdrPassSet;
|
|
typedef NLMISC::CSmartPtr<CPatchRdrPass> TSPRenderPass;
|
|
|
|
// The additional realtime structure for a tile.
|
|
struct CTileInfo
|
|
{
|
|
// NB: CSmartPtr are not used for simplicity, and because of TTileRdrPassSet...
|
|
// CPatchRdrPass::RefCount are excplictly incremented/decremented...
|
|
// The rdrpass for diffuse+Alpha material.
|
|
CPatchRdrPass *DiffuseRdrPass;
|
|
// The rdrpass for additive material (may be NULL if no additive part).
|
|
CPatchRdrPass *AdditiveRdrPass;
|
|
// The scale/Bias to access those tiles in the big texture.
|
|
// uv.z has the scale info. uv.x has the BiasU, and uv.y has the BiasV.
|
|
// Manages the demi-texel on tile border too.
|
|
CVector DiffuseUvScaleBias;
|
|
CVector AlphaUvScaleBias;
|
|
CVector AdditiveUvScaleBias;
|
|
// The additional rotation for this tile, in alpha.
|
|
uint8 RotAlpha;
|
|
};
|
|
|
|
|
|
// Tiles Data.
|
|
//=============
|
|
// The map of tile texture loaded.
|
|
TTileTextureMap TileTextureMap;
|
|
// The set of tile Rdr Pass.
|
|
TTileRdrPassSet TileRdrPassSet;
|
|
// The parrallel array of tile of those existing in TileBank. size of NbTilesMax.
|
|
std::vector<CTileInfo*> TileInfos;
|
|
// The Lightmap rdrpass for tiles.
|
|
// must have a vector of pointer, because of vector reallocation.
|
|
std::vector<TSPRenderPass> _TextureNears;
|
|
uint _NFreeLightMaps;
|
|
|
|
|
|
// The Tile material.
|
|
CMaterial TileMaterial;
|
|
|
|
// The Far material.
|
|
CMaterial FarMaterial;
|
|
|
|
|
|
// *** Far texture
|
|
|
|
// ** Some types
|
|
|
|
// The vector of far render pass
|
|
// must have a vector of pointer, because of vector reallocation.
|
|
typedef std::vector<TSPRenderPass>::iterator ItSPRenderPassVector;
|
|
std::vector<TSPRenderPass> _TextureFars;
|
|
bool _FarInitialized;
|
|
|
|
// Used internaly by initTileBanks
|
|
bool eraseTileFarIfNotGood (uint tileNumber, uint sizeOrder0, uint sizeOrder1, uint sizeOrder2);
|
|
|
|
// *** Lighting
|
|
CRGBA _LightValue[256];
|
|
|
|
bool _AutomaticLighting;
|
|
CVector _AutomaticLightDir;
|
|
|
|
private:
|
|
// Internal only. Force load of the tile (with TileBank).
|
|
void loadTile(uint16 tileId);
|
|
void releaseTile(uint16 tileId);
|
|
ITexture *findTileTexture(const std::string &textName, bool clamp);
|
|
CPatchRdrPass *findTileRdrPass(const CPatchRdrPass &pass);
|
|
|
|
// Tile LightMap mgt. NB: a lightmap is now a 2x2 tiles lightmap (10x10 pixels).
|
|
// @{
|
|
// Compute and get a lightmapId/lightmap renderpass.
|
|
// lightmap returned is to be uses with getTileRenderPass(). The id returned must be stored.
|
|
uint getTileLightMap(CRGBA map[NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE], CPatchRdrPass *&lightmapRdrPass);
|
|
// tileLightMapId must be the id returned by getTileLightMap().
|
|
void getTileLightMapUvInfo(uint tileLightMapId, CVector &uvScaleBias);
|
|
// tileLightMapId must be the id returned by getTileLightMap().
|
|
void releaseTileLightMap(uint tileLightMapId);
|
|
|
|
// refill a lightmap already computed. tileLightMapId must be the id returned by getTileLightMap().
|
|
void refillTileLightMap(uint tileLightMapId, CRGBA map[NL_TILE_LIGHTMAP_SIZE*NL_TILE_LIGHTMAP_SIZE]);
|
|
|
|
// @}
|
|
|
|
|
|
// check a zone, adding error to exception.
|
|
void checkZoneBinds(CZone &curZone, EBadBind &bindError);
|
|
|
|
|
|
/** A Bezier patch of One value only.
|
|
* NB: unlike CBezierPatch, layout is inverted on Y. (NB: same formulas...)
|
|
*/
|
|
struct CBezierPatchZ
|
|
{
|
|
/// The vertices a,b,c,d of the quad patch.
|
|
float Vertices[4];
|
|
/// The tangents ab, ba, bc, cb, cd, dc, da, ad. NB: tangents are points, not vectors.
|
|
float Tangents[8];
|
|
/// The interiors, ia,ib,ic,id. NB: interiors are points, not vectors.
|
|
float Interiors[4];
|
|
|
|
/// make default Interiors, according to Vertices and Tangents.
|
|
void makeInteriors();
|
|
/// Evaluate.
|
|
float eval(float s, float t) const; // s,t coordinates for quad.
|
|
};
|
|
|
|
|
|
// HeightFields.
|
|
struct CHeightField
|
|
{
|
|
std::vector<CBezierPatchZ> ZPatchs;
|
|
|
|
/// The origin of the bottom-left corner of this heightmap.
|
|
float OriginX, OriginY;
|
|
/// The size of one Element ot this HeightMap (eg: 160x160 for a zone).
|
|
float SizeX, SizeY;
|
|
float OOSizeX, OOSizeY;
|
|
/// The size of this array. Heights.size
|
|
uint Width, Height;
|
|
};
|
|
CHeightField _HeightField;
|
|
|
|
|
|
/// \name Visual Collision system.
|
|
// @{
|
|
|
|
// A CPatchIdent, with a ptr to the compiled CPatch
|
|
struct CPatchIdentEx : public CPatchIdent
|
|
{
|
|
const CPatch *Patch;
|
|
};
|
|
|
|
/// The QuadGrid of patch.
|
|
CQuadGrid<CPatchIdentEx> _PatchQuadGrid;
|
|
static const uint _PatchQuadGridSize;
|
|
static const float _PatchQuadGridEltSize;
|
|
|
|
/** This method search only on the given patch.
|
|
* NB: this method use a convex hull subdivion to search in O(logn) what part of the patch to insert.
|
|
* \param bbox the bbox to test against.
|
|
* \param triangles array to be filled (no clear performed, elements added).
|
|
* \param tileTessLevel 0,1 or 2 size of the triangles (2*2m, 1*1m or 0.5*0.5m). Level of subdivision of a tile.
|
|
*/
|
|
void addTrianglesInBBox(const CPatchIdentEx &paIdEx, const CAABBox &bbox, std::vector<CTrianglePatch> &triangles, uint8 tileTessLevel) const;
|
|
|
|
/** private version of buildPatchBlocksInBBox, searching only for one patch.
|
|
*/
|
|
void addPatchBlocksInBBox(const CPatchIdentEx &paIdEx, const CAABBox &bbox, std::vector<CPatchBlockIdent> &paBlockIds);
|
|
// @}
|
|
|
|
|
|
/// Noise Geometry.
|
|
// @{
|
|
// guess.
|
|
bool _NoiseEnabled;
|
|
// @}
|
|
|
|
|
|
/// Priority list.
|
|
// @{
|
|
/// The priority list of faces which may need to split
|
|
CTessFacePriorityList _SplitPriorityList;
|
|
/// The priority list of faces which may need to merge
|
|
CTessFacePriorityList _MergePriorityList;
|
|
/// OldRefineCenter setuped in prec refine()
|
|
CVector _OldRefineCenter;
|
|
bool _MustRefineAllAtNextRefine;
|
|
/// newTessFace() append the face to _RootNewLeaves.
|
|
CTessFacePListNode _RootNewLeaves;
|
|
// @}
|
|
|
|
|
|
/// Micro-Vegetation.
|
|
// @{
|
|
/// The VegetableManager. (ptr only for include speed).
|
|
CVegetableManager *_VegetableManager;
|
|
|
|
/// Tells if the Vegetable Managemnt is enabled.
|
|
bool _VegetableManagerEnabled;
|
|
/// Tells if the current driver support vegetable.
|
|
bool _DriverOkForVegetable;
|
|
|
|
/// List of VegetableBlock, to be tested for creation each frame.
|
|
CTessList<CLandscapeVegetableBlock> _VegetableBlockList;
|
|
|
|
/** For a given tile Id, look into tileSet, and get the tile vegetable descriptor
|
|
* \param tileId the tile [0..65535] to get the list of vegetable to create.
|
|
*/
|
|
const CTileVegetableDesc &getTileVegetableDesc(uint16 tileId);
|
|
|
|
// @}
|
|
|
|
|
|
/// \name Precision ZBuffer mgt.
|
|
// @{
|
|
/** \see setPZBModelPosition()
|
|
*/
|
|
CVector _PZBModelPosition;
|
|
// @}
|
|
|
|
|
|
/// \name UpdateLighting management
|
|
// @{
|
|
// Last update time.
|
|
double _ULPrecTime;
|
|
bool _ULPrecTimeInit;
|
|
double _ULTime;
|
|
/// Frequency of update.
|
|
float _ULFrequency;
|
|
|
|
|
|
/// Far UpdateLighting.
|
|
sint _ULTotalFarPixels;
|
|
/// Current number of far pixels to update. If negative, I have some advance.
|
|
float _ULFarPixelsToUpdate;
|
|
/// The current TextureFar rendered.
|
|
CTextureFar *_ULRootTextureFar;
|
|
|
|
|
|
/// Near UpdateLighting.
|
|
sint _ULTotalNearPixels;
|
|
/// Current number of near pixels to update. If negative, I have some advance.
|
|
float _ULNearPixelsToUpdate;
|
|
/// The current patch rendered.
|
|
CPatch *_ULRootNearPatch;
|
|
/// Current tessBlock id in the current patch processed
|
|
uint _ULNearCurrentTessBlockId;
|
|
|
|
/// Used by Patch to link/unlink from _ULRootNearPatch
|
|
void linkPatchToNearUL(CPatch *patch);
|
|
void unlinkPatchFromNearUL(CPatch *patch);
|
|
|
|
|
|
/// Update All Far texture, given a ratio along total lumels
|
|
void updateLightingTextureFar(float ratio);
|
|
/// Update All Near texture, given a ratio along total lumels
|
|
void updateLightingTextureNear(float ratio);
|
|
|
|
|
|
// @}
|
|
|
|
|
|
/// \name DynamicLighting management
|
|
// @{
|
|
/// The dynamic lightmap Texture.
|
|
NLMISC::CSmartPtr<ITexture> _TextureDLM;
|
|
/// for CPatch.
|
|
CTextureDLM *getTextureDLM() const {return (CTextureDLM*)(ITexture*)_TextureDLM;}
|
|
/// List of DLM Context.
|
|
CPatchDLMContextList *_PatchDLMContextList;
|
|
/// for CPatch.
|
|
CPatchDLMContextList *getPatchDLMContextList() const {return _PatchDLMContextList;}
|
|
/// Max AttEnd
|
|
float _DLMMaxAttEnd;
|
|
|
|
/// an approximate value used to simulate diffuse material of vegetables
|
|
CRGBA _DLMGlobalVegetableColor;
|
|
|
|
/// The diffuse material of landscape, used for StaticPointLights and DynamicPointLights
|
|
CRGBA _PointLightDiffuseMaterial;
|
|
|
|
// @}
|
|
|
|
|
|
/// \name Dynamic ShadowMap
|
|
// @{
|
|
CShadowPolyReceiver _ShadowPolyReceiver;
|
|
void appendToShadowPolyReceiver(CTessFace *face);
|
|
void removeFromShadowPolyReceiver(CTessFace *face);
|
|
// @}
|
|
|
|
/// \name Texture Profiling
|
|
// @{
|
|
NLMISC::CSmartPtr<ITexture::CTextureCategory> _TextureTileCategory;
|
|
NLMISC::CSmartPtr<ITexture::CTextureCategory> _TextureFarCategory;
|
|
NLMISC::CSmartPtr<ITexture::CTextureCategory> _TextureNearCategory;
|
|
// @}
|
|
|
|
};
|
|
|
|
|
|
|
|
} // NL3D
|
|
|
|
|
|
#endif // NL_LANDSCAPE_H
|
|
|
|
/* End of landscape.h */
|