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,85 +14,8 @@ 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 MD2_FRAME_SHIFT = 2;
const f32 MD2_FRAME_SHIFT_RECIPROCAL = 1.f / ( 1 << MD2_FRAME_SHIFT );
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
{
return InterpolationBuffer;
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

@ -11,6 +11,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,11 +48,13 @@ 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();
setAutomaticCulling( scene::EAC_OFF );
setAutomaticCulling(scene::EAC_OFF);
}
@ -73,7 +75,7 @@ namespace scene
bool CTerrainSceneNode::loadHeightMap(io::IReadFile* file, video::SColor vertexColor,
s32 smoothFactor)
{
if( !file )
if (!file)
return false;
Mesh.MeshBuffers.clear();
@ -91,34 +93,34 @@ namespace scene
// Get the dimension of the heightmap data
TerrainData.Size = heightMap->getDimension().Width;
switch( TerrainData.PatchSize )
switch (TerrainData.PatchSize)
{
case ETPS_9:
if( TerrainData.MaxLOD > 3 )
if (TerrainData.MaxLOD > 3)
{
TerrainData.MaxLOD = 3;
}
break;
case ETPS_17:
if( TerrainData.MaxLOD > 4 )
if (TerrainData.MaxLOD > 4)
{
TerrainData.MaxLOD = 4;
}
break;
case ETPS_33:
if( TerrainData.MaxLOD > 5 )
if (TerrainData.MaxLOD > 5)
{
TerrainData.MaxLOD = 5;
}
break;
case ETPS_65:
if( TerrainData.MaxLOD > 6 )
if (TerrainData.MaxLOD > 6)
{
TerrainData.MaxLOD = 6;
}
break;
case ETPS_129:
if( TerrainData.MaxLOD > 7 )
if (TerrainData.MaxLOD > 7)
{
TerrainData.MaxLOD = 7;
}
@ -153,17 +155,17 @@ namespace scene
s32 index = 0;
float fx=0.f;
float fx2=0.f;
for( s32 x = 0; x < TerrainData.Size; ++x )
for (s32 x = 0; x < TerrainData.Size; ++x)
{
float fz=0.f;
float fz2=0.f;
for( s32 z = 0; z < TerrainData.Size; ++z )
for (s32 z = 0; z < TerrainData.Size; ++z)
{
video::S3DVertex2TCoords& vertex= static_cast<video::S3DVertex2TCoords*>(mb->getVertexBuffer().pointer())[index++];
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;
@ -190,7 +192,7 @@ namespace scene
// We copy the data to the renderBuffer, after the normals have been calculated.
RenderBuffer->getVertexBuffer().set_used(numVertices);
for( u32 i = 0; i < numVertices; ++i )
for (u32 i = 0; i < numVertices; ++i)
{
RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i];
RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale;
@ -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;
@ -250,7 +254,7 @@ namespace scene
// Get the dimension of the heightmap data
const s32 filesize = file->getSize();
if (!width)
TerrainData.Size = core::floor32(sqrtf( (f32)( filesize / bytesPerPixel ) ));
TerrainData.Size = core::floor32(sqrtf((f32)(filesize / bytesPerPixel)));
else
{
if ((filesize-file->getPos())/bytesPerPixel>width*width)
@ -261,34 +265,34 @@ namespace scene
TerrainData.Size = width;
}
switch( TerrainData.PatchSize )
switch (TerrainData.PatchSize)
{
case ETPS_9:
if( TerrainData.MaxLOD > 3 )
if (TerrainData.MaxLOD > 3)
{
TerrainData.MaxLOD = 3;
}
break;
case ETPS_17:
if( TerrainData.MaxLOD > 4 )
if (TerrainData.MaxLOD > 4)
{
TerrainData.MaxLOD = 4;
}
break;
case ETPS_33:
if( TerrainData.MaxLOD > 5 )
if (TerrainData.MaxLOD > 5)
{
TerrainData.MaxLOD = 5;
}
break;
case ETPS_65:
if( TerrainData.MaxLOD > 6 )
if (TerrainData.MaxLOD > 6)
{
TerrainData.MaxLOD = 6;
}
break;
case ETPS_129:
if( TerrainData.MaxLOD > 7 )
if (TerrainData.MaxLOD > 7)
{
TerrainData.MaxLOD = 7;
}
@ -323,17 +327,17 @@ namespace scene
const f32 tdSize = 1.0f/(f32)(TerrainData.Size-1);
float fx=0.f;
float fx2=0.f;
for( s32 x = 0; x < TerrainData.Size; ++x )
for (s32 x = 0; x < TerrainData.Size; ++x)
{
float fz=0.f;
float fz2=0.f;
for( s32 z = 0; z < TerrainData.Size; ++z )
for (s32 z = 0; z < TerrainData.Size; ++z)
{
bool failure=false;
vertex.Pos.X = fx;
if (floatVals)
{
if( file->read( &vertex.Pos.Y, bytesPerPixel ) != bytesPerPixel )
if (file->read(&vertex.Pos.Y, bytesPerPixel) != bytesPerPixel)
failure=true;
}
else if (signedData)
@ -343,7 +347,7 @@ namespace scene
case 1:
{
s8 val;
if( file->read( &val, bytesPerPixel ) != bytesPerPixel )
if (file->read(&val, bytesPerPixel) != bytesPerPixel)
failure=true;
vertex.Pos.Y=val;
}
@ -351,7 +355,7 @@ namespace scene
case 2:
{
s16 val;
if( file->read( &val, bytesPerPixel ) != bytesPerPixel )
if (file->read(&val, bytesPerPixel) != bytesPerPixel)
failure=true;
vertex.Pos.Y=val/256.f;
}
@ -359,7 +363,7 @@ namespace scene
case 4:
{
s32 val;
if( file->read( &val, bytesPerPixel ) != bytesPerPixel )
if (file->read(&val, bytesPerPixel) != bytesPerPixel)
failure=true;
vertex.Pos.Y=val/16777216.f;
}
@ -373,7 +377,7 @@ namespace scene
case 1:
{
u8 val;
if( file->read( &val, bytesPerPixel ) != bytesPerPixel )
if (file->read(&val, bytesPerPixel) != bytesPerPixel)
failure=true;
vertex.Pos.Y=val;
}
@ -381,7 +385,7 @@ namespace scene
case 2:
{
u16 val;
if( file->read( &val, bytesPerPixel ) != bytesPerPixel )
if (file->read(&val, bytesPerPixel) != bytesPerPixel)
failure=true;
vertex.Pos.Y=val/256.f;
}
@ -389,7 +393,7 @@ namespace scene
case 4:
{
u32 val;
if( file->read( &val, bytesPerPixel ) != bytesPerPixel )
if (file->read(&val, bytesPerPixel) != bytesPerPixel)
failure=true;
vertex.Pos.Y=val/16777216.f;
}
@ -407,7 +411,7 @@ namespace scene
vertex.TCoords.X = vertex.TCoords2.X = 1.f-fx2;
vertex.TCoords.Y = vertex.TCoords2.Y = fz2;
mb->getVertexBuffer().push_back( vertex );
mb->getVertexBuffer().push_back(vertex);
++fz;
fz2 += tdSize;
}
@ -418,16 +422,16 @@ namespace scene
smoothTerrain(mb, smoothFactor);
// calculate smooth normals for the vertices
calculateNormals( mb );
calculateNormals(mb);
// add the MeshBuffer to the mesh
Mesh.addMeshBuffer( mb );
Mesh.addMeshBuffer(mb);
const u32 vertexCount = mb->getVertexCount();
// We copy the data to the renderBuffer, after the normals have been calculated.
RenderBuffer->getVertexBuffer().set_used( vertexCount );
RenderBuffer->getVertexBuffer().set_used(vertexCount);
for( u32 i = 0; i < vertexCount; i++ )
for (u32 i = 0; i < vertexCount; i++)
{
RenderBuffer->getVertexBuffer()[i] = mb->getVertexBuffer()[i];
RenderBuffer->getVertexBuffer()[i].Pos *= TerrainData.Scale;
@ -448,11 +452,12 @@ namespace scene
// Rotate the vertices of the terrain by the rotation specified. Must be done
// after calculating the terrain data, so we know what the current center of the
// terrain is.
setRotation( TerrainData.Rotation );
setRotation(TerrainData.Rotation);
// Pre-allocate memory for indices
RenderBuffer->getIndexBuffer().set_used( TerrainData.PatchCount * TerrainData.PatchCount *
TerrainData.CalcPatchSize * TerrainData.CalcPatchSize * 6 );
RenderBuffer->getIndexBuffer().set_used(
TerrainData.PatchCount*TerrainData.PatchCount*
TerrainData.CalcPatchSize*TerrainData.CalcPatchSize*6);
const u32 endTime = os::Timer::getTime();
@ -489,7 +494,7 @@ namespace scene
//! Sets the pivot point for rotation of this node. This is useful for the TiledTerrainManager to
//! rotate all terrain tiles around a global world point.
//! NOTE: The default for the RotationPivot will be the center of the individual tile.
void CTerrainSceneNode::setRotationPivot( const core::vector3df& pivot )
void CTerrainSceneNode::setRotationPivot(const core::vector3df& pivot)
{
UseDefaultRotationPivot = false;
TerrainData.RotationPivot = pivot;
@ -506,28 +511,28 @@ namespace scene
}
//! Apply transformation changes( scale, position, rotation )
//! Apply transformation changes(scale, position, rotation)
void CTerrainSceneNode::applyTransformation()
{
if( !Mesh.getMeshBufferCount() )
if (!Mesh.getMeshBufferCount())
return;
TerrainData.Position = TerrainData.Position;
video::S3DVertex2TCoords* meshVertices = (video::S3DVertex2TCoords*)Mesh.getMeshBuffer(0)->getVertices();
s32 vtxCount = Mesh.getMeshBuffer( 0 )->getVertexCount();
s32 vtxCount = Mesh.getMeshBuffer(0)->getVertexCount();
core::matrix4 rotMatrix;
rotMatrix.setRotationDegrees( TerrainData.Rotation );
rotMatrix.setRotationDegrees(TerrainData.Rotation);
for( s32 i = 0; i < vtxCount; ++i )
for (s32 i = 0; i < vtxCount; ++i)
{
RenderBuffer->getVertexBuffer()[i].Pos = meshVertices[i].Pos * TerrainData.Scale + TerrainData.Position;
RenderBuffer->getVertexBuffer()[i].Pos -= TerrainData.RotationPivot;
rotMatrix.inverseRotateVect( RenderBuffer->getVertexBuffer()[i].Pos );
rotMatrix.inverseRotateVect(RenderBuffer->getVertexBuffer()[i].Pos);
RenderBuffer->getVertexBuffer()[i].Pos += TerrainData.RotationPivot;
}
calculateDistanceThresholds( true );
calculateDistanceThresholds(true);
calculatePatchData();
RenderBuffer->setDirty(EBT_VERTEX);
@ -596,22 +601,22 @@ namespace scene
// Determine each patches LOD based on distance from camera (and whether or not they are in
// the view frustum).
const s32 count = TerrainData.PatchCount * TerrainData.PatchCount;
for( s32 j = 0; j < count; ++j )
for (s32 j = 0; j < count; ++j)
{
if( frustum->getBoundingBox().intersectsWithBox( TerrainData.Patches[j].BoundingBox ) )
if (frustum->getBoundingBox().intersectsWithBox(TerrainData.Patches[j].BoundingBox))
{
const f32 distance = (cameraPosition.X - TerrainData.Patches[j].Center.X) * (cameraPosition.X - TerrainData.Patches[j].Center.X) +
(cameraPosition.Y - TerrainData.Patches[j].Center.Y) * (cameraPosition.Y - TerrainData.Patches[j].Center.Y) +
(cameraPosition.Z - TerrainData.Patches[j].Center.Z) * (cameraPosition.Z - TerrainData.Patches[j].Center.Z);
for( s32 i = TerrainData.MaxLOD - 1; i >= 0; --i )
for (s32 i = TerrainData.MaxLOD - 1; i >= 0; --i)
{
if( distance >= TerrainData.LODDistanceThreshold[i] )
if (distance >= TerrainData.LODDistanceThreshold[i])
{
TerrainData.Patches[j].CurrentLOD = i;
break;
}
//else if( i == 0 )
//else if (i == 0)
{
// If we've turned off a patch from viewing, because of the frustum, and now we turn around and it's
// too close, we need to turn it back on, at the highest LOD. The if above doesn't catch this.
@ -647,12 +652,12 @@ namespace scene
IndicesToRender = 0;
// Then generate the indices for all patches that are visible.
for( s32 i = 0; i < TerrainData.PatchCount; ++i )
for (s32 i = 0; i < TerrainData.PatchCount; ++i)
{
for( s32 j = 0; j < TerrainData.PatchCount; ++j )
for (s32 j = 0; j < TerrainData.PatchCount; ++j)
{
const s32 index = i * TerrainData.PatchCount + j;
if( TerrainData.Patches[index].CurrentLOD >= 0 )
if (TerrainData.Patches[index].CurrentLOD >= 0)
{
s32 x = 0;
s32 z = 0;
@ -661,12 +666,12 @@ namespace scene
const s32 step = 1 << TerrainData.Patches[index].CurrentLOD;
// Loop through patch and generate indices
while( z < TerrainData.CalcPatchSize )
while (z < TerrainData.CalcPatchSize)
{
const s32 index11 = getIndex( j, i, index, x, z );
const s32 index21 = getIndex( j, i, index, x + step, z );
const s32 index12 = getIndex( j, i, index, x, z + step );
const s32 index22 = getIndex( j, i, index, x + step, z + step );
const s32 index11 = getIndex(j, i, index, x, z);
const s32 index21 = getIndex(j, i, index, x + step, z);
const s32 index12 = getIndex(j, i, index, x, z + step);
const s32 index22 = getIndex(j, i, index, x + step, z + step);
IndexBuffer[IndicesToRender++]= static_cast<INDEX_TYPE>(index12);
IndexBuffer[IndicesToRender++]= static_cast<INDEX_TYPE>(index11);
@ -691,7 +696,7 @@ namespace scene
RenderBuffer->setDirty(EBT_INDEX);
if ( DynamicSelectorUpdate && TriangleSelector )
if (DynamicSelectorUpdate && TriangleSelector)
{
CTerrainTriangleSelector* selector = (CTerrainTriangleSelector*)TriangleSelector;
selector->setTriangleData(this, -1);
@ -718,7 +723,7 @@ namespace scene
// For use with geomorphing
driver->drawMeshBuffer(RenderBuffer);
RenderBuffer->getIndexBuffer().set_used( RenderBuffer->getIndexBuffer().allocated_size() );
RenderBuffer->getIndexBuffer().set_used(RenderBuffer->getIndexBuffer().allocated_size());
// for debug purposes only:
if (DebugDataVisible)
@ -727,15 +732,15 @@ namespace scene
m.Lighting = false;
driver->setMaterial(m);
if (DebugDataVisible & scene::EDS_BBOX)
driver->draw3DBox( TerrainData.BoundingBox, video::SColor(255,255,255,255));
driver->draw3DBox(TerrainData.BoundingBox, video::SColor(255,255,255,255));
const s32 count = TerrainData.PatchCount * TerrainData.PatchCount;
s32 visible = 0;
if (DebugDataVisible & scene::EDS_BBOX_BUFFERS)
{
for( s32 j = 0; j < count; ++j )
for (s32 j = 0; j < count; ++j)
{
driver->draw3DBox( TerrainData.Patches[j].BoundingBox, video::SColor(255,255,0,0));
driver->draw3DBox(TerrainData.Patches[j].BoundingBox, video::SColor(255,255,0,0));
visible += (TerrainData.Patches[j].CurrentLOD >= 0);
}
}
@ -746,9 +751,9 @@ namespace scene
"__debugnormal", 0xFFECEC00,
0xFF999900, 4, 8, 1.f, 0.6f, 0.05f,
0.3f);
if ( 0 == arrow )
if (0 == arrow)
{
arrow = SceneManager->getMesh( "__debugnormal" );
arrow = SceneManager->getMesh("__debugnormal");
}
IMesh *mesh = arrow->getMesh(0);
@ -758,7 +763,7 @@ namespace scene
// draw normals
driver->setTransform(video::ETS_WORLD, core::IdentityMatrix);
for ( u32 i=0; i != RenderBuffer->getVertexCount(); ++i )
for (u32 i=0; i != RenderBuffer->getVertexCount(); ++i)
{
const core::vector3df& v = RenderBuffer->getNormal(i);
// align to v->Normal
@ -777,7 +782,7 @@ namespace scene
m2=AbsoluteTransformation*m2;
driver->setTransform(video::ETS_WORLD, m2 );
for ( u32 a = 0; a != mesh->getMeshBufferCount(); ++a )
for (u32 a = 0; a != mesh->getMeshBufferCount(); ++a)
driver->drawMeshBuffer(mesh->getMeshBuffer(a));
}
driver->setTransform(video::ETS_WORLD, AbsoluteTransformation);
@ -806,7 +811,7 @@ namespace scene
//! Return the bounding box of a patch
const core::aabbox3d<f32>& CTerrainSceneNode::getBoundingBox( s32 patchX, s32 patchZ ) const
const core::aabbox3d<f32>& CTerrainSceneNode::getBoundingBox(s32 patchX, s32 patchZ) const
{
return TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].BoundingBox;
}
@ -829,7 +834,7 @@ namespace scene
for (u32 n=0; n<numVertices; ++n)
mb.getVertexBuffer().push_back(vertices[n]);
mb.getIndexBuffer().setType( RenderBuffer->getIndexBuffer().getType() );
mb.getIndexBuffer().setType(RenderBuffer->getIndexBuffer().getType());
// calculate the step we take for all patches, since LOD is the same
const s32 step = 1 << LOD;
@ -846,17 +851,17 @@ namespace scene
// Loop through patch and generate indices
while (z < TerrainData.CalcPatchSize)
{
const s32 index11 = getIndex( j, i, index, x, z );
const s32 index21 = getIndex( j, i, index, x + step, z );
const s32 index12 = getIndex( j, i, index, x, z + step );
const s32 index22 = getIndex( j, i, index, x + step, z + step );
const s32 index11 = getIndex(j, i, index, x, z);
const s32 index21 = getIndex(j, i, index, x + step, z);
const s32 index12 = getIndex(j, i, index, x, z + step);
const s32 index22 = getIndex(j, i, index, x + step, z + step);
mb.getIndexBuffer().push_back( index12 );
mb.getIndexBuffer().push_back( index11 );
mb.getIndexBuffer().push_back( index22 );
mb.getIndexBuffer().push_back( index22 );
mb.getIndexBuffer().push_back( index11 );
mb.getIndexBuffer().push_back( index21 );
mb.getIndexBuffer().push_back(index12);
mb.getIndexBuffer().push_back(index11);
mb.getIndexBuffer().push_back(index22);
mb.getIndexBuffer().push_back(index22);
mb.getIndexBuffer().push_back(index11);
mb.getIndexBuffer().push_back(index21);
// increment index position horizontally
x += step;
@ -883,17 +888,18 @@ 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 )
if (LOD < -1 || LOD > TerrainData.MaxLOD - 1)
return -1;
core::array<s32> cLODs;
bool setLODs = false;
// If LOD of -1 was passed in, use the CurrentLOD of the patch specified
if ( LOD == -1 )
if (LOD == -1)
{
LOD = TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].CurrentLOD;
}
@ -904,7 +910,7 @@ namespace scene
setLODs = true;
}
if ( LOD < 0 )
if (LOD < 0)
return -2; // Patch not visible, don't generate indices.
// calculate the step we take for this LOD
@ -922,10 +928,10 @@ namespace scene
s32 rv=0;
while (z<TerrainData.CalcPatchSize)
{
const s32 index11 = getIndex( patchZ, patchX, index, x, z );
const s32 index21 = getIndex( patchZ, patchX, index, x + step, z );
const s32 index12 = getIndex( patchZ, patchX, index, x, z + step );
const s32 index22 = getIndex( patchZ, patchX, index, x + step, z + step );
const s32 index11 = getIndex(patchZ, patchX, index, x, z);
const s32 index21 = getIndex(patchZ, patchX, index, x + step, z);
const s32 index12 = getIndex(patchZ, patchX, index, x, z + step);
const s32 index22 = getIndex(patchZ, patchX, index, x + step, z + step);
indices[rv++] = index12;
indices[rv++] = index11;
@ -971,7 +977,7 @@ namespace scene
//! \param patchX: Patch x coordinate.
//! \param patchZ: Patch z coordinate.
//! \param LOD: The level of detail to set the patch to.
void CTerrainSceneNode::setLODOfPatch( s32 patchX, s32 patchZ, s32 LOD )
void CTerrainSceneNode::setLODOfPatch(s32 patchX, s32 patchZ, s32 LOD)
{
TerrainData.Patches[patchX * TerrainData.PatchCount + patchZ].CurrentLOD = LOD;
}
@ -983,7 +989,7 @@ namespace scene
{
OverrideDistanceThreshold = true;
if ( LOD < 0 || LOD > TerrainData.MaxLOD - 1 )
if (LOD < 0 || LOD > TerrainData.MaxLOD - 1)
return false;
TerrainData.LODDistanceThreshold[LOD] = newDistance * newDistance;
@ -1016,7 +1022,7 @@ namespace scene
if (RenderBuffer->getVertexType()==video::EVT_2TCOORDS)
{
if ( resolution2 == 0 )
if (resolution2 == 0)
{
((video::S3DVertex2TCoords&)RenderBuffer->getVertexBuffer()[index]).TCoords2 = RenderBuffer->getVertexBuffer()[index].TCoords;
}
@ -1048,47 +1054,47 @@ namespace scene
{
if (TerrainData.Patches[PatchIndex].Top &&
TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Top->CurrentLOD &&
(vX % ( 1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD)) != 0 )
(vX % (1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD)) != 0 )
{
vX -= vX % ( 1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD );
vX -= vX % (1 << TerrainData.Patches[PatchIndex].Top->CurrentLOD);
}
}
else
if ( vZ == (u32)TerrainData.CalcPatchSize ) // bottom border
if (vZ == (u32)TerrainData.CalcPatchSize) // bottom border
{
if (TerrainData.Patches[PatchIndex].Bottom &&
TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Bottom->CurrentLOD &&
(vX % ( 1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD)) != 0)
(vX % (1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD)) != 0)
{
vX -= vX % ( 1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD );
vX -= vX % (1 << TerrainData.Patches[PatchIndex].Bottom->CurrentLOD);
}
}
// left border
if ( vX == 0 )
if (vX == 0)
{
if (TerrainData.Patches[PatchIndex].Left &&
TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Left->CurrentLOD &&
( vZ % ( 1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD ) ) != 0)
(vZ % (1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD)) != 0)
{
vZ -= vZ % ( 1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD );
vZ -= vZ % (1 << TerrainData.Patches[PatchIndex].Left->CurrentLOD);
}
}
else
if ( vX == (u32)TerrainData.CalcPatchSize ) // right border
if (vX == (u32)TerrainData.CalcPatchSize) // right border
{
if (TerrainData.Patches[PatchIndex].Right &&
TerrainData.Patches[PatchIndex].CurrentLOD < TerrainData.Patches[PatchIndex].Right->CurrentLOD &&
( vZ % ( 1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD ) ) != 0)
(vZ % (1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD)) != 0)
{
vZ -= vZ % ( 1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD );
vZ -= vZ % (1 << TerrainData.Patches[PatchIndex].Right->CurrentLOD);
}
}
if ( vZ >= (u32)TerrainData.PatchSize )
if (vZ >= (u32)TerrainData.PatchSize)
vZ = TerrainData.CalcPatchSize;
if ( vX >= (u32)TerrainData.PatchSize )
if (vX >= (u32)TerrainData.PatchSize)
vX = TerrainData.CalcPatchSize;
return (vZ + ((TerrainData.CalcPatchSize) * PatchZ)) * TerrainData.Size +
@ -1119,7 +1125,7 @@ namespace scene
//! calculate smooth normals
void CTerrainSceneNode::calculateNormals( CDynamicMeshBuffer* mb )
void CTerrainSceneNode::calculateNormals(CDynamicMeshBuffer* mb)
{
s32 count;
core::vector3df a, b, c, t;
@ -1233,7 +1239,7 @@ namespace scene
}
else
{
normal.set( 0.0f, 1.0f, 0.0f );
normal.set(0.0f, 1.0f, 0.0f);
}
mb->getVertexBuffer()[x * TerrainData.Size + z].Normal = normal;
@ -1245,7 +1251,7 @@ namespace scene
//! create patches, stuff that needs to be done only once for patches goes here.
void CTerrainSceneNode::createPatches()
{
TerrainData.PatchCount = (TerrainData.Size - 1) / ( TerrainData.CalcPatchSize );
TerrainData.PatchCount = (TerrainData.Size - 1) / (TerrainData.CalcPatchSize);
if (TerrainData.Patches)
delete [] TerrainData.Patches;
@ -1260,9 +1266,9 @@ namespace scene
// Reset the Terrains Bounding Box for re-calculation
TerrainData.BoundingBox = core::aabbox3df(999999.9f, 999999.9f, 999999.9f, -999999.9f, -999999.9f, -999999.9f);
for( s32 x = 0; x < TerrainData.PatchCount; ++x )
for (s32 x = 0; x < TerrainData.PatchCount; ++x)
{
for( s32 z = 0; z < TerrainData.PatchCount; ++z )
for (s32 z = 0; z < TerrainData.PatchCount; ++z)
{
const s32 index = x * TerrainData.PatchCount + z;
TerrainData.Patches[index].CurrentLOD = 0;
@ -1271,38 +1277,38 @@ namespace scene
TerrainData.Patches[index].BoundingBox = core::aabbox3df(999999.9f, 999999.9f, 999999.9f,
-999999.9f, -999999.9f, -999999.9f);
for( s32 xx = x*(TerrainData.CalcPatchSize); xx <= ( x + 1 ) * TerrainData.CalcPatchSize; ++xx )
for( s32 zz = z*(TerrainData.CalcPatchSize); zz <= ( z + 1 ) * TerrainData.CalcPatchSize; ++zz )
TerrainData.Patches[index].BoundingBox.addInternalPoint( RenderBuffer->getVertexBuffer()[xx * TerrainData.Size + zz].Pos );
for (s32 xx = x*(TerrainData.CalcPatchSize); xx <= (x + 1) * TerrainData.CalcPatchSize; ++xx)
for (s32 zz = z*(TerrainData.CalcPatchSize); zz <= (z + 1) * TerrainData.CalcPatchSize; ++zz)
TerrainData.Patches[index].BoundingBox.addInternalPoint(RenderBuffer->getVertexBuffer()[xx * TerrainData.Size + zz].Pos);
// Reconfigure the bounding box of the terrain as a whole
TerrainData.BoundingBox.addInternalBox( TerrainData.Patches[index].BoundingBox );
TerrainData.BoundingBox.addInternalBox(TerrainData.Patches[index].BoundingBox);
// get center of Patch
TerrainData.Patches[index].Center = TerrainData.Patches[index].BoundingBox.getCenter();
// Assign Neighbours
// Top
if( x > 0 )
if (x > 0)
TerrainData.Patches[index].Top = &TerrainData.Patches[(x-1) * TerrainData.PatchCount + z];
else
TerrainData.Patches[index].Top = 0;
// Bottom
if( x < TerrainData.PatchCount - 1 )
if (x < TerrainData.PatchCount - 1)
TerrainData.Patches[index].Bottom = &TerrainData.Patches[(x+1) * TerrainData.PatchCount + z];
else
TerrainData.Patches[index].Bottom = 0;
// Left
if( z > 0 )
if (z > 0)
TerrainData.Patches[index].Left = &TerrainData.Patches[x * TerrainData.PatchCount + z - 1];
else
TerrainData.Patches[index].Left = 0;
// Right
if( z < TerrainData.PatchCount - 1 )
if (z < TerrainData.PatchCount - 1)
TerrainData.Patches[index].Right = &TerrainData.Patches[x * TerrainData.PatchCount + z + 1];
else
TerrainData.Patches[index].Right = 0;
@ -1313,7 +1319,7 @@ namespace scene
TerrainData.Center = TerrainData.BoundingBox.getCenter();
// if the default rotation pivot is still being used, update it.
if( UseDefaultRotationPivot )
if (UseDefaultRotationPivot)
{
TerrainData.RotationPivot = TerrainData.Center;
}
@ -1365,28 +1371,29 @@ namespace scene
f32 height = -999999.9f;
core::matrix4 rotMatrix;
rotMatrix.setRotationDegrees( TerrainData.Rotation );
core::vector3df pos( x, 0.0f, z );
rotMatrix.rotateVect( pos );
rotMatrix.setRotationDegrees(TerrainData.Rotation);
core::vector3df pos(x, 0.0f, z);
rotMatrix.rotateVect(pos);
pos -= TerrainData.Position;
pos /= TerrainData.Scale;
s32 X(core::floor32( pos.X ));
s32 Z(core::floor32( pos.Z ));
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;
const core::vector3df& b = Vertices[(X + 1) * TerrainData.Size + Z].Pos;
const core::vector3df& c = Vertices[X * TerrainData.Size + ( Z + 1 )].Pos;
const core::vector3df& d = Vertices[(X + 1) * TerrainData.Size + ( Z + 1 )].Pos;
const core::vector3df& c = Vertices[X * TerrainData.Size + (Z + 1)].Pos;
const core::vector3df& d = Vertices[(X + 1) * TerrainData.Size + (Z + 1)].Pos;
// offset from integer position
const f32 dx = pos.X - X;
const f32 dz = pos.Z - Z;
if( dx > dz )
if (dx > dz)
height = a.Y + (d.Y - b.Y)*dz + (b.Y - a.Y)*dx;
else
height = a.Y + (d.Y - c.Y)*dx + (c.Y - a.Y)*dz;

View File

@ -1,140 +1,146 @@
// This is the entry point for the Irrlicht test suite.
#define _CRT_SECURE_NO_WARNINGS
#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;
//! This is the main entry point for the Irrlicht test suite.
/** \return The number of test that failed, i.e. 0 is success. */
int main(int argumentCount, char * arguments[])
{
bool logFileOpened = openTestLog(1 == argumentCount);
assert(logFileOpened);
if(argumentCount > 3)
{
logTestString("\nUsage: %s [testNumber] [totalFails]\n");
closeTestLog();
return 9999;
}
#define TEST(x)\
{\
extern bool x(void);\
STestDefinition newTest;\
newTest.testSignature = x;\
newTest.testName = #x;\
tests.push_back(newTest);\
}
std::vector<STestDefinition> tests;
// 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();
unsigned int testToRun = 0;
unsigned int fails = 0;
if(argumentCount > 1)
{
testToRun = (unsigned int)atoi(arguments[1]);
if(testToRun >= numberOfTests)
{
logTestString("\nError: invalid test %d (maximum %d)\n",
testToRun, numberOfTests - 1);
closeTestLog();
return 9999;
}
}
if(argumentCount > 2)
fails = (unsigned int)atoi(arguments[2]);
logTestString("\nStarting test %d, '%s'\n",
testToRun, tests[testToRun].testName);
bool success = tests[testToRun].testSignature();
if(!success)
{
logTestString("\n\n\n******** Test failure ********\nTest %d '%s' failed\n"\
"******** Test failure ********\n",
testToRun, tests[testToRun].testName);
fails++;
}
testToRun++;
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);
if(0 == fails)
{
time_t rawtime;
struct tm * timeinfo;
(void)time(&rawtime);
timeinfo = gmtime(&rawtime);
(void)printf("\nTest suite pass at GMT %s\n", asctime(timeinfo));
FILE * testsLastPassedAtFile = fopen("tests-last-passed-at.txt", "w");
if(testsLastPassedAtFile)
{
(void)fprintf(testsLastPassedAtFile, "Test suite pass at GMT %s\n", asctime(timeinfo));
(void)fclose(testsLastPassedAtFile);
}
}
closeTestLog();
}
return fails;
}
// 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>
/* 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. */
int main(int argumentCount, char * arguments[])
{
bool logFileOpened = openTestLog(1 == argumentCount);
assert(logFileOpened);
if(argumentCount > 3)
{
logTestString("\nUsage: %s [testNumber] [totalFails]\n");
closeTestLog();
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);
typedef struct _STest
{
bool(*testSignature)(void);
const char * testName;
} STest;
#define TEST(x) { x, #x }
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;
if(argumentCount > 1)
{
testToRun = (unsigned int)atoi(arguments[1]);
if(testToRun >= numberOfTests)
{
logTestString("\nError: invalid test %d (maximum %d)\n",
testToRun, numberOfTests - 1);
closeTestLog();
return 9999;
}
}
if(argumentCount > 2)
fails = (unsigned int)atoi(arguments[2]);
logTestString("\nStarting test %d, '%s'\n",
testToRun, tests[testToRun].testName);
bool success = tests[testToRun].testSignature();
if(!success)
{
logTestString("\n\n\n******** Test failure ********\nTest %d '%s' failed\n"\
"******** Test failure ********\n",
testToRun, tests[testToRun].testName);
fails++;
}
testToRun++;
if(testToRun == numberOfTests)
{
logTestString("\nTests finished. %d test%s failed.\n", fails, 1 == fails ? "" : "s");
if(0 == fails)
{
time_t rawtime;
struct tm * timeinfo;
(void)time(&rawtime);
timeinfo = gmtime(&rawtime);
(void)printf("\nTest suite pass at GMT %s\n", asctime(timeinfo));
FILE * testsLastPassedAtFile = fopen("tests-last-passed-at.txt", "w");
if(testsLastPassedAtFile)
{
(void)fprintf(testsLastPassedAtFile, "Test suite pass at GMT %s\n", asctime(timeinfo));
(void)fclose(testsLastPassedAtFile);
}
}
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();