mirror of
https://github.com/minetest/irrlicht.git
synced 2024-11-03 00:40:41 +01:00
243 lines
6.3 KiB
C++
243 lines
6.3 KiB
C++
|
// 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 "CMeshTextureLoader.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(irr::io::IFileSystem* fs, video::IVideoDriver* driver)
|
||
|
{
|
||
|
TextureLoader = new CMeshTextureLoader( fs, 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)
|
||
|
{
|
||
|
if ( !file )
|
||
|
return 0;
|
||
|
|
||
|
if ( getMeshTextureLoader() )
|
||
|
getMeshTextureLoader()->setMeshFile(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 = getMeshTextureLoader() ? getMeshTextureLoader()->getTexture(textureName + *ext) : NULL;
|
||
|
if (texture)
|
||
|
{
|
||
|
textureName = textureName + *ext;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
// 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
|
||
|
|