aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/libraries/irrlicht-1.8.1/source/Irrlicht/CSMFMeshFileLoader.cpp
blob: 099f2aacdbacd357fed3987ade33a1117eb754c8 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// Copyright (C) 2010-2012 Gaz Davidson / Joseph Ellis
// 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_SMF_LOADER_

#include "CSMFMeshFileLoader.h"
#include "SAnimatedMesh.h"
#include "SMeshBuffer.h"
#include "IReadFile.h"
#include "coreutil.h"
#include "os.h"
#include "IVideoDriver.h"

namespace irr
{
namespace scene
{

CSMFMeshFileLoader::CSMFMeshFileLoader(video::IVideoDriver* driver)
: Driver(driver)
{
}

//! Returns true if the file might be loaded by this class.
bool CSMFMeshFileLoader::isALoadableFileExtension(const io::path& filename) const
{
	return core::hasFileExtension(filename, "smf");
}

//! Creates/loads an animated mesh from the file.
IAnimatedMesh* CSMFMeshFileLoader::createMesh(io::IReadFile* file)
{
	// create empty mesh
	SMesh *mesh = new SMesh();

	// load file
	u16 version;
	u8  flags;
	s32 limbCount;
	s32 i;

	io::BinaryFile::read(file, version);
	io::BinaryFile::read(file, flags);
	io::BinaryFile::read(file, limbCount);

	// load mesh data
	core::matrix4 identity;
	for (i=0; i < limbCount; ++i)
		loadLimb(file, mesh, identity);

	// recalculate buffer bounding boxes
	for (i=0; i < (s32)mesh->getMeshBufferCount(); ++i)
		mesh->getMeshBuffer(i)->recalculateBoundingBox();

	mesh->recalculateBoundingBox();
	SAnimatedMesh *am = new SAnimatedMesh();
	am->addMesh(mesh);
	mesh->drop();
	am->recalculateBoundingBox();

	return am;
}

void CSMFMeshFileLoader::loadLimb(io::IReadFile* file, SMesh* mesh, const core::matrix4 &parentTransformation)
{
	core::matrix4 transformation;

	// limb transformation
	core::vector3df translate, rotate, scale;
	io::BinaryFile::read(file, translate);
	io::BinaryFile::read(file, rotate);
	io::BinaryFile::read(file, scale);

	transformation.setTranslation(translate);
	transformation.setRotationDegrees(rotate);
	transformation.setScale(scale);

	transformation = parentTransformation * transformation;

	core::stringc textureName, textureGroupName;

	// texture information
	io::BinaryFile::read(file, textureGroupName);
	io::BinaryFile::read(file, textureName);

	// attempt to load texture using known formats
	video::ITexture* texture = 0;

	const c8* extensions[] = {".jpg", ".png", ".tga", ".bmp", 0};

	for (const c8 **ext = extensions; !texture && *ext; ++ext)
	{
		texture = Driver->getTexture(textureName + *ext);
		if (texture)
			textureName = textureName + *ext;
	}
	// find the correct mesh buffer
	u32 i;
	for (i=0; i<mesh->MeshBuffers.size(); ++i)
		if (mesh->MeshBuffers[i]->getMaterial().TextureLayer[0].Texture == texture)
			break;

	// create mesh buffer if none was found
	if (i == mesh->MeshBuffers.size())
	{
		CMeshBuffer<video::S3DVertex>* mb = new CMeshBuffer<video::S3DVertex>();
		mb->Material.TextureLayer[0].Texture = texture;

		// horribly hacky way to do this, maybe it's in the flags?
		if (core::hasFileExtension(textureName, "tga", "png"))
			mb->Material.MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
		else
			mb->Material.MaterialType = video::EMT_SOLID;

		mesh->MeshBuffers.push_back(mb);
	}

	CMeshBuffer<video::S3DVertex>* mb = (CMeshBuffer<video::S3DVertex>*)mesh->MeshBuffers[i];

	u16 vertexCount, firstVertex = mb->getVertexCount();

	io::BinaryFile::read(file, vertexCount);
	mb->Vertices.reallocate(mb->Vertices.size() + vertexCount);

	// add vertices and set positions
	for (i=0; i<vertexCount; ++i)
	{
		core::vector3df pos;
		io::BinaryFile::read(file, pos);
		transformation.transformVect(pos);
		video::S3DVertex vert;
		vert.Color = 0xFFFFFFFF;
		vert.Pos = pos;
		mb->Vertices.push_back(vert);
	}

	// set vertex normals
	for (i=0; i < vertexCount; ++i)
	{
		core::vector3df normal;
		io::BinaryFile::read(file, normal);
		transformation.rotateVect(normal);
		mb->Vertices[firstVertex + i].Normal = normal;
	}
	// set texture coordinates

	for (i=0; i < vertexCount; ++i)
	{
		core::vector2df tcoords;
		io::BinaryFile::read(file, tcoords);
		mb->Vertices[firstVertex + i].TCoords = tcoords;
	}

	// triangles
	u32 triangleCount;
	// vertexCount used as temporary
	io::BinaryFile::read(file, vertexCount);
	triangleCount=3*vertexCount;
	mb->Indices.reallocate(mb->Indices.size() + triangleCount);

	for (i=0; i < triangleCount; ++i)
	{
		u16 index;
		io::BinaryFile::read(file, index);
		mb->Indices.push_back(firstVertex + index);
	}

	// read limbs
	s32 limbCount;
	io::BinaryFile::read(file, limbCount);

	for (s32 l=0; l < limbCount; ++l)
		loadLimb(file, mesh, transformation);
}

} // namespace scene

// todo: at some point in the future let's move these to a place where everyone can use them.
namespace io
{

#if _BIGENDIAN
#define _SYSTEM_BIG_ENDIAN_ (true)
#else
#define _SYSTEM_BIG_ENDIAN_ (false)
#endif

template <class T>
void BinaryFile::read(io::IReadFile* file, T &out, bool bigEndian)
{
	file->read((void*)&out, sizeof(out));
	if (bigEndian != (_SYSTEM_BIG_ENDIAN_))
		out = os::Byteswap::byteswap(out);
}

//! reads a 3d vector from the file, moving the file pointer along
void BinaryFile::read(io::IReadFile* file, core::vector3df &outVector2d, bool bigEndian)
{
	BinaryFile::read(file, outVector2d.X, bigEndian);
	BinaryFile::read(file, outVector2d.Y, bigEndian);
	BinaryFile::read(file, outVector2d.Z, bigEndian);
}

//! reads a 2d vector from the file, moving the file pointer along
void BinaryFile::read(io::IReadFile* file, core::vector2df &outVector2d, bool bigEndian)
{
	BinaryFile::read(file, outVector2d.X, bigEndian);
	BinaryFile::read(file, outVector2d.Y, bigEndian);
}

//! reads a null terminated string from the file, moving the file pointer along
void BinaryFile::read(io::IReadFile* file, core::stringc &outString, bool bigEndian)
{
	c8 c;
	file->read((void*)&c, 1);

	while (c)
	{
		outString += c;
		file->read((void*)&c, 1);
	}
}

} // namespace io

} // namespace irr

#endif // compile with SMF loader