// NeL - 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 .
#include "prim_checker.h"
// NeL Misc includes
#include "nel/misc/vectord.h"
#include "nel/misc/path.h"
#include "nel/misc/i_xml.h"
#include "nel/misc/aabbox.h"
#include "nel/misc/file.h"
// NeL Ligo includes
#include "nel/ligo/ligo_config.h"
#include "nel/ligo/primitive.h"
// NeL 3d
#include "nel/3d/scene_group.h"
#include "nel/3d/transform_shape.h"
#include "nel/3d/water_model.h"
#include "nel/3d/water_shape.h"
#include "nel/3d/quad_grid.h"
// STL includes
#include
#include
using namespace NLMISC;
using namespace NLLIGO;
using namespace NL3D;
using namespace std;
NLLIGO::CLigoConfig LigoConfig;
extern bool Verbose;
extern float WaterThreshold;
/*
* Constructor
*/
CPrimChecker::CPrimChecker()
{
}
/*
* init()
*/
bool CPrimChecker::build(const string &primitivesPath, const string &igLandPath, const string &igVillagePath, const string &outputDirectory, bool forceRebuild)
{
if (Verbose)
nlinfo("Checking pacs.packed_prims consistency");
NLLIGO::Register();
// Init ligo
if (!LigoConfig.readPrimitiveClass ("world_editor_classes.xml", false))
{
// Should be in l:\leveldesign\world_edit_files
nlwarning ("Can't load ligo primitive config file world_editor_classes.xml");
return false;
}
uint i, j;
string outputfname = CPath::standardizePath(outputDirectory)+"pacs.packed_prims";
_Grid.clear();
vector files;
CPath::getPathContent(primitivesPath, true, false, true, files);
for (i=0; i noWaterShapes;
for (i=0; i(shape.getShapePointer());
if (wshape == NULL)
{
noWaterShapes.insert(shapeName);
continue;
}
//nlinfo("Render water shape '%s'", shapeNameLookup.c_str());
CMatrix matrix;
ig.getInstanceMatrix(j, matrix);
CPolygon wpoly;
//wshape->getShapeInWorldSpace(wpoly);
CPolygon2D wpoly2d = wshape->getShape();
uint k;
for (k=0; k(primitive) != NULL && primitive->getPropertyByName("class", className))
{
if (className == "pacs_include")
render(static_cast(primitive), Include);
else if (className == "pacs_exclude")
render(static_cast(primitive), Exclude);
else if (className == "pacs_cluster_hint")
render(static_cast(primitive), ClusterHint);
}
// parse children
uint i;
for (i=0; igetNumChildren(); ++i)
{
IPrimitive *child;
if (!primitive->getChild(child, i))
continue;
readPrimitive(child);
}
}
/*
* render()
*/
void CPrimChecker::render(CPrimZone *zone, uint8 bits)
{
if (zone->VPoints.size() < 3)
return;
string name;
if (zone->getPropertyByName("name", name) && Verbose)
nlinfo("Rendering CPrimZone '%s'", name.c_str());
// get the bouding box of the CPrimZone
CAABBox box;
box.setCenter(zone->VPoints[0]);
box.setHalfSize(CVector::Null);
uint i;
for (i=1; iVPoints.size(); ++i)
box.extend(zone->VPoints[i]);
sint32 xmin, ymin, xmax, ymax;
xmin = (sint32)(floor(box.getMin().x));
ymin = (sint32)(floor(box.getMin().y));
xmax = (sint32)(ceil(box.getMax().x));
ymax = (sint32)(ceil(box.getMax().y));
// Fill grid with points that belong to the CPrimZone
sint32 x, y;
for (y=ymin; y<=ymax; ++y)
for (x=xmin; x<=xmax; ++x)
if (zone->contains(CVector((float)x, (float)y, 0.0f)))
_Grid.set(x, y, bits);
}
/*
* Render a water shape, as a CPolygon
*/
void CPrimChecker::render(const CPolygon &poly, uint16 value)
{
list convex;
// divide poly in convex polys
if (!poly.toConvexPolygons(convex, CMatrix::Identity))
{
convex.clear();
CPolygon reverse = poly;
std::reverse(reverse.Vertices.begin(), reverse.Vertices.end());
if (!reverse.toConvexPolygons(convex, CMatrix::Identity))
return;
}
list::iterator it;
for (it=convex.begin(); it!=convex.end(); ++it)
{
CPolygon2D convex2d(*it);
CPolygon2D::TRasterVect rasterized;
sint ymin;
convex2d.computeBorders(rasterized, ymin);
sint dy;
for (dy=0; dy<(sint)rasterized.size(); ++dy)
{
sint x;
for (x=rasterized[dy].first; x<=rasterized[dy].second; ++x)
{
uint8 prevBits = _Grid.get((uint)x, (uint)(ymin+dy));
// only set if there was not a water shape there or if previous was lower
if ((prevBits & Water) != 0)
{
uint16 prevWS = _Grid.index((uint)x, (uint)(ymin+dy));
if (_WaterHeight[value] < _WaterHeight[prevWS])
continue;
}
_Grid.index((uint)x, (uint)(ymin+dy), value);
_Grid.set((uint)x, (uint)(ymin+dy), Water);
}
}
}
}
/*
* Render a CPolygon of bit value
*/
void CPrimChecker::renderBits(const CPolygon &poly, uint8 bits)
{
list convex;
// divide poly in convex polys
if (!poly.toConvexPolygons(convex, CMatrix::Identity))
{
convex.clear();
CPolygon reverse = poly;
std::reverse(reverse.Vertices.begin(), reverse.Vertices.end());
if (!reverse.toConvexPolygons(convex, CMatrix::Identity))
return;
}
list::iterator it;
for (it=convex.begin(); it!=convex.end(); ++it)
{
CPolygon2D convex2d(*it);
CPolygon2D::TRasterVect rasterized;
sint ymin;
convex2d.computeBorders(rasterized, ymin);
sint dy;
for (dy=0; dy<(sint)rasterized.size(); ++dy)
{
sint x;
for (x=rasterized[dy].first; x<=rasterized[dy].second; ++x)
{
_Grid.set((uint)x, (uint)(ymin+dy), bits);
}
}
}
}