From Sukender, "- Added support for extended filenames (=not 8.3) for images: reads without crashing, optionnally write extended filenames (correctly truncate names if option is OFF). Write option is OFF by default.
- Improved identifiers generation in duplicate name handling (was limited to 1000 name collisions, which can be very short for some usages). - Set all read/write operations use a custom log function that will redirect lib3DS log to osg::notify() (was only used for streams) - Removed custom code (now uses osgDB::getFilePath()) - Added missing supportsOption() calls - Cleaned a few minor things"
This commit is contained in:
@@ -1,4 +1,3 @@
|
||||
#define ENABLE_3DS_WRITER 1 // Enables the 3DS writer (the define should be removed when the writer will be stable and tested enough)
|
||||
|
||||
#include <osg/Notify>
|
||||
#include <osg/Group>
|
||||
@@ -20,9 +19,7 @@
|
||||
//MIKEC debug only for PrintVisitor
|
||||
#include <osg/NodeVisitor>
|
||||
|
||||
#ifdef ENABLE_3DS_WRITER
|
||||
#include "WriterNodeVisitor.h"
|
||||
#endif
|
||||
#include "WriterNodeVisitor.h"
|
||||
#include "lib3ds/lib3ds.h"
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -171,17 +168,16 @@ public:
|
||||
|
||||
virtual ReadResult readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const;
|
||||
virtual ReadResult readNode(std::istream& fin, const Options* options) const;
|
||||
#if ENABLE_3DS_WRITER
|
||||
virtual ReadResult doReadNode(std::istream& fin, const Options* options, const std::string & fileNamelib3ds) const; ///< Subfunction of readNode()s functions.
|
||||
|
||||
virtual WriteResult writeNode(const osg::Node& /*node*/,const std::string& /*fileName*/,const Options* =NULL) const;
|
||||
virtual WriteResult writeNode(const osg::Node& /*node*/,std::ostream& /*fout*/,const Options* =NULL) const;
|
||||
#endif
|
||||
virtual WriteResult doWriteNode(const osg::Node& /*node*/,std::ostream& /*fout*/,const Options*, const std::string & fileNamelib3ds) const;
|
||||
|
||||
protected:
|
||||
ReadResult constructFrom3dsFile(Lib3dsFile *f,const std::string& filename, const Options* options) const;
|
||||
|
||||
#if ENABLE_3DS_WRITER
|
||||
bool createFileObject(const osg::Node& node, Lib3dsFile * file3ds,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const;
|
||||
#endif
|
||||
|
||||
class ReaderObject
|
||||
{
|
||||
@@ -220,7 +216,12 @@ REGISTER_OSGPLUGIN(3ds, ReaderWriter3DS)
|
||||
ReaderWriter3DS::ReaderWriter3DS()
|
||||
{
|
||||
supportsExtension("3ds","3D Studio model format");
|
||||
supportsOption("OutputTextureFiles","Write out the texture images to file");
|
||||
//supportsOption("OutputTextureFiles","Write out the texture images to file");
|
||||
//supportsOption("flipTexture", "flip texture upside-down");
|
||||
supportsOption("extended3dsFilePaths", "Keeps long texture filenames (not 8.3) when exporting 3DS, but can lead to compatibility problems.");
|
||||
supportsOption("noMatrixTransforms", "Set the plugin to apply matrices into the mesh vertices (\"old behaviour\") instead of restoring them (\"new behaviour\"). You may use this option to avoid a few rounding errors.");
|
||||
supportsOption("checkForEspilonIdentityMatrices", "If not set, then consider \"almost identity\" matrices to be identity ones (in case of rounding errors).");
|
||||
supportsOption("restoreMatrixTransformsNoMeshes", "Makes an exception to the behaviour when 'noMatrixTransforms' is not set for mesh instances. When a mesh instance has a transform on it, the reader creates a MatrixTransform above the Geode. If you don't want the hierarchy to be modified, then you can use this option to merge the transform into vertices.");
|
||||
setByteOrder();
|
||||
|
||||
#if 0
|
||||
@@ -252,16 +253,18 @@ ReaderWriter3DS::ReaderObject::ReaderObject(const osgDB::ReaderWriter::Options*
|
||||
checkForEspilonIdentityMatrices(false),
|
||||
restoreMatrixTransformsNoMeshes(false)
|
||||
{
|
||||
std::istringstream iss(options->getOptionString());
|
||||
std::string opt;
|
||||
while (iss >> opt)
|
||||
{
|
||||
if (opt == "noMatrixTransforms")
|
||||
noMatrixTransforms = true;
|
||||
if (opt == "checkForEspilonIdentityMatrices")
|
||||
checkForEspilonIdentityMatrices = true;
|
||||
if (opt == "restoreMatrixTransformsNoMeshes")
|
||||
restoreMatrixTransformsNoMeshes = true;
|
||||
if (options) {
|
||||
std::istringstream iss(options->getOptionString());
|
||||
std::string opt;
|
||||
while (iss >> opt)
|
||||
{
|
||||
if (opt == "noMatrixTransforms")
|
||||
noMatrixTransforms = true;
|
||||
if (opt == "checkForEspilonIdentityMatrices")
|
||||
checkForEspilonIdentityMatrices = true;
|
||||
if (opt == "restoreMatrixTransformsNoMeshes")
|
||||
restoreMatrixTransformsNoMeshes = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -556,7 +559,6 @@ static long filei_seek_func(void *self, long offset, Lib3dsIoSeek origin) {
|
||||
return f->fail() ? -1 : 0;
|
||||
}
|
||||
|
||||
#if ENABLE_3DS_WRITER
|
||||
static long fileo_seek_func(void *self, long offset, Lib3dsIoSeek origin) {
|
||||
std::ostream *f = reinterpret_cast<std::ostream*>(self);
|
||||
ios_base::seekdir o = ios_base::beg;
|
||||
@@ -566,19 +568,16 @@ static long fileo_seek_func(void *self, long offset, Lib3dsIoSeek origin) {
|
||||
f->seekp(offset, o);
|
||||
return f->fail() ? -1 : 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
static long filei_tell_func(void *self) {
|
||||
std::istream *f = reinterpret_cast<std::istream*>(self);
|
||||
return f->tellg();
|
||||
}
|
||||
|
||||
#if ENABLE_3DS_WRITER
|
||||
static long fileo_tell_func(void *self) {
|
||||
std::ostream *f = reinterpret_cast<std::ostream*>(self);
|
||||
return f->tellp();
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
static size_t filei_read_func(void *self, void *buffer, size_t size) {
|
||||
@@ -587,19 +586,18 @@ static size_t filei_read_func(void *self, void *buffer, size_t size) {
|
||||
return f->gcount();
|
||||
}
|
||||
|
||||
#if ENABLE_3DS_WRITER
|
||||
static size_t fileo_write_func(void *self, const void *buffer, size_t size) {
|
||||
std::ostream *f = reinterpret_cast<std::ostream*>(self);
|
||||
f->write(static_cast<const char*>(buffer), size);
|
||||
return f->fail() ? 0 : size;
|
||||
}
|
||||
#endif
|
||||
|
||||
static void fileio_log_func(void *self, Lib3dsLogLevel level, int indent, const char *msg)
|
||||
{
|
||||
osg::NotifySeverity l = osg::INFO;
|
||||
if (level == LIB3DS_LOG_ERROR) l = osg::FATAL;
|
||||
else if (level == LIB3DS_LOG_WARN) l = osg::WARN;
|
||||
// Intentionally NOT mapping 3DS levels with OSG levels
|
||||
if (level == LIB3DS_LOG_ERROR) l = osg::WARN;
|
||||
else if (level == LIB3DS_LOG_WARN) l = osg::NOTICE;
|
||||
else if (level == LIB3DS_LOG_INFO) l = osg::INFO;
|
||||
else if (level == LIB3DS_LOG_DEBUG) l = osg::DEBUG_INFO;
|
||||
osg::notify(l) << msg << std::endl;
|
||||
@@ -608,14 +606,21 @@ static void fileio_log_func(void *self, Lib3dsLogLevel level, int indent, const
|
||||
|
||||
osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(std::istream& fin, const osgDB::ReaderWriter::Options* options) const
|
||||
{
|
||||
osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED;
|
||||
|
||||
std::string optFileName = "";
|
||||
std::string optFileName;
|
||||
if (options)
|
||||
{
|
||||
optFileName = options->getPluginStringData("STREAM_FILENAME");
|
||||
if (optFileName.empty()) optFileName = options->getPluginStringData("filename");
|
||||
}
|
||||
return doReadNode(fin, options, optFileName);
|
||||
}
|
||||
|
||||
osgDB::ReaderWriter::ReadResult ReaderWriter3DS::doReadNode(std::istream& fin, const osgDB::ReaderWriter::Options* options, const std::string & fileNamelib3ds) const
|
||||
{
|
||||
osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
|
||||
local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileNamelib3ds));
|
||||
|
||||
osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED;
|
||||
|
||||
// Prepare io structure to tell how to read the stream
|
||||
Lib3dsIo io;
|
||||
@@ -629,7 +634,7 @@ osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(std::istream& fin, co
|
||||
Lib3dsFile * file3ds = lib3ds_file_new();
|
||||
if (lib3ds_file_read(file3ds, &io) != 0)
|
||||
{
|
||||
result = constructFrom3dsFile(file3ds,optFileName,options);
|
||||
result = constructFrom3dsFile(file3ds,fileNamelib3ds,options);
|
||||
lib3ds_file_free(file3ds);
|
||||
}
|
||||
|
||||
@@ -638,15 +643,21 @@ osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(std::istream& fin, co
|
||||
|
||||
osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(const std::string& file, const osgDB::ReaderWriter::Options* options) const
|
||||
{
|
||||
osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED;
|
||||
|
||||
std::string ext = osgDB::getLowerCaseFileExtension(file);
|
||||
if (!acceptsExtension(ext)) return ReadResult::FILE_NOT_HANDLED;
|
||||
|
||||
std::string fileName = osgDB::findDataFile( file, options );
|
||||
if (fileName.empty()) return ReadResult::FILE_NOT_FOUND;
|
||||
|
||||
Lib3dsFile *f = lib3ds_file_open(fileName.c_str() /*,options*/);
|
||||
// Do not use the lib3ds_file_open() as:
|
||||
// 1. It relies on FILE* instead of iostreams (less safe)
|
||||
// 2. It doesn't allow us to set a custom log output
|
||||
std::ifstream fin(file.c_str(), std::ios_base::in | std::ios_base::binary);
|
||||
if (!fin.good()) return ReadResult::ERROR_IN_READING_FILE;
|
||||
return doReadNode(fin, options, fileName);
|
||||
/*
|
||||
osgDB::ReaderWriter::ReadResult result = ReadResult::FILE_NOT_HANDLED;
|
||||
Lib3dsFile *f = lib3ds_file_open(fileName.c_str()); // ,options
|
||||
|
||||
if (f)
|
||||
{
|
||||
@@ -658,6 +669,7 @@ osgDB::ReaderWriter::ReadResult ReaderWriter3DS::readNode(const std::string& fil
|
||||
}
|
||||
|
||||
return result;
|
||||
*/
|
||||
}
|
||||
|
||||
osgDB::ReaderWriter::ReadResult ReaderWriter3DS::constructFrom3dsFile(Lib3dsFile *f,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const
|
||||
@@ -1058,14 +1070,15 @@ osg::StateSet* ReaderWriter3DS::ReaderObject::createStateSet(Lib3dsMaterial *mat
|
||||
}
|
||||
|
||||
|
||||
|
||||
#if ENABLE_3DS_WRITER
|
||||
osgDB::ReaderWriter::WriteResult ReaderWriter3DS::writeNode(const osg::Node& node,const std::string& fileName,const Options* options) const {
|
||||
std::string ext = osgDB::getLowerCaseFileExtension(fileName);
|
||||
if (!acceptsExtension(ext)) return WriteResult::FILE_NOT_HANDLED;
|
||||
|
||||
//osg::notify(osg::WARN) << "!!WARNING!! 3DS write support is incomplete" << std::endl;
|
||||
|
||||
osgDB::makeDirectoryForFile(fileName.c_str());
|
||||
std::ofstream fout(fileName.c_str(), std::ios_base::out | std::ios_base::binary);
|
||||
if (!fout.good()) return WriteResult::ERROR_IN_WRITING_FILE;
|
||||
return doWriteNode(node, fout, options, fileName);
|
||||
/*
|
||||
bool ok = true;
|
||||
Lib3dsFile * file3ds = lib3ds_file_new();
|
||||
if (!file3ds) return WriteResult(WriteResult::ERROR_IN_WRITING_FILE);
|
||||
@@ -1074,7 +1087,7 @@ osgDB::ReaderWriter::WriteResult ReaderWriter3DS::writeNode(const osg::Node& nod
|
||||
osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
|
||||
local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileName));
|
||||
|
||||
if (!createFileObject(node, file3ds, fileName, local_opt.get())) ok = false;
|
||||
if (!createFileObject(node, file3ds, fileName, local_opt)) ok = false;
|
||||
if (ok && !lib3ds_file_save(file3ds, fileName.c_str())) ok = false;
|
||||
} catch (...) {
|
||||
lib3ds_file_free(file3ds);
|
||||
@@ -1083,18 +1096,24 @@ osgDB::ReaderWriter::WriteResult ReaderWriter3DS::writeNode(const osg::Node& nod
|
||||
lib3ds_file_free(file3ds);
|
||||
|
||||
return ok ? WriteResult(WriteResult::FILE_SAVED) : WriteResult(WriteResult::ERROR_IN_WRITING_FILE);
|
||||
//return ok ? WriteResult(WriteResult::FILE_SAVED) : WriteResult(WriteResult::FILE_NOT_HANDLED);
|
||||
*/
|
||||
}
|
||||
|
||||
|
||||
osgDB::ReaderWriter::WriteResult ReaderWriter3DS::writeNode(const osg::Node& node,std::ostream& fout,const Options* options) const {
|
||||
//osg::notify(osg::WARN) << "!!WARNING!! 3DS write support is incomplete" << std::endl;
|
||||
std::string optFileName = "";
|
||||
if (options)
|
||||
{
|
||||
std::string optFileName;
|
||||
if (options) {
|
||||
optFileName = options->getPluginStringData("STREAM_FILENAME");
|
||||
}
|
||||
|
||||
return doWriteNode(node, fout, options, optFileName);
|
||||
}
|
||||
|
||||
osgDB::ReaderWriter::WriteResult ReaderWriter3DS::doWriteNode(const osg::Node& node,std::ostream& fout, const Options* options, const std::string & fileNamelib3ds) const {
|
||||
osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
|
||||
local_opt->getDatabasePathList().push_front(osgDB::getFilePath(fileNamelib3ds));
|
||||
|
||||
Lib3dsIo io;
|
||||
io.self = &fout;
|
||||
io.seek_func = fileo_seek_func;
|
||||
@@ -1104,12 +1123,11 @@ osgDB::ReaderWriter::WriteResult ReaderWriter3DS::writeNode(const osg::Node& nod
|
||||
io.log_func = fileio_log_func;
|
||||
|
||||
Lib3dsFile * file3ds = lib3ds_file_new();
|
||||
if (!file3ds) return WriteResult(WriteResult::ERROR_IN_WRITING_FILE);
|
||||
|
||||
bool ok = true;
|
||||
try {
|
||||
osg::ref_ptr<Options> local_opt = options ? static_cast<Options*>(options->clone(osg::CopyOp::SHALLOW_COPY)) : new Options;
|
||||
local_opt->getDatabasePathList().push_front(osgDB::getFilePath(optFileName));
|
||||
|
||||
if (!createFileObject(node, file3ds, optFileName, local_opt.get())) ok = false;
|
||||
if (!createFileObject(node, file3ds, fileNamelib3ds, local_opt.get())) ok = false;
|
||||
if (ok && !lib3ds_file_write(file3ds, &io)) ok = false;
|
||||
|
||||
} catch (...) {
|
||||
@@ -1122,32 +1140,12 @@ osgDB::ReaderWriter::WriteResult ReaderWriter3DS::writeNode(const osg::Node& nod
|
||||
//return ok ? WriteResult(WriteResult::FILE_SAVED) : WriteResult(WriteResult::FILE_NOT_HANDLED);
|
||||
}
|
||||
|
||||
const std::string getParent(const std::string & pathBad)
|
||||
{
|
||||
const std::string & path = osgDB::convertFileNameToNativeStyle(pathBad);
|
||||
|
||||
std::string parent = "";
|
||||
std::string tmp = "";
|
||||
for(std::string::const_iterator itPath = path.begin();; ++itPath)
|
||||
{
|
||||
if (!parent.empty())
|
||||
parent += '\\';
|
||||
parent += tmp;
|
||||
tmp.clear();
|
||||
for(;itPath != path.end() && *itPath != '\\'; ++itPath)
|
||||
tmp += *itPath;
|
||||
if (itPath == path.end())
|
||||
break;
|
||||
}
|
||||
return parent;
|
||||
}
|
||||
|
||||
bool ReaderWriter3DS::createFileObject(const osg::Node& node, Lib3dsFile * file3ds,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const {
|
||||
WriterNodeVisitor w(file3ds, fileName, options, getParent(node.getName()));
|
||||
const_cast<osg::Node &>(node).accept(w); // TODO Remove that ugly const_cast<>. Any idea?
|
||||
WriterNodeVisitor w(file3ds, fileName, options, osgDB::getFilePath(node.getName()));
|
||||
const_cast<osg::Node &>(node).accept(w); // Ugly const_cast<> for visitor...
|
||||
if (!w.suceedLastApply())
|
||||
return false;
|
||||
w.writeMaterials();
|
||||
return true; //w.good();
|
||||
}
|
||||
#endif // ENABLE_3DS_WRITER
|
||||
|
||||
|
||||
@@ -1,135 +1,135 @@
|
||||
#include "WriterCompareTriangle.h"
|
||||
|
||||
WriterCompareTriangle::WriterCompareTriangle(const osg::Geode & geode, unsigned int nbVertices) : geode(geode)
|
||||
{
|
||||
cutscene(nbVertices, geode.getBoundingBox());
|
||||
}
|
||||
|
||||
bool
|
||||
WriterCompareTriangle::operator()(const std::pair<Triangle, int> & t1,
|
||||
const std::pair<Triangle, int> & t2) const
|
||||
{
|
||||
const osg::Geometry *g = geode.getDrawable( t1.second )->asGeometry();
|
||||
|
||||
const osg::Vec3Array * vecs= static_cast<const osg::Vec3Array *>(g->getVertexArray());
|
||||
const osg::BoundingBox::vec_type v1( (*vecs)[t1.first.t1] );
|
||||
|
||||
if (t1.second != t2.second)
|
||||
{
|
||||
const osg::Geometry *g = geode.getDrawable( t2.second )->asGeometry();
|
||||
vecs = static_cast<const osg::Vec3Array *>(g->getVertexArray());
|
||||
};
|
||||
const osg::BoundingBox::vec_type v2( (*vecs)[t2.first.t1] );
|
||||
int val1 = inWhichBox(v1);
|
||||
int val2 = inWhichBox(v2);
|
||||
|
||||
return (val1 < val2);
|
||||
}
|
||||
|
||||
void
|
||||
WriterCompareTriangle::setMaxMin(unsigned int & nbVerticesX,
|
||||
unsigned int & nbVerticesY,
|
||||
unsigned int & nbVerticesZ) const
|
||||
{
|
||||
static const unsigned int min = 1;
|
||||
static const unsigned int max = 5; // Number of blocks used to divide the scene (arbitrary but seems ok)
|
||||
nbVerticesX = osg::clampBetween<unsigned int>(nbVerticesX, min, max);
|
||||
nbVerticesY = osg::clampBetween<unsigned int>(nbVerticesY, min, max);
|
||||
nbVerticesZ = osg::clampBetween<unsigned int>(nbVerticesZ, min, max);
|
||||
}
|
||||
|
||||
void WriterCompareTriangle::cutscene(int nbVertices, const osg::BoundingBox & sceneBox)
|
||||
{
|
||||
osg::BoundingBox::vec_type length = sceneBox._max - sceneBox._min;
|
||||
|
||||
static const float k = 1.3f; // Arbitrary constant multiplier for density computation ("simulates" non-uniform point distributions)
|
||||
// Computes "density" of points, and thus the number of blocks to divide the mesh into
|
||||
unsigned int nbVerticesX = static_cast<unsigned int>( (nbVertices * k) / (length.z() * length.y()) );
|
||||
unsigned int nbVerticesY = static_cast<unsigned int>( (nbVertices * k) / (length.z() * length.x()) );
|
||||
unsigned int nbVerticesZ = static_cast<unsigned int>( (nbVertices * k) / (length.x() * length.y()) );
|
||||
|
||||
setMaxMin (nbVerticesX, nbVerticesY, nbVerticesZ); // This function prevent from cut scene in too many blocs
|
||||
|
||||
osg::notify(osg::ALWAYS) << "Cutting x by " << nbVerticesX << std::endl
|
||||
<< "Cutting y by " << nbVerticesY << std::endl
|
||||
<< "Cutting z by " << nbVerticesZ << std::endl;
|
||||
|
||||
osg::BoundingBox::value_type blocX = length.x() / nbVerticesX; //This 3 lines set the size of a bloc in x, y and z
|
||||
osg::BoundingBox::value_type blocY = length.y() / nbVerticesY;
|
||||
osg::BoundingBox::value_type blocZ = length.z() / nbVerticesZ;
|
||||
|
||||
boxList.reserve(nbVerticesX * nbVerticesY * nbVerticesZ);
|
||||
short yinc = 1;
|
||||
short xinc = 1;
|
||||
unsigned int y = 0;
|
||||
unsigned int x = 0;
|
||||
for (unsigned int z = 0; z < nbVerticesZ; ++z)
|
||||
{
|
||||
while (x < nbVerticesX && x >= 0)
|
||||
{
|
||||
while (y < nbVerticesY && y >= 0)
|
||||
{
|
||||
osg::BoundingBox::value_type xMin = sceneBox.xMin() + x * blocX;
|
||||
if (x == 0) //to prevent from mesh with no case
|
||||
xMin -= 10;
|
||||
|
||||
osg::BoundingBox::value_type yMin = sceneBox.yMin() + y * blocY;
|
||||
if (y == 0) //to prevent from mesh with no case
|
||||
yMin -= 10;
|
||||
|
||||
osg::BoundingBox::value_type zMin = sceneBox.zMin() + z * blocZ;
|
||||
if (z == 0) //to prevent from mesh with no case
|
||||
zMin -= 10;
|
||||
|
||||
osg::BoundingBox::value_type xMax = sceneBox.xMin() + (x + 1) * blocX;
|
||||
if (x == nbVerticesX - 1) //to prevent from mesh with no case
|
||||
xMax += 10;
|
||||
|
||||
osg::BoundingBox::value_type yMax = sceneBox.yMin() + (y + 1) * blocY;
|
||||
if (y == nbVerticesY - 1) //to prevent from mesh with no case
|
||||
yMax += 10;
|
||||
|
||||
osg::BoundingBox::value_type zMax = sceneBox.zMin() + (z + 1) * blocZ;
|
||||
if (z == nbVerticesZ - 1) //to prevent from mesh with no case
|
||||
zMax += 10;
|
||||
|
||||
boxList.push_back(osg::BoundingBox(xMin, // Add a bloc to the list
|
||||
yMin,
|
||||
zMin,
|
||||
xMax,
|
||||
yMax,
|
||||
zMax));
|
||||
y += yinc;
|
||||
}
|
||||
yinc = -yinc;
|
||||
y += yinc;
|
||||
x += xinc;
|
||||
}
|
||||
xinc = -xinc;
|
||||
x += xinc;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
WriterCompareTriangle::inWhichBox(const osg::BoundingBox::value_type x,
|
||||
const osg::BoundingBox::value_type y,
|
||||
const osg::BoundingBox::value_type z) const
|
||||
{
|
||||
for (unsigned int i = 0; i < boxList.size(); ++i)
|
||||
{
|
||||
if (x >= boxList[i].xMin() &&
|
||||
x < boxList[i].xMax() &&
|
||||
y >= boxList[i].yMin() &&
|
||||
y < boxList[i].yMax() &&
|
||||
z >= boxList[i].zMin() &&
|
||||
z < boxList[i].zMax())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw "Point is not in any blocs";
|
||||
}
|
||||
|
||||
int WriterCompareTriangle::inWhichBox(const osg::BoundingBox::vec_type & point) const {
|
||||
return inWhichBox(point.x(), point.y(), point.z());
|
||||
}
|
||||
#include "WriterCompareTriangle.h"
|
||||
|
||||
WriterCompareTriangle::WriterCompareTriangle(const osg::Geode & geode, unsigned int nbVertices) : geode(geode)
|
||||
{
|
||||
cutscene(nbVertices, geode.getBoundingBox());
|
||||
}
|
||||
|
||||
bool
|
||||
WriterCompareTriangle::operator()(const std::pair<Triangle, int> & t1,
|
||||
const std::pair<Triangle, int> & t2) const
|
||||
{
|
||||
const osg::Geometry *g = geode.getDrawable( t1.second )->asGeometry();
|
||||
|
||||
const osg::Vec3Array * vecs= static_cast<const osg::Vec3Array *>(g->getVertexArray());
|
||||
const osg::BoundingBox::vec_type v1( (*vecs)[t1.first.t1] );
|
||||
|
||||
if (t1.second != t2.second)
|
||||
{
|
||||
const osg::Geometry *g = geode.getDrawable( t2.second )->asGeometry();
|
||||
vecs = static_cast<const osg::Vec3Array *>(g->getVertexArray());
|
||||
};
|
||||
const osg::BoundingBox::vec_type v2( (*vecs)[t2.first.t1] );
|
||||
int val1 = inWhichBox(v1);
|
||||
int val2 = inWhichBox(v2);
|
||||
|
||||
return (val1 < val2);
|
||||
}
|
||||
|
||||
void
|
||||
WriterCompareTriangle::setMaxMin(unsigned int & nbVerticesX,
|
||||
unsigned int & nbVerticesY,
|
||||
unsigned int & nbVerticesZ) const
|
||||
{
|
||||
static const unsigned int min = 1;
|
||||
static const unsigned int max = 5; // Number of blocks used to divide the scene (arbitrary but seems ok)
|
||||
nbVerticesX = osg::clampBetween<unsigned int>(nbVerticesX, min, max);
|
||||
nbVerticesY = osg::clampBetween<unsigned int>(nbVerticesY, min, max);
|
||||
nbVerticesZ = osg::clampBetween<unsigned int>(nbVerticesZ, min, max);
|
||||
}
|
||||
|
||||
void WriterCompareTriangle::cutscene(int nbVertices, const osg::BoundingBox & sceneBox)
|
||||
{
|
||||
osg::BoundingBox::vec_type length = sceneBox._max - sceneBox._min;
|
||||
|
||||
static const float k = 1.3f; // Arbitrary constant multiplier for density computation ("simulates" non-uniform point distributions)
|
||||
// Computes "density" of points, and thus the number of blocks to divide the mesh into
|
||||
unsigned int nbVerticesX = static_cast<unsigned int>( (nbVertices * k) / (length.z() * length.y()) );
|
||||
unsigned int nbVerticesY = static_cast<unsigned int>( (nbVertices * k) / (length.z() * length.x()) );
|
||||
unsigned int nbVerticesZ = static_cast<unsigned int>( (nbVertices * k) / (length.x() * length.y()) );
|
||||
|
||||
setMaxMin (nbVerticesX, nbVerticesY, nbVerticesZ); // This function prevent from cut scene in too many blocs
|
||||
|
||||
osg::notify(osg::ALWAYS) << "Cutting x by " << nbVerticesX << std::endl
|
||||
<< "Cutting y by " << nbVerticesY << std::endl
|
||||
<< "Cutting z by " << nbVerticesZ << std::endl;
|
||||
|
||||
osg::BoundingBox::value_type blocX = length.x() / nbVerticesX; //This 3 lines set the size of a bloc in x, y and z
|
||||
osg::BoundingBox::value_type blocY = length.y() / nbVerticesY;
|
||||
osg::BoundingBox::value_type blocZ = length.z() / nbVerticesZ;
|
||||
|
||||
boxList.reserve(nbVerticesX * nbVerticesY * nbVerticesZ);
|
||||
short yinc = 1;
|
||||
short xinc = 1;
|
||||
unsigned int y = 0;
|
||||
unsigned int x = 0;
|
||||
for (unsigned int z = 0; z < nbVerticesZ; ++z)
|
||||
{
|
||||
while (x < nbVerticesX && x >= 0)
|
||||
{
|
||||
while (y < nbVerticesY && y >= 0)
|
||||
{
|
||||
osg::BoundingBox::value_type xMin = sceneBox.xMin() + x * blocX;
|
||||
if (x == 0) //to prevent from mesh with no case
|
||||
xMin -= 10;
|
||||
|
||||
osg::BoundingBox::value_type yMin = sceneBox.yMin() + y * blocY;
|
||||
if (y == 0) //to prevent from mesh with no case
|
||||
yMin -= 10;
|
||||
|
||||
osg::BoundingBox::value_type zMin = sceneBox.zMin() + z * blocZ;
|
||||
if (z == 0) //to prevent from mesh with no case
|
||||
zMin -= 10;
|
||||
|
||||
osg::BoundingBox::value_type xMax = sceneBox.xMin() + (x + 1) * blocX;
|
||||
if (x == nbVerticesX - 1) //to prevent from mesh with no case
|
||||
xMax += 10;
|
||||
|
||||
osg::BoundingBox::value_type yMax = sceneBox.yMin() + (y + 1) * blocY;
|
||||
if (y == nbVerticesY - 1) //to prevent from mesh with no case
|
||||
yMax += 10;
|
||||
|
||||
osg::BoundingBox::value_type zMax = sceneBox.zMin() + (z + 1) * blocZ;
|
||||
if (z == nbVerticesZ - 1) //to prevent from mesh with no case
|
||||
zMax += 10;
|
||||
|
||||
boxList.push_back(osg::BoundingBox(xMin, // Add a bloc to the list
|
||||
yMin,
|
||||
zMin,
|
||||
xMax,
|
||||
yMax,
|
||||
zMax));
|
||||
y += yinc;
|
||||
}
|
||||
yinc = -yinc;
|
||||
y += yinc;
|
||||
x += xinc;
|
||||
}
|
||||
xinc = -xinc;
|
||||
x += xinc;
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
WriterCompareTriangle::inWhichBox(const osg::BoundingBox::value_type x,
|
||||
const osg::BoundingBox::value_type y,
|
||||
const osg::BoundingBox::value_type z) const
|
||||
{
|
||||
for (unsigned int i = 0; i < boxList.size(); ++i)
|
||||
{
|
||||
if (x >= boxList[i].xMin() &&
|
||||
x < boxList[i].xMax() &&
|
||||
y >= boxList[i].yMin() &&
|
||||
y < boxList[i].yMax() &&
|
||||
z >= boxList[i].zMin() &&
|
||||
z < boxList[i].zMax())
|
||||
{
|
||||
return i;
|
||||
}
|
||||
}
|
||||
throw "Point is not in any blocs";
|
||||
}
|
||||
|
||||
int WriterCompareTriangle::inWhichBox(const osg::BoundingBox::vec_type & point) const {
|
||||
return inWhichBox(point.x(), point.y(), point.z());
|
||||
}
|
||||
|
||||
@@ -1,51 +1,51 @@
|
||||
#ifndef _3DS_WRITER_COMPARE_TRIANGLE_HEADER__
|
||||
#define _3DS_WRITER_COMPARE_TRIANGLE_HEADER__
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <iostream>
|
||||
|
||||
struct Triangle
|
||||
{
|
||||
unsigned int t1;
|
||||
unsigned int t2;
|
||||
unsigned int t3;
|
||||
unsigned int material;
|
||||
};
|
||||
|
||||
class WriterCompareTriangle {
|
||||
public:
|
||||
WriterCompareTriangle(const osg::Geode & geode, unsigned int nbVertices);
|
||||
|
||||
bool operator()(const std::pair<Triangle, int> & t1,
|
||||
const std::pair<Triangle, int> & t2) const;
|
||||
private:
|
||||
void // This function prevent from cut scene in too many blocs
|
||||
setMaxMin(unsigned int & nbVerticesX,
|
||||
unsigned int & nbVerticesY,
|
||||
unsigned int & nbVerticesZ) const;
|
||||
|
||||
/**
|
||||
* Cut the scene in different bloc to sort.
|
||||
* \param nbVertices is the number of vertice in mesh.
|
||||
* \param sceneBox contain the size of the scene.
|
||||
*/
|
||||
void
|
||||
cutscene(int nbVertices,
|
||||
const osg::BoundingBox & sceneBox);
|
||||
|
||||
/**
|
||||
* Find in which box those points are.
|
||||
* \return the place of the box in the vector.
|
||||
* \sa See cutScene() about the definition of the boxes for faces sorting.
|
||||
*/
|
||||
int inWhichBox(const osg::BoundingBox::value_type x,
|
||||
const osg::BoundingBox::value_type y,
|
||||
const osg::BoundingBox::value_type z) const;
|
||||
int inWhichBox(const osg::BoundingBox::vec_type & point) const;
|
||||
|
||||
const osg::Geode & geode;
|
||||
std::vector<osg::BoundingBox> boxList;
|
||||
};
|
||||
|
||||
#endif // _3DS_WRITER_COMPARE_TRIANGLE_HEADER__
|
||||
#ifndef _3DS_WRITER_COMPARE_TRIANGLE_HEADER__
|
||||
#define _3DS_WRITER_COMPARE_TRIANGLE_HEADER__
|
||||
|
||||
#include <osg/Geode>
|
||||
#include <osg/Geometry>
|
||||
#include <iostream>
|
||||
|
||||
struct Triangle
|
||||
{
|
||||
unsigned int t1;
|
||||
unsigned int t2;
|
||||
unsigned int t3;
|
||||
unsigned int material;
|
||||
};
|
||||
|
||||
class WriterCompareTriangle {
|
||||
public:
|
||||
WriterCompareTriangle(const osg::Geode & geode, unsigned int nbVertices);
|
||||
|
||||
bool operator()(const std::pair<Triangle, int> & t1,
|
||||
const std::pair<Triangle, int> & t2) const;
|
||||
private:
|
||||
void // This function prevent from cut scene in too many blocs
|
||||
setMaxMin(unsigned int & nbVerticesX,
|
||||
unsigned int & nbVerticesY,
|
||||
unsigned int & nbVerticesZ) const;
|
||||
|
||||
/**
|
||||
* Cut the scene in different bloc to sort.
|
||||
* \param nbVertices is the number of vertice in mesh.
|
||||
* \param sceneBox contain the size of the scene.
|
||||
*/
|
||||
void
|
||||
cutscene(int nbVertices,
|
||||
const osg::BoundingBox & sceneBox);
|
||||
|
||||
/**
|
||||
* Find in which box those points are.
|
||||
* \return the place of the box in the vector.
|
||||
* \sa See cutScene() about the definition of the boxes for faces sorting.
|
||||
*/
|
||||
int inWhichBox(const osg::BoundingBox::value_type x,
|
||||
const osg::BoundingBox::value_type y,
|
||||
const osg::BoundingBox::value_type z) const;
|
||||
int inWhichBox(const osg::BoundingBox::vec_type & point) const;
|
||||
|
||||
const osg::Geode & geode;
|
||||
std::vector<osg::BoundingBox> boxList;
|
||||
};
|
||||
|
||||
#endif // _3DS_WRITER_COMPARE_TRIANGLE_HEADER__
|
||||
|
||||
@@ -91,9 +91,10 @@ bool is83(const std::string & s) {
|
||||
}
|
||||
|
||||
/// Tests if the given string is a path supported by 3DS format (8.3, 63 chars max).
|
||||
bool is3DSpath(const std::string & s) {
|
||||
bool is3DSpath(const std::string & s, bool extendedFilePaths) {
|
||||
unsigned int len = s.length();
|
||||
if (len >= 64 || len == 0) return false;
|
||||
if (extendedFilePaths) return true; // Extended paths are simply those that fits the 64 bytes buffer!
|
||||
|
||||
unsigned int tokenBegin = 0;
|
||||
for (unsigned int tokenEnd=0; tokenEnd != std::string::npos; tokenBegin = tokenEnd+1) {
|
||||
@@ -145,7 +146,7 @@ public:
|
||||
triangle.t2 = i2;
|
||||
triangle.t3 = i3;
|
||||
triangle.material = _material;
|
||||
_listTriangles.push_back(std::make_pair(triangle, _drawable_n));
|
||||
_listTriangles.push_back(std::pair<Triangle, unsigned int>(triangle, _drawable_n));
|
||||
}
|
||||
virtual void begin(GLenum mode)
|
||||
{
|
||||
@@ -334,7 +335,7 @@ void PrimitiveIndexWriter::drawArrays(GLenum mode,GLint first,GLsizei count)
|
||||
case(GL_LINE_LOOP):
|
||||
//break;
|
||||
default:
|
||||
osg::notify(osg::WARN) << "WriterNodeVisitor :: can't handle mode " << mode << std::endl;
|
||||
osg::notify(osg::WARN) << "3DS WriterNodeVisitor: can't handle mode " << mode << std::endl;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -399,35 +400,54 @@ WriterNodeVisitor::Material::Material(WriterNodeVisitor & writerNodeVisitor, osg
|
||||
}
|
||||
|
||||
|
||||
std::string
|
||||
getPathRelative(const std::string & srcBad,
|
||||
const std::string & dstBad)
|
||||
// If 'to' is in a subdirectory of 'from' then this function returns the
|
||||
// subpath. Otherwise it just returns the file name.
|
||||
// (Same as in FBX plugin)
|
||||
std::string getPathRelative(const std::string& from/*directory*/,
|
||||
const std::string& to/*file path*/)
|
||||
{
|
||||
if(srcBad.empty())
|
||||
return osgDB::getSimpleFileName(dstBad);
|
||||
const std::string & src = osgDB::convertFileNameToNativeStyle(srcBad);
|
||||
const std::string & dst = osgDB::convertFileNameToNativeStyle(dstBad);
|
||||
std::string::const_iterator itDst = dst.begin();
|
||||
std::string::const_iterator itSrc = src.begin();
|
||||
|
||||
std::string result = "";
|
||||
|
||||
while(itDst != dst.end())
|
||||
std::string::size_type slash = to.find_last_of('/');
|
||||
std::string::size_type backslash = to.find_last_of('\\');
|
||||
if (slash == std::string::npos)
|
||||
{
|
||||
if (itSrc != src.end() && *itDst == *itSrc)
|
||||
++itSrc;
|
||||
else if (!result.empty() || *itDst != '\\')
|
||||
result += *itDst;
|
||||
++itDst;
|
||||
if (backslash == std::string::npos) return to;
|
||||
slash = backslash;
|
||||
}
|
||||
if (itSrc != src.end())
|
||||
result = osgDB::getSimpleFileName(dst);
|
||||
return result;
|
||||
else if (backslash != std::string::npos && backslash > slash)
|
||||
{
|
||||
slash = backslash;
|
||||
}
|
||||
|
||||
if (from.empty() || from.length() > to.length())
|
||||
return osgDB::getSimpleFileName(to);
|
||||
|
||||
std::string::const_iterator itTo = to.begin();
|
||||
for (std::string::const_iterator itFrom = from.begin();
|
||||
itFrom != from.end(); ++itFrom, ++itTo)
|
||||
{
|
||||
char a = tolower(*itFrom), b = tolower(*itTo);
|
||||
if (a == '\\') a = '/';
|
||||
if (b == '\\') b = '/';
|
||||
if (a != b || itTo == to.begin() + slash + 1)
|
||||
{
|
||||
return osgDB::getSimpleFileName(to);
|
||||
}
|
||||
}
|
||||
|
||||
while (itTo != to.end() && (*itTo == '\\' || *itTo == '/'))
|
||||
{
|
||||
++itTo;
|
||||
}
|
||||
|
||||
return std::string(itTo, to.end());
|
||||
}
|
||||
|
||||
/// Converts an extension to a 3-letters long one equivalent.
|
||||
std::string convertExt(const std::string & path)
|
||||
std::string convertExt(const std::string & path, bool extendedFilePaths)
|
||||
{
|
||||
if (extendedFilePaths) return path; // Extensions are not truncated for extended filenames
|
||||
|
||||
std::string ext = osgDB::getFileExtensionIncludingDot(path);
|
||||
if (ext == ".tiff") ext = ".tif";
|
||||
else if (ext == ".jpeg") ext = ".jpg";
|
||||
@@ -435,6 +455,37 @@ std::string convertExt(const std::string & path)
|
||||
return osgDB::getNameLessExtension(path) + ext;
|
||||
}
|
||||
|
||||
|
||||
WriterNodeVisitor::WriterNodeVisitor(Lib3dsFile * file3ds, const std::string & fileName,
|
||||
const osgDB::ReaderWriter::Options* options,
|
||||
const std::string & srcDirectory) :
|
||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
_suceedLastApply(true),
|
||||
_srcDirectory(srcDirectory),
|
||||
file3ds(file3ds),
|
||||
_currentStateSet(new osg::StateSet()),
|
||||
_lastMaterialIndex(0),
|
||||
_lastMeshIndex(0),
|
||||
_cur3dsNode(NULL),
|
||||
options(options),
|
||||
_imageCount(0),
|
||||
_extendedFilePaths(false)
|
||||
{
|
||||
if (!fileName.empty())
|
||||
_directory = options->getDatabasePathList().empty() ? osgDB::getFilePath(fileName) : options->getDatabasePathList().front();
|
||||
|
||||
if (options) {
|
||||
std::istringstream iss(options->getOptionString());
|
||||
std::string opt;
|
||||
while (iss >> opt)
|
||||
{
|
||||
if (opt == "extended3dsFilePaths" || opt == "extended3DSFilePaths")
|
||||
_extendedFilePaths = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void WriterNodeVisitor::writeMaterials()
|
||||
{
|
||||
unsigned int nbMat = _materialMap.size();
|
||||
@@ -470,9 +521,9 @@ void WriterNodeVisitor::writeMaterials()
|
||||
else {
|
||||
path = getPathRelative(_srcDirectory, mat.image->getFileName());
|
||||
}
|
||||
path = convertExt(path);
|
||||
path = convertExt(path, _extendedFilePaths);
|
||||
|
||||
if(!is3DSpath(path)) {
|
||||
if(!is3DSpath(path, _extendedFilePaths)) {
|
||||
path = getUniqueName(path, "", true);
|
||||
//path = osgDB::getSimpleFileName(path);
|
||||
}
|
||||
@@ -482,7 +533,11 @@ void WriterNodeVisitor::writeMaterials()
|
||||
osgDB::makeDirectoryForFile(path);
|
||||
|
||||
//if (mat.image->valid()) osgDB::writeImageFile(*(mat.image), path);
|
||||
osgDB::writeImageFile(*(mat.image), path);
|
||||
if(_imageSet.find(mat.image.get()) == _imageSet.end())
|
||||
{
|
||||
_imageSet.insert(mat.image.get());
|
||||
osgDB::writeImageFile(*(mat.image), path);
|
||||
}
|
||||
if (mat.texture_transparency) tex.flags |= LIB3DS_TEXTURE_ALPHA_SOURCE;
|
||||
if (mat.texture_no_tile) tex.flags |= LIB3DS_TEXTURE_NO_TILE;
|
||||
}
|
||||
@@ -497,26 +552,28 @@ void WriterNodeVisitor::writeMaterials()
|
||||
|
||||
|
||||
std::string WriterNodeVisitor::getUniqueName(const std::string& _defaultValue, const std::string & _defaultPrefix, bool nameIsPath) {
|
||||
if (_defaultPrefix.length()>=4) throw "Default prefix is too long"; // Arbitrarily defined to 3 chars. You can modify this, but you may have to change the code so that finding a number is okay, even when changing the default prefix length.
|
||||
static const unsigned int MAX_PREFIX_LEGNTH = 4;
|
||||
if (_defaultPrefix.length()>MAX_PREFIX_LEGNTH) throw "Default prefix is too long"; // Arbitrarily defined to 4 chars.
|
||||
|
||||
// Tests if default name is valid and unique
|
||||
bool defaultIs83 = is83(_defaultValue);
|
||||
bool defaultIsValid = nameIsPath ? is3DSpath(_defaultValue) : defaultIs83;
|
||||
bool defaultIsValid = nameIsPath ? is3DSpath(_defaultValue, _extendedFilePaths) : defaultIs83;
|
||||
if (defaultIsValid && _nameMap.find(_defaultValue) == _nameMap.end()) {
|
||||
_nameMap.insert(_defaultValue);
|
||||
return _defaultValue;
|
||||
}
|
||||
|
||||
// Handling of paths is not well done yet. Defaulting to something very simple.
|
||||
// We should actually ensure each component is 8 chars long, and final filename is 8.3, and total is <64 chars.
|
||||
// We should actually ensure each component is 8 chars long, and final filename is 8.3, and total is <64 chars, or simply ensure total length for extended 3DS paths.
|
||||
std::string defaultValue(nameIsPath ? osgDB::getSimpleFileName(_defaultValue) : _defaultValue);
|
||||
std::string ext(nameIsPath ? osgDB::getFileExtensionIncludingDot(_defaultValue).substr(0, std::min<unsigned int>(_defaultValue.size(), 4)) : ""); // 4 chars = dot + 3 chars
|
||||
if (ext == ".") ext = "";
|
||||
|
||||
std::string defaultPrefix(_defaultPrefix.empty() ? "_" : _defaultPrefix);
|
||||
|
||||
unsigned int max_val = 0;
|
||||
std::string truncDefaultValue = "";
|
||||
for (unsigned int i = 0; i < std::min<unsigned int>(defaultValue.size(), 4); ++i)
|
||||
for (unsigned int i = 0; i < std::min<unsigned int>(defaultValue.size(), MAX_PREFIX_LEGNTH); ++i)
|
||||
{
|
||||
if (defaultValue[i] == '.')
|
||||
{
|
||||
@@ -525,47 +582,53 @@ std::string WriterNodeVisitor::getUniqueName(const std::string& _defaultValue, c
|
||||
}
|
||||
}
|
||||
if (truncDefaultValue.empty())
|
||||
truncDefaultValue = defaultValue.substr(0, std::min<unsigned int>(defaultValue.size(), 4));
|
||||
truncDefaultValue = defaultValue.substr(0, std::min<unsigned int>(defaultValue.size(), MAX_PREFIX_LEGNTH));
|
||||
assert(truncDefaultValue.size() <= MAX_PREFIX_LEGNTH);
|
||||
std::map<std::string, unsigned int>::iterator pairPrefix;
|
||||
|
||||
// TODO - Handle the case of extended 3DS paths and allow more than 8 chars
|
||||
defaultIs83 = is83(truncDefaultValue);
|
||||
if (defaultIs83)
|
||||
{
|
||||
max_val = static_cast<unsigned int>(pow(10., 8. - truncDefaultValue.length() - 1)) -1; // defaultPrefix.length()-1 because we add an underscore ("_")
|
||||
max_val = static_cast<unsigned int>(pow(10., 8. - truncDefaultValue.length())) -1;
|
||||
pairPrefix = _mapPrefix.find(truncDefaultValue);
|
||||
}
|
||||
|
||||
if (defaultIs83 && (_mapPrefix.end() == pairPrefix || pairPrefix->second <= max_val))
|
||||
if (defaultIs83 && (pairPrefix == _mapPrefix.end() || pairPrefix->second <= max_val))
|
||||
{
|
||||
defaultPrefix = truncDefaultValue;
|
||||
}
|
||||
else
|
||||
{
|
||||
max_val = static_cast<unsigned int>(pow(10., 8. - defaultPrefix.length() - 1)) - 1; // defaultPrefix.length()-1 because we add an underscore ("_")
|
||||
max_val = static_cast<unsigned int>(pow(10., 8. - defaultPrefix.length())) -1;
|
||||
pairPrefix = _mapPrefix.find(defaultPrefix);
|
||||
}
|
||||
|
||||
unsigned int searchStart = 0;
|
||||
if (pairPrefix != _mapPrefix.end())
|
||||
if (pairPrefix != _mapPrefix.end()) {
|
||||
searchStart = pairPrefix->second;
|
||||
}
|
||||
|
||||
for(unsigned int i = searchStart; i <= max_val; ++i) {
|
||||
std::stringstream ss;
|
||||
ss << defaultPrefix << "_" << i;
|
||||
ss << defaultPrefix << i;
|
||||
const std::string & res = ss.str();
|
||||
if (_nameMap.find(res) == _nameMap.end()) {
|
||||
if (pairPrefix != _mapPrefix.end())
|
||||
{
|
||||
if (pairPrefix != _mapPrefix.end()) {
|
||||
pairPrefix->second = i + 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
_mapPrefix.insert(std::make_pair(defaultPrefix, i + 1));
|
||||
} else {
|
||||
_mapPrefix.insert(std::pair<std::string, unsigned int>(defaultPrefix, i + 1));
|
||||
}
|
||||
_nameMap.insert(res);
|
||||
return res + ext;
|
||||
}
|
||||
}
|
||||
if (defaultPrefix == "_") _lastGeneratedNumberedName = max_val;
|
||||
|
||||
// Failed finding a name
|
||||
// Try with a shorter prefix if possible
|
||||
if (defaultPrefix.length()>1) return getUniqueName(_defaultValue, defaultPrefix.substr(0, defaultPrefix.length()-1), nameIsPath);
|
||||
// Try with default prefix if not arleady done
|
||||
if (defaultPrefix != std::string("_")) return getUniqueName(_defaultValue, "_", nameIsPath);
|
||||
throw "No more names available! Is default prefix too long?";
|
||||
}
|
||||
|
||||
@@ -602,10 +665,10 @@ WriterNodeVisitor::getMeshIndexForGeometryIndex(MapIndices & index_vert,
|
||||
unsigned int index,
|
||||
unsigned int drawable_n)
|
||||
{
|
||||
MapIndices::iterator itIndex = index_vert.find(std::make_pair(index, drawable_n));
|
||||
MapIndices::iterator itIndex = index_vert.find(std::pair<unsigned int, unsigned int>(index, drawable_n));
|
||||
if (itIndex == index_vert.end()) {
|
||||
unsigned int indexMesh = index_vert.size();
|
||||
index_vert.insert(std::make_pair(std::make_pair(index, drawable_n), indexMesh));
|
||||
index_vert.insert(std::make_pair(std::pair<unsigned int, unsigned int>(index, drawable_n), indexMesh));
|
||||
return indexMesh;
|
||||
}
|
||||
return itIndex->second;
|
||||
@@ -692,7 +755,7 @@ WriterNodeVisitor::buildFaces(osg::Geode & geo,
|
||||
if (listTriangles.size() >= MAX_FACES-2 ||
|
||||
((nbVertices) >= MAX_VERTICES-2))
|
||||
{
|
||||
osg::notify(osg::ALWAYS) << "Sorting elements..." << std::endl;
|
||||
osg::notify(osg::INFO) << "Sorting elements..." << std::endl;
|
||||
WriterCompareTriangle cmp(geo, nbVertices);
|
||||
std::sort(listTriangles.begin(), listTriangles.end(), cmp);
|
||||
}
|
||||
|
||||
@@ -41,6 +41,7 @@
|
||||
|
||||
#include "lib3ds/lib3ds.h"
|
||||
#include "WriterCompareTriangle.h"
|
||||
#include <set>
|
||||
|
||||
void copyOsgMatrixToLib3dsMatrix(Lib3dsMatrix lib3ds_matrix, const osg::Matrix& osg_matrix);
|
||||
|
||||
@@ -49,30 +50,13 @@ typedef std::vector<std::pair<Triangle, int> > ListTriangle; //the int is the dr
|
||||
|
||||
class WriterNodeVisitor: public osg::NodeVisitor
|
||||
{
|
||||
|
||||
public:
|
||||
static const unsigned int MAX_VERTICES = 65000;
|
||||
static const unsigned int MAX_FACES = MAX_VERTICES;
|
||||
|
||||
WriterNodeVisitor(Lib3dsFile * file3ds, const std::string & fileName,
|
||||
const osgDB::ReaderWriter::Options* options,
|
||||
const std::string & srcDirectory) :
|
||||
osg::NodeVisitor(osg::NodeVisitor::TRAVERSE_ALL_CHILDREN),
|
||||
_suceedLastApply(true),
|
||||
_srcDirectory(srcDirectory),
|
||||
file3ds(file3ds),
|
||||
_currentStateSet(new osg::StateSet()),
|
||||
_lastGeneratedNumberedName(0),
|
||||
_lastMaterialIndex(0),
|
||||
_lastMeshIndex(0),
|
||||
_cur3dsNode(NULL),
|
||||
options(options),
|
||||
_imageCount(0)
|
||||
{
|
||||
//supportsOption("flipTexture", "flip texture upside-down");
|
||||
if (!fileName.empty())
|
||||
_directory = options->getDatabasePathList().empty() ? osgDB::getFilePath(fileName) : options->getDatabasePathList().front();
|
||||
}
|
||||
const std::string & srcDirectory);
|
||||
|
||||
bool suceedLastApply() const;
|
||||
void failedApply();
|
||||
@@ -215,15 +199,16 @@ class WriterNodeVisitor: public osg::NodeVisitor
|
||||
Lib3dsFile * file3ds;
|
||||
StateSetStack _stateSetStack;
|
||||
osg::ref_ptr<osg::StateSet> _currentStateSet;
|
||||
std::map<std::string, unsigned int> _mapPrefix;
|
||||
std::map<std::string, unsigned int> _mapPrefix; ///< List of next number to use in unique name generation, for each prefix
|
||||
std::set<std::string> _nameMap;
|
||||
MaterialMap _materialMap;
|
||||
unsigned int _lastGeneratedNumberedName;
|
||||
unsigned int _lastMaterialIndex;
|
||||
unsigned int _lastMeshIndex;
|
||||
Lib3dsMeshInstanceNode * _cur3dsNode;
|
||||
const osgDB::ReaderWriter::Options* options;
|
||||
unsigned int _imageCount;
|
||||
bool _extendedFilePaths;
|
||||
std::set<osg::Image *> _imageSet;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
Reference in New Issue
Block a user