Commit 383d3101 authored by hybrid's avatar hybrid

Some code cleanup for animated meshes.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@908 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 2d24d11b
...@@ -5,7 +5,6 @@ ...@@ -5,7 +5,6 @@
#ifndef __I_ANIMATED_MESH_H_INCLUDED__ #ifndef __I_ANIMATED_MESH_H_INCLUDED__
#define __I_ANIMATED_MESH_H_INCLUDED__ #define __I_ANIMATED_MESH_H_INCLUDED__
#include "IUnknown.h"
#include "aabbox3d.h" #include "aabbox3d.h"
#include "IMesh.h" #include "IMesh.h"
...@@ -28,36 +27,35 @@ namespace scene ...@@ -28,36 +27,35 @@ namespace scene
//! Milkshape 3d skeletal animation file //! Milkshape 3d skeletal animation file
EAMT_MS3D, EAMT_MS3D,
//! Maya .obj not animated model //! Maya .obj static model
EAMT_OBJ, EAMT_OBJ,
//! Quake 3 .bsp Map, not animated //! Quake 3 .bsp static Map
EAMT_BSP, EAMT_BSP,
//! 3D Studio .3ds file //! 3D Studio .3ds file
EAMT_3DS, EAMT_3DS,
//! Microsoft Direct3D .x-file. Can contain static and skeletal animated //! Microsoft Direct3D .x file. Can contain static and skeletal
//! skinned meshes. This is the standard and best supported //! animated skinned meshes.
//! format of the Irrlicht Engine.
EAMT_X, EAMT_X,
//! My3D Mesh, the file format by Zhuck Dimitry //! My3D Mesh, the file format by Zhuck Dimitry
EAMT_MY3D, EAMT_MY3D,
//! Pulsar LMTools (.lmts) file. The Irrlicht loader for this was written by //! Pulsar LMTools .lmts file. This Irrlicht loader was
//! Jonas Petersen //! written by Jonas Petersen
EAMT_LMTS, EAMT_LMTS,
//! Cartography Shop .csm file. The loader for this was created by Saurav Mohapatra. //! Cartography Shop .csm file. This loader was created by Saurav Mohapatra.
EAMT_CSM, EAMT_CSM,
//! .oct file for Paul Nette's FSRad or from Murphy McCauley's Blender .oct exporter. //! .oct file for Paul Nette's FSRad or from Murphy McCauley's
//! The oct file format contains 3D geometry and lightmaps and can //! Blender .oct exporter. The oct file format contains 3D
//! be loaded directly by Irrlicht //! geometry and lightmaps and can be loaded directly by Irrlicht
EAMT_OCT, EAMT_OCT,
//! genetic skinned mesh //! generic skinned mesh
EAMT_SKINNED EAMT_SKINNED
}; };
...@@ -79,23 +77,20 @@ namespace scene ...@@ -79,23 +77,20 @@ namespace scene
virtual s32 getFrameCount() = 0; virtual s32 getFrameCount() = 0;
//! Returns the IMesh interface for a frame. //! Returns the IMesh interface for a frame.
/** \param frame: Frame number as zero based index. The maximum frame number is /** \param frame: Frame number as zero based index. The maximum
getFrameCount() - 1; frame number is getFrameCount() - 1;
\param detailLevel: Level of detail. 0 is the lowest, \param detailLevel: Level of detail. 0 is the lowest, 255 the
255 the highest level of detail. Most meshes will ignore the detail level. highest level of detail. Most meshes will ignore the detail level.
\param startFrameLoop: Because some animated meshes (.MD2) are blended between 2 \param startFrameLoop: Because some animated meshes (.MD2) are
static frames, and maybe animated in a loop, the startFrameLoop and the endFrameLoop blended between 2 static frames, and maybe animated in a loop,
have to be defined, to prevent the animation to be blended between frames which are the startFrameLoop and the endFrameLoop have to be defined, to
prevent the animation to be blended between frames which are
outside of this loop. outside of this loop.
If startFrameLoop and endFrameLoop are both -1, they are ignored. If startFrameLoop and endFrameLoop are both -1, they are ignored.
\param endFrameLoop: see startFrameLoop. \param endFrameLoop: see startFrameLoop.
\return Returns the animated mesh based on a detail level. */ \return Returns the animated mesh based on a detail level. */
virtual IMesh* getMesh(s32 frame, s32 detailLevel=255, s32 startFrameLoop=-1, s32 endFrameLoop=-1) = 0; virtual IMesh* getMesh(s32 frame, s32 detailLevel=255, s32 startFrameLoop=-1, s32 endFrameLoop=-1) = 0;
//! Returns an axis aligned bounding box of the mesh.
/** \return A bounding box of this mesh is returned. */
virtual const core::aabbox3d<f32>& getBoundingBox() const = 0;
//! Returns the type of the animated mesh. //! Returns the type of the animated mesh.
/** In most cases it is not neccessary to use this method. /** In most cases it is not neccessary to use this method.
This is useful for making a safe downcast. For example, This is useful for making a safe downcast. For example,
......
...@@ -223,7 +223,6 @@ namespace scene ...@@ -223,7 +223,6 @@ namespace scene
}; };
//! Holding Frames Buffers and Tag Infos //! Holding Frames Buffers and Tag Infos
struct SMD3Mesh: public IUnknown struct SMD3Mesh: public IUnknown
{ {
...@@ -240,7 +239,6 @@ namespace scene ...@@ -240,7 +239,6 @@ namespace scene
}; };
//! Interface for using some special functions of MD3 meshes //! Interface for using some special functions of MD3 meshes
class IAnimatedMeshMD3 : public IAnimatedMesh class IAnimatedMeshMD3 : public IAnimatedMesh
{ {
...@@ -252,7 +250,6 @@ namespace scene ...@@ -252,7 +250,6 @@ namespace scene
virtual SMD3QuaterionTagList *getTagList(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) = 0; virtual SMD3QuaterionTagList *getTagList(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) = 0;
virtual SMD3Mesh * getOriginalMesh () = 0; virtual SMD3Mesh * getOriginalMesh () = 0;
}; };
} // end namespace scene } // end namespace scene
......
...@@ -53,7 +53,6 @@ namespace scene ...@@ -53,7 +53,6 @@ namespace scene
/** \param flag: Flag to set in all materials. /** \param flag: Flag to set in all materials.
\param newvalue: New value to set in all materials. */ \param newvalue: New value to set in all materials. */
virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) = 0; virtual void setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue) = 0;
}; };
} // end namespace scene } // end namespace scene
......
...@@ -367,7 +367,6 @@ IMeshBuffer* CAnimatedMeshMD2::getMeshBuffer(const video::SMaterial &material) c ...@@ -367,7 +367,6 @@ IMeshBuffer* CAnimatedMeshMD2::getMeshBuffer(const video::SMaterial &material) c
} }
// updates the interpolation buffer // updates the interpolation buffer
void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, s32 endFrameLoop) void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, s32 endFrameLoop)
{ {
...@@ -421,8 +420,6 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, ...@@ -421,8 +420,6 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop,
} }
//! loads an md2 file //! loads an md2 file
bool CAnimatedMeshMD2::loadFile(io::IReadFile* file) bool CAnimatedMeshMD2::loadFile(io::IReadFile* file)
{ {
...@@ -658,7 +655,6 @@ bool CAnimatedMeshMD2::loadFile(io::IReadFile* file) ...@@ -658,7 +655,6 @@ bool CAnimatedMeshMD2::loadFile(io::IReadFile* file)
} }
//! calculates the bounding box //! calculates the bounding box
void CAnimatedMeshMD2::calculateBoundingBox() void CAnimatedMeshMD2::calculateBoundingBox()
{ {
...@@ -671,8 +667,8 @@ void CAnimatedMeshMD2::calculateBoundingBox() ...@@ -671,8 +667,8 @@ void CAnimatedMeshMD2::calculateBoundingBox()
if (defaultFrame>=FrameCount) if (defaultFrame>=FrameCount)
defaultFrame = 0; defaultFrame = 0;
for (u32 j=0; j<FrameList[defaultFrame].size(); ++j) for (u32 j=0; j<FrameList[defaultFrame].size(); ++j)
InterpolationBuffer.BoundingBox.addInternalPoint(FrameList[defaultFrame].pointer()[j].Pos); InterpolationBuffer.BoundingBox.addInternalPoint(FrameList[defaultFrame].pointer()[j].Pos);
} }
} }
...@@ -684,13 +680,13 @@ void CAnimatedMeshMD2::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalu ...@@ -684,13 +680,13 @@ void CAnimatedMeshMD2::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalu
} }
//! returns an axis aligned bounding box //! returns an axis aligned bounding box
const core::aabbox3d<f32>& CAnimatedMeshMD2::getBoundingBox() const const core::aabbox3d<f32>& CAnimatedMeshMD2::getBoundingBox() const
{ {
return InterpolationBuffer.BoundingBox; return InterpolationBuffer.BoundingBox;
} }
//! set user axis aligned bounding box //! set user axis aligned bounding box
void CAnimatedMeshMD2::setBoundingBox( const core::aabbox3df& box) void CAnimatedMeshMD2::setBoundingBox( const core::aabbox3df& box)
{ {
...@@ -698,7 +694,6 @@ void CAnimatedMeshMD2::setBoundingBox( const core::aabbox3df& box) ...@@ -698,7 +694,6 @@ void CAnimatedMeshMD2::setBoundingBox( const core::aabbox3df& box)
} }
//! Returns the type of the animated mesh. //! Returns the type of the animated mesh.
E_ANIMATED_MESH_TYPE CAnimatedMeshMD2::getMeshType() const E_ANIMATED_MESH_TYPE CAnimatedMeshMD2::getMeshType() const
{ {
...@@ -740,7 +735,6 @@ bool CAnimatedMeshMD2::getFrameLoop(const c8* name, ...@@ -740,7 +735,6 @@ bool CAnimatedMeshMD2::getFrameLoop(const c8* name,
} }
//! Returns amount of md2 animations in this file. //! Returns amount of md2 animations in this file.
s32 CAnimatedMeshMD2::getAnimationCount() const s32 CAnimatedMeshMD2::getAnimationCount() const
{ {
...@@ -762,3 +756,4 @@ const c8* CAnimatedMeshMD2::getAnimationName(s32 nr) const ...@@ -762,3 +756,4 @@ const c8* CAnimatedMeshMD2::getAnimationName(s32 nr) const
} // end namespace irr } // end namespace irr
#endif // _IRR_COMPILE_WITH_MD2_LOADER_ #endif // _IRR_COMPILE_WITH_MD2_LOADER_
...@@ -27,9 +27,9 @@ namespace scene ...@@ -27,9 +27,9 @@ namespace scene
struct SMD3Bone struct SMD3Bone
{ {
f32 Mins[3]; // bounding box per frame f32 Mins[3]; // bounding box per frame
f32 Maxs[3]; f32 Maxs[3];
f32 Position[3]; // position of bounding box f32 Position[3]; // position of bounding box
f32 scale; f32 scale;
c8 creator[16]; c8 creator[16];
}; };
...@@ -37,9 +37,9 @@ struct SMD3Bone ...@@ -37,9 +37,9 @@ struct SMD3Bone
struct SMD3Tag struct SMD3Tag
{ {
c8 Name[64]; //name of 'tag' as it's usually called in the md3 files try to see it as a sub-mesh/seperate mesh-part. c8 Name[64]; //name of 'tag' as it's usually called in the md3 files try to see it as a sub-mesh/seperate mesh-part.
f32 position[3]; //relative position of tag f32 position[3]; //relative position of tag
f32 rotationMatrix[9]; //3x3 rotation direction of tag f32 rotationMatrix[9]; //3x3 rotation direction of tag
}; };
struct SMD3Skin struct SMD3Skin
...@@ -72,7 +72,6 @@ CAnimatedMeshMD3::CAnimatedMeshMD3 () ...@@ -72,7 +72,6 @@ CAnimatedMeshMD3::CAnimatedMeshMD3 ()
} }
//! Destructor //! Destructor
CAnimatedMeshMD3::~CAnimatedMeshMD3() CAnimatedMeshMD3::~CAnimatedMeshMD3()
{ {
...@@ -82,13 +81,13 @@ CAnimatedMeshMD3::~CAnimatedMeshMD3() ...@@ -82,13 +81,13 @@ CAnimatedMeshMD3::~CAnimatedMeshMD3()
} }
//! Returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh. //! Returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
s32 CAnimatedMeshMD3::getFrameCount() s32 CAnimatedMeshMD3::getFrameCount()
{ {
return Mesh->MD3Header.numFrames << IPolShift; return Mesh->MD3Header.numFrames << IPolShift;
} }
//! Rendering Hint //! Rendering Hint
void CAnimatedMeshMD3::setInterpolationShift ( u32 shift, u32 loopMode ) void CAnimatedMeshMD3::setInterpolationShift ( u32 shift, u32 loopMode )
{ {
...@@ -106,6 +105,7 @@ SMD3QuaterionTagList *CAnimatedMeshMD3::getTagList(s32 frame, s32 detailLevel, s ...@@ -106,6 +105,7 @@ SMD3QuaterionTagList *CAnimatedMeshMD3::getTagList(s32 frame, s32 detailLevel, s
return &TagListIPol; return &TagListIPol;
} }
//! Returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. //! Returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail.
IMesh* CAnimatedMeshMD3::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop) IMesh* CAnimatedMeshMD3::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
{ {
...@@ -152,16 +152,15 @@ IMesh* CAnimatedMeshMD3::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, ...@@ -152,16 +152,15 @@ IMesh* CAnimatedMeshMD3::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop,
frame >>= IPolShift; frame >>= IPolShift;
frameA = core::s32_clamp ( frame, startFrameLoop, endFrameLoop ); frameA = core::s32_clamp ( frame, startFrameLoop, endFrameLoop );
frameB = core::s32_min ( frameA + 1, endFrameLoop ); frameB = core::s32_min ( frameA + 1, endFrameLoop );
} }
// build curren vertex // build current vertex
for ( i = 0; i!= Mesh->Buffer.size (); ++i ) for ( i = 0; i!= Mesh->Buffer.size (); ++i )
{ {
buildVertexArray ( frameA, frameB, iPol, buildVertexArray(frameA, frameB, iPol,
Mesh->Buffer[i], Mesh->Buffer[i],
(SMeshBuffer*) MeshIPol.getMeshBuffer ( i ) (SMeshBuffer*) MeshIPol.getMeshBuffer(i)
); );
} }
MeshIPol.recalculateBoundingBox (); MeshIPol.recalculateBoundingBox ();
...@@ -202,18 +201,15 @@ IMeshBuffer * CAnimatedMeshMD3::createMeshBuffer ( const SMD3MeshBuffer * source ...@@ -202,18 +201,15 @@ IMeshBuffer * CAnimatedMeshMD3::createMeshBuffer ( const SMD3MeshBuffer * source
//! build final mesh's vertices from frames frameA and frameB with linear interpolation. //! build final mesh's vertices from frames frameA and frameB with linear interpolation.
void CAnimatedMeshMD3::buildVertexArray ( u32 frameA, u32 frameB, f32 interpolate, void CAnimatedMeshMD3::buildVertexArray ( u32 frameA, u32 frameB, f32 interpolate,
const SMD3MeshBuffer * source, const SMD3MeshBuffer * source,
SMeshBuffer * dest SMeshBuffer * dest
) )
{ {
u32 i; u32 i;
u32 frameOffsetA = frameA * source->MeshHeader.numVertices; u32 frameOffsetA = frameA * source->MeshHeader.numVertices;
u32 frameOffsetB = frameB * source->MeshHeader.numVertices; u32 frameOffsetB = frameB * source->MeshHeader.numVertices;
f32 scale = ( 1.f/ 64.f ); const f32 scale = ( 1.f/ 64.f );
core::vector3df nA;
core::vector3df nB;
for ( i = 0; i!= (u32)source->MeshHeader.numVertices; ++i ) for ( i = 0; i!= (u32)source->MeshHeader.numVertices; ++i )
{ {
...@@ -228,13 +224,12 @@ void CAnimatedMeshMD3::buildVertexArray ( u32 frameA, u32 frameB, f32 interpolat ...@@ -228,13 +224,12 @@ void CAnimatedMeshMD3::buildVertexArray ( u32 frameA, u32 frameB, f32 interpolat
v.Pos.Z = scale * ( vA.position[1] + interpolate * ( vB.position[1] - vA.position[1] ) ); v.Pos.Z = scale * ( vA.position[1] + interpolate * ( vB.position[1] - vA.position[1] ) );
// normal // normal
getNormal ( nA, vA.normal[0], vA.normal[1] ); const core::vector3df nA(getNormal ( vA.normal[0], vA.normal[1] ));
getNormal ( nB, vB.normal[0], vB.normal[1] ); const core::vector3df nB(getNormal ( vB.normal[0], vB.normal[1] ));
v.Normal.X = nA.X + interpolate * ( nB.X - nA.X ); v.Normal.X = nA.X + interpolate * ( nB.X - nA.X );
v.Normal.Y = nA.Z + interpolate * ( nB.Z - nA.Z ); v.Normal.Y = nA.Z + interpolate * ( nB.Z - nA.Z );
v.Normal.Z = nA.Y + interpolate * ( nB.Y - nA.Y ); v.Normal.Z = nA.Y + interpolate * ( nB.Y - nA.Y );
} }
dest->recalculateBoundingBox (); dest->recalculateBoundingBox ();
...@@ -262,7 +257,6 @@ void CAnimatedMeshMD3::buildTagArray ( u32 frameA, u32 frameB, f32 interpolate ) ...@@ -262,7 +257,6 @@ void CAnimatedMeshMD3::buildTagArray ( u32 frameA, u32 frameB, f32 interpolate )
d.position.X = qA.position.X + interpolate * ( qB.position.X - qA.position.X ); d.position.X = qA.position.X + interpolate * ( qB.position.X - qA.position.X );
d.position.Y = qA.position.Y + interpolate * ( qB.position.Y - qA.position.Y ); d.position.Y = qA.position.Y + interpolate * ( qB.position.Y - qA.position.Y );
d.position.Z = qA.position.Z + interpolate * ( qB.position.Z - qA.position.Z ); d.position.Z = qA.position.Z + interpolate * ( qB.position.Z - qA.position.Z );
} }
} }
...@@ -275,8 +269,6 @@ bool CAnimatedMeshMD3::loadModelFile( u32 modelIndex, io::IReadFile* file) ...@@ -275,8 +269,6 @@ bool CAnimatedMeshMD3::loadModelFile( u32 modelIndex, io::IReadFile* file)
if (!file) if (!file)
return false; return false;
u32 i,g;
file->seek(0); file->seek(0);
//! Check MD3Header //! Check MD3Header
...@@ -299,6 +291,7 @@ bool CAnimatedMeshMD3::loadModelFile( u32 modelIndex, io::IReadFile* file) ...@@ -299,6 +291,7 @@ bool CAnimatedMeshMD3::loadModelFile( u32 modelIndex, io::IReadFile* file)
SMD3Tag import; SMD3Tag import;
SMD3QuaterionTag exp; SMD3QuaterionTag exp;
u32 i,g;
file->seek( Mesh->MD3Header.tagStart ); file->seek( Mesh->MD3Header.tagStart );
for (i = 0; i != totalTags; ++i ) for (i = 0; i != totalTags; ++i )
...@@ -385,7 +378,6 @@ bool CAnimatedMeshMD3::loadModelFile( u32 modelIndex, io::IReadFile* file) ...@@ -385,7 +378,6 @@ bool CAnimatedMeshMD3::loadModelFile( u32 modelIndex, io::IReadFile* file)
TagListIPol.Container.push_back ( Mesh->TagList.Container[i] ); TagListIPol.Container.push_back ( Mesh->TagList.Container[i] );
} }
return true; return true;
} }
...@@ -396,13 +388,13 @@ SMD3Mesh * CAnimatedMeshMD3::getOriginalMesh () ...@@ -396,13 +388,13 @@ SMD3Mesh * CAnimatedMeshMD3::getOriginalMesh ()
} }
//! Returns an axis aligned bounding box //! Returns an axis aligned bounding box
const core::aabbox3d<f32>& CAnimatedMeshMD3::getBoundingBox() const const core::aabbox3d<f32>& CAnimatedMeshMD3::getBoundingBox() const
{ {
return MeshIPol.BoundingBox; return MeshIPol.BoundingBox;
} }
//! Returns the type of the animated mesh. //! Returns the type of the animated mesh.
E_ANIMATED_MESH_TYPE CAnimatedMeshMD3::getMeshType() const E_ANIMATED_MESH_TYPE CAnimatedMeshMD3::getMeshType() const
{ {
...@@ -410,8 +402,8 @@ E_ANIMATED_MESH_TYPE CAnimatedMeshMD3::getMeshType() const ...@@ -410,8 +402,8 @@ E_ANIMATED_MESH_TYPE CAnimatedMeshMD3::getMeshType() const
} }
} // end namespace scene } // end namespace scene
} // end namespace irr } // end namespace irr
#endif // _IRR_COMPILE_WITH_MD3_LOADER_ #endif // _IRR_COMPILE_WITH_MD3_LOADER_
...@@ -18,7 +18,6 @@ namespace irr ...@@ -18,7 +18,6 @@ namespace irr
namespace scene namespace scene
{ {
class CAnimatedMeshMD3 : public IAnimatedMeshMD3 class CAnimatedMeshMD3 : public IAnimatedMeshMD3
{ {
public: public:
...@@ -79,7 +78,6 @@ namespace scene ...@@ -79,7 +78,6 @@ namespace scene
} }
private: private:
//! animates one frame //! animates one frame
inline void Animate (u32 frame); inline void Animate (u32 frame);
...@@ -123,15 +121,14 @@ namespace scene ...@@ -123,15 +121,14 @@ namespace scene
void buildTagArray ( u32 frameA, u32 frameB, f32 interpolate ); void buildTagArray ( u32 frameA, u32 frameB, f32 interpolate );
void getNormal ( core::vector3df & out, u32 i, u32 j ) core::vector3df getNormal ( u32 i, u32 j )
{ {
f32 lng = i * 2.0f * core::PI / 255.0f; const f32 lng = i * 2.0f * core::PI / 255.0f;
f32 lat = j * 2.0f * core::PI / 255.0f; const f32 lat = j * 2.0f * core::PI / 255.0f;
out.X = cosf ( lat ) * sinf ( lng ); return core::vector3df(cosf ( lat ) * sinf ( lng ),
out.Y = sinf ( lat ) * sinf ( lng ); sinf ( lat ) * sinf ( lng ),
out.Z = cos ( lng ); cos ( lng ));
} }
}; };
} // end namespace scene } // end namespace scene
......
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include "os.h" #include "os.h"
namespace irr namespace irr
{ {
namespace scene namespace scene
...@@ -27,19 +26,15 @@ CB3DMeshFileLoader::CB3DMeshFileLoader(scene::ISceneManager* smgr) ...@@ -27,19 +26,15 @@ CB3DMeshFileLoader::CB3DMeshFileLoader(scene::ISceneManager* smgr)
#endif #endif
} }
//! destructor //! destructor
CB3DMeshFileLoader::~CB3DMeshFileLoader() CB3DMeshFileLoader::~CB3DMeshFileLoader()
{ {
s32 n; for (s32 n=Materials.size()-1; n>=0; --n)
delete Materials[n].Material;
for (n=Materials.size()-1; n>=0; --n)
{
if (Materials[n].Material)
delete Materials[n].Material;
}
} }
//! returns true if the file maybe is able to be loaded by this class //! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".bsp") //! based on the file extension (e.g. ".bsp")
bool CB3DMeshFileLoader::isALoadableFileExtension(const c8* fileName) bool CB3DMeshFileLoader::isALoadableFileExtension(const c8* fileName)
...@@ -47,13 +42,13 @@ bool CB3DMeshFileLoader::isALoadableFileExtension(const c8* fileName) ...@@ -47,13 +42,13 @@ bool CB3DMeshFileLoader::isALoadableFileExtension(const c8* fileName)
return strstr(fileName, ".b3d") != 0; return strstr(fileName, ".b3d") != 0;
} }
//! creates/loads an animated mesh from the file. //! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed. //! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). //! If you no longer need the mesh, you should call IAnimatedMesh::drop().
//! See IUnknown::drop() for more information. //! See IUnknown::drop() for more information.
IAnimatedMesh* CB3DMeshFileLoader::createMesh(irr::io::IReadFile* f) IAnimatedMesh* CB3DMeshFileLoader::createMesh(irr::io::IReadFile* f)
{ {
if (!f) if (!f)
return 0; return 0;
...@@ -76,16 +71,13 @@ IAnimatedMesh* CB3DMeshFileLoader::createMesh(irr::io::IReadFile* f) ...@@ -76,16 +71,13 @@ IAnimatedMesh* CB3DMeshFileLoader::createMesh(irr::io::IReadFile* f)
return AnimatedMesh; return AnimatedMesh;
} }
bool CB3DMeshFileLoader::load() bool CB3DMeshFileLoader::load()
{ {
B3dStack.clear(); B3dStack.clear();
NormalsInFile=false; NormalsInFile=false;
//------ Get header ------ //------ Get header ------
SB3dChunkHeader header; SB3dChunkHeader header;
...@@ -179,16 +171,12 @@ bool CB3DMeshFileLoader::load() ...@@ -179,16 +171,12 @@ bool CB3DMeshFileLoader::load()
Buffers=0; Buffers=0;
AllJoints=0; AllJoints=0;
return true; return true;
} }
bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *InJoint) bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *InJoint)
{ {
core::stringc JointName = readString(); core::stringc JointName = readString();
f32 position[3], scale[3], rotation[4]; f32 position[3], scale[3], rotation[4];
...@@ -300,7 +288,6 @@ bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *InJoint) ...@@ -300,7 +288,6 @@ bool CB3DMeshFileLoader::readChunkNODE(CSkinnedMesh::SJoint *InJoint)
bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *InJoint) bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *InJoint)
{ {
s32 Vertices_Start=BaseVertices.size(); //B3Ds have Vertex ID's local within the mesh I don't want this s32 Vertices_Start=BaseVertices.size(); //B3Ds have Vertex ID's local within the mesh I don't want this
s32 brush_id; s32 brush_id;
...@@ -315,7 +302,6 @@ bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *InJoint) ...@@ -315,7 +302,6 @@ bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *InJoint)
while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) //this chunk repeats while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) //this chunk repeats
{ {
B3dStack.push_back(SB3dChunk()); B3dStack.push_back(SB3dChunk());
SB3dChunkHeader header; SB3dChunkHeader header;
...@@ -373,9 +359,6 @@ bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *InJoint) ...@@ -373,9 +359,6 @@ bool CB3DMeshFileLoader::readChunkMESH(CSkinnedMesh::SJoint *InJoint)
BaseVertices[Vertices_Start+i]->Normal=MeshBuffer->getVertex(i)->Normal; BaseVertices[Vertices_Start+i]->Normal=MeshBuffer->getVertex(i)->Normal;
} }
} }
} }
if (!knownChunk) if (!knownChunk)
...@@ -406,7 +389,6 @@ VRTS: ...@@ -406,7 +389,6 @@ VRTS:
*/ */
bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *InJoint, scene::SSkinMeshBuffer* MeshBuffer, s32 Vertices_Start) bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *InJoint, scene::SSkinMeshBuffer* MeshBuffer, s32 Vertices_Start)
{ {
s32 flags, tex_coord_sets, tex_coord_set_size; s32 flags, tex_coord_sets, tex_coord_set_size;
file->read(&flags, sizeof(flags)); file->read(&flags, sizeof(flags));
...@@ -430,12 +412,12 @@ bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *InJoint, scene::SSk ...@@ -430,12 +412,12 @@ bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *InJoint, scene::SSk
s32 MemoryNeeded = B3dStack.getLast().length / sizeof(f32); s32 MemoryNeeded = B3dStack.getLast().length / sizeof(f32);
s32 NumberOfReads = 3; s32 NumberOfReads = 3;
if (flags & 1) NumberOfReads += 3; if (flags & 1)
if (flags & 2) NumberOfReads += 4; NumberOfReads += 3;
if (flags & 2)
NumberOfReads += 4;
for (s32 i=0; i<tex_coord_sets; ++i) NumberOfReads += tex_coord_sets*tex_coord_set_size;
for (s32 j=0; j<tex_coord_set_size; ++j)
NumberOfReads += 1;
MemoryNeeded /= NumberOfReads; MemoryNeeded /= NumberOfReads;
...@@ -542,7 +524,6 @@ bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *InJoint, scene::SSk ...@@ -542,7 +524,6 @@ bool CB3DMeshFileLoader::readChunkVRTS(CSkinnedMesh::SJoint *InJoint, scene::SSk
bool CB3DMeshFileLoader::readChunkTRIS(CSkinnedMesh::SJoint *InJoint, scene::SSkinMeshBuffer *MeshBuffer, u32 MeshBufferID, s32 Vertices_Start) bool CB3DMeshFileLoader::readChunkTRIS(CSkinnedMesh::SJoint *InJoint, scene::SSkinMeshBuffer *MeshBuffer, u32 MeshBufferID, s32 Vertices_Start)
{ {
s32 triangle_brush_id; // Note: Irrlicht can't have different brushes for each triangle (I'm using a workaround) s32 triangle_brush_id; // Note: Irrlicht can't have different brushes for each triangle (I'm using a workaround)
file->read(&triangle_brush_id, sizeof(triangle_brush_id)); file->read(&triangle_brush_id, sizeof(triangle_brush_id));
...@@ -640,10 +621,8 @@ bool CB3DMeshFileLoader::readChunkTRIS(CSkinnedMesh::SJoint *InJoint, scene::SSk ...@@ -640,10 +621,8 @@ bool CB3DMeshFileLoader::readChunkTRIS(CSkinnedMesh::SJoint *InJoint, scene::SSk
} }
bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *InJoint) bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *InJoint)
{ {
if (B3dStack.getLast().length > 8) if (B3dStack.getLast().length > 8)
{ {
while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) // this chunk repeats while(B3dStack.getLast().startposition + B3dStack.getLast().length>file->getPos()) // this chunk repeats
...@@ -660,7 +639,6 @@ bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *InJoint) ...@@ -660,7 +639,6 @@ bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *InJoint)
Weight->strength = os::Byteswap::byteswap(Weight->strength); Weight->strength = os::Byteswap::byteswap(Weight->strength);
#endif #endif
if (AnimatedVertices_VertexID[GlobalVertexID]==-1) if (AnimatedVertices_VertexID[GlobalVertexID]==-1)
{ {
os::Printer::log("B3dMeshLoader: Weight has bad vertex id (no link to meshbuffer index found)"); os::Printer::log("B3dMeshLoader: Weight has bad vertex id (no link to meshbuffer index found)");
...@@ -680,10 +658,8 @@ bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *InJoint) ...@@ -680,10 +658,8 @@ bool CB3DMeshFileLoader::readChunkBONE(CSkinnedMesh::SJoint *InJoint)
} }
bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *InJoint) bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *InJoint)
{ {
s32 flags; s32 flags;
file->read(&flags, sizeof(flags)); file->read(&flags, sizeof(flags));
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
...@@ -713,8 +689,6 @@ bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *InJoint) ...@@ -713,8 +689,6 @@ bool CB3DMeshFileLoader::readChunkKEYS(CSkinnedMesh::SJoint *InJoint)
frame = os::Byteswap::byteswap(frame); frame = os::Byteswap::byteswap(frame);
#endif #endif
//frame *= 100; // Scale the animation frames up
core::vector3df position = core::vector3df(positionData[0], positionData[1], positionData[2]); core::vector3df position = core::vector3df(positionData[0], positionData[1], positionData[2]);
core::vector3df scale = core::vector3df(scaleData[0], scaleData[1], scaleData[2]); core::vector3df scale = core::vector3df(scaleData[0], scaleData[1], scaleData[2]);
core::quaternion rotation = core::quaternion(rotationData[1], rotationData[2], rotationData[3], rotationData[0]); // meant to be in this order core::quaternion rotation = core::quaternion(rotationData[1], rotationData[2], rotationData[3], rotationData[0]); // meant to be in this order
...@@ -761,15 +735,12 @@ bool CB3DMeshFileLoader::readChunkANIM(CSkinnedMesh::SJoint *InJoint) ...@@ -761,15 +735,12 @@ bool CB3DMeshFileLoader::readChunkANIM(CSkinnedMesh::SJoint *InJoint)
AnimFrames = os::Byteswap::byteswap(AnimFrames); AnimFrames = os::Byteswap::byteswap(AnimFrames);
#endif #endif
//AnimFrames*=100; //unneed soon...
B3dStack.erase(B3dStack.size()-1); B3dStack.erase(B3dStack.size()-1);
return true; return true;
} }
bool CB3DMeshFileLoader::readChunkTEXS() bool CB3DMeshFileLoader::readChunkTEXS()
{ {
bool Previous32BitTextureFlag = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_ALWAYS_32_BIT); bool Previous32BitTextureFlag = SceneManager->getVideoDriver()->getTextureCreationFlag(video::ETCF_ALWAYS_32_BIT);
SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true); SceneManager->getVideoDriver()->setTextureCreationFlag(video::ETCF_ALWAYS_32_BIT, true);
...@@ -805,9 +776,9 @@ bool CB3DMeshFileLoader::readChunkTEXS() ...@@ -805,9 +776,9 @@ bool CB3DMeshFileLoader::readChunkTEXS()
return true; return true;
} }
bool CB3DMeshFileLoader::readChunkBRUS() bool CB3DMeshFileLoader::readChunkBRUS()
{ {
s32 n_texs; s32 n_texs;
file->read(&n_texs, sizeof(s32)); file->read(&n_texs, sizeof(s32));
...@@ -865,6 +836,7 @@ bool CB3DMeshFileLoader::readChunkBRUS() ...@@ -865,6 +836,7 @@ bool CB3DMeshFileLoader::readChunkBRUS()
//Fixes problems when the lightmap is on the first texture: //Fixes problems when the lightmap is on the first texture:
if (texture_id[0] != -1) if (texture_id[0] != -1)
{
if (Textures[texture_id[0]].Flags & 65536) // 65536 = secondary UV if (Textures[texture_id[0]].Flags & 65536) // 65536 = secondary UV
{ {
SB3dTexture *TmpTexture; SB3dTexture *TmpTexture;
...@@ -872,6 +844,7 @@ bool CB3DMeshFileLoader::readChunkBRUS() ...@@ -872,6 +844,7 @@ bool CB3DMeshFileLoader::readChunkBRUS()
B3dMaterial.Textures[1] = B3dMaterial.Textures[0]; B3dMaterial.Textures[1] = B3dMaterial.Textures[0];
B3dMaterial.Textures[0] = TmpTexture; B3dMaterial.Textures[0] = TmpTexture;
} }
}
if (B3dMaterial.Textures[0] != 0) if (B3dMaterial.Textures[0] != 0)
B3dMaterial.Material->Textures[0] = B3dMaterial.Textures[0]->Texture; B3dMaterial.Material->Textures[0] = B3dMaterial.Textures[0]->Texture;
...@@ -900,9 +873,7 @@ bool CB3DMeshFileLoader::readChunkBRUS() ...@@ -900,9 +873,7 @@ bool CB3DMeshFileLoader::readChunkBRUS()
else else
B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
} }
else if (B3dMaterial.Textures[0]) //One texture:
//One texture:
else if (B3dMaterial.Textures[0])
{ {
if (B3dMaterial.Textures[0]->Flags & 2) //(Alpha mapped) if (B3dMaterial.Textures[0]->Flags & 2) //(Alpha mapped)
B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL; B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_ALPHA_CHANNEL;
...@@ -913,9 +884,7 @@ bool CB3DMeshFileLoader::readChunkBRUS() ...@@ -913,9 +884,7 @@ bool CB3DMeshFileLoader::readChunkBRUS()
else else
B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA; B3dMaterial.Material->MaterialType = video::EMT_TRANSPARENT_VERTEX_ALPHA;
} }
else //No texture:
//No texture:
else
{ {
if (B3dMaterial.alpha == 1) if (B3dMaterial.alpha == 1)
B3dMaterial.Material->MaterialType = video::EMT_SOLID; B3dMaterial.Material->MaterialType = video::EMT_SOLID;
...@@ -964,7 +933,8 @@ core::stringc CB3DMeshFileLoader::readString() ...@@ -964,7 +933,8 @@ core::stringc CB3DMeshFileLoader::readString()
{ {
c8 character; c8 character;
file->read(&character, sizeof(character)); file->read(&character, sizeof(character));
if (character==0) return newstring; if (character==0)
return newstring;
newstring.append(character); newstring.append(character);
} }
return newstring; return newstring;
...@@ -1003,3 +973,4 @@ void CB3DMeshFileLoader::readFloats(f32* vec, u32 count) ...@@ -1003,3 +973,4 @@ void CB3DMeshFileLoader::readFloats(f32* vec, u32 count)
#endif // _IRR_COMPILE_WITH_B3D_LOADER_ #endif // _IRR_COMPILE_WITH_B3D_LOADER_
// B3D mesh loader // B3D mesh loader
#include "IrrCompileConfig.h" #include "IrrCompileConfig.h"
#ifndef __C_B3D_MESH_LOADER_H_INCLUDED__ #ifndef __C_B3D_MESH_LOADER_H_INCLUDED__
...@@ -102,7 +101,6 @@ private: ...@@ -102,7 +101,6 @@ private:
core::array<video::S3DVertex2TCoords*> BaseVertices; core::array<video::S3DVertex2TCoords*> BaseVertices;
core::array<scene::SSkinMeshBuffer*> *Buffers; core::array<scene::SSkinMeshBuffer*> *Buffers;
core::array<CSkinnedMesh::SJoint*> *AllJoints; core::array<CSkinnedMesh::SJoint*> *AllJoints;
...@@ -110,11 +108,9 @@ private: ...@@ -110,11 +108,9 @@ private:
ISceneManager* SceneManager; ISceneManager* SceneManager;
CSkinnedMesh* AnimatedMesh; CSkinnedMesh* AnimatedMesh;
io::IReadFile* file; io::IReadFile* file;
}; };
} // end namespace scene } // end namespace scene
} // end namespace irr } // end namespace irr
......
...@@ -22,11 +22,9 @@ CBSPMeshFileLoader::CBSPMeshFileLoader(io::IFileSystem* fs,video::IVideoDriver* ...@@ -22,11 +22,9 @@ CBSPMeshFileLoader::CBSPMeshFileLoader(io::IFileSystem* fs,video::IVideoDriver*
if (Driver) if (Driver)
Driver->grab(); Driver->grab();
} }
//! destructor //! destructor
CBSPMeshFileLoader::~CBSPMeshFileLoader() CBSPMeshFileLoader::~CBSPMeshFileLoader()
{ {
...@@ -35,11 +33,9 @@ CBSPMeshFileLoader::~CBSPMeshFileLoader() ...@@ -35,11 +33,9 @@ CBSPMeshFileLoader::~CBSPMeshFileLoader()
if (Driver) if (Driver)
Driver->drop(); Driver->drop();
} }
//! returns true if the file maybe is able to be loaded by this class //! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".bsp") //! based on the file extension (e.g. ".bsp")
bool CBSPMeshFileLoader::isALoadableFileExtension(const c8* filename) bool CBSPMeshFileLoader::isALoadableFileExtension(const c8* filename)
...@@ -48,7 +44,6 @@ bool CBSPMeshFileLoader::isALoadableFileExtension(const c8* filename) ...@@ -48,7 +44,6 @@ bool CBSPMeshFileLoader::isALoadableFileExtension(const c8* filename)
} }
//! creates/loads an animated mesh from the file. //! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed. //! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). //! If you no longer need the mesh, you should call IAnimatedMesh::drop().
...@@ -85,3 +80,4 @@ IAnimatedMesh* CBSPMeshFileLoader::createMesh(irr::io::IReadFile* file) ...@@ -85,3 +80,4 @@ IAnimatedMesh* CBSPMeshFileLoader::createMesh(irr::io::IReadFile* file)
} // end namespace irr } // end namespace irr
#endif // _IRR_COMPILE_WITH_BSP_LOADER_ #endif // _IRR_COMPILE_WITH_BSP_LOADER_
...@@ -27,22 +27,20 @@ bool CMD2MeshFileLoader::isALoadableFileExtension(const c8* filename) ...@@ -27,22 +27,20 @@ bool CMD2MeshFileLoader::isALoadableFileExtension(const c8* filename)
} }
//! creates/loads an animated mesh from the file. //! creates/loads an animated mesh from the file.
//! \return Pointer to the created mesh. Returns 0 if loading failed. //! \return Pointer to the created mesh. Returns 0 if loading failed.
//! If you no longer need the mesh, you should call IAnimatedMesh::drop(). //! If you no longer need the mesh, you should call IAnimatedMesh::drop().
//! See IUnknown::drop() for more information. //! See IUnknown::drop() for more information.
IAnimatedMesh* CMD2MeshFileLoader::createMesh(irr::io::IReadFile* file) IAnimatedMesh* CMD2MeshFileLoader::createMesh(irr::io::IReadFile* file)
{ {
IAnimatedMesh* msh = 0; IAnimatedMesh* msh = new CAnimatedMeshMD2();
if (msh)
bool success = false; {
msh = new CAnimatedMeshMD2(); if (((CAnimatedMeshMD2*)msh)->loadFile(file))
success = ((CAnimatedMeshMD2*)msh)->loadFile(file); return msh;
if (success)
return msh;
msh->drop(); msh->drop();
}
return 0; return 0;
} }
...@@ -52,3 +50,4 @@ IAnimatedMesh* CMD2MeshFileLoader::createMesh(irr::io::IReadFile* file) ...@@ -52,3 +50,4 @@ IAnimatedMesh* CMD2MeshFileLoader::createMesh(irr::io::IReadFile* file)
#endif // _IRR_COMPILE_WITH_MD2_LOADER_ #endif // _IRR_COMPILE_WITH_MD2_LOADER_
...@@ -20,14 +20,12 @@ CMD3MeshFileLoader::CMD3MeshFileLoader(io::IFileSystem* fs, video::IVideoDriver* ...@@ -20,14 +20,12 @@ CMD3MeshFileLoader::CMD3MeshFileLoader(io::IFileSystem* fs, video::IVideoDriver*
} }
//! destructor //! destructor
CMD3MeshFileLoader::~CMD3MeshFileLoader() CMD3MeshFileLoader::~CMD3MeshFileLoader()
{ {
} }
//! returns true if the file maybe is able to be loaded by this class //! returns true if the file maybe is able to be loaded by this class
//! based on the file extension (e.g. ".bsp") //! based on the file extension (e.g. ".bsp")
bool CMD3MeshFileLoader::isALoadableFileExtension(const c8* filename) bool CMD3MeshFileLoader::isALoadableFileExtension(const c8* filename)
...@@ -35,6 +33,7 @@ bool CMD3MeshFileLoader::isALoadableFileExtension(const c8* filename) ...@@ -35,6 +33,7 @@ bool CMD3MeshFileLoader::isALoadableFileExtension(const c8* filename)
return strstr(filename, ".md3") != 0; return strstr(filename, ".md3") != 0;
} }
IAnimatedMesh* CMD3MeshFileLoader::createMesh(irr::io::IReadFile* file) IAnimatedMesh* CMD3MeshFileLoader::createMesh(irr::io::IReadFile* file)
{ {
CAnimatedMeshMD3 * mesh = new CAnimatedMeshMD3(); CAnimatedMeshMD3 * mesh = new CAnimatedMeshMD3();
...@@ -51,3 +50,4 @@ IAnimatedMesh* CMD3MeshFileLoader::createMesh(irr::io::IReadFile* file) ...@@ -51,3 +50,4 @@ IAnimatedMesh* CMD3MeshFileLoader::createMesh(irr::io::IReadFile* file)
} // end namespace irr } // end namespace irr
#endif // _IRR_COMPILE_WITH_MD3_LOADER_ #endif // _IRR_COMPILE_WITH_MD3_LOADER_
...@@ -11,6 +11,7 @@ ...@@ -11,6 +11,7 @@
#include "fast_atof.h" #include "fast_atof.h"
#include "coreutil.h" #include "coreutil.h"
#include "IVideoDriver.h"
namespace irr namespace irr
{ {
......
...@@ -7,10 +7,7 @@ ...@@ -7,10 +7,7 @@
#include "IMeshLoader.h" #include "IMeshLoader.h"
#include "IReadFile.h" #include "IReadFile.h"
#include "IVideoDriver.h"
#include "irrString.h" #include "irrString.h"
#include "CSkinnedMesh.h" #include "CSkinnedMesh.h"
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment