2010-05-06 00:08:41 +00:00
|
|
|
// 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/>.
|
|
|
|
|
|
|
|
#include "../zone_lib/zone_utility.h"
|
|
|
|
|
|
|
|
#include "nel/3d/zone.h"
|
|
|
|
#include "nel/3d/quad_grid.h"
|
|
|
|
#include "nel/3d/scene_group.h"
|
|
|
|
#include "nel/3d/shape.h"
|
|
|
|
#include "nel/3d/water_shape.h"
|
|
|
|
#include "nel/3d/register_3d.h"
|
|
|
|
|
|
|
|
#include "nel/georges/u_form.h"
|
|
|
|
#include "nel/georges/u_form_elm.h"
|
|
|
|
#include "nel/georges/u_form_loader.h"
|
|
|
|
|
|
|
|
#include "nel/misc/config_file.h"
|
|
|
|
#include "nel/misc/file.h"
|
|
|
|
#include "nel/misc/aabbox.h"
|
|
|
|
#include "nel/misc/path.h"
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <map>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
using namespace NLMISC;
|
|
|
|
using namespace NL3D;
|
|
|
|
|
|
|
|
typedef pair<sint, sint> CZoneDependenciesValue;
|
|
|
|
|
|
|
|
|
|
|
|
#define BAR_LENGTH 21
|
|
|
|
|
|
|
|
const char *progressbar[BAR_LENGTH]=
|
|
|
|
{
|
|
|
|
"[ ]",
|
|
|
|
"[. ]",
|
|
|
|
"[.. ]",
|
|
|
|
"[... ]",
|
|
|
|
"[.... ]",
|
|
|
|
"[..... ]",
|
|
|
|
"[...... ]",
|
|
|
|
"[....... ]",
|
|
|
|
"[........ ]",
|
|
|
|
"[......... ]",
|
|
|
|
"[.......... ]",
|
|
|
|
"[........... ]",
|
|
|
|
"[............ ]",
|
|
|
|
"[............. ]",
|
|
|
|
"[.............. ]",
|
|
|
|
"[............... ]",
|
|
|
|
"[................ ]",
|
|
|
|
"[................. ]",
|
|
|
|
"[.................. ]",
|
|
|
|
"[................... ]",
|
|
|
|
"[....................]"
|
|
|
|
};
|
|
|
|
|
|
|
|
void progress (const char *message, float progress)
|
|
|
|
{
|
|
|
|
// Progress bar
|
|
|
|
char msg[512];
|
|
|
|
uint pgId= (uint)(progress*(float)BAR_LENGTH);
|
|
|
|
pgId= min(pgId, (uint)(BAR_LENGTH-1));
|
|
|
|
sprintf (msg, "\r%s: %s", message, progressbar[pgId]);
|
|
|
|
uint i;
|
2010-05-13 21:29:42 +00:00
|
|
|
for (i=(uint)strlen(msg); i<79; i++)
|
2010-05-06 00:08:41 +00:00
|
|
|
msg[i]=' ';
|
|
|
|
msg[i]=0;
|
2010-08-09 14:20:03 +00:00
|
|
|
printf ("%s\r", msg);
|
2010-05-06 00:08:41 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
class CZoneDependencies
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// Default Ctor
|
|
|
|
CZoneDependencies ()
|
|
|
|
{
|
|
|
|
// Not loaded
|
|
|
|
Loaded=false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Zone coordinates
|
|
|
|
sint X;
|
|
|
|
sint Y;
|
|
|
|
|
|
|
|
// BBox
|
|
|
|
CAABBoxExt BBox;
|
|
|
|
|
|
|
|
// Loaded
|
|
|
|
bool Loaded;
|
|
|
|
|
|
|
|
// List
|
|
|
|
set<CZoneDependenciesValue> Dependences;
|
|
|
|
};
|
|
|
|
|
|
|
|
class CZoneDescriptorBB
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
// Zone coordinates
|
|
|
|
sint X;
|
|
|
|
sint Y;
|
|
|
|
|
|
|
|
// BBox
|
|
|
|
CAABBoxExt BBox;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// a bbox with a 'NULL' flad added
|
|
|
|
class CPotentialBBox
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CPotentialBBox() : IsVoid(true) {}
|
|
|
|
CPotentialBBox(const CAABBox &b) : Box(b), IsVoid(false) {}
|
|
|
|
CAABBox Box;
|
|
|
|
bool IsVoid;
|
|
|
|
void makeUnion(const CPotentialBBox &other)
|
|
|
|
{
|
|
|
|
if (IsVoid && other.IsVoid) return;
|
|
|
|
if( IsVoid)
|
|
|
|
{
|
|
|
|
Box = other.Box;
|
|
|
|
}
|
|
|
|
else if (!other.IsVoid)
|
|
|
|
{
|
|
|
|
Box = CAABBox::computeAABBoxUnion(Box, other.Box);
|
|
|
|
}
|
|
|
|
IsVoid = false;
|
|
|
|
}
|
|
|
|
void transform(const NLMISC::CMatrix &matrix)
|
|
|
|
{
|
|
|
|
if (!IsVoid)
|
|
|
|
{
|
|
|
|
Box = NLMISC::CAABBox::transformAABBox(matrix, Box);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// If the bbox has a null size, then mark it void
|
|
|
|
void removeVoid()
|
|
|
|
{
|
|
|
|
if (!IsVoid && Box.getHalfSize() == CVector::Null)
|
|
|
|
{
|
|
|
|
IsVoid = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// a couple of bbox to identity occluding / receiving bbox
|
|
|
|
struct CLightingBBox
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
CPotentialBBox OccludingBox;
|
|
|
|
CPotentialBBox ReceivingBox;
|
|
|
|
void makeUnion(const CLightingBBox &other)
|
|
|
|
{
|
|
|
|
OccludingBox.makeUnion(other.OccludingBox);
|
|
|
|
ReceivingBox.makeUnion(other.ReceivingBox);
|
|
|
|
}
|
|
|
|
void transform(const NLMISC::CMatrix &matrix)
|
|
|
|
{
|
|
|
|
OccludingBox.transform(matrix);
|
|
|
|
ReceivingBox.transform(matrix);
|
|
|
|
}
|
|
|
|
// If the bbox has a null size, then mark it void
|
|
|
|
void removeVoid()
|
|
|
|
{
|
|
|
|
OccludingBox.removeVoid();
|
|
|
|
ReceivingBox.removeVoid();
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
typedef std::map<std::string, CLightingBBox> TString2LightingBBox;
|
|
|
|
/// A map to cache the shapes bbox's
|
|
|
|
typedef TString2LightingBBox TShapeMap;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// compute the bbox of the igs in a zone
|
|
|
|
static void computeZoneIGBBox(const char *zoneName, CLightingBBox &result, TShapeMap &shapeMap, const TString2LightingBBox &additionnalIG);
|
|
|
|
// ryzom specific, see definition
|
|
|
|
static void computeIGBBoxFromContinent(NLMISC::CConfigFile ¶meter,
|
|
|
|
TShapeMap &shapeMap,
|
|
|
|
TString2LightingBBox &zone2BBox
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
///=========================================================
|
|
|
|
int main (int argc, char* argv[])
|
|
|
|
{
|
|
|
|
// Filter addSearchPath
|
|
|
|
NLMISC::createDebug();
|
|
|
|
InfoLog->addNegativeFilter ("adding the path");
|
|
|
|
|
|
|
|
TShapeMap shapeMap;
|
|
|
|
|
|
|
|
// Check number of args
|
|
|
|
if (argc<5)
|
|
|
|
{
|
|
|
|
// Help message
|
|
|
|
printf ("zone_dependencies [properties.cfg] [firstZone.zone] [lastzone.zone] [output_dependencies.cfg]\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
NL3D::registerSerial3d();
|
|
|
|
// Light direction
|
|
|
|
CVector lightDirection;
|
|
|
|
|
|
|
|
// Config file handler
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Read the properties file
|
|
|
|
CConfigFile properties;
|
|
|
|
|
|
|
|
// Load and parse the properties file
|
|
|
|
properties.load (argv[1]);
|
|
|
|
|
|
|
|
// Get the light direction
|
|
|
|
CConfigFile::CVar &sun_direction = properties.getVar ("sun_direction");
|
|
|
|
lightDirection.set (sun_direction.asFloat(0), sun_direction.asFloat(1), sun_direction.asFloat(2));
|
|
|
|
lightDirection.normalize();
|
|
|
|
|
|
|
|
|
|
|
|
// Get the search pathes
|
|
|
|
CConfigFile::CVar &search_pathes = properties.getVar ("search_pathes");
|
|
|
|
uint path;
|
|
|
|
for (path = 0; path < (uint)search_pathes.size(); path++)
|
|
|
|
{
|
|
|
|
// Add to search path
|
|
|
|
CPath::addSearchPath (search_pathes.asString(path));
|
|
|
|
}
|
|
|
|
/*
|
|
|
|
CConfigFile::CVar &ig_path = properties.getVar ("ig_path");
|
|
|
|
NLMISC::CPath::addSearchPath(ig_path.asString(), true, true);
|
|
|
|
|
|
|
|
CConfigFile::CVar &shapes_path = properties.getVar ("shapes_path");
|
|
|
|
NLMISC::CPath::addSearchPath(shapes_path.asString(), true, true);
|
|
|
|
*/
|
|
|
|
CConfigFile::CVar &compute_dependencies_with_igs = properties.getVar ("compute_dependencies_with_igs");
|
|
|
|
bool computeDependenciesWithIgs = compute_dependencies_with_igs.asInt() != 0;
|
|
|
|
|
|
|
|
|
|
|
|
// Get the file extension
|
|
|
|
string ext=getExt (argv[2]);
|
|
|
|
|
|
|
|
// Get the file directory
|
|
|
|
string dir=getDir (argv[2]);
|
|
|
|
|
|
|
|
// Get output extension
|
|
|
|
string outExt=getExt (argv[4]);
|
|
|
|
|
|
|
|
// Get output directory
|
|
|
|
string outDir=getDir (argv[4]);
|
|
|
|
|
|
|
|
// Get the first and last name
|
|
|
|
string firstName=getName (argv[2]);
|
|
|
|
string lastName=getName (argv[3]);
|
|
|
|
|
|
|
|
// Get the coordinates
|
|
|
|
uint16 firstX, firstY;
|
|
|
|
uint16 lastX, lastY;
|
|
|
|
if (getZoneCoordByName (firstName.c_str(), firstX, firstY))
|
|
|
|
{
|
|
|
|
// Last zone
|
|
|
|
if (getZoneCoordByName (lastName.c_str(), lastX, lastY))
|
|
|
|
{
|
|
|
|
// Take care
|
|
|
|
if (lastX<firstX)
|
|
|
|
{
|
|
|
|
uint16 tmp=firstX;
|
|
|
|
firstX=lastX;
|
|
|
|
lastX=firstX;
|
|
|
|
}
|
|
|
|
if (lastY<firstY)
|
|
|
|
{
|
|
|
|
uint16 tmp=firstY;
|
|
|
|
firstY=lastY;
|
|
|
|
lastY=firstY;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Min z
|
|
|
|
float minZ=FLT_MAX;
|
|
|
|
|
|
|
|
// Make a quad grid
|
|
|
|
CQuadGrid<CZoneDescriptorBB> quadGrid;
|
|
|
|
quadGrid.create (256, 100);
|
|
|
|
|
|
|
|
// The dependencies list
|
|
|
|
vector< CZoneDependencies > dependencies;
|
|
|
|
dependencies.resize ((lastX-firstX+1)*(lastY-firstY+1));
|
|
|
|
|
|
|
|
// Ryzom specific: build bbox for villages
|
|
|
|
TString2LightingBBox villagesBBox;
|
|
|
|
computeIGBBoxFromContinent(properties, shapeMap, villagesBBox);
|
|
|
|
|
|
|
|
|
|
|
|
// Insert each zone in the quad tree
|
|
|
|
sint y, x;
|
|
|
|
for (y=firstY; y<=lastY; y++)
|
|
|
|
for (x=firstX; x<=lastX; x++)
|
|
|
|
{
|
|
|
|
|
|
|
|
|
|
|
|
// Progress
|
|
|
|
progress ("Build bounding boxes", (float)(x+y*lastX)/(float)(lastX*lastY));
|
|
|
|
|
|
|
|
// Make a zone file name
|
|
|
|
string zoneName;
|
|
|
|
getZoneNameByCoord (x, y, zoneName);
|
|
|
|
|
|
|
|
// Open the file
|
|
|
|
CIFile file;
|
|
|
|
if (file.open (dir+zoneName+ext))
|
|
|
|
{
|
|
|
|
// The zone
|
|
|
|
CZone zone;
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
// Serial the zone
|
|
|
|
file.serial (zone);
|
|
|
|
|
|
|
|
/// get bbox from the ig of this zone
|
|
|
|
CLightingBBox igBBox;
|
|
|
|
if (computeDependenciesWithIgs)
|
|
|
|
{
|
|
|
|
computeZoneIGBBox(zoneName.c_str(), igBBox, shapeMap, villagesBBox);
|
|
|
|
}
|
|
|
|
// Create a zone descriptor
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
NLMISC::CAABBox zoneBox;
|
|
|
|
zoneBox.setCenter(zone.getZoneBB().getCenter());
|
|
|
|
zoneBox.setHalfSize(zone.getZoneBB().getHalfSize());
|
|
|
|
|
|
|
|
CLightingBBox zoneLBox;
|
|
|
|
zoneLBox.OccludingBox = zoneLBox.ReceivingBox = zoneBox; // can't be void
|
|
|
|
zoneLBox.makeUnion(igBBox);
|
|
|
|
nlassert(!zoneLBox.ReceivingBox.IsVoid);
|
|
|
|
//
|
|
|
|
CZoneDescriptorBB zoneDesc;
|
|
|
|
zoneDesc.X=x;
|
|
|
|
zoneDesc.Y=y;
|
|
|
|
zoneDesc.BBox=zoneLBox.ReceivingBox.Box;
|
|
|
|
//
|
|
|
|
if (!zoneLBox.OccludingBox.IsVoid)
|
|
|
|
{
|
|
|
|
quadGrid.insert (zoneLBox.ReceivingBox.Box.getMin(), zoneLBox.ReceivingBox.Box.getMax(), zoneDesc);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Insert in the dependencies
|
|
|
|
// Index
|
|
|
|
uint index=(x-firstX)+(y-firstY)*(lastX-firstX+1);
|
|
|
|
|
|
|
|
|
|
|
|
// Loaded
|
|
|
|
dependencies[index].Loaded=true;
|
|
|
|
dependencies[index].X=x;
|
|
|
|
dependencies[index].Y=y;
|
|
|
|
dependencies[index].BBox=zoneLBox.OccludingBox.Box;
|
|
|
|
|
|
|
|
// ZMin
|
|
|
|
float newZ=zoneLBox.ReceivingBox.Box.getMin().z;
|
|
|
|
if (newZ<minZ)
|
|
|
|
minZ=newZ;
|
|
|
|
}
|
|
|
|
catch (Exception& e)
|
|
|
|
{
|
|
|
|
// Error handling
|
|
|
|
nlwarning ("ERROR in file %s, %s", (dir+zoneName+ext).c_str(), e.what ());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Now select each zone in others and make a depencies list
|
|
|
|
for (y=firstY; y<=lastY; y++)
|
|
|
|
for (x=firstX; x<=lastX; x++)
|
|
|
|
{
|
|
|
|
// Progress
|
|
|
|
progress ("Compute dependencies", (float)(x+y*lastX)/(float)(lastX*lastY));
|
|
|
|
|
|
|
|
// Index
|
|
|
|
uint index=(x-firstX)+(y-firstY)*(lastX-firstX+1);
|
|
|
|
|
|
|
|
// Loaded ?
|
|
|
|
if (dependencies[index].Loaded)
|
|
|
|
{
|
|
|
|
// Min max vectors
|
|
|
|
CVector vMin (dependencies[index].BBox.getMin());
|
|
|
|
CVector vMax (dependencies[index].BBox.getMax());
|
|
|
|
|
|
|
|
// Make a corner array
|
|
|
|
CVector corners[4] =
|
|
|
|
{
|
|
|
|
CVector (vMin.x, vMin.y, vMax.z), CVector (vMax.x, vMin.y, vMax.z),
|
|
|
|
CVector (vMax.x, vMax.y, vMax.z), CVector (vMin.x, vMax.y, vMax.z)
|
|
|
|
};
|
|
|
|
|
|
|
|
// Extended bbox
|
|
|
|
CAABBox bBox=dependencies[index].BBox.getAABBox();
|
|
|
|
|
|
|
|
// For each corner
|
|
|
|
uint corner;
|
|
|
|
for (corner=0; corner<4; corner++)
|
|
|
|
{
|
|
|
|
// Target position
|
|
|
|
CVector target;
|
|
|
|
if (lightDirection.z!=0)
|
|
|
|
{
|
|
|
|
// Not horizontal target
|
|
|
|
target=corners[corner]+(lightDirection*((minZ-corners[corner].z)/lightDirection.z));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Horizontal target, select 500 meters around.
|
|
|
|
target=(500*lightDirection)+corners[corner];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extend the bbox
|
|
|
|
bBox.extend (target);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Clear quad tree selection
|
|
|
|
quadGrid.clearSelection ();
|
|
|
|
|
|
|
|
// Select
|
|
|
|
quadGrid.select (bBox.getMin(), bBox.getMax());
|
|
|
|
|
|
|
|
// Check selection
|
|
|
|
CQuadGrid<CZoneDescriptorBB>::CIterator it=quadGrid.begin();
|
|
|
|
while (it!=quadGrid.end())
|
|
|
|
{
|
|
|
|
// Index
|
|
|
|
uint targetIndex=((*it).X-firstX)+((*it).Y-firstY)*(lastX-firstX+1);
|
|
|
|
|
|
|
|
// Not the same
|
|
|
|
if (targetIndex!=index)
|
|
|
|
{
|
|
|
|
// Target min z
|
|
|
|
float targetMinZ=dependencies[targetIndex].BBox.getMin().z;
|
|
|
|
if (targetMinZ<vMax.z)
|
|
|
|
{
|
|
|
|
// Min z inf to max z ?
|
|
|
|
// Target optimized bbox
|
|
|
|
CAABBox bBoxOptimized=dependencies[index].BBox.getAABBox();
|
|
|
|
|
|
|
|
// For each corner
|
|
|
|
for (corner=0; corner<4; corner++)
|
|
|
|
{
|
|
|
|
// Target position
|
|
|
|
CVector target;
|
|
|
|
if (lightDirection.z!=0)
|
|
|
|
{
|
|
|
|
// Not horizontal target
|
|
|
|
target=corners[corner]+(lightDirection*((targetMinZ-corners[corner].z)
|
|
|
|
/lightDirection.z));
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Horizontal target, select 500 meters around.
|
|
|
|
target=(500*lightDirection)+corners[corner];
|
|
|
|
}
|
|
|
|
|
|
|
|
// Extend the bbox
|
|
|
|
bBoxOptimized.extend (target);
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check it more presisly
|
|
|
|
//if ((*it).BBox.intersect (bBoxOptimized))
|
|
|
|
if ((*it).BBox.intersect (bBox))
|
|
|
|
{
|
|
|
|
// Insert in the set
|
|
|
|
dependencies[targetIndex].Dependences.insert (CZoneDependenciesValue (x, y));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Next selected
|
|
|
|
it++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// For each zone
|
|
|
|
for (y=firstY; y<=lastY; y++)
|
|
|
|
for (x=firstX; x<=lastX; x++)
|
|
|
|
{
|
|
|
|
// Progress
|
|
|
|
progress ("Save depend files", (float)(x+y*lastX)/(float)(lastX*lastY));
|
|
|
|
|
|
|
|
// Index
|
|
|
|
uint index=(x-firstX)+(y-firstY)*(lastX-firstX+1);
|
|
|
|
|
|
|
|
// Loaded ?
|
|
|
|
if (dependencies[index].Loaded)
|
|
|
|
{
|
|
|
|
// Make a file name
|
|
|
|
string outputFileName;
|
|
|
|
getZoneNameByCoord(x, y, outputFileName);
|
|
|
|
outputFileName=outDir+outputFileName+outExt;
|
|
|
|
|
|
|
|
// Write the dependencies file
|
|
|
|
FILE *outputFile;
|
2010-08-09 14:20:03 +00:00
|
|
|
if ((outputFile=fopen (toLower (outputFileName).c_str(), "w")))
|
2010-05-06 00:08:41 +00:00
|
|
|
{
|
|
|
|
// Add a dependency entry
|
|
|
|
fprintf (outputFile, "dependencies =\n{\n");
|
|
|
|
|
|
|
|
// Add dependent zones
|
|
|
|
set<CZoneDependenciesValue>::iterator ite=dependencies[index].Dependences.begin();
|
|
|
|
while (ite!=dependencies[index].Dependences.end())
|
|
|
|
{
|
|
|
|
// Name of the dependent zone
|
|
|
|
std::string zoneName;
|
|
|
|
getZoneNameByCoord(ite->first, ite->second, zoneName);
|
|
|
|
|
|
|
|
// Write it
|
|
|
|
string message="\t\""+zoneName+"\"";
|
2010-08-09 14:20:03 +00:00
|
|
|
fprintf (outputFile, "%s", toLower (message).c_str());
|
2010-05-06 00:08:41 +00:00
|
|
|
|
|
|
|
// Next ite;
|
|
|
|
ite++;
|
|
|
|
if (ite!=dependencies[index].Dependences.end())
|
|
|
|
fprintf (outputFile, ",\n");
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close the variable
|
|
|
|
fprintf (outputFile, "\n};\n\n");
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nlwarning ("ERROR can't open %s for writing.\n", outputFileName.c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// Close the file
|
|
|
|
fclose (outputFile);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Not valid
|
|
|
|
nlwarning ("ERROR %s is not a valid zone name.\n", lastName.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Not valid
|
|
|
|
nlwarning ("ERROR %s is not a valid zone name.\n", firstName.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (Exception &ee)
|
|
|
|
{
|
|
|
|
nlwarning ("ERROR %s\n", ee.what());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
///===========================================================================
|
|
|
|
/** Load and compute the bbox of the models that are contained in a given instance group
|
|
|
|
* \return true if the computed bbox is valid
|
|
|
|
*/
|
|
|
|
static void computeIGBBox(const NL3D::CInstanceGroup &ig, CLightingBBox &result, TShapeMap &shapeMap)
|
|
|
|
{
|
|
|
|
result = CLightingBBox(); // starts with void result
|
|
|
|
bool firstBBox = true;
|
|
|
|
/// now, compute the union of all bboxs
|
|
|
|
for (CInstanceGroup::TInstanceArray::const_iterator it = ig._InstancesInfos.begin(); it != ig._InstancesInfos.end(); ++it)
|
|
|
|
{
|
|
|
|
CLightingBBox currBBox;
|
|
|
|
|
|
|
|
bool validBBox = false;
|
|
|
|
/// get the bbox from file or from map
|
|
|
|
if (shapeMap.count(it->Name)) // already loaded ?
|
|
|
|
{
|
|
|
|
currBBox = shapeMap[it->Name];
|
|
|
|
validBBox = true;
|
|
|
|
}
|
|
|
|
else // must load the shape to get its bbox
|
|
|
|
{
|
|
|
|
std::string shapePathName;
|
|
|
|
std::string toLoad = it->Name;
|
|
|
|
if (getExt(toLoad).empty()) toLoad += ".shape";
|
|
|
|
shapePathName = NLMISC::CPath::lookup(toLoad, false, false);
|
|
|
|
|
|
|
|
if (shapePathName.empty())
|
|
|
|
{
|
|
|
|
nlwarning("Unable to find shape %s", it->Name.c_str());
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
CIFile shapeInputFile;
|
|
|
|
|
|
|
|
if (shapeInputFile.open (shapePathName.c_str()))
|
|
|
|
{
|
|
|
|
NL3D::CShapeStream shapeStream;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
shapeStream.serial (shapeInputFile);
|
|
|
|
// NB Nico :
|
|
|
|
// Deal with water shape -> their 'Receiving' box is set to 'void'
|
|
|
|
// this prevent the case where a huge surface of water will cause the zone it is attached to (the 'Zone'
|
|
|
|
// field in the villages sheets) to load all the zones that the water surface cover. (This caused
|
|
|
|
// an 'out of memory error' in the zone lighter due to too many zone being loaded)
|
|
|
|
|
|
|
|
// FIXME : test for water case hardcoded for now
|
|
|
|
CWaterShape *ws = dynamic_cast<CWaterShape *>(shapeStream.getShapePointer());
|
|
|
|
if (ws)
|
|
|
|
{
|
|
|
|
CAABBox bbox;
|
|
|
|
shapeStream.getShapePointer()->getAABBox(bbox);
|
|
|
|
currBBox.OccludingBox = CPotentialBBox(bbox); // occluding box is used, though the water shape
|
|
|
|
// doesn't cast shadow -> the tiles flag ('above', 'intersect', 'below water')
|
|
|
|
// are updated inside the zone_lighter
|
|
|
|
currBBox.ReceivingBox.IsVoid = true; // no lighted by the zone lighter !!!
|
|
|
|
currBBox.removeVoid();
|
|
|
|
shapeMap[it->Name] = currBBox;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
|
|
|
|
CAABBox bbox;
|
|
|
|
shapeStream.getShapePointer()->getAABBox(bbox);
|
|
|
|
currBBox.OccludingBox = CPotentialBBox(bbox);
|
|
|
|
currBBox.ReceivingBox = CPotentialBBox(bbox);
|
|
|
|
currBBox.removeVoid();
|
|
|
|
shapeMap[it->Name] = currBBox;
|
|
|
|
}
|
|
|
|
validBBox = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
catch (NLMISC::Exception &e)
|
|
|
|
{
|
|
|
|
nlwarning("Error while loading shape %s. \n\t Reason : %s ", it->Name.c_str(), e.what());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nlwarning("Unable to open shape file %s to get its bbox", it->Name.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (validBBox)
|
|
|
|
{
|
|
|
|
/// build the model matrix
|
|
|
|
NLMISC::CMatrix mat;
|
|
|
|
mat.scale(it->Scale);
|
|
|
|
NLMISC::CMatrix rotMat;
|
|
|
|
rotMat.setRot(it->Rot);
|
|
|
|
mat = rotMat * mat;
|
|
|
|
mat.setPos(it->Pos);
|
|
|
|
|
|
|
|
/// transform the bbox
|
|
|
|
currBBox.transform(mat);
|
|
|
|
currBBox.removeVoid();
|
|
|
|
if (firstBBox)
|
|
|
|
{
|
|
|
|
result = currBBox;
|
|
|
|
firstBBox = false;
|
|
|
|
}
|
|
|
|
else // add to previous one
|
|
|
|
{
|
|
|
|
result.makeUnion(currBBox);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
///===========================================================================
|
|
|
|
/** Load and compute the bbox of the models that are located in a given zone
|
|
|
|
* \param the zone whose bbox must be computed
|
|
|
|
* \param result the result bbox
|
|
|
|
* \param shapeMap for speedup (avoid loading the same shape twice)
|
|
|
|
* \param additionnalIG a map that gives an additionnal ig for a zone from its name (ryzom specific : used to compute village bbox)
|
|
|
|
* \return true if the computed bbox is valid
|
|
|
|
*/
|
|
|
|
static void computeZoneIGBBox(const char *zoneName, CLightingBBox &result, TShapeMap &shapeMap, const TString2LightingBBox &additionnalIG)
|
|
|
|
{
|
|
|
|
result = CLightingBBox(); // starts with a void box
|
2010-08-09 14:20:03 +00:00
|
|
|
std::string lcZoneName = NLMISC::toLower(std::string(zoneName));
|
2010-05-06 00:08:41 +00:00
|
|
|
TString2LightingBBox::const_iterator zoneIt = additionnalIG.find(lcZoneName);
|
|
|
|
if (zoneIt != additionnalIG.end())
|
|
|
|
{
|
|
|
|
result = zoneIt->second;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string igFileName = zoneName + std::string(".ig");
|
|
|
|
std::string pathName = CPath::lookup(igFileName, false, false);
|
|
|
|
|
|
|
|
if (pathName.empty())
|
|
|
|
{
|
|
|
|
// nlwarning("unable to find instance group of zone : %s", zoneName);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/// Load the instance group of this zone
|
|
|
|
CIFile igFile;
|
|
|
|
if (!igFile.open(pathName))
|
|
|
|
{
|
|
|
|
nlwarning("unable to open file : %s", pathName.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
NL3D::CInstanceGroup ig;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
ig.serial(igFile);
|
|
|
|
}
|
|
|
|
catch (NLMISC::Exception &e)
|
|
|
|
{
|
|
|
|
nlwarning("Error while reading an instance group file : %s \n reason : %s", pathName.c_str(), e.what());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
CLightingBBox tmpBBox;
|
|
|
|
computeIGBBox(ig, tmpBBox, shapeMap);
|
|
|
|
result.makeUnion(tmpBBox);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
//=======================================================================================
|
|
|
|
// ryzom specific build bbox of a village in a zone
|
|
|
|
static void computeBBoxFromVillage(const NLGEORGES::UFormElm *villageItem,
|
|
|
|
const std::string &continentName,
|
|
|
|
uint villageIndex,
|
|
|
|
TShapeMap &shapeMap,
|
|
|
|
CLightingBBox &result
|
|
|
|
)
|
|
|
|
{
|
|
|
|
result = CLightingBBox();
|
|
|
|
const NLGEORGES::UFormElm *igNamesItem;
|
|
|
|
if (! (villageItem->getNodeByName (&igNamesItem, "IgList") && igNamesItem) )
|
|
|
|
{
|
|
|
|
nlwarning("No list of IGs was found in the continent form %s, village #%d", continentName.c_str(), villageIndex);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
// Get number of village
|
|
|
|
uint numIgs;
|
|
|
|
nlverify (igNamesItem->getArraySize (numIgs));
|
|
|
|
const NLGEORGES::UFormElm *currIg;
|
|
|
|
for(uint l = 0; l < numIgs; ++l)
|
|
|
|
{
|
|
|
|
if (!(igNamesItem->getArrayNode (&currIg, l) && currIg))
|
|
|
|
{
|
|
|
|
nlwarning("Couldn't get ig #%d in the continent form %s, in village #%d", l, continentName.c_str(), villageIndex);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
const NLGEORGES::UFormElm *igNameItem;
|
|
|
|
currIg->getNodeByName (&igNameItem, "IgName");
|
|
|
|
std::string igName;
|
|
|
|
if (!igNameItem->getValue (igName))
|
|
|
|
{
|
|
|
|
nlwarning("Couldn't get ig name of ig #%d in the continent form %s, in village #%d", l, continentName.c_str(), villageIndex);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if (igName.empty())
|
|
|
|
{
|
|
|
|
nlwarning("Ig name of ig #%d in the continent form %s, in village #%d is an empty string", l, continentName.c_str(), villageIndex);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
igName = CFile::getFilenameWithoutExtension(igName) + ".ig";
|
|
|
|
string nameLookup = CPath::lookup (igName, false, true);
|
|
|
|
if (!nameLookup.empty())
|
|
|
|
{
|
|
|
|
CIFile inputFile;
|
|
|
|
// Try to open the file
|
|
|
|
if (inputFile.open (nameLookup))
|
|
|
|
{
|
|
|
|
CInstanceGroup group;
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CLightingBBox currBBox;
|
|
|
|
group.serial (inputFile);
|
|
|
|
computeIGBBox(group, currBBox, shapeMap);
|
|
|
|
result.makeUnion(currBBox);
|
|
|
|
}
|
|
|
|
catch(NLMISC::Exception &)
|
|
|
|
{
|
|
|
|
nlwarning ("Error while loading instance group %s\n", igName.c_str());
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
inputFile.close();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Error
|
|
|
|
nlwarning ("Can't open instance group %s\n", igName.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
//=======================================================================================
|
|
|
|
/** Load additionnal ig from a continent (ryzom specific)
|
|
|
|
* \param parameter a config file that contains the name of the continent containing the zones we are processing
|
|
|
|
* \param zone2bbox This will be filled with the name of a zone and the bbox of the village it contains
|
|
|
|
* \param a map of shape
|
|
|
|
* \param a vector that will be filled with a zone name and the bbox of the village it contains
|
|
|
|
*/
|
|
|
|
static void computeIGBBoxFromContinent(NLMISC::CConfigFile ¶meter,
|
|
|
|
TShapeMap &shapeMap,
|
|
|
|
TString2LightingBBox &zone2BBox
|
|
|
|
)
|
|
|
|
{
|
|
|
|
|
|
|
|
try
|
|
|
|
{
|
|
|
|
CConfigFile::CVar &continent_name_var = parameter.getVar ("continent_name");
|
|
|
|
CConfigFile::CVar &level_design_directory = parameter.getVar ("level_design_directory");
|
|
|
|
CConfigFile::CVar &level_design_world_directory = parameter.getVar ("level_design_world_directory");
|
|
|
|
CConfigFile::CVar &level_design_dfn_directory = parameter.getVar ("level_design_dfn_directory");
|
|
|
|
CPath::addSearchPath(level_design_dfn_directory.asString(), true, false);
|
|
|
|
CPath::addSearchPath(level_design_world_directory.asString(), true, false);
|
|
|
|
|
|
|
|
std::string continentName = continent_name_var.asString();
|
|
|
|
if (CFile::getExtension(continentName).empty())
|
|
|
|
continentName += ".continent";
|
|
|
|
// Load the form
|
|
|
|
NLGEORGES::UFormLoader *loader = NLGEORGES::UFormLoader::createLoader();
|
|
|
|
//
|
|
|
|
std::string pathName = level_design_world_directory.asString() + "/" + continentName;
|
|
|
|
if (pathName.empty())
|
|
|
|
{
|
|
|
|
nlwarning("Can't find continent form : %s", continentName.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
NLGEORGES::UForm *villageForm;
|
|
|
|
villageForm = loader->loadForm(pathName.c_str());
|
|
|
|
if(villageForm != NULL)
|
|
|
|
{
|
|
|
|
NLGEORGES::UFormElm &rootItem = villageForm->getRootNode();
|
|
|
|
// try to get the village list
|
|
|
|
// Load the village list
|
|
|
|
NLGEORGES::UFormElm *villagesItem;
|
|
|
|
if(!(rootItem.getNodeByName (&villagesItem, "Villages") && villagesItem))
|
|
|
|
{
|
|
|
|
nlwarning("No villages where found in %s", continentName.c_str());
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Get number of village
|
|
|
|
uint numVillage;
|
|
|
|
nlverify (villagesItem->getArraySize (numVillage));
|
|
|
|
|
|
|
|
// For each village
|
|
|
|
for(uint k = 0; k < numVillage; ++k)
|
|
|
|
{
|
|
|
|
NLGEORGES::UFormElm *currVillage;
|
|
|
|
if (!(villagesItem->getArrayNode (&currVillage, k) && currVillage))
|
|
|
|
{
|
|
|
|
nlwarning("Couldn't get village %d in continent %s", continentName.c_str(), k);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// check that this village is in the dependency zones
|
|
|
|
NLGEORGES::UFormElm *zoneNameItem;
|
|
|
|
if (!currVillage->getNodeByName (&zoneNameItem, "Zone") && zoneNameItem)
|
|
|
|
{
|
|
|
|
nlwarning("Couldn't get zone item of village %d in continent %s", continentName.c_str(), k);
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
std::string zoneName;
|
|
|
|
if (!zoneNameItem->getValue(zoneName))
|
|
|
|
{
|
|
|
|
nlwarning("Couldn't get zone name of village %d in continent %s", continentName.c_str(), k);
|
|
|
|
continue;
|
|
|
|
}
|
2010-08-09 14:20:03 +00:00
|
|
|
zoneName = NLMISC::toLower(CFile::getFilenameWithoutExtension(zoneName));
|
2010-05-06 00:08:41 +00:00
|
|
|
CLightingBBox result;
|
|
|
|
// ok, it is in the dependant zones
|
|
|
|
computeBBoxFromVillage(currVillage, continentName, k, shapeMap, result);
|
|
|
|
if (!result.OccludingBox.IsVoid || result.ReceivingBox.IsVoid)
|
|
|
|
{
|
|
|
|
zone2BBox[zoneName] = result;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
nlwarning("Can't load continent form : %s", continentName.c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
catch (NLMISC::EUnknownVar &e)
|
|
|
|
{
|
|
|
|
nlinfo(e.what());
|
|
|
|
}
|
|
|
|
}
|