From d236d99c6cdab4567ebcc81a61e82c6a781de8f3 Mon Sep 17 00:00:00 2001 From: cutealien Date: Wed, 27 Feb 2019 20:20:38 +0000 Subject: [PATCH] Merging r5686 through r5778 from trunk to ogl-es branch. git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/branches/ogl-es@5779 dfc29bdd-3216-0410-991c-e03cc46cb475 --- source/Irrlicht/CCameraSceneNode.cpp | 12 +- source/Irrlicht/CCameraSceneNode.h | 2 + source/Irrlicht/CColladaFileLoader.cpp | 144 +-- source/Irrlicht/CColladaFileLoader.h | 4 + source/Irrlicht/CColladaMeshWriter.cpp | 1175 ++++++++++++------------ source/Irrlicht/CColladaMeshWriter.h | 116 ++- source/Irrlicht/CFileSystem.cpp | 32 +- source/Irrlicht/CFileSystem.h | 6 + source/Irrlicht/CGUIEnvironment.h | 5 +- source/Irrlicht/CIrrDeviceOSX.mm | 2 +- source/Irrlicht/CIrrMeshWriter.h | 6 +- source/Irrlicht/COpenGLCoreTexture.h | 2 - source/Irrlicht/COpenGLDriver.cpp | 9 +- source/Irrlicht/CSceneManager.h | 1 - source/Irrlicht/CSoftwareDriver.cpp | 2 +- source/Irrlicht/CXMLWriter.cpp | 263 +++++- source/Irrlicht/CXMLWriter.h | 103 ++- 17 files changed, 1073 insertions(+), 811 deletions(-) diff --git a/source/Irrlicht/CCameraSceneNode.cpp b/source/Irrlicht/CCameraSceneNode.cpp index 8786a8cd..e3ccb1ab 100644 --- a/source/Irrlicht/CCameraSceneNode.cpp +++ b/source/Irrlicht/CCameraSceneNode.cpp @@ -19,7 +19,8 @@ CCameraSceneNode::CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 i : ICameraSceneNode(parent, mgr, id, position), BoundingBox(core::vector3df(0, 0, 0)), // Camera has no size. Still not sure if FLT_MAX might be the better variant Target(lookat), UpVector(0.0f, 1.0f, 0.0f), ZNear(1.0f), ZFar(3000.0f), - InputReceiverEnabled(true), TargetAndRotationAreBound(false) + InputReceiverEnabled(true), TargetAndRotationAreBound(false), + HasD3DStyleProjectionMatrix(true) { #ifdef _DEBUG setDebugName("CCameraSceneNode"); @@ -30,8 +31,11 @@ CCameraSceneNode::CCameraSceneNode(ISceneNode* parent, ISceneManager* mgr, s32 i const video::IVideoDriver* const d = mgr?mgr->getVideoDriver():0; if (d) + { Aspect = (f32)d->getCurrentRenderTargetSize().Width / (f32)d->getCurrentRenderTargetSize().Height; + HasD3DStyleProjectionMatrix = d->getDriverType() != video::EDT_OPENGL; + } else Aspect = 4.0f / 3.0f; // Aspect ratio. @@ -230,7 +234,9 @@ void CCameraSceneNode::setFOV(f32 f) void CCameraSceneNode::recalculateProjectionMatrix() { - ViewArea.getTransform ( video::ETS_PROJECTION ).buildProjectionMatrixPerspectiveFovLH(Fovy, Aspect, ZNear, ZFar); + video::E_DRIVER_TYPE driverType = SceneManager->getVideoDriver()->getDriverType(); + ViewArea.getTransform ( video::ETS_PROJECTION ).buildProjectionMatrixPerspectiveFovLH(Fovy, Aspect, ZNear, ZFar, HasD3DStyleProjectionMatrix); + IsOrthogonal = false; } @@ -305,7 +311,7 @@ void CCameraSceneNode::recalculateViewArea() core::matrix4 m(core::matrix4::EM4CONST_NOTHING); m.setbyproduct_nocheck(ViewArea.getTransform(video::ETS_PROJECTION), ViewArea.getTransform(video::ETS_VIEW)); - ViewArea.setFrom(m); + ViewArea.setFrom(m, HasD3DStyleProjectionMatrix); } diff --git a/source/Irrlicht/CCameraSceneNode.h b/source/Irrlicht/CCameraSceneNode.h index 6f16a99b..4916a472 100644 --- a/source/Irrlicht/CCameraSceneNode.h +++ b/source/Irrlicht/CCameraSceneNode.h @@ -168,6 +168,8 @@ namespace scene bool InputReceiverEnabled; bool TargetAndRotationAreBound; + + bool HasD3DStyleProjectionMatrix; // true: projection from 0 to w; false: -w to w }; } // end namespace diff --git a/source/Irrlicht/CColladaFileLoader.cpp b/source/Irrlicht/CColladaFileLoader.cpp index 7709b20c..1e1f5247 100644 --- a/source/Irrlicht/CColladaFileLoader.cpp +++ b/source/Irrlicht/CColladaFileLoader.cpp @@ -83,7 +83,6 @@ namespace const core::stringc scaleNodeName = "scale"; const core::stringc translateNodeName = "translate"; const core::stringc skewNodeName = "skew"; - const core::stringc bboxNodeName = "boundingbox"; const core::stringc minNodeName = "min"; const core::stringc maxNodeName = "max"; const core::stringc instanceName = "instance"; @@ -645,7 +644,6 @@ void CColladaFileLoader::readSceneSection(io::IXMLReaderUTF8* reader) // read the scene core::matrix4 transform; // transformation of this node - core::aabbox3df bbox; scene::IDummyTransformationSceneNode* node = 0; while(reader->read()) @@ -673,9 +671,6 @@ void CColladaFileLoader::readSceneSection(io::IXMLReaderUTF8* reader) if (translateNodeName == reader->getNodeName()) transform *= readTranslateNode(reader); else - if (bboxNodeName == reader->getNodeName()) - readBboxNode(reader, bbox); - else if (nodeSectionName == reader->getNodeName()) { // create dummy node if there is none yet. @@ -751,7 +746,6 @@ void CColladaFileLoader::readNodeSection(io::IXMLReaderUTF8* reader, scene::ISce #endif core::matrix4 transform; // transformation of this node - core::aabbox3df bbox; scene::ISceneNode* node = 0; // instance CScenePrefab* nodeprefab = 0; // prefab for library_nodes usage @@ -792,9 +786,6 @@ void CColladaFileLoader::readNodeSection(io::IXMLReaderUTF8* reader, scene::ISce if (translateNodeName == reader->getNodeName()) transform *= readTranslateNode(reader); else - if (bboxNodeName == reader->getNodeName()) - readBboxNode(reader, bbox); - else if ((instanceName == reader->getNodeName()) || (instanceNodeName == reader->getNodeName()) || (instanceGeometryName == reader->getNodeName()) || @@ -879,10 +870,20 @@ core::matrix4 CColladaFileLoader::readLookAtNode(io::IXMLReaderUTF8* reader) f32 floats[9]; readFloatsInsideElement(reader, floats, 9); - mat.buildCameraLookAtMatrixLH( - core::vector3df(floats[0], floats[1], floats[2]), - core::vector3df(floats[3], floats[4], floats[5]), - core::vector3df(floats[6], floats[7], floats[8])); + if (FlipAxis) + { + mat.buildCameraLookAtMatrixLH( + core::vector3df(floats[0], floats[2], floats[1]), + core::vector3df(floats[3], floats[5], floats[4]), + core::vector3df(floats[6], floats[8], floats[7])); + } + else + { + mat.buildCameraLookAtMatrixLH( + core::vector3df(floats[0], floats[1], floats[2]*-1.f), + core::vector3df(floats[3], floats[4], floats[5]*-1.f), + core::vector3df(floats[6], floats[7], floats[8]*-1.f)); + } return mat; } @@ -903,6 +904,8 @@ core::matrix4 CColladaFileLoader::readSkewNode(io::IXMLReaderUTF8* reader) readFloatsInsideElement(reader, floats, 7); // build skew matrix from these 7 floats + // TODO: missing example, not sure if rotation is in correct direction. + // TODO: shouldn't FlipAxis also be regarded here? core::quaternion q; q.fromAngleAxis(floats[0]*core::DEGTORAD, core::vector3df(floats[1], floats[2], floats[3])); mat = q.getMatrix(); @@ -931,53 +934,12 @@ core::matrix4 CColladaFileLoader::readSkewNode(io::IXMLReaderUTF8* reader) mat[6]=0.f; } - return mat; + if ( FlipAxis ) + return mat; + else + return flipZAxis(mat); } - -//! reads a element and its content and stores it in bbox -void CColladaFileLoader::readBboxNode(io::IXMLReaderUTF8* reader, - core::aabbox3df& bbox) -{ - #ifdef COLLADA_READER_DEBUG - os::Printer::log("COLLADA reading boundingbox node", ELL_DEBUG); - #endif - - bbox.reset(core::aabbox3df()); - - if (reader->isEmptyElement()) - return; - - f32 floats[3]; - - while(reader->read()) - { - if (reader->getNodeType() == io::EXN_ELEMENT) - { - if (minNodeName == reader->getNodeName()) - { - readFloatsInsideElement(reader, floats, 3); - bbox.MinEdge.set(floats[0], floats[1], floats[2]); - } - else - if (maxNodeName == reader->getNodeName()) - { - readFloatsInsideElement(reader, floats, 3); - bbox.MaxEdge.set(floats[0], floats[1], floats[2]); - } - else - skipSection(reader, true); // ignore all other sections - } - else - if (reader->getNodeType() == io::EXN_ELEMENT_END) - { - if (bboxNodeName == reader->getNodeName()) - break; - } - } -} - - //! reads a element and its content and creates a matrix from it core::matrix4 CColladaFileLoader::readMatrixNode(io::IXMLReaderUTF8* reader) { @@ -990,6 +952,7 @@ core::matrix4 CColladaFileLoader::readMatrixNode(io::IXMLReaderUTF8* reader) return mat; readFloatsInsideElement(reader, mat.pointer(), 16); + // put translation into the correct place if (FlipAxis) { @@ -1008,7 +971,7 @@ core::matrix4 CColladaFileLoader::readMatrixNode(io::IXMLReaderUTF8* reader) return mat2; } else - return core::matrix4(mat, core::matrix4::EM4CONST_TRANSPOSED); + return flipZAxis(core::matrix4(mat, core::matrix4::EM4CONST_TRANSPOSED)); } @@ -1026,7 +989,7 @@ core::matrix4 CColladaFileLoader::readPerspectiveNode(io::IXMLReaderUTF8* reader f32 floats[1]; readFloatsInsideElement(reader, floats, 1); - // TODO: build perspecitve matrix from this float + // TODO: build perspective matrix from this float os::Printer::log("COLLADA loader warning: not implemented yet.", ELL_WARNING); @@ -1047,6 +1010,7 @@ core::matrix4 CColladaFileLoader::readRotateNode(io::IXMLReaderUTF8* reader) f32 floats[4]; readFloatsInsideElement(reader, floats, 4); + floats[3] *= -1.f; // to left handed rotation if (!core::iszero(floats[3])) { @@ -1054,7 +1018,7 @@ core::matrix4 CColladaFileLoader::readRotateNode(io::IXMLReaderUTF8* reader) if (FlipAxis) q.fromAngleAxis(floats[3]*core::DEGTORAD, core::vector3df(floats[0], floats[2], floats[1])); else - q.fromAngleAxis(floats[3]*core::DEGTORAD, core::vector3df(floats[0], floats[1], floats[2])); + q.fromAngleAxis(floats[3]*core::DEGTORAD, core::vector3df(floats[0], floats[1], floats[2]*-1.f)); return q.getMatrix(); } else @@ -1102,7 +1066,7 @@ core::matrix4 CColladaFileLoader::readTranslateNode(io::IXMLReaderUTF8* reader) if (FlipAxis) mat.setTranslation(core::vector3df(floats[0], floats[2], floats[1])); else - mat.setTranslation(core::vector3df(floats[0], floats[1], floats[2])); + mat.setTranslation(core::vector3df(floats[0], floats[1], floats[2]*-1.f)); return mat; } @@ -2181,7 +2145,7 @@ void CColladaFileLoader::readPolygonSection(io::IXMLReaderUTF8* reader, else { vtx.Pos.Y = localInputs[k].Data[idx+1]; - vtx.Pos.Z = localInputs[k].Data[idx+2]; + vtx.Pos.Z = localInputs[k].Data[idx+2] * -1.f; } break; case ECIS_NORMAL: @@ -2194,7 +2158,7 @@ void CColladaFileLoader::readPolygonSection(io::IXMLReaderUTF8* reader, else { vtx.Normal.Y = localInputs[k].Data[idx+1]; - vtx.Normal.Z = localInputs[k].Data[idx+2]; + vtx.Normal.Z = localInputs[k].Data[idx+2] * -1.f; } break; case ECIS_TEXCOORD: @@ -2235,26 +2199,14 @@ void CColladaFileLoader::readPolygonSection(io::IXMLReaderUTF8* reader, if (polygonsSectionName == polygonType && indices.size() > 3) { - // need to tesselate for polygons of 4 or more vertices + // need to tessellate for polygons of 4 or more vertices // for now we naively turn interpret it as a triangle fan - // as full tesselation is problematic - if (FlipAxis) + // as full tessellation is problematic + for (u32 ind = 0; ind+2 < indices.size(); ++ind) { - for (u32 ind = indices.size()-3; ind>0 ; --ind) - { - mbuffer->Indices.push_back(indices[0]); - mbuffer->Indices.push_back(indices[ind+2]); - mbuffer->Indices.push_back(indices[ind+1]); - } - } - else - { - for (u32 ind = 0; ind+2 < indices.size(); ++ind) - { - mbuffer->Indices.push_back(indices[0]); - mbuffer->Indices.push_back(indices[ind+1]); - mbuffer->Indices.push_back(indices[ind+2]); - } + mbuffer->Indices.push_back(indices[0]); + mbuffer->Indices.push_back(indices[ind+2]); + mbuffer->Indices.push_back(indices[ind+1]); } } else @@ -2262,18 +2214,9 @@ void CColladaFileLoader::readPolygonSection(io::IXMLReaderUTF8* reader, // it's just triangles for (u32 ind = 0; ind < indices.size(); ind+=3) { - if (FlipAxis) - { - mbuffer->Indices.push_back(indices[ind+2]); - mbuffer->Indices.push_back(indices[ind+1]); - mbuffer->Indices.push_back(indices[ind+0]); - } - else - { - mbuffer->Indices.push_back(indices[ind+0]); - mbuffer->Indices.push_back(indices[ind+1]); - mbuffer->Indices.push_back(indices[ind+2]); - } + mbuffer->Indices.push_back(indices[ind+2]); + mbuffer->Indices.push_back(indices[ind+1]); + mbuffer->Indices.push_back(indices[ind+0]); } } @@ -2986,6 +2929,19 @@ void CColladaFileLoader::readParameter(io::IXMLReaderUTF8* reader, io::IAttribut } } +core::matrix4 CColladaFileLoader::flipZAxis(const core::matrix4& m) +{ + core::matrix4 matrix(m); + matrix[2] *= -1.f; + matrix[6] *= -1.f; + matrix[8] *= -1.f; + matrix[9] *= -1.f; + matrix[11] *= -1.f; + matrix[14] *= -1.f; + + return matrix; +} + } // end namespace scene } // end namespace irr diff --git a/source/Irrlicht/CColladaFileLoader.h b/source/Irrlicht/CColladaFileLoader.h index a0568113..c574a27c 100644 --- a/source/Irrlicht/CColladaFileLoader.h +++ b/source/Irrlicht/CColladaFileLoader.h @@ -340,6 +340,10 @@ private: //! read a parameter and value void readParameter(io::IXMLReaderUTF8* reader, io::IAttributes* parameters); + //! Flip z axis in matrix around to convert between right-handed and left-handed coordinate system. + //! Note that function is symmetric (no difference if called before or after a transpose). + core::matrix4 flipZAxis(const core::matrix4& m); + scene::ISceneManager* SceneManager; io::IFileSystem* FileSystem; diff --git a/source/Irrlicht/CColladaMeshWriter.cpp b/source/Irrlicht/CColladaMeshWriter.cpp index 07a1878a..eb5c6a54 100644 --- a/source/Irrlicht/CColladaMeshWriter.cpp +++ b/source/Irrlicht/CColladaMeshWriter.cpp @@ -163,56 +163,56 @@ CColladaMeshWriterNames::CColladaMeshWriterNames(IColladaMeshWriter * writer) { } -irr::core::stringw CColladaMeshWriterNames::nameForMesh(const scene::IMesh* mesh, int instance) +irr::core::stringc CColladaMeshWriterNames::nameForMesh(const scene::IMesh* mesh, int instance) { - irr::core::stringw name(L"mesh"); + irr::core::stringc name("mesh"); name += nameForPtr(mesh); if ( instance > 0 ) { - name += L"i"; - name += irr::core::stringw(instance); + name += "i"; + name += irr::core::stringc(instance); } return ColladaMeshWriter->toNCName(name); } -irr::core::stringw CColladaMeshWriterNames::nameForNode(const scene::ISceneNode* node) +irr::core::stringc CColladaMeshWriterNames::nameForNode(const scene::ISceneNode* node) { - irr::core::stringw name; + irr::core::stringc name; // Prefix, because xs::ID can't start with a number, also nicer name if ( node && node->getType() == ESNT_LIGHT ) - name = L"light"; + name = "light"; else - name = L"node"; + name = "node"; name += nameForPtr(node); if ( node ) { - name += irr::core::stringw(node->getName()); + name += irr::core::stringc(node->getName()); } return ColladaMeshWriter->toNCName(name); } -irr::core::stringw CColladaMeshWriterNames::nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) +irr::core::stringc CColladaMeshWriterNames::nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) { - core::stringw strMat(L"mat"); + core::stringc strMat("mat"); bool nodeMaterial = ColladaMeshWriter->getProperties()->useNodeMaterial(node); if ( nodeMaterial ) { - strMat += L"node"; + strMat += "node"; strMat += nameForPtr(node); - strMat += irr::core::stringw(node->getName()); + strMat += irr::core::stringc(node->getName()); } - strMat += L"mesh"; + strMat += "mesh"; strMat += nameForPtr(mesh); strMat += materialId; return ColladaMeshWriter->toNCName(strMat); } -irr::core::stringw CColladaMeshWriterNames::nameForPtr(const void* ptr) const +irr::core::stringc CColladaMeshWriterNames::nameForPtr(const void* ptr) const { - wchar_t buf[32]; - swprintf_irr(buf, 32, L"%p", ptr); - return irr::core::stringw(buf); + c8 buf[32]; + snprintf_irr(buf, 32, "%p", ptr); + return irr::core::stringc(buf); } @@ -275,14 +275,14 @@ EMESH_WRITER_TYPE CColladaMeshWriter::getType() const } //! writes a scene starting with the given node -bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* root) +bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* root, int writeRoot) { if (!file || !root) return false; reset(); - Writer = FileSystem->createXMLWriter(file); + Writer = FileSystem->createXMLWriterUTF8(file); if (!Writer) { @@ -301,25 +301,25 @@ bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* roo Writer->writeXMLHeader(); - Writer->writeElement(L"COLLADA", false, - L"xmlns", L"http://www.collada.org/2005/11/COLLADASchema", - L"version", L"1.4.1"); + Writer->writeElement("COLLADA", false, + "xmlns", "http://www.collada.org/2005/11/COLLADASchema", + "version", "1.4.1"); Writer->writeLineBreak(); // write asset data writeAsset(); // write all materials - Writer->writeElement(L"library_materials", false); + Writer->writeElement("library_materials", false); Writer->writeLineBreak(); writeNodeMaterials(root); - Writer->writeClosingTag(L"library_materials"); + Writer->writeClosingTag("library_materials"); Writer->writeLineBreak(); - Writer->writeElement(L"library_effects", false); + Writer->writeElement("library_effects", false); Writer->writeLineBreak(); writeNodeEffects(root); - Writer->writeClosingTag(L"library_effects"); + Writer->writeClosingTag("library_effects"); Writer->writeLineBreak(); @@ -327,45 +327,45 @@ bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* roo writeLibraryImages(); // lights - Writer->writeElement(L"library_lights", false); + Writer->writeElement("library_lights", false); Writer->writeLineBreak(); writeAmbientLightElement( getAmbientLight() ); writeNodeLights(root); - Writer->writeClosingTag(L"library_lights"); + Writer->writeClosingTag("library_lights"); Writer->writeLineBreak(); // cameras - Writer->writeElement(L"library_cameras", false); + Writer->writeElement("library_cameras", false); Writer->writeLineBreak(); writeNodeCameras(root); - Writer->writeClosingTag(L"library_cameras"); + Writer->writeClosingTag("library_cameras"); Writer->writeLineBreak(); // write meshes - Writer->writeElement(L"library_geometries", false); + Writer->writeElement("library_geometries", false); Writer->writeLineBreak(); writeAllMeshGeometries(); - Writer->writeClosingTag(L"library_geometries"); + Writer->writeClosingTag("library_geometries"); Writer->writeLineBreak(); // write scene - Writer->writeElement(L"library_visual_scenes", false); + Writer->writeElement("library_visual_scenes", false); Writer->writeLineBreak(); - Writer->writeElement(L"visual_scene", false, L"id", L"default_scene"); + Writer->writeElement("visual_scene", false, "id", "default_scene"); Writer->writeLineBreak(); // ambient light (instance_light also needs a node as parent so we have to create one) - Writer->writeElement(L"node", false); + Writer->writeElement("node", false); Writer->writeLineBreak(); - Writer->writeElement(L"instance_light", true, L"url", L"#ambientlight"); + Writer->writeElement("instance_light", true, "url", "#ambientlight"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"node"); + Writer->writeClosingTag("node"); Writer->writeLineBreak(); // Write the scenegraph. - if ( root->getType() != ESNT_SCENE_MANAGER ) + if ( writeRoot == 2 || (writeRoot == 1 && root->getType() != ESNT_SCENE_MANAGER) ) { // TODO: Not certain if we should really write the root or if we should just always only write the children. // For now writing root to keep backward compatibility for this case, but if anyone needs to _not_ write @@ -386,26 +386,26 @@ bool CColladaMeshWriter::writeScene(io::IWriteFile* file, scene::ISceneNode* roo } - Writer->writeClosingTag(L"visual_scene"); + Writer->writeClosingTag("visual_scene"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"library_visual_scenes"); + Writer->writeClosingTag("library_visual_scenes"); Writer->writeLineBreak(); // instance scene - Writer->writeElement(L"scene", false); + Writer->writeElement("scene", false); Writer->writeLineBreak(); - Writer->writeElement(L"instance_visual_scene", true, L"url", L"#default_scene"); + Writer->writeElement("instance_visual_scene", true, "url", "#default_scene"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"scene"); + Writer->writeClosingTag("scene"); Writer->writeLineBreak(); // close everything - Writer->writeClosingTag(L"COLLADA"); + Writer->writeClosingTag("COLLADA"); Writer->drop(); return true; @@ -439,7 +439,7 @@ void CColladaMeshWriter::writeNodeMaterials(irr::scene::ISceneNode * node) if ( !node || !getProperties() || !getProperties()->isExportable(node) ) return; - core::array materialNames; + core::array materialNames; IMesh* mesh = getProperties()->getMesh(node); if ( mesh ) @@ -460,7 +460,7 @@ void CColladaMeshWriter::writeNodeMaterials(irr::scene::ISceneNode * node) for (u32 i=0; igetMaterialCount(); ++i) { video::SMaterial & material = node->getMaterial(i); - core::stringw strMat(nameForMaterial(material, i, mesh, node)); + core::stringc strMat(nameForMaterial(material, i, mesh, node)); writeMaterial(strMat); if ( getGeometryWriting() == ECGI_PER_MESH_AND_MATERIAL ) materialNames.push_back(strMat); @@ -495,26 +495,26 @@ void CColladaMeshWriter::writeNodeMaterials(irr::scene::ISceneNode * node) } } -void CColladaMeshWriter::writeMaterial(const irr::core::stringw& materialname) +void CColladaMeshWriter::writeMaterial(const irr::core::stringc& materialname) { if ( MaterialsWritten.find(materialname) ) return; MaterialsWritten.insert(materialname, true); - Writer->writeElement(L"material", false, - L"id", materialname.c_str(), - L"name", materialname.c_str()); + Writer->writeElement("material", false, + "id", materialname.c_str(), + "name", materialname.c_str()); Writer->writeLineBreak(); // We don't make a difference between material and effect on export. // Every material is just using an instance of an effect. - core::stringw strFx(materialname); - strFx += L"-fx"; - Writer->writeElement(L"instance_effect", true, - L"url", (core::stringw(L"#") + strFx).c_str()); + core::stringc strFx(materialname); + strFx += "-fx"; + Writer->writeElement("instance_effect", true, + "url", (core::stringc("#") + strFx).c_str()); Writer->writeLineBreak(); - Writer->writeClosingTag(L"material"); + Writer->writeClosingTag("material"); Writer->writeLineBreak(); } @@ -542,8 +542,8 @@ void CColladaMeshWriter::writeNodeEffects(irr::scene::ISceneNode * node) for (u32 i=0; igetMaterialCount(); ++i) { video::SMaterial & material = node->getMaterial(i); - irr::core::stringw materialfxname(nameForMaterial(material, i, mesh, node)); - materialfxname += L"-fx"; + irr::core::stringc materialfxname(nameForMaterial(material, i, mesh, node)); + materialfxname += "-fx"; writeMaterialEffect(materialfxname, material); } } @@ -570,61 +570,61 @@ void CColladaMeshWriter::writeNodeLights(irr::scene::ISceneNode * node) cLight.Name = nameForNode(node); LightNodes.insert(node, cLight); - Writer->writeElement(L"light", false, L"id", cLight.Name.c_str()); + Writer->writeElement("light", false, "id", cLight.Name.c_str()); Writer->writeLineBreak(); - Writer->writeElement(L"technique_common", false); + Writer->writeElement("technique_common", false); Writer->writeLineBreak(); switch ( lightNode->getLightType() ) { case video::ELT_POINT: - Writer->writeElement(L"point", false); + Writer->writeElement("point", false); Writer->writeLineBreak(); writeColorElement(lightData.DiffuseColor, false); - writeNode(L"constant_attenuation ", core::stringw(lightData.Attenuation.X).c_str()); - writeNode(L"linear_attenuation ", core::stringw(lightData.Attenuation.Y).c_str()); - writeNode(L"quadratic_attenuation", core::stringw(lightData.Attenuation.Z).c_str()); + writeNode("constant_attenuation ", core::stringc(lightData.Attenuation.X).c_str()); + writeNode("linear_attenuation ", core::stringc(lightData.Attenuation.Y).c_str()); + writeNode("quadratic_attenuation", core::stringc(lightData.Attenuation.Z).c_str()); - Writer->writeClosingTag(L"point"); + Writer->writeClosingTag("point"); Writer->writeLineBreak(); break; case video::ELT_SPOT: - Writer->writeElement(L"spot", false); + Writer->writeElement("spot", false); Writer->writeLineBreak(); writeColorElement(lightData.DiffuseColor, false); - writeNode(L"constant_attenuation ", core::stringw(lightData.Attenuation.X).c_str()); - writeNode(L"linear_attenuation ", core::stringw(lightData.Attenuation.Y).c_str()); - writeNode(L"quadratic_attenuation", core::stringw(lightData.Attenuation.Z).c_str()); + writeNode("constant_attenuation ", core::stringc(lightData.Attenuation.X).c_str()); + writeNode("linear_attenuation ", core::stringc(lightData.Attenuation.Y).c_str()); + writeNode("quadratic_attenuation", core::stringc(lightData.Attenuation.Z).c_str()); - writeNode(L"falloff_angle", core::stringw(lightData.OuterCone * core::RADTODEG).c_str()); - writeNode(L"falloff_exponent", core::stringw(lightData.Falloff).c_str()); + writeNode("falloff_angle", core::stringc(lightData.OuterCone * core::RADTODEG).c_str()); + writeNode("falloff_exponent", core::stringc(lightData.Falloff).c_str()); - Writer->writeClosingTag(L"spot"); + Writer->writeClosingTag("spot"); Writer->writeLineBreak(); break; case video::ELT_DIRECTIONAL: - Writer->writeElement(L"directional", false); + Writer->writeElement("directional", false); Writer->writeLineBreak(); writeColorElement(lightData.DiffuseColor, false); - Writer->writeClosingTag(L"directional"); + Writer->writeClosingTag("directional"); Writer->writeLineBreak(); break; default: break; } - Writer->writeClosingTag(L"technique_common"); + Writer->writeClosingTag("technique_common"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"light"); + Writer->writeClosingTag("light"); Writer->writeLineBreak(); } @@ -644,21 +644,21 @@ void CColladaMeshWriter::writeNodeCameras(irr::scene::ISceneNode * node) if ( isCamera(node) ) { ICameraSceneNode * cameraNode = static_cast(node); - irr::core::stringw name = nameForNode(node); + irr::core::stringc name = nameForNode(node); CameraNodes.insert(cameraNode, name); - Writer->writeElement(L"camera", false, L"id", name.c_str()); + Writer->writeElement("camera", false, "id", name.c_str()); Writer->writeLineBreak(); - Writer->writeElement(L"optics", false); + Writer->writeElement("optics", false); Writer->writeLineBreak(); - Writer->writeElement(L"technique_common", false); + Writer->writeElement("technique_common", false); Writer->writeLineBreak(); if ( cameraNode->isOrthogonal() ) { - Writer->writeElement(L"orthographic", false); + Writer->writeElement("orthographic", false); Writer->writeLineBreak(); irr::core::matrix4 projMat( cameraNode->getProjectionMatrix() ); @@ -671,35 +671,35 @@ void CColladaMeshWriter::writeNodeCameras(irr::scene::ISceneNode * node) irr::f32 zNear = projMat[14]*nearMinusFar; irr::f32 zFar = 1.f/projMat[10] + zNear; - writeNode(L"xmag", core::stringw(xmag).c_str()); - writeNode(L"ymag", core::stringw(ymag).c_str()); - writeNode(L"znear", core::stringw(zNear).c_str()); - writeNode(L"zfar", core::stringw(zFar).c_str()); + writeNode("xmag", core::stringc(xmag).c_str()); + writeNode("ymag", core::stringc(ymag).c_str()); + writeNode("znear", core::stringc(zNear).c_str()); + writeNode("zfar", core::stringc(zFar).c_str()); - Writer->writeClosingTag(L"orthographic"); + Writer->writeClosingTag("orthographic"); Writer->writeLineBreak(); } else { - Writer->writeElement(L"perspective", false); + Writer->writeElement("perspective", false); Writer->writeLineBreak(); - writeNode(L"yfov", core::stringw(cameraNode->getFOV()*core::RADTODEG).c_str()); - writeNode(L"aspect_ratio", core::stringw(cameraNode->getAspectRatio()).c_str()); - writeNode(L"znear", core::stringw(cameraNode->getNearValue()).c_str()); - writeNode(L"zfar", core::stringw(cameraNode->getFarValue()).c_str()); + writeNode("yfov", core::stringc(cameraNode->getFOV()*core::RADTODEG).c_str()); + writeNode("aspect_ratio", core::stringc(cameraNode->getAspectRatio()).c_str()); + writeNode("znear", core::stringc(cameraNode->getNearValue()).c_str()); + writeNode("zfar", core::stringc(cameraNode->getFarValue()).c_str()); - Writer->writeClosingTag(L"perspective"); + Writer->writeClosingTag("perspective"); Writer->writeLineBreak(); } - Writer->writeClosingTag(L"technique_common"); + Writer->writeClosingTag("technique_common"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"optics"); + Writer->writeClosingTag("optics"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"camera"); + Writer->writeClosingTag("camera"); Writer->writeLineBreak(); } @@ -738,8 +738,8 @@ void CColladaMeshWriter::writeSceneNode(irr::scene::ISceneNode * node ) return; // 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(nameForNode(node)); - Writer->writeElement(L"node", false, L"id", nameId.c_str()); + irr::core::stringc nameId(nameForNode(node)); + Writer->writeElement("node", false, "id", nameId.c_str()); Writer->writeLineBreak(); // DummyTransformationSceneNode don't have rotation, position, scale information @@ -809,7 +809,7 @@ void CColladaMeshWriter::writeSceneNode(irr::scene::ISceneNode * node ) writeSceneNode( *it ); } - Writer->writeClosingTag(L"node"); + Writer->writeClosingTag("node"); Writer->writeLineBreak(); } @@ -821,7 +821,7 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 reset(); - Writer = FileSystem->createXMLWriter(file); + Writer = FileSystem->createXMLWriterUTF8(file); if (!Writer) { @@ -837,9 +837,9 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 Writer->writeXMLHeader(); - Writer->writeElement(L"COLLADA", false, - L"xmlns", L"http://www.collada.org/2005/11/COLLADASchema", - L"version", L"1.4.1"); + Writer->writeElement("COLLADA", false, + "xmlns", "http://www.collada.org/2005/11/COLLADASchema", + "version", "1.4.1"); Writer->writeLineBreak(); // write asset data @@ -847,20 +847,20 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 // write all materials - Writer->writeElement(L"library_materials", false); + Writer->writeElement("library_materials", false); Writer->writeLineBreak(); writeMeshMaterials(mesh); - Writer->writeClosingTag(L"library_materials"); + Writer->writeClosingTag("library_materials"); Writer->writeLineBreak(); - Writer->writeElement(L"library_effects", false); + Writer->writeElement("library_effects", false); Writer->writeLineBreak(); writeMeshEffects(mesh); - Writer->writeClosingTag(L"library_effects"); + Writer->writeClosingTag("library_effects"); Writer->writeLineBreak(); // images @@ -868,69 +868,69 @@ bool CColladaMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 // write mesh - Writer->writeElement(L"library_geometries", false); + Writer->writeElement("library_geometries", false); Writer->writeLineBreak(); - irr::core::stringw meshname(nameForMesh(mesh, 0)); + irr::core::stringc meshname(nameForMesh(mesh, 0)); writeMeshGeometry(meshname, mesh); - Writer->writeClosingTag(L"library_geometries"); + Writer->writeClosingTag("library_geometries"); Writer->writeLineBreak(); // write scene_library if ( getWriteDefaultScene() ) { - Writer->writeElement(L"library_visual_scenes", false); + Writer->writeElement("library_visual_scenes", false); Writer->writeLineBreak(); - Writer->writeElement(L"visual_scene", false, L"id", L"default_scene"); + Writer->writeElement("visual_scene", false, "id", "default_scene"); Writer->writeLineBreak(); - Writer->writeElement(L"node", false); + Writer->writeElement("node", false); Writer->writeLineBreak(); writeMeshInstanceGeometry(meshname, mesh); - Writer->writeClosingTag(L"node"); + Writer->writeClosingTag("node"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"visual_scene"); + Writer->writeClosingTag("visual_scene"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"library_visual_scenes"); + Writer->writeClosingTag("library_visual_scenes"); Writer->writeLineBreak(); // write scene - Writer->writeElement(L"scene", false); + Writer->writeElement("scene", false); Writer->writeLineBreak(); - Writer->writeElement(L"instance_visual_scene", true, L"url", L"#default_scene"); + Writer->writeElement("instance_visual_scene", true, "url", "#default_scene"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"scene"); + Writer->writeClosingTag("scene"); Writer->writeLineBreak(); } // close everything - Writer->writeClosingTag(L"COLLADA"); + Writer->writeClosingTag("COLLADA"); Writer->drop(); return true; } -void CColladaMeshWriter::writeMeshInstanceGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh, scene::ISceneNode* node) +void CColladaMeshWriter::writeMeshInstanceGeometry(const irr::core::stringc& meshname, scene::IMesh* mesh, scene::ISceneNode* node) { // - Writer->writeElement(L"instance_geometry", false, L"url", toRef(meshname).c_str()); + Writer->writeElement("instance_geometry", false, "url", toRef(meshname).c_str()); Writer->writeLineBreak(); - Writer->writeElement(L"bind_material", false); + Writer->writeElement("bind_material", false); Writer->writeLineBreak(); - Writer->writeElement(L"technique_common", false); + Writer->writeElement("technique_common", false); Writer->writeLineBreak(); // instance materials @@ -938,41 +938,41 @@ void CColladaMeshWriter::writeMeshInstanceGeometry(const irr::core::stringw& mes bool useNodeMaterials = node && node->getMaterialCount() == mesh->getMeshBufferCount(); for (u32 i=0; igetMeshBufferCount(); ++i) { - irr::core::stringw strMatSymbol(nameForMaterialSymbol(mesh, i)); - core::stringw strMatTarget = "#"; + irr::core::stringc strMatSymbol(nameForMaterialSymbol(mesh, i)); + core::stringc strMatTarget = "#"; video::SMaterial & material = useNodeMaterials ? node->getMaterial(i) : mesh->getMeshBuffer(i)->getMaterial(); strMatTarget += nameForMaterial(material, i, mesh, node); - Writer->writeElement(L"instance_material", false, L"symbol", strMatSymbol.c_str(), L"target", strMatTarget.c_str()); + Writer->writeElement("instance_material", false, "symbol", strMatSymbol.c_str(), "target", strMatTarget.c_str()); Writer->writeLineBreak(); // TODO: need to handle second UV-set // - Writer->writeElement(L"bind_vertex_input", true, L"semantic", L"uv", L"input_semantic", L"TEXCOORD", L"input_set", L"0" ); + Writer->writeElement("bind_vertex_input", true, "semantic", "uv", "input_semantic", "TEXCOORD", "input_set", "0" ); Writer->writeLineBreak(); - Writer->writeClosingTag(L"instance_material"); + Writer->writeClosingTag("instance_material"); Writer->writeLineBreak(); } - Writer->writeClosingTag(L"technique_common"); + Writer->writeClosingTag("technique_common"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"bind_material"); + Writer->writeClosingTag("bind_material"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"instance_geometry"); + Writer->writeClosingTag("instance_geometry"); Writer->writeLineBreak(); } -void CColladaMeshWriter::writeLightInstance(const irr::core::stringw& lightName) +void CColladaMeshWriter::writeLightInstance(const irr::core::stringc& lightName) { - Writer->writeElement(L"instance_light", true, L"url", toRef(lightName).c_str()); + Writer->writeElement("instance_light", true, "url", toRef(lightName).c_str()); Writer->writeLineBreak(); } -void CColladaMeshWriter::writeCameraInstance(const irr::core::stringw& cameraName) +void CColladaMeshWriter::writeCameraInstance(const irr::core::stringc& cameraName) { - Writer->writeElement(L"instance_camera", true, L"url", toRef(cameraName).c_str()); + Writer->writeElement("instance_camera", true, "url", toRef(cameraName).c_str()); Writer->writeLineBreak(); } @@ -983,83 +983,107 @@ bool CColladaMeshWriter::hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) void CColladaMeshWriter::writeVector(const irr::core::vector3df& vec) { - wchar_t tmpbuf[255]; - swprintf_irr(tmpbuf, 255, L"%f %f %f", vec.X, vec.Y, vec.Z); + c8 tmpbuf[255]; - Writer->writeText(tmpbuf); + snprintf_irr(tmpbuf, 255, "%f", vec.X); + WriteBuffer = tmpbuf; + WriteBuffer.eraseTrailingFloatZeros(); + + snprintf_irr(tmpbuf, 255, " %f", vec.Y); + WriteBuffer.append(tmpbuf); + WriteBuffer.eraseTrailingFloatZeros(); + + snprintf_irr(tmpbuf, 255, " %f", vec.Z*-1.f); // change handedness + WriteBuffer.append(tmpbuf); + WriteBuffer.eraseTrailingFloatZeros(); + + Writer->writeText(WriteBuffer.c_str()); } void CColladaMeshWriter::writeUv(const irr::core::vector2df& vec) { - // change handedness - wchar_t tmpbuf[255]; - swprintf_irr(tmpbuf, 255, L"%f %f", vec.X, 1.f-vec.Y); + c8 tmpbuf[255]; - Writer->writeText(tmpbuf); -} + snprintf_irr(tmpbuf, 255, "%f", vec.X); + WriteBuffer = tmpbuf; + WriteBuffer.eraseTrailingFloatZeros(); -void CColladaMeshWriter::writeVector(const irr::core::vector2df& vec) -{ - wchar_t tmpbuf[255]; - swprintf_irr(tmpbuf, 255, L"%f %f", vec.X, vec.Y); + snprintf_irr(tmpbuf, 255, " %f", 1.f-vec.Y); // change handedness + WriteBuffer.append(tmpbuf); + WriteBuffer.eraseTrailingFloatZeros(); - Writer->writeText(tmpbuf); + Writer->writeText(WriteBuffer.c_str()); } void CColladaMeshWriter::writeColor(const irr::video::SColorf& colorf, bool writeAlpha) { - wchar_t tmpbuf[255]; - if ( writeAlpha ) - swprintf_irr(tmpbuf, 255, L"%f %f %f %f", colorf.getRed(), colorf.getGreen(), colorf.getBlue(), colorf.getAlpha()); - else - swprintf_irr(tmpbuf, 255, L"%f %f %f", colorf.getRed(), colorf.getGreen(), colorf.getBlue()); + c8 tmpbuf[255]; - Writer->writeText(tmpbuf); + snprintf_irr(tmpbuf, 255, "%f", colorf.getRed()); + WriteBuffer = tmpbuf; + WriteBuffer.eraseTrailingFloatZeros(); + + snprintf_irr(tmpbuf, 255, " %f", colorf.getGreen()); + WriteBuffer.append(tmpbuf); + WriteBuffer.eraseTrailingFloatZeros(); + + snprintf_irr(tmpbuf, 255, " %f", colorf.getBlue()); + WriteBuffer.append(tmpbuf); + WriteBuffer.eraseTrailingFloatZeros(); + + if ( writeAlpha ) + { + snprintf_irr(tmpbuf, 255, " %f", colorf.getAlpha()); + WriteBuffer.append(tmpbuf); + WriteBuffer.eraseTrailingFloatZeros(); + } + + Writer->writeText(WriteBuffer.c_str()); } -irr::core::stringw CColladaMeshWriter::toString(const irr::video::ECOLOR_FORMAT format) const +irr::core::stringc 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""); + case video::ECF_A1R5G5B5: return irr::core::stringc("A1R5G5B5"); + case video::ECF_R5G6B5: return irr::core::stringc("R5G6B5"); + case video::ECF_R8G8B8: return irr::core::stringc("R8G8B8"); + case video::ECF_A8R8G8B8: return irr::core::stringc("A8R8G8B8"); + default: return irr::core::stringc(""); } } -irr::core::stringw CColladaMeshWriter::toString(const irr::video::E_TEXTURE_CLAMP clamp) const +irr::core::stringc CColladaMeshWriter::toString(const irr::video::E_TEXTURE_CLAMP clamp) const { switch ( clamp ) { case video::ETC_REPEAT: - return core::stringw(L"WRAP"); + return core::stringc("WRAP"); case video::ETC_CLAMP: case video::ETC_CLAMP_TO_EDGE: - return core::stringw(L"CLAMP"); + return core::stringc("CLAMP"); case video::ETC_CLAMP_TO_BORDER: - return core::stringw(L"BORDER"); + return core::stringc("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::stringc("MIRROR"); } - return core::stringw(L"NONE"); + return core::stringc("NONE"); } -irr::core::stringw CColladaMeshWriter::toString(const irr::scene::E_COLLADA_TRANSPARENT_FX transparent) const +irr::core::stringc CColladaMeshWriter::toString(const irr::scene::E_COLLADA_TRANSPARENT_FX transparent) const { if ( transparent & ECOF_RGB_ZERO ) - return core::stringw(L"RGB_ZERO"); + return core::stringc("RGB_ZERO"); else - return core::stringw(L"A_ONE"); + return core::stringc("A_ONE"); } -irr::core::stringw CColladaMeshWriter::toRef(const irr::core::stringw& source) const +irr::core::stringc CColladaMeshWriter::toRef(const irr::core::stringc& source) const { - irr::core::stringw ref(L"#"); + irr::core::stringc ref("#"); ref += source; return ref; } @@ -1074,29 +1098,29 @@ bool CColladaMeshWriter::isCamera(const scene::ISceneNode* node) const return false; } -irr::core::stringw CColladaMeshWriter::nameForMesh(const scene::IMesh* mesh, int instance) const +irr::core::stringc CColladaMeshWriter::nameForMesh(const scene::IMesh* mesh, int instance) const { IColladaMeshWriterNames * nameGenerator = getNameGenerator(); if ( nameGenerator ) { return nameGenerator->nameForMesh(mesh, instance); } - return irr::core::stringw(L"missing_name_generator"); + return irr::core::stringc("missing_name_generator"); } -irr::core::stringw CColladaMeshWriter::nameForNode(const scene::ISceneNode* node) const +irr::core::stringc CColladaMeshWriter::nameForNode(const scene::ISceneNode* node) const { IColladaMeshWriterNames * nameGenerator = getNameGenerator(); if ( nameGenerator ) { return nameGenerator->nameForNode(node); } - return irr::core::stringw(L"missing_name_generator"); + return irr::core::stringc("missing_name_generator"); } -irr::core::stringw CColladaMeshWriter::nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) +irr::core::stringc CColladaMeshWriter::nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) { - irr::core::stringw matName; + irr::core::stringc matName; if ( getExportSMaterialsOnlyOnce() ) { matName = findCachedMaterialName(material); @@ -1110,7 +1134,7 @@ irr::core::stringw CColladaMeshWriter::nameForMaterial(const video::SMaterial & matName = nameGenerator->nameForMaterial(material, materialId, mesh, node); } else - matName = irr::core::stringw(L"missing_name_generator"); + matName = irr::core::stringc("missing_name_generator"); if ( getExportSMaterialsOnlyOnce() ) MaterialNameCache.push_back (MaterialName(material, matName)); @@ -1118,50 +1142,52 @@ irr::core::stringw CColladaMeshWriter::nameForMaterial(const video::SMaterial & } // Each mesh-material has one symbol which is replaced on instantiation -irr::core::stringw CColladaMeshWriter::nameForMaterialSymbol(const scene::IMesh* mesh, int materialId) const +irr::core::stringc CColladaMeshWriter::nameForMaterialSymbol(const scene::IMesh* mesh, int materialId) const { - wchar_t buf[100]; - swprintf_irr(buf, 100, L"mat_symb_%p_%d", mesh, materialId); - return irr::core::stringw(buf); + c8 buf[100]; + snprintf_irr(buf, 100, "mat_symb_%p_%d", mesh, materialId); + return irr::core::stringc(buf); } -irr::core::stringw CColladaMeshWriter::findCachedMaterialName(const irr::video::SMaterial& material) const +irr::core::stringc CColladaMeshWriter::findCachedMaterialName(const irr::video::SMaterial& material) const { for ( u32 i=0; i= 'A' && c <= 'Z') - || c == L'_' - || (c >= 'a' && c <= 'z') - || (c >= 0xC0 && c <= 0xD6) + return (c >= 'A' && c <= 'Z') + || c == '_' + || (c >= 'a' && c <= 'z'); + /* Following would also be legal, but only when using real unicode. + We do only check ansi codes as they are sufficient for us. + || (c >= 0xC0 && c <= 0xD6) || (c >= 0xD8 && c <= 0xF6) || (c >= 0xF8 && c <= 0x2FF) - || (c >= 0x370 && c <= 0x37D) + || (c >= 0x370 && c <= 0x37D) || (c >= 0x37F && c <= 0x1FFF) || (c >= 0x200C && c <= 0x200D) || (c >= 0x2070 && c <= 0x218F) @@ -1169,37 +1195,39 @@ bool CColladaMeshWriter::isXmlNameStartChar(wchar_t c) const || (c >= 0x3001 && c <= 0xD7FF) || (c >= 0xF900 && c <= 0xFDCF) || (c >= 0xFDF0 && c <= 0xFFFD) -#if __SIZEOF_WCHAR_T__ == 4 || __WCHAR_MAX__ > 0x10000 - || (c >= 0x10000 && c <= 0xEFFFF) -#endif + || (c >= 0x10000 && c <=0xEFFFF) +*/ ; } -bool CColladaMeshWriter::isXmlNameChar(wchar_t c) const +bool CColladaMeshWriter::isXmlNameChar(c8 c) const { return isXmlNameStartChar(c) - || c == L'-' - || c == L'.' - || (c >= '0' && c <= '9') - || c == 0xB7 - || (c >= 0x0300 && c <= 0x036F) - || (c >= 0x203F && c <= 0x2040); + || c == '-' + || c == '.' + || (c >= '0' && c <= '9'); + /* Following would also be legal, but only when using real unicode. + We do only check ansi codes for now as they are sufficient for us. + || c == 0xB7 + || (c >= 9x0300 && c <= 0x036F) + || (c >= 0x203F && c <= 0x2040) + */ } // Restrict the characters to a set of allowed characters in xs::NCName. -irr::core::stringw CColladaMeshWriter::toNCName(const irr::core::stringw& oldString, const irr::core::stringw& prefix) const +irr::core::stringc CColladaMeshWriter::toNCName(const irr::core::stringc& oldString, const irr::core::stringc& prefix) const { - irr::core::stringw result(prefix); // help to ensure id starts with a valid char and reduce chance of name-conflicts + irr::core::stringc result(prefix); // help to ensure id starts with a valid char and reduce chance of name-conflicts if ( oldString.empty() ) return result; result.append( oldString ); // We replace all characters not allowed by a replacement char - const wchar_t REPLACMENT = L'-'; + const c8 REPLACMENT = '-'; for ( irr::u32 i=1; i < result.size(); ++i ) { - if ( result[i] == L':' || !isXmlNameChar(result[i]) ) + if ( result[i] == ':' || !isXmlNameChar(result[i]) ) { result[i] = REPLACMENT; } @@ -1207,7 +1235,7 @@ irr::core::stringw CColladaMeshWriter::toNCName(const irr::core::stringw& oldStr return result; } -const irr::core::stringw* CColladaMeshWriter::findGeometryNameForNode(ISceneNode* node) +const irr::core::stringc* CColladaMeshWriter::findGeometryNameForNode(ISceneNode* node) { IMesh* mesh = getProperties()->getMesh(node); if ( !mesh ) @@ -1222,9 +1250,9 @@ const irr::core::stringw* CColladaMeshWriter::findGeometryNameForNode(ISceneNode } // Restrict the characters to a set of allowed characters in xs::NCName. -irr::core::stringw CColladaMeshWriter::pathToURI(const irr::io::path& path) const +irr::core::stringc CColladaMeshWriter::pathToURI(const irr::io::path& path) const { - irr::core::stringw result; + irr::core::stringc result; // is this a relative path? if ( path.size() > 1 @@ -1236,7 +1264,7 @@ irr::core::stringw CColladaMeshWriter::pathToURI(const irr::io::path& path) cons if ( path[0] != _IRR_TEXT('.') || path[1] != _IRR_TEXT('/') ) { - result.append(L"./"); + result.append("./"); } } result.append(path); @@ -1248,62 +1276,73 @@ irr::core::stringw CColladaMeshWriter::pathToURI(const irr::io::path& path) cons void CColladaMeshWriter::writeAsset() { - Writer->writeElement(L"asset", false); + Writer->writeElement("asset", false); Writer->writeLineBreak(); - Writer->writeElement(L"contributor", false); + Writer->writeElement("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->writeElement("authoring_tool", false); + Writer->writeText("Irrlicht Engine"); + Writer->writeClosingTag("authoring_tool"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"contributor"); + Writer->writeClosingTag("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->writeElement("created", false); + Writer->writeText("2008-01-31T00:00:00Z"); + Writer->writeClosingTag("created"); Writer->writeLineBreak(); - Writer->writeElement(L"modified", false); - Writer->writeText(L"2008-01-31T00:00:00Z"); - Writer->writeClosingTag(L"modified"); + Writer->writeElement("modified", false); + Writer->writeText("2008-01-31T00:00:00Z"); + Writer->writeClosingTag("modified"); Writer->writeLineBreak(); - Writer->writeElement(L"revision", false); - Writer->writeText(L"1.0"); - Writer->writeClosingTag(L"revision"); + // Revision 2.0 changes (since 1.0): + // - All coordinates are now written with right-handed coordinate system. + // Before only texture V of first textures was swapped and all other + // parameters where exported left-handed. + // For specific changes change svn revision 5708. + // - authoring_tool no longer mentions IrrEdit (this code has originated + // from irrEdit 0.7) to avoid conflicts as the software is now + // independent of each other and we're not aware of irrEdit revision numbers. + Writer->writeElement("revision", false); + Writer->writeText("2.0"); + Writer->writeClosingTag("revision"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"asset"); + Writer->writeElement("unit", true, "meter", core::stringc(getUnitMeter()).eraseTrailingFloatZeros().c_str(), "name", getUnitName().c_str()); + Writer->writeLineBreak(); + + Writer->writeClosingTag("asset"); Writer->writeLineBreak(); } -void CColladaMeshWriter::writeMeshMaterials(scene::IMesh* mesh, irr::core::array * materialNamesOut) +void CColladaMeshWriter::writeMeshMaterials(scene::IMesh* mesh, irr::core::array * materialNamesOut) { u32 i; for (i=0; igetMeshBufferCount(); ++i) { video::SMaterial & material = mesh->getMeshBuffer(i)->getMaterial(); - core::stringw strMat(nameForMaterial(material, i, mesh, NULL)); + core::stringc strMat(nameForMaterial(material, i, mesh, NULL)); writeMaterial(strMat); if ( materialNamesOut ) materialNamesOut->push_back(strMat); } } -void CColladaMeshWriter::writeMaterialEffect(const irr::core::stringw& materialfxname, const video::SMaterial & material) +void CColladaMeshWriter::writeMaterialEffect(const irr::core::stringc& materialfxname, const video::SMaterial & material) { if ( EffectsWritten.find(materialfxname) ) return; EffectsWritten.insert(materialfxname, true); - Writer->writeElement(L"effect", false, - L"id", materialfxname.c_str(), - L"name", materialfxname.c_str()); + Writer->writeElement("effect", false, + "id", materialfxname.c_str(), + "name", materialfxname.c_str()); Writer->writeLineBreak(); - Writer->writeElement(L"profile_COMMON", false); + Writer->writeElement("profile_COMMON", false); Writer->writeLineBreak(); int numTextures = 0; @@ -1320,83 +1359,83 @@ void CColladaMeshWriter::writeMaterialEffect(const irr::core::stringw& materialf if ( LibraryImages.linear_search(layer.Texture) < 0 ) LibraryImages.push_back( layer.Texture ); - irr::core::stringw texName("tex"); - texName += irr::core::stringw(t); + irr::core::stringc texName("tex"); + texName += irr::core::stringc(t); // write texture surface // - irr::core::stringw texSurface(texName); - texSurface += L"-surface"; - Writer->writeElement(L"newparam", false, L"sid", texSurface.c_str()); + irr::core::stringc texSurface(texName); + texSurface += "-surface"; + Writer->writeElement("newparam", false, "sid", texSurface.c_str()); Writer->writeLineBreak(); // - Writer->writeElement(L"surface", false, L"type", L"2D"); + Writer->writeElement("surface", false, "type", "2D"); Writer->writeLineBreak(); // internal_texturename - Writer->writeElement(L"init_from", false); + Writer->writeElement("init_from", false); irr::io::path p(FileSystem->getRelativeFilename(layer.Texture->getName().getPath(), Directory)); - Writer->writeText(toNCName(irr::core::stringw(p)).c_str()); - Writer->writeClosingTag(L"init_from"); + Writer->writeText(toNCName(irr::core::stringc(p)).c_str()); + Writer->writeClosingTag("init_from"); Writer->writeLineBreak(); // A8R8G8B8 - Writer->writeElement(L"format", false); + Writer->writeElement("format", false); video::ECOLOR_FORMAT format = layer.Texture->getColorFormat(); Writer->writeText(toString(format).c_str()); - Writer->writeClosingTag(L"format"); + Writer->writeClosingTag("format"); Writer->writeLineBreak(); // - Writer->writeClosingTag(L"surface"); + Writer->writeClosingTag("surface"); Writer->writeLineBreak(); // - Writer->writeClosingTag(L"newparam"); + Writer->writeClosingTag("newparam"); Writer->writeLineBreak(); // write texture sampler // - irr::core::stringw texSampler(texName); - texSampler += L"-sampler"; - Writer->writeElement(L"newparam", false, L"sid", texSampler.c_str()); + irr::core::stringc texSampler(texName); + texSampler += "-sampler"; + Writer->writeElement("newparam", false, "sid", texSampler.c_str()); Writer->writeLineBreak(); // - Writer->writeElement(L"sampler2D", false); + Writer->writeElement("sampler2D", false); Writer->writeLineBreak(); // tex0-surface - Writer->writeElement(L"source", false); + Writer->writeElement("source", false); Writer->writeText(texSurface.c_str()); - Writer->writeClosingTag(L"source"); + Writer->writeClosingTag("source"); Writer->writeLineBreak(); // WRAP - Writer->writeElement(L"wrap_s", false); + Writer->writeElement("wrap_s", false); Writer->writeText(toString((video::E_TEXTURE_CLAMP)layer.TextureWrapU).c_str()); - Writer->writeClosingTag(L"wrap_s"); + Writer->writeClosingTag("wrap_s"); Writer->writeLineBreak(); // WRAP - Writer->writeElement(L"wrap_t", false); + Writer->writeElement("wrap_t", false); Writer->writeText(toString((video::E_TEXTURE_CLAMP)layer.TextureWrapV).c_str()); - Writer->writeClosingTag(L"wrap_t"); + Writer->writeClosingTag("wrap_t"); Writer->writeLineBreak(); - // WRAP - Writer->writeElement(L"wrap_p", false); + // WRAP // TODO: Should only be written in Collada 1.5 + Writer->writeElement("wrap_p", false); Writer->writeText(toString((video::E_TEXTURE_CLAMP)layer.TextureWrapW).c_str()); - Writer->writeClosingTag(L"wrap_p"); + Writer->writeClosingTag("wrap_p"); Writer->writeLineBreak(); // LINEAR_MIPMAP_LINEAR - Writer->writeElement(L"minfilter", false); + Writer->writeElement("minfilter", false); Writer->writeText(minTexfilterToString(layer.BilinearFilter, layer.TrilinearFilter).c_str()); - Writer->writeClosingTag(L"minfilter"); + Writer->writeClosingTag("minfilter"); Writer->writeLineBreak(); // LINEAR - Writer->writeElement(L"magfilter", false); + Writer->writeElement("magfilter", false); Writer->writeText(magTexfilterToString(layer.BilinearFilter, layer.TrilinearFilter).c_str()); - Writer->writeClosingTag(L"magfilter"); + Writer->writeClosingTag("magfilter"); Writer->writeLineBreak(); // TBD - actually not sure how anisotropic should be written, so for now it writes in a way @@ -1404,32 +1443,32 @@ void CColladaMeshWriter::writeMaterialEffect(const irr::core::stringw& materialf if ( layer.AnisotropicFilter ) { // LINEAR_MIPMAP_LINEAR - Writer->writeElement(L"mipfilter", false); - Writer->writeText(L"LINEAR_MIPMAP_LINEAR"); - Writer->writeClosingTag(L"mipfilter"); + Writer->writeElement("mipfilter", false); + Writer->writeText("LINEAR_MIPMAP_LINEAR"); + Writer->writeClosingTag("mipfilter"); Writer->writeLineBreak(); } // - Writer->writeClosingTag(L"sampler2D"); + Writer->writeClosingTag("sampler2D"); Writer->writeLineBreak(); // - Writer->writeClosingTag(L"newparam"); + Writer->writeClosingTag("newparam"); Writer->writeLineBreak(); } } - Writer->writeElement(L"technique", false, L"sid", L"common"); + Writer->writeElement("technique", false, "sid", "common"); Writer->writeLineBreak(); E_COLLADA_TECHNIQUE_FX techFx = getProperties() ? getProperties()->getTechniqueFx(material) : ECTF_BLINN; writeFxElement(material, techFx); - Writer->writeClosingTag(L"technique"); + Writer->writeClosingTag("technique"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"profile_COMMON"); + Writer->writeClosingTag("profile_COMMON"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"effect"); + Writer->writeClosingTag("effect"); Writer->writeLineBreak(); } @@ -1438,19 +1477,19 @@ void CColladaMeshWriter::writeMeshEffects(scene::IMesh* mesh) for (u32 i=0; igetMeshBufferCount(); ++i) { video::SMaterial & material = mesh->getMeshBuffer(i)->getMaterial(); - irr::core::stringw materialfxname(nameForMaterial(material, i, mesh, NULL)); - materialfxname += L"-fx"; + irr::core::stringc materialfxname(nameForMaterial(material, i, mesh, NULL)); + materialfxname += "-fx"; writeMaterialEffect(materialfxname, material); } } -void CColladaMeshWriter::writeMeshGeometry(const irr::core::stringw& meshname, scene::IMesh* mesh) +void CColladaMeshWriter::writeMeshGeometry(const irr::core::stringc& meshname, scene::IMesh* mesh) { - core::stringw meshId(meshname); + core::stringc meshId(meshname); - Writer->writeElement(L"geometry", false, L"id", meshId.c_str(), L"name", meshId.c_str()); + Writer->writeElement("geometry", false, "id", meshId.c_str(), "name", meshId.c_str()); Writer->writeLineBreak(); - Writer->writeElement(L"mesh"); + Writer->writeElement("mesh"); Writer->writeLineBreak(); // do some statistics for the mesh to know which stuff needs to be saved into @@ -1475,304 +1514,215 @@ void CColladaMeshWriter::writeMeshGeometry(const irr::core::stringw& meshname, s needsTangents = mesh->getMeshBuffer(i)->getVertexType() == video::EVT_TANGENTS; } - SComponentGlobalStartPos* globalIndices = new SComponentGlobalStartPos[mesh->getMeshBufferCount()]; + const irr::u32 mbCount = mesh->getMeshBufferCount(); + SComponentGlobalStartPos* globalIndices = new SComponentGlobalStartPos[mbCount]; // write positions - core::stringw meshPosId(meshId); - meshPosId += L"-Pos"; - Writer->writeElement(L"source", false, L"id", meshPosId.c_str()); + core::stringc meshPosId(meshId); + meshPosId += "-Pos"; + Writer->writeElement("source", false, "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()); + core::stringc vertexCountStr(totalVertexCount*3); + core::stringc meshPosArrayId(meshPosId); + meshPosArrayId += "-array"; + Writer->writeElement("float_array", false, "id", meshPosArrayId.c_str(), + "count", vertexCountStr.c_str()); Writer->writeLineBreak(); - for (i=0; igetMeshBufferCount(); ++i) + for (i=0; igetMeshBuffer(i); - video::E_VERTEX_TYPE vtxType = buffer->getVertexType(); u32 vertexCount = buffer->getVertexCount(); - globalIndices[i].PosStartIndex = 0; + if ( i == 0 ) + globalIndices[i].PosStartIndex = 0; - if (i!=0) - globalIndices[i].PosStartIndex = globalIndices[i-1].PosLastIndex + 1; + if (i+1 < mbCount) + globalIndices[i+1].PosStartIndex = globalIndices[i].PosStartIndex + vertexCount; - globalIndices[i].PosLastIndex = globalIndices[i].PosStartIndex + vertexCount - 1; - - switch(vtxType) + u8* vertices = static_cast(buffer->getVertices()); + u32 vertexPitch = getVertexPitchFromType(buffer->getVertexType()); + for (u32 j=0; jgetVertices(); - for (u32 j=0; jwriteLineBreak(); - } - } - break; - case video::EVT_2TCOORDS: - { - video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices(); - for (u32 j=0; jwriteLineBreak(); - } - } - break; - case video::EVT_TANGENTS: - { - video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices(); - for (u32 j=0; jwriteLineBreak(); - } - } - break; + writeVector( (*reinterpret_cast(&vertices[j*vertexPitch])).Pos ); + Writer->writeLineBreak(); } } - Writer->writeClosingTag(L"float_array"); + Writer->writeClosingTag("float_array"); Writer->writeLineBreak(); - Writer->writeElement(L"technique_common", false); + Writer->writeElement("technique_common", false); Writer->writeLineBreak(); - vertexCountStr = core::stringw(totalVertexCount); + vertexCountStr = core::stringc(totalVertexCount); - Writer->writeElement(L"accessor", false, L"source", toRef(meshPosArrayId).c_str(), - L"count", vertexCountStr.c_str(), L"stride", L"3"); + Writer->writeElement("accessor", false, "source", toRef(meshPosArrayId).c_str(), + "count", vertexCountStr.c_str(), "stride", "3"); Writer->writeLineBreak(); - Writer->writeElement(L"param", true, L"name", L"X", L"type", L"float"); + Writer->writeElement("param", true, "name", "X", "type", "float"); Writer->writeLineBreak(); - Writer->writeElement(L"param", true, L"name", L"Y", L"type", L"float"); + Writer->writeElement("param", true, "name", "Y", "type", "float"); Writer->writeLineBreak(); - Writer->writeElement(L"param", true, L"name", L"Z", L"type", L"float"); + Writer->writeElement("param", true, "name", "Z", "type", "float"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"accessor"); + Writer->writeClosingTag("accessor"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"technique_common"); + Writer->writeClosingTag("technique_common"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"source"); + Writer->writeClosingTag("source"); Writer->writeLineBreak(); // write texture coordinates - core::stringw meshTexCoord0Id(meshId); - meshTexCoord0Id += L"-TexCoord0"; - Writer->writeElement(L"source", false, L"id", meshTexCoord0Id.c_str()); + core::stringc meshTexCoord0Id(meshId); + meshTexCoord0Id += "-TexCoord0"; + Writer->writeElement("source", false, "id", meshTexCoord0Id.c_str()); Writer->writeLineBreak(); - 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()); + vertexCountStr = core::stringc(totalVertexCount*2); + core::stringc meshTexCoordArrayId(meshTexCoord0Id); + meshTexCoordArrayId += "-array"; + Writer->writeElement("float_array", false, "id", meshTexCoordArrayId.c_str(), + "count", vertexCountStr.c_str()); Writer->writeLineBreak(); - for (i=0; igetMeshBufferCount(); ++i) + for (i=0; igetMeshBuffer(i); - video::E_VERTEX_TYPE vtxType = buffer->getVertexType(); u32 vertexCount = buffer->getVertexCount(); - globalIndices[i].TCoord0StartIndex = 0; + if (i==0) + globalIndices[i].TCoord0StartIndex = 0; - if (i!=0) - globalIndices[i].TCoord0StartIndex = globalIndices[i-1].TCoord0LastIndex + 1; + if (i+1 < mbCount) + globalIndices[i+1].TCoord0StartIndex = globalIndices[i].TCoord0StartIndex + vertexCount; - globalIndices[i].TCoord0LastIndex = globalIndices[i].TCoord0StartIndex + vertexCount - 1; - - switch(vtxType) + u8* vertices = static_cast(buffer->getVertices()); + u32 vertexPitch = getVertexPitchFromType(buffer->getVertexType()); + for (u32 j=0; jgetVertices(); - for (u32 j=0; jwriteLineBreak(); - } - } - break; - case video::EVT_2TCOORDS: - { - video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices(); - for (u32 j=0; jwriteLineBreak(); - } - } - break; - case video::EVT_TANGENTS: - { - video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices(); - for (u32 j=0; jwriteLineBreak(); - } - } - break; + writeUv( (*reinterpret_cast(&vertices[j*vertexPitch])).TCoords ); + Writer->writeLineBreak(); } } - Writer->writeClosingTag(L"float_array"); + Writer->writeClosingTag("float_array"); Writer->writeLineBreak(); - Writer->writeElement(L"technique_common", false); + Writer->writeElement("technique_common", false); Writer->writeLineBreak(); - vertexCountStr = core::stringw(totalVertexCount); + vertexCountStr = core::stringc(totalVertexCount); - Writer->writeElement(L"accessor", false, L"source", toRef(meshTexCoordArrayId).c_str(), - L"count", vertexCountStr.c_str(), L"stride", L"2"); + Writer->writeElement("accessor", false, "source", toRef(meshTexCoordArrayId).c_str(), + "count", vertexCountStr.c_str(), "stride", "2"); Writer->writeLineBreak(); - Writer->writeElement(L"param", true, L"name", L"U", L"type", L"float"); + Writer->writeElement("param", true, "name", ParamNamesUV[0].c_str(), "type", "float"); Writer->writeLineBreak(); - Writer->writeElement(L"param", true, L"name", L"V", L"type", L"float"); + Writer->writeElement("param", true, "name", ParamNamesUV[1].c_str(), "type", "float"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"accessor"); + Writer->writeClosingTag("accessor"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"technique_common"); + Writer->writeClosingTag("technique_common"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"source"); + Writer->writeClosingTag("source"); Writer->writeLineBreak(); // write normals - core::stringw meshNormalId(meshId); - meshNormalId += L"-Normal"; - Writer->writeElement(L"source", false, L"id", meshNormalId.c_str()); + core::stringc meshNormalId(meshId); + meshNormalId += "-Normal"; + Writer->writeElement("source", false, "id", meshNormalId.c_str()); Writer->writeLineBreak(); - 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()); + vertexCountStr = core::stringc(totalVertexCount*3); + core::stringc meshNormalArrayId(meshNormalId); + meshNormalArrayId += "-array"; + Writer->writeElement("float_array", false, "id", meshNormalArrayId.c_str(), + "count", vertexCountStr.c_str()); Writer->writeLineBreak(); - for (i=0; igetMeshBufferCount(); ++i) + for (i=0; igetMeshBuffer(i); - video::E_VERTEX_TYPE vtxType = buffer->getVertexType(); u32 vertexCount = buffer->getVertexCount(); - globalIndices[i].NormalStartIndex = 0; + if ( i==0 ) + globalIndices[i].NormalStartIndex = 0; - if (i!=0) - globalIndices[i].NormalStartIndex = globalIndices[i-1].NormalLastIndex + 1; + if (i+1 < mbCount) + globalIndices[i+1].NormalStartIndex = globalIndices[i].NormalStartIndex + vertexCount; - globalIndices[i].NormalLastIndex = globalIndices[i].NormalStartIndex + vertexCount - 1; - - switch(vtxType) + u8* vertices = static_cast(buffer->getVertices()); + u32 vertexPitch = getVertexPitchFromType(buffer->getVertexType()); + for (u32 j=0; jgetVertices(); - for (u32 j=0; jwriteLineBreak(); - } - } - break; - case video::EVT_2TCOORDS: - { - video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices(); - for (u32 j=0; jwriteLineBreak(); - } - } - break; - case video::EVT_TANGENTS: - { - video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices(); - for (u32 j=0; jwriteLineBreak(); - } - } - break; + writeVector( (*reinterpret_cast(&vertices[j*vertexPitch])).Normal ); + Writer->writeLineBreak(); } } - Writer->writeClosingTag(L"float_array"); + Writer->writeClosingTag("float_array"); Writer->writeLineBreak(); - Writer->writeElement(L"technique_common", false); + Writer->writeElement("technique_common", false); Writer->writeLineBreak(); - vertexCountStr = core::stringw(totalVertexCount); + vertexCountStr = core::stringc(totalVertexCount); - Writer->writeElement(L"accessor", false, L"source", toRef(meshNormalArrayId).c_str(), - L"count", vertexCountStr.c_str(), L"stride", L"3"); + Writer->writeElement("accessor", false, "source", toRef(meshNormalArrayId).c_str(), + "count", vertexCountStr.c_str(), "stride", "3"); Writer->writeLineBreak(); - Writer->writeElement(L"param", true, L"name", L"X", L"type", L"float"); + Writer->writeElement("param", true, "name", "X", "type", "float"); Writer->writeLineBreak(); - Writer->writeElement(L"param", true, L"name", L"Y", L"type", L"float"); + Writer->writeElement("param", true, "name", "Y", "type", "float"); Writer->writeLineBreak(); - Writer->writeElement(L"param", true, L"name", L"Z", L"type", L"float"); + Writer->writeElement("param", true, "name", "Z", "type", "float"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"accessor"); + Writer->writeClosingTag("accessor"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"technique_common"); + Writer->writeClosingTag("technique_common"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"source"); + Writer->writeClosingTag("source"); Writer->writeLineBreak(); // write second set of texture coordinates - core::stringw meshTexCoord1Id(meshId); - meshTexCoord1Id += L"-TexCoord1"; + core::stringc meshTexCoord1Id(meshId); + meshTexCoord1Id += "-TexCoord1"; if (totalTCoords2Count) { - Writer->writeElement(L"source", false, L"id", meshTexCoord1Id.c_str()); + Writer->writeElement("source", false, "id", meshTexCoord1Id.c_str()); Writer->writeLineBreak(); - 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()); + vertexCountStr = core::stringc(totalTCoords2Count*2); + core::stringc meshTexCoord1ArrayId(meshTexCoord1Id); + meshTexCoord1ArrayId += "-array"; + Writer->writeElement("float_array", false, "id", meshTexCoord1ArrayId.c_str(), + "count", vertexCountStr.c_str()); Writer->writeLineBreak(); - for (i=0; igetMeshBufferCount(); ++i) + for (i=0; igetMeshBuffer(i); video::E_VERTEX_TYPE vtxType = buffer->getVertexType(); - u32 vertexCount = buffer->getVertexCount(); + u32 vertexCount = 0; if (hasSecondTextureCoordinates(vtxType)) { - globalIndices[i].TCoord1StartIndex = 0; - - if (i!=0 && globalIndices[i-1].TCoord1LastIndex != -1) - globalIndices[i].TCoord1StartIndex = globalIndices[i-1].TCoord1LastIndex + 1; - - globalIndices[i].TCoord1LastIndex = globalIndices[i].TCoord1StartIndex + vertexCount - 1; - + vertexCount = buffer->getVertexCount(); switch(vtxType) { case video::EVT_2TCOORDS: @@ -1780,7 +1730,7 @@ void CColladaMeshWriter::writeMeshGeometry(const irr::core::stringw& meshname, s video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices(); for (u32 j=0; jwriteLineBreak(); } } @@ -1789,32 +1739,38 @@ void CColladaMeshWriter::writeMeshGeometry(const irr::core::stringw& meshname, s break; } } // end this buffer has 2 texture coordinates + + if ( i == 0 ) + globalIndices[i].TCoord1StartIndex = 0; + + if (i+1 < mbCount) + globalIndices[i+1].TCoord1StartIndex = globalIndices[i].TCoord1StartIndex + vertexCount; } - Writer->writeClosingTag(L"float_array"); + Writer->writeClosingTag("float_array"); Writer->writeLineBreak(); - Writer->writeElement(L"technique_common", false); + Writer->writeElement("technique_common", false); Writer->writeLineBreak(); - vertexCountStr = core::stringw(totalTCoords2Count); + vertexCountStr = core::stringc(totalTCoords2Count); - Writer->writeElement(L"accessor", false, L"source", toRef(meshTexCoord1ArrayId).c_str(), - L"count", vertexCountStr.c_str(), L"stride", L"2"); + Writer->writeElement("accessor", false, "source", toRef(meshTexCoord1ArrayId).c_str(), + "count", vertexCountStr.c_str(), "stride", "2"); Writer->writeLineBreak(); - Writer->writeElement(L"param", true, L"name", L"U", L"type", L"float"); + Writer->writeElement("param", true, "name", ParamNamesUV[0].c_str(), "type", "float"); Writer->writeLineBreak(); - Writer->writeElement(L"param", true, L"name", L"V", L"type", L"float"); + Writer->writeElement("param", true, "name", ParamNamesUV[1].c_str(), "type", "float"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"accessor"); + Writer->writeClosingTag("accessor"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"technique_common"); + Writer->writeClosingTag("technique_common"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"source"); + Writer->writeClosingTag("source"); Writer->writeLineBreak(); } @@ -1823,36 +1779,42 @@ void CColladaMeshWriter::writeMeshGeometry(const irr::core::stringw& meshname, s // TODO // write vertices - core::stringw meshVtxId(meshId); - meshVtxId += L"-Vtx"; - Writer->writeElement(L"vertices", false, L"id", meshVtxId.c_str()); + core::stringc meshVtxId(meshId); + meshVtxId += "-Vtx"; + Writer->writeElement("vertices", false, "id", meshVtxId.c_str()); Writer->writeLineBreak(); - Writer->writeElement(L"input", true, L"semantic", L"POSITION", L"source", toRef(meshPosId).c_str()); + Writer->writeElement("input", true, "semantic", "POSITION", "source", toRef(meshPosId).c_str()); Writer->writeLineBreak(); - Writer->writeClosingTag(L"vertices"); + Writer->writeClosingTag("vertices"); Writer->writeLineBreak(); // write polygons - for (i=0; igetMeshBufferCount(); ++i) + for (i=0; igetMeshBuffer(i); - const u32 polyCount = buffer->getIndexCount() / 3; - core::stringw strPolyCount(polyCount); - irr::core::stringw strMat(nameForMaterialSymbol(mesh, i)); + if ( buffer->getPrimitiveType() != EPT_TRIANGLES ) + { + os::Printer::log("Collada writer does not support non-triangle meshbuffers. Mesh: ", meshname.c_str(), ELL_WARNING); + continue; + } - Writer->writeElement(L"triangles", false, L"count", strPolyCount.c_str(), - L"material", strMat.c_str()); + const u32 polyCount = buffer->getPrimitiveCount(); + core::stringc strPolyCount(polyCount); + irr::core::stringc strMat(nameForMaterialSymbol(mesh, i)); + + Writer->writeElement("triangles", false, "count", strPolyCount.c_str(), + "material", strMat.c_str()); Writer->writeLineBreak(); - Writer->writeElement(L"input", true, L"semantic", L"VERTEX", L"source", toRef(meshVtxId).c_str(), L"offset", L"0"); + Writer->writeElement("input", true, "semantic", "VERTEX", "source", toRef(meshVtxId).c_str(), "offset", "0"); Writer->writeLineBreak(); - Writer->writeElement(L"input", true, L"semantic", L"TEXCOORD", L"source", toRef(meshTexCoord0Id).c_str(), L"offset", L"1", L"set", L"0"); + Writer->writeElement("input", true, "semantic", "TEXCOORD", "source", toRef(meshTexCoord0Id).c_str(), "offset", "1", "set", "0"); Writer->writeLineBreak(); - Writer->writeElement(L"input", true, L"semantic", L"NORMAL", L"source", toRef(meshNormalId).c_str(), L"offset", L"2"); + Writer->writeElement("input", true, "semantic", "NORMAL", "source", toRef(meshNormalId).c_str(), "offset", "2"); Writer->writeLineBreak(); bool has2ndTexCoords = hasSecondTextureCoordinates(buffer->getVertexType()); @@ -1860,77 +1822,82 @@ void CColladaMeshWriter::writeMeshGeometry(const irr::core::stringw& meshname, s { // TODO: when working on second uv-set - my suspicion is that this one should be called "TEXCOORD2" // to allow bind_vertex_input to differentiate the uv-sets. - Writer->writeElement(L"input", true, L"semantic", L"TEXCOORD", L"source", toRef(meshTexCoord1Id).c_str(), L"idx", L"3"); + Writer->writeElement("input", true, "semantic", "TEXCOORD", "source", toRef(meshTexCoord1Id).c_str(), "idx", "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; + // In Collada we us a single global buffer for all vertices, so indices have this offset compared to Irrlicht + u32 posIdx = globalIndices[i].PosStartIndex; + u32 tCoordIdx = globalIndices[i].TCoord0StartIndex; + u32 normalIdx = globalIndices[i].NormalStartIndex; + u32 tCoord2Idx = globalIndices[i].TCoord1StartIndex; - Writer->writeElement(L"p", false); + Writer->writeElement("p", false); - core::stringw strP; + core::stringc strP; strP.reserve(100); for (u32 p=0; pgetIndices()[(p*3) + 2]; strP = ""; - strP += buffer->getIndices()[(p*3) + 0] + posIdx; + strP += irrIdx + posIdx; strP += " "; - strP += buffer->getIndices()[(p*3) + 0] + tCoordIdx; + strP += irrIdx + tCoordIdx; strP += " "; - strP += buffer->getIndices()[(p*3) + 0] + normalIdx; + strP += irrIdx + normalIdx; strP += " "; if (has2ndTexCoords) { - strP += buffer->getIndices()[(p*3) + 0] + tCoord2Idx; + strP += irrIdx + tCoord2Idx; strP += " "; } - strP += buffer->getIndices()[(p*3) + 1] + posIdx; + irrIdx = buffer->getIndices()[(p*3) + 1]; + strP += irrIdx + posIdx; strP += " "; - strP += buffer->getIndices()[(p*3) + 1] + tCoordIdx; + strP += irrIdx + tCoordIdx; strP += " "; - strP += buffer->getIndices()[(p*3) + 1] + normalIdx; + strP += irrIdx + normalIdx; strP += " "; if (has2ndTexCoords) { - strP += buffer->getIndices()[(p*3) + 1] + tCoord2Idx; + strP += irrIdx + tCoord2Idx; strP += " "; } - strP += buffer->getIndices()[(p*3) + 2] + posIdx; + irrIdx = buffer->getIndices()[(p*3) + 0]; + strP += irrIdx + posIdx; strP += " "; - strP += buffer->getIndices()[(p*3) + 2] + tCoordIdx; + strP += irrIdx + tCoordIdx; strP += " "; - strP += buffer->getIndices()[(p*3) + 2] + normalIdx; + strP += irrIdx + normalIdx; if (has2ndTexCoords) { strP += " "; - strP += buffer->getIndices()[(p*3) + 2] + tCoord2Idx; + strP += irrIdx + tCoord2Idx; } strP += " "; Writer->writeText(strP.c_str()); } - Writer->writeClosingTag(L"p"); + Writer->writeClosingTag("p"); Writer->writeLineBreak(); // close index buffer section - Writer->writeClosingTag(L"triangles"); + Writer->writeClosingTag("triangles"); Writer->writeLineBreak(); } // close mesh and geometry delete [] globalIndices; - Writer->writeClosingTag(L"mesh"); + Writer->writeClosingTag("mesh"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"geometry"); + Writer->writeClosingTag("geometry"); Writer->writeLineBreak(); } @@ -1938,38 +1905,38 @@ void CColladaMeshWriter::writeLibraryImages() { if ( getWriteTextures() && !LibraryImages.empty() ) { - Writer->writeElement(L"library_images", false); + Writer->writeElement("library_images", false); Writer->writeLineBreak(); for ( irr::u32 i=0; igetRelativeFilename(LibraryImages[i]->getName().getPath(), Directory)); // - irr::core::stringw ncname( toNCName(irr::core::stringw(p)) ); - Writer->writeElement(L"image", false, L"id", ncname.c_str(), L"name", ncname.c_str()); + irr::core::stringc ncname( toNCName(irr::core::stringc(p)) ); + Writer->writeElement("image", false, "id", ncname.c_str(), "name", ncname.c_str()); Writer->writeLineBreak(); // ../flowers/rose01.jpg - Writer->writeElement(L"init_from", false); + Writer->writeElement("init_from", false); Writer->writeText(pathToURI(p).c_str()); - Writer->writeClosingTag(L"init_from"); + Writer->writeClosingTag("init_from"); Writer->writeLineBreak(); // - Writer->writeClosingTag(L"image"); + Writer->writeClosingTag("image"); Writer->writeLineBreak(); } - Writer->writeClosingTag(L"library_images"); + Writer->writeClosingTag("library_images"); Writer->writeLineBreak(); } } void CColladaMeshWriter::writeColorElement(const video::SColorf & col, bool writeAlpha) { - Writer->writeElement(L"color", false); + Writer->writeElement("color", false); writeColor(col, writeAlpha); - Writer->writeClosingTag(L"color"); + Writer->writeClosingTag("color"); Writer->writeLineBreak(); } @@ -1980,24 +1947,24 @@ void CColladaMeshWriter::writeColorElement(const video::SColor & col, bool write void CColladaMeshWriter::writeAmbientLightElement(const video::SColorf & col) { - Writer->writeElement(L"light", false, L"id", L"ambientlight"); + Writer->writeElement("light", false, "id", "ambientlight"); Writer->writeLineBreak(); - Writer->writeElement(L"technique_common", false); + Writer->writeElement("technique_common", false); Writer->writeLineBreak(); - Writer->writeElement(L"ambient", false); + Writer->writeElement("ambient", false); Writer->writeLineBreak(); writeColorElement(col, false); - Writer->writeClosingTag(L"ambient"); + Writer->writeClosingTag("ambient"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"technique_common"); + Writer->writeClosingTag("technique_common"); Writer->writeLineBreak(); - Writer->writeClosingTag(L"light"); + Writer->writeClosingTag("light"); Writer->writeLineBreak(); } @@ -2041,18 +2008,18 @@ video::SColor CColladaMeshWriter::getColorMapping(const video::SMaterial & mater void CColladaMeshWriter::writeTextureSampler(s32 textureIdx) { - irr::core::stringw sampler(L"tex"); - sampler += irr::core::stringw(textureIdx); - sampler += L"-sampler"; + irr::core::stringc sampler("tex"); + sampler += irr::core::stringc(textureIdx); + sampler += "-sampler"; // - Writer->writeElement(L"texture", true, L"texture", sampler.c_str(), L"texcoord", L"uv" ); + Writer->writeElement("texture", true, "texture", sampler.c_str(), "texcoord", "uv" ); Writer->writeLineBreak(); } void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COLLADA_TECHNIQUE_FX techFx) { - core::stringw fxLabel; + core::stringc fxLabel; bool writeEmission = true; bool writeAmbient = true; bool writeDiffuse = true; @@ -2066,18 +2033,18 @@ void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COL switch ( techFx ) { case ECTF_BLINN: - fxLabel = L"blinn"; + fxLabel = "blinn"; break; case ECTF_PHONG: - fxLabel = L"phong"; + fxLabel = "phong"; break; case ECTF_LAMBERT: - fxLabel = L"lambert"; + fxLabel = "lambert"; writeSpecular = false; writeShininess = false; break; case ECTF_CONSTANT: - fxLabel = L"constant"; + fxLabel = "constant"; writeAmbient = false; writeDiffuse = false; writeSpecular = false; @@ -2094,36 +2061,36 @@ void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COL { if ( writeEmission ) { - writeColorFx(material, L"emission", ECCS_EMISSIVE); + writeColorFx(material, "emission", ECCS_EMISSIVE); } if ( writeAmbient ) { - writeColorFx(material, L"ambient", ECCS_AMBIENT); + writeColorFx(material, "ambient", ECCS_AMBIENT); } if ( writeDiffuse ) { - writeColorFx(material, L"diffuse", ECCS_DIFFUSE); + writeColorFx(material, "diffuse", ECCS_DIFFUSE); } if ( writeSpecular ) { - writeColorFx(material, L"specular", ECCS_SPECULAR); + writeColorFx(material, "specular", ECCS_SPECULAR); } if ( writeShininess ) { - Writer->writeElement(L"shininess", false); + Writer->writeElement("shininess", false); Writer->writeLineBreak(); writeFloatElement(material.Shininess); - Writer->writeClosingTag(L"shininess"); + Writer->writeClosingTag("shininess"); Writer->writeLineBreak(); } if ( writeReflective ) { - writeColorFx(material, L"reflective", ECCS_REFLECTIVE); + writeColorFx(material, "reflective", ECCS_REFLECTIVE); } if ( writeReflectivity ) @@ -2132,10 +2099,10 @@ void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COL if ( t >= 0.f ) { // 1.000000 - Writer->writeElement(L"reflectivity", false); + Writer->writeElement("reflectivity", false); Writer->writeLineBreak(); writeFloatElement(t); - Writer->writeClosingTag(L"reflectivity"); + Writer->writeClosingTag("reflectivity"); Writer->writeLineBreak(); } } @@ -2143,7 +2110,7 @@ void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COL if ( writeTransparent ) { E_COLLADA_TRANSPARENT_FX transparentFx = getProperties()->getTransparentFx(material); - writeColorFx(material, L"transparent", ECCS_TRANSPARENT, L"opaque", toString(transparentFx).c_str()); + writeColorFx(material, "transparent", ECCS_TRANSPARENT, "opaque", toString(transparentFx).c_str()); } if ( writeTransparency ) @@ -2152,10 +2119,10 @@ void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COL if ( t >= 0.f ) { // 1.000000 - Writer->writeElement(L"transparency", false); + Writer->writeElement("transparency", false); Writer->writeLineBreak(); writeFloatElement(t); - Writer->writeClosingTag(L"transparency"); + Writer->writeClosingTag("transparency"); Writer->writeLineBreak(); } } @@ -2165,10 +2132,10 @@ void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COL f32 t = getProperties()->getIndexOfRefraction(material); if ( t >= 0.f ) { - Writer->writeElement(L"index_of_refraction", false); + Writer->writeElement("index_of_refraction", false); Writer->writeLineBreak(); writeFloatElement(t); - Writer->writeClosingTag(L"index_of_refraction"); + Writer->writeClosingTag("index_of_refraction"); Writer->writeLineBreak(); } } @@ -2179,7 +2146,7 @@ void CColladaMeshWriter::writeFxElement(const video::SMaterial & material, E_COL Writer->writeLineBreak(); } -void CColladaMeshWriter::writeColorFx(const video::SMaterial & material, const wchar_t * colorname, E_COLLADA_COLOR_SAMPLER cs, const wchar_t* attr1Name, const wchar_t* attr1Value) +void CColladaMeshWriter::writeColorFx(const video::SMaterial & material, const c8 * colorname, E_COLLADA_COLOR_SAMPLER cs, const c8* attr1Name, const c8* attr1Value) { irr::s32 idx = getCheckedTextureIdx(material, cs); E_COLLADA_IRR_COLOR colType = idx < 0 ? getProperties()->getColorMapping(material, cs) : ECIC_NONE; @@ -2196,7 +2163,7 @@ void CColladaMeshWriter::writeColorFx(const video::SMaterial & material, const w } } -void CColladaMeshWriter::writeNode(const wchar_t * nodeName, const wchar_t * content) +void CColladaMeshWriter::writeNode(const c8 * nodeName, const c8 * content) { Writer->writeElement(nodeName, false); Writer->writeText(content); @@ -2206,85 +2173,103 @@ void CColladaMeshWriter::writeNode(const wchar_t * nodeName, const wchar_t * con void CColladaMeshWriter::writeFloatElement(irr::f32 value) { - Writer->writeElement(L"float", false); - Writer->writeText(core::stringw((double)value).c_str()); - Writer->writeClosingTag(L"float"); + Writer->writeElement("float", false); + Writer->writeText(core::stringc((double)value).eraseTrailingFloatZeros().c_str()); + Writer->writeClosingTag("float"); 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((double)angle); + Writer->writeElement("rotate", false); + irr::core::stringc txt(axis.X); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc(axis.Y); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc(axis.Z * -1.f); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc((double)angle * -1.f); + txt.eraseTrailingFloatZeros(); Writer->writeText(txt.c_str()); - Writer->writeClosingTag(L"rotate"); + Writer->writeClosingTag("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->writeElement("scale", false); + irr::core::stringc txt(scale.X); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc(scale.Y); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc(scale.Z); + txt.eraseTrailingFloatZeros(); Writer->writeText(txt.c_str()); - Writer->writeClosingTag(L"scale"); + Writer->writeClosingTag("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->writeElement("translate", false); + irr::core::stringc txt(translate.X); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc(translate.Y); + txt.eraseTrailingFloatZeros(); + txt += " "; + txt += irr::core::stringc(translate.Z*-1.f); + txt.eraseTrailingFloatZeros(); Writer->writeText(txt.c_str()); - Writer->writeClosingTag(L"translate"); + Writer->writeClosingTag("translate"); Writer->writeLineBreak(); } void CColladaMeshWriter::writeLookAtElement(const irr::core::vector3df& eyePos, const irr::core::vector3df& targetPos, const irr::core::vector3df& upVector) { - Writer->writeElement(L"lookat", false); + Writer->writeElement("lookat", false); - wchar_t tmpbuf[255]; - swprintf_irr(tmpbuf, 255, L"%f %f %f %f %f %f %f %f %f", eyePos.X, eyePos.Y, eyePos.Z, targetPos.X, targetPos.Y, targetPos.Z, upVector.X, upVector.Y, upVector.Z); + c8 tmpbuf[255]; + snprintf_irr(tmpbuf, 255, "%f %f %f %f %f %f %f %f %f", eyePos.X, eyePos.Y, eyePos.Z*-1.f, targetPos.X, targetPos.Y, targetPos.Z*-1.f, upVector.X, upVector.Y, upVector.Z*-1.f); Writer->writeText(tmpbuf); - Writer->writeClosingTag(L"lookat"); + Writer->writeClosingTag("lookat"); Writer->writeLineBreak(); } -void CColladaMeshWriter::writeMatrixElement(const irr::core::matrix4& matrix) +void CColladaMeshWriter::writeMatrixElement(const irr::core::matrix4& matrixIrr) { - Writer->writeElement(L"matrix", false); + irr::core::matrix4 matrix(matrixIrr.getTransposed()); // transposed because row/lines are written other way round in Collada + // Convert to right-handed + matrix[2] *= -1.f; + matrix[6] *= -1.f; + matrix[8] *= -1.f; + matrix[9] *= -1.f; + matrix[11] *= -1.f; + matrix[14] *= -1.f; + + Writer->writeElement("matrix", false); Writer->writeLineBreak(); for ( int a=0; a<4; ++a ) { - irr::core::stringw txt; + irr::core::stringc txt; for ( int b=0; b<4; ++b ) { if ( b > 0 ) txt += " "; - // row-column switched compared to Irrlicht - txt += irr::core::stringw(matrix[b*4+a]); + txt += irr::core::stringc(matrix[a*4+b]).eraseTrailingFloatZeros(); } Writer->writeText(txt.c_str()); Writer->writeLineBreak(); } - Writer->writeClosingTag(L"matrix"); + Writer->writeClosingTag("matrix"); Writer->writeLineBreak(); } diff --git a/source/Irrlicht/CColladaMeshWriter.h b/source/Irrlicht/CColladaMeshWriter.h index 74fbb5c2..1761e53d 100644 --- a/source/Irrlicht/CColladaMeshWriter.h +++ b/source/Irrlicht/CColladaMeshWriter.h @@ -9,12 +9,12 @@ #include "S3DVertex.h" #include "irrMap.h" #include "IVideoDriver.h" +#include "IXMLWriter.h" namespace irr { namespace io { - class IXMLWriter; class IFileSystem; } @@ -63,11 +63,11 @@ namespace scene { public: CColladaMeshWriterNames(IColladaMeshWriter * writer); - virtual irr::core::stringw nameForMesh(const scene::IMesh* mesh, int instance) _IRR_OVERRIDE_; - virtual irr::core::stringw nameForNode(const scene::ISceneNode* node) _IRR_OVERRIDE_; - virtual irr::core::stringw nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) _IRR_OVERRIDE_; + virtual irr::core::stringc nameForMesh(const scene::IMesh* mesh, int instance) _IRR_OVERRIDE_; + virtual irr::core::stringc nameForNode(const scene::ISceneNode* node) _IRR_OVERRIDE_; + virtual irr::core::stringc nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node) _IRR_OVERRIDE_; protected: - irr::core::stringw nameForPtr(const void* ptr) const; + irr::core::stringc nameForPtr(const void* ptr) const; private: IColladaMeshWriter * ColladaMeshWriter; }; @@ -88,40 +88,39 @@ public: virtual EMESH_WRITER_TYPE getType() const _IRR_OVERRIDE_; //! writes a scene starting with the given node - virtual bool writeScene(io::IWriteFile* file, scene::ISceneNode* root) _IRR_OVERRIDE_; + virtual bool writeScene(io::IWriteFile* file, scene::ISceneNode* root, int writeRoot) _IRR_OVERRIDE_; //! writes a mesh virtual bool writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags=EMWF_NONE) _IRR_OVERRIDE_; // Restrict the characters of oldString a set of allowed characters in xs::NCName and add the prefix. - virtual irr::core::stringw toNCName(const irr::core::stringw& oldString, const irr::core::stringw& prefix=irr::core::stringw(L"_NC_")) const _IRR_OVERRIDE_; + virtual irr::core::stringc toNCName(const irr::core::stringc& oldString, const irr::core::stringc& prefix=irr::core::stringc("_NC_")) const _IRR_OVERRIDE_; //! After export you can find out which name had been used for writing the geometry for this node. - virtual const irr::core::stringw* findGeometryNameForNode(ISceneNode* node) _IRR_OVERRIDE_; + virtual const irr::core::stringc* findGeometryNameForNode(ISceneNode* node) _IRR_OVERRIDE_; protected: void reset(); bool hasSecondTextureCoordinates(video::E_VERTEX_TYPE type) const; void writeUv(const irr::core::vector2df& vec); - void writeVector(const irr::core::vector2df& vec); void writeVector(const irr::core::vector3df& vec); void writeColor(const irr::video::SColorf& colorf, bool writeAlpha=true); - 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; + inline irr::core::stringc toString(const irr::video::ECOLOR_FORMAT format) const; + inline irr::core::stringc toString(const irr::video::E_TEXTURE_CLAMP clamp) const; + inline irr::core::stringc toString(const irr::scene::E_COLLADA_TRANSPARENT_FX opaque) const; + inline irr::core::stringc toRef(const irr::core::stringc& source) const; bool isCamera(const scene::ISceneNode* node) const; - irr::core::stringw nameForMesh(const scene::IMesh* mesh, int instance) 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); - irr::core::stringw nameForMaterialSymbol(const scene::IMesh* mesh, int materialId) const; - irr::core::stringw findCachedMaterialName(const irr::video::SMaterial& material) const; - irr::core::stringw minTexfilterToString(bool bilinear, bool trilinear) const; - irr::core::stringw magTexfilterToString(bool bilinear, bool trilinear) const; - irr::core::stringw pathToURI(const irr::io::path& path) const; - inline bool isXmlNameStartChar(wchar_t c) const; - inline bool isXmlNameChar(wchar_t c) const; + irr::core::stringc nameForMesh(const scene::IMesh* mesh, int instance) const; + irr::core::stringc nameForNode(const scene::ISceneNode* node) const; + irr::core::stringc nameForMaterial(const video::SMaterial & material, int materialId, const scene::IMesh* mesh, const scene::ISceneNode* node); + irr::core::stringc nameForMaterialSymbol(const scene::IMesh* mesh, int materialId) const; + irr::core::stringc findCachedMaterialName(const irr::video::SMaterial& material) const; + irr::core::stringc minTexfilterToString(bool bilinear, bool trilinear) const; + irr::core::stringc magTexfilterToString(bool bilinear, bool trilinear) const; + irr::core::stringc pathToURI(const irr::io::path& path) const; + inline bool isXmlNameStartChar(c8 c) const; + inline bool isXmlNameChar(c8 c) const; s32 getCheckedTextureIdx(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs); video::SColor getColorMapping(const video::SMaterial & material, E_COLLADA_COLOR_SAMPLER cs, E_COLLADA_IRR_COLOR colType); void writeAsset(); @@ -132,22 +131,22 @@ protected: void writeNodeCameras(irr::scene::ISceneNode * node); void writeAllMeshGeometries(); void writeSceneNode(irr::scene::ISceneNode * node); - void writeMeshMaterials(scene::IMesh* mesh, irr::core::array * materialNamesOut=0); + void writeMeshMaterials(scene::IMesh* mesh, irr::core::array * materialNamesOut=0); void writeMeshEffects(scene::IMesh* mesh); - void writeMaterialEffect(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, scene::ISceneNode* node=0); - void writeMaterial(const irr::core::stringw& materialname); - void writeLightInstance(const irr::core::stringw& lightName); - void writeCameraInstance(const irr::core::stringw& cameraName); + void writeMaterialEffect(const irr::core::stringc& materialname, const video::SMaterial & material); + void writeMeshGeometry(const irr::core::stringc& meshname, scene::IMesh* mesh); + void writeMeshInstanceGeometry(const irr::core::stringc& meshname, scene::IMesh* mesh, scene::ISceneNode* node=0); + void writeMaterial(const irr::core::stringc& materialname); + void writeLightInstance(const irr::core::stringc& lightName); + void writeCameraInstance(const irr::core::stringc& cameraName); void writeLibraryImages(); - void writeColorFx(const video::SMaterial & material, const wchar_t * colorname, E_COLLADA_COLOR_SAMPLER cs, const wchar_t* attr1Name=0, const wchar_t* attr1Value=0); + void writeColorFx(const video::SMaterial & material, const c8 * colorname, E_COLLADA_COLOR_SAMPLER cs, const c8* attr1Name=0, const c8* attr1Value=0); void writeAmbientLightElement(const video::SColorf & col); void writeColorElement(const video::SColor & col, bool writeAlpha=true); void writeColorElement(const video::SColorf & col, bool writeAlpha=true); void writeTextureSampler(s32 textureIdx); void writeFxElement(const video::SMaterial & material, E_COLLADA_TECHNIQUE_FX techFx); - void writeNode(const wchar_t * nodeName, const wchar_t * content); + void writeNode(const c8 * nodeName, const c8 * content); void writeFloatElement(irr::f32 value); void writeRotateElement(const irr::core::vector3df& axis, irr::f32 angle); void writeScaleElement(const irr::core::vector3df& scale); @@ -157,35 +156,28 @@ protected: struct SComponentGlobalStartPos { - SComponentGlobalStartPos() : PosStartIndex(-1), PosLastIndex(-1), - NormalStartIndex(-1), NormalLastIndex(-1), - TCoord0StartIndex(-1), TCoord0LastIndex(-1), - TCoord1StartIndex(-1), TCoord1LastIndex(-1) + SComponentGlobalStartPos() : PosStartIndex(0), + NormalStartIndex(0), + TCoord0StartIndex(0), + TCoord1StartIndex(0) { } - s32 PosStartIndex; - s32 PosLastIndex; - - s32 NormalStartIndex; - s32 NormalLastIndex; - - s32 TCoord0StartIndex; - s32 TCoord0LastIndex; - - s32 TCoord1StartIndex; - s32 TCoord1LastIndex; + u32 PosStartIndex; + u32 NormalStartIndex; + u32 TCoord0StartIndex; + u32 TCoord1StartIndex; }; io::IFileSystem* FileSystem; video::IVideoDriver* VideoDriver; - io::IXMLWriter* Writer; + io::IXMLWriterUTF8* Writer; core::array LibraryImages; io::path Directory; // Helper struct for creating geometry copies for the ECGI_PER_MESH_AND_MATERIAL settings. struct SGeometryMeshMaterials { - bool equals(const core::array& names) const + bool equals(const core::array& names) const { if ( names.size() != MaterialNames.size() ) return false; @@ -195,8 +187,8 @@ protected: return true; } - irr::core::stringw GeometryName; // replacing the usual ColladaMesh::Name - core::array MaterialNames; // Material names exported for this instance + irr::core::stringc GeometryName; // replacing the usual ColladaMesh::Name + core::array MaterialNames; // Material names exported for this instance core::array MaterialOwners; // Nodes using this specific mesh-material combination }; @@ -207,7 +199,7 @@ protected: { } - SGeometryMeshMaterials * findGeometryMeshMaterials(const irr::core::array materialNames) + SGeometryMeshMaterials * findGeometryMeshMaterials(const irr::core::array materialNames) { for ( irr::u32 i=0; i::Node LightNode; core::map LightNodes; // structure for the camera library - typedef core::map::Node CameraNode; - core::map CameraNodes; + typedef core::map::Node CameraNode; + core::map CameraNodes; // 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 MaterialsWritten; - core::map EffectsWritten; + core::map MaterialsWritten; + core::map EffectsWritten; // Cache material names struct MaterialName { - MaterialName(const irr::video::SMaterial & material, const irr::core::stringw& name) + MaterialName(const irr::video::SMaterial & material, const irr::core::stringc& name) : Material(material), Name(name) {} irr::video::SMaterial Material; - irr::core::stringw Name; + irr::core::stringc Name; }; irr::core::array< MaterialName > MaterialNameCache; + + irr::core::stringc WriteBuffer; // use for writing short strings to avoid regular memory allocations }; diff --git a/source/Irrlicht/CFileSystem.cpp b/source/Irrlicht/CFileSystem.cpp index 5993f557..6e336b91 100644 --- a/source/Irrlicht/CFileSystem.cpp +++ b/source/Irrlicht/CFileSystem.cpp @@ -1070,7 +1070,37 @@ IXMLWriter* CFileSystem::createXMLWriter(const io::path& filename) IXMLWriter* CFileSystem::createXMLWriter(IWriteFile* file) { #ifdef _IRR_COMPILE_WITH_XML_ - return new CXMLWriter(file); + return createIXMLWriter(file); +#else + noXML(); + return 0; +#endif +} + +//! Creates a XML Writer from a file. +IXMLWriterUTF8* CFileSystem::createXMLWriterUTF8(const io::path& filename) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + IWriteFile* file = createAndWriteFile(filename); + IXMLWriterUTF8* writer = 0; + if (file) + { + writer = createXMLWriterUTF8(file); + file->drop(); + } + return writer; +#else + noXML(); + return 0; +#endif +} + + +//! Creates a XML Writer from a file. +IXMLWriterUTF8* CFileSystem::createXMLWriterUTF8(IWriteFile* file) +{ +#ifdef _IRR_COMPILE_WITH_XML_ + return createIXMLWriterUTF8(file); #else noXML(); return 0; diff --git a/source/Irrlicht/CFileSystem.h b/source/Irrlicht/CFileSystem.h index 5c542b36..87c51340 100644 --- a/source/Irrlicht/CFileSystem.h +++ b/source/Irrlicht/CFileSystem.h @@ -145,6 +145,12 @@ public: //! Creates a XML Writer from a file. virtual IXMLWriter* createXMLWriter(IWriteFile* file) _IRR_OVERRIDE_; + //! Creates a XML Writer from a file which will write ASCII/UTF-8 characters (char*). + virtual IXMLWriterUTF8* createXMLWriterUTF8(const path& filename) _IRR_OVERRIDE_; + + //! Creates a XML Writer from a file which will write ASCII/UTF-8 characters (char*). + virtual IXMLWriterUTF8* createXMLWriterUTF8(IWriteFile* file) _IRR_OVERRIDE_; + //! Creates a new empty collection of attributes, usable for serialization and more. virtual IAttributes* createEmptyAttributes(video::IVideoDriver* driver) _IRR_OVERRIDE_; diff --git a/source/Irrlicht/CGUIEnvironment.h b/source/Irrlicht/CGUIEnvironment.h index 0ac22157..58b7f545 100644 --- a/source/Irrlicht/CGUIEnvironment.h +++ b/source/Irrlicht/CGUIEnvironment.h @@ -16,10 +16,7 @@ namespace irr { -namespace io -{ - class IXMLWriter; -} + namespace gui { diff --git a/source/Irrlicht/CIrrDeviceOSX.mm b/source/Irrlicht/CIrrDeviceOSX.mm index 39842820..c2ae7e51 100644 --- a/source/Irrlicht/CIrrDeviceOSX.mm +++ b/source/Irrlicht/CIrrDeviceOSX.mm @@ -577,7 +577,7 @@ CIrrDeviceMacOSX::CIrrDeviceMacOSX(const SIrrlichtCreationParameters& param) if (!CreationParams.WindowId) { [[NSAutoreleasePool alloc] init]; - [NSApplication sharedApplication]; + [[NSApplication sharedApplication] activateIgnoringOtherApps:YES]; [NSApp setDelegate:(id)[[[CIrrDelegateOSX alloc] initWithDevice:this] autorelease]]; // Create menu diff --git a/source/Irrlicht/CIrrMeshWriter.h b/source/Irrlicht/CIrrMeshWriter.h index 60237b60..c69d8bfd 100644 --- a/source/Irrlicht/CIrrMeshWriter.h +++ b/source/Irrlicht/CIrrMeshWriter.h @@ -9,13 +9,11 @@ #include "S3DVertex.h" #include "IVideoDriver.h" #include "IFileSystem.h" +#include "IXMLWriter.h" namespace irr { -namespace io -{ - class IXMLWriter; -} + namespace scene { class IMeshBuffer; diff --git a/source/Irrlicht/COpenGLCoreTexture.h b/source/Irrlicht/COpenGLCoreTexture.h index 8635b468..dfe81f41 100644 --- a/source/Irrlicht/COpenGLCoreTexture.h +++ b/source/Irrlicht/COpenGLCoreTexture.h @@ -203,8 +203,6 @@ public: virtual ~COpenGLCoreTexture() { - Driver->getCacheHandler()->getTextureCache().remove(this); - if (TextureName) glDeleteTextures(1, &TextureName); diff --git a/source/Irrlicht/COpenGLDriver.cpp b/source/Irrlicht/COpenGLDriver.cpp index 95467829..37ae1099 100644 --- a/source/Irrlicht/COpenGLDriver.cpp +++ b/source/Irrlicht/COpenGLDriver.cpp @@ -3584,10 +3584,11 @@ void COpenGLDriver::draw3DLine(const core::vector3df& start, //! Removes a texture from the texture cache and deletes it, freeing lot of memory. void COpenGLDriver::removeTexture(ITexture* texture) { - if (!texture) - return; - - CNullDriver::removeTexture(texture); + if (texture) + { + CacheHandler->getTextureCache().remove(texture); + CNullDriver::removeTexture(texture); + } } //! Check if the driver supports creating textures with the given color format diff --git a/source/Irrlicht/CSceneManager.h b/source/Irrlicht/CSceneManager.h index c145dd65..26afb921 100644 --- a/source/Irrlicht/CSceneManager.h +++ b/source/Irrlicht/CSceneManager.h @@ -18,7 +18,6 @@ namespace irr { namespace io { - class IXMLWriter; class IFileSystem; } namespace scene diff --git a/source/Irrlicht/CSoftwareDriver.cpp b/source/Irrlicht/CSoftwareDriver.cpp index ffe22f97..c1b8140c 100644 --- a/source/Irrlicht/CSoftwareDriver.cpp +++ b/source/Irrlicht/CSoftwareDriver.cpp @@ -491,7 +491,7 @@ void CSoftwareDriver::drawClippedIndexedTriangleListT(const VERTEXTYPE* vertices worldinv.makeInverse(); // calculate view frustum planes - scene::SViewFrustum frustum(TransformationMatrix[ETS_PROJECTION] * TransformationMatrix[ETS_VIEW]); + scene::SViewFrustum frustum(TransformationMatrix[ETS_PROJECTION] * TransformationMatrix[ETS_VIEW], true); // copy and transform clipping planes ignoring far plane core::plane3df planes[5]; // ordered by near, left, right, bottom, top diff --git a/source/Irrlicht/CXMLWriter.cpp b/source/Irrlicht/CXMLWriter.cpp index b801c203..4e9d6900 100644 --- a/source/Irrlicht/CXMLWriter.cpp +++ b/source/Irrlicht/CXMLWriter.cpp @@ -15,30 +15,28 @@ namespace irr namespace io { +//! creates an IXMLReader +IXMLWriter* createIXMLWriter(IWriteFile* file) +{ + return new CXMLWriter(file); +} + +//! creates an IXMLReader +IXMLWriterUTF8* createIXMLWriterUTF8(IWriteFile* file) +{ + return new CXMLWriterUTF8(file); +} //! Constructor CXMLWriter::CXMLWriter(IWriteFile* file) -: File(file), Tabs(0), TextWrittenLast(false) +: CXMLWriterCommon(file) { #ifdef _DEBUG setDebugName("CXMLWriter"); #endif - - if (File) - File->grab(); } - -//! Destructor -CXMLWriter::~CXMLWriter() -{ - if (File) - File->drop(); -} - - - //! Writes a xml 1.0 header like void CXMLWriter::writeXMLHeader() { @@ -189,18 +187,6 @@ void CXMLWriter::writeClosingTag(const wchar_t* name) TextWrittenLast = false; } - - -const CXMLWriter::XMLSpecialCharacters XMLWSChar[] = -{ - { L'&', L"&" }, - { L'<', L"<" }, - { L'>', L">" }, - { L'"', L""" }, - { L'\0', 0 } -}; - - //! Writes a text into the file. All occurrences of special characters like //! & (&), < (<), > (>), and " (") are automatically replaced. void CXMLWriter::writeText(const wchar_t* text) @@ -208,6 +194,15 @@ void CXMLWriter::writeText(const wchar_t* text) if (!File || !text) return; + static const CXMLWriter::XMLSpecialCharacters XMLWSChar[] = + { + { L'&', L"&" }, + { L'<', L"<" }, + { L'>', L">" }, + { L'"', L""" }, + { L'\0', 0 } + }; + // TODO: we have to get rid of that reserve call as well as it slows down xml-writing seriously. // Making a member-variable would work, but a lot of memory would stay around after writing. // So the correct solution is probably using fixed block here and always write when that is full. @@ -255,6 +250,222 @@ void CXMLWriter::writeLineBreak() } + +//! Constructor +CXMLWriterUTF8::CXMLWriterUTF8(IWriteFile* file) +: CXMLWriterCommon(file) +{ + #ifdef _DEBUG + setDebugName("CXMLWriter"); + #endif +} + + +//! Writes a xml 1.0 header like +void CXMLWriterUTF8::writeXMLHeader() +{ + if (!File) + return; + + // No BOM as it's not necessarily utf8 + + const c8* const p = ""; + File->write(p, strlen(p) * sizeof(c8)); + + writeLineBreak(); + TextWrittenLast = false; +} + + + +//! Writes an xml element with maximal 5 attributes +void CXMLWriterUTF8::writeElement(const c8* name, bool empty, + const c8* attr1Name, const c8* attr1Value, + const c8* attr2Name, const c8* attr2Value, + const c8* attr3Name, const c8* attr3Value, + const c8* attr4Name, const c8* attr4Value, + const c8* attr5Name, const c8* attr5Value) +{ + if (!File || !name) + return; + + if (Tabs > 0) + { + for (int i=0; iwrite("\t", sizeof(c8)); + } + + // write name + + File->write("<", sizeof(c8)); + File->write(name, strlen(name)*sizeof(c8)); + + // write attributes + + writeAttribute(attr1Name, attr1Value); + writeAttribute(attr2Name, attr2Value); + writeAttribute(attr3Name, attr3Value); + writeAttribute(attr4Name, attr4Value); + writeAttribute(attr5Name, attr5Value); + + // write closing tag + if (empty) + File->write(" />", 3*sizeof(c8)); + else + { + File->write(">", sizeof(c8)); + ++Tabs; + } + + TextWrittenLast = false; +} + +//! Writes an xml element with any number of attributes +void CXMLWriterUTF8::writeElement(const c8* name, bool empty, + core::array &names, + core::array &values) +{ + if (!File || !name) + return; + + if (Tabs > 0) + { + for (int i=0; iwrite("\t", sizeof(c8)); + } + + // write name + + File->write("<", sizeof(c8)); + File->write(name, strlen(name)*sizeof(c8)); + + // write attributes + u32 i=0; + for (; i < names.size() && i < values.size(); ++i) + writeAttribute(names[i].c_str(), values[i].c_str()); + + // write closing tag + if (empty) + File->write(" />", 3*sizeof(c8)); + else + { + File->write(">", sizeof(c8)); + ++Tabs; + } + + TextWrittenLast = false; +} + + +void CXMLWriterUTF8::writeAttribute(const c8* name, const c8* value) +{ + if (!name || !value) + return; + + File->write(" ", sizeof(c8)); + File->write(name, strlen(name)*sizeof(c8)); + File->write("=\"", 2*sizeof(c8)); + writeText(value); + File->write("\"", sizeof(c8)); +} + + +//! Writes a comment into the xml file +void CXMLWriterUTF8::writeComment(const c8* comment) +{ + if (!File || !comment) + return; + + File->write("", 3*sizeof(c8)); +} + + +//! Writes the closing tag for an element. Like +void CXMLWriterUTF8::writeClosingTag(const c8* name) +{ + if (!File || !name) + return; + + --Tabs; + + if (Tabs > 0 && !TextWrittenLast) + { + for (int i=0; iwrite("\t", sizeof(c8)); + } + + File->write("write(name, strlen(name)*sizeof(c8)); + File->write(">", sizeof(c8)); + TextWrittenLast = false; +} + + + +//! Writes a text into the file. All occurrences of special characters like +//! & (&), < (<), > (>), and " (") are automatically replaced. +void CXMLWriterUTF8::writeText(const c8* text) +{ + if (!File || !text) + return; + + static const CXMLWriterUTF8::XMLSpecialCharacters XMLWSChar[] = + { + { '&', "&" }, + { '<', "<" }, + { '>', ">" }, + { '"', """ }, + { '\0', 0 } + }; + + // TODO: we have to get rid of that reserve call as well as it slows down xml-writing seriously. + // Making a member-variable would work, but a lot of memory would stay around after writing. + // So the correct solution is probably using fixed block here and always write when that is full. + core::stringc s; + s.reserve(strlen(text)+1); + const c8* p = text; + + while(*p) + { + // check if it is matching + bool found = false; + for (s32 i=0; XMLWSChar[i].Character != '\0'; ++i) + if (*p == XMLWSChar[i].Character) + { + s.append(XMLWSChar[i].Symbol); + found = true; + break; + } + + if (!found) + s.append(*p); + ++p; + } + + // write new string + File->write(s.c_str(), s.size()*sizeof(c8)); + TextWrittenLast = true; +} + + +//! Writes a line break +void CXMLWriterUTF8::writeLineBreak() +{ + if (!File) + return; + +#if defined(_IRR_OSX_PLATFORM_) + File->write("\r", sizeof(c8)); +#elif defined(_IRR_WINDOWS_API_) + File->write("\r\n", 2*sizeof(c8)); +#else + File->write("\n", sizeof(c8)); +#endif + +} + } // end namespace irr } // end namespace io diff --git a/source/Irrlicht/CXMLWriter.h b/source/Irrlicht/CXMLWriter.h index 5149c323..6febc66a 100644 --- a/source/Irrlicht/CXMLWriter.h +++ b/source/Irrlicht/CXMLWriter.h @@ -17,8 +17,49 @@ namespace irr namespace io { - //! Interface providing methods for making it easier to write XML files. - class CXMLWriter : public IXMLWriter + //! creates an IXMLReader + IXMLWriter* createIXMLWriter(IWriteFile* file); + + //! creates an IXMLReader + IXMLWriterUTF8* createIXMLWriterUTF8(IWriteFile* file); + + // Stuff needed by implementations for all character types + // TODO: With some more work it could maybe become a pure template based thing like CXMLReaderImpl + // and replace the type based writer implementations. Sorry, too lazy for now :-/ + template + class CXMLWriterCommon + { + public: + //! Constructor + CXMLWriterCommon(IWriteFile* file): File(file), Tabs(0), TextWrittenLast(false) + { + if (File) + File->grab(); + } + + //! Destructor + virtual ~CXMLWriterCommon() + { + if (File) + File->drop(); + } + + struct XMLSpecialCharacters + { + char_type Character; + const char_type* Symbol; + }; + + protected: + IWriteFile* File; + s32 Tabs; + + bool TextWrittenLast; + }; + + + //! Implementation providing methods for making it easier to write XML files. + class CXMLWriter : public IXMLWriter, public CXMLWriterCommon { public: @@ -26,7 +67,7 @@ namespace io CXMLWriter(IWriteFile* file); //! Destructor - virtual ~CXMLWriter(); + virtual ~CXMLWriter() {} //! Writes a xml 1.0 header like virtual void writeXMLHeader() _IRR_OVERRIDE_; @@ -56,22 +97,56 @@ namespace io //! Writes a line break virtual void writeLineBreak() _IRR_OVERRIDE_; - struct XMLSpecialCharacters - { - wchar_t Character; - const wchar_t* Symbol; - }; - private: void writeAttribute(const wchar_t* att, const wchar_t* name); - - IWriteFile* File; - s32 Tabs; - - bool TextWrittenLast; }; + //! Implementation providing methods for making it easier to write XML files. + class CXMLWriterUTF8 : public IXMLWriterUTF8, public CXMLWriterCommon + { + public: + + //! Constructor + CXMLWriterUTF8(IWriteFile* file); + + //! Destructor + virtual ~CXMLWriterUTF8() {} + + //! Writes a xml 1.0 header like + virtual void writeXMLHeader() _IRR_OVERRIDE_; + + //! Writes an xml element with maximal 5 attributes + virtual void writeElement(const c8* name, bool empty=false, + const c8* attr1Name = 0, const c8* attr1Value = 0, + const c8* attr2Name = 0, const c8* attr2Value = 0, + const c8* attr3Name = 0, const c8* attr3Value = 0, + const c8* attr4Name = 0, const c8* attr4Value = 0, + const c8* attr5Name = 0, const c8* attr5Value = 0) _IRR_OVERRIDE_; + + //! Writes an xml element with any number of attributes + virtual void writeElement(const c8* name, bool empty, + core::array &names, core::array &values) _IRR_OVERRIDE_; + + //! Writes a comment into the xml file + virtual void writeComment(const c8* comment) _IRR_OVERRIDE_; + + //! Writes the closing tag for an element. Like + virtual void writeClosingTag(const c8* name) _IRR_OVERRIDE_; + + //! Writes a text into the file. All occurrences of special characters like + //! & (&), < (<), > (>), and " (") are automatically replaced. + virtual void writeText(const c8* text) _IRR_OVERRIDE_; + + //! Writes a line break + virtual void writeLineBreak() _IRR_OVERRIDE_; + + private: + + void writeAttribute(const c8* att, const c8* name); + }; + + } // end namespace irr } // end namespace io