856 lines
23 KiB
C++
856 lines
23 KiB
C++
// Copyright (C) 2002-2007 Nikolaus Gebhardt
|
|
// This file is part of the "Irrlicht Engine".
|
|
// For conditions of distribution and use, see copyright notice in irrlicht.h
|
|
|
|
#include "CAnimatedMeshMD2.h"
|
|
#include "os.h"
|
|
#include "SColor.h"
|
|
#include "IReadFile.h"
|
|
#include "irrMath.h"
|
|
|
|
namespace irr
|
|
{
|
|
namespace scene
|
|
{
|
|
|
|
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
|
|
# pragma pack( push, packing )
|
|
# pragma pack( 1 )
|
|
# define PACK_STRUCT
|
|
#elif defined( __GNUC__ )
|
|
# define PACK_STRUCT __attribute__((packed))
|
|
#else
|
|
# error compiler not supported
|
|
#endif
|
|
|
|
// structs needed to load the md2-format
|
|
|
|
const s32 MD2_MAGIC_NUMBER = 844121161;
|
|
const s32 MD2_VERSION = 8;
|
|
const s32 MD2_MAX_VERTS = 2048;
|
|
|
|
// TA: private
|
|
const s32 MD2_FRAME_SHIFT = 2;
|
|
const f32 MD2_FRAME_SHIFT_RECIPROCAL = 1.f / ( 1 << MD2_FRAME_SHIFT );
|
|
|
|
struct SMD2Header
|
|
{
|
|
s32 magic;
|
|
s32 version;
|
|
s32 skinWidth;
|
|
s32 skinHeight;
|
|
s32 frameSize;
|
|
s32 numSkins;
|
|
s32 numVertices;
|
|
s32 numTexcoords;
|
|
s32 numTriangles;
|
|
s32 numGlCommands;
|
|
s32 numFrames;
|
|
s32 offsetSkins;
|
|
s32 offsetTexcoords;
|
|
s32 offsetTriangles;
|
|
s32 offsetFrames;
|
|
s32 offsetGlCommands;
|
|
s32 offsetEnd;
|
|
} PACK_STRUCT;
|
|
|
|
struct SMD2Vertex
|
|
{
|
|
u8 vertex[3];
|
|
u8 lightNormalIndex;
|
|
} PACK_STRUCT;
|
|
|
|
struct SMD2Frame
|
|
{
|
|
f32 scale[3];
|
|
f32 translate[3];
|
|
c8 name[16];
|
|
SMD2Vertex vertices[1];
|
|
} PACK_STRUCT;
|
|
|
|
struct SMD2Triangle
|
|
{
|
|
u16 vertexIndices[3];
|
|
u16 textureIndices[3];
|
|
} PACK_STRUCT;
|
|
|
|
struct SMD2TextureCoordinate
|
|
{
|
|
s16 s;
|
|
s16 t;
|
|
} PACK_STRUCT;
|
|
|
|
struct SMD2GLCommand
|
|
{
|
|
f32 s, t;
|
|
s32 vertexIndex;
|
|
} PACK_STRUCT;
|
|
|
|
// Default alignment
|
|
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
|
|
# pragma pack( pop, packing )
|
|
#endif
|
|
|
|
#undef PACK_STRUCT
|
|
|
|
|
|
const s32 Q2_VERTEX_NORMAL_TABLE_SIZE = 162;
|
|
|
|
static const f32 Q2_VERTEX_NORMAL_TABLE[Q2_VERTEX_NORMAL_TABLE_SIZE][3] = {
|
|
{-0.525731f, 0.000000f, 0.850651f},
|
|
{-0.442863f, 0.238856f, 0.864188f},
|
|
{-0.295242f, 0.000000f, 0.955423f},
|
|
{-0.309017f, 0.500000f, 0.809017f},
|
|
{-0.162460f, 0.262866f, 0.951056f},
|
|
{0.000000f, 0.000000f, 1.000000f},
|
|
{0.000000f, 0.850651f, 0.525731f},
|
|
{-0.147621f, 0.716567f, 0.681718f},
|
|
{0.147621f, 0.716567f, 0.681718f},
|
|
{0.000000f, 0.525731f, 0.850651f},
|
|
{0.309017f, 0.500000f, 0.809017f},
|
|
{0.525731f, 0.000000f, 0.850651f},
|
|
{0.295242f, 0.000000f, 0.955423f},
|
|
{0.442863f, 0.238856f, 0.864188f},
|
|
{0.162460f, 0.262866f, 0.951056f},
|
|
{-0.681718f, 0.147621f, 0.716567f},
|
|
{-0.809017f, 0.309017f, 0.500000f},
|
|
{-0.587785f, 0.425325f, 0.688191f},
|
|
{-0.850651f, 0.525731f, 0.000000f},
|
|
{-0.864188f, 0.442863f, 0.238856f},
|
|
{-0.716567f, 0.681718f, 0.147621f},
|
|
{-0.688191f, 0.587785f, 0.425325f},
|
|
{-0.500000f, 0.809017f, 0.309017f},
|
|
{-0.238856f, 0.864188f, 0.442863f},
|
|
{-0.425325f, 0.688191f, 0.587785f},
|
|
{-0.716567f, 0.681718f, -0.147621f},
|
|
{-0.500000f, 0.809017f, -0.309017f},
|
|
{-0.525731f, 0.850651f, 0.000000f},
|
|
{0.000000f, 0.850651f, -0.525731f},
|
|
{-0.238856f, 0.864188f, -0.442863f},
|
|
{0.000000f, 0.955423f, -0.295242f},
|
|
{-0.262866f, 0.951056f, -0.162460f},
|
|
{0.000000f, 1.000000f, 0.000000f},
|
|
{0.000000f, 0.955423f, 0.295242f},
|
|
{-0.262866f, 0.951056f, 0.162460f},
|
|
{0.238856f, 0.864188f, 0.442863f},
|
|
{0.262866f, 0.951056f, 0.162460f},
|
|
{0.500000f, 0.809017f, 0.309017f},
|
|
{0.238856f, 0.864188f, -0.442863f},
|
|
{0.262866f, 0.951056f, -0.162460f},
|
|
{0.500000f, 0.809017f, -0.309017f},
|
|
{0.850651f, 0.525731f, 0.000000f},
|
|
{0.716567f, 0.681718f, 0.147621f},
|
|
{0.716567f, 0.681718f, -0.147621f},
|
|
{0.525731f, 0.850651f, 0.000000f},
|
|
{0.425325f, 0.688191f, 0.587785f},
|
|
{0.864188f, 0.442863f, 0.238856f},
|
|
{0.688191f, 0.587785f, 0.425325f},
|
|
{0.809017f, 0.309017f, 0.500000f},
|
|
{0.681718f, 0.147621f, 0.716567f},
|
|
{0.587785f, 0.425325f, 0.688191f},
|
|
{0.955423f, 0.295242f, 0.000000f},
|
|
{1.000000f, 0.000000f, 0.000000f},
|
|
{0.951056f, 0.162460f, 0.262866f},
|
|
{0.850651f, -0.525731f, 0.000000f},
|
|
{0.955423f, -0.295242f, 0.000000f},
|
|
{0.864188f, -0.442863f, 0.238856f},
|
|
{0.951056f, -0.162460f, 0.262866f},
|
|
{0.809017f, -0.309017f, 0.500000f},
|
|
{0.681718f, -0.147621f, 0.716567f},
|
|
{0.850651f, 0.000000f, 0.525731f},
|
|
{0.864188f, 0.442863f, -0.238856f},
|
|
{0.809017f, 0.309017f, -0.500000f},
|
|
{0.951056f, 0.162460f, -0.262866f},
|
|
{0.525731f, 0.000000f, -0.850651f},
|
|
{0.681718f, 0.147621f, -0.716567f},
|
|
{0.681718f, -0.147621f, -0.716567f},
|
|
{0.850651f, 0.000000f, -0.525731f},
|
|
{0.809017f, -0.309017f, -0.500000f},
|
|
{0.864188f, -0.442863f, -0.238856f},
|
|
{0.951056f, -0.162460f, -0.262866f},
|
|
{0.147621f, 0.716567f, -0.681718f},
|
|
{0.309017f, 0.500000f, -0.809017f},
|
|
{0.425325f, 0.688191f, -0.587785f},
|
|
{0.442863f, 0.238856f, -0.864188f},
|
|
{0.587785f, 0.425325f, -0.688191f},
|
|
{0.688191f, 0.587785f, -0.425325f},
|
|
{-0.147621f, 0.716567f, -0.681718f},
|
|
{-0.309017f, 0.500000f, -0.809017f},
|
|
{0.000000f, 0.525731f, -0.850651f},
|
|
{-0.525731f, 0.000000f, -0.850651f},
|
|
{-0.442863f, 0.238856f, -0.864188f},
|
|
{-0.295242f, 0.000000f, -0.955423f},
|
|
{-0.162460f, 0.262866f, -0.951056f},
|
|
{0.000000f, 0.000000f, -1.000000f},
|
|
{0.295242f, 0.000000f, -0.955423f},
|
|
{0.162460f, 0.262866f, -0.951056f},
|
|
{-0.442863f, -0.238856f, -0.864188f},
|
|
{-0.309017f, -0.500000f, -0.809017f},
|
|
{-0.162460f, -0.262866f, -0.951056f},
|
|
{0.000000f, -0.850651f, -0.525731f},
|
|
{-0.147621f, -0.716567f, -0.681718f},
|
|
{0.147621f, -0.716567f, -0.681718f},
|
|
{0.000000f, -0.525731f, -0.850651f},
|
|
{0.309017f, -0.500000f, -0.809017f},
|
|
{0.442863f, -0.238856f, -0.864188f},
|
|
{0.162460f, -0.262866f, -0.951056f},
|
|
{0.238856f, -0.864188f, -0.442863f},
|
|
{0.500000f, -0.809017f, -0.309017f},
|
|
{0.425325f, -0.688191f, -0.587785f},
|
|
{0.716567f, -0.681718f, -0.147621f},
|
|
{0.688191f, -0.587785f, -0.425325f},
|
|
{0.587785f, -0.425325f, -0.688191f},
|
|
{0.000000f, -0.955423f, -0.295242f},
|
|
{0.000000f, -1.000000f, 0.000000f},
|
|
{0.262866f, -0.951056f, -0.162460f},
|
|
{0.000000f, -0.850651f, 0.525731f},
|
|
{0.000000f, -0.955423f, 0.295242f},
|
|
{0.238856f, -0.864188f, 0.442863f},
|
|
{0.262866f, -0.951056f, 0.162460f},
|
|
{0.500000f, -0.809017f, 0.309017f},
|
|
{0.716567f, -0.681718f, 0.147621f},
|
|
{0.525731f, -0.850651f, 0.000000f},
|
|
{-0.238856f, -0.864188f, -0.442863f},
|
|
{-0.500000f, -0.809017f, -0.309017f},
|
|
{-0.262866f, -0.951056f, -0.162460f},
|
|
{-0.850651f, -0.525731f, 0.000000f},
|
|
{-0.716567f, -0.681718f, -0.147621f},
|
|
{-0.716567f, -0.681718f, 0.147621f},
|
|
{-0.525731f, -0.850651f, 0.000000f},
|
|
{-0.500000f, -0.809017f, 0.309017f},
|
|
{-0.238856f, -0.864188f, 0.442863f},
|
|
{-0.262866f, -0.951056f, 0.162460f},
|
|
{-0.864188f, -0.442863f, 0.238856f},
|
|
{-0.809017f, -0.309017f, 0.500000f},
|
|
{-0.688191f, -0.587785f, 0.425325f},
|
|
{-0.681718f, -0.147621f, 0.716567f},
|
|
{-0.442863f, -0.238856f, 0.864188f},
|
|
{-0.587785f, -0.425325f, 0.688191f},
|
|
{-0.309017f, -0.500000f, 0.809017f},
|
|
{-0.147621f, -0.716567f, 0.681718f},
|
|
{-0.425325f, -0.688191f, 0.587785f},
|
|
{-0.162460f, -0.262866f, 0.951056f},
|
|
{0.442863f, -0.238856f, 0.864188f},
|
|
{0.162460f, -0.262866f, 0.951056f},
|
|
{0.309017f, -0.500000f, 0.809017f},
|
|
{0.147621f, -0.716567f, 0.681718f},
|
|
{0.000000f, -0.525731f, 0.850651f},
|
|
{0.425325f, -0.688191f, 0.587785f},
|
|
{0.587785f, -0.425325f, 0.688191f},
|
|
{0.688191f, -0.587785f, 0.425325f},
|
|
{-0.955423f, 0.295242f, 0.000000f},
|
|
{-0.951056f, 0.162460f, 0.262866f},
|
|
{-1.000000f, 0.000000f, 0.000000f},
|
|
{-0.850651f, 0.000000f, 0.525731f},
|
|
{-0.955423f, -0.295242f, 0.000000f},
|
|
{-0.951056f, -0.162460f, 0.262866f},
|
|
{-0.864188f, 0.442863f, -0.238856f},
|
|
{-0.951056f, 0.162460f, -0.262866f},
|
|
{-0.809017f, 0.309017f, -0.500000f},
|
|
{-0.864188f, -0.442863f, -0.238856f},
|
|
{-0.951056f, -0.162460f, -0.262866f},
|
|
{-0.809017f, -0.309017f, -0.500000f},
|
|
{-0.681718f, 0.147621f, -0.716567f},
|
|
{-0.681718f, -0.147621f, -0.716567f},
|
|
{-0.850651f, 0.000000f, -0.525731f},
|
|
{-0.688191f, 0.587785f, -0.425325f},
|
|
{-0.587785f, 0.425325f, -0.688191f},
|
|
{-0.425325f, 0.688191f, -0.587785f},
|
|
{-0.425325f, -0.688191f, -0.587785f},
|
|
{-0.587785f, -0.425325f, -0.688191f},
|
|
{-0.688191f, -0.587785f, -0.425325f},
|
|
};
|
|
|
|
struct SMD2AnimationType
|
|
{
|
|
s32 begin;
|
|
s32 end;
|
|
s32 fps;
|
|
};
|
|
|
|
static const SMD2AnimationType MD2AnimationTypeList[21] =
|
|
{
|
|
{ 0, 39, 9 }, // STAND
|
|
{ 40, 45, 10 }, // RUN
|
|
{ 46, 53, 10 }, // ATTACK
|
|
{ 54, 57, 7 }, // PAIN_A
|
|
{ 58, 61, 7 }, // PAIN_B
|
|
{ 62, 65, 7 }, // PAIN_C
|
|
{ 66, 71, 7 }, // JUMP
|
|
{ 72, 83, 7 }, // FLIP
|
|
{ 84, 94, 7 }, // SALUTE
|
|
{ 95, 111, 10 }, // FALLBACK
|
|
{ 112, 122, 7 }, // WAVE
|
|
{ 123, 134, 6 }, // POINT
|
|
{ 135, 153, 10 }, // CROUCH_STAND
|
|
{ 154, 159, 7 }, // CROUCH_WALK
|
|
{ 160, 168, 10 }, // CROUCH_ATTACK
|
|
{ 169, 172, 7 }, // CROUCH_PAIN
|
|
{ 173, 177, 5 }, // CROUCH_DEATH
|
|
{ 178, 183, 7 }, // DEATH_FALLBACK
|
|
{ 184, 189, 7 }, // DEATH_FALLFORWARD
|
|
{ 190, 197, 7 }, // DEATH_FALLBACKSLOW
|
|
{ 198, 198, 5 }, // BOOM
|
|
};
|
|
|
|
|
|
//! constructor
|
|
CAnimatedMeshMD2::CAnimatedMeshMD2()
|
|
: FrameList(0), FrameCount(0), TriangleCount(0)
|
|
{
|
|
#ifdef _DEBUG
|
|
IAnimatedMesh::setDebugName("CAnimatedMeshMD2 IAnimatedMesh");
|
|
IMesh::setDebugName("CAnimatedMeshMD2 IMesh");
|
|
IMeshBuffer::setDebugName("CAnimatedMeshMD2 IMeshBuffer");
|
|
#endif
|
|
}
|
|
|
|
|
|
|
|
//! destructor
|
|
CAnimatedMeshMD2::~CAnimatedMeshMD2()
|
|
{
|
|
if (FrameList)
|
|
delete [] FrameList;
|
|
}
|
|
|
|
|
|
|
|
//! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
|
|
s32 CAnimatedMeshMD2::getFrameCount()
|
|
{
|
|
return FrameCount<<MD2_FRAME_SHIFT;
|
|
}
|
|
|
|
|
|
|
|
//! returns the animated mesh based on a detail level. 0 is the lowest, 255 the highest detail. Note, that some Meshes will ignore the detail level.
|
|
IMesh* CAnimatedMeshMD2::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop, s32 endFrameLoop)
|
|
{
|
|
if ((u32)frame > (FrameCount<<MD2_FRAME_SHIFT))
|
|
frame = (frame % (FrameCount<<MD2_FRAME_SHIFT));
|
|
|
|
if (startFrameLoop == -1 && endFrameLoop == -1)
|
|
{
|
|
startFrameLoop = 0;
|
|
endFrameLoop = FrameCount<<MD2_FRAME_SHIFT;
|
|
}
|
|
|
|
updateInterpolationBuffer(frame, startFrameLoop, endFrameLoop);
|
|
return this;
|
|
}
|
|
|
|
|
|
//! returns amount of mesh buffers.
|
|
u32 CAnimatedMeshMD2::getMeshBufferCount() const
|
|
{
|
|
return 1;
|
|
}
|
|
|
|
|
|
//! returns pointer to a mesh buffer
|
|
IMeshBuffer* CAnimatedMeshMD2::getMeshBuffer(u32 nr) const
|
|
{
|
|
return (IMeshBuffer*) this;
|
|
}
|
|
|
|
|
|
//! Returns pointer to a mesh buffer which fits a material
|
|
IMeshBuffer* CAnimatedMeshMD2::getMeshBuffer( const video::SMaterial &material) const
|
|
{
|
|
if (Material == material)
|
|
return (IMeshBuffer*) this;
|
|
else
|
|
return 0;
|
|
}
|
|
|
|
|
|
//! returns the material of this meshbuffer
|
|
const video::SMaterial& CAnimatedMeshMD2::getMaterial() const
|
|
{
|
|
return Material;
|
|
}
|
|
|
|
|
|
//! returns the material of this meshbuffer
|
|
video::SMaterial& CAnimatedMeshMD2::getMaterial()
|
|
{
|
|
return Material;
|
|
}
|
|
|
|
|
|
|
|
//! returns pointer to vertices
|
|
const void* CAnimatedMeshMD2::getVertices() const
|
|
{
|
|
return InterpolateBuffer.const_pointer();
|
|
}
|
|
|
|
|
|
//! returns pointer to vertices
|
|
void* CAnimatedMeshMD2::getVertices()
|
|
{
|
|
return InterpolateBuffer.pointer();
|
|
}
|
|
|
|
|
|
|
|
//! returns which type of vertex data is stored.
|
|
video::E_VERTEX_TYPE CAnimatedMeshMD2::getVertexType() const
|
|
{
|
|
return video::EVT_STANDARD;
|
|
}
|
|
|
|
//! returns the byte size (stride, pitch) of the vertex
|
|
u32 CAnimatedMeshMD2::getVertexPitch() const
|
|
{
|
|
return sizeof ( video::S3DVertex );
|
|
}
|
|
|
|
|
|
|
|
//! returns amount of vertices
|
|
u32 CAnimatedMeshMD2::getVertexCount() const
|
|
{
|
|
return FrameList[0].size();
|
|
}
|
|
|
|
|
|
|
|
//! returns pointer to Indices
|
|
const u16* CAnimatedMeshMD2::getIndices() const
|
|
{
|
|
return Indices.const_pointer();
|
|
}
|
|
|
|
|
|
|
|
//! returns pointer to Indices
|
|
u16* CAnimatedMeshMD2::getIndices()
|
|
{
|
|
return Indices.pointer();
|
|
}
|
|
|
|
|
|
|
|
//! returns amount of indices
|
|
u32 CAnimatedMeshMD2::getIndexCount() const
|
|
{
|
|
return Indices.size();
|
|
}
|
|
|
|
|
|
// updates the interpolation buffer
|
|
void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, s32 endFrameLoop)
|
|
{
|
|
u32 firstFrame, secondFrame;
|
|
f32 div;
|
|
|
|
// TA: resolve missing ipol in loop between end-start
|
|
|
|
if (endFrameLoop - startFrameLoop == 0)
|
|
{
|
|
firstFrame = frame>>MD2_FRAME_SHIFT;
|
|
secondFrame = frame>>MD2_FRAME_SHIFT;
|
|
div = 1.0f;
|
|
}
|
|
else
|
|
{
|
|
// key frames
|
|
u32 s = startFrameLoop >> MD2_FRAME_SHIFT;
|
|
u32 e = endFrameLoop >> MD2_FRAME_SHIFT;
|
|
|
|
firstFrame = frame >> MD2_FRAME_SHIFT;
|
|
secondFrame = core::if_c_a_else_b ( firstFrame + 1 > e, s, firstFrame + 1 );
|
|
|
|
firstFrame = core::s32_min ( FrameCount - 1, firstFrame );
|
|
secondFrame = core::s32_min ( FrameCount - 1, secondFrame );
|
|
|
|
//div = (frame % (1<<MD2_FRAME_SHIFT)) / (f32)(1<<MD2_FRAME_SHIFT);
|
|
frame &= (1<<MD2_FRAME_SHIFT) - 1;
|
|
div = frame * MD2_FRAME_SHIFT_RECIPROCAL;
|
|
}
|
|
|
|
video::S3DVertex* target = &InterpolateBuffer[0];
|
|
video::S3DVertex* first = FrameList[firstFrame].pointer();
|
|
video::S3DVertex* second = FrameList[secondFrame].pointer();
|
|
|
|
s32 count = FrameList[firstFrame].size();
|
|
|
|
// interpolate both frames
|
|
for (s32 i=0; i<count; ++i)
|
|
{
|
|
target->Pos = (second->Pos - first->Pos) * div + first->Pos;
|
|
target->Normal = (second->Normal - first->Normal) * div + first->Normal;
|
|
|
|
++target;
|
|
++first;
|
|
++second;
|
|
}
|
|
|
|
//update bounding box
|
|
BoundingBox = BoxList[secondFrame].getInterpolated(BoxList[firstFrame], div);
|
|
}
|
|
|
|
|
|
|
|
|
|
//! loads an md2 file
|
|
bool CAnimatedMeshMD2::loadFile(io::IReadFile* file)
|
|
{
|
|
if (!file)
|
|
return false;
|
|
|
|
SMD2Header header;
|
|
|
|
file->read(&header, sizeof(SMD2Header));
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
header.magic = os::Byteswap::byteswap(header.magic);
|
|
header.version = os::Byteswap::byteswap(header.version);
|
|
header.skinWidth = os::Byteswap::byteswap(header.skinWidth);
|
|
header.skinHeight = os::Byteswap::byteswap(header.skinHeight);
|
|
header.frameSize = os::Byteswap::byteswap(header.frameSize);
|
|
header.numSkins = os::Byteswap::byteswap(header.numSkins);
|
|
header.numVertices = os::Byteswap::byteswap(header.numVertices);
|
|
header.numTexcoords = os::Byteswap::byteswap(header.numTexcoords);
|
|
header.numTriangles = os::Byteswap::byteswap(header.numTriangles);
|
|
header.numGlCommands = os::Byteswap::byteswap(header.numGlCommands);
|
|
header.numFrames = os::Byteswap::byteswap(header.numFrames);
|
|
header.offsetSkins = os::Byteswap::byteswap(header.offsetSkins);
|
|
header.offsetTexcoords = os::Byteswap::byteswap(header.offsetTexcoords);
|
|
header.offsetTriangles = os::Byteswap::byteswap(header.offsetTriangles);
|
|
header.offsetFrames = os::Byteswap::byteswap(header.offsetFrames);
|
|
header.offsetGlCommands = os::Byteswap::byteswap(header.offsetGlCommands);
|
|
header.offsetEnd = os::Byteswap::byteswap(header.offsetEnd);
|
|
#endif
|
|
|
|
if (header.magic != MD2_MAGIC_NUMBER || header.version != MD2_VERSION)
|
|
{
|
|
os::Printer::log("MD2 Loader: Wrong file header", file->getFileName(), ELL_WARNING);
|
|
return false;
|
|
}
|
|
|
|
// create Memory for indices and frames
|
|
|
|
TriangleCount = header.numTriangles;
|
|
if (FrameList)
|
|
delete [] FrameList;
|
|
FrameList = new core::array<video::S3DVertex>[header.numFrames];
|
|
FrameCount = header.numFrames;
|
|
|
|
s32 i;
|
|
|
|
for (i=0; i<header.numFrames; ++i)
|
|
FrameList[i].reallocate(header.numVertices);
|
|
|
|
// read TextureCoords
|
|
|
|
file->seek(header.offsetTexcoords, false);
|
|
SMD2TextureCoordinate* textureCoords = new SMD2TextureCoordinate[header.numTexcoords];
|
|
|
|
if (!file->read(textureCoords, sizeof(SMD2TextureCoordinate)*header.numTexcoords))
|
|
{
|
|
os::Printer::log("MD2 Loader: Error reading TextureCoords.", file->getFileName(), ELL_ERROR);
|
|
return false;
|
|
}
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
for (i=0; i<header.numTexcoords; ++i)
|
|
{
|
|
textureCoords[i].s = os::Byteswap::byteswap(textureCoords[i].s);
|
|
textureCoords[i].t = os::Byteswap::byteswap(textureCoords[i].t);
|
|
}
|
|
#endif
|
|
|
|
// read Triangles
|
|
|
|
file->seek(header.offsetTriangles, false);
|
|
|
|
SMD2Triangle *triangles = new SMD2Triangle[header.numTriangles];
|
|
if (!file->read(triangles, header.numTriangles *sizeof(SMD2Triangle)))
|
|
{
|
|
os::Printer::log("MD2 Loader: Error reading triangles.", file->getFileName(), ELL_ERROR);
|
|
return false;
|
|
}
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
for (i=0; i<header.numTriangles; ++i)
|
|
{
|
|
triangles[i].vertexIndices[0] = os::Byteswap::byteswap(triangles[i].vertexIndices[0]);
|
|
triangles[i].vertexIndices[1] = os::Byteswap::byteswap(triangles[i].vertexIndices[1]);
|
|
triangles[i].vertexIndices[2] = os::Byteswap::byteswap(triangles[i].vertexIndices[2]);
|
|
triangles[i].textureIndices[0] = os::Byteswap::byteswap(triangles[i].textureIndices[0]);
|
|
triangles[i].textureIndices[1] = os::Byteswap::byteswap(triangles[i].textureIndices[1]);
|
|
triangles[i].textureIndices[2] = os::Byteswap::byteswap(triangles[i].textureIndices[2]);
|
|
}
|
|
#endif
|
|
|
|
// read Vertices
|
|
|
|
u8 buffer[MD2_MAX_VERTS*4+128];
|
|
SMD2Frame* frame = (SMD2Frame*)buffer;
|
|
|
|
core::array< core::vector3df >* vertices = new core::array< core::vector3df >[header.numFrames];
|
|
core::array< core::vector3df >* normals = new core::array< core::vector3df >[header.numFrames];
|
|
|
|
file->seek(header.offsetFrames, false);
|
|
|
|
for (i = 0; i<header.numFrames; ++i)
|
|
{
|
|
// read vertices
|
|
|
|
file->read(frame, header.frameSize);
|
|
|
|
#ifdef __BIG_ENDIAN__
|
|
frame->scale[0] = os::Byteswap::byteswap(frame->scale[0]);
|
|
frame->scale[1] = os::Byteswap::byteswap(frame->scale[1]);
|
|
frame->scale[2] = os::Byteswap::byteswap(frame->scale[2]);
|
|
frame->translate[0] = os::Byteswap::byteswap(frame->translate[0]);
|
|
frame->translate[1] = os::Byteswap::byteswap(frame->translate[1]);
|
|
frame->translate[2] = os::Byteswap::byteswap(frame->translate[2]);
|
|
#endif
|
|
// store frame data
|
|
|
|
SFrameData fdata;
|
|
fdata.begin = i;
|
|
fdata.end = i;
|
|
fdata.fps = 7;
|
|
|
|
if (frame->name[0])
|
|
{
|
|
for (s32 s = 0; frame->name[s]!=0 && (frame->name[s] < '0' ||
|
|
frame->name[s] > '9'); ++s)
|
|
fdata.name += frame->name[s];
|
|
|
|
if (!FrameData.empty() && FrameData[FrameData.size()-1].name == fdata.name)
|
|
++FrameData[FrameData.size()-1].end;
|
|
else
|
|
FrameData.push_back(fdata);
|
|
}
|
|
|
|
// add vertices
|
|
|
|
vertices[i].reallocate(header.numVertices);
|
|
for (s32 j=0; j<header.numVertices; ++j)
|
|
{
|
|
core::vector3df v;
|
|
v.X = frame->vertices[j].vertex[0] * frame->scale[0] + frame->translate[0];
|
|
v.Z = frame->vertices[j].vertex[1] * frame->scale[1] + frame->translate[1];
|
|
v.Y = frame->vertices[j].vertex[2] * frame->scale[2] + frame->translate[2];
|
|
|
|
vertices[i].push_back(v);
|
|
|
|
u8 normalidx = frame->vertices[j].lightNormalIndex;
|
|
if (normalidx < Q2_VERTEX_NORMAL_TABLE_SIZE)
|
|
{
|
|
v.X = Q2_VERTEX_NORMAL_TABLE[normalidx][0];
|
|
v.Z = Q2_VERTEX_NORMAL_TABLE[normalidx][1];
|
|
v.Y = Q2_VERTEX_NORMAL_TABLE[normalidx][2];
|
|
}
|
|
|
|
normals[i].push_back(v);
|
|
}
|
|
|
|
// calculate bounding boxes
|
|
if (header.numVertices)
|
|
{
|
|
core::aabbox3d<f32> box;
|
|
box.reset(vertices[i][0]);
|
|
|
|
for (s32 j=1; j<header.numVertices; ++j)
|
|
box.addInternalPoint(vertices[i][j]);
|
|
|
|
BoxList.push_back(box);
|
|
}
|
|
|
|
}
|
|
|
|
// put triangles into frame list
|
|
|
|
f32 dmaxs = 1.0f/(header.skinWidth);
|
|
f32 dmaxt = 1.0f/(header.skinHeight);
|
|
|
|
video::S3DVertex vtx;
|
|
vtx.Color = video::SColor(255,255,255,255);
|
|
|
|
for (s32 f = 0; f<header.numFrames; ++f)
|
|
{
|
|
core::array< core::vector3df >& vert = vertices[f];
|
|
|
|
for (s32 t=0; t<header.numTriangles; ++t)
|
|
{
|
|
for (s32 n=0; n<3; ++n)
|
|
{
|
|
vtx.Pos = vert[triangles[t].vertexIndices[n]];
|
|
vtx.Normal = normals[f].pointer()[triangles[t].vertexIndices[n]];
|
|
vtx.TCoords.X = (textureCoords[triangles[t].textureIndices[n]].s + 0.5f) * dmaxs;
|
|
vtx.TCoords.Y = (textureCoords[triangles[t].textureIndices[n]].t + 0.5f) * dmaxt;
|
|
FrameList[f].push_back(vtx);
|
|
}
|
|
}
|
|
}
|
|
|
|
// create indices
|
|
|
|
Indices.reallocate(header.numVertices);
|
|
s16 count = TriangleCount*3;
|
|
for (s16 n=0; n<count; n+=3)
|
|
{
|
|
Indices.push_back(n);
|
|
Indices.push_back(n+1);
|
|
Indices.push_back(n+2);
|
|
}
|
|
|
|
// reallocate interpolate buffer
|
|
if (header.numFrames)
|
|
{
|
|
s32 currCount = FrameList[0].size();
|
|
InterpolateBuffer.set_used(currCount);
|
|
|
|
for (i=0; i<currCount; ++i)
|
|
{
|
|
InterpolateBuffer[i].TCoords = FrameList[0].pointer()[i].TCoords;
|
|
InterpolateBuffer[i].Color = vtx.Color;
|
|
}
|
|
}
|
|
|
|
// clean up
|
|
|
|
delete [] normals;
|
|
delete [] vertices;
|
|
delete [] triangles;
|
|
delete [] textureCoords;
|
|
|
|
// return
|
|
|
|
calculateBoundingBox();
|
|
|
|
return true;
|
|
}
|
|
|
|
|
|
|
|
//! calculates the bounding box
|
|
void CAnimatedMeshMD2::calculateBoundingBox()
|
|
{
|
|
BoundingBox.reset(0,0,0);
|
|
|
|
if (FrameCount)
|
|
{
|
|
u32 defaultFrame = 1;
|
|
|
|
if (defaultFrame>=FrameCount)
|
|
defaultFrame = 0;
|
|
|
|
for (u32 j=0; j<FrameList[defaultFrame].size(); ++j)
|
|
BoundingBox.addInternalPoint(FrameList[defaultFrame].pointer()[j].Pos);
|
|
}
|
|
}
|
|
|
|
|
|
//! sets a flag of all contained materials to a new value
|
|
void CAnimatedMeshMD2::setMaterialFlag(video::E_MATERIAL_FLAG flag, bool newvalue)
|
|
{
|
|
Material.setFlag(flag, newvalue);
|
|
}
|
|
|
|
|
|
|
|
//! returns an axis aligned bounding box
|
|
const core::aabbox3d<f32>& CAnimatedMeshMD2::getBoundingBox() const
|
|
{
|
|
return BoundingBox;
|
|
}
|
|
|
|
//! set user axis aligned bounding box
|
|
void CAnimatedMeshMD2::setBoundingBox( const core::aabbox3df& box)
|
|
{
|
|
BoundingBox = box;
|
|
}
|
|
|
|
|
|
|
|
//! calculates normals
|
|
void CAnimatedMeshMD2::calculateNormals()
|
|
{
|
|
for (u32 i=0; i<FrameCount; ++i)
|
|
{
|
|
video::S3DVertex* vtx = FrameList[i].pointer();
|
|
|
|
for (u32 j=0; j<Indices.size(); j+=3)
|
|
{
|
|
core::plane3d<f32> plane(
|
|
vtx[Indices[j]].Pos, vtx[Indices[j+1]].Pos, vtx[Indices[j+2]].Pos);
|
|
|
|
vtx[Indices[j]].Normal = plane.Normal;
|
|
vtx[Indices[j+1]].Normal = plane.Normal;
|
|
vtx[Indices[j+2]].Normal = plane.Normal;
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
//! Returns the type of the animated mesh.
|
|
E_ANIMATED_MESH_TYPE CAnimatedMeshMD2::getMeshType() const
|
|
{
|
|
return EAMT_MD2;
|
|
}
|
|
|
|
|
|
//! Returns frame loop data for a special MD2 animation type.
|
|
void CAnimatedMeshMD2::getFrameLoop(EMD2_ANIMATION_TYPE l,
|
|
s32& outBegin, s32& outEnd, s32& outFPS) const
|
|
{
|
|
if (l < 0 || l >= EMAT_COUNT)
|
|
return;
|
|
|
|
outBegin = MD2AnimationTypeList[l].begin << MD2_FRAME_SHIFT;
|
|
outEnd = MD2AnimationTypeList[l].end << MD2_FRAME_SHIFT;
|
|
|
|
// correct to anim between last->first frame
|
|
outEnd += MD2_FRAME_SHIFT == 0 ? 1 : ( 1 << MD2_FRAME_SHIFT ) - 1;
|
|
outFPS = MD2AnimationTypeList[l].fps << MD2_FRAME_SHIFT;
|
|
}
|
|
|
|
|
|
//! Returns frame loop data for a special MD2 animation type.
|
|
bool CAnimatedMeshMD2::getFrameLoop(const c8* name,
|
|
s32& outBegin, s32&outEnd, s32& outFPS) const
|
|
{
|
|
for (s32 i=0; i<(s32)FrameData.size(); ++i)
|
|
if (FrameData[i].name == name)
|
|
{
|
|
outBegin = FrameData[i].begin << MD2_FRAME_SHIFT;
|
|
outEnd = FrameData[i].end << MD2_FRAME_SHIFT;
|
|
outEnd += MD2_FRAME_SHIFT == 0 ? 1 : ( 1 << MD2_FRAME_SHIFT ) - 1;
|
|
outFPS = FrameData[i].fps << MD2_FRAME_SHIFT;
|
|
return true;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
|
|
|
|
//! Returns amount of md2 animations in this file.
|
|
s32 CAnimatedMeshMD2::getAnimationCount() const
|
|
{
|
|
return FrameData.size();
|
|
}
|
|
|
|
|
|
//! Returns name of md2 animation.
|
|
const c8* CAnimatedMeshMD2::getAnimationName(s32 nr) const
|
|
{
|
|
if (nr < 0 || nr >= (s32)FrameData.size())
|
|
return 0;
|
|
|
|
return FrameData[nr].name.c_str();
|
|
}
|
|
|
|
|
|
} // end namespace scene
|
|
} // end namespace irr
|
|
|