mirror of
https://github.com/minetest/irrlicht.git
synced 2024-12-27 11:10:31 +01:00
313 lines
7.1 KiB
C++
313 lines
7.1 KiB
C++
|
// Copyright (C) 2002-2012 Nikolaus Gebhardt
|
||
|
// This file is part of the "Irrlicht Engine".
|
||
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
||
|
|
||
|
#include "IrrCompileConfig.h"
|
||
|
|
||
|
#ifdef _IRR_COMPILE_WITH_IRR_WRITER_
|
||
|
|
||
|
#include "CIrrMeshWriter.h"
|
||
|
#include "os.h"
|
||
|
#include "IWriteFile.h"
|
||
|
#include "IXMLWriter.h"
|
||
|
#include "IMesh.h"
|
||
|
#include "IAttributes.h"
|
||
|
|
||
|
namespace irr
|
||
|
{
|
||
|
namespace scene
|
||
|
{
|
||
|
|
||
|
|
||
|
CIrrMeshWriter::CIrrMeshWriter(video::IVideoDriver* driver,
|
||
|
io::IFileSystem* fs)
|
||
|
: FileSystem(fs), VideoDriver(driver), Writer(0)
|
||
|
{
|
||
|
#ifdef _DEBUG
|
||
|
setDebugName("CIrrMeshWriter");
|
||
|
#endif
|
||
|
|
||
|
if (VideoDriver)
|
||
|
VideoDriver->grab();
|
||
|
|
||
|
if (FileSystem)
|
||
|
FileSystem->grab();
|
||
|
}
|
||
|
|
||
|
|
||
|
CIrrMeshWriter::~CIrrMeshWriter()
|
||
|
{
|
||
|
if (VideoDriver)
|
||
|
VideoDriver->drop();
|
||
|
|
||
|
if (FileSystem)
|
||
|
FileSystem->drop();
|
||
|
}
|
||
|
|
||
|
|
||
|
//! Returns the type of the mesh writer
|
||
|
EMESH_WRITER_TYPE CIrrMeshWriter::getType() const
|
||
|
{
|
||
|
return EMWT_IRR_MESH;
|
||
|
}
|
||
|
|
||
|
|
||
|
//! writes a mesh
|
||
|
bool CIrrMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags)
|
||
|
{
|
||
|
if (!file)
|
||
|
return false;
|
||
|
|
||
|
Writer = FileSystem->createXMLWriter(file);
|
||
|
|
||
|
if (!Writer)
|
||
|
{
|
||
|
os::Printer::log("Could not write file", file->getFileName());
|
||
|
return false;
|
||
|
}
|
||
|
|
||
|
os::Printer::log("Writing mesh", file->getFileName());
|
||
|
|
||
|
// write IRR MESH header
|
||
|
|
||
|
Writer->writeXMLHeader();
|
||
|
|
||
|
Writer->writeElement(L"mesh", false,
|
||
|
L"xmlns", L"http://irrlicht.sourceforge.net/IRRMESH_09_2007",
|
||
|
L"version", L"1.0");
|
||
|
Writer->writeLineBreak();
|
||
|
|
||
|
// add some informational comment. Add a space after and before the comment
|
||
|
// tags so that some braindead xml parsers (AS anyone?) are able to parse this too.
|
||
|
|
||
|
core::stringw infoComment = L" This file contains a static mesh in the Irrlicht Engine format with ";
|
||
|
infoComment += core::stringw(mesh->getMeshBufferCount());
|
||
|
infoComment += L" materials.";
|
||
|
|
||
|
Writer->writeComment(infoComment.c_str());
|
||
|
Writer->writeLineBreak();
|
||
|
|
||
|
// write mesh bounding box
|
||
|
|
||
|
writeBoundingBox(mesh->getBoundingBox());
|
||
|
Writer->writeLineBreak();
|
||
|
|
||
|
// write mesh buffers
|
||
|
|
||
|
for (int i=0; i<(int)mesh->getMeshBufferCount(); ++i)
|
||
|
{
|
||
|
scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
|
||
|
if (buffer)
|
||
|
{
|
||
|
writeMeshBuffer(buffer);
|
||
|
Writer->writeLineBreak();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
Writer->writeClosingTag(L"mesh");
|
||
|
|
||
|
Writer->drop();
|
||
|
return true;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CIrrMeshWriter::writeBoundingBox(const core::aabbox3df& box)
|
||
|
{
|
||
|
Writer->writeElement(L"boundingBox", true,
|
||
|
L"minEdge", getVectorAsStringLine(box.MinEdge).c_str(),
|
||
|
L"maxEdge", getVectorAsStringLine(box.MaxEdge).c_str());
|
||
|
}
|
||
|
|
||
|
|
||
|
core::stringw CIrrMeshWriter::getVectorAsStringLine(const core::vector3df& v) const
|
||
|
{
|
||
|
core::stringw str;
|
||
|
|
||
|
str = core::stringw(v.X);
|
||
|
str += L" ";
|
||
|
str += core::stringw(v.Y);
|
||
|
str += L" ";
|
||
|
str += core::stringw(v.Z);
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
|
||
|
core::stringw CIrrMeshWriter::getVectorAsStringLine(const core::vector2df& v) const
|
||
|
{
|
||
|
core::stringw str;
|
||
|
|
||
|
str = core::stringw(v.X);
|
||
|
str += L" ";
|
||
|
str += core::stringw(v.Y);
|
||
|
|
||
|
return str;
|
||
|
}
|
||
|
|
||
|
|
||
|
void CIrrMeshWriter::writeMeshBuffer(const scene::IMeshBuffer* buffer)
|
||
|
{
|
||
|
Writer->writeElement(L"buffer", false);
|
||
|
Writer->writeLineBreak();
|
||
|
|
||
|
// write bounding box
|
||
|
|
||
|
writeBoundingBox(buffer->getBoundingBox());
|
||
|
Writer->writeLineBreak();
|
||
|
|
||
|
// write material
|
||
|
|
||
|
writeMaterial(buffer->getMaterial());
|
||
|
|
||
|
// write vertices
|
||
|
|
||
|
const core::stringw vertexTypeStr = video::sBuiltInVertexTypeNames[buffer->getVertexType()];
|
||
|
|
||
|
Writer->writeElement(L"vertices", false,
|
||
|
L"type", vertexTypeStr.c_str(),
|
||
|
L"vertexCount", core::stringw(buffer->getVertexCount()).c_str());
|
||
|
|
||
|
Writer->writeLineBreak();
|
||
|
|
||
|
u32 vertexCount = buffer->getVertexCount();
|
||
|
|
||
|
switch(buffer->getVertexType())
|
||
|
{
|
||
|
case video::EVT_STANDARD:
|
||
|
{
|
||
|
video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
|
||
|
for (u32 j=0; j<vertexCount; ++j)
|
||
|
{
|
||
|
core::stringw str = getVectorAsStringLine(vtx[j].Pos);
|
||
|
str += L" ";
|
||
|
str += getVectorAsStringLine(vtx[j].Normal);
|
||
|
|
||
|
char tmp[12];
|
||
|
sprintf(tmp, " %02x%02x%02x%02x ", vtx[j].Color.getAlpha(), vtx[j].Color.getRed(), vtx[j].Color.getGreen(), vtx[j].Color.getBlue());
|
||
|
str += tmp;
|
||
|
|
||
|
str += getVectorAsStringLine(vtx[j].TCoords);
|
||
|
|
||
|
Writer->writeText(str.c_str());
|
||
|
Writer->writeLineBreak();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case video::EVT_2TCOORDS:
|
||
|
{
|
||
|
video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
|
||
|
for (u32 j=0; j<vertexCount; ++j)
|
||
|
{
|
||
|
core::stringw str = getVectorAsStringLine(vtx[j].Pos);
|
||
|
str += L" ";
|
||
|
str += getVectorAsStringLine(vtx[j].Normal);
|
||
|
|
||
|
char tmp[12];
|
||
|
sprintf(tmp, " %02x%02x%02x%02x ", vtx[j].Color.getAlpha(), vtx[j].Color.getRed(), vtx[j].Color.getGreen(), vtx[j].Color.getBlue());
|
||
|
str += tmp;
|
||
|
|
||
|
str += getVectorAsStringLine(vtx[j].TCoords);
|
||
|
str += L" ";
|
||
|
str += getVectorAsStringLine(vtx[j].TCoords2);
|
||
|
|
||
|
Writer->writeText(str.c_str());
|
||
|
Writer->writeLineBreak();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case video::EVT_TANGENTS:
|
||
|
{
|
||
|
video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
|
||
|
for (u32 j=0; j<vertexCount; ++j)
|
||
|
{
|
||
|
core::stringw str = getVectorAsStringLine(vtx[j].Pos);
|
||
|
str += L" ";
|
||
|
str += getVectorAsStringLine(vtx[j].Normal);
|
||
|
|
||
|
char tmp[12];
|
||
|
sprintf(tmp, " %02x%02x%02x%02x ", vtx[j].Color.getAlpha(), vtx[j].Color.getRed(), vtx[j].Color.getGreen(), vtx[j].Color.getBlue());
|
||
|
str += tmp;
|
||
|
|
||
|
str += getVectorAsStringLine(vtx[j].TCoords);
|
||
|
str += L" ";
|
||
|
str += getVectorAsStringLine(vtx[j].Tangent);
|
||
|
str += L" ";
|
||
|
str += getVectorAsStringLine(vtx[j].Binormal);
|
||
|
|
||
|
Writer->writeText(str.c_str());
|
||
|
Writer->writeLineBreak();
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
Writer->writeClosingTag(L"vertices");
|
||
|
Writer->writeLineBreak();
|
||
|
|
||
|
// write indices
|
||
|
|
||
|
Writer->writeElement(L"indices", false,
|
||
|
L"indexCount", core::stringw(buffer->getIndexCount()).c_str());
|
||
|
|
||
|
Writer->writeLineBreak();
|
||
|
|
||
|
int indexCount = (int)buffer->getIndexCount();
|
||
|
|
||
|
video::E_INDEX_TYPE iType = buffer->getIndexType();
|
||
|
|
||
|
const u16* idx16 = buffer->getIndices();
|
||
|
const u32* idx32 = (u32*) buffer->getIndices();
|
||
|
const int maxIndicesPerLine = 25;
|
||
|
|
||
|
for (int i=0; i<indexCount; ++i)
|
||
|
{
|
||
|
if(iType == video::EIT_16BIT)
|
||
|
{
|
||
|
core::stringw str((int)idx16[i]);
|
||
|
Writer->writeText(str.c_str());
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
core::stringw str((int)idx32[i]);
|
||
|
Writer->writeText(str.c_str());
|
||
|
}
|
||
|
|
||
|
if (i % maxIndicesPerLine == maxIndicesPerLine-1)
|
||
|
Writer->writeLineBreak();
|
||
|
else
|
||
|
Writer->writeText(L" ");
|
||
|
}
|
||
|
|
||
|
if ((indexCount-1) % maxIndicesPerLine != maxIndicesPerLine-1)
|
||
|
Writer->writeLineBreak();
|
||
|
|
||
|
Writer->writeClosingTag(L"indices");
|
||
|
Writer->writeLineBreak();
|
||
|
|
||
|
// close buffer tag
|
||
|
|
||
|
Writer->writeClosingTag(L"buffer");
|
||
|
}
|
||
|
|
||
|
|
||
|
void CIrrMeshWriter::writeMaterial(const video::SMaterial& material)
|
||
|
{
|
||
|
// simply use irrlichts built-in attribute serialization capabilities here:
|
||
|
|
||
|
io::IAttributes* attributes =
|
||
|
VideoDriver->createAttributesFromMaterial(material);
|
||
|
|
||
|
if (attributes)
|
||
|
{
|
||
|
attributes->write(Writer, false, L"material");
|
||
|
attributes->drop();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
} // end namespace
|
||
|
} // end namespace
|
||
|
|
||
|
#endif
|
||
|
|