commit
46043f088a
@ -0,0 +1,11 @@
|
||||
FILE(GLOB SRC *.cpp *.h *.rc)
|
||||
|
||||
SOURCE_GROUP("" FILES ${SRC})
|
||||
|
||||
ADD_EXECUTABLE(zone_elevation ${SRC})
|
||||
|
||||
TARGET_LINK_LIBRARIES(zone_elevation nel3d nelmisc nelligo)
|
||||
NL_DEFAULT_PROPS(zone_elevation "NeL, Tools, 3D: Zone Elevation")
|
||||
NL_ADD_RUNTIME_FLAGS(zone_elevation)
|
||||
|
||||
INSTALL(TARGETS zone_elevation RUNTIME DESTINATION ${NL_BIN_PREFIX} COMPONENT tools3d)
|
Binary file not shown.
After Width: | Height: | Size: 3.6 KiB |
@ -0,0 +1,42 @@
|
||||
#include <windows.h>
|
||||
#include "config.h"
|
||||
|
||||
IDI_MAIN_ICON ICON DISCARDABLE "blue_pill.ico"
|
||||
|
||||
#ifdef _DEBUG
|
||||
#define NL_FILEEXT "_d"
|
||||
#else
|
||||
#define NL_FILEEXT ""
|
||||
#endif
|
||||
|
||||
VS_VERSION_INFO VERSIONINFO
|
||||
FILEVERSION NL_VERSION_RC
|
||||
PRODUCTVERSION NL_VERSION_RC
|
||||
FILEFLAGSMASK VS_FFI_FILEFLAGSMASK
|
||||
#ifdef _DEBUG
|
||||
FILEFLAGS VS_FF_DEBUG
|
||||
#else
|
||||
FILEFLAGS 0x0L
|
||||
#endif
|
||||
FILEOS VOS_NT_WINDOWS32
|
||||
FILETYPE VFT_APP
|
||||
FILESUBTYPE 0x0L
|
||||
BEGIN
|
||||
BLOCK "StringFileInfo"
|
||||
BEGIN
|
||||
BLOCK "040904b0"
|
||||
BEGIN
|
||||
VALUE "CompanyName", AUTHOR
|
||||
VALUE "FileDescription", "NeL Zone Heightmap"
|
||||
VALUE "FileVersion", NL_VERSION
|
||||
VALUE "LegalCopyright", COPYRIGHT
|
||||
VALUE "OriginalFilename", "zone_heightmap" NL_FILEEXT ".exe"
|
||||
VALUE "ProductName", "NeL Tools"
|
||||
VALUE "ProductVersion", NL_PRODUCT_VERSION
|
||||
END
|
||||
END
|
||||
BLOCK "VarFileInfo"
|
||||
BEGIN
|
||||
VALUE "Translation", 0x9, 1200
|
||||
END
|
||||
END
|
@ -0,0 +1,396 @@
|
||||
// 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 <iostream>
|
||||
#include <nel/misc/types_nl.h>
|
||||
#include <nel/misc/file.h>
|
||||
#include <nel/misc/i_xml.h>
|
||||
#include <nel/misc/common.h>
|
||||
#include <nel/misc/cmd_args.h>
|
||||
#include <nel/misc/bitmap.h>
|
||||
//#include <nel/3d/quad_tree.h>
|
||||
#include <nel/3d/zone.h>
|
||||
//#include <nel/3d/landscape.h>
|
||||
//#include <nel/3d/zone_smoother.h>
|
||||
//#include <nel/3d/zone_tgt_smoother.h>
|
||||
//#include <nel/3d/zone_corner_smoother.h>
|
||||
#include <nel/ligo/zone_region.h>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
|
||||
using namespace NL3D;
|
||||
using namespace NLMISC;
|
||||
using namespace NLLIGO;
|
||||
using namespace std;
|
||||
|
||||
namespace /* anonymous */
|
||||
{
|
||||
|
||||
sint32 s_ZoneMinX, s_ZoneMinY, s_ZoneMaxX, s_ZoneMaxY;
|
||||
float s_CellSize = 160.0f;
|
||||
|
||||
float s_ZFactor = 1.0f;
|
||||
NLMISC::CBitmap *s_HeightMap;
|
||||
|
||||
float s_ZFactor2 = 1.0f;
|
||||
NLMISC::CBitmap *s_HeightMap2;
|
||||
|
||||
std::string s_InputZone; // UTF-8
|
||||
std::string s_OutputZone; // UTF-8
|
||||
|
||||
CZoneRegion s_Land;
|
||||
|
||||
bool loadLand(const string &filename)
|
||||
{
|
||||
try
|
||||
{
|
||||
CIFile fileIn;
|
||||
if (fileIn.open (filename))
|
||||
{
|
||||
CIXml xml(true);
|
||||
nlverify(xml.init(fileIn));
|
||||
s_Land.serial(xml);
|
||||
}
|
||||
else
|
||||
{
|
||||
nlwarning("Can't open the land file: %s", filename.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (const Exception& e)
|
||||
{
|
||||
nlwarning("Error in land file: %s", e.what());
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
bool getXYFromZoneName(sint32 &x, sint32 &y, const string &zoneName)
|
||||
{
|
||||
string xStr, yStr;
|
||||
uint32 i = 0;
|
||||
while (zoneName[i] != '_')
|
||||
{
|
||||
yStr += zoneName[i];
|
||||
++i;
|
||||
if (i == zoneName.size())
|
||||
goto Fail;
|
||||
}
|
||||
if (!NLMISC::fromString(yStr, y))
|
||||
goto Fail;
|
||||
y = -y;
|
||||
++i;
|
||||
while (i < zoneName.size())
|
||||
{
|
||||
xStr += zoneName[i];
|
||||
++i;
|
||||
}
|
||||
if (xStr.size() != 2)
|
||||
goto Fail;
|
||||
xStr = NLMISC::toUpper(xStr);
|
||||
x = ((xStr[0] - 'A') * 26 + (xStr[1] - 'A'));
|
||||
return true;
|
||||
Fail:
|
||||
x = -1;
|
||||
y = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
float getHeight(float x, float y)
|
||||
{
|
||||
float deltaZ = 0.0f, deltaZ2 = 0.0f;
|
||||
CRGBAF color;
|
||||
sint32 sizeX = s_ZoneMaxX - s_ZoneMinX + 1;
|
||||
sint32 sizeY = s_ZoneMaxY - s_ZoneMinY + 1;
|
||||
|
||||
clamp(x, s_CellSize * s_ZoneMinX, s_CellSize * (s_ZoneMaxX + 1));
|
||||
clamp(y, s_CellSize * s_ZoneMinY, s_CellSize * (s_ZoneMaxY + 1));
|
||||
|
||||
if (s_HeightMap != NULL)
|
||||
{
|
||||
float xc = (x - s_CellSize * s_ZoneMinX) / (s_CellSize * sizeX);
|
||||
float yc = 1.0f - ((y - s_CellSize * s_ZoneMinY) / (s_CellSize * sizeY));
|
||||
color = s_HeightMap->getColor(xc, yc);
|
||||
color *= 255;
|
||||
deltaZ = color.A;
|
||||
deltaZ = deltaZ - 127.0f; // Median intensity is 127
|
||||
deltaZ *= s_ZFactor;
|
||||
}
|
||||
|
||||
if (s_HeightMap2 != NULL)
|
||||
{
|
||||
float xc = (x - s_CellSize * s_ZoneMinX) / (s_CellSize * sizeX);
|
||||
float yc = 1.0f - ((y - s_CellSize * s_ZoneMinY) / (s_CellSize * sizeY));
|
||||
color = s_HeightMap2->getColor(xc, yc);
|
||||
color *= 255;
|
||||
deltaZ2 = color.A;
|
||||
deltaZ2 = deltaZ2 - 127.0f; // Median intensity is 127
|
||||
deltaZ2 *= s_ZFactor2;
|
||||
}
|
||||
|
||||
return (deltaZ + deltaZ2);
|
||||
}
|
||||
|
||||
NLMISC::CVector getHeightNormal(float x, float y)
|
||||
{
|
||||
sint32 SizeX = s_ZoneMaxX - s_ZoneMinX + 1;
|
||||
sint32 SizeY = s_ZoneMaxY - s_ZoneMinY + 1;
|
||||
sint32 bmpW, bmpH;
|
||||
|
||||
// get width/height of the bitmap
|
||||
if (s_HeightMap != NULL)
|
||||
{
|
||||
bmpW = s_HeightMap->getWidth();
|
||||
bmpH = s_HeightMap->getHeight();
|
||||
}
|
||||
else if (s_HeightMap2 != NULL)
|
||||
{
|
||||
bmpW = s_HeightMap2->getWidth();
|
||||
bmpH = s_HeightMap2->getHeight();
|
||||
}
|
||||
else
|
||||
{
|
||||
// no heightmap: unmodified normal
|
||||
return CVector::K;
|
||||
}
|
||||
|
||||
// compute a good delta to compute tangents of the heightmap: 1/10 of a pixel, avoiding precision problem.
|
||||
float dx = ((s_CellSize * SizeX) / bmpW) / 10; // eg: 160m/20pixels/10= 0.8
|
||||
float dy = ((s_CellSize * SizeY) / bmpH) / 10;
|
||||
|
||||
// compute tangent around the position.
|
||||
float hc = getHeight(x, y);
|
||||
float hx = getHeight(x + dx, y);
|
||||
float hy = getHeight(x, y + dy);
|
||||
CVector ds(dx, 0, hx - hc);
|
||||
CVector dt(0, dy, hy - hc);
|
||||
|
||||
// compute the heightmap normal with the tangents
|
||||
return (ds ^ dt).normed();
|
||||
}
|
||||
|
||||
void applyZoneHeightmap()
|
||||
{
|
||||
// Load zone
|
||||
CIFile zoneFile(s_InputZone);
|
||||
CZone zone;
|
||||
zone.serial(zoneFile);
|
||||
zoneFile.close();
|
||||
|
||||
// Retrieve patches and vertices
|
||||
uint16 zoneId = zone.getZoneId();
|
||||
std::vector<CPatchInfo> zonePatches;
|
||||
std::vector<CBorderVertex> zoneBorderVertices;
|
||||
zone.retrieve(zonePatches, zoneBorderVertices);
|
||||
|
||||
// Apply the Heighmap to all vertices/tangents/interiors (see Land Export tool.)
|
||||
for (size_t i = 0; i < zonePatches.size(); ++i)
|
||||
{
|
||||
CPatchInfo &rPI = zonePatches[i];
|
||||
|
||||
// Elevate the vertices.
|
||||
CVector verticesBeforeHeightMap[4];
|
||||
for (size_t j = 0; j < 4; ++j)
|
||||
{
|
||||
verticesBeforeHeightMap[j] = rPI.Patch.Vertices[j];
|
||||
float height = getHeight(rPI.Patch.Vertices[j].x, rPI.Patch.Vertices[j].y);
|
||||
rPI.Patch.Vertices[j].z += height;
|
||||
}
|
||||
|
||||
// Interior and tangent are rotated to follow the heightmap normal, avoiding the "Stair Effect".
|
||||
// Compute the matrix to apply to interiors and tangents.
|
||||
CMatrix tgMatrix[4];
|
||||
for (size_t j = 0; j < 4; ++j)
|
||||
{
|
||||
// compute the normal of the heightmap.
|
||||
CVector hmapNormal = getHeightNormal(rPI.Patch.Vertices[j].x, rPI.Patch.Vertices[j].y);
|
||||
|
||||
// Compute the rotation which transforms the original normal: (0,0,1), to this normal.
|
||||
CAngleAxis angleAxis;
|
||||
angleAxis.Axis = CVector::K ^ hmapNormal;
|
||||
angleAxis.Angle = (float)asin(angleAxis.Axis.norm());
|
||||
angleAxis.Axis.normalize();
|
||||
|
||||
// build the matrix which transform the old tgt/interior to his newValue:
|
||||
// newVertexPos + rotate * (oldTgPos - oldVertexPos)
|
||||
tgMatrix[j].identity();
|
||||
tgMatrix[j].translate(rPI.Patch.Vertices[j]);
|
||||
tgMatrix[j].setRot(CQuat(angleAxis));
|
||||
tgMatrix[j].translate(-verticesBeforeHeightMap[j]);
|
||||
}
|
||||
|
||||
// For all interior.
|
||||
for (size_t j = 0; j < 4; ++j)
|
||||
rPI.Patch.Interiors[j] = tgMatrix[j] * rPI.Patch.Interiors[j];
|
||||
|
||||
// when j == 7 or 0 use vertex 0 for delta Z to ensure continuity of normals
|
||||
// when j == 1 or 2 use vertex 1
|
||||
// when j == 3 or 4 use vertex 2
|
||||
// when j == 5 or 6 use vertex 3
|
||||
for (size_t j = 0; j < 8; ++j)
|
||||
{
|
||||
// get the correct vertex
|
||||
uint vertexId = ((j + 1) / 2) % 4;
|
||||
// apply the tgMatrix to the tangent
|
||||
rPI.Patch.Tangents[j] = tgMatrix[vertexId] * rPI.Patch.Tangents[j];
|
||||
}
|
||||
}
|
||||
|
||||
// Save zone
|
||||
zone.build(zoneId, zonePatches, zoneBorderVertices);
|
||||
COFile centerSave(s_OutputZone);
|
||||
nldebug("Writing file %s", s_OutputZone.c_str());
|
||||
zone.serial(centerSave);
|
||||
}
|
||||
|
||||
} /* anonymous namespace */
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
NLMISC::CApplicationContext myApplicationContext;
|
||||
|
||||
NLMISC::CCmdArgs args;
|
||||
|
||||
args.addAdditionalArg("zonenhw", "Input zone"); // .zonenhw
|
||||
args.addAdditionalArg("zonew", "Output zone"); // .zonew
|
||||
args.addArg("", "land", "land", "Ligo land file (either specify this or the boundaries)");
|
||||
args.addArg("", "zonemin", "zone", "Zone boundary");
|
||||
args.addArg("", "zonemax", "zone", "Zone boundary");
|
||||
args.addArg("", "cellsize", "meters", "Zone cell size");
|
||||
args.addArg("", "zfactor", "factor", "Factor for heightmap");
|
||||
args.addArg("", "heightmap", "bitmap", "Heightmap");
|
||||
args.addArg("", "zfactor2", "factor", "Factor for second heightmap");
|
||||
args.addArg("", "heightmap2", "bitmap", "Second heightmap");
|
||||
// TODO: args.addArg("", "batch", "", "Process all zones in input (specify input as C:/folder/.zonenhw)");
|
||||
|
||||
if (!args.parse(argc, argv))
|
||||
{
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
s_InputZone = args.getAdditionalArg("zonenhw")[0];
|
||||
s_OutputZone = args.getAdditionalArg("zonew")[0];
|
||||
|
||||
if (args.haveLongArg("zonemin") && args.haveLongArg("zonemax"))
|
||||
{
|
||||
sint32 zoneMinX, zoneMinY;
|
||||
sint32 zoneMaxX, zoneMaxY;
|
||||
if (!getXYFromZoneName(zoneMinX, zoneMinY, args.getLongArg("zonemin")[0])
|
||||
|| !getXYFromZoneName(zoneMaxX, zoneMaxY, args.getLongArg("zonemax")[0]))
|
||||
{
|
||||
goto Fail;
|
||||
}
|
||||
s_ZoneMinX = min(zoneMinX, zoneMaxX);
|
||||
s_ZoneMaxX = max(zoneMinX, zoneMaxX);
|
||||
s_ZoneMinY = min(zoneMinY, zoneMaxY);
|
||||
s_ZoneMaxY = max(zoneMinY, zoneMaxY);
|
||||
}
|
||||
else if (args.haveLongArg("land"))
|
||||
{
|
||||
if (!loadLand(args.getLongArg("land")[0]))
|
||||
goto Fail;
|
||||
s_ZoneMinX = s_Land.getMinX();
|
||||
s_ZoneMaxX = s_Land.getMaxX();
|
||||
s_ZoneMinY = s_Land.getMinY();
|
||||
s_ZoneMaxY = s_Land.getMaxY();
|
||||
}
|
||||
else
|
||||
{
|
||||
nlwarning("Must have either both 'zonemin' and 'zonemax', or 'land' specified");
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
if (args.haveLongArg("heightmap"))
|
||||
{
|
||||
nldebug("Loading height map");
|
||||
s_HeightMap = new CBitmap();
|
||||
try
|
||||
{
|
||||
CIFile inFile;
|
||||
if (inFile.open(args.getLongArg("heightmap")[0]))
|
||||
{
|
||||
s_HeightMap->load(inFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
nldebug("Cant load height map: %s", args.getLongArg("heightmap")[0].c_str());
|
||||
delete s_HeightMap;
|
||||
s_HeightMap = NULL;
|
||||
}
|
||||
}
|
||||
catch (const Exception &)
|
||||
{
|
||||
nldebug("Cant load height map: %s", args.getLongArg("heightmap")[0].c_str());
|
||||
delete s_HeightMap;
|
||||
s_HeightMap = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (args.haveLongArg("heightmap2"))
|
||||
{
|
||||
nldebug("Loading height map");
|
||||
s_HeightMap2 = new CBitmap();
|
||||
try
|
||||
{
|
||||
CIFile inFile;
|
||||
if (inFile.open(args.getLongArg("heightmap2")[0]))
|
||||
{
|
||||
s_HeightMap2->load(inFile);
|
||||
}
|
||||
else
|
||||
{
|
||||
nldebug("Cant load height map: %s", args.getLongArg("heightmap2")[0].c_str());
|
||||
delete s_HeightMap2;
|
||||
s_HeightMap2 = NULL;
|
||||
}
|
||||
}
|
||||
catch (const Exception &)
|
||||
{
|
||||
nldebug("Cant load height map: %s", args.getLongArg("heightmap2")[0].c_str());
|
||||
delete s_HeightMap2;
|
||||
s_HeightMap2 = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if (args.haveLongArg("zfactor"))
|
||||
{
|
||||
if (!NLMISC::fromString(args.getLongArg("zfactor")[0], s_ZFactor))
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
if (args.haveLongArg("zfactor2"))
|
||||
{
|
||||
if (!NLMISC::fromString(args.getLongArg("zfactor2")[0], s_ZFactor2))
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
if (args.haveLongArg("cellsize"))
|
||||
{
|
||||
if (!NLMISC::fromString(args.getLongArg("cellsize")[0], s_CellSize))
|
||||
goto Fail;
|
||||
}
|
||||
|
||||
applyZoneHeightmap();
|
||||
|
||||
return EXIT_SUCCESS;
|
||||
Fail:
|
||||
args.displayHelp();
|
||||
delete s_HeightMap;
|
||||
delete s_HeightMap2;
|
||||
return EXIT_FAILURE;
|
||||
}
|
Loading…
Reference in New Issue