655 lines
14 KiB
C++
655 lines
14 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_BUILD_SURF_H
|
|
#define NL_BUILD_SURF_H
|
|
|
|
#include <vector>
|
|
|
|
#include "nel/misc/debug.h"
|
|
#include "nel/misc/file.h"
|
|
|
|
#include "nel/3d/zone.h"
|
|
#include "nel/3d/patch.h"
|
|
#include "nel/3d/mesh.h"
|
|
#include "nel/3d/landscape.h"
|
|
|
|
#include "nel/3d/quad_tree.h"
|
|
#include "nel/3d/quad_grid.h"
|
|
|
|
#include "nel/misc/vector.h"
|
|
#include "nel/misc/aabbox.h"
|
|
#include "nel/misc/geom_ext.h"
|
|
#include "nel/misc/polygon.h"
|
|
|
|
#include "nel/../../src/pacs/surface_quad.h"
|
|
#include "nel/../../src/pacs/retrievable_surface.h"
|
|
|
|
#include "prim_checker.h"
|
|
|
|
|
|
|
|
extern std::string OutputRootPath;
|
|
extern std::string OutputDirectory;
|
|
extern std::string OutputPath;
|
|
extern std::string TessellationPath;
|
|
extern std::string IGBoxes;
|
|
extern uint TessellateLevel;
|
|
extern bool ReduceSurfaces;
|
|
extern bool SmoothBorders;
|
|
extern bool ComputeElevation;
|
|
extern bool ComputeLevels;
|
|
extern std::vector<std::string> ZoneNames;
|
|
extern std::string ZoneExt;
|
|
extern std::string ZoneNHExt;
|
|
extern std::string ZoneLookUpPath;
|
|
|
|
extern bool ProcessAllPasses;
|
|
extern bool CheckPrims;
|
|
extern bool TessellateZones;
|
|
extern bool MoulineZones;
|
|
extern bool TessellateAndMoulineZones;
|
|
extern bool ProcessRetrievers;
|
|
extern std::string PreprocessDirectory;
|
|
|
|
extern float WaterThreshold;
|
|
|
|
extern bool UseZoneSquare;
|
|
extern std::string ZoneUL;
|
|
extern std::string ZoneDR;
|
|
|
|
extern std::string GlobalRetriever;
|
|
extern std::string RetrieverBank;
|
|
extern std::string GlobalUL;
|
|
extern std::string GlobalDR;
|
|
extern bool ProcessGlobal;
|
|
extern bool Verbose;
|
|
extern bool CheckConsistency;
|
|
|
|
extern CPrimChecker PrimChecker;
|
|
|
|
std::string getZoneNameById(uint16 id);
|
|
uint16 getZoneIdByName(std::string &name);
|
|
NLMISC::CAABBox getZoneBBoxById(uint16 id);
|
|
uint16 getZoneIdByPos(NLMISC::CVector &pos);
|
|
NL3D::CMesh *generateMeshFromBBox(const NLMISC::CAABBox &bbox, NLMISC::CRGBA color = NLMISC::CRGBA(255, 128, 0));
|
|
|
|
namespace NLPACS
|
|
{
|
|
|
|
class CSurfElement;
|
|
class CComputableSurfaceBorder;
|
|
class CComputableSurface;
|
|
class CPatchTessellation;
|
|
class CZoneTessellation;
|
|
|
|
|
|
|
|
/**/
|
|
|
|
const sint32 UnaffectedSurfaceId = -1;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* CSurfElement is an element of an iso-criteria surface. It is basically a CTriangle, and
|
|
* contains the various criteria values such as incline class, landscape material ...
|
|
* \author Benjamin Legros
|
|
* \author Nevrax France
|
|
* \date 2001
|
|
*/
|
|
class CSurfElement
|
|
{
|
|
public:
|
|
/**
|
|
*
|
|
*/
|
|
uint32 ElemId;
|
|
|
|
/**
|
|
* The support of the surface element.
|
|
* The index to the 3 vertices of the triangle.
|
|
*/
|
|
uint32 Tri[3];
|
|
|
|
/**
|
|
* The element normal vector
|
|
*/
|
|
NLMISC::CVector Normal;
|
|
|
|
/**
|
|
* The area of the element
|
|
*/
|
|
float Area;
|
|
|
|
/**
|
|
* The zone id
|
|
*/
|
|
uint16 ZoneId;
|
|
|
|
/**
|
|
* The tessellation vertices
|
|
*/
|
|
std::vector<NLMISC::CVector> *Vertices;
|
|
|
|
|
|
/* Here the surface criteria.
|
|
Probably some normal quantization, material, flags ... */
|
|
uint8 WaterShape;
|
|
uint8 QuantHeight;
|
|
|
|
uint32 ForceMerge;
|
|
|
|
bool ForceInvalid;
|
|
bool IsBorder;
|
|
bool IsValid;
|
|
bool IsMergable;
|
|
bool ClusterHint;
|
|
bool IsUnderWater;
|
|
|
|
enum
|
|
{
|
|
NumNormalQuantas = 4,
|
|
NumOrientationQuantas = 4
|
|
};
|
|
|
|
|
|
/**
|
|
* The links to the neighboring elements.
|
|
* Each edge is related to the opposite vertex in the triangle */
|
|
CSurfElement *EdgeLinks[3];
|
|
|
|
/**
|
|
* A flag for each edge, set if the edge has already been evaluated (in
|
|
* the surface border computation.
|
|
*/
|
|
bool EdgeFlag[3];
|
|
|
|
/**
|
|
* The Id of the surface container.
|
|
*/
|
|
sint32 SurfaceId;
|
|
|
|
public:
|
|
/**
|
|
* Constructor.
|
|
* Creates a simple CSurfElement.
|
|
*/
|
|
CSurfElement()
|
|
{
|
|
ElemId = 0;
|
|
EdgeLinks[0] = NULL;
|
|
EdgeLinks[1] = NULL;
|
|
EdgeLinks[2] = NULL;
|
|
EdgeFlag[0] = false;
|
|
EdgeFlag[1] = false;
|
|
EdgeFlag[2] = false;
|
|
SurfaceId = UnaffectedSurfaceId;
|
|
IsBorder = false;
|
|
IsValid = false;
|
|
IsMergable = true;
|
|
ClusterHint = false;
|
|
ForceInvalid = false;
|
|
IsUnderWater = false;
|
|
WaterShape = 255;
|
|
QuantHeight = 0;
|
|
ForceMerge = 0;
|
|
ZoneId = 0;
|
|
}
|
|
|
|
/// Computes the bbox of the surface element.
|
|
NLMISC::CAABBox getBBox() const;
|
|
|
|
|
|
/**
|
|
* Computes the various criteria values (associated to quantas)
|
|
*/
|
|
void computeQuantas(CZoneTessellation *zoneTessel);
|
|
|
|
/**
|
|
* Removes properly all links to the CSurfElement.
|
|
*/
|
|
void removeLinks()
|
|
{
|
|
uint i, j;
|
|
for (i=0; i<3; ++i)
|
|
{
|
|
if (EdgeLinks[i] != NULL)
|
|
for (j=0; j<3; ++j)
|
|
if (EdgeLinks[i]->EdgeLinks[j] == this)
|
|
EdgeLinks[i]->EdgeLinks[j] = NULL;
|
|
EdgeLinks[i] = NULL;
|
|
}
|
|
|
|
}
|
|
|
|
/**
|
|
* Get zone Id on edge
|
|
*/
|
|
sint32 getZoneIdOnEdge(uint edge) const
|
|
{
|
|
return (EdgeLinks[edge] != NULL ? EdgeLinks[edge]->ZoneId : -1);
|
|
}
|
|
|
|
void serial(NLMISC::IStream &f, std::vector<CSurfElement> &tessellation)
|
|
{
|
|
f.serial(ElemId);
|
|
f.serial(Tri[0], Tri[1], Tri[2]);
|
|
f.serial(Normal);
|
|
f.serial(ZoneId);
|
|
|
|
if (f.isReading())
|
|
{
|
|
sint32 s;
|
|
uint i;
|
|
for (i=0; i<3; ++i)
|
|
{
|
|
f.serial(s);
|
|
EdgeLinks[i] = (s >= 0 ? &tessellation[s] : NULL);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
sint32 s;
|
|
uint i;
|
|
for (i=0; i<3; ++i)
|
|
{
|
|
s = (EdgeLinks[i] != NULL ? EdgeLinks[i]->ElemId : -1);
|
|
f.serial(s);
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* CComputableSurfaceBorder separates geometrically 2 distinct CComputableSurface objects
|
|
* \author Benjamin Legros
|
|
* \author Nevrax France
|
|
* \date 2001
|
|
*/
|
|
class CComputableSurfaceBorder
|
|
{
|
|
public:
|
|
std::vector<NLMISC::CVector> Vertices;
|
|
|
|
sint32 Left;
|
|
sint32 Right;
|
|
|
|
float Length;
|
|
|
|
sint8 Edge;
|
|
|
|
bool DontSmooth;
|
|
|
|
public:
|
|
/// Constructor.
|
|
CComputableSurfaceBorder(sint32 left = 0, sint32 right = 0, sint edge=-1) : Left(left), Right(right), Edge(edge), DontSmooth(false) {}
|
|
|
|
/// Dump the vertices that constitue the border.
|
|
void dump();
|
|
|
|
/// Smoothes the border (and so reduces the number of vertices).
|
|
void smooth(float val);
|
|
|
|
/// Computes the length of the border
|
|
void computeLength()
|
|
{
|
|
sint n;
|
|
Length = 0.0;
|
|
for (n=0; n<(sint)Vertices.size()-1; ++n)
|
|
{
|
|
Length += (Vertices[n+1]-Vertices[n]).norm();
|
|
}
|
|
}
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* CComputableSurface is a compact connex set of CSurfElement.
|
|
* \author Benjamin Legros
|
|
* \author Nevrax France
|
|
* \date 2001
|
|
*/
|
|
class CComputableSurface
|
|
{
|
|
public:
|
|
|
|
public:
|
|
/// The Id of the surface
|
|
sint32 SurfaceId;
|
|
|
|
/// The references on the elements that belong to the surface
|
|
std::vector<CSurfElement *> Elements;
|
|
|
|
/// The object that stores all the borders used in the computed area
|
|
std::vector<CComputableSurfaceBorder> *BorderKeeper;
|
|
|
|
/// The border in the surface, by id
|
|
std::vector<uint16> BorderIds;
|
|
|
|
bool IsUnderWater;
|
|
bool ClusterHint;
|
|
|
|
float Area;
|
|
float WaterHeight;
|
|
uint8 QuantHeight;
|
|
|
|
/// The BBox of the whole zone (in which the surface should be contained.)
|
|
NLMISC::CAABBox BBox;
|
|
|
|
/// The height storage quad tree
|
|
CSurfaceQuadTree HeightQuad;
|
|
|
|
/// The center of the surface
|
|
NLMISC::CVector Center;
|
|
|
|
public:
|
|
/**
|
|
* Constructor.
|
|
* Builds an empty surface.
|
|
*/
|
|
CComputableSurface() : SurfaceId(UnaffectedSurfaceId), BorderKeeper(NULL), ClusterHint(false) {}
|
|
|
|
/**
|
|
* Flood fills the surface elements to find iso-criteria surfaces.
|
|
* Every linked surface element which has the same quantas values and a surfaceid == -1
|
|
* are marked and recursively called.
|
|
*/
|
|
template<class A>
|
|
void floodFill(CSurfElement *first, sint32 surfId, const A &cmp, CZoneTessellation *zoneTessel)
|
|
{
|
|
if (Verbose)
|
|
{
|
|
nldebug("flood fill surface %d", surfId);
|
|
}
|
|
|
|
std::vector<CSurfElement *> stack;
|
|
sint i;
|
|
|
|
stack.push_back(first);
|
|
first->SurfaceId = surfId;
|
|
|
|
SurfaceId = surfId;
|
|
ClusterHint = first->ClusterHint;
|
|
QuantHeight = first->QuantHeight;
|
|
uint waterShape = first->WaterShape;
|
|
|
|
IsUnderWater = first->IsUnderWater;
|
|
|
|
//WaterHeight = IsUnderWater ? zoneTessel->WaterShapes[first->WaterShape].Vertices[0].z : 123456.0f;
|
|
bool tamere;
|
|
WaterHeight = IsUnderWater ? PrimChecker.waterHeight(first->WaterShape, tamere)+WaterThreshold : 123456.0f;
|
|
|
|
|
|
uint32 currentZoneId = first->ZoneId;
|
|
|
|
Area = 0.0;
|
|
|
|
while (!stack.empty())
|
|
{
|
|
CSurfElement *pop = stack.back();
|
|
stack.pop_back();
|
|
Elements.push_back(pop);
|
|
Area += pop->Area;
|
|
|
|
for (i=0; i<3; ++i)
|
|
{
|
|
if (pop->EdgeLinks[i] != NULL && pop->EdgeLinks[i]->SurfaceId == UnaffectedSurfaceId && cmp.equal(first, pop->EdgeLinks[i]))
|
|
{
|
|
pop->EdgeLinks[i]->SurfaceId = SurfaceId;
|
|
stack.push_back(pop->EdgeLinks[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Verbose)
|
|
{
|
|
nldebug("%d elements added", Elements.size());
|
|
}
|
|
|
|
Center = NLMISC::CVector::Null;
|
|
for (i=0; i<(sint)Elements.size(); ++i)
|
|
{
|
|
std::vector<NLMISC::CVector> &vertices = *Elements[i]->Vertices;
|
|
Center += (vertices[Elements[i]->Tri[0]]+vertices[Elements[i]->Tri[1]]+vertices[Elements[i]->Tri[2]]);
|
|
}
|
|
Center /= (float)(Elements.size()*3);
|
|
}
|
|
|
|
|
|
/// Builds the border of the CComputableSurface.
|
|
void buildBorders(CZoneTessellation *zoneTessel);
|
|
|
|
/// Check Surface Consistency
|
|
bool checkConsistency();
|
|
|
|
private:
|
|
void followBorder(CZoneTessellation *zoneTessel, CSurfElement *first, uint edge, uint sens, std::vector<NLMISC::CVector> &vstore, bool &loop);
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
* CZoneTessellation is the whole tessellation of a given CZone.
|
|
* \author Benjamin Legros
|
|
* \author Nevrax France
|
|
* \date 2001
|
|
*/
|
|
class CZoneTessellation
|
|
{
|
|
private:
|
|
std::vector<CSurfElement> _Tessellation;
|
|
std::vector<NLMISC::CVector> _Vertices;
|
|
|
|
protected:
|
|
|
|
std::vector<uint16> _ZoneIds;
|
|
std::vector<const NL3D::CZone*> _ZonePtrs;
|
|
|
|
public:
|
|
class CMergeForceBox
|
|
{
|
|
public:
|
|
NLMISC::CAABBox MergeBox;
|
|
uint32 MergeId;
|
|
void serial(NLMISC::IStream &f) { f.serial(MergeBox, MergeId); }
|
|
};
|
|
|
|
public:
|
|
/// The zone valid tessellation elements.
|
|
std::vector<CSurfElement *> Elements;
|
|
|
|
///
|
|
NLMISC::CAABBox BBox;
|
|
NLMISC::CAABBox OriginalBBox;
|
|
NLMISC::CAABBox BestFittingBBox;
|
|
// Yoyo: if zone is empty, we must not apply the Translation delta to zone
|
|
bool BestFittingBBoxSetuped;
|
|
|
|
///
|
|
NLMISC::CVector Translation;
|
|
|
|
///
|
|
sint32 CentralZoneId;
|
|
|
|
std::vector<NLMISC::CPolygon> WaterShapes;
|
|
NL3D::CQuadGrid<uint32> WaterGrid;
|
|
|
|
/**
|
|
* The tessellation refinement. The size of the tessellation is equal to 2m/Refinement
|
|
* (say, for instance, a refinement of 2 means a 1m large tessellation.)
|
|
*/
|
|
sint16 Refinement;
|
|
|
|
/**
|
|
* The surfaces composing the tessellation.
|
|
*/
|
|
std::vector<CComputableSurface> Surfaces;
|
|
std::vector<CComputableSurface> ExtSurfaces;
|
|
|
|
/**
|
|
* The borders for the whole CZone.
|
|
*/
|
|
std::vector<CComputableSurfaceBorder> Borders;
|
|
|
|
/**
|
|
* The box that force merge into surface
|
|
*/
|
|
std::vector<CMergeForceBox> ForceMerge;
|
|
|
|
/**
|
|
* Flags
|
|
*/
|
|
std::vector<uint8> VerticesFlags;
|
|
|
|
public:
|
|
/**
|
|
* Constructor
|
|
* Creates an empty tessellation.
|
|
*/
|
|
CZoneTessellation() {}
|
|
|
|
/**
|
|
* Clear
|
|
*/
|
|
void clear();
|
|
|
|
/**
|
|
* Sets a zone tessellation up for building later.
|
|
*/
|
|
bool setup(uint16 zoneId, sint16 refinement, const NLMISC::CVector &translation);
|
|
|
|
/**
|
|
* Adds a zone light tessellation to the quad tree container.
|
|
*/
|
|
void addToContainer(const NL3D::CZone &zone);
|
|
NL3D::CMesh *generateCollisionMesh();
|
|
|
|
/**
|
|
* Builds the whole zone tessellation (with linkage) from the given zone.
|
|
*/
|
|
void build();
|
|
|
|
/**
|
|
* Sets the water polygons up.
|
|
*/
|
|
void addWaterShape(const NLMISC::CPolygon &poly)
|
|
{
|
|
WaterShapes.push_back(poly);
|
|
}
|
|
|
|
/**
|
|
* Compile the whole zone tessellation and creates surfaces
|
|
*/
|
|
void compile();
|
|
|
|
/**
|
|
* Generates a CMesh from the tessellation.
|
|
*/
|
|
NL3D::CMesh *generateMesh();
|
|
|
|
/**
|
|
* Generates borders for the whole zone tessellation.
|
|
* \param smooth how much to smooth the borders
|
|
*/
|
|
void generateBorders(float smooth);
|
|
|
|
/**
|
|
*
|
|
*/
|
|
NLMISC::CAABBox computeBBox() const;
|
|
|
|
/**
|
|
* Save tessellation
|
|
*/
|
|
void saveTessellation(NLMISC::COFile &output);
|
|
|
|
/**
|
|
* Load tessellation
|
|
*/
|
|
void loadTessellation(NLMISC::CIFile &input);
|
|
|
|
private:
|
|
void checkSameLandscapeHmBinds(const NL3D::CLandscape &landscape, const NL3D::CLandscape &landscapeNoHm);
|
|
};
|
|
|
|
|
|
|
|
class CSurfElemCompareSimple
|
|
{
|
|
public:
|
|
|
|
bool equal(const CSurfElement *a, const CSurfElement *b) const
|
|
{
|
|
return a->IsValid == b->IsValid &&
|
|
a->ForceInvalid == b->ForceInvalid;
|
|
}
|
|
};
|
|
|
|
class CSurfElemCompareNormal
|
|
{
|
|
public:
|
|
|
|
bool equal(const CSurfElement *a, const CSurfElement *b) const
|
|
{
|
|
return b->IsValid &&
|
|
a->ClusterHint == b->ClusterHint &&
|
|
a->ZoneId == b->ZoneId &&
|
|
a->IsUnderWater == b->IsUnderWater &&
|
|
a->WaterShape == b->WaterShape &&
|
|
a->QuantHeight == b->QuantHeight;
|
|
}
|
|
};
|
|
|
|
|
|
}; // NLPACS
|
|
|
|
#endif // NL_BUILD_SURF_H
|
|
|
|
/* End of build_surf.h */
|