Added: shapes_exporter in NeL tools
This commit is contained in:
parent
7d0505d70c
commit
58060f5804
5 changed files with 478 additions and 69 deletions
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
#include <nel/misc/path.h>
|
#include <nel/misc/path.h>
|
||||||
#include <nel/misc/md5.h>
|
#include <nel/misc/md5.h>
|
||||||
|
#include <nel/misc/file.h>
|
||||||
#include "shapes_exporter.h"
|
#include "shapes_exporter.h"
|
||||||
|
|
||||||
using namespace NLMISC;
|
using namespace NLMISC;
|
||||||
|
@ -40,6 +41,44 @@ void split(const std::string &str, std::vector<std::string> &tokens, const std::
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CHashKeyMD5 getNewMD5(const std::string &filename)
|
||||||
|
{
|
||||||
|
CMD5Context md5ctx;
|
||||||
|
CHashKeyMD5 Message_Digest;
|
||||||
|
Message_Digest.clear();
|
||||||
|
|
||||||
|
CIFile ifile;
|
||||||
|
if (!ifile.open(filename))
|
||||||
|
{
|
||||||
|
nlwarning ("MD5: Can't open the file '%s'", filename.c_str());
|
||||||
|
return Message_Digest;
|
||||||
|
}
|
||||||
|
|
||||||
|
md5ctx.init();
|
||||||
|
|
||||||
|
uint8 buffer[1024];
|
||||||
|
int bufferSize = 1024;
|
||||||
|
sint fs = ifile.getFileSize();
|
||||||
|
sint n, read = 0;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
//bs = (int)fread (buffer, 1, bufferSize, fp);
|
||||||
|
n = std::min (bufferSize, fs-read);
|
||||||
|
//nlinfo ("read %d bytes", n);
|
||||||
|
ifile.serialBuffer((uint8 *)buffer, n);
|
||||||
|
|
||||||
|
md5ctx.update(buffer, n);
|
||||||
|
|
||||||
|
read += n;
|
||||||
|
}
|
||||||
|
while (!ifile.eof());
|
||||||
|
|
||||||
|
ifile.close ();
|
||||||
|
|
||||||
|
md5ctx.final(Message_Digest);
|
||||||
|
|
||||||
|
return Message_Digest;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(NL_OS_WINDOWS) && !defined(_CONSOLE)
|
#if defined(NL_OS_WINDOWS) && !defined(_CONSOLE)
|
||||||
sint WINAPI WinMain(HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */, LPSTR cmdline, int /* nCmdShow */)
|
sint WINAPI WinMain(HINSTANCE /* hInstance */, HINSTANCE /* hPrevInstance */, LPSTR cmdline, int /* nCmdShow */)
|
||||||
|
@ -68,7 +107,6 @@ sint main(int argc, char **argv)
|
||||||
|
|
||||||
exporter.parseConfigFile("shapes_exporter.cfg");
|
exporter.parseConfigFile("shapes_exporter.cfg");
|
||||||
exporter.init();
|
exporter.init();
|
||||||
exporter.setupLight();
|
|
||||||
|
|
||||||
if (argc > 1)
|
if (argc > 1)
|
||||||
{
|
{
|
||||||
|
@ -84,8 +122,26 @@ sint main(int argc, char **argv)
|
||||||
std::vector<std::string> filenames;
|
std::vector<std::string> filenames;
|
||||||
|
|
||||||
// search all .max files
|
// search all .max files
|
||||||
|
CPath::getPathContent(exporter.settings.input_path, true, false, true, filenames);
|
||||||
// CPath::getFileList("max", filenames);
|
// CPath::getFileList("max", filenames);
|
||||||
// search .max files corresponding to a filter
|
// search .max files corresponding to a filter
|
||||||
|
// fix bad textures
|
||||||
|
CPath::remapFile("ma_hof_armor_00_tibia_c1.tga", "ma_hof_armor00_tibia_c1.png");
|
||||||
|
CPath::remapFile("ma_hof_armor_00_foot_c1.tga", "ma_hof_armor00_foot_c1.png");
|
||||||
|
CPath::remapFile("ma_hof_armor_01_botte_c1.tga", "ma_hof_armor01_botte_c1.png");
|
||||||
|
CPath::remapFile("ma_hof_armor_01_pied_c1.tga", "ma_hof_armor01_pied_c1.png");
|
||||||
|
|
||||||
|
CPath::remapFile("ma_hom_armor_01_botte_c1.tga", "ma_hom_armor01_botte_c1.png");
|
||||||
|
CPath::remapFile("ma_hom_armor_01_pied_c1.tga", "ma_hom_armor01_pied_c1.png");
|
||||||
|
|
||||||
|
CPath::remapFile("hair_spec.tga", "spec_hair.png");
|
||||||
|
|
||||||
|
CPath::remapFile("zo_hof_armor_00_mollet_c1.tga", "zo_hof_armor00_mollet_c1.png");
|
||||||
|
CPath::remapFile("zo_hof_armor_00_pied_c1.tga", "zo_hof_armor00_pied_c1.png");
|
||||||
|
|
||||||
|
CPath::remapFile("zo_hom_armor_00_mollet_c1.tga", "zo_hom_armor00_mollet_c1.png");
|
||||||
|
CPath::remapFile("zo_hom_armor_00_pied_c1.tga", "zo_hom_armor00_pied_c1.png");
|
||||||
|
|
||||||
// CPath::getFileListByName("ps", "braziera", filenames);
|
// CPath::getFileListByName("ps", "braziera", filenames);
|
||||||
// CPath::getFileListByName("ps", "fireworka", filenames);
|
// CPath::getFileListByName("ps", "fireworka", filenames);
|
||||||
// CPath::getFileListByName("ps", "fireworkf", filenames);
|
// CPath::getFileListByName("ps", "fireworkf", filenames);
|
||||||
|
@ -100,40 +156,108 @@ sint main(int argc, char **argv)
|
||||||
CPath::getFileList("ps", shapes);
|
CPath::getFileList("ps", shapes);
|
||||||
for(size_t i = 0; i < filenames.size(); ++i)
|
for(size_t i = 0; i < filenames.size(); ++i)
|
||||||
{
|
{
|
||||||
|
if (filenames[i].find(".max") == std::string::npos)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
std::string baseFilename = toLower(CFile::getFilenameWithoutExtension(filenames[i]));
|
||||||
|
|
||||||
// compute the md5 of .max file
|
// compute the md5 of .max file
|
||||||
std::string md5 = getMD5(filenames[i]).toString();
|
std::string md5 = getNewMD5(filenames[i]).toString();
|
||||||
nlinfo("processing %s with md5 = %s", filenames[i].c_str(), md5.c_str());
|
nlinfo("processing %s with md5 = %s", filenames[i].c_str(), md5.c_str());
|
||||||
|
|
||||||
// the final directory with images
|
// the final directory with images
|
||||||
std::string output_path = exporter.settings.output_path + md5.substr(0, 2) + "/" + md5;
|
std::string output_path = exporter.settings.output_path + md5.substr(0, 2) + "/" + md5;
|
||||||
|
|
||||||
|
// file is an animation
|
||||||
|
std::string animation = ""; // CPath::lookup(baseFilename + ".anim", false, false, false);
|
||||||
|
// file is a skeleton
|
||||||
|
std::string skeleton = ""; // CPath::lookup(baseFilename + ".skel", false, false, false);
|
||||||
|
// file is a shape
|
||||||
|
std::string shape = CPath::lookup(baseFilename + ".shape", false, false, false);
|
||||||
|
|
||||||
|
// copy .shape file
|
||||||
|
if (!shape.empty() && false)
|
||||||
|
{
|
||||||
|
CIFile in;
|
||||||
|
COFile out;
|
||||||
|
|
||||||
|
// create output directory if it doesn't already exists
|
||||||
|
if (!CFile::isExists(output_path) && !CFile::createDirectoryTree(output_path))
|
||||||
|
{
|
||||||
|
nlwarning("can't create %s", output_path.c_str());
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (in.open(shape) && out.open(output_path + "/" + baseFilename + ".shape"))
|
||||||
|
{
|
||||||
|
uint32 size = in.getFileSize();
|
||||||
|
|
||||||
|
uint8 *buffer = new uint8[size];
|
||||||
|
|
||||||
|
in.serialBuffer(buffer, size);
|
||||||
|
out.serialBuffer(buffer, size);
|
||||||
|
|
||||||
|
delete [] buffer;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// try with several shapes binded on a skeleton
|
||||||
std::vector<std::string> filtered_shapes;
|
std::vector<std::string> filtered_shapes;
|
||||||
|
|
||||||
if(CFile::getExtension(filenames[i]) == "ps")
|
if (!animation.empty())
|
||||||
{
|
{
|
||||||
|
// render animation
|
||||||
|
skeleton = ShapesExporter::findSkeleton(filenames[i]);
|
||||||
|
|
||||||
|
// TODO: take from cfg
|
||||||
|
// filtered_shapes.push_back();
|
||||||
|
continue;
|
||||||
|
|
||||||
// no filter if it's a PS
|
// no filter if it's a PS
|
||||||
filtered_shapes.push_back(filenames[i]);
|
filtered_shapes.push_back(filenames[i]);
|
||||||
}
|
}
|
||||||
|
else if (!shape.empty())
|
||||||
|
{
|
||||||
|
// skeleton = ShapesExporter::findSkeleton(shape);
|
||||||
|
// render shape
|
||||||
|
}
|
||||||
|
else if (!skeleton.empty())
|
||||||
|
{
|
||||||
|
// don't render anything
|
||||||
|
continue;
|
||||||
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
continue;
|
||||||
|
/*
|
||||||
// create a temporary list with shapes which could correspond to .max file
|
// create a temporary list with shapes which could correspond to .max file
|
||||||
for(size_t j = 0; j < shapes.size(); ++j)
|
for(size_t j = 0; j < shapes.size(); ++j)
|
||||||
{
|
{
|
||||||
// only add files with the same beginning
|
// only add files with the same beginning
|
||||||
if (shapes[j].find(CFile::getFilenameWithoutExtension(filenames[i])) == 0)
|
if (shapes[j].find(baseFilename) == 0)
|
||||||
{
|
{
|
||||||
filtered_shapes.push_back(shapes[j]);
|
filtered_shapes.push_back(shapes[j]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
*/
|
||||||
|
|
||||||
// if there is no corresponding file, we can't render it
|
// if there is no corresponding file, we can't render it
|
||||||
if (filtered_shapes.empty())
|
if (filtered_shapes.empty())
|
||||||
{
|
{
|
||||||
nlinfo("no shape found");
|
nlwarning("didn't find type of %s", filenames[i].c_str());
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// if we found only one shape, we don't need a skeleton
|
||||||
|
if (filtered_shapes.size() == 1)
|
||||||
|
{
|
||||||
|
shape = filtered_shapes[0];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
skeleton = ShapesExporter::findSkeleton(filenames[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// create output directory if it doesn't already exists
|
// create output directory if it doesn't already exists
|
||||||
if (!CFile::isExists(output_path) && !CFile::createDirectoryTree(output_path))
|
if (!CFile::isExists(output_path) && !CFile::createDirectoryTree(output_path))
|
||||||
{
|
{
|
||||||
|
@ -141,32 +265,29 @@ sint main(int argc, char **argv)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// if we found only one shape, we don't need a skeleton
|
bool res = false;
|
||||||
if (filtered_shapes.size() == 1)
|
|
||||||
|
if (!skeleton.empty())
|
||||||
{
|
{
|
||||||
if (!exporter.exportShape(filtered_shapes[0], output_path))
|
res = exporter.exportSkeleton(skeleton, filtered_shapes, output_path);
|
||||||
|
}
|
||||||
|
else
|
||||||
{
|
{
|
||||||
// an error occured, try to delete directory
|
res = exporter.exportShape(shape, output_path);
|
||||||
nlwarning("can't export shape");
|
}
|
||||||
CFile::deleteDirectory(output_path);
|
|
||||||
continue;
|
if (res)
|
||||||
|
{
|
||||||
|
if (!exporter.createThumbnail(filenames[i], output_path))
|
||||||
|
{
|
||||||
|
nlwarning("can't create thumbnail");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
|
||||||
// TODO: search for the right skeleton
|
|
||||||
if (!exporter.exportSkeleton("fy_hof_skel.skel", filtered_shapes, output_path))
|
|
||||||
{
|
{
|
||||||
// an error occured, try to delete directory
|
// an error occured, try to delete directory
|
||||||
nlwarning("can't export shape");
|
nlwarning("can't export shape");
|
||||||
CFile::deleteDirectory(output_path);
|
CFile::deleteDirectory(output_path);
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!exporter.createThumbnail(filenames[i], output_path))
|
|
||||||
{
|
|
||||||
nlwarning("can't create thumbnail");
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
|
input_path = "";
|
||||||
search_pathes = { };
|
search_pathes = { };
|
||||||
recursive_search_pathes = { };
|
recursive_search_pathes = { };
|
||||||
output_path = "storage";
|
output_path = "storage";
|
||||||
extensions_remapping = { "dds", "tga" };
|
extensions_remapping = { "png", "tga", "dds", "tga" };
|
||||||
|
|
||||||
preview_width = 80;
|
preview_width = 80;
|
||||||
preview_height = 80;
|
preview_height = 80;
|
||||||
|
@ -17,7 +18,7 @@ output_antialiasing = 2; // 0 or 1 = none, 2 = 2x, etc...
|
||||||
output_quality = 90;
|
output_quality = 90;
|
||||||
output_background = { 0, 0, 0 };
|
output_background = { 0, 0, 0 };
|
||||||
|
|
||||||
light_ambiant = { 255, 255, 255 };
|
light_ambiant = { 0, 0, 0 };
|
||||||
light_diffuse = { 255, 255, 255 };
|
light_diffuse = { 255, 255, 255 };
|
||||||
light_specular = { 255, 255, 255 };
|
light_specular = { 255, 255, 255 };
|
||||||
light_direction = { 0.25, 0.5, 0.25 };
|
light_direction = { 0.25, 0.25, 0.25 };
|
||||||
|
|
|
@ -106,6 +106,15 @@ bool ShapesExporter::parseConfigFile(const string &filename)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// input path
|
||||||
|
try
|
||||||
|
{
|
||||||
|
settings.input_path = CPath::standardizePath(cf.getVar("input_path").asString());
|
||||||
|
}
|
||||||
|
catch (EUnknownVar &)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
// output path
|
// output path
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
|
@ -332,7 +341,7 @@ bool ShapesExporter::parseConfigFile(const string &filename)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShapesExporter::setupLight()
|
bool ShapesExporter::setupLight(const CVector &position, const CVector &direction)
|
||||||
{
|
{
|
||||||
// create the light
|
// create the light
|
||||||
ULight *Light = ULight::createLight();
|
ULight *Light = ULight::createLight();
|
||||||
|
@ -342,7 +351,8 @@ bool ShapesExporter::setupLight()
|
||||||
Light->setMode(ULight::DirectionalLight);
|
Light->setMode(ULight::DirectionalLight);
|
||||||
|
|
||||||
// set position of the light
|
// set position of the light
|
||||||
Light->setupDirectional(settings.light_ambiant, settings.light_diffuse, settings.light_specular, settings.light_direction);
|
// Light->setupDirectional(settings.light_ambiant, settings.light_diffuse, settings.light_specular, settings.light_direction);
|
||||||
|
Light->setupPointLight(settings.light_ambiant, settings.light_diffuse, settings.light_specular, position, direction + settings.light_direction);
|
||||||
|
|
||||||
// set and enable the light
|
// set and enable the light
|
||||||
Driver->setLight(0, *Light);
|
Driver->setLight(0, *Light);
|
||||||
|
@ -351,21 +361,117 @@ bool ShapesExporter::setupLight()
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void ShapesExporter::setCamera(CAABBox &bbox, UInstance &entity, bool high_z)
|
void ShapesExporter::setCamera(CAABBox &bbox, UTransform &entity, bool high_z)
|
||||||
{
|
{
|
||||||
|
CVector pos(0.f, 0.f, 0.f);
|
||||||
|
CQuat quat(0.f, 0.f, 0.f, 0.f);
|
||||||
|
NL3D::UInstance inst;
|
||||||
|
inst.cast(entity);
|
||||||
|
if (!inst.empty())
|
||||||
|
{
|
||||||
|
inst.getDefaultPos(pos);
|
||||||
|
inst.getDefaultRotQuat(quat);
|
||||||
|
/*
|
||||||
|
if (quat.getAxis().isNull())
|
||||||
|
{
|
||||||
|
quat.set(0, 0, 0, 0);
|
||||||
|
inst.setRotQuat(quat);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// quat.set(1.f, 1.f, 0.f, 0.f);
|
||||||
|
|
||||||
|
// inst.setRotQuat(quat);
|
||||||
|
// inst.getRotQuat(quat);
|
||||||
|
|
||||||
|
// check for presence of all textures from each sets
|
||||||
|
bool allGood = true;
|
||||||
|
|
||||||
|
for(uint s = 0; s < 5; ++s)
|
||||||
|
{
|
||||||
|
inst.selectTextureSet(s);
|
||||||
|
|
||||||
|
uint numMat = inst.getNumMaterials();
|
||||||
|
|
||||||
|
// by default, all textures are present
|
||||||
|
allGood = true;
|
||||||
|
|
||||||
|
for(uint i = 0; i < numMat; ++i)
|
||||||
|
{
|
||||||
|
UInstanceMaterial mat = inst.getMaterial(i);
|
||||||
|
|
||||||
|
for(sint j = 0; j <= mat.getLastTextureStage(); ++j)
|
||||||
|
{
|
||||||
|
// if a texture is missing
|
||||||
|
if (mat.isTextureFile(j) && mat.getTextureFileName(j) == "CTextureMultiFile:Dummy")
|
||||||
|
allGood = false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// if all textures have been found for this set, skip other sets
|
||||||
|
if (allGood)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// fix scale (some shapes have a different value)
|
||||||
|
entity.setScale(1.f, 1.f, 1.f);
|
||||||
|
|
||||||
UCamera Camera = Scene->getCam();
|
UCamera Camera = Scene->getCam();
|
||||||
CVector center = bbox.getCenter();
|
|
||||||
CVector max_radius = bbox.getHalfSize();
|
CVector max_radius = bbox.getHalfSize();
|
||||||
|
|
||||||
|
CVector center = bbox.getCenter();
|
||||||
entity.setPivot(center);
|
entity.setPivot(center);
|
||||||
|
center += pos;
|
||||||
|
|
||||||
float fov = float(20.0*Pi/180.0);
|
float fov = float(20.0*Pi/180.0);
|
||||||
Camera.setPerspective (fov, 1.0f, 0.1f, 1000.0f);
|
Camera.setPerspective (fov, 1.0f, 0.1f, 1000.0f);
|
||||||
float radius = max(max(max_radius.x, max_radius.y), max_radius.z);
|
float radius = max(max(max_radius.x, max_radius.y), max_radius.z);
|
||||||
|
if (radius == 0.f) radius = 1.f;
|
||||||
float left, right, bottom, top, znear, zfar;
|
float left, right, bottom, top, znear, zfar;
|
||||||
Camera.getFrustum(left, right, bottom, top, znear, zfar);
|
Camera.getFrustum(left, right, bottom, top, znear, zfar);
|
||||||
float dist = radius / (tan(fov/2));
|
float dist = radius / (tan(fov/2));
|
||||||
Camera.lookAt(CVector(center.x+dist+max_radius.x, center.y, center.z+(high_z?max_radius.z/1.0f:0.0f)), center);
|
CVector eye(center);
|
||||||
|
/* if (axis == CVector::I)
|
||||||
|
eye.y -= dist+radius;
|
||||||
|
else if (axis == CVector::J)
|
||||||
|
eye.x += dist+radius;
|
||||||
|
*/
|
||||||
|
// quat.normalize();
|
||||||
|
|
||||||
|
CVector ax(quat.getAxis());
|
||||||
|
|
||||||
|
// float angle = quat.getAngle();
|
||||||
|
/*
|
||||||
|
if (ax.isNull())
|
||||||
|
{
|
||||||
|
if (int(angle*100.f) == int(NLMISC::Pi * 200.f))
|
||||||
|
{
|
||||||
|
ax = CVector::J;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
*/
|
||||||
|
if (ax.isNull() || ax == CVector::I)
|
||||||
|
{
|
||||||
|
ax = CVector::I;
|
||||||
|
}
|
||||||
|
else if (ax == -CVector::K)
|
||||||
|
{
|
||||||
|
ax = -CVector::J;
|
||||||
|
}
|
||||||
|
/* else if (ax.x < -0.9f && ax.y == 0.f && ax.z == 0.f)
|
||||||
|
{
|
||||||
|
ax = -CVector::J ;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
// ax.normalize();
|
||||||
|
|
||||||
|
eye -= ax * (dist+radius);
|
||||||
|
if (high_z)
|
||||||
|
eye.z += max_radius.z/1.0f;
|
||||||
|
Camera.lookAt(eye, center);
|
||||||
|
|
||||||
|
setupLight(eye, center - eye);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShapesExporter::exportShape(const string &filename, const string &output_path)
|
bool ShapesExporter::exportShape(const string &filename, const string &output_path)
|
||||||
|
@ -397,6 +503,8 @@ bool ShapesExporter::exportShape(const string &filename, const string &output_pa
|
||||||
Scene->animate(1.0);
|
Scene->animate(1.0);
|
||||||
Scene->render();
|
Scene->render();
|
||||||
|
|
||||||
|
if(CFile::getExtension(filename) == "ps")
|
||||||
|
{
|
||||||
UParticleSystemInstance *psi = static_cast<UParticleSystemInstance*>(&Entity);
|
UParticleSystemInstance *psi = static_cast<UParticleSystemInstance*>(&Entity);
|
||||||
if(psi)
|
if(psi)
|
||||||
{
|
{
|
||||||
|
@ -404,8 +512,6 @@ bool ShapesExporter::exportShape(const string &filename, const string &output_pa
|
||||||
setCamera(bbox, Entity);
|
setCamera(bbox, Entity);
|
||||||
}
|
}
|
||||||
|
|
||||||
if(CFile::getExtension(filename) == "ps")
|
|
||||||
{
|
|
||||||
// first pass to detect bbox & duration
|
// first pass to detect bbox & duration
|
||||||
CAABBox bbox2;
|
CAABBox bbox2;
|
||||||
double duration = 0.0;
|
double duration = 0.0;
|
||||||
|
@ -418,7 +524,7 @@ bool ShapesExporter::exportShape(const string &filename, const string &output_pa
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
renderShape(Entity, CVector::I, output_path);
|
renderShape(Entity, output_path);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete entity
|
// delete entity
|
||||||
|
@ -470,22 +576,9 @@ bool ShapesExporter::exportSkeleton(const string &skeleton, const vector<string>
|
||||||
// get AABox of Entity
|
// get AABox of Entity
|
||||||
CAABBox bbox;
|
CAABBox bbox;
|
||||||
Skeleton.computeCurrentBBox(bbox, NULL);
|
Skeleton.computeCurrentBBox(bbox, NULL);
|
||||||
|
setCamera(bbox, Skeleton);
|
||||||
|
|
||||||
CVector center = bbox.getCenter();
|
renderShape(Skeleton, output_path);
|
||||||
CVector max_radius = bbox.getMax();
|
|
||||||
|
|
||||||
Skeleton.setPivot(center);
|
|
||||||
|
|
||||||
float radius = max_radius.x;
|
|
||||||
|
|
||||||
if (max_radius.y > radius) radius = max_radius.y;
|
|
||||||
if (max_radius.z > radius) radius = max_radius.z;
|
|
||||||
|
|
||||||
// camera will look at entities
|
|
||||||
// Camera.lookAt(CVector(center.x, center.y - bbox.getRadius() * 1.5f, center.z * 2.f), CVector(center.x, center.y, center.z * 2.f));
|
|
||||||
Camera.lookAt(CVector(center.x + bbox.getRadius() * 2.0f, center.y, center.z), CVector(center.x, center.y, center.z));
|
|
||||||
|
|
||||||
renderShape(Skeleton, CVector::J, output_path);
|
|
||||||
|
|
||||||
// delete entities
|
// delete entities
|
||||||
for(size_t i = 0; i < Entities.size(); ++i)
|
for(size_t i = 0; i < Entities.size(); ++i)
|
||||||
|
@ -500,6 +593,95 @@ bool ShapesExporter::exportSkeleton(const string &skeleton, const vector<string>
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
bool ShapesExporter::exportAnimation(const std::string &animation, const std::string &skeleton, const std::vector<std::string> &parts, const std::string &output_path)
|
||||||
|
{
|
||||||
|
UPlayListManager *PlayListManager = Scene->createPlayListManager();
|
||||||
|
UAnimationSet *AnimSet = Driver->createAnimationSet();
|
||||||
|
|
||||||
|
// uint anim_id = AnimSet->addAnimation("anim.anim", "anim_name", false);
|
||||||
|
// uint weight_id = AnimSet->addSkeletonWeight("file.wgt", "skel_name"):
|
||||||
|
|
||||||
|
// UAnimation *anim = AnimSet->getAnimation(anim_id);
|
||||||
|
// anim->getEndTime();
|
||||||
|
|
||||||
|
// UPlayList *playlist = playlist_manager->createPlayList(AnimSet);
|
||||||
|
// playlist->registerTransform(Skeleton);
|
||||||
|
|
||||||
|
// playlist->setAnimation(0, anim_id);
|
||||||
|
// playlist->setTimeOrigin(newSlot, time);
|
||||||
|
// playlist->setWeightSmoothness(newSlot, 1.0f);
|
||||||
|
|
||||||
|
// get scene camera
|
||||||
|
UCamera Camera = Scene->getCam();
|
||||||
|
if (Camera.empty())
|
||||||
|
{
|
||||||
|
nlwarning("can't get camera from scene");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// add a skeleton to the scene
|
||||||
|
USkeleton Skeleton = Scene->createSkeleton(skeleton);
|
||||||
|
|
||||||
|
// if we can't create entity, skip it
|
||||||
|
if (Skeleton.empty())
|
||||||
|
{
|
||||||
|
nlwarning("can't create skeleton from %s", skeleton.c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<UInstance> Entities(parts.size());
|
||||||
|
|
||||||
|
for(size_t i = 0; i < parts.size(); ++i)
|
||||||
|
{
|
||||||
|
Entities[i] = Scene->createInstance(parts[i]);
|
||||||
|
|
||||||
|
// if we can't create entity, skip it
|
||||||
|
if (Entities[i].empty())
|
||||||
|
{
|
||||||
|
nlwarning("can't create instance from %s", parts[i].c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Skeleton.bindSkin(Entities[i]))
|
||||||
|
{
|
||||||
|
nlwarning("can't bind %s to skeleton", parts[i].c_str());
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// get AABox of Entity
|
||||||
|
CAABBox bbox;
|
||||||
|
Skeleton.computeCurrentBBox(bbox, NULL);
|
||||||
|
|
||||||
|
setCamera();
|
||||||
|
|
||||||
|
// camera will look at skeleton
|
||||||
|
Camera.lookAt(CVector(center.x + dist - radius, center.y, center.z), center);
|
||||||
|
|
||||||
|
renderAllImages(Skeleton, CVector::J, output_path);
|
||||||
|
|
||||||
|
// delete entities
|
||||||
|
for(size_t i = 0; i < Entities.size(); ++i)
|
||||||
|
{
|
||||||
|
Skeleton.detachSkeletonSon(Entities[i]);
|
||||||
|
Scene->deleteInstance(Entities[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
// delete skeleton
|
||||||
|
Scene->deleteSkeleton(Skeleton);
|
||||||
|
|
||||||
|
Scene->deletePlayListManager(PlayListManager);
|
||||||
|
Driver->deleteAnimationSet(AnimSet);
|
||||||
|
|
||||||
|
// m_playlist->emptyPlayList();
|
||||||
|
// m_playlist->resetAllChannels();
|
||||||
|
// m_playlistman->deletePlayList(m_playlist);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
bool ShapesExporter::saveOneImage(const string &filename)
|
bool ShapesExporter::saveOneImage(const string &filename)
|
||||||
{
|
{
|
||||||
CBitmap btm;
|
CBitmap btm;
|
||||||
|
@ -543,21 +725,49 @@ bool ShapesExporter::saveOneImage(const string &filename)
|
||||||
nlwarning("can't create %s", filename.c_str());
|
nlwarning("can't create %s", filename.c_str());
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ShapesExporter::renderShape(UTransform &entity, const CVector &axis, const string &output_path)
|
bool ShapesExporter::renderShape(UTransform &entity, const string &output_path)
|
||||||
{
|
{
|
||||||
|
CQuat quat(0.f, 0.f, 0.f, 0.f);
|
||||||
|
|
||||||
|
CVector axis1 = CVector::J, axis2 = CVector::K;
|
||||||
|
int orientation1 = -1, orientation2 = 1;
|
||||||
|
|
||||||
|
NL3D::UInstance inst;
|
||||||
|
inst.cast(entity);
|
||||||
|
if (!inst.empty())
|
||||||
|
{
|
||||||
|
// inst.getDefaultRotQuat(quat);
|
||||||
|
inst.getRotQuat(quat);
|
||||||
|
/* if (!quat.getAxis().isNull())
|
||||||
|
{
|
||||||
|
CVector a = quat.getAxis();
|
||||||
|
if (a.z != 0 && a.x == 0.f)
|
||||||
|
{
|
||||||
|
axis1 = CVector::J;
|
||||||
|
orientation1 = -1;
|
||||||
|
}
|
||||||
|
if (a.y != 0.f)
|
||||||
|
{
|
||||||
|
axis2 = CVector::J;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
// main loop
|
// main loop
|
||||||
for (uint step_z = 0; step_z < settings.output_steps_z; ++step_z)
|
for (uint step_z = 0; step_z < settings.output_steps_z; ++step_z)
|
||||||
{
|
{
|
||||||
CQuat z(axis, (float)step_z * ((float)NLMISC::Pi*2.f / (float)settings.output_steps_z));
|
CQuat z(axis1, orientation1 * (float)step_z * ((float)NLMISC::Pi*2.f / (float)settings.output_steps_z));
|
||||||
|
|
||||||
for (uint step_x = 0; step_x < settings.output_steps_x; ++step_x)
|
for (uint step_x = 0; step_x < settings.output_steps_x; ++step_x)
|
||||||
{
|
{
|
||||||
CQuat x(CVector::K, (float)step_x * ((float)NLMISC::Pi*2.f / (float)settings.output_steps_x));
|
CQuat x(axis2, orientation2 * (float)step_x * ((float)NLMISC::Pi*2.f / (float)settings.output_steps_x));
|
||||||
|
|
||||||
entity.setRotQuat(z * x);
|
entity.setRotQuat(quat * z * x);
|
||||||
|
|
||||||
string filename = CPath::standardizePath(output_path) + toString("%03d_%03d.%s", step_z, step_x, settings.output_format.c_str());
|
string filename = CPath::standardizePath(output_path) + toString("%03d_%03d.%s", step_z, step_x, settings.output_format.c_str());
|
||||||
|
|
||||||
|
@ -729,3 +939,65 @@ bool ShapesExporter::createThumbnail(const string &filename, const string &path)
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::string ShapesExporter::findSkeleton(const std::string &shape)
|
||||||
|
{
|
||||||
|
std::string baseFilename = CFile::getFilenameWithoutExtension(shape);
|
||||||
|
|
||||||
|
// work in 60% of cases
|
||||||
|
std::string skeleton = CPath::lookup(baseFilename + ".skel", false, false, false);
|
||||||
|
|
||||||
|
if (!skeleton.empty())
|
||||||
|
return skeleton;
|
||||||
|
|
||||||
|
// remove last part
|
||||||
|
size_t pos = baseFilename.rfind("_");
|
||||||
|
|
||||||
|
if (pos != std::string::npos)
|
||||||
|
{
|
||||||
|
skeleton = CPath::lookup(baseFilename.substr(0, pos) + ".skel", false, false, false);
|
||||||
|
|
||||||
|
if (!skeleton.empty())
|
||||||
|
return skeleton;
|
||||||
|
|
||||||
|
pos = baseFilename.find("_");
|
||||||
|
|
||||||
|
std::vector<std::string> filenames;
|
||||||
|
|
||||||
|
CPath::getFileListByName("skel", baseFilename.substr(pos), filenames);
|
||||||
|
|
||||||
|
if (filenames.size() == 1)
|
||||||
|
{
|
||||||
|
skeleton = filenames[0];
|
||||||
|
return skeleton;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
int gender = 0;
|
||||||
|
|
||||||
|
if (baseFilename.find("_hom_") != std::string::npos)
|
||||||
|
{
|
||||||
|
gender = 1;
|
||||||
|
}
|
||||||
|
else if (baseFilename.find("_hof_") != std::string::npos)
|
||||||
|
{
|
||||||
|
gender = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
// bipeds
|
||||||
|
if (gender > 0)
|
||||||
|
{
|
||||||
|
// karavan
|
||||||
|
if (baseFilename.find("ca_") == 0)
|
||||||
|
return gender == 1 ? "ca_hom_armor01.skel":"ca_hof_armor01.skel";
|
||||||
|
|
||||||
|
return gender == 1 ? "fy_hom_skel.skel":"fy_hof_skel.skel";
|
||||||
|
}
|
||||||
|
|
||||||
|
nlwarning("can't find skeleton for %s", shape.c_str());
|
||||||
|
// goo mobs
|
||||||
|
// CPath::getFileListByName("max", "_hof_", filenames);
|
||||||
|
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
|
|
@ -26,6 +26,7 @@ struct Settings
|
||||||
{
|
{
|
||||||
Settings();
|
Settings();
|
||||||
|
|
||||||
|
std::string input_path;
|
||||||
std::string output_path;
|
std::string output_path;
|
||||||
|
|
||||||
std::string preview_format;
|
std::string preview_format;
|
||||||
|
@ -56,18 +57,19 @@ public:
|
||||||
|
|
||||||
bool init();
|
bool init();
|
||||||
bool parseConfigFile(const std::string &filename);
|
bool parseConfigFile(const std::string &filename);
|
||||||
bool setupLight();
|
bool setupLight(const NLMISC::CVector &position, const NLMISC::CVector &direction);
|
||||||
|
|
||||||
bool exportShape(const std::string &filename, const std::string &output_path);
|
bool exportShape(const std::string &filename, const std::string &output_path);
|
||||||
bool exportSkeleton(const std::string &skeleton, const std::vector<std::string> &parts, const std::string &output_path);
|
bool exportSkeleton(const std::string &skeleton, const std::vector<std::string> &parts, const std::string &output_path);
|
||||||
|
void setCamera(NLMISC::CAABBox &bbox, NL3D::UTransform &entity, bool high_z=false);
|
||||||
void setCamera(NLMISC::CAABBox &bbox, NL3D::UInstance &entity, bool high_z=false);
|
|
||||||
|
|
||||||
bool saveOneImage(const std::string &output_path);
|
bool saveOneImage(const std::string &output_path);
|
||||||
bool renderShape(NL3D::UTransform &entity, const NLMISC::CVector &axis, const std::string &output_path);
|
bool renderShape(NL3D::UTransform &entity, const std::string &output_path);
|
||||||
bool renderPS(NL3D::UInstance &entity, const std::string &output_path, double &duration, NLMISC::CAABBox &bbox);
|
bool renderPS(NL3D::UInstance &entity, const std::string &output_path, double &duration, NLMISC::CAABBox &bbox);
|
||||||
bool createThumbnail(const std::string &filename, const std::string &path);
|
bool createThumbnail(const std::string &filename, const std::string &path);
|
||||||
|
|
||||||
|
static std::string findSkeleton(const std::string &shape);
|
||||||
|
|
||||||
Settings settings;
|
Settings settings;
|
||||||
NL3D::UDriver* Driver;
|
NL3D::UDriver* Driver;
|
||||||
NL3D::UScene* Scene;
|
NL3D::UScene* Scene;
|
||||||
|
|
|
@ -395,6 +395,11 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "xml_packer", "misc\xml_pack
|
||||||
{44B21233-EFCC-4825-B5E5-3A3BD6CC5516} = {44B21233-EFCC-4825-B5E5-3A3BD6CC5516}
|
{44B21233-EFCC-4825-B5E5-3A3BD6CC5516} = {44B21233-EFCC-4825-B5E5-3A3BD6CC5516}
|
||||||
EndProjectSection
|
EndProjectSection
|
||||||
EndProject
|
EndProject
|
||||||
|
Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "shapes_exporter", "3d\shapes_exporter\shapes_exporter.vcproj", "{F8607267-5BA2-4BE8-A674-26C3F7D0A9BB}"
|
||||||
|
ProjectSection(ProjectDependencies) = postProject
|
||||||
|
{2B48BE83-108B-4E8E-8A55-6627CF09AC5A} = {2B48BE83-108B-4E8E-8A55-6627CF09AC5A}
|
||||||
|
EndProjectSection
|
||||||
|
EndProject
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Win32 = Debug|Win32
|
Debug|Win32 = Debug|Win32
|
||||||
|
@ -931,6 +936,14 @@ Global
|
||||||
{222663AE-5BAD-49B3-837F-26A518A3373A}.Release|Win32.Build.0 = Release|Win32
|
{222663AE-5BAD-49B3-837F-26A518A3373A}.Release|Win32.Build.0 = Release|Win32
|
||||||
{222663AE-5BAD-49B3-837F-26A518A3373A}.Release|x64.ActiveCfg = Release|x64
|
{222663AE-5BAD-49B3-837F-26A518A3373A}.Release|x64.ActiveCfg = Release|x64
|
||||||
{222663AE-5BAD-49B3-837F-26A518A3373A}.Release|x64.Build.0 = Release|x64
|
{222663AE-5BAD-49B3-837F-26A518A3373A}.Release|x64.Build.0 = Release|x64
|
||||||
|
{F8607267-5BA2-4BE8-A674-26C3F7D0A9BB}.Debug|Win32.ActiveCfg = Debug|Win32
|
||||||
|
{F8607267-5BA2-4BE8-A674-26C3F7D0A9BB}.Debug|Win32.Build.0 = Debug|Win32
|
||||||
|
{F8607267-5BA2-4BE8-A674-26C3F7D0A9BB}.Debug|x64.ActiveCfg = Debug|x64
|
||||||
|
{F8607267-5BA2-4BE8-A674-26C3F7D0A9BB}.Debug|x64.Build.0 = Debug|x64
|
||||||
|
{F8607267-5BA2-4BE8-A674-26C3F7D0A9BB}.Release|Win32.ActiveCfg = Release|Win32
|
||||||
|
{F8607267-5BA2-4BE8-A674-26C3F7D0A9BB}.Release|Win32.Build.0 = Release|Win32
|
||||||
|
{F8607267-5BA2-4BE8-A674-26C3F7D0A9BB}.Release|x64.ActiveCfg = Release|x64
|
||||||
|
{F8607267-5BA2-4BE8-A674-26C3F7D0A9BB}.Release|x64.Build.0 = Release|x64
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|
Loading…
Reference in a new issue