mirror of
https://port.numenaute.org/aleajactaest/khanat-opennel-code.git
synced 2024-12-24 01:48:44 +00:00
2211 lines
64 KiB
C++
2211 lines
64 KiB
C++
// Ryzom - MMORPG Framework <http://dev.ryzom.com/projects/ryzom/>
|
|
// 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 "export.h"
|
|
#include "formFlora.h"
|
|
#include "formPlant.h"
|
|
#ifdef NL_OS_WINDOWS
|
|
#define NOMINMAX
|
|
#include <windows.h>
|
|
#endif // NL_OS_WINDOWS
|
|
|
|
#include "nel/ligo/zone_region.h"
|
|
#include "nel/ligo/primitive.h"
|
|
|
|
#include "nel/georges/u_form_loader.h"
|
|
#include "nel/georges/u_form.h"
|
|
#include "nel/georges/u_form_elm.h"
|
|
|
|
#include "nel/3d/zone.h"
|
|
#include "nel/3d/landscape.h"
|
|
#include "nel/3d/scene_group.h"
|
|
#include "nel/3d/visual_collision_manager.h"
|
|
#include "nel/3d/visual_collision_entity.h"
|
|
|
|
#include "nel/misc/o_xml.h"
|
|
#include "nel/misc/i_xml.h"
|
|
#include "nel/misc/path.h"
|
|
#include "nel/misc/file.h"
|
|
|
|
#include "tools.h"
|
|
#include "../master/ContinentCfg.h"
|
|
|
|
using namespace std;
|
|
using namespace NLMISC;
|
|
using namespace NL3D;
|
|
using namespace NLLIGO;
|
|
using namespace NLGEORGES;
|
|
|
|
#define MAX_SYS_DIR 6
|
|
const char *gExportSysDir[MAX_SYS_DIR] =
|
|
{
|
|
".",
|
|
"..",
|
|
"ZoneBitmaps",
|
|
"ZoneLigos",
|
|
"dfn",
|
|
"tmp"
|
|
};
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// -----------------------------------------------------------------------------------------------
|
|
// Segment line intersection P1P2 and P3P4
|
|
bool CExport::segmentIntersection(double x1, double y1, double x2, double y2, double x3, double y3, double x4, double y4)
|
|
{
|
|
double denominator = (y4-y3)*(x2-x1) - (x4-x3)*(y2-y1);
|
|
if( denominator == 0.0 )
|
|
return false; // The segment are colinear
|
|
double k = ((x4-x3)*(y1-y3) - (y4-y3)*(x1-x3) ) / denominator;
|
|
if( (k<=0.0) || (k>=1.0) ) return false;
|
|
k = ( (x2-x1)*(y1-y3) - (y2-y1)*(x1-x3) ) / denominator;
|
|
if( (k<=0.0) || (k>=1.0) ) return false;
|
|
return true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
void CExport::delIGZone (sint32 x, sint32 y)
|
|
{
|
|
string sZoneName = CExport::getZoneNameFromXY (x, y);
|
|
sZoneName += ".ig";
|
|
if (CFile::deleteFile(sZoneName))
|
|
{
|
|
CTools::chdir (_ExeDir);
|
|
string sTmp = string(" zone ") + sZoneName + " deleted";
|
|
if (_ExportCB != NULL)
|
|
_ExportCB->dispInfo(sTmp);
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
void CExport::delAllIGZoneUnderPoint (float fCellSize, CPrimPoint *pPoint, const string &sIGOutputDir)
|
|
{
|
|
if (pPoint == NULL) return;
|
|
sint32 nX, nY;
|
|
CTools::chdir (sIGOutputDir);
|
|
nX = (sint32) floor (pPoint->Point.x / fCellSize);
|
|
nY = (sint32) floor (pPoint->Point.y / fCellSize);
|
|
delIGZone (nX, nY);
|
|
CTools::chdir (sIGOutputDir);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
void CExport::delAllIGZoneUnderPath (float fCellSize, CPrimPath *pPath, const string &sIGOutputDir)
|
|
{
|
|
if (pPath == NULL) return;
|
|
if (pPath->VPoints.size() == 0) return;
|
|
uint32 i, j;
|
|
CVector vMin, vMax;
|
|
|
|
CTools::chdir (sIGOutputDir);
|
|
vMin = vMax = pPath->VPoints[0];
|
|
for (i = 0; i < pPath->VPoints.size(); ++i)
|
|
{
|
|
if (vMin.x > pPath->VPoints[i].x) vMin.x = pPath->VPoints[i].x;
|
|
if (vMin.y > pPath->VPoints[i].y) vMin.y = pPath->VPoints[i].y;
|
|
if (vMin.z > pPath->VPoints[i].z) vMin.z = pPath->VPoints[i].z;
|
|
if (vMax.x < pPath->VPoints[i].x) vMax.x = pPath->VPoints[i].x;
|
|
if (vMax.y < pPath->VPoints[i].y) vMax.y = pPath->VPoints[i].y;
|
|
if (vMax.z < pPath->VPoints[i].z) vMax.z = pPath->VPoints[i].z;
|
|
}
|
|
|
|
sint32 x, y;
|
|
sint32 nMinX, nMinY, nMaxX, nMaxY;
|
|
nMinX = (sint32) floor (vMin.x / fCellSize);
|
|
nMinY = (sint32) floor (vMin.y / fCellSize);
|
|
nMaxX = (sint32) floor (vMax.x / fCellSize);
|
|
nMaxY = (sint32) floor (vMax.y / fCellSize);
|
|
|
|
for (x = nMinX; x <= nMaxX; ++x)
|
|
for (y = nMinY; y <= nMaxY; ++y)
|
|
{
|
|
// Does the zone (x,y) is under the patah ?
|
|
|
|
CVector vSquare[4];
|
|
vSquare[0].x = x * fCellSize;
|
|
vSquare[0].y = y * fCellSize;
|
|
vSquare[0].z = 0.0f;
|
|
|
|
vSquare[1].x = (x+1) * fCellSize;
|
|
vSquare[1].y = y * fCellSize;
|
|
vSquare[1].z = 0.0f;
|
|
|
|
vSquare[2].x = (x+1) * fCellSize;
|
|
vSquare[2].y = (y+1) * fCellSize;
|
|
vSquare[2].z = 0.0f;
|
|
|
|
vSquare[3].x = x * fCellSize;
|
|
vSquare[3].y = (y+1) * fCellSize;
|
|
vSquare[3].z = 0.0f;
|
|
|
|
// Is a vertex of the path inside the zone ?
|
|
for (i = 0; i < pPath->VPoints.size(); ++i)
|
|
{
|
|
if ((pPath->VPoints[i].x >= (x*fCellSize)) &&
|
|
(pPath->VPoints[i].x <= ((x+1)*fCellSize)) &&
|
|
(pPath->VPoints[i].y <= (y*fCellSize)) &&
|
|
(pPath->VPoints[i].y <= ((y+1)*fCellSize)))
|
|
{
|
|
delIGZone (x, y);
|
|
CTools::chdir (sIGOutputDir);
|
|
}
|
|
}
|
|
|
|
// Is an segment of the path cut an edge of the patat ?
|
|
for (i = 0; i < pPath->VPoints.size()-1; ++i)
|
|
for (j = 0; j < 4; ++j)
|
|
{
|
|
double x1 = vSquare[j].x;
|
|
double y1 = vSquare[j].y;
|
|
double x2 = vSquare[(j+1)%4].x;
|
|
double y2 = vSquare[(j+1)%4].y;
|
|
|
|
double x3 = pPath->VPoints[i].x;
|
|
double y3 = pPath->VPoints[i].y;
|
|
double x4 = pPath->VPoints[i+1].x;
|
|
double y4 = pPath->VPoints[i+1].y;
|
|
|
|
if (segmentIntersection(x1, y1, x2, y2, x3, y3, x4, y4))
|
|
{
|
|
delIGZone (x, y);
|
|
CTools::chdir (sIGOutputDir);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
void CExport::delAllIGZoneUnderPatat (float fCellSize, CPrimZone *pPatat, const string &sIGOutputDir)
|
|
{
|
|
if (pPatat == NULL) return;
|
|
if (pPatat->VPoints.size() == 0) return;
|
|
uint32 i, j;
|
|
CVector vMin, vMax;
|
|
|
|
CTools::chdir (sIGOutputDir);
|
|
vMin = vMax = pPatat->VPoints[0];
|
|
for (i = 0; i < pPatat->VPoints.size(); ++i)
|
|
{
|
|
if (vMin.x > pPatat->VPoints[i].x) vMin.x = pPatat->VPoints[i].x;
|
|
if (vMin.y > pPatat->VPoints[i].y) vMin.y = pPatat->VPoints[i].y;
|
|
if (vMin.z > pPatat->VPoints[i].z) vMin.z = pPatat->VPoints[i].z;
|
|
if (vMax.x < pPatat->VPoints[i].x) vMax.x = pPatat->VPoints[i].x;
|
|
if (vMax.y < pPatat->VPoints[i].y) vMax.y = pPatat->VPoints[i].y;
|
|
if (vMax.z < pPatat->VPoints[i].z) vMax.z = pPatat->VPoints[i].z;
|
|
}
|
|
|
|
sint32 x, y;
|
|
sint32 nMinX, nMinY, nMaxX, nMaxY;
|
|
nMinX = (sint32) floor (vMin.x / fCellSize);
|
|
nMinY = (sint32) floor (vMin.y / fCellSize);
|
|
nMaxX = (sint32) floor (vMax.x / fCellSize);
|
|
nMaxY = (sint32) floor (vMax.y / fCellSize);
|
|
|
|
for (x = nMinX; x <= nMaxX; ++x)
|
|
for (y = nMinY; y <= nMaxY; ++y)
|
|
{
|
|
// Does the zone (x,y) is under the patat ?
|
|
|
|
// Is a vertex of the zone in the patat ?
|
|
CVector vSquare[4];
|
|
vSquare[0].x = x * fCellSize;
|
|
vSquare[0].y = y * fCellSize;
|
|
vSquare[0].z = 0.0f;
|
|
|
|
vSquare[1].x = (x+1) * fCellSize;
|
|
vSquare[1].y = y * fCellSize;
|
|
vSquare[1].z = 0.0f;
|
|
|
|
vSquare[2].x = (x+1) * fCellSize;
|
|
vSquare[2].y = (y+1) * fCellSize;
|
|
vSquare[2].z = 0.0f;
|
|
|
|
vSquare[3].x = x * fCellSize;
|
|
vSquare[3].y = (y+1) * fCellSize;
|
|
vSquare[3].z = 0.0f;
|
|
|
|
for (i = 0; i < 4; ++i)
|
|
{
|
|
if (pPatat->contains(vSquare[i]))
|
|
{
|
|
delIGZone (x, y);
|
|
CTools::chdir (sIGOutputDir);
|
|
}
|
|
}
|
|
|
|
// Is a vertex of the patat inside the zone ?
|
|
for (i = 0; i < pPatat->VPoints.size(); ++i)
|
|
{
|
|
if ((pPatat->VPoints[i].x >= (x*fCellSize)) &&
|
|
(pPatat->VPoints[i].x <= ((x+1)*fCellSize)) &&
|
|
(pPatat->VPoints[i].y <= (y*fCellSize)) &&
|
|
(pPatat->VPoints[i].y <= ((y+1)*fCellSize)))
|
|
{
|
|
delIGZone (x, y);
|
|
CTools::chdir (sIGOutputDir);
|
|
}
|
|
}
|
|
|
|
// Is an edge of the zone cut an edge of the patat ?
|
|
for (i = 0; i < pPatat->VPoints.size(); ++i)
|
|
for (j = 0; j < 4; ++j)
|
|
{
|
|
double x1 = vSquare[j].x;
|
|
double y1 = vSquare[j].y;
|
|
double x2 = vSquare[(j+1)%4].x;
|
|
double y2 = vSquare[(j+1)%4].y;
|
|
|
|
double x3 = pPatat->VPoints[i].x;
|
|
double y3 = pPatat->VPoints[i].y;
|
|
double x4 = pPatat->VPoints[(i+1)%pPatat->VPoints.size()].x;
|
|
double y4 = pPatat->VPoints[(i+1)%pPatat->VPoints.size()].y;
|
|
|
|
if (segmentIntersection(x1, y1, x2, y2, x3, y3, x4, y4))
|
|
{
|
|
delIGZone (x, y);
|
|
CTools::chdir (sIGOutputDir);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// A patat needs an update if there is at least one zone under itself that is not present
|
|
bool CExport::isPatatNeedUpdate (float fCellSize, CPrimZone *pPatat, const string &sIGOutputDir)
|
|
{
|
|
uint32 i, j;
|
|
CVector vMin, vMax;
|
|
|
|
CTools::chdir (sIGOutputDir);
|
|
if (pPatat->VPoints.size() == 0)
|
|
return false;
|
|
vMin = vMax = pPatat->VPoints[0];
|
|
for (i = 0; i < pPatat->VPoints.size(); ++i)
|
|
{
|
|
if (vMin.x > pPatat->VPoints[i].x) vMin.x = pPatat->VPoints[i].x;
|
|
if (vMin.y > pPatat->VPoints[i].y) vMin.y = pPatat->VPoints[i].y;
|
|
if (vMin.z > pPatat->VPoints[i].z) vMin.z = pPatat->VPoints[i].z;
|
|
if (vMax.x < pPatat->VPoints[i].x) vMax.x = pPatat->VPoints[i].x;
|
|
if (vMax.y < pPatat->VPoints[i].y) vMax.y = pPatat->VPoints[i].y;
|
|
if (vMax.z < pPatat->VPoints[i].z) vMax.z = pPatat->VPoints[i].z;
|
|
}
|
|
|
|
sint32 x, y;
|
|
sint32 nMinX, nMinY, nMaxX, nMaxY;
|
|
nMinX = (sint32) floor (vMin.x / fCellSize);
|
|
nMinY = (sint32) floor (vMin.y / fCellSize);
|
|
nMaxX = (sint32) floor (vMax.x / fCellSize);
|
|
nMaxY = (sint32) floor (vMax.y / fCellSize);
|
|
|
|
for (x = nMinX; x <= nMaxX; ++x)
|
|
for (y = nMinY; y <= nMaxY; ++y)
|
|
{
|
|
// Does the zone (x,y) is under the patat ?
|
|
bool bZoneUnderPatat = false;
|
|
// Is a vertex of the zone in the patat ?
|
|
CVector vSquare[4];
|
|
vSquare[0].x = x * fCellSize;
|
|
vSquare[0].y = y * fCellSize;
|
|
vSquare[0].z = 0.0f;
|
|
|
|
vSquare[1].x = (x+1) * fCellSize;
|
|
vSquare[1].y = y * fCellSize;
|
|
vSquare[1].z = 0.0f;
|
|
|
|
vSquare[2].x = (x+1) * fCellSize;
|
|
vSquare[2].y = (y+1) * fCellSize;
|
|
vSquare[2].z = 0.0f;
|
|
|
|
vSquare[3].x = x * fCellSize;
|
|
vSquare[3].y = (y+1) * fCellSize;
|
|
vSquare[3].z = 0.0f;
|
|
|
|
for (i = 0; i < 4; ++i)
|
|
{
|
|
if (pPatat->contains(vSquare[i]))
|
|
{
|
|
string sTmp = CExport::getZoneNameFromXY(x,y) + ".ig";
|
|
if (!CTools::fileExist(sTmp)) // If the file does not exist
|
|
return true; // need update
|
|
}
|
|
}
|
|
|
|
// Is a vertex of the patat inside the zone ?
|
|
for (i = 0; i < pPatat->VPoints.size(); ++i)
|
|
{
|
|
if ((pPatat->VPoints[i].x >= (x*fCellSize)) &&
|
|
(pPatat->VPoints[i].x <= ((x+1)*fCellSize)) &&
|
|
(pPatat->VPoints[i].y >= (y*fCellSize)) &&
|
|
(pPatat->VPoints[i].y <= ((y+1)*fCellSize)))
|
|
{
|
|
string sTmp = CExport::getZoneNameFromXY(x,y) + ".ig";
|
|
if (!CTools::fileExist(sTmp)) // If the file does not exist
|
|
return true; // need update
|
|
}
|
|
}
|
|
|
|
// Is an edge of the zone cut an edge of the patat ?
|
|
for (i = 0; i < pPatat->VPoints.size(); ++i)
|
|
for (j = 0; j < 4; ++j)
|
|
{
|
|
double x1 = vSquare[j].x;
|
|
double y1 = vSquare[j].y;
|
|
double x2 = vSquare[(j+1)%4].x;
|
|
double y2 = vSquare[(j+1)%4].y;
|
|
|
|
double x3 = pPatat->VPoints[i].x;
|
|
double y3 = pPatat->VPoints[i].y;
|
|
double x4 = pPatat->VPoints[(i+1)%pPatat->VPoints.size()].x;
|
|
double y4 = pPatat->VPoints[(i+1)%pPatat->VPoints.size()].y;
|
|
|
|
if (segmentIntersection(x1, y1, x2, y2, x3, y3, x4, y4))
|
|
{
|
|
string sTmp = CExport::getZoneNameFromXY (x, y) + ".ig";
|
|
if (!CTools::fileExist(sTmp)) // If the file does not exist
|
|
return true; // need update
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// A path needs an update if there is at least one zone under itself that is not present
|
|
bool CExport::isPathNeedUpdate (float fCellSize, CPrimPath *pPath, const string &sIGOutputDir)
|
|
{
|
|
uint32 i, j;
|
|
CVector vMin, vMax;
|
|
|
|
CTools::chdir (sIGOutputDir);
|
|
if (pPath->VPoints.size() == 0)
|
|
return false;
|
|
vMin = vMax = pPath->VPoints[0];
|
|
for (i = 0; i < pPath->VPoints.size(); ++i)
|
|
{
|
|
if (vMin.x > pPath->VPoints[i].x) vMin.x = pPath->VPoints[i].x;
|
|
if (vMin.y > pPath->VPoints[i].y) vMin.y = pPath->VPoints[i].y;
|
|
if (vMin.z > pPath->VPoints[i].z) vMin.z = pPath->VPoints[i].z;
|
|
if (vMax.x < pPath->VPoints[i].x) vMax.x = pPath->VPoints[i].x;
|
|
if (vMax.y < pPath->VPoints[i].y) vMax.y = pPath->VPoints[i].y;
|
|
if (vMax.z < pPath->VPoints[i].z) vMax.z = pPath->VPoints[i].z;
|
|
}
|
|
|
|
sint32 x, y;
|
|
sint32 nMinX, nMinY, nMaxX, nMaxY;
|
|
nMinX = (sint32) floor (vMin.x / fCellSize);
|
|
nMinY = (sint32) floor (vMin.y / fCellSize);
|
|
nMaxX = (sint32) floor (vMax.x / fCellSize);
|
|
nMaxY = (sint32) floor (vMax.y / fCellSize);
|
|
|
|
for (x = nMinX; x <= nMaxX; ++x)
|
|
for (y = nMinY; y <= nMaxY; ++y)
|
|
{
|
|
// Does the zone (x,y) is under the patat ?
|
|
bool bZoneUnderPatat = false;
|
|
// Is a vertex of the zone in the patat ?
|
|
CVector vSquare[4];
|
|
vSquare[0].x = x * fCellSize;
|
|
vSquare[0].y = y * fCellSize;
|
|
vSquare[0].z = 0.0f;
|
|
|
|
vSquare[1].x = (x+1) * fCellSize;
|
|
vSquare[1].y = y * fCellSize;
|
|
vSquare[1].z = 0.0f;
|
|
|
|
vSquare[2].x = (x+1) * fCellSize;
|
|
vSquare[2].y = (y+1) * fCellSize;
|
|
vSquare[2].z = 0.0f;
|
|
|
|
vSquare[3].x = x * fCellSize;
|
|
vSquare[3].y = (y+1) * fCellSize;
|
|
vSquare[3].z = 0.0f;
|
|
|
|
// Is a vertex of the path inside the zone ?
|
|
for (i = 0; i < pPath->VPoints.size(); ++i)
|
|
{
|
|
if ((pPath->VPoints[i].x >= (x*fCellSize)) &&
|
|
(pPath->VPoints[i].x <= ((x+1)*fCellSize)) &&
|
|
(pPath->VPoints[i].y >= (y*fCellSize)) &&
|
|
(pPath->VPoints[i].y <= ((y+1)*fCellSize)))
|
|
{
|
|
string sTmp = CExport::getZoneNameFromXY(x,y) + ".ig";
|
|
if (!CTools::fileExist(sTmp)) // If the file does not exist
|
|
return true; // need update
|
|
}
|
|
}
|
|
|
|
// Is an edge of the zone cut an edge of the patat ?
|
|
for (i = 0; i < (pPath->VPoints.size()-1); ++i)
|
|
for (j = 0; j < 4; ++j)
|
|
{
|
|
double x1 = vSquare[j].x;
|
|
double y1 = vSquare[j].y;
|
|
double x2 = vSquare[(j+1)%4].x;
|
|
double y2 = vSquare[(j+1)%4].y;
|
|
|
|
double x3 = pPath->VPoints[i].x;
|
|
double y3 = pPath->VPoints[i].y;
|
|
double x4 = pPath->VPoints[i+1].x;
|
|
double y4 = pPath->VPoints[i+1].y;
|
|
|
|
if (segmentIntersection(x1, y1, x2, y2, x3, y3, x4, y4))
|
|
{
|
|
string sTmp = CExport::getZoneNameFromXY (x, y) + ".ig";
|
|
if (!CTools::fileExist(sTmp)) // If the file does not exist
|
|
return true; // need update
|
|
}
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// A path needs an update if there is at least one zone under itself that is not present
|
|
bool CExport::isPointNeedUpdate (float fCellSize, CPrimPoint *pPoint, const string &sIGOutputDir)
|
|
{
|
|
CTools::chdir (sIGOutputDir);
|
|
|
|
sint32 x, y;
|
|
x = (sint32) floor (pPoint->Point.x / fCellSize);
|
|
y = (sint32) floor (pPoint->Point.y / fCellSize);
|
|
|
|
// Does the zone (x,y) is under the patat ?
|
|
bool bZoneUnderPatat = false;
|
|
// Is a vertex of the zone in the patat ?
|
|
CVector vSquare[4];
|
|
vSquare[0].x = x * fCellSize;
|
|
vSquare[0].y = y * fCellSize;
|
|
vSquare[0].z = 0.0f;
|
|
|
|
vSquare[1].x = (x+1) * fCellSize;
|
|
vSquare[1].y = y * fCellSize;
|
|
vSquare[1].z = 0.0f;
|
|
|
|
vSquare[2].x = (x+1) * fCellSize;
|
|
vSquare[2].y = (y+1) * fCellSize;
|
|
vSquare[2].z = 0.0f;
|
|
|
|
vSquare[3].x = x * fCellSize;
|
|
vSquare[3].y = (y+1) * fCellSize;
|
|
vSquare[3].z = 0.0f;
|
|
|
|
// Is the vertex inside the zone ?
|
|
if ((pPoint->Point.x >= (x*fCellSize)) &&
|
|
(pPoint->Point.x <= ((x+1)*fCellSize)) &&
|
|
(pPoint->Point.y >= (y*fCellSize)) &&
|
|
(pPoint->Point.y <= ((y+1)*fCellSize)))
|
|
{
|
|
string sTmp = CExport::getZoneNameFromXY(x,y) + ".ig";
|
|
if (!CTools::fileExist(sTmp)) // If the file does not exist
|
|
return true; // need update
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SExportOptions
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// ---------------------------------------------------------------------------
|
|
SExportOptions::SExportOptions ()
|
|
{
|
|
CellSize = 160.0f;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
bool SExportOptions::loadcf (CConfigFile &cf)
|
|
{
|
|
// Out
|
|
CConfigFile::CVar &cvOutIGDir = cf.getVar("EXP_OutIGDir");
|
|
OutIGDir = cvOutIGDir.asString();
|
|
|
|
// In
|
|
CConfigFile::CVar &cvInLandscapeDir = cf.getVar("EXP_ZoneWDir");
|
|
InLandscapeDir = cvInLandscapeDir.asString();
|
|
|
|
CConfigFile::CVar &cvLandBankFile = cf.getVar("EXP_SmallBank");
|
|
LandBankFile = cvLandBankFile.asString();
|
|
CConfigFile::CVar &cvLandFarBankFile = cf.getVar("EXP_FarBank");
|
|
LandFarBankFile = cvLandFarBankFile.asString();
|
|
CConfigFile::CVar &cvLandTileNoiseDir = cf.getVar("EXP_DisplaceDir");
|
|
LandTileNoiseDir = cvLandTileNoiseDir.asString();
|
|
|
|
CConfigFile::CVar &cvCellSize = cf.getVar("EXP_CellSize");
|
|
CellSize = cvCellSize.asFloat();
|
|
|
|
CConfigFile::CVar &cvPrimFloraDir = cf.getVar("EXP_PrimFloraDir");
|
|
PrimFloraDir = cvPrimFloraDir.asString();
|
|
|
|
return true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
bool SExportOptions::save (FILE *f)
|
|
{
|
|
fprintf (f,"\n// Export Options\n");
|
|
fprintf (f, "EXP_OutIGDir = \"%s\";\n", OutIGDir);
|
|
fprintf (f, "EXP_ZoneWDir = \"%s\";\n", InLandscapeDir);
|
|
fprintf (f, "EXP_SmallBank = \"%s\";\n", LandBankFile);
|
|
fprintf (f, "EXP_FarBank = \"%s\";\n", LandFarBankFile);
|
|
fprintf (f, "EXP_DisplaceDir = \"%s\";\n", LandTileNoiseDir);
|
|
fprintf (f, "EXP_CellSize = %f;\n", CellSize);
|
|
fprintf (f, "EXP_PrimFloraDir = \"%s\";\n", PrimFloraDir);
|
|
return true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// SExportPrimitive
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// ---------------------------------------------------------------------------
|
|
bool SExportPrimitive::operator == (const SExportPrimitive &rRightArg)
|
|
{
|
|
if (strcmp(this->FullPrimName.c_str(), rRightArg.FullPrimName.c_str()) == 0)
|
|
if (strcmp(this->PrimitiveName.c_str(), rRightArg.PrimitiveName.c_str()) == 0)
|
|
return true;
|
|
return false;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
// CExport
|
|
// ---------------------------------------------------------------------------
|
|
|
|
// ---------------------------------------------------------------------------
|
|
CExport::CExport()
|
|
{
|
|
_Landscape = NULL;
|
|
_VCM = NULL;
|
|
_VCE = NULL;
|
|
_ExportCB = NULL;
|
|
_Options = NULL;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
CExport::~CExport()
|
|
{
|
|
if (_Landscape != NULL)
|
|
delete _Landscape;
|
|
if (_VCM != NULL)
|
|
{
|
|
_VCM->deleteEntity (_VCE);
|
|
delete _VCM;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
// ---------------------------------------------------------------------------
|
|
bool CExport::newExport (SExportOptions &opt, IExportCB *expCB)
|
|
{
|
|
_ExeDir = CTools::pwd();
|
|
_Options = &opt;
|
|
_ExportCB = expCB;
|
|
|
|
string sTmp;
|
|
uint32 i, j, k, m;
|
|
|
|
|
|
|
|
// First of all read the CFG
|
|
string sContinentDir = _Options->PrimFloraDir;
|
|
|
|
sContinentDir = CTools::normalizePath (sContinentDir);
|
|
CTools::chdir (sContinentDir.c_str()); // Relative to absolute path
|
|
sContinentDir = CTools::pwd () + "\\";
|
|
CTools::chdir (_ExeDir);
|
|
|
|
// Read continent.cfg
|
|
SContinentCfg ContinentCFG;
|
|
{
|
|
string sTmp = sContinentDir + "continent.cfg";
|
|
if (!ContinentCFG.load(sTmp.c_str()))
|
|
throw Exception("Cannot load continent.cfg");
|
|
}
|
|
|
|
// Ok set parameters from options first and with CFG if no options set
|
|
|
|
if (_Options->OutIGDir == "")
|
|
_OutIGDir = CTools::normalizePath (ContinentCFG.OutIGDir);
|
|
else
|
|
_OutIGDir = CTools::normalizePath (_Options->OutIGDir);
|
|
|
|
if (_Options->LandFile == "")
|
|
_LandFile = ContinentCFG.LandFile;
|
|
else
|
|
_LandFile = _Options->LandFile;
|
|
|
|
if (_Options->DfnDir == "")
|
|
_DfnDir = ContinentCFG.DfnDir;
|
|
else
|
|
_DfnDir = _Options->DfnDir;
|
|
|
|
if (_Options->GameElemDir == "")
|
|
_GameElemDir = ContinentCFG.GameElemDir;
|
|
else
|
|
_GameElemDir = _Options->GameElemDir;
|
|
|
|
if (_Options->InLandscapeDir == "")
|
|
_InLandscapeDir = ContinentCFG.LandZoneWDir; // Directory where to get .zonew files
|
|
else
|
|
_InLandscapeDir = _Options->InLandscapeDir;
|
|
|
|
if (_Options->LandFarBankFile == "")
|
|
_LandBankFile = ContinentCFG.LandBankFile; // The .smallbank file associated with the landscape
|
|
else
|
|
_LandBankFile = _Options->LandBankFile;
|
|
|
|
if (_Options->LandFarBankFile == "")
|
|
_LandFarBankFile = ContinentCFG.LandFarBankFile; // The .farbank file
|
|
else
|
|
_LandFarBankFile = _Options->LandFarBankFile;
|
|
|
|
if (_Options->LandTileNoiseDir == "")
|
|
_LandTileNoiseDir = ContinentCFG.LandTileNoiseDir; // Directory where to get displacement map
|
|
else
|
|
_LandTileNoiseDir = _Options->LandTileNoiseDir;
|
|
|
|
|
|
// Now create output directory
|
|
CTools::mkdir (_OutIGDir);
|
|
|
|
CTools::chdir (_OutIGDir.c_str());
|
|
_OutIGDir = CTools::pwd () + "\\";
|
|
CTools::chdir (_ExeDir);
|
|
|
|
|
|
CPath::addSearchPath (_DfnDir, true, true);
|
|
CPath::addSearchPath (_GameElemDir, true, true);
|
|
CPath::addSearchPath (_LandTileNoiseDir, true, true);
|
|
|
|
|
|
// Get all regions
|
|
vector<string> vRegions;
|
|
WIN32_FIND_DATA findData;
|
|
HANDLE hFind;
|
|
|
|
CTools::chdir (sContinentDir);
|
|
hFind = FindFirstFile ("*.*", &findData);
|
|
while (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (GetFileAttributes(findData.cFileName)&FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
// Look if the name is a system directory
|
|
bool bFound = false;
|
|
for (i = 0; i < MAX_SYS_DIR; ++i)
|
|
if (stricmp (findData.cFileName, gExportSysDir[i]) == 0)
|
|
{
|
|
bFound = true;
|
|
break;
|
|
}
|
|
if (!bFound) // No, ok lets recurse it
|
|
{
|
|
vRegions.push_back (findData.cFileName);
|
|
}
|
|
}
|
|
if (FindNextFile (hFind, &findData) == 0)
|
|
break;
|
|
}
|
|
FindClose (hFind);
|
|
|
|
|
|
// Process all regions
|
|
uint32 nRegion;
|
|
for (nRegion = 0; nRegion < vRegions.size(); ++nRegion)
|
|
{
|
|
CTools::chdir (sContinentDir + vRegions[nRegion]);
|
|
|
|
// Process if a flora has been modified
|
|
vector<SFloraToUpdate> vFloraToUpdate;
|
|
uint32 nFloraFile;
|
|
|
|
// Fill the structure for update
|
|
{
|
|
// Get all new flora of the region
|
|
vector<string> vFloraFiles;
|
|
CTools::dirSub ("*.flora", vFloraFiles, true);
|
|
for (nFloraFile = 0; nFloraFile < vFloraFiles.size(); ++nFloraFile)
|
|
{
|
|
// Compare the date with the old file stored in the IG output directory
|
|
CTools::chdir (sContinentDir + vRegions[nRegion]);
|
|
string sBaseName = vFloraFiles[nFloraFile].substr(sContinentDir.size());
|
|
sBaseName = sBaseName.substr(0,sBaseName.rfind('\\'));
|
|
for (i = 0; i < sBaseName.size(); ++i)
|
|
if (sBaseName[i] == '\\')
|
|
sBaseName[i] = '-';
|
|
sBaseName += '-';
|
|
string sOldFloraName = _OutIGDir + sBaseName + vFloraFiles[nFloraFile].substr(vFloraFiles[nFloraFile].rfind('\\')+1);
|
|
|
|
if (CTools::fileExist(sOldFloraName))
|
|
{
|
|
if (CTools::fileDateCmp(vFloraFiles[nFloraFile], sOldFloraName) > 0)
|
|
{
|
|
// Delete zones from the 2 files
|
|
SFloraToUpdate ftuTmp;
|
|
// Delete zones from the newest file
|
|
ftuTmp.FloraFile = vFloraFiles[nFloraFile];
|
|
CTools::chdir (vFloraFiles[nFloraFile].substr(0,vFloraFiles[nFloraFile].rfind('\\')));
|
|
CTools::dir ("*.prim", ftuTmp.PrimFile, true);
|
|
vFloraToUpdate.push_back (ftuTmp);
|
|
// Delete zones from the oldest file
|
|
CTools::chdir (_OutIGDir);
|
|
ftuTmp.FloraFile = sOldFloraName;
|
|
CTools::dir (sBaseName + "*.prim", ftuTmp.PrimFile, true);
|
|
vFloraToUpdate.push_back (ftuTmp);
|
|
CTools::chdir (_ExeDir);
|
|
sTmp = vFloraFiles[nFloraFile] + " has been modified.";
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
}
|
|
else
|
|
{
|
|
CTools::chdir (_ExeDir);
|
|
sTmp = vFloraFiles[nFloraFile] + string(" up to date.");
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Delete zone from newest file
|
|
SFloraToUpdate ftuTmp;
|
|
ftuTmp.FloraFile = vFloraFiles[nFloraFile];
|
|
CTools::chdir (vFloraFiles[nFloraFile].substr(0,vFloraFiles[nFloraFile].rfind('\\')));
|
|
CTools::dir ("*.prim", ftuTmp.PrimFile, true);
|
|
vFloraToUpdate.push_back (ftuTmp);
|
|
CTools::chdir (_ExeDir);
|
|
sTmp = vFloraFiles[nFloraFile] + " not generated.";
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
}
|
|
}
|
|
|
|
// Get all old flora of the current region
|
|
CTools::chdir (_OutIGDir);
|
|
CTools::dir (vRegions[nRegion] + "-*.flora", vFloraFiles, true);
|
|
for (nFloraFile = 0; nFloraFile < vFloraFiles.size(); ++nFloraFile)
|
|
{
|
|
CTools::chdir (_OutIGDir);
|
|
// if the old flora file still exist but the new one not -> delete zone for the oldest file
|
|
string sNewFloraName = vFloraFiles[nFloraFile].substr(vFloraFiles[nFloraFile].rfind('\\')+1);
|
|
string sBaseName = sNewFloraName.substr (0, vFloraFiles[nFloraFile].rfind('-'));
|
|
for (i = 0; i < sNewFloraName.size(); ++i)
|
|
if (sNewFloraName[i] == '-')
|
|
sNewFloraName[i] = '\\';
|
|
|
|
sNewFloraName = sContinentDir + sNewFloraName;
|
|
if (!CTools::fileExist(sNewFloraName))
|
|
{
|
|
SFloraToUpdate ftuTmp;
|
|
// Delete zones from the oldest file
|
|
ftuTmp.FloraFile = vFloraFiles[nFloraFile];
|
|
CTools::dir (sBaseName + "*.prim", ftuTmp.PrimFile, true);
|
|
vFloraToUpdate.push_back (ftuTmp);
|
|
CTools::chdir (_ExeDir);
|
|
sTmp = vFloraFiles[nFloraFile] + " not needed anymore.";
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
}
|
|
}
|
|
}
|
|
// End of fill the structure for update
|
|
|
|
// Interpret the FloraToUpdate
|
|
for (nFloraFile = 0; nFloraFile < vFloraToUpdate.size(); ++nFloraFile)
|
|
{
|
|
// Get all patats referenced by the flora and suppress zones under
|
|
|
|
// Load the .flora file
|
|
SFormFlora FormFlora;
|
|
{
|
|
// Get a loader
|
|
UFormLoader *loader = UFormLoader::createLoader ();
|
|
|
|
// Load the form
|
|
CSmartPtr<UForm> form = loader->loadForm (vFloraToUpdate[nFloraFile].FloraFile.c_str ());
|
|
if (form)
|
|
FormFlora.build (form->getRootNode ());
|
|
|
|
// Release the loader
|
|
UFormLoader::releaseLoader (loader);
|
|
}
|
|
|
|
// Load all the .prim files that can be referenced by the flora
|
|
vector<CPrimRegion> vPrimRegions;
|
|
{
|
|
vector<string> &rPrimFiles = vFloraToUpdate[nFloraFile].PrimFile;
|
|
for (i = 0; i < rPrimFiles.size(); ++i)
|
|
{
|
|
CPrimRegion tmpPrimRegion;
|
|
CIFile fileIn;
|
|
fileIn.open (rPrimFiles[i]);
|
|
CIXml input;
|
|
input.init (fileIn);
|
|
tmpPrimRegion.serial (input);
|
|
vPrimRegions.push_back (tmpPrimRegion);
|
|
}
|
|
}
|
|
|
|
// Delete zones under the old prims referenced by the old zone
|
|
|
|
for (i = 0; i < FormFlora.IncludePatats.size(); ++i)
|
|
{
|
|
// Get the patat
|
|
CPrimZone *pPatat = NULL;
|
|
CPrimPoint *pPoint = NULL;
|
|
CPrimPath *pPath = NULL;
|
|
for (j = 0; j < vPrimRegions.size(); ++j)
|
|
{
|
|
for (k = 0; k < vPrimRegions[j].VZones.size(); ++k)
|
|
if (vPrimRegions[j].VZones[k].getName() == FormFlora.IncludePatats[i])
|
|
pPatat = &vPrimRegions[j].VZones[k];
|
|
for (k = 0; k < vPrimRegions[j].VPoints.size(); ++k)
|
|
if (vPrimRegions[j].VPoints[k].getName() == FormFlora.IncludePatats[i])
|
|
pPoint = &vPrimRegions[j].VPoints[k];
|
|
for (k = 0; k < vPrimRegions[j].VPaths.size(); ++k)
|
|
if (vPrimRegions[j].VPaths[k].getName() == FormFlora.IncludePatats[i])
|
|
pPath = &vPrimRegions[j].VPaths[k];
|
|
}
|
|
|
|
if ((pPatat == NULL) && (pPoint == NULL) && (pPath == NULL))
|
|
{
|
|
CTools::chdir (_ExeDir);
|
|
sTmp = "WARNING : Cannot find " + FormFlora.IncludePatats[i];
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
continue;
|
|
}
|
|
|
|
if ((pPatat != NULL) && (pPatat->VPoints.size() <= 2))
|
|
{
|
|
CTools::chdir (_ExeDir);
|
|
sTmp = "Patat " + pPatat->getName() + " has less than 3 points";
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
continue;
|
|
}
|
|
|
|
if ((pPath != NULL) && (pPath->VPoints.size() < 2))
|
|
{
|
|
CTools::chdir (_ExeDir);
|
|
sTmp = "Patat " + pPatat->getName() + " has less than 2 points";
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
continue;
|
|
}
|
|
|
|
if (pPatat != NULL)
|
|
delAllIGZoneUnderPatat (160.0f, pPatat, _OutIGDir);
|
|
if (pPoint != NULL)
|
|
delAllIGZoneUnderPoint (160.0f, pPoint, _OutIGDir);
|
|
if (pPath != NULL)
|
|
delAllIGZoneUnderPath (160.0f, pPath, _OutIGDir);
|
|
}
|
|
}
|
|
// End of Process if a flora has been modified
|
|
|
|
// Process if a prim has been modified
|
|
// Fill the structure for update
|
|
CTools::chdir (sContinentDir + vRegions[nRegion]);
|
|
vector<SPrimToUpdate> vPrimToUpdate;
|
|
{
|
|
uint32 nPrimFile;
|
|
vector<string> vPrimFiles;
|
|
// Get all new prim of the region
|
|
CTools::dirSub ("*.prim", vPrimFiles, true);
|
|
for (nPrimFile = 0; nPrimFile < vPrimFiles.size(); ++nPrimFile)
|
|
{
|
|
CTools::chdir (sContinentDir + vRegions[nRegion]);
|
|
// Compare the date with the old file stored in the IG output directory
|
|
string sBaseName = vPrimFiles[nPrimFile].substr(sContinentDir.size());
|
|
sBaseName = sBaseName.substr(0,sBaseName.rfind('\\'));
|
|
for (i = 0; i < sBaseName.size(); ++i)
|
|
if (sBaseName[i] == '\\')
|
|
sBaseName[i] = '-';
|
|
sBaseName += '-';
|
|
string sOldPrimName = _OutIGDir + sBaseName + vPrimFiles[nPrimFile].substr(vPrimFiles[nPrimFile].rfind('\\')+1);
|
|
|
|
if (CTools::fileExist(sOldPrimName))
|
|
{
|
|
if (CTools::fileDateCmp(vPrimFiles[nPrimFile], sOldPrimName) > 0)
|
|
{
|
|
// Delete zones from the 2 files
|
|
SPrimToUpdate ptuTmp;
|
|
// Delete zones from the newest file
|
|
ptuTmp.PrimFile = vPrimFiles[nPrimFile];
|
|
CTools::chdir (vPrimFiles[nPrimFile].substr(0,vPrimFiles[nPrimFile].rfind('\\')));
|
|
CTools::dir ("*.flora", ptuTmp.FloraFile, true);
|
|
vPrimToUpdate.push_back (ptuTmp);
|
|
// Delete zones from the oldest file
|
|
CTools::chdir (_OutIGDir);
|
|
ptuTmp.PrimFile = sOldPrimName;
|
|
CTools::dir (sBaseName + "*.flora", ptuTmp.FloraFile, true);
|
|
vPrimToUpdate.push_back (ptuTmp);
|
|
CTools::chdir (_ExeDir);
|
|
sTmp = vPrimFiles[nPrimFile] + " has been modified.";
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
}
|
|
else
|
|
{
|
|
CTools::chdir (_ExeDir);
|
|
sTmp = vPrimFiles[nPrimFile] + " up to date.";
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
// Delete zone from newest file
|
|
SPrimToUpdate ptuTmp;
|
|
ptuTmp.PrimFile = vPrimFiles[nPrimFile];
|
|
CTools::chdir (vPrimFiles[nPrimFile].substr(0,vPrimFiles[nPrimFile].rfind('\\')));
|
|
CTools::dir ("*.flora", ptuTmp.FloraFile, true);
|
|
vPrimToUpdate.push_back (ptuTmp);
|
|
CTools::chdir (_ExeDir);
|
|
sTmp = vPrimFiles[nPrimFile] + " not generated.";
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
}
|
|
}
|
|
|
|
// Get all old prim of the current region
|
|
CTools::chdir (_OutIGDir);
|
|
CTools::dir (vRegions[nRegion] + "-*.prim", vPrimFiles, false);
|
|
for (nPrimFile = 0; nPrimFile < vPrimFiles.size(); ++nPrimFile)
|
|
{
|
|
CTools::chdir (_OutIGDir);
|
|
// if the old prim file still exist but the new one not -> delete zone for the oldest file
|
|
string sNewPrimName = vPrimFiles[nPrimFile].substr(vPrimFiles[nPrimFile].rfind('\\')+1);
|
|
string sBaseName = sNewPrimName.substr (0, vPrimFiles[nPrimFile].rfind('-'));
|
|
for (i = 0; i < sNewPrimName.size(); ++i)
|
|
if (sNewPrimName[i] == '-')
|
|
sNewPrimName[i] = '\\';
|
|
|
|
sNewPrimName = sContinentDir + sNewPrimName;
|
|
if (!CTools::fileExist(sNewPrimName))
|
|
{
|
|
// Delete zones from the oldest file
|
|
CPrimRegion PrimRegion;
|
|
{
|
|
CIFile fileIn;
|
|
fileIn.open (vPrimFiles[nPrimFile]);
|
|
CIXml input;
|
|
input.init (fileIn);
|
|
PrimRegion.serial (input);
|
|
}
|
|
|
|
for (j = 0; j < PrimRegion.VZones.size(); ++j)
|
|
delAllIGZoneUnderPatat (_Options->CellSize, &PrimRegion.VZones[j], _OutIGDir);
|
|
for (j = 0; j < PrimRegion.VPaths.size(); ++j)
|
|
delAllIGZoneUnderPath (_Options->CellSize, &PrimRegion.VPaths[j], _OutIGDir);
|
|
for (j = 0; j < PrimRegion.VPoints.size(); ++j)
|
|
delAllIGZoneUnderPoint (_Options->CellSize, &PrimRegion.VPoints[j], _OutIGDir);
|
|
|
|
CTools::chdir (_ExeDir);
|
|
sTmp = vPrimFiles[nPrimFile] + " not needed anymore.";
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
}
|
|
}
|
|
}
|
|
// End of fill the structure for update
|
|
|
|
// Interpretation of structure for update
|
|
for (i = 0; i < vPrimToUpdate.size(); ++i)
|
|
{
|
|
// Load all the .flora file
|
|
vector<SFormFlora> vFormFloras;
|
|
for (j = 0; j < vPrimToUpdate[i].FloraFile.size(); ++j)
|
|
{
|
|
// Create the loader
|
|
UFormLoader *loader = UFormLoader::createLoader ();
|
|
|
|
// Load the form
|
|
CSmartPtr<UForm> form = loader->loadForm (vPrimToUpdate[i].FloraFile[j].c_str ());
|
|
if (form)
|
|
{
|
|
SFormFlora FormFloraTmp;
|
|
FormFloraTmp.build (form->getRootNode ());
|
|
vFormFloras.push_back (FormFloraTmp);
|
|
}
|
|
|
|
// Release the loader
|
|
UFormLoader::releaseLoader (loader);
|
|
}
|
|
|
|
// Load all the .prim files that can be referenced by the flora
|
|
CPrimRegion PrimRegion;
|
|
{
|
|
CIFile fileIn;
|
|
fileIn.open (vPrimToUpdate[i].PrimFile);
|
|
CIXml input;
|
|
input.init (fileIn);
|
|
PrimRegion.serial (input);
|
|
}
|
|
|
|
// Delete zones under the prims that has been referenced by a flora
|
|
|
|
for (j = 0; j < PrimRegion.VZones.size(); ++j)
|
|
{
|
|
// Get the patat
|
|
CPrimZone *pPatat = NULL;
|
|
|
|
// Check if the current patat is referenced by a flora
|
|
for (k = 0; k < vFormFloras.size(); ++k)
|
|
for (m = 0; m < vFormFloras[k].IncludePatats.size(); ++m)
|
|
if (PrimRegion.VZones[j].getName() == vFormFloras[k].IncludePatats[m])
|
|
pPatat = &PrimRegion.VZones[j];
|
|
|
|
if ((pPatat == NULL) || (pPatat->VPoints.size() <= 2))
|
|
{
|
|
continue;
|
|
}
|
|
delAllIGZoneUnderPatat (_Options->CellSize, pPatat, _OutIGDir);
|
|
}
|
|
for (j = 0; j < PrimRegion.VPoints.size(); ++j)
|
|
{
|
|
// Get the point
|
|
CPrimPoint *pPoint = NULL;
|
|
|
|
// Check if the current point is referenced by a flora
|
|
for (k = 0; k < vFormFloras.size(); ++k)
|
|
for (m = 0; m < vFormFloras[k].IncludePatats.size(); ++m)
|
|
if (PrimRegion.VPoints[j].getName() == vFormFloras[k].IncludePatats[m])
|
|
pPoint = &PrimRegion.VPoints[j];
|
|
delAllIGZoneUnderPoint (_Options->CellSize, pPoint, _OutIGDir);
|
|
}
|
|
for (j = 0; j < PrimRegion.VPaths.size(); ++j)
|
|
{
|
|
// Get the path
|
|
CPrimPath *pPath = NULL;
|
|
|
|
// Check if the current path is referenced by a flora
|
|
for (k = 0; k < vFormFloras.size(); ++k)
|
|
for (m = 0; m < vFormFloras[k].IncludePatats.size(); ++m)
|
|
if (PrimRegion.VPaths[j].getName() == vFormFloras[k].IncludePatats[m])
|
|
pPath = &PrimRegion.VPaths[j];
|
|
delAllIGZoneUnderPath (_Options->CellSize, pPath, _OutIGDir);
|
|
}
|
|
}
|
|
// End of Process if a prim has been modified
|
|
|
|
}
|
|
// End of process all regions
|
|
|
|
// Check all patat to export (a patat that has no zone under itself (deleted or not present))
|
|
vector<SExportPrimitive> vExportPrimitives;
|
|
vector<string> vAllPrimFiles; // All prim files of a continent
|
|
CTools::chdir (sContinentDir);
|
|
CTools::dirSub ("*.prim", vAllPrimFiles, true);
|
|
for (i = 0; i < vAllPrimFiles.size(); ++i)
|
|
{
|
|
vAllPrimFiles[i] = strlwr(vAllPrimFiles[i]);
|
|
// Load the primfile
|
|
CPrimRegion PrimRegion;
|
|
{
|
|
CIFile fileIn;
|
|
fileIn.open (vAllPrimFiles[i]);
|
|
CIXml input;
|
|
input.init (fileIn);
|
|
PrimRegion.serial (input);
|
|
}
|
|
|
|
for (j = 0; j < PrimRegion.VZones.size(); ++j)
|
|
{
|
|
// Check all zones to know if this patat must be updated
|
|
if (isPatatNeedUpdate(_Options->CellSize, &PrimRegion.VZones[j], _OutIGDir))
|
|
{
|
|
SExportPrimitive epTmp;
|
|
epTmp.FullPrimName = vAllPrimFiles[i];
|
|
epTmp.PrimitiveName = PrimRegion.VZones[j].getName();
|
|
vExportPrimitives.push_back (epTmp);
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < PrimRegion.VPaths.size(); ++j)
|
|
{
|
|
// Check all pathes to know if some must be updated (if no zone under)
|
|
if (isPathNeedUpdate(_Options->CellSize, &PrimRegion.VPaths[j], _OutIGDir))
|
|
{
|
|
SExportPrimitive epTmp;
|
|
epTmp.FullPrimName = vAllPrimFiles[i];
|
|
epTmp.PrimitiveName = PrimRegion.VPaths[j].getName();
|
|
vExportPrimitives.push_back (epTmp);
|
|
}
|
|
}
|
|
|
|
for (j = 0; j < PrimRegion.VPoints.size(); ++j)
|
|
{
|
|
// Check all points to know if some must be updated (if no zone under)
|
|
if (isPointNeedUpdate(_Options->CellSize, &PrimRegion.VPoints[j], _OutIGDir))
|
|
{
|
|
SExportPrimitive epTmp;
|
|
epTmp.FullPrimName = vAllPrimFiles[i];
|
|
epTmp.PrimitiveName = PrimRegion.VPoints[j].getName();
|
|
vExportPrimitives.push_back (epTmp);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Export
|
|
|
|
CTools::chdir (_ExeDir);
|
|
_Options->PrimFloraDir = sContinentDir;
|
|
sTmp = "Exporting";
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
doExport (*_Options, _ExportCB, &vExportPrimitives);
|
|
|
|
// Copy new files for incremental purpose
|
|
CTools::chdir (_ExeDir);
|
|
sTmp = "Incrementing";
|
|
if (_ExportCB != NULL) _ExportCB->dispInfo (sTmp);
|
|
for (nRegion = 0; nRegion < vRegions.size(); ++nRegion)
|
|
{
|
|
CTools::chdir (sContinentDir + vRegions[nRegion]);
|
|
vector<string> vFiles;
|
|
CTools::dirSub ("*.prim", vFiles, true);
|
|
for (i = 0; i < vFiles.size(); ++i)
|
|
{
|
|
string sDst = vFiles[i].substr (sContinentDir.size());
|
|
for (j = 0; j < sDst.size(); ++j)
|
|
if (sDst[j] == '\\')
|
|
sDst[j] = '-';
|
|
sDst = _OutIGDir + sDst;
|
|
CTools::copy (sDst, vFiles[i]);
|
|
}
|
|
CTools::chdir (sContinentDir + vRegions[nRegion]);
|
|
CTools::dirSub ("*.flora", vFiles, true);
|
|
for (i = 0; i < vFiles.size(); ++i)
|
|
{
|
|
string sDst = vFiles[i].substr (sContinentDir.size());
|
|
for (j = 0; j < sDst.size(); ++j)
|
|
if (sDst[j] == '\\')
|
|
sDst[j] = '-';
|
|
sDst = _OutIGDir + sDst;
|
|
CTools::copy (sDst, vFiles[i]);
|
|
}
|
|
|
|
// -------------------------------------------------------------------
|
|
// If the new file do not exists anymore but the old file exists -> delete old file
|
|
CTools::chdir (_OutIGDir);
|
|
CTools::dir (vRegions[nRegion] + "-*.prim", vFiles, false);
|
|
for (i = 0; i < vFiles.size(); ++i)
|
|
{
|
|
// Get the name of the recent file
|
|
string sNewName = vFiles[i];
|
|
for (j = 0; j < sNewName.size(); ++j)
|
|
if (sNewName[j] == '-')
|
|
sNewName[j] = '\\';
|
|
|
|
sNewName = sContinentDir + sNewName;
|
|
if (!CTools::fileExist(sNewName))
|
|
{
|
|
// Delete the oldest file
|
|
CFile::deleteFile(vFiles[i]);
|
|
}
|
|
}
|
|
|
|
// If the new file do not exists anymore but the old file exists -> delete old file
|
|
CTools::dir (vRegions[nRegion] + "-*.flora", vFiles, false);
|
|
for (i = 0; i < vFiles.size(); ++i)
|
|
{
|
|
// Get the name of the recent file
|
|
string sNewName = vFiles[i];
|
|
for (j = 0; j < sNewName.size(); ++j)
|
|
if (sNewName[j] == '-')
|
|
sNewName[j] = '\\';
|
|
|
|
sNewName = sContinentDir + sNewName;
|
|
if (!CTools::fileExist(sNewName))
|
|
{
|
|
// Delete the oldest file
|
|
CFile::deleteFile(vFiles[i]);
|
|
}
|
|
}
|
|
}
|
|
|
|
CTools::chdir (_ExeDir);
|
|
return true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
bool CExport::doExport (SExportOptions &opt, IExportCB *expCB, vector<SExportPrimitive> *selection)
|
|
{
|
|
char sTmp[MAX_PATH];
|
|
GetCurrentDirectory (MAX_PATH, sTmp);
|
|
|
|
_Options = &opt;
|
|
_ExportCB = expCB;
|
|
|
|
// Does we have something to export
|
|
if ((selection != NULL) && (selection->size() == 0))
|
|
{
|
|
if (_ExportCB)
|
|
_ExportCB->dispInfo ("Nothing to export");
|
|
return true;
|
|
}
|
|
|
|
// If we want to generate flora then we have to load the landscape
|
|
uint32 i;
|
|
|
|
if (_ExportCB)
|
|
_ExportCB->dispPass ("Load Landscape");
|
|
if (_Landscape == NULL)
|
|
{
|
|
_Landscape = new CLandscape;
|
|
_Landscape->init ();
|
|
_VCM = new CVisualCollisionManager;
|
|
_VCE = _VCM->createEntity ();
|
|
_VCM->setLandscape (_Landscape);
|
|
_VCE->setSnapToRenderedTesselation (false);
|
|
try
|
|
{
|
|
CIFile bankFile (_LandBankFile);
|
|
_Landscape->TileBank.serial (bankFile);
|
|
CIFile farbankFile (_LandFarBankFile);
|
|
_Landscape->TileFarBank.serial (farbankFile);
|
|
_Landscape->TileBank.makeAllPathRelative ();
|
|
_Landscape->TileBank.setAbsPath ("");
|
|
_Landscape->TileBank.makeAllExtensionDDS ();
|
|
_Landscape->initTileBanks ();
|
|
|
|
loadLandscape (_LandFile);
|
|
}
|
|
catch (const Exception &/*e*/)
|
|
{
|
|
if (_ExportCB)
|
|
_ExportCB->dispError ("Cannot load banks files");
|
|
}
|
|
}
|
|
|
|
_FloraInsts.clear ();
|
|
if (_ExportCB)
|
|
_ExportCB->dispPass ("Generate Flora");
|
|
vector<string> allFloraFiles;
|
|
SetCurrentDirectory (_Options->PrimFloraDir.c_str());
|
|
getAllFiles (".Flora", allFloraFiles);
|
|
SetCurrentDirectory (sTmp);
|
|
for (i = 0; i < allFloraFiles.size(); ++i)
|
|
{
|
|
generateIGFromFlora (allFloraFiles[i], selection);
|
|
}
|
|
|
|
writeFloraIG (_LandFile, (selection != NULL)); // If selection != NULL then test for writing
|
|
|
|
SetCurrentDirectory (sTmp);
|
|
if (_ExportCB)
|
|
_ExportCB->dispPass ("Finished");
|
|
|
|
return true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
void CExport::getAllFiles (const string &ext, vector<string> &files)
|
|
{
|
|
char sCurDir[MAX_PATH];
|
|
GetCurrentDirectory (MAX_PATH, sCurDir);
|
|
|
|
WIN32_FIND_DATA findData;
|
|
HANDLE hFind = FindFirstFile ("*.*", &findData);
|
|
while (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
if (!((strcmp (findData.cFileName, ".") == 0) || (strcmp (findData.cFileName, "..") == 0)))
|
|
{
|
|
if (findData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
string sNewDir = sCurDir;
|
|
sNewDir += string("\\") + findData.cFileName;
|
|
SetCurrentDirectory (sNewDir.c_str());
|
|
getAllFiles (ext, files);
|
|
SetCurrentDirectory (sCurDir);
|
|
}
|
|
else
|
|
{
|
|
if (strlen(findData.cFileName) > strlen(ext.c_str()))
|
|
if (stricmp(&findData.cFileName[strlen(findData.cFileName)-strlen(ext.c_str())], ext.c_str()) == 0)
|
|
{
|
|
string fullName = sCurDir;
|
|
fullName += string("\\") + findData.cFileName;
|
|
fullName = strlwr (fullName);
|
|
files.push_back (fullName);
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FindNextFile (hFind, &findData) == 0)
|
|
break;
|
|
}
|
|
FindClose (hFind);
|
|
|
|
SetCurrentDirectory (sCurDir);
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
bool CExport::searchFile (const std::string &plantName, std::string &dir)
|
|
{
|
|
char sCurDir[MAX_PATH];
|
|
bool bFound = false;
|
|
GetCurrentDirectory (MAX_PATH, sCurDir);
|
|
|
|
WIN32_FIND_DATA findData;
|
|
HANDLE hFind = FindFirstFile ("*.*", &findData);
|
|
while (hFind != INVALID_HANDLE_VALUE)
|
|
{
|
|
string filename = findData.cFileName;
|
|
filename = strlwr(filename);
|
|
if (!((filename == ".") || (filename == "..")))
|
|
{
|
|
if (findData.dwFileAttributes&FILE_ATTRIBUTE_DIRECTORY)
|
|
{
|
|
string sNewDir = sCurDir;
|
|
sNewDir += string("\\") + filename;
|
|
SetCurrentDirectory (sNewDir.c_str());
|
|
if (searchFile (plantName, dir))
|
|
{
|
|
bFound = true;
|
|
break;
|
|
}
|
|
SetCurrentDirectory (sCurDir);
|
|
}
|
|
else
|
|
{
|
|
if (strlwr(plantName) == filename)
|
|
{
|
|
dir = sCurDir;
|
|
bFound = true;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (FindNextFile (hFind, &findData) == 0)
|
|
break;
|
|
}
|
|
FindClose (hFind);
|
|
SetCurrentDirectory (sCurDir);
|
|
return bFound;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
bool CExport::generateIGFromFlora (const std::string &SrcFile, std::vector<SExportPrimitive> *selection)
|
|
{
|
|
uint32 i, j, k, l, m;
|
|
|
|
if (_ExportCB)
|
|
_ExportCB->dispPass ("Generating From " + SrcFile);
|
|
|
|
// Load all .prim
|
|
vector<CPrimRegion> allPrimRegion;
|
|
vector<string> allPrimFiles;
|
|
{
|
|
char sCurDir[MAX_PATH];
|
|
GetCurrentDirectory (MAX_PATH, sCurDir);
|
|
SetCurrentDirectory (_Options->PrimFloraDir.c_str());
|
|
getAllFiles (".prim", allPrimFiles);
|
|
SetCurrentDirectory (sCurDir);
|
|
for (i = 0; i < allPrimFiles.size(); ++i)
|
|
{
|
|
try
|
|
{
|
|
CPrimRegion tmpPrimRegion;
|
|
CIFile fileIn;
|
|
fileIn.open (allPrimFiles[i]);
|
|
CIXml input;
|
|
input.init (fileIn);
|
|
tmpPrimRegion.serial (input);
|
|
allPrimRegion.push_back (tmpPrimRegion);
|
|
}
|
|
catch (const Exception &/*e*/)
|
|
{
|
|
if (_ExportCB != NULL)
|
|
_ExportCB->dispWarning (string("Cant load ") + allPrimFiles[i]);
|
|
CPrimRegion tmpPrimRegion;
|
|
allPrimRegion.push_back (tmpPrimRegion);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Load the .Flora file (georges file) and load all associated .plant
|
|
SFormFlora formFlora;
|
|
map<string, SFormPlant> Plants;
|
|
{
|
|
// Create a loader
|
|
UFormLoader *loader = UFormLoader::createLoader ();
|
|
// CPath::addSearchPath (_Options->DfnDir, true, true);
|
|
// CPath::addSearchPath (_Options->GameElemDir, true, true);
|
|
// CPath::addSearchPath (_Options->LandTileNoiseDir, true, true);
|
|
|
|
// Load the form
|
|
CSmartPtr<UForm> form = loader->loadForm (SrcFile.c_str ());
|
|
if (form == NULL)
|
|
{
|
|
if (_ExportCB != NULL)
|
|
_ExportCB->dispError (string("Cant load ") + SrcFile );
|
|
}
|
|
else
|
|
{
|
|
// Read .Flora
|
|
formFlora.build (form->getRootNode ());
|
|
|
|
// Load the .plant associated
|
|
for (i = 0; i < formFlora.PlantInstances.size(); ++i)
|
|
{
|
|
const string &plantName = formFlora.PlantInstances[i].Name;
|
|
map<string, SFormPlant>::iterator it = Plants.find (plantName);
|
|
if (it != Plants.end()) // Already here ?!
|
|
continue; // Zap it
|
|
|
|
char sCurDir[MAX_PATH];
|
|
GetCurrentDirectory (MAX_PATH, sCurDir);
|
|
|
|
try
|
|
{
|
|
SetCurrentDirectory (_GameElemDir.c_str());
|
|
string dir;
|
|
|
|
if (searchFile (plantName, dir))
|
|
{
|
|
string tmpName = dir + string("\\") + plantName;
|
|
|
|
CSmartPtr<UForm> form2 = loader->loadForm (tmpName.c_str());
|
|
if (form2)
|
|
{
|
|
SFormPlant plantTmp;
|
|
plantTmp.build (form2->getRootNode ());
|
|
Plants.insert (map<string, SFormPlant>::value_type(plantName, plantTmp));
|
|
}
|
|
else
|
|
{
|
|
if (_ExportCB != NULL)
|
|
_ExportCB->dispWarning (string("Cant load ") + plantName);
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if (_ExportCB != NULL)
|
|
_ExportCB->dispWarning (string("Cant load ") + plantName);
|
|
}
|
|
SetCurrentDirectory (sCurDir);
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
SetCurrentDirectory (sCurDir);
|
|
if (_ExportCB != NULL)
|
|
_ExportCB->dispWarning (string("Cant load ") + plantName + "(" + e.what() + ")" );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Sort PlantInstances by biggest radius first
|
|
if (formFlora.PlantInstances.size() > 1)
|
|
for (i = 0; i < (formFlora.PlantInstances.size()-1); ++i)
|
|
for (j = i+1; j < formFlora.PlantInstances.size(); ++j)
|
|
{
|
|
SPlantInstance &rPlantI = formFlora.PlantInstances[i];
|
|
SPlantInstance &rPlantJ = formFlora.PlantInstances[j];
|
|
map<string, SFormPlant>::iterator it = Plants.find (rPlantI.Name);
|
|
if (it == Plants.end())
|
|
continue;
|
|
SFormPlant &rFormPlantI = it->second;
|
|
|
|
it = Plants.find (rPlantJ.Name);
|
|
if (it == Plants.end())
|
|
continue;
|
|
SFormPlant &rFormPlantJ = it->second;
|
|
if (rFormPlantI.BoundingRadius < rFormPlantJ.BoundingRadius)
|
|
{
|
|
SPlantInstance pi = formFlora.PlantInstances[i];
|
|
formFlora.PlantInstances[i] = formFlora.PlantInstances[j];
|
|
formFlora.PlantInstances[j] = pi;
|
|
}
|
|
}
|
|
|
|
// Generating
|
|
float jitter = formFlora.JitterPos;
|
|
clamp (jitter, 0.0f, 1.0f);
|
|
srand (formFlora.RandomSeed);
|
|
for (i = 0; i < formFlora.IncludePatats.size(); ++i)
|
|
{
|
|
uint32 nCurPlant = 0;
|
|
CVector vMin, vMax;
|
|
|
|
if (_ExportCB)
|
|
_ExportCB->dispPass ("IncludePatats("+toString(i+1)+"/"+toString(formFlora.IncludePatats.size())+")");
|
|
|
|
// Get the patat
|
|
CPrimZone *pPatat = NULL;
|
|
CPrimPoint *pPoint = NULL;
|
|
CPrimPath *pPath = NULL;
|
|
|
|
// Look if this is a patat
|
|
for (j = 0; j < allPrimRegion.size(); ++j)
|
|
{
|
|
for (k = 0; k < allPrimRegion[j].VZones.size(); ++k)
|
|
{
|
|
if (allPrimRegion[j].VZones[k].getName() == formFlora.IncludePatats[i])
|
|
{
|
|
if (selection != NULL)
|
|
{
|
|
SExportPrimitive epTmp;
|
|
epTmp.FullPrimName = allPrimFiles[j];
|
|
epTmp.PrimitiveName = allPrimRegion[j].VZones[k].getName();
|
|
for (m = 0; m < selection->size(); ++m)
|
|
if (selection->operator[](m) == epTmp)
|
|
{
|
|
pPatat = &allPrimRegion[j].VZones[k];
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pPatat = &allPrimRegion[j].VZones[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Look if this is a point
|
|
for (j = 0; j < allPrimRegion.size(); ++j)
|
|
{
|
|
for (k = 0; k < allPrimRegion[j].VPoints.size(); ++k)
|
|
{
|
|
if (allPrimRegion[j].VPoints[k].getName() == formFlora.IncludePatats[i])
|
|
{
|
|
if (selection != NULL)
|
|
{
|
|
SExportPrimitive epTmp;
|
|
epTmp.FullPrimName = allPrimFiles[j];
|
|
epTmp.PrimitiveName = allPrimRegion[j].VPoints[k].getName();
|
|
for (m = 0; m < selection->size(); ++m)
|
|
if (selection->operator[](m) == epTmp)
|
|
{
|
|
pPoint = &allPrimRegion[j].VPoints[k];
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pPoint = &allPrimRegion[j].VPoints[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
//Look if this is a path
|
|
for (j = 0; j < allPrimRegion.size(); ++j)
|
|
{
|
|
for (k = 0; k < allPrimRegion[j].VPaths.size(); ++k)
|
|
{
|
|
if (allPrimRegion[j].VPaths[k].getName() == formFlora.IncludePatats[i])
|
|
{
|
|
if (selection != NULL)
|
|
{
|
|
SExportPrimitive epTmp;
|
|
epTmp.FullPrimName = allPrimFiles[j];
|
|
epTmp.PrimitiveName = allPrimRegion[j].VPaths[k].getName();
|
|
for (m = 0; m < selection->size(); ++m)
|
|
if (selection->operator[](m) == epTmp)
|
|
{
|
|
pPath = &allPrimRegion[j].VPaths[k];
|
|
break;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
pPath = &allPrimRegion[j].VPaths[k];
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
if ((pPatat == NULL) && (pPoint == NULL) && (pPath == NULL))
|
|
{
|
|
if (selection == NULL)
|
|
if (_ExportCB)
|
|
_ExportCB->dispWarning ("Cannot find " + formFlora.IncludePatats[i]);
|
|
continue;
|
|
}
|
|
|
|
if ((pPatat != NULL) && (pPatat->VPoints.size() <= 2))
|
|
{
|
|
if (_ExportCB)
|
|
_ExportCB->dispWarning ("Patat " + pPatat->getName() + " has less than 3 points");
|
|
continue;
|
|
}
|
|
|
|
if ((pPath != NULL) && (pPath->VPoints.size() <= 1))
|
|
{
|
|
if (_ExportCB)
|
|
_ExportCB->dispWarning ("Path " + pPath->getName() + " has less than 2 points");
|
|
continue;
|
|
}
|
|
|
|
// Generate for a patat
|
|
if (pPatat != NULL)
|
|
{
|
|
vMin = vMax = pPatat->VPoints[0];
|
|
for (j = 0; j < pPatat->VPoints.size(); ++j)
|
|
{
|
|
if (vMin.x > pPatat->VPoints[j].x) vMin.x = pPatat->VPoints[j].x;
|
|
if (vMin.y > pPatat->VPoints[j].y) vMin.y = pPatat->VPoints[j].y;
|
|
if (vMin.z > pPatat->VPoints[j].z) vMin.z = pPatat->VPoints[j].z;
|
|
if (vMax.x < pPatat->VPoints[j].x) vMax.x = pPatat->VPoints[j].x;
|
|
if (vMax.y < pPatat->VPoints[j].y) vMax.y = pPatat->VPoints[j].y;
|
|
if (vMax.z < pPatat->VPoints[j].z) vMax.z = pPatat->VPoints[j].z;
|
|
}
|
|
|
|
for (j = 0; j < formFlora.PlantInstances.size(); ++j)
|
|
{
|
|
SPlantInstance &rPlant = formFlora.PlantInstances[j];
|
|
map<string, SFormPlant>::iterator it = Plants.find (rPlant.Name);
|
|
if (it == Plants.end())
|
|
{
|
|
if (_ExportCB)
|
|
_ExportCB->dispWarning ("Cannot find " + rPlant.Name);
|
|
continue;
|
|
}
|
|
SFormPlant &rFormPlant = it->second;
|
|
|
|
float squareLength = (float)sqrt (Pi*rFormPlant.BoundingRadius*rFormPlant.BoundingRadius / rPlant.Density);
|
|
uint32 nNbPlantX = 1+(int)floor ((vMax.x-vMin.x) / squareLength);
|
|
uint32 nNbPlantY = 1+(int)floor ((vMax.y-vMin.y) / squareLength);
|
|
for (l = 0; l < nNbPlantY; ++l)
|
|
for (k = 0; k < nNbPlantX; ++k)
|
|
{
|
|
if (_ExportCB)
|
|
_ExportCB->dispPassProgress (((float)(k+l*nNbPlantX))/((float)(nNbPlantX*nNbPlantY)));
|
|
|
|
bool bExists = false;
|
|
CVector pos;
|
|
float scaleTmp;
|
|
for (m = 0; m < 32; ++m)
|
|
{
|
|
pos.x = vMin.x + squareLength * k + (frand(2.0f)-1.0f) * jitter * 0.5f * squareLength;
|
|
pos.y = vMin.y + squareLength * l + (frand(2.0f)-1.0f) * jitter * 0.5f * squareLength;
|
|
pos.z = 0.0f;
|
|
scaleTmp = (formFlora.ScaleMax-formFlora.ScaleMin)*frand(1.0)+formFlora.ScaleMin;
|
|
if (pPatat->contains(pos))
|
|
{
|
|
if (isWellPlaced(pos, rPlant, rFormPlant, scaleTmp))
|
|
{
|
|
// Testt finally with the exclude patats ...
|
|
bExists = true;
|
|
for (uint32 expat = 0; expat < formFlora.ExcludePatats.size(); ++expat)
|
|
{
|
|
CPrimZone *pExPatat = NULL;
|
|
for (uint32 epj = 0; epj < allPrimRegion.size(); ++epj)
|
|
for (uint32 epk = 0; epk < allPrimRegion[epj].VZones.size(); ++epk)
|
|
if (allPrimRegion[epj].VZones[epk].getName() == formFlora.ExcludePatats[expat])
|
|
{
|
|
pExPatat = &allPrimRegion[epj].VZones[epk];
|
|
break;
|
|
}
|
|
if (pExPatat != NULL)
|
|
{
|
|
if (pExPatat->contains(pos))
|
|
{
|
|
bExists = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (bExists)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!bExists)
|
|
continue;
|
|
|
|
SFloraInst vi;
|
|
vi.ShapeName = rFormPlant.Shape;
|
|
vi.PlantName = rPlant.Name;
|
|
vi.Scale = scaleTmp;
|
|
vi.Radius = rFormPlant.BoundingRadius * vi.Scale;
|
|
vi.Rot = (float)Pi * frand (1.0);
|
|
|
|
if (formFlora.PutOnWater)
|
|
{
|
|
if (pos.z < formFlora.WaterHeight)
|
|
pos.z = formFlora.WaterHeight;
|
|
}
|
|
vi.Pos = pos;
|
|
_FloraInsts.push_back (vi);
|
|
} // End of for all position of a plant x,y check if we cant put it
|
|
} // End of for all plant instances
|
|
} // End of Generate for a patat
|
|
|
|
// Generate for a point
|
|
if (pPoint != NULL)
|
|
{
|
|
// Choose a plant
|
|
float total = 0.0f;
|
|
for (j = 0; j < formFlora.PlantInstances.size(); ++j)
|
|
{
|
|
total += formFlora.PlantInstances[j].Density;
|
|
}
|
|
float posf = total * frand(1.0);
|
|
total = 0.0f;
|
|
for (j = 0; j < formFlora.PlantInstances.size(); ++j)
|
|
{
|
|
total += formFlora.PlantInstances[j].Density;
|
|
if (posf < total) break;
|
|
}
|
|
if (j == formFlora.PlantInstances.size())
|
|
j = (uint32)formFlora.PlantInstances.size()-1;
|
|
|
|
SPlantInstance &rPlant = formFlora.PlantInstances[j];
|
|
map<string, SFormPlant>::iterator it = Plants.find (rPlant.Name);
|
|
if (it == Plants.end())
|
|
{
|
|
if (_ExportCB)
|
|
_ExportCB->dispWarning ("Cannot find " + rPlant.Name);
|
|
continue;
|
|
}
|
|
SFormPlant &rFormPlant = it->second;
|
|
|
|
SFloraInst vi;
|
|
vi.ShapeName = rFormPlant.Shape;
|
|
vi.PlantName = rPlant.Name;
|
|
vi.Scale = (formFlora.ScaleMax-formFlora.ScaleMin)*frand(1.0)+formFlora.ScaleMin;
|
|
vi.Radius = rFormPlant.BoundingRadius * vi.Scale;
|
|
vi.Rot = (float)Pi * frand (1.0);
|
|
|
|
CVector pos;
|
|
pos.x = pPoint->Point.x;
|
|
pos.y = pPoint->Point.y;
|
|
pos.z = getZFromXY (pos.x, pos.y);
|
|
if (formFlora.PutOnWater)
|
|
{
|
|
if (pos.z < formFlora.WaterHeight)
|
|
pos.z = formFlora.WaterHeight;
|
|
}
|
|
vi.Pos = pos;
|
|
if (pos.z > -90000.0f)
|
|
_FloraInsts.push_back (vi);
|
|
} // End of Generate for a point
|
|
|
|
// Generate for a path
|
|
if (pPath != NULL)
|
|
{
|
|
float rLength = 0.0f; // Total length of the broken line
|
|
for (j = 0; j < pPath->VPoints.size()-1; ++j)
|
|
{
|
|
rLength += (pPath->VPoints[j]-pPath->VPoints[j+1]).norm();
|
|
}
|
|
|
|
for (j = 0; j < formFlora.PlantInstances.size(); ++j)
|
|
{
|
|
SPlantInstance &rPlant = formFlora.PlantInstances[j];
|
|
map<string, SFormPlant>::iterator it = Plants.find (rPlant.Name);
|
|
if (it == Plants.end())
|
|
{
|
|
if (_ExportCB)
|
|
_ExportCB->dispWarning ("Cannot find " + rPlant.Name);
|
|
continue;
|
|
}
|
|
SFormPlant &rFormPlant = it->second;
|
|
|
|
float squareLength = (float)(2*rFormPlant.BoundingRadius / rPlant.Density);
|
|
uint32 nNbPlant = 1+(int)floor (rLength / squareLength);
|
|
|
|
for (k = 0; k < nNbPlant; ++k)
|
|
{
|
|
if (_ExportCB)
|
|
_ExportCB->dispPassProgress (((float)(k))/((float)(nNbPlant)));
|
|
|
|
bool bExists = false;
|
|
CVector pos;
|
|
float scaleTmp;
|
|
for (m = 0; m < 32; ++m)
|
|
{
|
|
// Calculate the curviline abscisse
|
|
float curvAbs = squareLength * k + (frand(2.0f)-1.0f) * jitter * 0.5f * squareLength;
|
|
float TempLength = 0.0f;
|
|
// Convert to a real point along the curve (broken line)
|
|
for (l = 0; l < pPath->VPoints.size()-1; ++l)
|
|
{
|
|
float newSize = (pPath->VPoints[l]-pPath->VPoints[l+1]).norm();
|
|
if (curvAbs < (TempLength+newSize))
|
|
{
|
|
curvAbs -= TempLength;
|
|
break;
|
|
}
|
|
TempLength += newSize;
|
|
}
|
|
if (l == (pPath->VPoints.size()-1))
|
|
{
|
|
l = (uint32)pPath->VPoints.size()-2;
|
|
curvAbs = (pPath->VPoints[l]-pPath->VPoints[l+1]).norm();
|
|
}
|
|
// Calculate the coord
|
|
curvAbs = curvAbs / (pPath->VPoints[l]-pPath->VPoints[l+1]).norm();
|
|
pos = pPath->VPoints[l] + (pPath->VPoints[l+1]-pPath->VPoints[l])*curvAbs;
|
|
pos.z = 0.0f;
|
|
scaleTmp = (formFlora.ScaleMax-formFlora.ScaleMin)*frand(1.0)+formFlora.ScaleMin;
|
|
if (isWellPlaced(pos, rPlant, rFormPlant, scaleTmp))
|
|
{
|
|
// Test finally with the exclude patats ...
|
|
bExists = true;
|
|
for (uint32 expat = 0; expat < formFlora.ExcludePatats.size(); ++expat)
|
|
{
|
|
CPrimZone *pExPatat = NULL;
|
|
for (uint32 epj = 0; epj < allPrimRegion.size(); ++epj)
|
|
for (uint32 epk = 0; epk < allPrimRegion[epj].VZones.size(); ++epk)
|
|
if (allPrimRegion[epj].VZones[epk].getName() == formFlora.ExcludePatats[expat])
|
|
{
|
|
pExPatat = &allPrimRegion[epj].VZones[epk];
|
|
break;
|
|
}
|
|
if (pExPatat != NULL)
|
|
{
|
|
if (pExPatat->contains(pos))
|
|
{
|
|
bExists = false;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if (bExists)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (!bExists)
|
|
continue;
|
|
|
|
SFloraInst vi;
|
|
vi.ShapeName = rFormPlant.Shape;
|
|
vi.PlantName = rPlant.Name;
|
|
vi.Scale = scaleTmp;
|
|
vi.Radius = rFormPlant.BoundingRadius * vi.Scale;
|
|
vi.Rot = (float)Pi * frand (1.0);
|
|
|
|
if (formFlora.PutOnWater)
|
|
{
|
|
if (pos.z < formFlora.WaterHeight)
|
|
pos.z = formFlora.WaterHeight;
|
|
}
|
|
vi.Pos = pos;
|
|
_FloraInsts.push_back (vi);
|
|
} // End of for all position of a plant x,y check if we cant put it
|
|
} // End of for all plant instances
|
|
|
|
} // End of Generate for a path
|
|
|
|
} // End of for all IncludePatats
|
|
return true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
float CExport::getZFromXY (float x, float y)
|
|
{
|
|
CVector pos = CVector(x, y, 0);
|
|
CVector normal;
|
|
float z, zmin, zmax;
|
|
|
|
// Approximate the z with patch bounding boxes
|
|
sint32 zoneX = (sint32)floor (x/_Options->CellSize);
|
|
sint32 zoneY = (sint32)floor (-y/_Options->CellSize);
|
|
sint32 zoneId = zoneY * 256 + zoneX;
|
|
CZone *pZone = _Landscape->getZone (zoneId);
|
|
if (pZone == NULL)
|
|
return -100000.0f;
|
|
|
|
CAABBoxExt bb = pZone->getZoneBB();
|
|
zmin = bb.getMin().z;
|
|
zmax = bb.getMax().z;
|
|
pos.z = zmin;
|
|
z = zmin;
|
|
while (z < zmax)
|
|
{
|
|
if (_VCE->snapToGround(pos, normal))
|
|
break;
|
|
z += CVisualCollisionEntity::BBoxRadiusZ / 2.0f; // Super sampling due to max frequency on radiosity
|
|
pos.z = z;
|
|
}
|
|
|
|
if (z >= zmax)
|
|
return -100000.0f;
|
|
|
|
return pos.z;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
bool CExport::isWellPlaced (CVector &pos, SPlantInstance &rPI, SFormPlant &rFP, float scale)
|
|
{
|
|
uint32 i;
|
|
|
|
// Look if this Flora intersect with one of the current ones
|
|
for (i = 0; i < _FloraInsts.size(); ++i)
|
|
{
|
|
CVector temp = _FloraInsts[i].Pos - pos;
|
|
temp.z = 0.0f;
|
|
if (temp.norm() < (_FloraInsts[i].Radius + scale*rFP.BoundingRadius))
|
|
return false;
|
|
}
|
|
|
|
// Get the real Z
|
|
pos.z = getZFromXY (pos.x, pos.y);
|
|
if (pos.z < -90000.0f)
|
|
return false;
|
|
|
|
// Get some Z around to see if we can put the Flora on the ground
|
|
uint32 nNbSamples = 8; // Const to be put somewhere
|
|
vector<CVector> base;
|
|
base.resize (nNbSamples);
|
|
for (i = 0; i < nNbSamples; ++i)
|
|
{
|
|
base[i] = pos;
|
|
base[i].x += scale * rFP.CollisionRadius * cosf((2.0f*(float)Pi*i)/(float)nNbSamples);
|
|
base[i].y += scale * rFP.CollisionRadius * sinf((2.0f*(float)Pi*i)/(float)nNbSamples);
|
|
base[i].z = getZFromXY (base[i].x, base[i].y);
|
|
|
|
if (fabs(base[i].z-pos.z) > 0.8f)
|
|
return false;
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
void CExport::writeFloraIG (const string &LandFile, bool bTestForWriting)
|
|
{
|
|
sint32 i, j, k;
|
|
|
|
if (_FloraInsts.size() == 0)
|
|
return;
|
|
|
|
CZoneRegion zoneRegion;
|
|
CIFile inFile;
|
|
if (inFile.open (LandFile))
|
|
{
|
|
CIXml xml(true);
|
|
xml.init (inFile);
|
|
zoneRegion.serial (xml);
|
|
|
|
inFile.close();
|
|
}
|
|
else
|
|
{
|
|
nlwarning ("Can't open the file %s", LandFile.c_str());
|
|
}
|
|
|
|
// Load all zone
|
|
|
|
for (j = zoneRegion.getMinY(); j <= zoneRegion.getMaxY(); ++j)
|
|
for (i = zoneRegion.getMinX(); i <= zoneRegion.getMaxX(); ++i)
|
|
{
|
|
if ((zoneRegion.getName(i,j) == STRING_OUT_OF_BOUND) ||
|
|
(zoneRegion.getName(i,j) == STRING_UNUSED))
|
|
continue;
|
|
|
|
vector<int> vegZone;
|
|
// Take all Flora instances in the zone (i,j)
|
|
for (k = 0; k < (sint32)_FloraInsts.size(); ++k)
|
|
{
|
|
if (((i*_Options->CellSize) < _FloraInsts[k].Pos.x) && (_FloraInsts[k].Pos.x < ((i+1)*_Options->CellSize)) &&
|
|
((j*_Options->CellSize) < _FloraInsts[k].Pos.y) && (_FloraInsts[k].Pos.y < ((j+1)*_Options->CellSize)))
|
|
{
|
|
vegZone.push_back (k);
|
|
}
|
|
}
|
|
|
|
|
|
// Make the .IG
|
|
string ZoneName;
|
|
ZoneName += NLMISC::toString(-j) + "_";
|
|
ZoneName += 'a' + (i/26);
|
|
ZoneName += 'a' + (i%26);
|
|
|
|
CVector vGlobalPos = CVector (0.0f, 0.0f, 0.0f);
|
|
CInstanceGroup::TInstanceArray Instances;
|
|
vector<CCluster> Portals;
|
|
vector<CPortal> Clusters;
|
|
Instances.resize (vegZone.size());
|
|
|
|
for (k = 0; k < (sint32)vegZone.size(); ++k)
|
|
{
|
|
//vGlobalPos += _FloraInsts[vegZone[k]].Pos;
|
|
Instances[k].Pos = _FloraInsts[vegZone[k]].Pos;
|
|
Instances[k].Rot = CQuat(CVector::K, _FloraInsts[vegZone[k]].Rot);
|
|
Instances[k].Scale = CVector(_FloraInsts[vegZone[k]].Scale, _FloraInsts[vegZone[k]].Scale, _FloraInsts[vegZone[k]].Scale);
|
|
Instances[k].nParent = -1;
|
|
Instances[k].Name = _FloraInsts[vegZone[k]].ShapeName;
|
|
Instances[k].InstanceName = _FloraInsts[vegZone[k]].PlantName;
|
|
/*Instances[k].InstanceName = "Flora_"; // see if it works
|
|
Instances[k].InstanceName += ZoneName + "_";
|
|
Instances[k].InstanceName += '0' + ((k/1000)%10);
|
|
Instances[k].InstanceName += '0' + ((k/100) %10);
|
|
Instances[k].InstanceName += '0' + ((k/10) %10);
|
|
Instances[k].InstanceName += '0' + ( k %10);*/
|
|
}
|
|
|
|
// \todo trap -> look why it dont seems to work with a global positionning
|
|
//vGlobalPos /= (float)vegZone.size();
|
|
//for (k = 0; k < (sint32)vegZone.size(); ++k)
|
|
// Instances[k].Pos -= vGlobalPos;
|
|
|
|
CInstanceGroup IG;
|
|
IG.build (vGlobalPos, Instances, Portals, Clusters);
|
|
|
|
ZoneName = _OutIGDir + "\\" + ZoneName;
|
|
ZoneName += ".ig";
|
|
|
|
CIFile inFile; // If file already exists and we have selection...
|
|
if (bTestForWriting)
|
|
if (inFile.open(ZoneName))
|
|
{
|
|
inFile.close();
|
|
continue;
|
|
}
|
|
|
|
try
|
|
{
|
|
COFile outFile (ZoneName);
|
|
IG.serial (outFile);
|
|
if (_ExportCB != NULL)
|
|
_ExportCB->dispInfo (ZoneName + " generated");
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
if (_ExportCB != NULL)
|
|
_ExportCB->dispWarning ("Cant write " + ZoneName + " (" + e.what() + ")");
|
|
}
|
|
}
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
void CExport::loadLandscape (const string &LandFile)
|
|
{
|
|
CZoneRegion zoneRegion;
|
|
|
|
CIFile inFile;
|
|
try
|
|
{
|
|
if (inFile.open (LandFile))
|
|
{
|
|
CIXml xml(true);
|
|
xml.init (inFile);
|
|
zoneRegion.serial (xml);
|
|
|
|
inFile.close();
|
|
}
|
|
else
|
|
{
|
|
if (_ExportCB != NULL)
|
|
_ExportCB->dispWarning (string("Can't open file ") + LandFile);
|
|
}
|
|
}
|
|
catch (const Exception &e)
|
|
{
|
|
if (_ExportCB != NULL)
|
|
_ExportCB->dispWarning (string("Cant load ") + LandFile + " : " + e.what());
|
|
}
|
|
// Load all zone
|
|
|
|
sint32 nTotalFile = (1 + zoneRegion.getMaxY() - zoneRegion.getMinY()) * (1 + zoneRegion.getMaxX() - zoneRegion.getMinX());
|
|
sint32 nCurrentFile = 0;
|
|
for (sint32 j = zoneRegion.getMinY(); j <= zoneRegion.getMaxY(); ++j)
|
|
for (sint32 i = zoneRegion.getMinX(); i <= zoneRegion.getMaxX(); ++i)
|
|
{
|
|
++nCurrentFile;
|
|
if (_ExportCB != NULL)
|
|
_ExportCB->dispPassProgress(((float)nCurrentFile)/((float)nTotalFile));
|
|
|
|
if ((zoneRegion.getName(i,j) == STRING_OUT_OF_BOUND) ||
|
|
(zoneRegion.getName(i,j) == STRING_UNUSED))
|
|
continue;
|
|
|
|
// Generate zone name
|
|
|
|
string ZoneName = getZoneNameFromXY (i, j);
|
|
|
|
ZoneName = _InLandscapeDir + string("\\") + ZoneName;
|
|
|
|
//if (_ExportCB != NULL)
|
|
// _ExportCB->dispInfo (string("Loading ") + ZoneName);
|
|
|
|
try
|
|
{
|
|
CZone zone;
|
|
if (!inFile.open (ZoneName + string(".zonew")))
|
|
inFile.open (ZoneName + string(".zonel"));
|
|
zone.serial (inFile);
|
|
inFile.close ();
|
|
_Landscape->addZone (zone);
|
|
}
|
|
catch(const Exception &/*e*/)
|
|
{
|
|
if (_ExportCB != NULL)
|
|
_ExportCB->dispWarning (string("Cant load ") + ZoneName + string(".zone(l,w)"));
|
|
}
|
|
if ((_ExportCB != NULL) && (_ExportCB->isCanceled()))
|
|
return;
|
|
}
|
|
|
|
}
|
|
|
|
// Public Helpers
|
|
// **************
|
|
|
|
// ---------------------------------------------------------------------------
|
|
string CExport::getZoneNameFromXY (sint32 x, sint32 y)
|
|
{
|
|
string tmp;
|
|
|
|
if ((y>0) || (y<-255) || (x<0) || (x>255))
|
|
return "NOT VALID";
|
|
tmp = toString(-y) + "_";
|
|
tmp += ('A' + (x/26));
|
|
tmp += ('A' + (x%26));
|
|
return tmp;
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
sint32 CExport::getXFromZoneName (const string &ZoneName)
|
|
{
|
|
string xStr, yStr;
|
|
uint32 i = 0;
|
|
while (ZoneName[i] != '_')
|
|
{
|
|
yStr += ZoneName[i]; ++i;
|
|
if (i == ZoneName.size())
|
|
return -1;
|
|
}
|
|
++i;
|
|
while (i < ZoneName.size())
|
|
{
|
|
xStr += ZoneName[i]; ++i;
|
|
}
|
|
return ((xStr[0] - 'A')*26 + (xStr[1] - 'A'));
|
|
}
|
|
|
|
// ---------------------------------------------------------------------------
|
|
sint32 CExport::getYFromZoneName (const string &ZoneName)
|
|
{
|
|
string xStr, yStr;
|
|
uint32 i = 0;
|
|
while (ZoneName[i] != '_')
|
|
{
|
|
yStr += ZoneName[i]; ++i;
|
|
if (i == ZoneName.size())
|
|
return 1;
|
|
}
|
|
++i;
|
|
while (i < ZoneName.size())
|
|
{
|
|
xStr += ZoneName[i]; ++i;
|
|
}
|
|
return -atoi(yStr.c_str());
|
|
}
|