From Sukender, "Added support for texcoords scale and offset (UV scaling and offset in Lib3DS Materials), for texture unit 0."

This commit is contained in:
Robert Osfield
2011-03-11 11:25:19 +00:00
parent a81b2341c6
commit 9da669cbd8
3 changed files with 204 additions and 126 deletions

View File

@@ -184,18 +184,29 @@ protected:
bool createFileObject(const osg::Node& node, Lib3dsFile * file3ds,const std::string& fileName, const osgDB::ReaderWriter::Options* options) const;
/// An OSG state set with the original 3DS material attached (used to get info such as UV scaling & offset)
struct StateSetInfo
{
StateSetInfo(osg::StateSet * stateset=NULL, Lib3dsMaterial * lib3dsmat=NULL) : stateset(stateset), lib3dsmat(lib3dsmat) {}
StateSetInfo(const StateSetInfo & v) : stateset(v.stateset), lib3dsmat(v.lib3dsmat) {}
StateSetInfo & operator=(const StateSetInfo & v) { stateset=v.stateset; lib3dsmat=v.lib3dsmat; return *this; }
osg::StateSet * stateset;
Lib3dsMaterial * lib3dsmat;
};
class ReaderObject
{
public:
ReaderObject(const osgDB::ReaderWriter::Options* options);
typedef std::vector<osg::StateSet*> StateSetMap;
typedef std::vector<StateSetInfo> StateSetMap;
typedef std::vector<int> FaceList;
typedef std::map<std::string,osg::StateSet*> GeoStateMap;
osg::Texture2D* createTexture(Lib3dsTextureMap *texture,const char* label,bool& transparancy);
osg::StateSet* createStateSet(Lib3dsMaterial *materials);
osg::Drawable* createDrawable(Lib3dsMesh *meshes,FaceList& faceList, const osg::Matrix * matrix);
StateSetInfo createStateSet(Lib3dsMaterial *materials);
osg::Drawable* createDrawable(Lib3dsMesh *meshes,FaceList& faceList, const osg::Matrix * matrix, StateSetInfo & ssi);
std::string _directory;
bool _useSmoothingGroups;
@@ -203,14 +214,14 @@ protected:
// MIKEC
osg::Node* processMesh(StateSetMap& drawStateMap,osg::Group* parent,Lib3dsMesh* mesh, const osg::Matrix * matrix);
osg::Node* processNode(StateSetMap drawStateMap,Lib3dsFile *f,Lib3dsNode *node);
osg::Node* processNode(StateSetMap& drawStateMap,Lib3dsFile *f,Lib3dsNode *node);
private:
const osgDB::ReaderWriter::Options* options;
bool noMatrixTransforms; ///< Should the plugin apply matrices into the mesh vertices ("old behaviour"), instead of restoring matrices ("new behaviour")?
bool checkForEspilonIdentityMatrices;
bool restoreMatrixTransformsNoMeshes;
typedef std::map<unsigned int,FaceList> SmoothingFaceMap;
void addDrawableFromFace(osg::Geode * geode, FaceList & faceList, Lib3dsMesh * mesh, const osg::Matrix * matrix, osg::StateSet * stateSet);
void addDrawableFromFace(osg::Geode * geode, FaceList & faceList, Lib3dsMesh * mesh, const osg::Matrix * matrix, StateSetInfo & ssi);
typedef std::map<std::string, osg::ref_ptr<osg::Texture2D> > TexturesMap; // Should be an unordered map (faster)
TexturesMap texturesMap;
@@ -368,7 +379,7 @@ void print(Lib3dsNode *node, int level)
void ReaderWriter3DS::ReaderObject::addDrawableFromFace(osg::Geode * geode, FaceList & faceList,
Lib3dsMesh * mesh,
const osg::Matrix * matrix,
osg::StateSet * stateSet)
StateSetInfo & ssi)
{
if (_useSmoothingGroups)
{
@@ -388,22 +399,22 @@ void ReaderWriter3DS::ReaderObject::addDrawableFromFace(osg::Geode * geode, Face
// to ensure the vertices on adjacent groups
// don't get shared.
FaceList& smoothFaceMap = sitr->second;
osg::ref_ptr<osg::Drawable> drawable = createDrawable(mesh,smoothFaceMap,matrix);
osg::ref_ptr<osg::Drawable> drawable = createDrawable(mesh,smoothFaceMap,matrix,ssi);
if (drawable.valid())
{
if (stateSet)
drawable->setStateSet(stateSet);
if (ssi.stateset)
drawable->setStateSet(ssi.stateset);
geode->addDrawable(drawable.get());
}
}
}
else // ignore smoothing groups.
{
osg::ref_ptr<osg::Drawable> drawable = createDrawable(mesh,faceList,matrix);
osg::ref_ptr<osg::Drawable> drawable = createDrawable(mesh,faceList,matrix,ssi);
if (drawable.valid())
{
if (stateSet)
drawable->setStateSet(stateSet);
if (ssi.stateset)
drawable->setStateSet(ssi.stateset);
geode->addDrawable(drawable.get());
}
}
@@ -443,7 +454,8 @@ osg::Node* ReaderWriter3DS::ReaderObject::processMesh(StateSetMap& drawStateMap,
geode->setName(mesh->name);
if (!defaultMaterialFaceList.empty())
{
addDrawableFromFace(geode, defaultMaterialFaceList, mesh, matrix, NULL);
StateSetInfo emptySSI;
addDrawableFromFace(geode, defaultMaterialFaceList, mesh, matrix, emptySSI);
}
for(unsigned int imat=0; imat<numMaterials; ++imat)
{
@@ -478,7 +490,7 @@ How to cope with pivot points in 3ds (short version)
Transform the node by the node matrix, which does the orientation about the pivot point, (and currently) transforms the object back by a translation to the PP.
*/
osg::Node* ReaderWriter3DS::ReaderObject::processNode(StateSetMap drawStateMap,Lib3dsFile *f,Lib3dsNode *node)
osg::Node* ReaderWriter3DS::ReaderObject::processNode(StateSetMap& drawStateMap,Lib3dsFile *f,Lib3dsNode *node)
{
// Get mesh
Lib3dsMeshInstanceNode * object = (node->type == LIB3DS_NODE_MESH_INSTANCE) ? reinterpret_cast<Lib3dsMeshInstanceNode *>(node) : NULL;
@@ -746,7 +758,7 @@ osgDB::ReaderWriter::ReadResult ReaderWriter3DS::constructFrom3dsFile(Lib3dsFile
ReaderObject::StateSetMap drawStateMap;
unsigned int numMaterials = f->nmaterials;
drawStateMap.insert(drawStateMap.begin(), numMaterials, NULL); // Setup the map
drawStateMap.insert(drawStateMap.begin(), numMaterials, StateSetInfo()); // Setup the map
for (unsigned int imat=0; imat<numMaterials; ++imat)
{
Lib3dsMaterial * mat = f->materials[imat];
@@ -821,7 +833,7 @@ osgDB::ReaderWriter::ReadResult ReaderWriter3DS::constructFrom3dsFile(Lib3dsFile
/**
use matrix to pretransform geometry, or NULL to do nothing
*/
osg::Drawable* ReaderWriter3DS::ReaderObject::createDrawable(Lib3dsMesh *m,FaceList& faceList, const osg::Matrix * matrix)
osg::Drawable* ReaderWriter3DS::ReaderObject::createDrawable(Lib3dsMesh *m,FaceList& faceList, const osg::Matrix * matrix, StateSetInfo & ssi)
{
osg::Geometry * geom = new osg::Geometry;
unsigned int i;
@@ -876,9 +888,24 @@ osg::Drawable* ReaderWriter3DS::ReaderObject::createDrawable(Lib3dsMesh *m,FaceL
{
osg::ref_ptr<osg::Vec2Array> osg_tcoords = new osg::Vec2Array(noVertex);
geom->setTexCoordArray(0, osg_tcoords.get());
// Texture 0 parameters (only one texture supported for now)
float scaleU(1.f), scaleV(1.f);
float offsetU(0.f), offsetV(0.f);
if (ssi.lib3dsmat && *(ssi.lib3dsmat->texture1_map.name)) // valid texture = name not empty
{
Lib3dsTextureMap & tex3ds = ssi.lib3dsmat->texture1_map;
scaleU = tex3ds.scale[0];
scaleV = tex3ds.scale[1];
offsetU = tex3ds.offset[0];
offsetV = tex3ds.offset[1];
if (tex3ds.rotation != 0) OSG_NOTICE << "3DS texture rotation not supported yet" << std::endl;
//TODO: tint_1, tint_2, tint_r, tint_g, tint_b
}
for (i=0; i<m->nvertices; ++i)
{
if (orig2NewMapping[i]>=0) (*osg_tcoords)[orig2NewMapping[i]].set(m->texcos[i][0],m->texcos[i][1]);
if (orig2NewMapping[i]>=0) (*osg_tcoords)[orig2NewMapping[i]].set(m->texcos[i][0]*scaleU + offsetU, m->texcos[i][1]*scaleV + offsetV);
}
}
@@ -1049,9 +1076,9 @@ osg::Texture2D* ReaderWriter3DS::ReaderObject::createTexture(Lib3dsTextureMap *
}
osg::StateSet* ReaderWriter3DS::ReaderObject::createStateSet(Lib3dsMaterial *mat)
ReaderWriter3DS::StateSetInfo ReaderWriter3DS::ReaderObject::createStateSet(Lib3dsMaterial *mat)
{
if (mat==NULL) return NULL;
if (mat==NULL) return StateSetInfo();
bool textureTransparency=false;
bool transparency = false;
@@ -1151,6 +1178,7 @@ osg::StateSet* ReaderWriter3DS::ReaderObject::createStateSet(Lib3dsMaterial *mat
if ((alpha < 1.0f) || transparency)
{
//stateset->setAttributeAndModes(new osg::BlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA));
stateset->setMode(GL_BLEND,osg::StateAttribute::ON);
stateset->setRenderingHint(osg::StateSet::TRANSPARENT_BIN);
}
@@ -1172,7 +1200,7 @@ osg::StateSet* ReaderWriter3DS::ReaderObject::createStateSet(Lib3dsMaterial *mat
osg::ref_ptr<osg::Texture> reflection_map = createTexture(&(mat->reflection_map),"reflection_map",textureTransparancy);
osg::ref_ptr<osg::Texture> reflection_mask = createTexture(&(mat->reflection_mask),"reflection_mask",textureTransparancy);
*/
return stateset;
return StateSetInfo(stateset, mat);
}

View File

@@ -82,13 +82,6 @@ inline void copyOsgQuatToLib3dsQuat(float lib3ds_vector[4], const osg::Quat& osg
lib3ds_vector[3] = static_cast<float>(-angle);
}
std::string getFileName(const std::string & path)
{
size_t slashPos = path.find_last_of("/\\");
if (slashPos == std::string::npos) return path;
return path.substr(slashPos+1);
}
/// Checks if a filename (\b not path) is 8.3 (an empty name is never 8.3, and a path is never 8.3).
/// Please note the '8' and '3' limitations are in \b bytes, not in characters (which is different when using UTF8).
@@ -107,23 +100,20 @@ bool is83(const std::string & s)
return true;
}
/// Tests if the given string is a path supported by 3DS format (8.3, 63 chars max).
bool is3DSpath(const std::string & s, bool extendedFilePaths)
inline std::string::size_type maxNameLen(bool extendedFilePaths, bool isNodeName) {
if (extendedFilePaths) return 63;
return isNodeName ? 8 : (8+1+3);
}
/// Tests if the given string is a path supported by 3DS format (8.3, 63 chars max, non empty).
inline bool is3DSName(const std::string & s, bool extendedFilePaths, bool isNodeName)
{
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!
// For each subdirectory
size_t tokenLen;
for (size_t tokenBegin=0, tokenEnd=0; tokenEnd != std::string::npos; tokenBegin = tokenEnd+1)
{
tokenEnd = s.find_first_of("/\\", tokenBegin);
if (tokenEnd != std::string::npos) tokenLen = tokenEnd-tokenBegin-1; // -1 to avoid reading the separator
else tokenLen = len-tokenBegin;
if ( tokenLen>0 && !is83(s.substr(tokenBegin, tokenLen)) ) return false;
}
return true;
if (len > maxNameLen(extendedFilePaths, isNodeName) || len == 0) return false;
// Extended paths are simply those that fits the 64 bytes buffer.
if (extendedFilePaths) return true;
// Short paths simply must have no subdirectory.
return is83(s);
}
@@ -397,7 +387,7 @@ WriterNodeVisitor::Material::Material(WriterNodeVisitor & writerNodeVisitor, osg
//shininess = mat->getShininess(osg::Material::FRONT) <= 0 ? 0 : log( mat->getShininess(osg::Material::FRONT) ) / log(2.f) / 10.f;
transparency = 1-diffuse.w();
name = writerNodeVisitor.getUniqueName(mat->getName(),"mat");
name = writerNodeVisitor.getUniqueName(mat->getName(),true,"mat");
osg::StateAttribute * attribute = stateset->getAttribute(osg::StateAttribute::CULLFACE);
if (!attribute)
{
@@ -501,7 +491,7 @@ void WriterNodeVisitor::writeMaterials()
found = true;
assert(mat.index>=0 && mat.index < static_cast<int>(_materialMap.size()));
Lib3dsMaterial * mat3ds = lib3ds_material_new(getFileName(mat.name).c_str());
Lib3dsMaterial * mat3ds = lib3ds_material_new(osgDB::getSimpleFileName(mat.name).c_str());
copyOsgColorToLib3dsColor(mat3ds->ambient, mat.ambient);
copyOsgColorToLib3dsColor(mat3ds->diffuse, mat.diffuse);
copyOsgColorToLib3dsColor(mat3ds->specular, mat.specular);
@@ -510,36 +500,40 @@ void WriterNodeVisitor::writeMaterials()
mat3ds->two_sided = mat.double_sided ? 1 : 0;
if (mat.image)
{
Lib3dsTextureMap & tex = mat3ds->texture1_map;
std::string path;
if(mat.image->getFileName().empty())
ImageSet::const_iterator itImage( _imageSet.find(mat.image.get()) );
if (itImage != _imageSet.end())
{
std::ostringstream oss;
oss << "Image_" << _imageCount++ << ".rgb";
path = oss.str();
// Image has been already used
path = itImage->second;
}
else
{
path = osgDB::getPathRelative(_srcDirectory, mat.image->getFileName());
}
path = convertExt(path, _extendedFilePaths);
// First time we 'see' this image
if (mat.image->getFileName().empty())
{
std::ostringstream oss;
oss << "Image_" << _imageCount++ << ".rgb";
path = oss.str();
}
else
{
path = osgDB::getPathRelative(_srcDirectory, mat.image->getFileName());
}
path = convertExt(path, _extendedFilePaths);
path = getUniqueName(path, false, "");
if(!is3DSpath(path, _extendedFilePaths))
{
path = getUniqueName(path, "", true);
//path = osgDB::getSimpleFileName(path);
// Write
const std::string fullPath( osgDB::concatPaths(_directory, path) );
osgDB::makeDirectoryForFile(fullPath);
osgDB::writeImageFile(*(mat.image), fullPath, _options);
// Insert in map
_imageSet.insert(ImageSet::value_type(mat.image.get(), path));
}
Lib3dsTextureMap & tex = mat3ds->texture1_map;
strcpy(tex.name, path.c_str());
path = osgDB::concatPaths(_directory, path);
osgDB::makeDirectoryForFile(path);
//if (mat.image->valid()) osgDB::writeImageFile(*(mat.image), path);
if(_imageSet.find(mat.image.get()) == _imageSet.end())
{
_imageSet.insert(mat.image.get());
osgDB::writeImageFile(*(mat.image), path, _options);
}
// Here we don't assume anything about initial flags state (actually it is set to LIB3DS_TEXTURE_NO_TILE by lib3DS, but this is subject to change)
if (mat.texture_transparency) tex.flags |= LIB3DS_TEXTURE_ALPHA_SOURCE;
else tex.flags &= ~LIB3DS_TEXTURE_ALPHA_SOURCE;
@@ -581,92 +575,143 @@ std::string utf8TruncateBytes(const std::string & s, std::string::size_type byte
# define truncateFilenameBytes(str, size) std::string(str, 0, size)
#endif
std::string WriterNodeVisitor::getUniqueName(const std::string& _defaultValue, const std::string & _defaultPrefix, bool nameIsPath)
std::string WriterNodeVisitor::getUniqueName(const std::string& _defaultValue, bool isNodeName, const std::string & _defaultPrefix, int currentPrefixLen)
{
static const unsigned int MAX_PREFIX_LEGNTH = 4; // Arbitrarily defined to 4 chars
assert(_defaultPrefix.length()<=MAX_PREFIX_LEGNTH); // Default prefix is too long (implementation error)
//const unsigned int MAX_LENGTH = maxNameLen(_extendedFilePaths);
const unsigned int MAX_PREFIX_LENGTH = _extendedFilePaths ? 52 : 6; // Arbitrarily defined for short names, kept enough room for displaying UINT_MAX (10 characters) for long names.
assert(_defaultPrefix.length()<=4); // Default prefix is too long (implementation error)
const std::string defaultPrefix(_defaultPrefix.empty() ? "_" : _defaultPrefix);
if (currentPrefixLen<0) currentPrefixLen = osg::maximum(_defaultPrefix.length(), _defaultValue.length());
currentPrefixLen = osg::clampBelow(currentPrefixLen, static_cast<int>(MAX_PREFIX_LENGTH));
// Tests if default name is valid and unique
bool defaultIs83 = is83(_defaultValue);
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, or simply ensure total length for extended 3DS paths.
std::string defaultValue(nameIsPath ? osgDB::getSimpleFileName(_defaultValue) : _defaultValue);
std::string ext(nameIsPath ? osgDB::getFileExtensionIncludingDot(_defaultValue) : "");
ext = truncateFilenameBytes(ext, std::min<unsigned int>(_defaultValue.size(), 4)); // 4 chars = dot + 3 chars
if (ext == ".") ext = "";
std::string defaultPrefix(_defaultPrefix.empty() ? "_" : _defaultPrefix);
NameMap & nameMap = isNodeName ? _nodeNameMap : _imageNameMap;
PrefixMap & prefixMap = isNodeName ? _nodePrefixMap : _imagePrefixMap;
// Handling of paths is simple. Algorithm:
// - For short names, subdirectories are simply forbidden. Use the simple file name.
// - Else, the whole (relative) path must simply be <64 chars.
// After this, begin enumeration.
std::string parentPath, filename, ext, namePrefix;
unsigned int max_val = 0;
std::string truncDefaultValue = "";
for (unsigned int i = 0; i < std::min<unsigned int>(defaultValue.size(), MAX_PREFIX_LEGNTH); ++i)
// TODO Move the two parts of this giant if/else into two separate functions for better readability.
if (_extendedFilePaths)
{
if (defaultValue[i] == '.')
// Tests if default name is valid and unique
if (is3DSName(_defaultValue, _extendedFilePaths, isNodeName))
{
truncDefaultValue = truncateFilenameBytes(defaultValue, i);
break;
std::pair<NameMap::iterator, bool> insertion( nameMap.insert(_defaultValue) );
if (insertion.second) return _defaultValue; // Return if element is newly inserted in the map (else there is a naming collision)
}
}
if (truncDefaultValue.empty())
truncDefaultValue = truncateFilenameBytes(defaultValue, 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;
pairPrefix = _mapPrefix.find(truncDefaultValue);
}
// Simply separate name and last extension
filename = osgDB::getNameLessExtension(osgDB::getSimpleFileName(_defaultValue));
if (!isNodeName)
{
ext = osgDB::getFileExtensionIncludingDot(_defaultValue);
if (ext == ".") ext = "";
}
if (defaultIs83 && (pairPrefix == _mapPrefix.end() || pairPrefix->second <= max_val))
{
defaultPrefix = truncDefaultValue;
// Compute parent path
// Pre-condition: paths are supposed to be relative.
// If full path is too long (>MAX_PREFIX_LENGTH), cut path to let enough space for simple file name.
// Do not cut in the middle of a name, but at path separators.
parentPath = osgDB::getFilePath(_defaultValue);
if (_defaultValue.length() >MAX_PREFIX_LENGTH) // Not parentPath but _defaultValue!
{
// Nodes names: keep last directories (used only for the root name, generally named after the full file path)
// Images names: keep first directories (for images)
if (isNodeName) std::reverse(parentPath.begin(), parentPath.end());
parentPath = truncateFilenameBytes(parentPath, MAX_PREFIX_LENGTH - (filename.length() + ext.length() + 1)); // +1 for the path separator
std::string::size_type separator = parentPath.find_last_of("/\\");
if (separator != std::string::npos) parentPath = parentPath.substr(0, separator);
if (isNodeName) std::reverse(parentPath.begin(), parentPath.end());
}
// Assert "MAX_PREFIX_LENGTH - parent path length - extension length -1" is >=0 and truncate name to this length to get our new prefix.
assert(parentPath.length() + ext.length() <= MAX_PREFIX_LENGTH);
const unsigned int len = MAX_PREFIX_LENGTH - (parentPath.length() + ext.length() +1);
namePrefix = truncateFilenameBytes(filename, len);
if (namePrefix.empty()) namePrefix = defaultPrefix;
// Truncate the filename to get our new prefix
namePrefix = truncateFilenameBytes(filename, currentPrefixLen);
// Enough space has been reserved for UINT_MAX values
max_val = UINT_MAX;
}
else
{
max_val = static_cast<unsigned int>(pow(10., 8. - defaultPrefix.length())) -1;
pairPrefix = _mapPrefix.find(defaultPrefix);
}
// Get last extension, and make filename have no extension
filename = osgDB::getNameLessAllExtensions(osgDB::getSimpleFileName(_defaultValue));
if (!isNodeName)
{
ext = truncateFilenameBytes(osgDB::getFileExtensionIncludingDot(_defaultValue), 4); // 4 chars = dot + 3 chars
if (ext == ".") ext = "";
}
unsigned int searchStart = 0;
if (pairPrefix != _mapPrefix.end())
// Tests if STRIPPED default name is valid and unique
const std::string strippedName( filename + ext );
if (is3DSName(strippedName, _extendedFilePaths, isNodeName))
{
std::pair<NameMap::iterator, bool> insertion( nameMap.insert(strippedName) );
if (insertion.second) return strippedName; // Return if element is newly inserted in the map (else there is a naming collision)
}
namePrefix = filename;
if (namePrefix.empty()) namePrefix = defaultPrefix;
// Truncate the filename to get our new prefix
namePrefix = truncateFilenameBytes(namePrefix, currentPrefixLen);
// Compute the maximum enumeration value
max_val = static_cast<unsigned int>(pow(10., 8. - namePrefix.length())) -1;
}
assert(namePrefix.size() <= MAX_PREFIX_LENGTH);
// Find the current enumeration value (searchStart)
unsigned int searchStart(0);
PrefixMap::iterator pairPrefix( prefixMap.find(namePrefix) );
if (pairPrefix != prefixMap.end())
{
searchStart = pairPrefix->second;
}
else
{
// Check if truncated name is ok
const std::string res( osgDB::concatPaths(parentPath, namePrefix + ext) );
if (nameMap.find(res) == nameMap.end()) {
prefixMap.insert(std::pair<std::string, unsigned int>(namePrefix, 0));
nameMap.insert(res);
return res;
}
}
// Search for a free value
for(unsigned int i = searchStart; i <= max_val; ++i)
{
std::stringstream ss;
ss << defaultPrefix << i;
const std::string & res = ss.str();
if (_nameMap.find(res) == _nameMap.end())
ss << namePrefix << i;
const std::string res( osgDB::concatPaths(parentPath, ss.str() + ext) );
if (nameMap.find(res) == nameMap.end())
{
if (pairPrefix != _mapPrefix.end())
if (pairPrefix != prefixMap.end())
{
pairPrefix->second = i + 1;
} else
{
_mapPrefix.insert(std::pair<std::string, unsigned int>(defaultPrefix, i + 1));
prefixMap.insert(std::pair<std::string, unsigned int>(namePrefix, i + 1));
}
_nameMap.insert(res);
return res + ext;
nameMap.insert(res);
return res;
}
}
// Failed finding a name
// Try with a shorter prefix if possible
if (defaultPrefix.length()>1) return getUniqueName(_defaultValue, truncateFilenameBytes(defaultPrefix, defaultPrefix.length()-1), nameIsPath);
if (currentPrefixLen>1) return getUniqueName(_defaultValue, isNodeName, defaultPrefix, currentPrefixLen-1);
// Try with default prefix if not arleady done
if (defaultPrefix != std::string("_")) return getUniqueName(_defaultValue, "_", nameIsPath);
if (defaultPrefix != std::string("_")) return getUniqueName(_defaultValue, isNodeName, "_", 1);
// No more names
OSG_NOTIFY(osg::FATAL) << "No more names available!" << std::endl;
@@ -809,7 +854,7 @@ WriterNodeVisitor::buildFaces(osg::Geode & geo,
unsigned int nbVerticesRemaining = calcVertices(geo); // May set _succeded to false
if (!succeeded()) return;
std::string name( getUniqueName(geo.getName().empty() ? geo.className() : geo.getName(), "geo") );
std::string name( getUniqueName(geo.getName().empty() ? geo.className() : geo.getName(), true, "geo") );
if (!succeeded()) return;
Lib3dsMesh *mesh = lib3ds_mesh_new( name.c_str() );
if (!mesh)
@@ -855,7 +900,7 @@ WriterNodeVisitor::buildFaces(osg::Geode & geo,
// We can't call a thing like "nbVerticesRemaining -= ...;" because points may be used multiple times.
// [Sukender: An optimisation here would take too much time I think.]
mesh = lib3ds_mesh_new( getUniqueName(geo.getName().empty() ? geo.className() : geo.getName(), "geo").c_str());
mesh = lib3ds_mesh_new( getUniqueName(geo.getName().empty() ? geo.className() : geo.getName(), true, "geo").c_str());
if (!mesh)
{
OSG_NOTIFY(osg::FATAL) << "Allocation error" << std::endl;
@@ -1043,11 +1088,11 @@ void WriterNodeVisitor::apply3DSMatrixNode(osg::Node &node, const osg::Matrix *
copyOsgVectorToLib3dsVector(pos, osgPos);
copyOsgVectorToLib3dsVector(scl, osgScl);
copyOsgQuatToLib3dsQuat(rot, osgRot);
node3ds = lib3ds_node_new_mesh_instance(NULL, getUniqueName(node.getName().empty() ? node.className() : node.getName(), prefix).c_str(), pos, scl, rot);
node3ds = lib3ds_node_new_mesh_instance(NULL, getUniqueName(node.getName().empty() ? node.className() : node.getName(), true, prefix).c_str(), pos, scl, rot);
}
else
{
node3ds = lib3ds_node_new_mesh_instance(NULL, getUniqueName(node.getName().empty() ? node.className() : node.getName(), prefix).c_str(), NULL, NULL, NULL);
node3ds = lib3ds_node_new_mesh_instance(NULL, getUniqueName(node.getName().empty() ? node.className() : node.getName(), true, prefix).c_str(), NULL, NULL, NULL);
}
lib3ds_file_append_node(_file3ds, reinterpret_cast<Lib3dsNode*>(node3ds), reinterpret_cast<Lib3dsNode*>(parent));

View File

@@ -190,7 +190,7 @@ class WriterNodeVisitor: public osg::NodeVisitor
int processStateSet(osg::StateSet* stateset);
std::string getUniqueName(const std::string& defaultvalue="", const std::string & defaultPrefix = "", bool nameIsPath = false);
std::string getUniqueName(const std::string& defaultvalue, bool isNodeName, const std::string & defaultPrefix = "", int currentPrefixLen = -1);
std::string export3DSTexture(const osg::Image * image, const std::string & fileName);
typedef std::stack<osg::ref_ptr<osg::StateSet> > StateSetStack;
@@ -204,8 +204,12 @@ class WriterNodeVisitor: public osg::NodeVisitor
Lib3dsFile * _file3ds;
StateSetStack _stateSetStack;
osg::ref_ptr<osg::StateSet> _currentStateSet;
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;
typedef std::map<std::string, unsigned int> PrefixMap;
PrefixMap _nodePrefixMap; ///< List of next number to use in unique name generation, for each prefix
PrefixMap _imagePrefixMap;
typedef std::set<std::string> NameMap;
NameMap _nodeNameMap;
NameMap _imageNameMap;
MaterialMap _materialMap;
unsigned int _lastMaterialIndex;
unsigned int _lastMeshIndex;
@@ -213,7 +217,8 @@ class WriterNodeVisitor: public osg::NodeVisitor
const osgDB::ReaderWriter::Options* _options;
unsigned int _imageCount;
bool _extendedFilePaths;
std::set<osg::Image *> _imageSet;
typedef std::map<osg::Image*, std::string> ImageSet;
ImageSet _imageSet; ///< Map used to avoid renaming and writing twice an image
};
// end namespace plugin3ds