1 // Copyright (C) 2002-2012 Nikolaus Gebhardt
2 // This file is part of the "Irrlicht Engine".
3 // For conditions of distribution and use, see copyright notice in irrlicht.h
4 
5 #include "IrrCompileConfig.h"
6 
7 #ifdef _IRR_COMPILE_WITH_IRR_WRITER_
8 
9 #include "CIrrMeshWriter.h"
10 #include "os.h"
11 #include "IWriteFile.h"
12 #include "IXMLWriter.h"
13 #include "IMesh.h"
14 #include "IAttributes.h"
15 
16 namespace irr
17 {
18 namespace scene
19 {
20 
21 
CIrrMeshWriter(video::IVideoDriver * driver,io::IFileSystem * fs)22 CIrrMeshWriter::CIrrMeshWriter(video::IVideoDriver* driver,
23 				io::IFileSystem* fs)
24 	: FileSystem(fs), VideoDriver(driver), Writer(0)
25 {
26 	#ifdef _DEBUG
27 	setDebugName("CIrrMeshWriter");
28 	#endif
29 
30 	if (VideoDriver)
31 		VideoDriver->grab();
32 
33 	if (FileSystem)
34 		FileSystem->grab();
35 }
36 
37 
~CIrrMeshWriter()38 CIrrMeshWriter::~CIrrMeshWriter()
39 {
40 	if (VideoDriver)
41 		VideoDriver->drop();
42 
43 	if (FileSystem)
44 		FileSystem->drop();
45 }
46 
47 
48 //! Returns the type of the mesh writer
getType() const49 EMESH_WRITER_TYPE CIrrMeshWriter::getType() const
50 {
51 	return EMWT_IRR_MESH;
52 }
53 
54 
55 //! writes a mesh
writeMesh(io::IWriteFile * file,scene::IMesh * mesh,s32 flags)56 bool CIrrMeshWriter::writeMesh(io::IWriteFile* file, scene::IMesh* mesh, s32 flags)
57 {
58 	if (!file)
59 		return false;
60 
61 	Writer = FileSystem->createXMLWriter(file);
62 
63 	if (!Writer)
64 	{
65 		os::Printer::log("Could not write file", file->getFileName());
66 		return false;
67 	}
68 
69 	os::Printer::log("Writing mesh", file->getFileName());
70 
71 	// write IRR MESH header
72 
73 	Writer->writeXMLHeader();
74 
75 	Writer->writeElement(L"mesh", false,
76 		L"xmlns", L"http://irrlicht.sourceforge.net/IRRMESH_09_2007",
77 		L"version", L"1.0");
78 	Writer->writeLineBreak();
79 
80 	// add some informational comment. Add a space after and before the comment
81 	// tags so that some braindead xml parsers (AS anyone?) are able to parse this too.
82 
83 	core::stringw infoComment = L" This file contains a static mesh in the Irrlicht Engine format with ";
84 	infoComment += core::stringw(mesh->getMeshBufferCount());
85 	infoComment += L" materials.";
86 
87 	Writer->writeComment(infoComment.c_str());
88 	Writer->writeLineBreak();
89 
90 	// write mesh bounding box
91 
92 	writeBoundingBox(mesh->getBoundingBox());
93 	Writer->writeLineBreak();
94 
95 	// write mesh buffers
96 
97 	for (int i=0; i<(int)mesh->getMeshBufferCount(); ++i)
98 	{
99 		scene::IMeshBuffer* buffer = mesh->getMeshBuffer(i);
100 		if (buffer)
101 		{
102 			writeMeshBuffer(buffer);
103 			Writer->writeLineBreak();
104 		}
105 	}
106 
107 	Writer->writeClosingTag(L"mesh");
108 
109 	Writer->drop();
110 	return true;
111 }
112 
113 
writeBoundingBox(const core::aabbox3df & box)114 void CIrrMeshWriter::writeBoundingBox(const core::aabbox3df& box)
115 {
116 	Writer->writeElement(L"boundingBox", true,
117 		L"minEdge", getVectorAsStringLine(box.MinEdge).c_str(),
118 		L"maxEdge", getVectorAsStringLine(box.MaxEdge).c_str());
119 }
120 
121 
getVectorAsStringLine(const core::vector3df & v) const122 core::stringw CIrrMeshWriter::getVectorAsStringLine(const core::vector3df& v) const
123 {
124 	core::stringw str;
125 
126 	str = core::stringw(v.X);
127 	str += L" ";
128 	str += core::stringw(v.Y);
129 	str += L" ";
130 	str += core::stringw(v.Z);
131 
132 	return str;
133 }
134 
135 
getVectorAsStringLine(const core::vector2df & v) const136 core::stringw CIrrMeshWriter::getVectorAsStringLine(const core::vector2df& v) const
137 {
138 	core::stringw str;
139 
140 	str = core::stringw(v.X);
141 	str += L" ";
142 	str += core::stringw(v.Y);
143 
144 	return str;
145 }
146 
147 
writeMeshBuffer(const scene::IMeshBuffer * buffer)148 void CIrrMeshWriter::writeMeshBuffer(const scene::IMeshBuffer* buffer)
149 {
150 	Writer->writeElement(L"buffer", false);
151 	Writer->writeLineBreak();
152 
153 	// write bounding box
154 
155 	writeBoundingBox(buffer->getBoundingBox());
156 	Writer->writeLineBreak();
157 
158 	// write material
159 
160 	writeMaterial(buffer->getMaterial());
161 
162 	// write vertices
163 
164 	const core::stringw vertexTypeStr = video::sBuiltInVertexTypeNames[buffer->getVertexType()];
165 
166 	Writer->writeElement(L"vertices", false,
167 		L"type", vertexTypeStr.c_str(),
168 		L"vertexCount", core::stringw(buffer->getVertexCount()).c_str());
169 
170 	Writer->writeLineBreak();
171 
172 	u32 vertexCount = buffer->getVertexCount();
173 
174 	switch(buffer->getVertexType())
175 	{
176 	case video::EVT_STANDARD:
177 		{
178 			video::S3DVertex* vtx = (video::S3DVertex*)buffer->getVertices();
179 			for (u32 j=0; j<vertexCount; ++j)
180 			{
181 				core::stringw str = getVectorAsStringLine(vtx[j].Pos);
182 				str += L" ";
183 				str += getVectorAsStringLine(vtx[j].Normal);
184 
185 				char tmp[12];
186 				sprintf(tmp, " %02x%02x%02x%02x ", vtx[j].Color.getAlpha(), vtx[j].Color.getRed(), vtx[j].Color.getGreen(), vtx[j].Color.getBlue());
187 				str += tmp;
188 
189 				str += getVectorAsStringLine(vtx[j].TCoords);
190 
191 				Writer->writeText(str.c_str());
192 				Writer->writeLineBreak();
193 			}
194 		}
195 		break;
196 	case video::EVT_2TCOORDS:
197 		{
198 			video::S3DVertex2TCoords* vtx = (video::S3DVertex2TCoords*)buffer->getVertices();
199 			for (u32 j=0; j<vertexCount; ++j)
200 			{
201 				core::stringw str = getVectorAsStringLine(vtx[j].Pos);
202 				str += L" ";
203 				str += getVectorAsStringLine(vtx[j].Normal);
204 
205 				char tmp[12];
206 				sprintf(tmp, " %02x%02x%02x%02x ", vtx[j].Color.getAlpha(), vtx[j].Color.getRed(), vtx[j].Color.getGreen(), vtx[j].Color.getBlue());
207 				str += tmp;
208 
209 				str += getVectorAsStringLine(vtx[j].TCoords);
210 				str += L" ";
211 				str += getVectorAsStringLine(vtx[j].TCoords2);
212 
213 				Writer->writeText(str.c_str());
214 				Writer->writeLineBreak();
215 			}
216 		}
217 		break;
218 	case video::EVT_TANGENTS:
219 		{
220 			video::S3DVertexTangents* vtx = (video::S3DVertexTangents*)buffer->getVertices();
221 			for (u32 j=0; j<vertexCount; ++j)
222 			{
223 				core::stringw str = getVectorAsStringLine(vtx[j].Pos);
224 				str += L" ";
225 				str += getVectorAsStringLine(vtx[j].Normal);
226 
227 				char tmp[12];
228 				sprintf(tmp, " %02x%02x%02x%02x ", vtx[j].Color.getAlpha(), vtx[j].Color.getRed(), vtx[j].Color.getGreen(), vtx[j].Color.getBlue());
229 				str += tmp;
230 
231 				str += getVectorAsStringLine(vtx[j].TCoords);
232 				str += L" ";
233 				str += getVectorAsStringLine(vtx[j].Tangent);
234 				str += L" ";
235 				str += getVectorAsStringLine(vtx[j].Binormal);
236 
237 				Writer->writeText(str.c_str());
238 				Writer->writeLineBreak();
239 			}
240 		}
241 		break;
242 	}
243 
244 	Writer->writeClosingTag(L"vertices");
245 	Writer->writeLineBreak();
246 
247 	// write indices
248 
249 	Writer->writeElement(L"indices", false,
250 		L"indexCount", core::stringw(buffer->getIndexCount()).c_str());
251 
252 	Writer->writeLineBreak();
253 
254 	int indexCount = (int)buffer->getIndexCount();
255 
256 	video::E_INDEX_TYPE iType = buffer->getIndexType();
257 
258 	const u16* idx16 = buffer->getIndices();
259 	const u32* idx32 = (u32*) buffer->getIndices();
260 	const int maxIndicesPerLine = 25;
261 
262 	for (int i=0; i<indexCount; ++i)
263 	{
264 		if(iType == video::EIT_16BIT)
265 		{
266 			core::stringw str((int)idx16[i]);
267 			Writer->writeText(str.c_str());
268 		}
269 		else
270 		{
271 			core::stringw str((int)idx32[i]);
272 			Writer->writeText(str.c_str());
273 		}
274 
275 		if (i % maxIndicesPerLine != maxIndicesPerLine)
276 		{
277 			if (i % maxIndicesPerLine == maxIndicesPerLine-1)
278 				Writer->writeLineBreak();
279 			else
280 				Writer->writeText(L" ");
281 		}
282 	}
283 
284 	if ((indexCount-1) % maxIndicesPerLine != maxIndicesPerLine-1)
285 		Writer->writeLineBreak();
286 
287 	Writer->writeClosingTag(L"indices");
288 	Writer->writeLineBreak();
289 
290 	// close buffer tag
291 
292 	Writer->writeClosingTag(L"buffer");
293 }
294 
295 
writeMaterial(const video::SMaterial & material)296 void CIrrMeshWriter::writeMaterial(const video::SMaterial& material)
297 {
298 	// simply use irrlichts built-in attribute serialization capabilities here:
299 
300 	io::IAttributes* attributes =
301 		VideoDriver->createAttributesFromMaterial(material);
302 
303 	if (attributes)
304 	{
305 		attributes->write(Writer, false, L"material");
306 		attributes->drop();
307 	}
308 }
309 
310 
311 } // end namespace
312 } // end namespace
313 
314 #endif
315 
316