Commit 87f86371 authored by cutealien's avatar cutealien

- add overloaded map::getValue which can return a reference

- simplified IColladaMeshWriterProperties interface
- ColladaMeshWriter can now write complete scenes as well as just writing single meshes.


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@3859 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 7d101163
......@@ -6,6 +6,8 @@
#define __IRR_I_COLLADA_MESH_WRITER_H_INCLUDED__
#include "IMeshWriter.h"
#include "ISceneNode.h"
#include "IAnimatedMesh.h"
#include "SMaterial.h"
namespace irr
......@@ -63,7 +65,18 @@ namespace scene
ECOF_TRANSPARENT_SPECULAR = 16
};
//! For mapping irrlicht textures indices to collada color-types
enum E_COLLADA_COLOR_SAMPLER
{
ECCS_DIFFUSE,
ECCS_AMBIENT,
ECCS_EMISSIVE,
ECCS_SPECULAR,
ECCS_TRANSPARENT
};
//! 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
{
public:
......@@ -72,27 +85,11 @@ namespace scene
//! Which lighting model should be used in the technique (FX) section when exporting effects (materials)
virtual E_COLLADA_TECHNIQUE_FX getTechniqueFx(const video::SMaterial& material) const = 0;
//! Which texture index should be used when writing the emissive texture
/** \return the index to the texture-layer or -1 if that texture should never be exported */
virtual s32 getEmissiveTextureIdx(const video::SMaterial& material) const = 0;
//! Which texture index should be used when writing the ambient texture
/** \return the index to the texture-layer or -1 if that texture should never be exported */
virtual s32 getAmbientTextureIdx(const video::SMaterial& material) const = 0;
//! Which texture index should be used when writing the diffuse texture
/** \return the index to the texture-layer or -1 if that texture should never be exported */
virtual s32 getDiffuseTextureIdx(const video::SMaterial& material) const = 0;
//! Which texture index should be used when writing the specular texture
/** \return the index to the texture-layer or -1 if that texture should never be exported */
virtual s32 getSpecularTextureIdx(const video::SMaterial& material) const = 0;
//! Which texture index should be used when writing the transparent texture
/** Note: By default the alpha channel is used, if you want to use RGB you have to set
the ECOF_RGB_ZERO flag in getTransparentFx.
\return the index to the texture-layer or -1 if that texture should never be exported */
virtual s32 getTransparentTextureIdx( const video::SMaterial& material) const = 0;
//! Which texture index should be used when writing the texture of the given sampler color.
/** \return the index to the texture-layer or -1 if that texture should never be exported
Note: for ECCS_TRANSPARENT by default the alpha channel is used, if you want to use RGB you have to set
also the ECOF_RGB_ZERO flag in getTransparentFx. */
virtual s32 getTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const = 0;
//! Return the settings for transparence
virtual E_COLLADA_TRANSPARENT_FX getTransparentFx(const video::SMaterial& material) const = 0;
......@@ -101,6 +98,14 @@ namespace scene
/** This value is additional to transparent settings, if both are set they will be multiplicated.
\return 1.0 for fully transparent, 0.0 for not transparent and not written at all when < 0.f */
virtual f32 getTransparency(const video::SMaterial& material) const = 0;
//! Should node be used in scene export?
//! By default all visible nodes are exported.
virtual bool isExportable(const irr::scene::ISceneNode * node) const = 0;
//! Return the mesh for the given node. If it has no mesh or shouldn't export it's mesh return 0
//! then only the transformation matrix of the node will be used.
virtual IMesh* getMesh(irr::scene::ISceneNode * node) = 0;
};
......@@ -109,8 +114,7 @@ namespace scene
{
public:
IColladaMeshWriter() : Properties(0), DefaultProperties(0), WriteTextures(true), WriteScene(false)
IColladaMeshWriter() : Properties(0), DefaultProperties(0), WriteTextures(true), WriteDefaultScene(false)
{
}
......@@ -123,6 +127,10 @@ namespace scene
DefaultProperties->drop();
}
//! writes a scene starting with the given node
virtual bool writeScene(io::IWriteFile* file, scene::ISceneNode* root) = 0;
//! Set if texture information should be written
virtual void setWriteTextures(bool write)
{
......@@ -135,19 +143,20 @@ namespace scene
return WriteTextures;
}
//! Set if a default scene should be written
//! Set if a default scene should be written when writing meshes.
/** Many collada readers fail to read a mesh if the collada files doesn't contain a scene as well.
The scene is doing an instantiation of the mesh.
When using writeScene this flag is ignored (as we have scene there already)
*/
virtual void setWriteScene(bool write)
virtual void setWriteDefaultScene(bool write)
{
WriteScene = write;
WriteDefaultScene = write;
}
//! Get if a default scene should be written
virtual bool getWriteScene() const
virtual bool getWriteDefaultScene() const
{
return WriteScene;
return WriteDefaultScene;
}
//! Set properties to use by the meshwriter instead of it's default properties.
......@@ -194,7 +203,7 @@ namespace scene
IColladaMeshWriterProperties * Properties;
IColladaMeshWriterProperties * DefaultProperties;
bool WriteTextures;
bool WriteScene;
bool WriteDefaultScene;
};
......
......@@ -58,6 +58,12 @@ class map
return Value;
}
ValueTypeRB& getValue()
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
return Value;
}
KeyTypeRB getKey() const
{
_IRR_IMPLEMENT_MANAGED_MARSHALLING_BUGFIX;
......
......@@ -2,6 +2,8 @@
// This file is part of the "Irrlicht Engine".
// For conditions of distribution and use, see copyright notice in irrlicht.h
// TODO: second UV-coordinates currently ignored in textures
#include "IrrCompileConfig.h"
#ifdef _IRR_COMPILE_WITH_COLLADA_WRITER_
......@@ -13,6 +15,9 @@
#include "IXMLWriter.h"
#include "IMesh.h"
#include "IAttributes.h"
#include "IAnimatedMeshSceneNode.h"
#include "IMeshSceneNode.h"
#include "ITerrainSceneNode.h"
namespace irr
{
......@@ -25,34 +30,25 @@ E_COLLADA_TECHNIQUE_FX CColladaMeshWriterProperties::getTechniqueFx(const video:
return ECTF_BLINN;
}
//! Which texture index should be used when setting the emissive texture
s32 CColladaMeshWriterProperties::getEmissiveTextureIdx(const video::SMaterial& material) const
{
return 0;
}
//! Which texture index should be used when setting the ambient texture
s32 CColladaMeshWriterProperties::getAmbientTextureIdx(const video::SMaterial& material) const
{
return 1;
}
//! Which texture index should be used when setting the diffuse texture
s32 CColladaMeshWriterProperties::getDiffuseTextureIdx(const video::SMaterial& material) const
//! Which texture index should be used when writing the texture of the given sampler color.
s32 CColladaMeshWriterProperties::getTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const
{
return 2;
}
//! Which texture index should be used when setting the specular texture
s32 CColladaMeshWriterProperties::getSpecularTextureIdx(const video::SMaterial& material) const
{
return 3;
}
//! Which texture index should be used when writing the transparent texture
s32 CColladaMeshWriterProperties::getTransparentTextureIdx( const video::SMaterial& material) const
{
// TODO
// So far we just export in a way which is similar to how we import colladas.
// There might be better ways to do this, but I suppose it depends a lot for which target
// application we export, so in most cases it will have to be done in user-code anyway.
switch ( cs )
{
case ECCS_DIFFUSE:
return 2;
case ECCS_AMBIENT:
return 1;
case ECCS_EMISSIVE:
return 0;
case ECCS_SPECULAR:
return 3;
case ECCS_TRANSPARENT:
return -1;
};
return -1;
}
......@@ -70,6 +66,30 @@ f32 CColladaMeshWriterProperties::getTransparency(const video::SMaterial& materi
return -1.f;
}
bool CColladaMeshWriterProperties::isExportable(const irr::scene::ISceneNode * node) const
{
return node && node->isVisible();
}
IMesh* CColladaMeshWriterProperties::getMesh(irr::scene::ISceneNode * node)
{
if ( !node )
return 0;
if ( node->getType() == ESNT_ANIMATED_MESH )
return static_cast<IAnimatedMeshSceneNode*>(node)->getMesh()->getMesh(0);
if ( node->getType() == ESNT_MESH
|| node->getType() == ESNT_CUBE
|| node->getType() == ESNT_SPHERE
|| node->getType() == ESNT_WATER_SURFACE
|| node->getType() == ESNT_Q3SHADER_SCENE_NODE
)
return static_cast<IMeshSceneNode*>(node)->getMesh();
if ( node->getType() == ESNT_TERRAIN )
return static_cast<ITerrainSceneNode*>(node)->getMesh();
return 0;
}
CColladaMeshWriter::CColladaMeshWriter(video::IVideoDriver* driver,
io::IFileSystem* fs)
......@@ -109,9 +129,8 @@ EMESH_WRITER_TYPE CColladaMeshWriter::getType() const
return EMWT_COLLADA;
}
//! writes a mesh
bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags)
//! writes a scene starting with the given node
bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* root)
{
if (!file)
return false;
......@@ -126,7 +145,11 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
Directory = FileSystem->getFileDir(FileSystem->getAbsolutePath( file->getFileName() ));
os::Printer::log("Writing mesh", file->getFileName());
// make names for all nodes with exportable meshes
Meshes.clear();
makeMeshNames(root);
os::Printer::log("Writing scene", file->getFileName());
// write COLLADA header
......@@ -138,537 +161,877 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
Writer->writeLineBreak();
// write asset data
writeAsset();
Writer->writeElement(L"asset", false);
// write all materials
Writer->writeElement(L"library_materials", false);
Writer->writeLineBreak();
Writer->writeElement(L"contributor", false);
writeNodeMaterials(root);
Writer->writeClosingTag(L"library_materials");
Writer->writeLineBreak();
Writer->writeElement(L"authoring_tool", false);
Writer->writeText(L"Irrlicht Engine / irrEdit"); // this code has originated from irrEdit 0.7
Writer->writeClosingTag(L"authoring_tool");
LibraryImages.clear();
Writer->writeElement(L"library_effects", false);
Writer->writeLineBreak();
Writer->writeClosingTag(L"contributor");
writeNodeEffects(root);
Writer->writeClosingTag(L"library_effects");
Writer->writeLineBreak();
// The next two are required
Writer->writeElement(L"created", false);
Writer->writeText(L"2008-01-31T00:00:00Z");
Writer->writeClosingTag(L"created");
// images
writeLibraryImages();
// write meshes
Writer->writeElement(L"library_geometries", false);
Writer->writeLineBreak();
writeNodeGeometries(root);
Writer->writeClosingTag(L"library_geometries");
Writer->writeLineBreak();
Writer->writeElement(L"modified", false);
Writer->writeText(L"2008-01-31T00:00:00Z");
Writer->writeClosingTag(L"modified");
// write scene
Writer->writeElement(L"library_visual_scenes", false);
Writer->writeLineBreak();
Writer->writeElement(L"visual_scene", false, L"id", L"default_scene");
Writer->writeLineBreak();
writeSceneNode(root);
Writer->writeClosingTag(L"visual_scene");
Writer->writeLineBreak();
Writer->writeClosingTag(L"library_visual_scenes");
Writer->writeLineBreak();
Writer->writeElement(L"revision", false);
Writer->writeText(L"1.0");
Writer->writeClosingTag(L"revision");
// instance scene
Writer->writeElement(L"scene", false);
Writer->writeLineBreak();
Writer->writeClosingTag(L"asset");
Writer->writeElement(L"instance_visual_scene", true, L"url", L"#default_scene");
Writer->writeLineBreak();
Writer->writeClosingTag(L"scene");
Writer->writeLineBreak();
// write all materials
// close everything
Writer->writeElement(L"library_materials", false);
Writer->writeLineBreak();
Writer->writeClosingTag(L"COLLADA");
Writer->drop();
u32 i;
for (i=0; i<mesh->getMeshBufferCount(); ++i)
{
core::stringw strMat = "mat";
strMat += i;
return true;
}
Writer->writeElement(L"material", false,
L"id", strMat.c_str(),
L"name", strMat.c_str());
Writer->writeLineBreak();
void CColladaMeshWriter::makeMeshNames(irr::scene::ISceneNode * node)
{
if ( !node || !getProperties() || !getProperties()->isExportable(node) )
return;
strMat += L"-fx";
Writer->writeElement(L"instance_effect", true,
L"url", (core::stringw(L"#") + strMat).c_str());
Writer->writeLineBreak();
IMesh* mesh = getProperties()->getMesh(node);
if ( mesh )
{
if ( !Meshes.find(mesh) )
{
ColladaMesh cm;
cm.Name = uniqueNameForMesh(mesh);
Meshes.insert(mesh, cm);
}
}
Writer->writeClosingTag(L"material");
Writer->writeLineBreak();
const core::list<ISceneNode*>& children = node->getChildren();
for ( auto it = children.begin(); it != children.end(); ++it )
{
makeMeshNames(*it);
}
}
Writer->writeClosingTag(L"library_materials");
Writer->writeLineBreak();
void CColladaMeshWriter::writeNodeMaterials(irr::scene::ISceneNode * node)
{
if ( !node || !getProperties() || !getProperties()->isExportable(node) )
return;
Writer->writeElement(L"library_effects", false);
Writer->writeLineBreak();
LibraryImages.clear();
for (i=0; i<mesh->getMeshBufferCount(); ++i)
IMesh* mesh = getProperties()->getMesh(node);
if ( mesh )
{
core::stringw strMat = "mat";
strMat += i;
strMat += L"-fx";
MeshNode * n = Meshes.find(mesh);
if ( n && !n->getValue().MaterialWritten )
{
writeMeshMaterials(n->getValue().Name, mesh);
n->getValue().MaterialWritten = true;
}
}
Writer->writeElement(L"effect", false,
L"id", strMat.c_str(),
L"name", strMat.c_str());
Writer->writeLineBreak();
Writer->writeElement(L"profile_COMMON", false);
Writer->writeLineBreak();
const core::list<ISceneNode*>& children = node->getChildren();
for ( auto it = children.begin(); it != children.end(); ++it )
{
writeNodeMaterials( *it );
}
}
video::SMaterial & material = mesh->getMeshBuffer(i)->getMaterial();
void CColladaMeshWriter::writeNodeEffects(irr::scene::ISceneNode * node)
{
if ( !node || !getProperties() || !getProperties()->isExportable(node) )
return;
int numTextures = 0;
if ( getWriteTextures() )
IMesh* mesh = getProperties()->getMesh(node);
if ( mesh )
{
MeshNode * n = Meshes.find(mesh);
if ( n && !n->getValue().EffectWritten )
{
// write texture surfaces and samplers and buffer all used imagess
for ( int t=0; t<4; ++t )
irr::core::stringw meshname(n->getValue().Name);
for (u32 i=0; i<node->getMaterialCount(); ++i)
{
video::SMaterialLayer& layer = material.TextureLayer[t];
if ( !layer.Texture )
break;
++numTextures;
if ( LibraryImages.linear_search(layer.Texture) < 0 )
LibraryImages.push_back( layer.Texture );
irr::core::stringw texName("tex");
texName += irr::core::stringw(t);
// write texture surface
//<newparam sid="tex0-surface">
irr::core::stringw texSurface(texName);
texSurface += L"-surface";
Writer->writeElement(L"newparam", false, L"sid", texSurface.c_str());
Writer->writeLineBreak();
// <surface type="2D">
Writer->writeElement(L"surface", false, L"type", L"2D");
Writer->writeLineBreak();
// <init_from>internal_texturename</init_from>
Writer->writeElement(L"init_from", false);
irr::io::path p(FileSystem->getRelativeFilename(layer.Texture->getName().getPath(), Directory));
Writer->writeText(pathToNCName(p).c_str());
Writer->writeClosingTag(L"init_from");
Writer->writeLineBreak();
// <format>A8R8G8B8</format>
Writer->writeElement(L"format", false);
video::ECOLOR_FORMAT format = layer.Texture->getColorFormat();
Writer->writeText(toString(format).c_str());
Writer->writeClosingTag(L"format");
Writer->writeLineBreak();
// </surface>
Writer->writeClosingTag(L"surface");
Writer->writeLineBreak();
// </newparam>
Writer->writeClosingTag(L"newparam");
Writer->writeLineBreak();
// write texture sampler
// <newparam sid="tex0-sampler">
irr::core::stringw texSampler(texName);
texSampler += L"-sampler";
Writer->writeElement(L"newparam", false, L"sid", texSampler.c_str());
Writer->writeLineBreak();
// <sampler2D>
Writer->writeElement(L"sampler2D", false);
Writer->writeLineBreak();
core::stringw strMat = "mat";
strMat += meshname;
strMat += i;
strMat += L"-fx";
// <source>tex0-surface</source>
Writer->writeElement(L"source", false);
Writer->writeText(texSurface.c_str());
Writer->writeClosingTag(L"source");
Writer->writeLineBreak();
video::SMaterial & material = node->getMaterial(i);
writeMaterialEffect(meshname, strMat, material);
}
n->getValue().EffectWritten = true;
}
}
// <wrap_s>WRAP</wrap_s>
Writer->writeElement(L"wrap_s", false);
Writer->writeText(toString((video::E_TEXTURE_CLAMP)layer.TextureWrapU).c_str());
Writer->writeClosingTag(L"wrap_s");
Writer->writeLineBreak();
const core::list<ISceneNode*>& children = node->getChildren();
for ( auto it = children.begin(); it != children.end(); ++it )
{
writeNodeEffects( *it );
}
}
// <wrap_t>WRAP</wrap_t>
Writer->writeElement(L"wrap_t", false);
Writer->writeText(toString((video::E_TEXTURE_CLAMP)layer.TextureWrapV).c_str());
Writer->writeClosingTag(L"wrap_t");
Writer->writeLineBreak();
void CColladaMeshWriter::writeNodeGeometries(irr::scene::ISceneNode * node)
{
if ( !node || !getProperties() || !getProperties()->isExportable(node) )
return;
// <minfilter>LINEAR_MIPMAP_LINEAR</minfilter>
Writer->writeElement(L"minfilter", false);
Writer->writeText(minTexfilterToString(layer.BilinearFilter, layer.TrilinearFilter).c_str());
Writer->writeClosingTag(L"minfilter");
Writer->writeLineBreak();
IMesh* mesh = getProperties()->getMesh(node);
if ( mesh )
{
MeshNode * n = Meshes.find(mesh);
if ( n && !n->getValue().GeometryWritten )
{
writeMeshGeometry(n->getValue().Name, mesh);
n->getValue().GeometryWritten = true;
}
}
// <magfilter>LINEAR</magfilter>
Writer->writeElement(L"magfilter", false);
Writer->writeText(magTexfilterToString(layer.BilinearFilter, layer.TrilinearFilter).c_str());
Writer->writeClosingTag(L"magfilter");
Writer->writeLineBreak();
const core::list<ISceneNode*>& children = node->getChildren();
for ( auto it = children.begin(); it != children.end(); ++it )
{
writeNodeGeometries( *it );
}
}
// TBD - actually not sure how anisotropic should be written, so for now it writes in a way
// that works with the way the loader reads it again.
if ( layer.AnisotropicFilter )
{
// <mipfilter>LINEAR_MIPMAP_LINEAR</mipfilter>
Writer->writeElement(L"mipfilter", false);
Writer->writeText(L"LINEAR_MIPMAP_LINEAR");
Writer->writeClosingTag(L"mipfilter");
Writer->writeLineBreak();
}
void CColladaMeshWriter::writeSceneNode(irr::scene::ISceneNode * node )
{
if ( !node || !getProperties() || !getProperties()->isExportable(node) )
return;
// </sampler2D>
Writer->writeClosingTag(L"sampler2D");
Writer->writeLineBreak();
// </newparam>
Writer->writeClosingTag(L"newparam");
Writer->writeLineBreak();
}
}
// Collada doesn't require to set the id, but some other tools have problems if none exists, so we just add it).
irr::core::stringw nameId(uniqueNameForNode(node));
Writer->writeElement(L"node", false, L"id", nameId.c_str());
Writer->writeLineBreak();
Writer->writeElement(L"technique", false, L"sid", L"common");
Writer->writeLineBreak();
irr::core::vector3df rot(node->getRotation());
writeTranslateElement( node->getPosition() );
writeRotateElement( irr::core::vector3df(1.f, 0.f, 0.f), rot.X );
writeRotateElement( irr::core::vector3df(0.f, 1.f, 0.f), rot.Y );
writeRotateElement( irr::core::vector3df(0.f, 0.f, 1.f), rot.Z );
writeScaleElement( node->getScale() );
E_COLLADA_TECHNIQUE_FX techFx = getProperties() ? getProperties()->getTechniqueFx(material) : ECTF_BLINN;
writeFxElement(material, techFx);
IMesh* mesh = getProperties()->getMesh(node);
if ( mesh )
{
MeshNode * n = Meshes.find(mesh);
if ( n )
writeMeshInstanceGeometry(n->getValue().Name, mesh);
}
Writer->writeClosingTag(L"technique");
Writer->writeLineBreak();
Writer->writeClosingTag(L"profile_COMMON");
Writer->writeLineBreak();
Writer->writeClosingTag(L"effect");
Writer->writeLineBreak();
const core::list<ISceneNode*>& children = node->getChildren();
for ( auto it = children.begin(); it != children.end(); ++it )
{
writeSceneNode( *it );
}
Writer->writeClosingTag(L"library_effects");
Writer->writeClosingTag(L"node");
Writer->writeLineBreak();
}
// images
if ( getWriteTextures() && !LibraryImages.empty() )
{
Writer->writeElement(L"library_images", false);
Writer->writeLineBreak();
//! writes a mesh
bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags)
{
if (!file)
return false;
for ( irr::u32 i=0; i<LibraryImages.size(); ++i )
{
irr::io::path p(FileSystem->getRelativeFilename(LibraryImages[i]->getName().getPath(), Directory));
//<image name="rose01">
irr::core::stringw ncname(pathToNCName(p));
Writer->writeElement(L"image", false, L"id", ncname.c_str(), L"name", ncname.c_str());
Writer->writeLineBreak();
// <init_from>../flowers/rose01.jpg</init_from>
Writer->writeElement(L"init_from", false);
Writer->writeText(pathToURI(p).c_str());
Writer->writeClosingTag(L"init_from");
Writer->writeLineBreak();
// </image>
Writer->writeClosingTag(L"image");
Writer->writeLineBreak();
}
Writer = FileSystem->createXMLWriter(file);
Writer->writeClosingTag(L"library_images");
Writer->writeLineBreak();
if (!Writer)
{
os::Printer::log("Could not write file", file->getFileName());
return false;
}
// write mesh
Directory = FileSystem->getFileDir(FileSystem->getAbsolutePath( file->getFileName() ));
Writer->writeElement(L"library_geometries", false);
Writer->writeLineBreak();
os::Printer::log("Writing mesh", file->getFileName());
// write COLLADA header
Writer->writeElement(L"geometry", false, L"id", L"mesh", L"name", L"mesh");
Writer->writeXMLHeader();
Writer->writeElement(L"COLLADA", false,
L"xmlns", L"http://www.collada.org/2005/11/COLLADASchema",
L"version", L"1.4.1");
Writer->writeLineBreak();
Writer->writeElement(L"mesh");
// write asset data
writeAsset();
// write all materials
Writer->writeElement(L"library_materials", false);
Writer->writeLineBreak();
// do some statistics for the mesh to know which stuff needs to be saved into
// the file:
// - count vertices
// - check for the need of a second texture coordinate
// - count amount of second texture coordinates
// - check for the need of tangents (TODO)
irr::core::stringw meshname(L"name");
writeMeshMaterials(meshname, mesh);
u32 totalVertexCount = 0;
u32 totalTCoords2Count = 0;
bool needsTangents = false; // TODO: tangents not supported here yet
Writer->writeClosingTag(L"library_materials");
Writer->writeLineBreak();
for (i=0; i<mesh->getMeshBufferCount(); ++i)
{
totalVertexCount += mesh->getMeshBuffer(i)->getVertexCount();
LibraryImages.clear();
Writer->writeElement(L"library_effects", false);
Writer->writeLineBreak();
if (hasSecondTextureCoordinates(mesh->getMeshBuffer(i)->getVertexType()))
totalTCoords2Count += mesh->getMeshBuffer(i)->getVertexCount();
writeMeshEffects(meshname, mesh);
if (!needsTangents)
needsTangents = mesh->getMeshBuffer(i)->getVertexType() == video::EVT_TANGENTS;
}
Writer->writeClosingTag(L"library_effects");
Writer->writeLineBreak();
SComponentGlobalStartPos* globalIndices = new SComponentGlobalStartPos[mesh->getMeshBufferCount()];
// images
writeLibraryImages();
// write positions
// write mesh
Writer->writeElement(L"source", false, L"id", L"mesh-Pos");
Writer->writeElement(L"library_geometries", false);
Writer->writeLineBreak();
core::stringw vertexCountStr(totalVertexCount*3);
Writer->writeElement(L"float_array", false, L"id", L"mesh-Pos-array",
L"count", vertexCountStr.c_str());
writeMeshGeometry(meshname, mesh);
Writer->writeClosingTag(L"library_geometries");
Writer->writeLineBreak();
for (i=0; i<mesh->getMeshBufferCount(); ++i)
// write scene_library
if ( getWriteDefaultScene() )
{
scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
u32 vertexCount = buffer->getVertexCount();
Writer->writeElement(L"library_visual_scenes", false);
Writer->writeLineBreak();
globalIndices[i].PosStartIndex = 0;
Writer->writeElement(L"visual_scene", false, L"id", L"default_scene");
Writer->writeLineBreak();
if (i!=0)
globalIndices[i].PosStartIndex = globalIndices[i-1].PosLastIndex + 1;
Writer->writeElement(L"node", false);
Writer->writeLineBreak();
globalIndices[i].PosLastIndex = globalIndices[i].PosStartIndex + vertexCount - 1;
writeMeshInstanceGeometry(meshname, mesh);
switch(vtxType)
{
case video::EVT_STANDARD:
{
video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].Pos).c_str());
Writer->writeLineBreak();
}
}
break;
case video::EVT_2TCOORDS:
{
video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].Pos).c_str());
Writer->writeLineBreak();
}
}
break;
case video::EVT_TANGENTS:
{
video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].Pos).c_str());
Writer->writeLineBreak();
}
}
break;
}
}
Writer->writeClosingTag(L"node");
Writer->writeLineBreak();
Writer->writeClosingTag(L"float_array");
Writer->writeLineBreak();
Writer->writeClosingTag(L"visual_scene");
Writer->writeLineBreak();
Writer->writeElement(L"technique_common", false);
Writer->writeLineBreak();
Writer->writeClosingTag(L"library_visual_scenes");
Writer->writeLineBreak();
vertexCountStr = core::stringw(totalVertexCount);
Writer->writeElement(L"accessor", false, L"source", L"#mesh-Pos-array",
L"count", vertexCountStr.c_str(), L"stride", L"3");
// write scene
Writer->writeElement(L"scene", false);
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"X", L"type", L"float");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"Y", L"type", L"float");
Writer->writeElement(L"instance_visual_scene", true, L"url", L"#default_scene");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"Z", L"type", L"float");
Writer->writeClosingTag(L"scene");
Writer->writeLineBreak();
}
// close everything
Writer->writeClosingTag(L"COLLADA");
Writer->drop();
return true;
}
void CColladaMeshWriter::writeMeshInstanceGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh)
{
//<instance_geometry url="#mesh">
core::stringw meshId("mesh-");
meshId += meshname;
Writer->writeElement(L"instance_geometry", false, L"url", toRef(meshId).c_str());
Writer->writeLineBreak();
Writer->writeElement(L"bind_material", false);
Writer->writeLineBreak();
Writer->writeElement(L"technique_common", false);
Writer->writeLineBreak();
// instance materials
// <instance_material symbol="leaf" target="#MidsummerLeaf01"/>
for (u32 i=0; i<mesh->getMeshBufferCount(); ++i)
{
core::stringw strMat = "mat";
strMat += meshname;
strMat += i;
core::stringw strMatInst(L"#");
strMatInst += strMat;
Writer->writeElement(L"instance_material", false, L"symbol", strMat.c_str(), L"target", strMatInst.c_str());
Writer->writeLineBreak();
Writer->writeClosingTag(L"accessor");
// <bind_vertex_input semantic="mesh-TexCoord0" input_semantic="TEXCOORD"/>
core::stringw meshTexCoordId("mesh-");
meshTexCoordId += meshname;
meshTexCoordId += L"-TexCoord0"; // TODO: need to handle second UV-set
Writer->writeElement(L"bind_vertex_input", true, L"semantic", meshTexCoordId.c_str(), L"input_semantic", L"TEXCOORD" );
Writer->writeLineBreak();
Writer->writeClosingTag(L"instance_material");
Writer->writeLineBreak();
}
Writer->writeClosingTag(L"technique_common");
Writer->writeLineBreak();
Writer->writeClosingTag(L"technique_common");
Writer->writeLineBreak();
Writer->writeClosingTag(L"bind_material");
Writer->writeLineBreak();
Writer->writeClosingTag(L"source");
Writer->writeClosingTag(L"instance_geometry");
Writer->writeLineBreak();
}
// write texture coordinates
bool CColladaMeshWriter::hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) const
{
return type == video::EVT_2TCOORDS;
}
Writer->writeElement(L"source", false, L"id", L"mesh-TexCoord0");
Writer->writeLineBreak();
irr::core::stringw CColladaMeshWriter::toString(const irr::core::vector3df& vec) const
{
c8 tmpbuf[255];
snprintf(tmpbuf, 255, "%f %f %f", vec.X, vec.Y, vec.Z);
core::stringw str = tmpbuf;
vertexCountStr = core::stringw(totalVertexCount*2);
Writer->writeElement(L"float_array", false, L"id", L"mesh-TexCoord0-array",
L"count", vertexCountStr.c_str());
Writer->writeLineBreak();
return str;
}
for (i=0; i<mesh->getMeshBufferCount(); ++i)
irr::core::stringw CColladaMeshWriter::toString(const irr::core::vector2df& vec) const
{
c8 tmpbuf[255];
snprintf(tmpbuf, 255, "%f %f", vec.X, vec.Y);
core::stringw str = tmpbuf;
return str;
}
irr::core::stringw CColladaMeshWriter::toString(const irr::video::SColorf& colorf) const
{
c8 tmpbuf[255];
snprintf(tmpbuf, 255, "%f %f %f %f", colorf.getRed(), colorf.getGreen(), colorf.getBlue(), colorf.getAlpha());
core::stringw str = tmpbuf;
return str;
}
irr::core::stringw CColladaMeshWriter::toString(const irr::video::ECOLOR_FORMAT format) const
{
switch ( format )
{
scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
u32 vertexCount = buffer->getVertexCount();
case video::ECF_A1R5G5B5: return irr::core::stringw(L"A1R5G5B5");
case video::ECF_R5G6B5: return irr::core::stringw(L"R5G6B5");
case video::ECF_R8G8B8: return irr::core::stringw(L"R8G8B8");
case video::ECF_A8R8G8B8: return irr::core::stringw(L"A8R8G8B8");
default: return irr::core::stringw(L"");
}
}
irr::core::stringw CColladaMeshWriter::toString(const irr::video::E_TEXTURE_CLAMP clamp) const
{
switch ( clamp )
{
case video::ETC_REPEAT:
return core::stringw(L"WRAP");
case video::ETC_CLAMP:
case video::ETC_CLAMP_TO_EDGE:
return core::stringw(L"CLAMP");
case video::ETC_CLAMP_TO_BORDER:
return core::stringw(L"BORDER");
case video::ETC_MIRROR:
case video::ETC_MIRROR_CLAMP:
case video::ETC_MIRROR_CLAMP_TO_EDGE:
case video::ETC_MIRROR_CLAMP_TO_BORDER:
return core::stringw(L"MIRROR");
}
return core::stringw(L"NONE");
}
irr::core::stringw CColladaMeshWriter::toString(const irr::scene::E_COLLADA_TRANSPARENT_FX transparent) const
{
if ( transparent & ECOF_RGB_ZERO )
return core::stringw(L"RGB_ZERO");
else
return core::stringw(L"A_ONE");
}
irr::core::stringw CColladaMeshWriter::toRef(const irr::core::stringw& source) const
{
irr::core::stringw ref(L"#");
ref += source;
return ref;
}
irr::core::stringw CColladaMeshWriter::uniqueNameForMesh(const scene::IMesh* mesh) const
{
return irr::core::stringw( (int)mesh );
}
irr::core::stringw CColladaMeshWriter::uniqueNameForNode(const scene::ISceneNode* node) const
{
irr::core::stringw name((int)node);
if ( node )
name += irr::core::stringw(node->getName());
return name;
}
irr::core::stringw CColladaMeshWriter::minTexfilterToString(bool bilinear, bool trilinear) const
{
if ( trilinear )
return core::stringw(L"LINEAR_MIPMAP_LINEAR");
else if ( bilinear )
return core::stringw(L"LINEAR_MIPMAP_NEAREST");
return core::stringw(L"NONE");
}
inline irr::core::stringw CColladaMeshWriter::magTexfilterToString(bool bilinear, bool trilinear) const
{
if ( bilinear || trilinear )
return core::stringw(L"LINEAR");
return core::stringw(L"NONE");
}
bool CColladaMeshWriter::isXmlNameStartChar(wchar_t c) const
{
return (c >= 'A' && c <= 'Z')
|| c == L'_'
|| (c >= 'a' && c <= 'z')
|| (c >= 0xC0 && c <= 0xD6)
|| (c >= 0xD8 && c <= 0xF6)
|| (c >= 0xF8 && c <= 0x2FF)
|| (c >= 0x370 && c <= 0x37D)
|| (c >= 0x37F && c <= 0x1FFF)
|| (c >= 0x200C && c <= 0x200D)
|| (c >= 0x2070 && c <= 0x218F)
|| (c >= 0x2C00 && c <= 0x2FEF)
|| (c >= 0x3001 && c <= 0xD7FF)
|| (c >= 0xF900 && c <= 0xFDCF)
|| (c >= 0xFDF0 && c <= 0xFFFD)
|| (c >= 0x10000 && c <= 0xEFFFF);
}
bool CColladaMeshWriter::isXmlNameChar(wchar_t c) const
{
return isXmlNameStartChar(c)
|| c == L'-'
|| c == L'.'
|| (c >= '0' && c <= '9')
|| c == 0xB7
|| (c >= 0x0300 && c <= 0x036F)
|| (c >= 0x203F && c <= 0x2040);
}
globalIndices[i].TCoord0StartIndex = 0;
// Restrict the characters to a set of allowed characters in xs::NCName.
irr::core::stringw CColladaMeshWriter::pathToNCName(const irr::io::path& path) const
{
irr::core::stringw result(L"_NCNAME_"); // ensure id starts with a valid char and reduce chance of name-conflicts
if ( path.empty() )
return result;
if (i!=0)
globalIndices[i].TCoord0StartIndex = globalIndices[i-1].TCoord0LastIndex + 1;
result.append( irr::core::stringw(path) );
globalIndices[i].TCoord0LastIndex = globalIndices[i].TCoord0StartIndex + vertexCount - 1;
// We replace all characters not allowed by a replacement char
const wchar_t REPLACMENT = L'-';
for ( irr::u32 i=1; i < result.size(); ++i )
{
if ( result[i] == L':' || !isXmlNameChar(result[i]) )
{
result[i] = REPLACMENT;
}
}
return result;
}
switch(vtxType)
irr::core::stringw CColladaMeshWriter::pathToURI(const irr::io::path& path) const
{
irr::core::stringw result;
// is this a relative path?
if ( path.size() > 1
&& path[0] != _IRR_TEXT('/')
&& path[0] != _IRR_TEXT('\\')
&& path[1] != _IRR_TEXT(':') )
{
// not already starting with "./" ?
if ( path[0] != _IRR_TEXT('.')
|| path[1] != _IRR_TEXT('/') )
{
case video::EVT_STANDARD:
{
video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].TCoords).c_str());
Writer->writeLineBreak();
}
}
break;
case video::EVT_2TCOORDS:
{
video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].TCoords).c_str());
Writer->writeLineBreak();
}
}
break;
case video::EVT_TANGENTS:
{
video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].TCoords).c_str());
Writer->writeLineBreak();
}
}
break;
result.append(L"./");
}
}
result.append(path);
// TODO: make correct URI (without whitespaces)
return result;
}
Writer->writeClosingTag(L"float_array");
void CColladaMeshWriter::writeAsset()
{
Writer->writeElement(L"asset", false);
Writer->writeLineBreak();
Writer->writeElement(L"technique_common", false);
Writer->writeElement(L"contributor", false);
Writer->writeLineBreak();
Writer->writeElement(L"authoring_tool", false);
Writer->writeText(L"Irrlicht Engine / irrEdit"); // this code has originated from irrEdit 0.7
Writer->writeClosingTag(L"authoring_tool");
Writer->writeLineBreak();
Writer->writeClosingTag(L"contributor");
Writer->writeLineBreak();
// The next two are required
Writer->writeElement(L"created", false);
Writer->writeText(L"2008-01-31T00:00:00Z");
Writer->writeClosingTag(L"created");
Writer->writeLineBreak();
Writer->writeElement(L"modified", false);
Writer->writeText(L"2008-01-31T00:00:00Z");
Writer->writeClosingTag(L"modified");
Writer->writeLineBreak();
Writer->writeElement(L"revision", false);
Writer->writeText(L"1.0");
Writer->writeClosingTag(L"revision");
Writer->writeLineBreak();
Writer->writeClosingTag(L"asset");
Writer->writeLineBreak();
}
void CColladaMeshWriter::writeMeshMaterials(const irr::core::stringw& meshname, scene::IMesh* mesh)
{
u32 i;
for (i=0; i<mesh->getMeshBufferCount(); ++i)
{
core::stringw strMat = "mat";
strMat += meshname;
strMat += i;
Writer->writeElement(L"material", false,
L"id", strMat.c_str(),
L"name", strMat.c_str());
Writer->writeLineBreak();
vertexCountStr = core::stringw(totalVertexCount);
strMat += L"-fx";
Writer->writeElement(L"instance_effect", true,
L"url", (core::stringw(L"#") + strMat).c_str());
Writer->writeLineBreak();
Writer->writeElement(L"accessor", false, L"source", L"#mesh-TexCoord0-array",
L"count", vertexCountStr.c_str(), L"stride", L"2");
Writer->writeClosingTag(L"material");
Writer->writeLineBreak();
}
}
void CColladaMeshWriter::writeMaterialEffect(const irr::core::stringw& meshname, const irr::core::stringw& materialname, const video::SMaterial & material)
{
Writer->writeElement(L"effect", false,
L"id", materialname.c_str(),
L"name", materialname.c_str());
Writer->writeLineBreak();
Writer->writeElement(L"profile_COMMON", false);
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"U", L"type", L"float");
int numTextures = 0;
if ( getWriteTextures() )
{
// write texture surfaces and samplers and buffer all used imagess
for ( int t=0; t<4; ++t )
{
const video::SMaterialLayer& layer = material.TextureLayer[t];
if ( !layer.Texture )
break;
++numTextures;
if ( LibraryImages.linear_search(layer.Texture) < 0 )
LibraryImages.push_back( layer.Texture );
irr::core::stringw texName("tex");
texName += irr::core::stringw(t);
// write texture surface
//<newparam sid="tex0-surface">
irr::core::stringw texSurface(texName);
texSurface += L"-surface";
Writer->writeElement(L"newparam", false, L"sid", texSurface.c_str());
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"V", L"type", L"float");
// <surface type="2D">
Writer->writeElement(L"surface", false, L"type", L"2D");
Writer->writeLineBreak();
// <init_from>internal_texturename</init_from>
Writer->writeElement(L"init_from", false);
irr::io::path p(FileSystem->getRelativeFilename(layer.Texture->getName().getPath(), Directory));
Writer->writeText(pathToNCName(p).c_str());
Writer->writeClosingTag(L"init_from");
Writer->writeLineBreak();
// <format>A8R8G8B8</format>
Writer->writeElement(L"format", false);
video::ECOLOR_FORMAT format = layer.Texture->getColorFormat();
Writer->writeText(toString(format).c_str());
Writer->writeClosingTag(L"format");
Writer->writeLineBreak();
// </surface>
Writer->writeClosingTag(L"surface");
Writer->writeLineBreak();
// </newparam>
Writer->writeClosingTag(L"newparam");
Writer->writeLineBreak();
Writer->writeClosingTag(L"accessor");
Writer->writeLineBreak();
// write texture sampler
// <newparam sid="tex0-sampler">
irr::core::stringw texSampler(texName);
texSampler += L"-sampler";
Writer->writeElement(L"newparam", false, L"sid", texSampler.c_str());
Writer->writeLineBreak();
// <sampler2D>
Writer->writeElement(L"sampler2D", false);
Writer->writeLineBreak();
Writer->writeClosingTag(L"technique_common");
Writer->writeLineBreak();
// <source>tex0-surface</source>
Writer->writeElement(L"source", false);
Writer->writeText(texSurface.c_str());
Writer->writeClosingTag(L"source");
Writer->writeLineBreak();
Writer->writeClosingTag(L"source");
// <wrap_s>WRAP</wrap_s>
Writer->writeElement(L"wrap_s", false);
Writer->writeText(toString((video::E_TEXTURE_CLAMP)layer.TextureWrapU).c_str());
Writer->writeClosingTag(L"wrap_s");
Writer->writeLineBreak();
// <wrap_t>WRAP</wrap_t>
Writer->writeElement(L"wrap_t", false);
Writer->writeText(toString((video::E_TEXTURE_CLAMP)layer.TextureWrapV).c_str());
Writer->writeClosingTag(L"wrap_t");
Writer->writeLineBreak();
// <minfilter>LINEAR_MIPMAP_LINEAR</minfilter>
Writer->writeElement(L"minfilter", false);
Writer->writeText(minTexfilterToString(layer.BilinearFilter, layer.TrilinearFilter).c_str());
Writer->writeClosingTag(L"minfilter");
Writer->writeLineBreak();
// <magfilter>LINEAR</magfilter>
Writer->writeElement(L"magfilter", false);
Writer->writeText(magTexfilterToString(layer.BilinearFilter, layer.TrilinearFilter).c_str());
Writer->writeClosingTag(L"magfilter");
Writer->writeLineBreak();
// TBD - actually not sure how anisotropic should be written, so for now it writes in a way
// that works with the way the loader reads it again.
if ( layer.AnisotropicFilter )
{
// <mipfilter>LINEAR_MIPMAP_LINEAR</mipfilter>
Writer->writeElement(L"mipfilter", false);
Writer->writeText(L"LINEAR_MIPMAP_LINEAR");
Writer->writeClosingTag(L"mipfilter");
Writer->writeLineBreak();
}
// </sampler2D>
Writer->writeClosingTag(L"sampler2D");
Writer->writeLineBreak();
// </newparam>
Writer->writeClosingTag(L"newparam");
Writer->writeLineBreak();
}
}
Writer->writeElement(L"technique", false, L"sid", L"common");
Writer->writeLineBreak();
// write normals
E_COLLADA_TECHNIQUE_FX techFx = getProperties() ? getProperties()->getTechniqueFx(material) : ECTF_BLINN;
writeFxElement(meshname, material, techFx);
Writer->writeElement(L"source", false, L"id", L"mesh-Normal");
Writer->writeClosingTag(L"technique");
Writer->writeLineBreak();
Writer->writeClosingTag(L"profile_COMMON");
Writer->writeLineBreak();
Writer->writeClosingTag(L"effect");
Writer->writeLineBreak();
}
void CColladaMeshWriter::writeMeshEffects(const irr::core::stringw& meshname, scene::IMesh* mesh)
{
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();
writeMaterialEffect(meshname, strMat, material);
}
}
void CColladaMeshWriter::writeMeshGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh)
{
core::stringw meshId("mesh-");
meshId += meshname;
vertexCountStr = core::stringw(totalVertexCount*3);
Writer->writeElement(L"float_array", false, L"id", L"mesh-Normal-array",
L"count", vertexCountStr.c_str());
Writer->writeElement(L"geometry", false, L"id", meshId.c_str(), L"name", meshId.c_str());
Writer->writeLineBreak();
Writer->writeElement(L"mesh");
Writer->writeLineBreak();
// do some statistics for the mesh to know which stuff needs to be saved into
// the file:
// - count vertices
// - check for the need of a second texture coordinate
// - count amount of second texture coordinates
// - check for the need of tangents (TODO)
u32 totalVertexCount = 0;
u32 totalTCoords2Count = 0;
bool needsTangents = false; // TODO: tangents not supported here yet
u32 i=0;
for (i=0; i<mesh->getMeshBufferCount(); ++i)
{
scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
u32 vertexCount = buffer->getVertexCount();
totalVertexCount += mesh->getMeshBuffer(i)->getVertexCount();
if (hasSecondTextureCoordinates(mesh->getMeshBuffer(i)->getVertexType()))
totalTCoords2Count += mesh->getMeshBuffer(i)->getVertexCount();
if (!needsTangents)
needsTangents = mesh->getMeshBuffer(i)->getVertexType() == video::EVT_TANGENTS;
}
SComponentGlobalStartPos* globalIndices = new SComponentGlobalStartPos[mesh->getMeshBufferCount()];
// write positions
core::stringw meshPosId(meshId);
meshPosId += L"-Pos";
Writer->writeElement(L"source", false, L"id", meshPosId.c_str());
Writer->writeLineBreak();
core::stringw vertexCountStr(totalVertexCount*3);
core::stringw meshPosArrayId(meshPosId);
meshPosArrayId += L"-array";
Writer->writeElement(L"float_array", false, L"id", meshPosArrayId.c_str(),
L"count", vertexCountStr.c_str());
Writer->writeLineBreak();
globalIndices[i].NormalStartIndex = 0;
for (i=0; i<mesh->getMeshBufferCount(); ++i)
{
scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
u32 vertexCount = buffer->getVertexCount();
if (i!=0)
globalIndices[i].NormalStartIndex = globalIndices[i-1].NormalLastIndex + 1;
globalIndices[i].PosStartIndex = 0;
globalIndices[i].NormalLastIndex = globalIndices[i].NormalStartIndex + vertexCount - 1;
if (i!=0)
globalIndices[i].PosStartIndex = globalIndices[i-1].PosLastIndex + 1;
switch(vtxType)
{
case video::EVT_STANDARD:
globalIndices[i].PosLastIndex = globalIndices[i].PosStartIndex + vertexCount - 1;
switch(vtxType)
{
video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
case video::EVT_STANDARD:
{
Writer->writeText(toString(vtx[j].Normal).c_str());
Writer->writeLineBreak();
video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].Pos).c_str());
Writer->writeLineBreak();
}
}
}
break;
case video::EVT_2TCOORDS:
{
video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
break;
case video::EVT_2TCOORDS:
{
Writer->writeText(toString(vtx[j].Normal).c_str());
Writer->writeLineBreak();
video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].Pos).c_str());
Writer->writeLineBreak();
}
}
}
break;
case video::EVT_TANGENTS:
{
video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
break;
case video::EVT_TANGENTS:
{
Writer->writeText(toString(vtx[j].Normal).c_str());
Writer->writeLineBreak();
video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].Pos).c_str());
Writer->writeLineBreak();
}
}
break;
}
break;
}
}
Writer->writeClosingTag(L"float_array");
Writer->writeLineBreak();
Writer->writeElement(L"technique_common", false);
Writer->writeLineBreak();
vertexCountStr = core::stringw(totalVertexCount);
Writer->writeClosingTag(L"float_array");
Writer->writeLineBreak();
Writer->writeElement(L"accessor", false, L"source", L"#mesh-Normal-array",
L"count", vertexCountStr.c_str(), L"stride", L"3");
Writer->writeElement(L"technique_common", false);
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"X", L"type", L"float");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"Y", L"type", L"float");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"Z", L"type", L"float");
vertexCountStr = core::stringw(totalVertexCount);
Writer->writeElement(L"accessor", false, L"source", toRef(meshPosArrayId).c_str(),
L"count", vertexCountStr.c_str(), L"stride", L"3");
Writer->writeLineBreak();
Writer->writeClosingTag(L"accessor");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"X", L"type", L"float");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"Y", L"type", L"float");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"Z", L"type", L"float");
Writer->writeLineBreak();
Writer->writeClosingTag(L"technique_common");
Writer->writeLineBreak();
Writer->writeClosingTag(L"accessor");
Writer->writeLineBreak();
Writer->writeClosingTag(L"technique_common");
Writer->writeLineBreak();
Writer->writeClosingTag(L"source");
Writer->writeLineBreak();
// write second set of texture coordinates
// write texture coordinates
if (totalTCoords2Count)
{
Writer->writeElement(L"source", false, L"id", L"mesh-TexCoord1");
Writer->writeLineBreak();
core::stringw meshTexCoord0Id(meshId);
meshTexCoord0Id += L"-TexCoord0";
Writer->writeElement(L"source", false, L"id", meshTexCoord0Id.c_str());
Writer->writeLineBreak();
vertexCountStr = core::stringw(totalTCoords2Count*2);
Writer->writeElement(L"float_array", false, L"id", L"mesh-TexCoord1-array",
L"count", vertexCountStr.c_str());
vertexCountStr = core::stringw(totalVertexCount*2);
core::stringw meshTexCoordArrayId(meshTexCoord0Id);
meshTexCoordArrayId += L"-array";
Writer->writeElement(L"float_array", false, L"id", meshTexCoordArrayId.c_str(),
L"count", vertexCountStr.c_str());
Writer->writeLineBreak();
for (i=0; i<mesh->getMeshBufferCount(); ++i)
......@@ -677,31 +1040,46 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
u32 vertexCount = buffer->getVertexCount();
if (hasSecondTextureCoordinates(vtxType))
{
globalIndices[i].TCoord1StartIndex = 0;
globalIndices[i].TCoord0StartIndex = 0;
if (i!=0 && globalIndices[i-1].TCoord1LastIndex != -1)
globalIndices[i].TCoord1StartIndex = globalIndices[i-1].TCoord1LastIndex + 1;
if (i!=0)
globalIndices[i].TCoord0StartIndex = globalIndices[i-1].TCoord0LastIndex + 1;
globalIndices[i].TCoord1LastIndex = globalIndices[i].TCoord1StartIndex + vertexCount - 1;
globalIndices[i].TCoord0LastIndex = globalIndices[i].TCoord0StartIndex + vertexCount - 1;
switch(vtxType)
switch(vtxType)
{
case video::EVT_STANDARD:
{
case video::EVT_2TCOORDS:
video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].TCoords2).c_str());
Writer->writeLineBreak();
}
Writer->writeText(toString(vtx[j].TCoords).c_str());
Writer->writeLineBreak();
}
}
break;
case video::EVT_2TCOORDS:
{
video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].TCoords).c_str());
Writer->writeLineBreak();
}
}
break;
case video::EVT_TANGENTS:
{
video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].TCoords).c_str());
Writer->writeLineBreak();
}
break;
default:
break;
}
} // end this buffer has 2 texture coordinates
break;
}
}
Writer->writeClosingTag(L"float_array");
......@@ -710,10 +1088,10 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
Writer->writeElement(L"technique_common", false);
Writer->writeLineBreak();
vertexCountStr = core::stringw(totalTCoords2Count);
vertexCountStr = core::stringw(totalVertexCount);
Writer->writeElement(L"accessor", false, L"source", L"#mesh-TexCoord1-array",
L"count", vertexCountStr.c_str(), L"stride", L"2");
Writer->writeElement(L"accessor", false, L"source", toRef(meshTexCoordArrayId).c_str(),
L"count", vertexCountStr.c_str(), L"stride", L"2");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"U", L"type", L"float");
......@@ -727,373 +1105,315 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32
Writer->writeClosingTag(L"technique_common");
Writer->writeLineBreak();
Writer->writeClosingTag(L"source");
Writer->writeLineBreak();
}
// write tangents
// TODO
// write vertices
Writer->writeElement(L"vertices", false, L"id", L"mesh-Vtx");
Writer->writeLineBreak();
Writer->writeElement(L"input", true, L"semantic", L"POSITION", L"source", L"#mesh-Pos");
Writer->writeClosingTag(L"source");
Writer->writeLineBreak();
Writer->writeClosingTag(L"vertices");
// write normals
core::stringw meshNormalId(meshId);
meshNormalId += L"-Normal";
Writer->writeElement(L"source", false, L"id", meshNormalId.c_str());
Writer->writeLineBreak();
// write polygons
for (i=0; i<mesh->getMeshBufferCount(); ++i)
{
scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
const u32 polyCount = buffer->getIndexCount() / 3;
core::stringw strPolyCount(polyCount);
core::stringw strMat = "mat";
strMat += i;
Writer->writeElement(L"triangles", false, L"count", strPolyCount.c_str(),
L"material", strMat.c_str());
Writer->writeLineBreak();
Writer->writeElement(L"input", true, L"semantic", L"VERTEX", L"source", L"#mesh-Vtx", L"offset", L"0");
Writer->writeLineBreak();
Writer->writeElement(L"input", true, L"semantic", L"TEXCOORD", L"source", L"#mesh-TexCoord0", L"offset", L"1");
Writer->writeLineBreak();
Writer->writeElement(L"input", true, L"semantic", L"NORMAL", L"source", L"#mesh-Normal", L"offset", L"2");
vertexCountStr = core::stringw(totalVertexCount*3);
core::stringw meshNormalArrayId(meshNormalId);
meshNormalArrayId += L"-array";
Writer->writeElement(L"float_array", false, L"id", meshNormalArrayId.c_str(),
L"count", vertexCountStr.c_str());
Writer->writeLineBreak();
bool has2ndTexCoords = hasSecondTextureCoordinates(buffer->getVertexType());
if (has2ndTexCoords)
for (i=0; i<mesh->getMeshBufferCount(); ++i)
{
Writer->writeElement(L"input", true, L"semantic", L"TEXCOORD", L"source", L"#mesh-TexCoord1", L"idx", L"3");
Writer->writeLineBreak();
}
// write indices now
s32 posIdx = globalIndices[i].PosStartIndex;
s32 tCoordIdx = globalIndices[i].TCoord0StartIndex;
s32 normalIdx = globalIndices[i].NormalStartIndex;
s32 tCoord2Idx = globalIndices[i].TCoord1StartIndex;
Writer->writeElement(L"p", false);
scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
u32 vertexCount = buffer->getVertexCount();
for (u32 p=0; p<polyCount; ++p)
{
core::stringw strP;
globalIndices[i].NormalStartIndex = 0;
strP += buffer->getIndices()[(p*3) + 0] + posIdx;
strP += " ";
strP += buffer->getIndices()[(p*3) + 0] + tCoordIdx;
strP += " ";
strP += buffer->getIndices()[(p*3) + 0] + normalIdx;
strP += " ";
if (has2ndTexCoords)
{
strP += buffer->getIndices()[(p*3) + 0] + tCoord2Idx;
strP += " ";
}
if (i!=0)
globalIndices[i].NormalStartIndex = globalIndices[i-1].NormalLastIndex + 1;
strP += buffer->getIndices()[(p*3) + 1] + posIdx;
strP += " ";
strP += buffer->getIndices()[(p*3) + 1] + tCoordIdx;
strP += " ";
strP += buffer->getIndices()[(p*3) + 1] + normalIdx;
strP += " ";
if (has2ndTexCoords)
{
strP += buffer->getIndices()[(p*3) + 1] + tCoord2Idx;
strP += " ";
}
globalIndices[i].NormalLastIndex = globalIndices[i].NormalStartIndex + vertexCount - 1;
strP += buffer->getIndices()[(p*3) + 2] + posIdx;
strP += " ";
strP += buffer->getIndices()[(p*3) + 2] + tCoordIdx;
strP += " ";
strP += buffer->getIndices()[(p*3) + 2] + normalIdx;
if (has2ndTexCoords)
switch(vtxType)
{
strP += " ";
strP += buffer->getIndices()[(p*3) + 2] + tCoord2Idx;
case video::EVT_STANDARD:
{
video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].Normal).c_str());
Writer->writeLineBreak();
}
}
break;
case video::EVT_2TCOORDS:
{
video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].Normal).c_str());
Writer->writeLineBreak();
}
}
break;
case video::EVT_TANGENTS:
{
video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].Normal).c_str());
Writer->writeLineBreak();
}
}
break;
}
strP += " ";
Writer->writeText(strP.c_str());
}
Writer->writeClosingTag(L"p");
Writer->writeClosingTag(L"float_array");
Writer->writeLineBreak();
// close index buffer section
Writer->writeClosingTag(L"triangles");
Writer->writeElement(L"technique_common", false);
Writer->writeLineBreak();
}
// close mesh and geometry
vertexCountStr = core::stringw(totalVertexCount);
Writer->writeClosingTag(L"mesh");
Writer->writeLineBreak();
Writer->writeClosingTag(L"geometry");
Writer->writeLineBreak();
Writer->writeElement(L"accessor", false, L"source", toRef(meshNormalArrayId).c_str(),
L"count", vertexCountStr.c_str(), L"stride", L"3");
Writer->writeLineBreak();
Writer->writeClosingTag(L"library_geometries");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"X", L"type", L"float");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"Y", L"type", L"float");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"Z", L"type", L"float");
Writer->writeLineBreak();
Writer->writeClosingTag(L"accessor");
Writer->writeLineBreak();
Writer->writeClosingTag(L"technique_common");
Writer->writeLineBreak();
// write scene_library
if ( getWriteScene() )
Writer->writeClosingTag(L"source");
Writer->writeLineBreak();
// write second set of texture coordinates
core::stringw meshTexCoord1Id(meshId);
meshTexCoord1Id += L"-TexCoord1";
if (totalTCoords2Count)
{
Writer->writeElement(L"library_visual_scenes", false);
Writer->writeElement(L"source", false, L"id", meshTexCoord1Id.c_str());
Writer->writeLineBreak();
Writer->writeElement(L"visual_scene", false, L"id", L"default_scene");
vertexCountStr = core::stringw(totalTCoords2Count*2);
core::stringw meshTexCoord1ArrayId(meshTexCoord1Id);
meshTexCoord1ArrayId += L"-array";
Writer->writeElement(L"float_array", false, L"id", meshTexCoord1ArrayId.c_str(),
L"count", vertexCountStr.c_str());
Writer->writeLineBreak();
Writer->writeElement(L"node", false);
Writer->writeLineBreak();
//<instance_geometry url="#mesh">
Writer->writeElement(L"instance_geometry", false, L"url", L"#mesh");
Writer->writeLineBreak();
for (i=0; i<mesh->getMeshBufferCount(); ++i)
{
scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
video::E_VERTEX_TYPE vtxType = buffer->getVertexType();
u32 vertexCount = buffer->getVertexCount();
Writer->writeElement(L"bind_material", false);
Writer->writeLineBreak();
if (hasSecondTextureCoordinates(vtxType))
{
globalIndices[i].TCoord1StartIndex = 0;
Writer->writeElement(L"technique_common", false);
Writer->writeLineBreak();
// instance materials
// <instance_material symbol="leaf" target="#MidsummerLeaf01"/>
for (i=0; i<mesh->getMeshBufferCount(); ++i)
{
core::stringw strMat = "mat";
strMat += i;
core::stringw strMatInst(L"#");
strMatInst += strMat;
Writer->writeElement(L"instance_material", false, L"symbol", strMat.c_str(), L"target", strMatInst.c_str());
Writer->writeLineBreak();
if (i!=0 && globalIndices[i-1].TCoord1LastIndex != -1)
globalIndices[i].TCoord1StartIndex = globalIndices[i-1].TCoord1LastIndex + 1;
// <bind_vertex_input semantic="mesh-TexCoord0" input_semantic="TEXCOORD"/>
Writer->writeElement(L"bind_vertex_input", true, L"semantic", L"mesh-TexCoord0", L"input_semantic", L"TEXCOORD" );
Writer->writeLineBreak();
globalIndices[i].TCoord1LastIndex = globalIndices[i].TCoord1StartIndex + vertexCount - 1;
Writer->writeClosingTag(L"instance_material");
switch(vtxType)
{
case video::EVT_2TCOORDS:
{
video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
for (u32 j=0; j<vertexCount; ++j)
{
Writer->writeText(toString(vtx[j].TCoords2).c_str());
Writer->writeLineBreak();
}
Writer->writeClosingTag(L"technique_common");
Writer->writeLineBreak();
Writer->writeClosingTag(L"bind_material");
Writer->writeLineBreak();
Writer->writeClosingTag(L"instance_geometry");
Writer->writeLineBreak();
}
break;
default:
break;
}
} // end this buffer has 2 texture coordinates
}
Writer->writeClosingTag(L"node");
Writer->writeLineBreak();
Writer->writeClosingTag(L"float_array");
Writer->writeLineBreak();
Writer->writeClosingTag(L"visual_scene");
Writer->writeElement(L"technique_common", false);
Writer->writeLineBreak();
vertexCountStr = core::stringw(totalTCoords2Count);
Writer->writeClosingTag(L"library_visual_scenes");
Writer->writeLineBreak();
Writer->writeElement(L"accessor", false, L"source", toRef(meshTexCoord1ArrayId).c_str(),
L"count", vertexCountStr.c_str(), L"stride", L"2");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"U", L"type", L"float");
Writer->writeLineBreak();
Writer->writeElement(L"param", true, L"name", L"V", L"type", L"float");
Writer->writeLineBreak();
// write scene
Writer->writeElement(L"scene", false);
Writer->writeLineBreak();
Writer->writeClosingTag(L"accessor");
Writer->writeLineBreak();
Writer->writeElement(L"instance_visual_scene", true, L"url", L"#default_scene");
Writer->writeClosingTag(L"technique_common");
Writer->writeLineBreak();
Writer->writeClosingTag(L"scene");
Writer->writeClosingTag(L"source");
Writer->writeLineBreak();
}
// close everything
Writer->writeClosingTag(L"COLLADA");
Writer->drop();
delete [] globalIndices;
return true;
}
bool CColladaMeshWriter::hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) const
{
return type == video::EVT_2TCOORDS;
}
irr::core::stringw CColladaMeshWriter::toString(const irr::core::vector3df& vec) const
{
c8 tmpbuf[255];
snprintf(tmpbuf, 255, "%f %f %f", vec.X, vec.Y, vec.Z);
core::stringw str = tmpbuf;
}
return str;
}
// write tangents
irr::core::stringw CColladaMeshWriter::toString(const irr::core::vector2df& vec) const
{
c8 tmpbuf[255];
snprintf(tmpbuf, 255, "%f %f", vec.X, vec.Y);
core::stringw str = tmpbuf;
// TODO
return str;
}
// write vertices
core::stringw meshVtxId(meshId);
meshVtxId += L"-Vtx";
Writer->writeElement(L"vertices", false, L"id", meshVtxId.c_str());
Writer->writeLineBreak();
irr::core::stringw CColladaMeshWriter::toString(const irr::video::SColorf& colorf) const
{
c8 tmpbuf[255];
snprintf(tmpbuf, 255, "%f %f %f %f", colorf.getRed(), colorf.getGreen(), colorf.getBlue(), colorf.getAlpha());
core::stringw str = tmpbuf;
Writer->writeElement(L"input", true, L"semantic", L"POSITION", L"source", toRef(meshPosId).c_str());
Writer->writeLineBreak();
return str;
}
Writer->writeClosingTag(L"vertices");
Writer->writeLineBreak();
irr::core::stringw CColladaMeshWriter::toString(const irr::video::ECOLOR_FORMAT format) const
{
switch ( format )
{
case video::ECF_A1R5G5B5: return irr::core::stringw(L"A1R5G5B5");
case video::ECF_R5G6B5: return irr::core::stringw(L"R5G6B5");
case video::ECF_R8G8B8: return irr::core::stringw(L"R8G8B8");
case video::ECF_A8R8G8B8: return irr::core::stringw(L"A8R8G8B8");
default: return irr::core::stringw(L"");
}
}
// write polygons
irr::core::stringw CColladaMeshWriter::toString(const irr::video::E_TEXTURE_CLAMP clamp) const
{
switch ( clamp )
for (i=0; i<mesh->getMeshBufferCount(); ++i)
{
case video::ETC_REPEAT:
return core::stringw(L"WRAP");
case video::ETC_CLAMP:
case video::ETC_CLAMP_TO_EDGE:
return core::stringw(L"CLAMP");
case video::ETC_CLAMP_TO_BORDER:
return core::stringw(L"BORDER");
case video::ETC_MIRROR:
case video::ETC_MIRROR_CLAMP:
case video::ETC_MIRROR_CLAMP_TO_EDGE:
case video::ETC_MIRROR_CLAMP_TO_BORDER:
return core::stringw(L"MIRROR");
}
return core::stringw(L"NONE");
}
irr::core::stringw CColladaMeshWriter::toString(const irr::scene::E_COLLADA_TRANSPARENT_FX transparent) const
{
if ( transparent & ECOF_RGB_ZERO )
return core::stringw(L"RGB_ZERO");
else
return core::stringw(L"A_ONE");
}
scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
irr::core::stringw CColladaMeshWriter::minTexfilterToString(bool bilinear, bool trilinear) const
{
if ( trilinear )
return core::stringw(L"LINEAR_MIPMAP_LINEAR");
else if ( bilinear )
return core::stringw(L"LINEAR_MIPMAP_NEAREST");
return core::stringw(L"NONE");
}
const u32 polyCount = buffer->getIndexCount() / 3;
core::stringw strPolyCount(polyCount);
core::stringw strMat = "mat";
strMat += meshname;
strMat += i;
inline irr::core::stringw CColladaMeshWriter::magTexfilterToString(bool bilinear, bool trilinear) const
{
if ( bilinear || trilinear )
return core::stringw(L"LINEAR");
Writer->writeElement(L"triangles", false, L"count", strPolyCount.c_str(),
L"material", strMat.c_str());
Writer->writeLineBreak();
return core::stringw(L"NONE");
}
Writer->writeElement(L"input", true, L"semantic", L"VERTEX", L"source", toRef(meshVtxId).c_str(), L"offset", L"0");
Writer->writeLineBreak();
Writer->writeElement(L"input", true, L"semantic", L"TEXCOORD", L"source", toRef(meshTexCoord0Id).c_str(), L"offset", L"1");
Writer->writeLineBreak();
Writer->writeElement(L"input", true, L"semantic", L"NORMAL", L"source", toRef(meshNormalId).c_str(), L"offset", L"2");
Writer->writeLineBreak();
bool CColladaMeshWriter::isXmlNameStartChar(wchar_t c) const
{
return (c >= 'A' && c <= 'Z')
|| c == L'_'
|| (c >= 'a' && c <= 'z')
|| (c >= 0xC0 && c <= 0xD6)
|| (c >= 0xD8 && c <= 0xF6)
|| (c >= 0xF8 && c <= 0x2FF)
|| (c >= 0x370 && c <= 0x37D)
|| (c >= 0x37F && c <= 0x1FFF)
|| (c >= 0x200C && c <= 0x200D)
|| (c >= 0x2070 && c <= 0x218F)
|| (c >= 0x2C00 && c <= 0x2FEF)
|| (c >= 0x3001 && c <= 0xD7FF)
|| (c >= 0xF900 && c <= 0xFDCF)
|| (c >= 0xFDF0 && c <= 0xFFFD)
|| (c >= 0x10000 && c <= 0xEFFFF);
}
bool has2ndTexCoords = hasSecondTextureCoordinates(buffer->getVertexType());
if (has2ndTexCoords)
{
Writer->writeElement(L"input", true, L"semantic", L"TEXCOORD", L"source", toRef(meshTexCoord1Id).c_str(), L"idx", L"3");
Writer->writeLineBreak();
}
bool CColladaMeshWriter::isXmlNameChar(wchar_t c) const
{
return isXmlNameStartChar(c)
|| c == L'-'
|| c == L'.'
|| (c >= '0' && c <= '9')
|| c == 0xB7
|| (c >= 0x0300 && c <= 0x036F)
|| (c >= 0x203F && c <= 0x2040);
}
// write indices now
// Restrict the characters to a set of allowed characters in xs::NCName.
irr::core::stringw CColladaMeshWriter::pathToNCName(const irr::io::path& path) const
{
irr::core::stringw result(L"_NCNAME_"); // ensure id starts with a valid char and reduce chance of name-conflicts
if ( path.empty() )
return result;
s32 posIdx = globalIndices[i].PosStartIndex;
s32 tCoordIdx = globalIndices[i].TCoord0StartIndex;
s32 normalIdx = globalIndices[i].NormalStartIndex;
s32 tCoord2Idx = globalIndices[i].TCoord1StartIndex;
result.append( irr::core::stringw(path) );
Writer->writeElement(L"p", false);
// We replace all characters not allowed by a replacement char
const wchar_t REPLACMENT = L'-';
for ( irr::u32 i=1; i < result.size(); ++i )
{
if ( result[i] == L':' || !isXmlNameChar(result[i]) )
for (u32 p=0; p<polyCount; ++p)
{
result[i] = REPLACMENT;
core::stringw strP;
strP += buffer->getIndices()[(p*3) + 0] + posIdx;
strP += " ";
strP += buffer->getIndices()[(p*3) + 0] + tCoordIdx;
strP += " ";
strP += buffer->getIndices()[(p*3) + 0] + normalIdx;
strP += " ";
if (has2ndTexCoords)
{
strP += buffer->getIndices()[(p*3) + 0] + tCoord2Idx;
strP += " ";
}
strP += buffer->getIndices()[(p*3) + 1] + posIdx;
strP += " ";
strP += buffer->getIndices()[(p*3) + 1] + tCoordIdx;
strP += " ";
strP += buffer->getIndices()[(p*3) + 1] + normalIdx;
strP += " ";
if (has2ndTexCoords)
{
strP += buffer->getIndices()[(p*3) + 1] + tCoord2Idx;
strP += " ";
}
strP += buffer->getIndices()[(p*3) + 2] + posIdx;
strP += " ";
strP += buffer->getIndices()[(p*3) + 2] + tCoordIdx;
strP += " ";
strP += buffer->getIndices()[(p*3) + 2] + normalIdx;
if (has2ndTexCoords)
{
strP += " ";
strP += buffer->getIndices()[(p*3) + 2] + tCoord2Idx;
}
strP += " ";
Writer->writeText(strP.c_str());
}
Writer->writeClosingTag(L"p");
Writer->writeLineBreak();
// close index buffer section
Writer->writeClosingTag(L"triangles");
Writer->writeLineBreak();
}
return result;
// close mesh and geometry
delete [] globalIndices;
Writer->writeClosingTag(L"mesh");
Writer->writeLineBreak();
Writer->writeClosingTag(L"geometry");
Writer->writeLineBreak();
}
irr::core::stringw CColladaMeshWriter::pathToURI(const irr::io::path& path) const
void CColladaMeshWriter::writeLibraryImages()
{
irr::core::stringw result;
// is this a relative path?
if ( path.size() > 1
&& path[0] != _IRR_TEXT('/')
&& path[0] != _IRR_TEXT('\\')
&& path[1] != _IRR_TEXT(':') )
if ( getWriteTextures() && !LibraryImages.empty() )
{
// not already starting with "./" ?
if ( path[0] != _IRR_TEXT('.')
|| path[1] != _IRR_TEXT('/') )
Writer->writeElement(L"library_images", false);
Writer->writeLineBreak();
for ( irr::u32 i=0; i<LibraryImages.size(); ++i )
{
result.append(L"./");
irr::io::path p(FileSystem->getRelativeFilename(LibraryImages[i]->getName().getPath(), Directory));
//<image name="rose01">
irr::core::stringw ncname(pathToNCName(p));
Writer->writeElement(L"image", false, L"id", ncname.c_str(), L"name", ncname.c_str());
Writer->writeLineBreak();
// <init_from>../flowers/rose01.jpg</init_from>
Writer->writeElement(L"init_from", false);
Writer->writeText(pathToURI(p).c_str());
Writer->writeClosingTag(L"init_from");
Writer->writeLineBreak();
// </image>
Writer->writeClosingTag(L"image");
Writer->writeLineBreak();
}
}
result.append(path);
// TODO: make correct URI (without whitespaces)
return result;
Writer->writeClosingTag(L"library_images");
Writer->writeLineBreak();
}
}
void CColladaMeshWriter::writeColorElement(const video::SColor & col)
......@@ -1113,33 +1433,14 @@ s32 CColladaMeshWriter::getTextureIdx(const video::SMaterial & material, E_COLLA
|| !getProperties() )
return -1;
s32 idx = -1;
switch ( cs )
{
case ECS_DIFFUSE:
idx = getProperties()->getDiffuseTextureIdx(material);
break;
case ECS_AMBIENT:
idx = getProperties()->getAmbientTextureIdx(material);
break;
case ECS_EMISSIVE:
idx = getProperties()->getEmissiveTextureIdx(material);
break;
case ECS_SPECULAR:
idx = getProperties()->getSpecularTextureIdx(material);
break;
case ECS_TRANSPARENT:
idx = getProperties()->getTransparentTextureIdx(material);
break;
}
s32 idx = getProperties()->getTextureIdx(material, cs);
if ( idx >= 0 && !material.TextureLayer[idx].Texture )
return -1;
return idx;
}
bool CColladaMeshWriter::writeTextureSampler(s32 textureIdx)
bool CColladaMeshWriter::writeTextureSampler(const irr::core::stringw& meshname, s32 textureIdx)
{
if ( textureIdx < 0 )
return false;
......@@ -1149,13 +1450,16 @@ bool CColladaMeshWriter::writeTextureSampler(s32 textureIdx)
sampler += L"-sampler";
// <texture texture="sampler" texcoord="texCoord"/>
Writer->writeElement(L"texture", true, L"texture", sampler.c_str(), L"texcoord", L"mesh-TexCoord0" );
core::stringw meshTexCoordId("mesh-");
meshTexCoordId += meshname;
meshTexCoordId += L"-TexCoord0"; // TODO: need to handle second UV-set
Writer->writeElement(L"texture", true, L"texture", sampler.c_str(), L"texcoord", meshTexCoordId.c_str() );
Writer->writeLineBreak();
return true;
}
void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COLLADA_TECHNIQUE_FX techFx)
void CColladaMeshWriter::writeFxElement(const irr::core::stringw& meshname, const video::SMaterial & material, E_COLLADA_TECHNIQUE_FX techFx)
{
core::stringw fxLabel;
bool writeEmission = true;
......@@ -1199,7 +1503,7 @@ void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COL
{
Writer->writeElement(L"emission", false);
Writer->writeLineBreak();
if ( !writeTextureSampler( getTextureIdx(material, ECS_EMISSIVE)) )
if ( !writeTextureSampler( meshname, getTextureIdx(material, ECCS_EMISSIVE)) )
writeColorElement(material.EmissiveColor);
Writer->writeClosingTag(L"emission");
Writer->writeLineBreak();
......@@ -1209,7 +1513,7 @@ void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COL
{
Writer->writeElement(L"ambient", false);
Writer->writeLineBreak();
if ( !writeTextureSampler( getTextureIdx(material, ECS_AMBIENT)) )
if ( !writeTextureSampler( meshname, getTextureIdx(material, ECCS_AMBIENT)) )
writeColorElement(material.AmbientColor);
Writer->writeClosingTag(L"ambient");
Writer->writeLineBreak();
......@@ -1219,7 +1523,7 @@ void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COL
{
Writer->writeElement(L"diffuse", false);
Writer->writeLineBreak();
if ( !writeTextureSampler( getTextureIdx(material, ECS_DIFFUSE)) )
if ( !writeTextureSampler( meshname, getTextureIdx(material, ECCS_DIFFUSE)) )
writeColorElement(material.DiffuseColor);
Writer->writeClosingTag(L"diffuse");
Writer->writeLineBreak();
......@@ -1229,7 +1533,7 @@ void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COL
{
Writer->writeElement(L"specular", false);
Writer->writeLineBreak();
if ( !writeTextureSampler( getTextureIdx(material, ECS_SPECULAR)) )
if ( !writeTextureSampler( meshname, getTextureIdx(material, ECCS_SPECULAR)) )
writeColorElement(material.SpecularColor);
Writer->writeClosingTag(L"specular");
Writer->writeLineBreak();
......@@ -1255,13 +1559,13 @@ void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COL
if ( writeTransparent )
{
s32 textureIdx = getTextureIdx(material, ECS_TRANSPARENT);
s32 textureIdx = getTextureIdx(material, ECCS_TRANSPARENT);
E_COLLADA_TRANSPARENT_FX transparentFx = getProperties() ? getProperties()->getTransparentFx(material) : ECOF_A_ONE;
if ( textureIdx >= 0 || transparentFx >= ECOF_TRANSPARENT_DIFFUSE )
{
Writer->writeElement(L"transparent", false, L"opaque", toString(transparentFx).c_str());
Writer->writeLineBreak();
if ( !writeTextureSampler(textureIdx) )
if ( !writeTextureSampler(meshname, textureIdx) )
{
if ( transparentFx & ECOF_TRANSPARENT_DIFFUSE )
writeColorElement(material.DiffuseColor);
......@@ -1309,6 +1613,47 @@ void CColladaMeshWriter::writeFloatElement(irr::f32 value)
Writer->writeLineBreak();
}
void CColladaMeshWriter::writeRotateElement(const irr::core::vector3df& axis, irr::f32 angle)
{
Writer->writeElement(L"rotate", false);
irr::core::stringw txt(axis.X);
txt += L" ";
txt += irr::core::stringw(axis.Y);
txt += L" ";
txt += irr::core::stringw(axis.Z);
txt += L" ";
txt += irr::core::stringw(angle);
Writer->writeText(txt.c_str());
Writer->writeClosingTag(L"rotate");
Writer->writeLineBreak();
}
void CColladaMeshWriter::writeScaleElement(const irr::core::vector3df& scale)
{
Writer->writeElement(L"scale", false);
irr::core::stringw txt(scale.X);
txt += L" ";
txt += irr::core::stringw(scale.Y);
txt += L" ";
txt += irr::core::stringw(scale.Z);
Writer->writeText(txt.c_str());
Writer->writeClosingTag(L"scale");
Writer->writeLineBreak();
}
void CColladaMeshWriter::writeTranslateElement(const irr::core::vector3df& translate)
{
Writer->writeElement(L"translate", false);
irr::core::stringw txt(translate.X);
txt += L" ";
txt += irr::core::stringw(translate.Y);
txt += L" ";
txt += irr::core::stringw(translate.Z);
Writer->writeText(txt.c_str());
Writer->writeClosingTag(L"translate");
Writer->writeLineBreak();
}
} // end namespace
} // end namespace
......
......@@ -7,6 +7,7 @@
#include "IColladaMeshWriter.h"
#include "S3DVertex.h"
#include "irrMap.h"
#include "IVideoDriver.h"
namespace irr
......@@ -26,27 +27,9 @@ namespace scene
//! Which lighting model should be used in the technique (FX) section when exporting effects (materials)
virtual E_COLLADA_TECHNIQUE_FX getTechniqueFx(const video::SMaterial& material) const;
//! Which texture index should be used when setting the emissive texture
//! Which texture index should be used when writing the texture of the given sampler color.
/** \return the index to the texture-layer or -1 if that texture should never be exported */
virtual s32 getEmissiveTextureIdx(const video::SMaterial& material) const;
//! Which texture index should be used when setting the ambient texture
/** \return the index to the texture-layer or -1 if that texture should never be exported */
virtual s32 getAmbientTextureIdx(const video::SMaterial& material) const;
//! Which texture index should be used when setting the diffuse texture
/** \return the index to the texture-layer or -1 if that texture should never be exported */
virtual s32 getDiffuseTextureIdx(const video::SMaterial& material) const;
//! Which texture index should be used when setting the specular texture
/** \return the index to the texture-layer or -1 if that texture should never be exported */
virtual s32 getSpecularTextureIdx(const video::SMaterial& material) const;
//! Which texture index should be used when writing the transparent texture
/** Note: By default the alpha channel is used, if you want to use RGB you have to set
the ECOF_RGB_ZERO flag in getTransparentFx.
\return the index to the texture-layer or -1 if that texture should never be exported */
virtual s32 getTransparentTextureIdx( const video::SMaterial& material) const;
virtual s32 getTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs) const;
//! Return the settings for transparence
virtual E_COLLADA_TRANSPARENT_FX getTransparentFx(const video::SMaterial& material) const;
......@@ -55,6 +38,12 @@ namespace scene
/** This value is additional to transparent settings, if both are set they will be multiplicated.
\return 1.0 for fully transparent, 0.0 for not transparent and not written at all when < 0.f */
virtual f32 getTransparency(const video::SMaterial& material) const;
//! Should node be used in scene export? By default all visible nodes are exported.
virtual bool isExportable(const irr::scene::ISceneNode * node) const;
//! Return the mesh for the given nod. If it has no mesh or shouldn't export it's mesh return 0.
virtual IMesh* getMesh(irr::scene::ISceneNode * node);
};
......@@ -71,21 +60,15 @@ public:
//! Returns the type of the mesh writer
virtual EMESH_WRITER_TYPE getType() const;
//! writes a scene starting with the given node
virtual bool writeScene(io::IWriteFile* file, scene::ISceneNode* root);
//! writes a mesh
virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE);
protected:
enum E_COLLADA_COLOR_SAMPLER
{
ECS_DIFFUSE,
ECS_AMBIENT,
ECS_EMISSIVE,
ECS_SPECULAR,
ECS_TRANSPARENT
};
bool hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) const;
inline irr::core::stringw toString(const irr::core::vector3df& vec) const;
inline irr::core::stringw toString(const irr::core::vector2df& vec) const;
......@@ -93,6 +76,9 @@ protected:
inline irr::core::stringw toString(const irr::video::ECOLOR_FORMAT format) const;
inline irr::core::stringw toString(const irr::video::E_TEXTURE_CLAMP clamp) 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;
irr::core::stringw uniqueNameForMesh(const scene::IMesh* mesh) const;
irr::core::stringw uniqueNameForNode(const scene::ISceneNode* node) const;
irr::core::stringw minTexfilterToString(bool bilinear, bool trilinear) const;
irr::core::stringw magTexfilterToString(bool bilinear, bool trilinear) const;
irr::core::stringw pathToNCName(const irr::io::path& path) const;
......@@ -100,10 +86,25 @@ protected:
inline bool isXmlNameStartChar(wchar_t c) const;
inline bool isXmlNameChar(wchar_t c) const;
s32 getTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs);
void writeAsset();
void makeMeshNames(irr::scene::ISceneNode * node);
void writeNodeMaterials(irr::scene::ISceneNode * node);
void writeNodeEffects(irr::scene::ISceneNode * node);
void writeNodeGeometries(irr::scene::ISceneNode * node);
void writeSceneNode(irr::scene::ISceneNode * node);
void writeMeshMaterials(const irr::core::stringw& meshname, scene::IMesh* mesh);
void writeMeshEffects(const irr::core::stringw& meshname, scene::IMesh* mesh);
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 writeMeshInstanceGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh);
void writeLibraryImages();
void writeColorElement(const video::SColor & col);
bool writeTextureSampler(s32 textureIdx);
void writeFxElement(const video::SMaterial & material, E_COLLADA_TECHNIQUE_FX techFx);
bool writeTextureSampler(const irr::core::stringw& meshname, s32 textureIdx);
void writeFxElement(const irr::core::stringw& meshname, const video::SMaterial & material, E_COLLADA_TECHNIQUE_FX techFx);
void writeFloatElement(irr::f32 value);
void writeRotateElement(const irr::core::vector3df& axis, irr::f32 angle);
void writeScaleElement(const irr::core::vector3df& scale);
void writeTranslateElement(const irr::core::vector3df& translate);
struct SComponentGlobalStartPos
{
......@@ -131,6 +132,20 @@ protected:
io::IXMLWriter* Writer;
core::array<video::ITexture*> LibraryImages;
io::path Directory;
struct ColladaMesh
{
ColladaMesh() : MaterialWritten(false), EffectWritten(false), GeometryWritten(false)
{
}
irr::core::stringw Name;
bool MaterialWritten;
bool EffectWritten;
bool GeometryWritten;
};
typedef core::map<IMesh*, ColladaMesh>::Node MeshNode;
core::map<IMesh*, ColladaMesh> Meshes;
};
......
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