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-e03cc46cb475
master
hybrid 2008-12-30 11:13:22 +00:00
parent 0ef1056eb8
commit 7809c48144
15 changed files with 754 additions and 625 deletions

View File

@ -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)

View File

@ -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();
}

View File

@ -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

View File

@ -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

View File

@ -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

View File

@ -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);

View File

@ -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;

View File

@ -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

View File

@ -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"
>

View File

@ -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;
}

View File

@ -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();