Commit 8fbc2fb8 authored by cutealien's avatar cutealien

- Colladawriter does now reset correctly (calling writeMesh twice failed...

- Colladawriter does now reset correctly (calling writeMesh twice failed before and writeScene twice didn't write light-nodes second time)
- Add some callbacks that allow users to use custom-names on writing
(I'll probably add an example as well soon for how to use all that - the problem is that there don't seem to be 2 tools out there interpreting Collada the same way and so we have to be rather flexible on export. And yeah - our own import also still  has way to go...)

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@4268 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 7dc53232
...@@ -77,7 +77,6 @@ namespace scene ...@@ -77,7 +77,6 @@ namespace scene
}; };
//! Callback interface for properties which can be used to influence collada writing //! Callback interface for properties which can be used to influence collada writing
//! NOTE: Interface is still work in process and might change some more before 1.8 release
class IColladaMeshWriterProperties : public virtual IReferenceCounted class IColladaMeshWriterProperties : public virtual IReferenceCounted
{ {
public: public:
...@@ -131,13 +130,106 @@ namespace scene ...@@ -131,13 +130,106 @@ namespace scene
virtual IMesh* getMesh(irr::scene::ISceneNode * node) = 0; virtual IMesh* getMesh(irr::scene::ISceneNode * node) = 0;
}; };
//! Callback interface to use custom names on collada writing.
/** Many names and id's have to be unique in collada. By default
Irrlicht guarantees for example by using using pointer-values in the name.
This works for most tools, but occasionally you might need another naming scheme
to make it easier finding names again for further processing.
*/
class IColladaMeshWriterNames : public virtual IReferenceCounted
{
public:
IColladaMeshWriterNames() : MeshToNC(true), NodeToNC(true), NCNamePrefix(L"_NC_") {}
virtual ~IColladaMeshWriterNames () {}
//! Return a unique name for the given mesh
/** Note that names really must be unique here per mesh-pointer, so mostly it's a good idea to return
the nameForMesh from IColladaMeshWriter::getDefaultNameGenerator().
*/
virtual irr::core::stringw nameForMesh(const scene::IMesh* mesh) const = 0;
//! Return a unique name for the given node
/** Note that names really must be unique here per node-pointer, so mostly it's a good idea to return
the nameForNode from IColladaMeshWriter::getDefaultNameGenerator().
*/
virtual irr::core::stringw nameForNode(const scene::ISceneNode* node) const = 0;
//! Return a name for the material
/** There is one material created in the writer for each unique name. So you can use this to control
the number of materials which get written. For example Irrlicht does by default write one material for each
material instanced by a node. So if you know that in your application material instances per node are identical
between different nodes you can reduce the number of exported materials using that knowledge by using identical
names for such shared materials. */
virtual irr::core::stringw nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) const = 0;
//! Ensure meshnames follow the xs::NCName format (so this will change names!)
/** Names need to have a certain format in collada, like not starting with numbers,
and avoiding certain special characters.
*/
void SetConvertMeshNameToNC(bool doConvert)
{
MeshToNC = doConvert;
}
//! Check if meshnames are forced to follow the xs::NCName format
bool GetConvertMeshNameToNC() const
{
return MeshToNC;
}
//! Ensure nodenames follow the xs::NCName format (so this will change names!)
void SetConvertNodeNameToNC(bool doConvert)
{
NodeToNC = doConvert;
}
//! Check if nodenames are forced to follow the xs::NCName format
bool GetConvertNodeNameToNC() const
{
return NodeToNC;
}
//! Ensure materialnames follow the xs::NCName format (so this will change names!)
void SetConvertMaterialNameToNC(bool doConvert)
{
MaterialToNC = doConvert;
}
//! Check if materialnames are forced to follow the xs::NCName format
bool GetConvertMaterialNameToNC() const
{
return MaterialToNC;
}
//! When conversion to NCName's is enforced resulting names will have this prefix
void SetNCNamePrefix(const irr::core::stringw& prefix)
{
NCNamePrefix = prefix;
}
//! Get the NCName prefix
const irr::core::stringw& getNCNamePrefix() const
{
return NCNamePrefix;
}
protected:
bool MeshToNC;
bool NodeToNC;
bool MaterialToNC;
irr::core::stringw NCNamePrefix;
};
//! Interface for writing meshes //! Interface for writing meshes
class IColladaMeshWriter : public IMeshWriter class IColladaMeshWriter : public IMeshWriter
{ {
public: public:
IColladaMeshWriter() : Properties(0), DefaultProperties(0), WriteTextures(true), WriteDefaultScene(false), AmbientLight(0.f, 0.f, 0.f, 1.f) IColladaMeshWriter()
: Properties(0), DefaultProperties(0), NameGenerator(0), DefaultNameGenerator(0)
, WriteTextures(true), WriteDefaultScene(false), AmbientLight(0.f, 0.f, 0.f, 1.f)
{ {
} }
...@@ -148,6 +240,10 @@ namespace scene ...@@ -148,6 +240,10 @@ namespace scene
Properties->drop(); Properties->drop();
if ( DefaultProperties ) if ( DefaultProperties )
DefaultProperties->drop(); DefaultProperties->drop();
if ( NameGenerator )
NameGenerator->drop();
if ( DefaultNameGenerator )
DefaultNameGenerator->drop();
} }
//! writes a scene starting with the given node //! writes a scene starting with the given node
...@@ -209,7 +305,7 @@ namespace scene ...@@ -209,7 +305,7 @@ namespace scene
} }
//! Get properties which are currently used. //! Get properties which are currently used.
virtual IColladaMeshWriterProperties * getProperties() virtual IColladaMeshWriterProperties * getProperties() const
{ {
return Properties; return Properties;
} }
...@@ -221,8 +317,34 @@ namespace scene ...@@ -221,8 +317,34 @@ namespace scene
return DefaultProperties; return DefaultProperties;
} }
//! Install a generator to create custom names on export.
virtual void setNameGenerator(IColladaMeshWriterNames * nameGenerator)
{
if ( nameGenerator == NameGenerator )
return;
if ( nameGenerator )
nameGenerator->grab();
if ( NameGenerator )
NameGenerator->drop();
NameGenerator = nameGenerator;
}
//! Get currently used name generator
virtual IColladaMeshWriterNames * getNameGenerator() const
{
return NameGenerator;
}
//! Return the original default name generator of the writer.
/** You can use this pointer in your own generator to access and return default values. */
IColladaMeshWriterNames * getDefaultNameGenerator() const
{
return DefaultNameGenerator;
}
protected: protected:
// NOTE: you should also call setProperties // NOTE: You usually should also call setProperties with the same paraemter when using setDefaultProperties
virtual void setDefaultProperties(IColladaMeshWriterProperties * p) virtual void setDefaultProperties(IColladaMeshWriterProperties * p)
{ {
if ( p == DefaultProperties ) if ( p == DefaultProperties )
...@@ -234,9 +356,23 @@ namespace scene ...@@ -234,9 +356,23 @@ namespace scene
DefaultProperties = p; DefaultProperties = p;
} }
// NOTE: You usually should also call setNameGenerator with the same paraemter when using setDefaultProperties
virtual void setDefaultNameGenerator(IColladaMeshWriterNames * p)
{
if ( p == DefaultNameGenerator )
return;
if ( p )
p->grab();
if ( DefaultNameGenerator )
DefaultNameGenerator->drop();
DefaultNameGenerator = p;
}
private: private:
IColladaMeshWriterProperties * Properties; IColladaMeshWriterProperties * Properties;
IColladaMeshWriterProperties * DefaultProperties; IColladaMeshWriterProperties * DefaultProperties;
IColladaMeshWriterNames * NameGenerator;
IColladaMeshWriterNames * DefaultNameGenerator;
bool WriteTextures; bool WriteTextures;
bool WriteDefaultScene; bool WriteDefaultScene;
video::SColorf AmbientLight; video::SColorf AmbientLight;
......
...@@ -122,6 +122,7 @@ IMesh* CColladaMeshWriterProperties::getMesh(irr::scene::ISceneNode * node) ...@@ -122,6 +122,7 @@ IMesh* CColladaMeshWriterProperties::getMesh(irr::scene::ISceneNode * node)
return 0; return 0;
if ( node->getType() == ESNT_ANIMATED_MESH ) if ( node->getType() == ESNT_ANIMATED_MESH )
return static_cast<IAnimatedMeshSceneNode*>(node)->getMesh()->getMesh(0); return static_cast<IAnimatedMeshSceneNode*>(node)->getMesh()->getMesh(0);
// TODO: we need some ISceneNode::hasType() function to get rid of those checks
if ( node->getType() == ESNT_MESH if ( node->getType() == ESNT_MESH
|| node->getType() == ESNT_CUBE || node->getType() == ESNT_CUBE
|| node->getType() == ESNT_SPHERE || node->getType() == ESNT_SPHERE
...@@ -134,6 +135,65 @@ IMesh* CColladaMeshWriterProperties::getMesh(irr::scene::ISceneNode * node) ...@@ -134,6 +135,65 @@ IMesh* CColladaMeshWriterProperties::getMesh(irr::scene::ISceneNode * node)
return 0; return 0;
} }
CColladaMeshWriterNames::CColladaMeshWriterNames()
{
SetConvertMeshNameToNC(true);
SetConvertNodeNameToNC(true);
SetConvertMaterialNameToNC(true);
}
irr::core::stringw CColladaMeshWriterNames::nameForMesh(const scene::IMesh* mesh) const
{
irr::core::stringw name(L"mesh");
name += nameForPtr(mesh);
return name;
}
irr::core::stringw CColladaMeshWriterNames::nameForNode(const scene::ISceneNode* node) const
{
irr::core::stringw name;
// Prefix, because xs::ID can't start with a number, also nicer name
if ( node && node->getType() == ESNT_LIGHT )
name = L"light";
else
name = L"node";
name += nameForPtr(node);
if ( node )
{
name += irr::core::stringw(node->getName());
}
return name;
}
irr::core::stringw CColladaMeshWriterNames::nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) const
{
core::stringw strMat(L"mat");
bool useMeshMaterial = !node ||
( (node->getType() == ESNT_MESH || // TODO: we need some ISceneNode::hasType() function to get rid of those checks
node->getType() == ESNT_CUBE ||
node->getType() == ESNT_SPHERE ||
node->getType() == ESNT_WATER_SURFACE ||
node->getType() == ESNT_Q3SHADER_SCENE_NODE)
&& static_cast<const IMeshSceneNode*>(node)->isReadOnlyMaterials())
|| (node->getType() == ESNT_ANIMATED_MESH && static_cast<const IAnimatedMeshSceneNode*>(node)->isReadOnlyMaterials() );
if ( !useMeshMaterial )
{
strMat += nameForNode(node);
}
strMat += nameForMesh(mesh);
strMat += materialId;
return strMat;
}
irr::core::stringw CColladaMeshWriterNames::nameForPtr(const void* ptr) const
{
wchar_t buf[32];
swprintf(buf, 32, L"%p", ptr);
return irr::core::stringw(buf);
}
CColladaMeshWriter::CColladaMeshWriter( ISceneManager * smgr, video::IVideoDriver* driver, CColladaMeshWriter::CColladaMeshWriter( ISceneManager * smgr, video::IVideoDriver* driver,
...@@ -158,6 +218,11 @@ CColladaMeshWriter::CColladaMeshWriter( ISceneManager * smgr, video::IVideoDrive ...@@ -158,6 +218,11 @@ CColladaMeshWriter::CColladaMeshWriter( ISceneManager * smgr, video::IVideoDrive
setDefaultProperties(p); setDefaultProperties(p);
setProperties(p); setProperties(p);
p->drop(); p->drop();
CColladaMeshWriterNames * nameGenerator = new CColladaMeshWriterNames();
setDefaultNameGenerator(nameGenerator);
setNameGenerator(nameGenerator);
nameGenerator->drop();
} }
...@@ -171,6 +236,15 @@ CColladaMeshWriter::~CColladaMeshWriter() ...@@ -171,6 +236,15 @@ CColladaMeshWriter::~CColladaMeshWriter()
} }
void CColladaMeshWriter::reset()
{
LibraryImages.clear();
Meshes.clear();
LightNodes.clear();
MaterialsWritten.clear();
EffectsWritten.clear();
}
//! Returns the type of the mesh writer //! Returns the type of the mesh writer
EMESH_WRITER_TYPE CColladaMeshWriter::getType() const EMESH_WRITER_TYPE CColladaMeshWriter::getType() const
{ {
...@@ -183,6 +257,8 @@ bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* roo ...@@ -183,6 +257,8 @@ bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* roo
if (!file || !root) if (!file || !root)
return false; return false;
reset();
Writer = FileSystem->createXMLWriter(file); Writer = FileSystem->createXMLWriter(file);
if (!Writer) if (!Writer)
...@@ -194,7 +270,6 @@ bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* roo ...@@ -194,7 +270,6 @@ bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* roo
Directory = FileSystem->getFileDir(FileSystem->getAbsolutePath( file->getFileName() )); Directory = FileSystem->getFileDir(FileSystem->getAbsolutePath( file->getFileName() ));
// make names for all nodes with exportable meshes // make names for all nodes with exportable meshes
Meshes.clear();
makeMeshNames(root); makeMeshNames(root);
os::Printer::log("Writing scene", file->getFileName()); os::Printer::log("Writing scene", file->getFileName());
...@@ -218,7 +293,6 @@ bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* roo ...@@ -218,7 +293,6 @@ bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* roo
Writer->writeClosingTag(L"library_materials"); Writer->writeClosingTag(L"library_materials");
Writer->writeLineBreak(); Writer->writeLineBreak();
LibraryImages.clear();
Writer->writeElement(L"library_effects", false); Writer->writeElement(L"library_effects", false);
Writer->writeLineBreak(); Writer->writeLineBreak();
writeNodeEffects(root); writeNodeEffects(root);
...@@ -310,7 +384,7 @@ bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* roo ...@@ -310,7 +384,7 @@ bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* roo
void CColladaMeshWriter::makeMeshNames(irr::scene::ISceneNode * node) void CColladaMeshWriter::makeMeshNames(irr::scene::ISceneNode * node)
{ {
if ( !node || !getProperties() || !getProperties()->isExportable(node) ) if ( !node || !getProperties() || !getProperties()->isExportable(node) || !getNameGenerator())
return; return;
IMesh* mesh = getProperties()->getMesh(node); IMesh* mesh = getProperties()->getMesh(node);
...@@ -344,22 +418,19 @@ void CColladaMeshWriter::writeNodeMaterials(irr::scene::ISceneNode * node) ...@@ -344,22 +418,19 @@ void CColladaMeshWriter::writeNodeMaterials(irr::scene::ISceneNode * node)
{ {
// no material overrides - write mesh materials // no material overrides - write mesh materials
MeshNode * n = Meshes.find(mesh); MeshNode * n = Meshes.find(mesh);
if ( n && !n->getValue().MaterialWritten ) if ( n && !n->getValue().MaterialsWritten )
{ {
writeMeshMaterials(n->getValue().Name, mesh); writeMeshMaterials(mesh);
n->getValue().MaterialWritten = true; n->getValue().MaterialsWritten = true;
} }
} }
else else
{ {
// write node materials // write node materials
irr::core::stringw nodename(nameForNode(node));
for (u32 i=0; i<node->getMaterialCount(); ++i) for (u32 i=0; i<node->getMaterialCount(); ++i)
{ {
core::stringw strMat = "mat"; video::SMaterial & material = node->getMaterial(i);
strMat += nodename; core::stringw strMat(nameForMaterial(material, i, mesh, node));
strMat += i;
writeMaterial(strMat); writeMaterial(strMat);
} }
} }
...@@ -374,6 +445,10 @@ void CColladaMeshWriter::writeNodeMaterials(irr::scene::ISceneNode * node) ...@@ -374,6 +445,10 @@ void CColladaMeshWriter::writeNodeMaterials(irr::scene::ISceneNode * node)
void CColladaMeshWriter::writeMaterial(const irr::core::stringw& materialname) void CColladaMeshWriter::writeMaterial(const irr::core::stringw& materialname)
{ {
if ( MaterialsWritten.find(materialname) )
return;
MaterialsWritten.insert(materialname, true);
Writer->writeElement(L"material", false, Writer->writeElement(L"material", false,
L"id", materialname.c_str(), L"id", materialname.c_str(),
L"name", materialname.c_str()); L"name", materialname.c_str());
...@@ -393,7 +468,7 @@ void CColladaMeshWriter::writeMaterial(const irr::core::stringw& materialname) ...@@ -393,7 +468,7 @@ void CColladaMeshWriter::writeMaterial(const irr::core::stringw& materialname)
void CColladaMeshWriter::writeNodeEffects(irr::scene::ISceneNode * node) void CColladaMeshWriter::writeNodeEffects(irr::scene::ISceneNode * node)
{ {
if ( !node || !getProperties() || !getProperties()->isExportable(node) ) if ( !node || !getProperties() || !getProperties()->isExportable(node) || !getNameGenerator() )
return; return;
IMesh* mesh = getProperties()->getMesh(node); IMesh* mesh = getProperties()->getMesh(node);
...@@ -404,11 +479,10 @@ void CColladaMeshWriter::writeNodeEffects(irr::scene::ISceneNode * node) ...@@ -404,11 +479,10 @@ void CColladaMeshWriter::writeNodeEffects(irr::scene::ISceneNode * node)
{ {
// no material overrides - write mesh materials // no material overrides - write mesh materials
MeshNode * n = Meshes.find(mesh); MeshNode * n = Meshes.find(mesh);
if ( n && !n->getValue().EffectWritten ) if ( n && !n->getValue().EffectsWritten )
{ {
irr::core::stringw meshname(n->getValue().Name); writeMeshEffects(mesh);
writeMeshEffects(meshname, mesh); n->getValue().EffectsWritten = true;
n->getValue().EffectWritten = true;
} }
} }
else else
...@@ -418,13 +492,10 @@ void CColladaMeshWriter::writeNodeEffects(irr::scene::ISceneNode * node) ...@@ -418,13 +492,10 @@ void CColladaMeshWriter::writeNodeEffects(irr::scene::ISceneNode * node)
// write node materials // write node materials
for (u32 i=0; i<node->getMaterialCount(); ++i) for (u32 i=0; i<node->getMaterialCount(); ++i)
{ {
core::stringw strMat = "mat";
strMat += nodename;
strMat += i;
strMat += L"-fx";
video::SMaterial & material = node->getMaterial(i); video::SMaterial & material = node->getMaterial(i);
writeMaterialEffect(meshname, strMat, material); irr::core::stringw materialname(nameForMaterial(material, i, mesh, node));
materialname += L"-fx";
writeMaterialEffect(meshname, materialname, material);
} }
} }
} }
...@@ -447,7 +518,7 @@ void CColladaMeshWriter::writeNodeLights(irr::scene::ISceneNode * node) ...@@ -447,7 +518,7 @@ void CColladaMeshWriter::writeNodeLights(irr::scene::ISceneNode * node)
const video::SLight& lightData = lightNode->getLightData(); const video::SLight& lightData = lightNode->getLightData();
ColladaLight cLight; ColladaLight cLight;
cLight.Name = nameForLightNode(node); cLight.Name = nameForNode(node);
LightNodes.insert(node, cLight); LightNodes.insert(node, cLight);
Writer->writeElement(L"light", false, L"id", cLight.Name.c_str()); Writer->writeElement(L"light", false, L"id", cLight.Name.c_str());
...@@ -609,6 +680,8 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 ...@@ -609,6 +680,8 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
if (!file) if (!file)
return false; return false;
reset();
Writer = FileSystem->createXMLWriter(file); Writer = FileSystem->createXMLWriter(file);
if (!Writer) if (!Writer)
...@@ -638,17 +711,15 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 ...@@ -638,17 +711,15 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
Writer->writeElement(L"library_materials", false); Writer->writeElement(L"library_materials", false);
Writer->writeLineBreak(); Writer->writeLineBreak();
irr::core::stringw meshname(nameForMesh(mesh)); writeMeshMaterials(mesh);
writeMeshMaterials(meshname, mesh);
Writer->writeClosingTag(L"library_materials"); Writer->writeClosingTag(L"library_materials");
Writer->writeLineBreak(); Writer->writeLineBreak();
LibraryImages.clear();
Writer->writeElement(L"library_effects", false); Writer->writeElement(L"library_effects", false);
Writer->writeLineBreak(); Writer->writeLineBreak();
writeMeshEffects(meshname, mesh); writeMeshEffects(mesh);
Writer->writeClosingTag(L"library_effects"); Writer->writeClosingTag(L"library_effects");
Writer->writeLineBreak(); Writer->writeLineBreak();
...@@ -661,6 +732,7 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 ...@@ -661,6 +732,7 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
Writer->writeElement(L"library_geometries", false); Writer->writeElement(L"library_geometries", false);
Writer->writeLineBreak(); Writer->writeLineBreak();
irr::core::stringw meshname(nameForMesh(mesh));
writeMeshGeometry(meshname, mesh); writeMeshGeometry(meshname, mesh);
Writer->writeClosingTag(L"library_geometries"); Writer->writeClosingTag(L"library_geometries");
...@@ -712,17 +784,6 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 ...@@ -712,17 +784,6 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
void CColladaMeshWriter::writeMeshInstanceGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh, scene::ISceneNode* node) void CColladaMeshWriter::writeMeshInstanceGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh, scene::ISceneNode* node)
{ {
core::stringw materialOwner;
if ( !node || ( node->getType() == ESNT_MESH )
&& static_cast<IMeshSceneNode*>(node)->isReadOnlyMaterials() )
{
materialOwner = meshname;
}
else
{
materialOwner = nameForNode(node);
}
//<instance_geometry url="#mesh"> //<instance_geometry url="#mesh">
core::stringw meshId(meshname); core::stringw meshId(meshname);
Writer->writeElement(L"instance_geometry", false, L"url", toRef(meshId).c_str()); Writer->writeElement(L"instance_geometry", false, L"url", toRef(meshId).c_str());
...@@ -736,14 +797,13 @@ void CColladaMeshWriter::writeMeshInstanceGeometry(const irr::core::stringw& mes ...@@ -736,14 +797,13 @@ void CColladaMeshWriter::writeMeshInstanceGeometry(const irr::core::stringw& mes
// instance materials // instance materials
// <instance_material symbol="leaf" target="#MidsummerLeaf01"/> // <instance_material symbol="leaf" target="#MidsummerLeaf01"/>
bool useNodeMaterials = node && node->getMaterialCount() == mesh->getMeshBufferCount();
for (u32 i=0; i<mesh->getMeshBufferCount(); ++i) for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
{ {
core::stringw strMatSymbol = "mat"; irr::core::stringw strMatSymbol(nameForMaterialSymbol(mesh, i));
strMatSymbol += meshname; core::stringw strMatTarget = "#";
strMatSymbol += i; video::SMaterial & material = useNodeMaterials ? node->getMaterial(i) : mesh->getMeshBuffer(i)->getMaterial();
core::stringw strMatTarget = "#mat"; strMatTarget += nameForMaterial(material, i, mesh, node);
strMatTarget += materialOwner;
strMatTarget += i;
Writer->writeElement(L"instance_material", false, L"symbol", strMatSymbol.c_str(), L"target", strMatTarget.c_str()); Writer->writeElement(L"instance_material", false, L"symbol", strMatSymbol.c_str(), L"target", strMatTarget.c_str());
Writer->writeLineBreak(); Writer->writeLineBreak();
...@@ -863,34 +923,48 @@ irr::core::stringw CColladaMeshWriter::toRef(const irr::core::stringw& source) c ...@@ -863,34 +923,48 @@ irr::core::stringw CColladaMeshWriter::toRef(const irr::core::stringw& source) c
irr::core::stringw CColladaMeshWriter::nameForMesh(const scene::IMesh* mesh) const irr::core::stringw CColladaMeshWriter::nameForMesh(const scene::IMesh* mesh) const
{ {
irr::core::stringw name(L"mesh"); IColladaMeshWriterNames * nameGenerator = getNameGenerator();
name += nameForPtr(mesh); if ( nameGenerator )
return name; {
if ( nameGenerator->GetConvertMeshNameToNC() )
return toNCName(nameGenerator->nameForMesh(mesh), nameGenerator->getNCNamePrefix());
else
return nameGenerator->nameForMesh(mesh);
}
return irr::core::stringw(L"missing_name_generator");
} }
irr::core::stringw CColladaMeshWriter::nameForLightNode(const scene::ISceneNode* lightNode) const irr::core::stringw CColladaMeshWriter::nameForNode(const scene::ISceneNode* node) const
{ {
irr::core::stringw name(L"light"); // (prefix, because xs::ID can't start with a number) IColladaMeshWriterNames * nameGenerator = getNameGenerator();
name += nameForPtr(lightNode); if ( nameGenerator )
return name; {
if ( nameGenerator->GetConvertNodeNameToNC() )
return toNCName(nameGenerator->nameForNode(node), nameGenerator->getNCNamePrefix());
else
return nameGenerator->nameForNode(node);
}
return irr::core::stringw(L"missing_name_generator");
} }
irr::core::stringw CColladaMeshWriter::nameForNode(const scene::ISceneNode* node) const irr::core::stringw CColladaMeshWriter::nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) const
{ {
irr::core::stringw name(L"node"); // (prefix, because xs::ID can't start with a number) IColladaMeshWriterNames * nameGenerator = getNameGenerator();
name += nameForPtr(node); if ( nameGenerator )
if ( node )
{ {
name += irr::core::stringw(node->getName()); if ( nameGenerator->GetConvertMaterialNameToNC() )
name = toNCName(name); return toNCName(nameGenerator->nameForMaterial(material, materialId, mesh, node), nameGenerator->getNCNamePrefix());
else
return nameGenerator->nameForMaterial(material, materialId, mesh, node);
} }
return name; return irr::core::stringw(L"missing_name_generator");
} }
irr::core::stringw CColladaMeshWriter::nameForPtr(const void* ptr) const // Each mesh-material has one symbol which is replaced on instantiation
irr::core::stringw CColladaMeshWriter::nameForMaterialSymbol(const scene::IMesh* mesh, int materialId) const
{ {
wchar_t buf[32]; wchar_t buf[100];
swprintf(buf, 32, L"%p", ptr); swprintf(buf, 100, L"mat_symb_%p_%d", mesh, materialId);
return irr::core::stringw(buf); return irr::core::stringw(buf);
} }
...@@ -1025,21 +1099,23 @@ void CColladaMeshWriter::writeAsset() ...@@ -1025,21 +1099,23 @@ void CColladaMeshWriter::writeAsset()
Writer->writeLineBreak(); Writer->writeLineBreak();
} }
void CColladaMeshWriter::writeMeshMaterials(const irr::core::stringw& meshname, scene::IMesh* mesh) void CColladaMeshWriter::writeMeshMaterials(scene::IMesh* mesh)
{ {
u32 i; u32 i;
for (i=0; i<mesh->getMeshBufferCount(); ++i) for (i=0; i<mesh->getMeshBufferCount(); ++i)
{ {
core::stringw strMat = "mat"; video::SMaterial & material = mesh->getMeshBuffer(i)->getMaterial();
strMat += meshname; core::stringw strMat(nameForMaterial(material, i, mesh, NULL));
strMat += i;
writeMaterial(strMat); writeMaterial(strMat);
} }
} }
void CColladaMeshWriter::writeMaterialEffect(const irr::core::stringw& meshname, const irr::core::stringw& materialname, const video::SMaterial & material) void CColladaMeshWriter::writeMaterialEffect(const irr::core::stringw& meshname, const irr::core::stringw& materialname, const video::SMaterial & material)
{ {
if ( EffectsWritten.find(materialname) )
return;
EffectsWritten.insert(materialname, true);
Writer->writeElement(L"effect", false, Writer->writeElement(L"effect", false,
L"id", materialname.c_str(), L"id", materialname.c_str(),
L"name", materialname.c_str()); L"name", materialname.c_str());
...@@ -1168,17 +1244,15 @@ void CColladaMeshWriter::writeMaterialEffect(const irr::core::stringw& meshname, ...@@ -1168,17 +1244,15 @@ void CColladaMeshWriter::writeMaterialEffect(const irr::core::stringw& meshname,
Writer->writeLineBreak(); Writer->writeLineBreak();
} }
void CColladaMeshWriter::writeMeshEffects(const irr::core::stringw& meshname, scene::IMesh* mesh) void CColladaMeshWriter::writeMeshEffects(scene::IMesh* mesh)
{ {
const irr::core::stringw meshname(nameForMesh(mesh));
for (u32 i=0; i<mesh->getMeshBufferCount(); ++i) for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
{ {
core::stringw strMat = "mat";
strMat += meshname;
strMat += i;
strMat += L"-fx";
video::SMaterial & material = mesh->getMeshBuffer(i)->getMaterial(); video::SMaterial & material = mesh->getMeshBuffer(i)->getMaterial();
writeMaterialEffect(meshname, strMat, material); irr::core::stringw materialname(nameForMaterial(material, i, mesh, NULL));
materialname += L"-fx";
writeMaterialEffect(meshname, materialname, material);
} }
} }
...@@ -1580,9 +1654,7 @@ void CColladaMeshWriter::writeMeshGeometry(const irr::core::stringw& meshname, s ...@@ -1580,9 +1654,7 @@ void CColladaMeshWriter::writeMeshGeometry(const irr::core::stringw& meshname, s
const u32 polyCount = buffer->getIndexCount() / 3; const u32 polyCount = buffer->getIndexCount() / 3;
core::stringw strPolyCount(polyCount); core::stringw strPolyCount(polyCount);
core::stringw strMat = "mat"; irr::core::stringw strMat(nameForMaterialSymbol(mesh, i));
strMat += meshname;
strMat += i;
Writer->writeElement(L"triangles", false, L"count", strPolyCount.c_str(), Writer->writeElement(L"triangles", false, L"count", strPolyCount.c_str(),
L"material", strMat.c_str()); L"material", strMat.c_str());
......
...@@ -56,6 +56,18 @@ namespace scene ...@@ -56,6 +56,18 @@ namespace scene
virtual irr::scene::IMesh* getMesh(irr::scene::ISceneNode * node); virtual irr::scene::IMesh* getMesh(irr::scene::ISceneNode * node);
}; };
class CColladaMeshWriterNames : public virtual IColladaMeshWriterNames
{
public:
CColladaMeshWriterNames();
virtual irr::core::stringw nameForMesh(const scene::IMesh* mesh) const;
virtual irr::core::stringw nameForNode(const scene::ISceneNode* node) const;
virtual irr::core::stringw nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) const;
protected:
irr::core::stringw nameForPtr(const void* ptr) const;
};
//! class to write meshes, implementing a COLLADA (.dae, .xml) writer //! class to write meshes, implementing a COLLADA (.dae, .xml) writer
/** This writer implementation has been originally developed for irrEdit and then /** This writer implementation has been originally developed for irrEdit and then
...@@ -79,6 +91,7 @@ public: ...@@ -79,6 +91,7 @@ public:
protected: protected:
void reset();
bool hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) const; bool hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) const;
void writeUv(const irr::core::vector2df& vec); void writeUv(const irr::core::vector2df& vec);
void writeVector(const irr::core::vector2df& vec); void writeVector(const irr::core::vector2df& vec);
...@@ -89,8 +102,9 @@ protected: ...@@ -89,8 +102,9 @@ protected:
inline irr::core::stringw toString(const irr::scene::E_COLLADA_TRANSPARENT_FX opaque) const; inline irr::core::stringw toString(const irr::scene::E_COLLADA_TRANSPARENT_FX opaque) const;
inline irr::core::stringw toRef(const irr::core::stringw& source) const; inline irr::core::stringw toRef(const irr::core::stringw& source) const;
irr::core::stringw nameForMesh(const scene::IMesh* mesh) const; irr::core::stringw nameForMesh(const scene::IMesh* mesh) const;
irr::core::stringw nameForLightNode(const scene::ISceneNode* lightNode) const;
irr::core::stringw nameForNode(const scene::ISceneNode* node) const; irr::core::stringw nameForNode(const scene::ISceneNode* node) const;
irr::core::stringw nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) const;
irr::core::stringw nameForMaterialSymbol(const scene::IMesh* mesh, int materialId) const;
irr::core::stringw nameForPtr(const void* ptr) const; irr::core::stringw nameForPtr(const void* ptr) const;
irr::core::stringw minTexfilterToString(bool bilinear, bool trilinear) const; irr::core::stringw minTexfilterToString(bool bilinear, bool trilinear) const;
irr::core::stringw magTexfilterToString(bool bilinear, bool trilinear) const; irr::core::stringw magTexfilterToString(bool bilinear, bool trilinear) const;
...@@ -107,8 +121,8 @@ protected: ...@@ -107,8 +121,8 @@ protected:
void writeNodeLights(irr::scene::ISceneNode * node); void writeNodeLights(irr::scene::ISceneNode * node);
void writeNodeGeometries(irr::scene::ISceneNode * node); void writeNodeGeometries(irr::scene::ISceneNode * node);
void writeSceneNode(irr::scene::ISceneNode * node); void writeSceneNode(irr::scene::ISceneNode * node);
void writeMeshMaterials(const irr::core::stringw& meshname, scene::IMesh* mesh); void writeMeshMaterials(scene::IMesh* mesh);
void writeMeshEffects(const irr::core::stringw& meshname, scene::IMesh* mesh); void writeMeshEffects(scene::IMesh* mesh);
void writeMaterialEffect(const irr::core::stringw& meshname, const irr::core::stringw& materialname, const video::SMaterial & material); void writeMaterialEffect(const irr::core::stringw& meshname, const irr::core::stringw& materialname, const video::SMaterial & material);
void writeMeshGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh); void writeMeshGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh);
void writeMeshInstanceGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh, scene::ISceneNode* node=0); void writeMeshInstanceGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh, scene::ISceneNode* node=0);
...@@ -154,15 +168,16 @@ protected: ...@@ -154,15 +168,16 @@ protected:
core::array<video::ITexture*> LibraryImages; core::array<video::ITexture*> LibraryImages;
io::path Directory; io::path Directory;
// Check per mesh-ptr if stuff has been written for this mesh already
struct ColladaMesh struct ColladaMesh
{ {
ColladaMesh() : MaterialWritten(false), EffectWritten(false), GeometryWritten(false) ColladaMesh() : MaterialsWritten(false), EffectsWritten(false), GeometryWritten(false)
{ {
} }
irr::core::stringw Name; irr::core::stringw Name;
bool MaterialWritten; bool MaterialsWritten; // just an optimization doing that here in addition to the MaterialsWritten map
bool EffectWritten; bool EffectsWritten; // just an optimization doing that here in addition to the EffectsWritten map
bool GeometryWritten; bool GeometryWritten;
}; };
typedef core::map<IMesh*, ColladaMesh>::Node MeshNode; typedef core::map<IMesh*, ColladaMesh>::Node MeshNode;
...@@ -175,6 +190,11 @@ protected: ...@@ -175,6 +190,11 @@ protected:
}; };
typedef core::map<ISceneNode*, ColladaLight>::Node LightNode; typedef core::map<ISceneNode*, ColladaLight>::Node LightNode;
core::map<ISceneNode*, ColladaLight> LightNodes; core::map<ISceneNode*, ColladaLight> LightNodes;
// Check per name if stuff has been written already
// TODO: second parameter not needed, we just don't have a core::set class yet in Irrlicht
core::map<irr::core::stringw, bool> MaterialsWritten;
core::map<irr::core::stringw, bool> EffectsWritten;
}; };
...@@ -182,5 +202,3 @@ protected: ...@@ -182,5 +202,3 @@ protected:
} // end namespace } // end namespace
#endif #endif
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment