Merged revisions 1972:2004 from 1.5 branch, except for some revisions which seemed to be merged already. MD2 loader updated, terrain node fixed, opengl texture handling fixed.
git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2005 dfc29bdd-3216-0410-991c-e03cc46cb475master
parent
0ef1056eb8
commit
7809c48144
|
@ -8,6 +8,11 @@ Changes in version 1.6
|
|||
|
||||
- Add a hitPosition out parameter to ISceneCollisionManager::getCollisionResultPosition() - this is a (small) API breaking change.
|
||||
|
||||
-------------------------------------
|
||||
Changes in version 1.5.1 (??.?? 2009)
|
||||
|
||||
- MD2 mesh loader: Now uses much less memory, reduced number of allocations when loading meshes.
|
||||
|
||||
-----------------------------------
|
||||
Changes in version 1.5 (15.12.2008)
|
||||
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
#ifdef _IRR_COMPILE_WITH_MD2_LOADER_
|
||||
|
||||
#include "CAnimatedMeshMD2.h"
|
||||
#include "os.h"
|
||||
#include "SColor.h"
|
||||
#include "IReadFile.h"
|
||||
#include "irrMath.h"
|
||||
|
||||
namespace irr
|
||||
|
@ -16,86 +14,9 @@ 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;
|
||||
|
||||
|
@ -299,7 +220,7 @@ static const SMD2AnimationType MD2AnimationTypeList[21] =
|
|||
|
||||
//! constructor
|
||||
CAnimatedMeshMD2::CAnimatedMeshMD2()
|
||||
: InterpolationBuffer(0), FrameList(0), FrameCount(0), TriangleCount(0)
|
||||
: InterpolationBuffer(0), FrameList(0), FrameCount(0)
|
||||
{
|
||||
#ifdef _DEBUG
|
||||
IAnimatedMesh::setDebugName("CAnimatedMeshMD2 IAnimatedMesh");
|
||||
|
@ -317,7 +238,6 @@ CAnimatedMeshMD2::~CAnimatedMeshMD2()
|
|||
InterpolationBuffer->drop();
|
||||
}
|
||||
|
||||
|
||||
//! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
|
||||
u32 CAnimatedMeshMD2::getFrameCount() const
|
||||
{
|
||||
|
@ -342,7 +262,7 @@ IMesh* CAnimatedMeshMD2::getMesh(s32 frame, s32 detailLevel, s32 startFrameLoop,
|
|||
}
|
||||
|
||||
|
||||
//! returns amount of mesh buffers.
|
||||
//! returns amount of mesh buffers. MD2 meshes only have one buffer
|
||||
u32 CAnimatedMeshMD2::getMeshBufferCount() const
|
||||
{
|
||||
return 1;
|
||||
|
@ -352,7 +272,10 @@ u32 CAnimatedMeshMD2::getMeshBufferCount() const
|
|||
//! returns pointer to a mesh buffer
|
||||
IMeshBuffer* CAnimatedMeshMD2::getMeshBuffer(u32 nr) const
|
||||
{
|
||||
if (nr == 0)
|
||||
return InterpolationBuffer;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
@ -371,6 +294,7 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop,
|
|||
{
|
||||
u32 firstFrame, secondFrame;
|
||||
f32 div;
|
||||
core::vector3df* NormalTable = (core::vector3df*)&Q2_VERTEX_NORMAL_TABLE;
|
||||
|
||||
// TA: resolve missing ipol in loop between end-start
|
||||
|
||||
|
@ -398,16 +322,24 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop,
|
|||
}
|
||||
|
||||
video::S3DVertex* target = static_cast<video::S3DVertex*>(InterpolationBuffer->getVertices());
|
||||
video::S3DVertex* first = FrameList[firstFrame].pointer();
|
||||
video::S3DVertex* second = FrameList[secondFrame].pointer();
|
||||
SMD2Vert* first = FrameList[firstFrame].pointer();
|
||||
SMD2Vert* second = FrameList[secondFrame].pointer();
|
||||
|
||||
// interpolate both frames
|
||||
const u32 count = FrameList[firstFrame].size();
|
||||
for (u32 i=0; i<count; ++i)
|
||||
{
|
||||
target->Pos = (second->Pos - first->Pos) * div + first->Pos;
|
||||
target->Normal = (second->Normal - first->Normal) * div + first->Normal;
|
||||
core::vector3df one, two;
|
||||
one.X = f32(first->Pos.X) * FrameTransforms[firstFrame].scale.X + FrameTransforms[firstFrame].translate.X;
|
||||
one.Y = f32(first->Pos.Y) * FrameTransforms[firstFrame].scale.Y + FrameTransforms[firstFrame].translate.Y;
|
||||
one.Z = f32(first->Pos.Z) * FrameTransforms[firstFrame].scale.Z + FrameTransforms[firstFrame].translate.Z;
|
||||
two.X = f32(second->Pos.X) * FrameTransforms[secondFrame].scale.X + FrameTransforms[secondFrame].translate.X;
|
||||
two.Y = f32(second->Pos.Y) * FrameTransforms[secondFrame].scale.Y + FrameTransforms[secondFrame].translate.Y;
|
||||
two.Z = f32(second->Pos.Z) * FrameTransforms[secondFrame].scale.Z + FrameTransforms[secondFrame].translate.Z;
|
||||
target->Pos = (two - one) * div + one;
|
||||
|
||||
target->Normal = (NormalTable[second->NormalIdx] - NormalTable[first->NormalIdx]) * div
|
||||
+ NormalTable[first->NormalIdx];
|
||||
++target;
|
||||
++first;
|
||||
++second;
|
||||
|
@ -418,242 +350,6 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop,
|
|||
InterpolationBuffer->setDirty();
|
||||
}
|
||||
|
||||
|
||||
//! 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);
|
||||
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);
|
||||
|
||||
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);
|
||||
|
||||
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
|
||||
|
||||
InterpolationBuffer->Indices.reallocate(header.numVertices);
|
||||
const u32 count = TriangleCount*3;
|
||||
for (u32 n=0; n<count; n+=3)
|
||||
{
|
||||
InterpolationBuffer->Indices.push_back(n);
|
||||
InterpolationBuffer->Indices.push_back(n+1);
|
||||
InterpolationBuffer->Indices.push_back(n+2);
|
||||
}
|
||||
|
||||
// reallocate interpolate buffer
|
||||
if (header.numFrames)
|
||||
{
|
||||
const u32 currCount = FrameList[0].size();
|
||||
InterpolationBuffer->Vertices.set_used(currCount);
|
||||
|
||||
for (u32 num=0; num<currCount; ++num)
|
||||
{
|
||||
InterpolationBuffer->Vertices[num].TCoords = FrameList[0].pointer()[num].TCoords;
|
||||
InterpolationBuffer->Vertices[num].Color = vtx.Color;
|
||||
}
|
||||
}
|
||||
|
||||
// clean up
|
||||
|
||||
delete [] normals;
|
||||
delete [] vertices;
|
||||
delete [] triangles;
|
||||
delete [] textureCoords;
|
||||
|
||||
// return
|
||||
|
||||
calculateBoundingBox();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
//! calculates the bounding box
|
||||
void CAnimatedMeshMD2::calculateBoundingBox()
|
||||
{
|
||||
|
@ -666,8 +362,8 @@ void CAnimatedMeshMD2::calculateBoundingBox()
|
|||
if (defaultFrame>=FrameCount)
|
||||
defaultFrame = 0;
|
||||
|
||||
for (u32 j=0; j<FrameList[defaultFrame].size(); ++j)
|
||||
InterpolationBuffer->BoundingBox.addInternalPoint(FrameList[defaultFrame].pointer()[j].Pos);
|
||||
// for (u32 j=0; j<FrameList[defaultFrame].size(); ++j)
|
||||
// InterpolationBuffer->BoundingBox.addInternalPoint(FrameList[defaultFrame].pointer()[j].Pos);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -736,14 +432,14 @@ void CAnimatedMeshMD2::getFrameLoop(EMD2_ANIMATION_TYPE l,
|
|||
bool CAnimatedMeshMD2::getFrameLoop(const c8* name,
|
||||
s32& outBegin, s32&outEnd, s32& outFPS) const
|
||||
{
|
||||
for (u32 i=0; i<FrameData.size(); ++i)
|
||||
for (u32 i=0; i < AnimationData.size(); ++i)
|
||||
{
|
||||
if (FrameData[i].name == name)
|
||||
if (AnimationData[i].name == name)
|
||||
{
|
||||
outBegin = FrameData[i].begin << MD2_FRAME_SHIFT;
|
||||
outEnd = FrameData[i].end << MD2_FRAME_SHIFT;
|
||||
outBegin = AnimationData[i].begin << MD2_FRAME_SHIFT;
|
||||
outEnd = AnimationData[i].end << MD2_FRAME_SHIFT;
|
||||
outEnd += MD2_FRAME_SHIFT == 0 ? 1 : ( 1 << MD2_FRAME_SHIFT ) - 1;
|
||||
outFPS = FrameData[i].fps << MD2_FRAME_SHIFT;
|
||||
outFPS = AnimationData[i].fps << MD2_FRAME_SHIFT;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -755,17 +451,17 @@ bool CAnimatedMeshMD2::getFrameLoop(const c8* name,
|
|||
//! Returns amount of md2 animations in this file.
|
||||
s32 CAnimatedMeshMD2::getAnimationCount() const
|
||||
{
|
||||
return FrameData.size();
|
||||
return AnimationData.size();
|
||||
}
|
||||
|
||||
|
||||
//! Returns name of md2 animation.
|
||||
const c8* CAnimatedMeshMD2::getAnimationName(s32 nr) const
|
||||
{
|
||||
if ((u32)nr >= FrameData.size())
|
||||
if ((u32)nr >= AnimationData.size())
|
||||
return 0;
|
||||
|
||||
return FrameData[nr].name.c_str();
|
||||
return AnimationData[nr].name.c_str();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,9 +28,6 @@ namespace scene
|
|||
//! destructor
|
||||
virtual ~CAnimatedMeshMD2();
|
||||
|
||||
//! loads an md2 file
|
||||
virtual bool loadFile(io::IReadFile* file);
|
||||
|
||||
//! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
|
||||
virtual u32 getFrameCount() const;
|
||||
|
||||
|
@ -82,19 +79,16 @@ namespace scene
|
|||
//! \param nr: Zero based index of animation.
|
||||
virtual const c8* getAnimationName(s32 nr) const;
|
||||
|
||||
private:
|
||||
|
||||
//! updates the interpolation buffer
|
||||
void updateInterpolationBuffer(s32 frame, s32 startFrame, s32 endFrame);
|
||||
|
||||
//! calculates the bounding box
|
||||
virtual void calculateBoundingBox();
|
||||
//
|
||||
// exposed for loader
|
||||
//
|
||||
|
||||
//! the buffer that contains the most recent animation
|
||||
SMeshBuffer* InterpolationBuffer;
|
||||
core::array<video::S3DVertex> *FrameList;
|
||||
core::array<core::aabbox3d<f32> > BoxList;
|
||||
|
||||
struct SFrameData
|
||||
//! named animations
|
||||
struct SAnimationData
|
||||
{
|
||||
core::stringc name;
|
||||
s32 begin;
|
||||
|
@ -102,10 +96,44 @@ namespace scene
|
|||
s32 fps;
|
||||
};
|
||||
|
||||
core::array< SFrameData > FrameData;
|
||||
//! scale and translations for keyframes
|
||||
struct SKeyFrameTransform
|
||||
{
|
||||
core::vector3df scale;
|
||||
core::vector3df translate;
|
||||
};
|
||||
|
||||
//! md2 vertex data
|
||||
struct SMD2Vert
|
||||
{
|
||||
core::vector3d<u8> Pos;
|
||||
u8 NormalIdx;
|
||||
};
|
||||
|
||||
//! keyframe transformations
|
||||
core::array<SKeyFrameTransform> FrameTransforms;
|
||||
|
||||
//! keyframe vertex data
|
||||
core::array<SMD2Vert> *FrameList;
|
||||
|
||||
//! bounding boxes for each keyframe
|
||||
core::array<core::aabbox3d<f32> > BoxList;
|
||||
|
||||
//! named animations
|
||||
core::array< SAnimationData > AnimationData;
|
||||
|
||||
//! calculates the bounding box
|
||||
virtual void calculateBoundingBox();
|
||||
|
||||
u32 FrameCount;
|
||||
s32 TriangleCount;
|
||||
|
||||
private:
|
||||
|
||||
//! updates the interpolation buffer
|
||||
void updateInterpolationBuffer(s32 frame, s32 startFrame, s32 endFrame);
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
|
|
|
@ -7,20 +7,96 @@
|
|||
|
||||
#include "CMD2MeshFileLoader.h"
|
||||
#include "CAnimatedMeshMD2.h"
|
||||
#include "os.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;
|
||||
|
||||
struct SMD2Header
|
||||
{
|
||||
s32 magic; // four character code "IDP2"
|
||||
s32 version; // must be 8
|
||||
s32 skinWidth; // width of the texture
|
||||
s32 skinHeight; // height of the texture
|
||||
s32 frameSize; // size in bytes of an animation frame
|
||||
s32 numSkins; // number of textures
|
||||
s32 numVertices; // total number of vertices
|
||||
s32 numTexcoords; // number of vertices with texture coords
|
||||
s32 numTriangles; // number of triangles
|
||||
s32 numGlCommands; // number of opengl commands (triangle strip or triangle fan)
|
||||
s32 numFrames; // animation keyframe count
|
||||
s32 offsetSkins; // offset in bytes to 64 character skin names
|
||||
s32 offsetTexcoords; // offset in bytes to texture coordinate list
|
||||
s32 offsetTriangles; // offset in bytes to triangle list
|
||||
s32 offsetFrames; // offset in bytes to frame list
|
||||
s32 offsetGlCommands;// offset in bytes to opengl commands
|
||||
s32 offsetEnd; // offset in bytes to end of file
|
||||
} PACK_STRUCT;
|
||||
|
||||
struct SMD2Vertex
|
||||
{
|
||||
u8 vertex[3]; // [0] = X, [1] = Z, [2] = Y
|
||||
u8 lightNormalIndex; // index in the normal table
|
||||
} PACK_STRUCT;
|
||||
|
||||
struct SMD2Frame
|
||||
{
|
||||
f32 scale[3]; // first scale the vertex position
|
||||
f32 translate[3]; // then translate the position
|
||||
c8 name[16]; // the name of the animation that this key belongs to
|
||||
SMD2Vertex vertices[1]; // vertex 1 of SMD2Header.numVertices
|
||||
} 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
|
||||
|
||||
//! Constructor
|
||||
CMD2MeshFileLoader::CMD2MeshFileLoader()
|
||||
{
|
||||
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CMD2MeshFileLoader");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,7 +117,7 @@ IAnimatedMesh* CMD2MeshFileLoader::createMesh(io::IReadFile* file)
|
|||
IAnimatedMesh* msh = new CAnimatedMeshMD2();
|
||||
if (msh)
|
||||
{
|
||||
if (((CAnimatedMeshMD2*)msh)->loadFile(file))
|
||||
if (loadFile(file, (CAnimatedMeshMD2*)msh) )
|
||||
return msh;
|
||||
|
||||
msh->drop();
|
||||
|
@ -50,6 +126,246 @@ IAnimatedMesh* CMD2MeshFileLoader::createMesh(io::IReadFile* file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//! loads an md2 file
|
||||
bool CMD2MeshFileLoader::loadFile(io::IReadFile* file, CAnimatedMeshMD2* mesh)
|
||||
{
|
||||
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;
|
||||
}
|
||||
|
||||
//
|
||||
// prepare mesh and allocate memory
|
||||
//
|
||||
|
||||
mesh->FrameCount = header.numFrames;
|
||||
|
||||
// create keyframes
|
||||
mesh->FrameTransforms.set_used(header.numFrames);
|
||||
|
||||
// create vertex arrays for each keyframe
|
||||
if (mesh->FrameList)
|
||||
delete [] mesh->FrameList;
|
||||
mesh->FrameList = new core::array<CAnimatedMeshMD2::SMD2Vert>[header.numFrames];
|
||||
|
||||
// allocate space in vertex arrays
|
||||
s32 i;
|
||||
for (i=0; i<header.numFrames; ++i)
|
||||
mesh->FrameList[i].reallocate(header.numVertices);
|
||||
|
||||
// allocate interpolation buffer vertices
|
||||
mesh->InterpolationBuffer->Vertices.set_used(header.numTriangles*3);
|
||||
|
||||
// populate triangles
|
||||
mesh->InterpolationBuffer->Indices.reallocate(header.numTriangles*3);
|
||||
const s32 count = header.numTriangles*3;
|
||||
for (i=0; i<count; i+=3)
|
||||
{
|
||||
mesh->InterpolationBuffer->Indices.push_back(i);
|
||||
mesh->InterpolationBuffer->Indices.push_back(i+1);
|
||||
mesh->InterpolationBuffer->Indices.push_back(i+2);
|
||||
}
|
||||
|
||||
//
|
||||
// read texture coordinates
|
||||
//
|
||||
|
||||
file->seek(header.offsetTexcoords);
|
||||
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);
|
||||
|
||||
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;
|
||||
|
||||
file->seek(header.offsetFrames);
|
||||
|
||||
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
|
||||
//
|
||||
|
||||
CAnimatedMeshMD2::SAnimationData adata;
|
||||
adata.begin = i;
|
||||
adata.end = i;
|
||||
adata.fps = 7;
|
||||
|
||||
// Add new named animation if necessary
|
||||
if (frame->name[0])
|
||||
{
|
||||
// get animation name
|
||||
for (s32 s = 0; s < 16 && frame->name[s]!=0 && (frame->name[s] < '0' || frame->name[s] > '9'); ++s)
|
||||
{
|
||||
adata.name += frame->name[s];
|
||||
}
|
||||
|
||||
// Does this keyframe have the same animation name as the current animation?
|
||||
if (!mesh->AnimationData.empty() && mesh->AnimationData[mesh->AnimationData.size()-1].name == adata.name)
|
||||
{
|
||||
// Increase the length of the animation
|
||||
++mesh->AnimationData[mesh->AnimationData.size() - 1].end;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the new animation
|
||||
mesh->AnimationData.push_back(adata);
|
||||
}
|
||||
}
|
||||
|
||||
// save keyframe scale and translation
|
||||
|
||||
mesh->FrameTransforms[i].scale.X = frame->scale[0];
|
||||
mesh->FrameTransforms[i].scale.Z = frame->scale[1];
|
||||
mesh->FrameTransforms[i].scale.Y = frame->scale[2];
|
||||
mesh->FrameTransforms[i].translate.X = frame->translate[0];
|
||||
mesh->FrameTransforms[i].translate.Z = frame->translate[1];
|
||||
mesh->FrameTransforms[i].translate.Y = frame->translate[2];
|
||||
|
||||
// add vertices
|
||||
for (s32 j=0; j<header.numTriangles; ++j)
|
||||
{
|
||||
for (u32 ti=0; ti<3; ++ti)
|
||||
{
|
||||
CAnimatedMeshMD2::SMD2Vert v;
|
||||
u32 num = triangles[j].vertexIndices[ti];
|
||||
v.Pos.X = frame->vertices[num].vertex[0];
|
||||
v.Pos.Z = frame->vertices[num].vertex[1];
|
||||
v.Pos.Y = frame->vertices[num].vertex[2];
|
||||
v.NormalIdx = frame->vertices[num].lightNormalIndex;
|
||||
|
||||
mesh->FrameList[i].push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate bounding boxes
|
||||
if (header.numVertices)
|
||||
{
|
||||
core::aabbox3d<f32> box;
|
||||
core::vector3df pos;
|
||||
pos.X = f32(mesh->FrameList[i] [0].Pos.X) * mesh->FrameTransforms[i].scale.X + mesh->FrameTransforms[i].translate.X;
|
||||
pos.Y = f32(mesh->FrameList[i] [0].Pos.Y) * mesh->FrameTransforms[i].scale.Y + mesh->FrameTransforms[i].translate.Y;
|
||||
pos.Z = f32(mesh->FrameList[i] [0].Pos.Z) * mesh->FrameTransforms[i].scale.Z + mesh->FrameTransforms[i].translate.Z;
|
||||
|
||||
box.reset(pos);
|
||||
|
||||
for (s32 j=1; j<header.numTriangles*3; ++j)
|
||||
{
|
||||
pos.X = f32(mesh->FrameList[i] [j].Pos.X) * mesh->FrameTransforms[i].scale.X + mesh->FrameTransforms[i].translate.X;
|
||||
pos.Y = f32(mesh->FrameList[i] [j].Pos.Y) * mesh->FrameTransforms[i].scale.Y + mesh->FrameTransforms[i].translate.Y;
|
||||
pos.Z = f32(mesh->FrameList[i] [j].Pos.Z) * mesh->FrameTransforms[i].scale.Z + mesh->FrameTransforms[i].translate.Z;
|
||||
|
||||
box.addInternalPoint(pos);
|
||||
}
|
||||
mesh->BoxList.push_back(box);
|
||||
}
|
||||
}
|
||||
|
||||
// populate interpolation buffer with texture coordinates and colours
|
||||
if (header.numFrames)
|
||||
{
|
||||
f32 dmaxs = 1.0f/(header.skinWidth);
|
||||
f32 dmaxt = 1.0f/(header.skinHeight);
|
||||
|
||||
for (s32 t=0; t<header.numTriangles; ++t)
|
||||
{
|
||||
for (s32 n=0; n<3; ++n)
|
||||
{
|
||||
mesh->InterpolationBuffer->Vertices[t*3 + n].TCoords.X = (textureCoords[triangles[t].textureIndices[n]].s + 0.5f) * dmaxs;
|
||||
mesh->InterpolationBuffer->Vertices[t*3 + n].TCoords.Y = (textureCoords[triangles[t].textureIndices[n]].t + 0.5f) * dmaxt;
|
||||
mesh->InterpolationBuffer->Vertices[t*3 + n].Color = video::SColor(255,255,255,255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clean up
|
||||
delete [] triangles;
|
||||
delete [] textureCoords;
|
||||
|
||||
// return
|
||||
|
||||
mesh->calculateBoundingBox();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace scene
|
||||
} // end namespace irr
|
||||
|
||||
|
|
|
@ -12,6 +12,8 @@ namespace irr
|
|||
namespace scene
|
||||
{
|
||||
|
||||
class CAnimatedMeshMD2;
|
||||
|
||||
//! Meshloader capable of loading MD2 files
|
||||
class CMD2MeshFileLoader : public IMeshLoader
|
||||
{
|
||||
|
@ -30,6 +32,10 @@ public:
|
|||
//! See IReferenceCounted::drop() for more information.
|
||||
virtual IAnimatedMesh* createMesh(io::IReadFile* file);
|
||||
|
||||
private:
|
||||
//! Loads the file data into the mesh
|
||||
bool loadFile(io::IReadFile* file, CAnimatedMeshMD2* mesh);
|
||||
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
|
|
|
@ -178,7 +178,7 @@ void COpenGLTexture::copyTexture(bool newTexture)
|
|||
break;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, TextureName);
|
||||
Driver->setTexture(0, this);
|
||||
if (Driver->testGLError())
|
||||
os::Printer::log("Could not bind Texture", ELL_ERROR);
|
||||
|
||||
|
@ -416,7 +416,7 @@ void COpenGLTexture::bindRTT()
|
|||
//! Unbind Render Target Texture
|
||||
void COpenGLTexture::unbindRTT()
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, getOpenGLTextureName());
|
||||
Driver->setTexture(0, this);
|
||||
|
||||
// Copy Our ViewPort To The Texture
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, getSize().Width, getSize().Height);
|
||||
|
@ -456,7 +456,7 @@ COpenGLFBOTexture::COpenGLFBOTexture(const core::dimension2d<s32>& size,
|
|||
|
||||
// generate color texture
|
||||
glGenTextures(1, &TextureName);
|
||||
glBindTexture(GL_TEXTURE_2D, TextureName);
|
||||
Driver->setTexture(0, this);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
|
|
@ -48,6 +48,8 @@ namespace scene
|
|||
#endif
|
||||
|
||||
RenderBuffer = new CDynamicMeshBuffer(video::EVT_2TCOORDS, video::EIT_16BIT);
|
||||
RenderBuffer->setHardwareMappingHint(scene::EHM_STATIC, scene::EBT_VERTEX);
|
||||
RenderBuffer->setHardwareMappingHint(scene::EHM_DYNAMIC, scene::EBT_INDEX);
|
||||
|
||||
if (FileSystem)
|
||||
FileSystem->grab();
|
||||
|
@ -163,7 +165,7 @@ namespace scene
|
|||
vertex.Normal.set(0.0f, 1.0f, 0.0f);
|
||||
vertex.Color = vertexColor;
|
||||
vertex.Pos.X = fx;
|
||||
vertex.Pos.Y = (f32) heightMap->getPixel(TerrainData.Size-x,z).getLuminance();
|
||||
vertex.Pos.Y = (f32) heightMap->getPixel(TerrainData.Size-x-1,z).getLuminance();
|
||||
vertex.Pos.Z = fz;
|
||||
|
||||
vertex.TCoords.X = vertex.TCoords2.X = 1.f-fx2;
|
||||
|
@ -233,7 +235,9 @@ namespace scene
|
|||
|
||||
|
||||
//! Initializes the terrain data. Loads the vertices from the heightMapFile
|
||||
bool CTerrainSceneNode::loadHeightMapRAW( io::IReadFile* file, s32 bitsPerPixel, bool signedData, bool floatVals, s32 width, video::SColor vertexColor, s32 smoothFactor )
|
||||
bool CTerrainSceneNode::loadHeightMapRAW(io::IReadFile* file,
|
||||
s32 bitsPerPixel, bool signedData, bool floatVals,
|
||||
s32 width, video::SColor vertexColor, s32 smoothFactor)
|
||||
{
|
||||
if (!file)
|
||||
return false;
|
||||
|
@ -451,7 +455,8 @@ namespace scene
|
|||
setRotation(TerrainData.Rotation);
|
||||
|
||||
// Pre-allocate memory for indices
|
||||
RenderBuffer->getIndexBuffer().set_used( TerrainData.PatchCount * TerrainData.PatchCount *
|
||||
RenderBuffer->getIndexBuffer().set_used(
|
||||
TerrainData.PatchCount*TerrainData.PatchCount*
|
||||
TerrainData.CalcPatchSize*TerrainData.CalcPatchSize*6);
|
||||
|
||||
const u32 endTime = os::Timer::getTime();
|
||||
|
@ -883,7 +888,8 @@ namespace scene
|
|||
//! \return: Number if indices put into the buffer.
|
||||
s32 CTerrainSceneNode::getIndicesForPatch(core::array<u32>& indices, s32 patchX, s32 patchZ, s32 LOD)
|
||||
{
|
||||
if ( patchX < 0 || patchX > TerrainData.PatchCount - 1 || patchZ < 0 || patchZ > TerrainData.PatchCount - 1 )
|
||||
if (patchX < 0 || patchX > TerrainData.PatchCount-1 ||
|
||||
patchZ < 0 || patchZ > TerrainData.PatchCount-1)
|
||||
return -1;
|
||||
|
||||
if (LOD < -1 || LOD > TerrainData.MaxLOD - 1)
|
||||
|
@ -1374,7 +1380,8 @@ namespace scene
|
|||
s32 X(core::floor32(pos.X));
|
||||
s32 Z(core::floor32(pos.Z));
|
||||
|
||||
if( X >= 0 && X < TerrainData.Size && Z >= 0 && Z < TerrainData.Size )
|
||||
if (X >= 0 && X < TerrainData.Size-1 &&
|
||||
Z >= 0 && Z < TerrainData.Size-1)
|
||||
{
|
||||
const video::S3DVertex2TCoords* Vertices = (const video::S3DVertex2TCoords*)Mesh.getMeshBuffer(0)->getVertices();
|
||||
const core::vector3df& a = Vertices[X * TerrainData.Size + Z].Pos;
|
||||
|
|
126
tests/main.cpp
126
tests/main.cpp
|
@ -1,23 +1,31 @@
|
|||
// This is the entry point for the Irrlicht test suite.
|
||||
// This is an MSVC pragma to link against the Irrlicht library.
|
||||
// Other builds must link against it in the project files.
|
||||
#if defined(_MSC_VER)
|
||||
#pragma comment(lib, "Irrlicht.lib")
|
||||
#define _CRT_SECURE_NO_WARNINGS
|
||||
#endif // _MSC_VER
|
||||
|
||||
#include "testUtils.h"
|
||||
#include <stdio.h>
|
||||
#include <time.h>
|
||||
#include <assert.h>
|
||||
#include <vector>
|
||||
|
||||
// This is an MSVC pragma to link against the Irrlicht library.
|
||||
// Other builds must link against it in the project files.
|
||||
#if defined(_MSC_VER)
|
||||
#pragma comment(lib, "Irrlicht.lib")
|
||||
#endif // _MSC_VER
|
||||
|
||||
typedef struct _STestDefinition
|
||||
{
|
||||
bool(*testSignature)(void);
|
||||
const char * testName;
|
||||
} STestDefinition;
|
||||
/* Each test must have the same signature. Test should (but are not
|
||||
* required to) live in a .cpp file of the same name. There is no
|
||||
* need to #include anything since the test entry points can be
|
||||
* declared as extern before calling them.
|
||||
*/
|
||||
#define RUN_TEST(testEntryPoint)\
|
||||
extern bool testEntryPoint(void);\
|
||||
logTestString("\nStarting test '" #testEntryPoint "'\n");\
|
||||
if(!testEntryPoint()) \
|
||||
{\
|
||||
(void)printf("\n\n\n******** Test failure ********\nTest '" #testEntryPoint "' failed\n"\
|
||||
"******** Test failure ********\n\nPress return to continue\n");\
|
||||
(void)getc(stdin);\
|
||||
fails++;\
|
||||
}
|
||||
|
||||
//! This is the main entry point for the Irrlicht test suite.
|
||||
/** \return The number of test that failed, i.e. 0 is success. */
|
||||
|
@ -33,42 +41,45 @@ int main(int argumentCount, char * arguments[])
|
|||
return 9999;
|
||||
}
|
||||
|
||||
extern bool disambiguateTextures(void);
|
||||
extern bool softwareDevice(void);
|
||||
extern bool exports(void);
|
||||
extern bool testVector3d(void);
|
||||
extern bool testVector2d(void);
|
||||
extern bool planeMatrix(void);
|
||||
extern bool fast_atof(void);
|
||||
extern bool line2dIntersectWith(void);
|
||||
extern bool drawPixel(void);
|
||||
extern bool md2Animation(void);
|
||||
extern bool b3dAnimation(void);
|
||||
extern bool guiDisabledMenu(void);
|
||||
extern bool textureRenderStates(void);
|
||||
|
||||
#define TEST(x)\
|
||||
{\
|
||||
extern bool x(void);\
|
||||
STestDefinition newTest;\
|
||||
newTest.testSignature = x;\
|
||||
newTest.testName = #x;\
|
||||
tests.push_back(newTest);\
|
||||
}
|
||||
typedef struct _STest
|
||||
{
|
||||
bool(*testSignature)(void);
|
||||
const char * testName;
|
||||
} STest;
|
||||
|
||||
std::vector<STestDefinition> tests;
|
||||
#define TEST(x) { x, #x }
|
||||
|
||||
// Note that to interactively debug a test, you will generally want to move it
|
||||
// (temporarily) to the beginning of the list, since each test runs in its own
|
||||
// process.
|
||||
TEST(disambiguateTextures); // Normally you should run this first, since it validates the working directory.
|
||||
TEST(vectorPositionDimension2d);
|
||||
TEST(irrCoreEquals);
|
||||
TEST(sceneNodeAnimator);
|
||||
TEST(sceneCollisionManager);
|
||||
TEST(collisionResponseAnimator);
|
||||
TEST(exports);
|
||||
TEST(testVector3d);
|
||||
TEST(testVector2d);
|
||||
TEST(planeMatrix);
|
||||
TEST(fast_atof);
|
||||
TEST(line2dIntersectWith);
|
||||
TEST(testDimension2d);
|
||||
TEST(drawPixel);
|
||||
TEST(md2Animation);
|
||||
TEST(guiDisabledMenu);
|
||||
TEST(softwareDevice);
|
||||
TEST(b3dAnimation);
|
||||
TEST(terrainSceneNode);
|
||||
|
||||
const unsigned int numberOfTests = tests.size();
|
||||
static const STest tests[] =
|
||||
{
|
||||
TEST(disambiguateTextures), // Run this first, since it validates the WD.
|
||||
TEST(exports),
|
||||
TEST(testVector3d),
|
||||
TEST(testVector2d),
|
||||
TEST(planeMatrix),
|
||||
TEST(fast_atof),
|
||||
TEST(line2dIntersectWith),
|
||||
TEST(drawPixel),
|
||||
TEST(md2Animation),
|
||||
TEST(guiDisabledMenu),
|
||||
TEST(softwareDevice),
|
||||
TEST(b3dAnimation),
|
||||
TEST(textureRenderStates)
|
||||
};
|
||||
static const unsigned int numberOfTests = sizeof tests / sizeof tests[0];
|
||||
|
||||
unsigned int testToRun = 0;
|
||||
unsigned int fails = 0;
|
||||
|
@ -102,22 +113,10 @@ int main(int argumentCount, char * arguments[])
|
|||
}
|
||||
|
||||
testToRun++;
|
||||
if(testToRun < numberOfTests)
|
||||
|
||||
if(testToRun == numberOfTests)
|
||||
{
|
||||
closeTestLog();
|
||||
char runNextTest[256];
|
||||
(void)sprintf(runNextTest, "\"%s\" %d %d", arguments[0], testToRun, fails);
|
||||
fails = system(runNextTest);
|
||||
}
|
||||
|
||||
if(1 == testToRun)
|
||||
{
|
||||
(void)openTestLog(false);
|
||||
const int passed = numberOfTests - fails;
|
||||
|
||||
logTestString("\nTests finished. %d test%s of %d passed.\n",
|
||||
passed, 1 == passed ? "" : "s", numberOfTests);
|
||||
|
||||
logTestString("\nTests finished. %d test%s failed.\n", fails, 1 == fails ? "" : "s");
|
||||
if(0 == fails)
|
||||
{
|
||||
time_t rawtime;
|
||||
|
@ -134,6 +133,13 @@ int main(int argumentCount, char * arguments[])
|
|||
}
|
||||
closeTestLog();
|
||||
}
|
||||
else
|
||||
{
|
||||
closeTestLog();
|
||||
char runNextTest[256];
|
||||
(void)sprintf(runNextTest, "\"%s\" %d %d", arguments[0], testToRun, fails);
|
||||
fails = system(runNextTest);
|
||||
}
|
||||
|
||||
return fails;
|
||||
}
|
||||
|
|
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
After Width: | Height: | Size: 21 KiB |
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
Binary file not shown.
After Width: | Height: | Size: 30 KiB |
|
@ -59,6 +59,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="..\lib\Win32-visualstudio\Irrlicht.lib"
|
||||
OutputFile="..\bin\Win32-VisualStudio\$(ProjectName).exe"
|
||||
GenerateDebugInformation="true"
|
||||
TargetMachine="1"
|
||||
|
@ -129,6 +130,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="..\lib\Win32-visualstudio\Irrlicht.lib"
|
||||
OutputFile="..\bin\Win32-VisualStudio\$(ProjectName).exe"
|
||||
GenerateDebugInformation="true"
|
||||
OptimizeReferences="2"
|
||||
|
@ -246,6 +248,10 @@
|
|||
RelativePath=".\testVector3d.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\textureRenderStates.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\vectorPositionDimension2d.cpp"
|
||||
>
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright (C) 2008 Christian Stehno, Colin MacDonald
|
||||
// No rights reserved: this software is in the public domain.
|
||||
|
||||
#include "irrlicht.h"
|
||||
#include "testUtils.h"
|
||||
|
||||
using namespace irr;
|
||||
using namespace core;
|
||||
using namespace scene;
|
||||
using namespace video;
|
||||
using namespace io;
|
||||
using namespace gui;
|
||||
|
||||
//! Tests interleaved loading and rendering of textures
|
||||
/** The test loads a texture, renders it using draw2dimage, loads another
|
||||
texture and renders the first one again. Due to the texture cache this
|
||||
can lead to rendering of the second texture in second place. */
|
||||
static bool runTestWithDriver(E_DRIVER_TYPE driverType)
|
||||
{
|
||||
IrrlichtDevice *device = createDevice( driverType, dimension2d<s32>(160, 120), 32);
|
||||
if (!device)
|
||||
return true; // Treat a failure to create a driver as benign; this saves a lot of #ifdefs
|
||||
|
||||
IVideoDriver* driver = device->getVideoDriver();
|
||||
ISceneManager * smgr = device->getSceneManager();
|
||||
|
||||
ITexture* tex1 = driver->getTexture("../media/wall.bmp");
|
||||
|
||||
(void)smgr->addCameraSceneNode();
|
||||
|
||||
driver->beginScene(true, true, SColor(255,100,101,140));
|
||||
driver->draw2DImage(tex1, position2di(0,0));
|
||||
driver->endScene();
|
||||
|
||||
driver->getTexture("../media/tools.png");
|
||||
|
||||
driver->beginScene(true, true, SColor(255,100,101,140));
|
||||
driver->draw2DImage(tex1, position2di(0,0));
|
||||
driver->endScene();
|
||||
|
||||
bool result = takeScreenshotAndCompareAgainstReference(driver, "-textureRenderStates.png", 100);
|
||||
|
||||
device->drop();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool textureRenderStates(void)
|
||||
{
|
||||
bool passed = true;
|
||||
|
||||
passed &= runTestWithDriver(EDT_SOFTWARE);
|
||||
passed &= runTestWithDriver(EDT_BURNINGSVIDEO);
|
||||
passed &= runTestWithDriver(EDT_DIRECT3D9);
|
||||
passed &= runTestWithDriver(EDT_DIRECT3D8);
|
||||
passed &= runTestWithDriver(EDT_OPENGL);
|
||||
|
||||
return passed;
|
||||
}
|
||||
|
|
@ -860,13 +860,11 @@ void CGUIEditWorkspace::PasteXMLToSelectedElement()
|
|||
// rewind file
|
||||
memWrite->seek(0, false);
|
||||
|
||||
io::IXMLReader* xmlReader = (io::IXMLReader*) Environment->getFileSystem()->createXMLReader(memWrite);
|
||||
|
||||
// read xml
|
||||
Environment->readGUIElement(xmlReader, SelectedElement);
|
||||
Environment->loadGUI(memWrite, SelectedElement);
|
||||
|
||||
// drop the xml reader
|
||||
xmlReader->drop();
|
||||
// reset focus
|
||||
Environment->setFocus(this);
|
||||
|
||||
// drop the read file
|
||||
memWrite->drop();
|
||||
|
|
Loading…
Reference in New Issue