Merged revisions 1972:2004 from 1.5 branch, except for some revisions which seemed to be merged already. MD2 loader updated, terrain node fixed, opengl texture handling fixed.
git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@2005 dfc29bdd-3216-0410-991c-e03cc46cb475master
parent
0ef1056eb8
commit
7809c48144
|
@ -8,6 +8,11 @@ Changes in version 1.6
|
|||
|
||||
- Add a hitPosition out parameter to ISceneCollisionManager::getCollisionResultPosition() - this is a (small) API breaking change.
|
||||
|
||||
-------------------------------------
|
||||
Changes in version 1.5.1 (??.?? 2009)
|
||||
|
||||
- MD2 mesh loader: Now uses much less memory, reduced number of allocations when loading meshes.
|
||||
|
||||
-----------------------------------
|
||||
Changes in version 1.5 (15.12.2008)
|
||||
|
||||
|
|
|
@ -6,9 +6,7 @@
|
|||
#ifdef _IRR_COMPILE_WITH_MD2_LOADER_
|
||||
|
||||
#include "CAnimatedMeshMD2.h"
|
||||
#include "os.h"
|
||||
#include "SColor.h"
|
||||
#include "IReadFile.h"
|
||||
#include "irrMath.h"
|
||||
|
||||
namespace irr
|
||||
|
@ -16,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();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
@ -28,9 +28,6 @@ namespace scene
|
|||
//! destructor
|
||||
virtual ~CAnimatedMeshMD2();
|
||||
|
||||
//! loads an md2 file
|
||||
virtual bool loadFile(io::IReadFile* file);
|
||||
|
||||
//! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
|
||||
virtual u32 getFrameCount() const;
|
||||
|
||||
|
@ -82,19 +79,16 @@ namespace scene
|
|||
//! \param nr: Zero based index of animation.
|
||||
virtual const c8* getAnimationName(s32 nr) const;
|
||||
|
||||
private:
|
||||
|
||||
//! updates the interpolation buffer
|
||||
void updateInterpolationBuffer(s32 frame, s32 startFrame, s32 endFrame);
|
||||
|
||||
//! calculates the bounding box
|
||||
virtual void calculateBoundingBox();
|
||||
//
|
||||
// exposed for loader
|
||||
//
|
||||
|
||||
//! the buffer that contains the most recent animation
|
||||
SMeshBuffer* InterpolationBuffer;
|
||||
core::array<video::S3DVertex> *FrameList;
|
||||
core::array<core::aabbox3d<f32> > BoxList;
|
||||
|
||||
struct SFrameData
|
||||
//! named animations
|
||||
struct SAnimationData
|
||||
{
|
||||
core::stringc name;
|
||||
s32 begin;
|
||||
|
@ -102,10 +96,44 @@ namespace scene
|
|||
s32 fps;
|
||||
};
|
||||
|
||||
core::array< SFrameData > FrameData;
|
||||
//! scale and translations for keyframes
|
||||
struct SKeyFrameTransform
|
||||
{
|
||||
core::vector3df scale;
|
||||
core::vector3df translate;
|
||||
};
|
||||
|
||||
//! md2 vertex data
|
||||
struct SMD2Vert
|
||||
{
|
||||
core::vector3d<u8> Pos;
|
||||
u8 NormalIdx;
|
||||
};
|
||||
|
||||
//! keyframe transformations
|
||||
core::array<SKeyFrameTransform> FrameTransforms;
|
||||
|
||||
//! keyframe vertex data
|
||||
core::array<SMD2Vert> *FrameList;
|
||||
|
||||
//! bounding boxes for each keyframe
|
||||
core::array<core::aabbox3d<f32> > BoxList;
|
||||
|
||||
//! named animations
|
||||
core::array< SAnimationData > AnimationData;
|
||||
|
||||
//! calculates the bounding box
|
||||
virtual void calculateBoundingBox();
|
||||
|
||||
u32 FrameCount;
|
||||
s32 TriangleCount;
|
||||
|
||||
private:
|
||||
|
||||
//! updates the interpolation buffer
|
||||
void updateInterpolationBuffer(s32 frame, s32 startFrame, s32 endFrame);
|
||||
|
||||
|
||||
};
|
||||
|
||||
} // end namespace scene
|
||||
|
|
|
@ -7,20 +7,96 @@
|
|||
|
||||
#include "CMD2MeshFileLoader.h"
|
||||
#include "CAnimatedMeshMD2.h"
|
||||
#include "os.h"
|
||||
|
||||
namespace irr
|
||||
{
|
||||
namespace scene
|
||||
{
|
||||
|
||||
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
|
||||
# pragma pack( push, packing )
|
||||
# pragma pack( 1 )
|
||||
# define PACK_STRUCT
|
||||
#elif defined( __GNUC__ )
|
||||
# define PACK_STRUCT __attribute__((packed))
|
||||
#else
|
||||
# error compiler not supported
|
||||
#endif
|
||||
|
||||
// structs needed to load the md2-format
|
||||
|
||||
const s32 MD2_MAGIC_NUMBER = 844121161;
|
||||
const s32 MD2_VERSION = 8;
|
||||
const s32 MD2_MAX_VERTS = 2048;
|
||||
|
||||
struct SMD2Header
|
||||
{
|
||||
s32 magic; // four character code "IDP2"
|
||||
s32 version; // must be 8
|
||||
s32 skinWidth; // width of the texture
|
||||
s32 skinHeight; // height of the texture
|
||||
s32 frameSize; // size in bytes of an animation frame
|
||||
s32 numSkins; // number of textures
|
||||
s32 numVertices; // total number of vertices
|
||||
s32 numTexcoords; // number of vertices with texture coords
|
||||
s32 numTriangles; // number of triangles
|
||||
s32 numGlCommands; // number of opengl commands (triangle strip or triangle fan)
|
||||
s32 numFrames; // animation keyframe count
|
||||
s32 offsetSkins; // offset in bytes to 64 character skin names
|
||||
s32 offsetTexcoords; // offset in bytes to texture coordinate list
|
||||
s32 offsetTriangles; // offset in bytes to triangle list
|
||||
s32 offsetFrames; // offset in bytes to frame list
|
||||
s32 offsetGlCommands;// offset in bytes to opengl commands
|
||||
s32 offsetEnd; // offset in bytes to end of file
|
||||
} PACK_STRUCT;
|
||||
|
||||
struct SMD2Vertex
|
||||
{
|
||||
u8 vertex[3]; // [0] = X, [1] = Z, [2] = Y
|
||||
u8 lightNormalIndex; // index in the normal table
|
||||
} PACK_STRUCT;
|
||||
|
||||
struct SMD2Frame
|
||||
{
|
||||
f32 scale[3]; // first scale the vertex position
|
||||
f32 translate[3]; // then translate the position
|
||||
c8 name[16]; // the name of the animation that this key belongs to
|
||||
SMD2Vertex vertices[1]; // vertex 1 of SMD2Header.numVertices
|
||||
} PACK_STRUCT;
|
||||
|
||||
struct SMD2Triangle
|
||||
{
|
||||
u16 vertexIndices[3];
|
||||
u16 textureIndices[3];
|
||||
} PACK_STRUCT;
|
||||
|
||||
struct SMD2TextureCoordinate
|
||||
{
|
||||
s16 s;
|
||||
s16 t;
|
||||
} PACK_STRUCT;
|
||||
|
||||
struct SMD2GLCommand
|
||||
{
|
||||
f32 s, t;
|
||||
s32 vertexIndex;
|
||||
} PACK_STRUCT;
|
||||
|
||||
// Default alignment
|
||||
#if defined(_MSC_VER) || defined(__BORLANDC__) || defined (__BCPLUSPLUS__)
|
||||
# pragma pack( pop, packing )
|
||||
#endif
|
||||
|
||||
#undef PACK_STRUCT
|
||||
|
||||
//! Constructor
|
||||
CMD2MeshFileLoader::CMD2MeshFileLoader()
|
||||
{
|
||||
|
||||
#ifdef _DEBUG
|
||||
setDebugName("CMD2MeshFileLoader");
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -41,7 +117,7 @@ IAnimatedMesh* CMD2MeshFileLoader::createMesh(io::IReadFile* file)
|
|||
IAnimatedMesh* msh = new CAnimatedMeshMD2();
|
||||
if (msh)
|
||||
{
|
||||
if (((CAnimatedMeshMD2*)msh)->loadFile(file))
|
||||
if (loadFile(file, (CAnimatedMeshMD2*)msh) )
|
||||
return msh;
|
||||
|
||||
msh->drop();
|
||||
|
@ -50,6 +126,246 @@ IAnimatedMesh* CMD2MeshFileLoader::createMesh(io::IReadFile* file)
|
|||
return 0;
|
||||
}
|
||||
|
||||
//! loads an md2 file
|
||||
bool CMD2MeshFileLoader::loadFile(io::IReadFile* file, CAnimatedMeshMD2* mesh)
|
||||
{
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
SMD2Header header;
|
||||
|
||||
file->read(&header, sizeof(SMD2Header));
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
header.magic = os::Byteswap::byteswap(header.magic);
|
||||
header.version = os::Byteswap::byteswap(header.version);
|
||||
header.skinWidth = os::Byteswap::byteswap(header.skinWidth);
|
||||
header.skinHeight = os::Byteswap::byteswap(header.skinHeight);
|
||||
header.frameSize = os::Byteswap::byteswap(header.frameSize);
|
||||
header.numSkins = os::Byteswap::byteswap(header.numSkins);
|
||||
header.numVertices = os::Byteswap::byteswap(header.numVertices);
|
||||
header.numTexcoords = os::Byteswap::byteswap(header.numTexcoords);
|
||||
header.numTriangles = os::Byteswap::byteswap(header.numTriangles);
|
||||
header.numGlCommands = os::Byteswap::byteswap(header.numGlCommands);
|
||||
header.numFrames = os::Byteswap::byteswap(header.numFrames);
|
||||
header.offsetSkins = os::Byteswap::byteswap(header.offsetSkins);
|
||||
header.offsetTexcoords = os::Byteswap::byteswap(header.offsetTexcoords);
|
||||
header.offsetTriangles = os::Byteswap::byteswap(header.offsetTriangles);
|
||||
header.offsetFrames = os::Byteswap::byteswap(header.offsetFrames);
|
||||
header.offsetGlCommands = os::Byteswap::byteswap(header.offsetGlCommands);
|
||||
header.offsetEnd = os::Byteswap::byteswap(header.offsetEnd);
|
||||
#endif
|
||||
|
||||
if (header.magic != MD2_MAGIC_NUMBER || header.version != MD2_VERSION)
|
||||
{
|
||||
os::Printer::log("MD2 Loader: Wrong file header", file->getFileName(), ELL_WARNING);
|
||||
return false;
|
||||
}
|
||||
|
||||
//
|
||||
// prepare mesh and allocate memory
|
||||
//
|
||||
|
||||
mesh->FrameCount = header.numFrames;
|
||||
|
||||
// create keyframes
|
||||
mesh->FrameTransforms.set_used(header.numFrames);
|
||||
|
||||
// create vertex arrays for each keyframe
|
||||
if (mesh->FrameList)
|
||||
delete [] mesh->FrameList;
|
||||
mesh->FrameList = new core::array<CAnimatedMeshMD2::SMD2Vert>[header.numFrames];
|
||||
|
||||
// allocate space in vertex arrays
|
||||
s32 i;
|
||||
for (i=0; i<header.numFrames; ++i)
|
||||
mesh->FrameList[i].reallocate(header.numVertices);
|
||||
|
||||
// allocate interpolation buffer vertices
|
||||
mesh->InterpolationBuffer->Vertices.set_used(header.numTriangles*3);
|
||||
|
||||
// populate triangles
|
||||
mesh->InterpolationBuffer->Indices.reallocate(header.numTriangles*3);
|
||||
const s32 count = header.numTriangles*3;
|
||||
for (i=0; i<count; i+=3)
|
||||
{
|
||||
mesh->InterpolationBuffer->Indices.push_back(i);
|
||||
mesh->InterpolationBuffer->Indices.push_back(i+1);
|
||||
mesh->InterpolationBuffer->Indices.push_back(i+2);
|
||||
}
|
||||
|
||||
//
|
||||
// read texture coordinates
|
||||
//
|
||||
|
||||
file->seek(header.offsetTexcoords);
|
||||
SMD2TextureCoordinate* textureCoords = new SMD2TextureCoordinate[header.numTexcoords];
|
||||
|
||||
if (!file->read(textureCoords, sizeof(SMD2TextureCoordinate)*header.numTexcoords))
|
||||
{
|
||||
os::Printer::log("MD2 Loader: Error reading TextureCoords.", file->getFileName(), ELL_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
for (i=0; i<header.numTexcoords; ++i)
|
||||
{
|
||||
textureCoords[i].s = os::Byteswap::byteswap(textureCoords[i].s);
|
||||
textureCoords[i].t = os::Byteswap::byteswap(textureCoords[i].t);
|
||||
}
|
||||
#endif
|
||||
|
||||
// read Triangles
|
||||
|
||||
file->seek(header.offsetTriangles);
|
||||
|
||||
SMD2Triangle *triangles = new SMD2Triangle[header.numTriangles];
|
||||
if (!file->read(triangles, header.numTriangles *sizeof(SMD2Triangle)))
|
||||
{
|
||||
os::Printer::log("MD2 Loader: Error reading triangles.", file->getFileName(), ELL_ERROR);
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
for (i=0; i<header.numTriangles; ++i)
|
||||
{
|
||||
triangles[i].vertexIndices[0] = os::Byteswap::byteswap(triangles[i].vertexIndices[0]);
|
||||
triangles[i].vertexIndices[1] = os::Byteswap::byteswap(triangles[i].vertexIndices[1]);
|
||||
triangles[i].vertexIndices[2] = os::Byteswap::byteswap(triangles[i].vertexIndices[2]);
|
||||
triangles[i].textureIndices[0] = os::Byteswap::byteswap(triangles[i].textureIndices[0]);
|
||||
triangles[i].textureIndices[1] = os::Byteswap::byteswap(triangles[i].textureIndices[1]);
|
||||
triangles[i].textureIndices[2] = os::Byteswap::byteswap(triangles[i].textureIndices[2]);
|
||||
}
|
||||
#endif
|
||||
|
||||
// read Vertices
|
||||
|
||||
u8 buffer[MD2_MAX_VERTS*4+128];
|
||||
SMD2Frame* frame = (SMD2Frame*)buffer;
|
||||
|
||||
file->seek(header.offsetFrames);
|
||||
|
||||
for (i = 0; i<header.numFrames; ++i)
|
||||
{
|
||||
// read vertices
|
||||
|
||||
file->read(frame, header.frameSize);
|
||||
|
||||
#ifdef __BIG_ENDIAN__
|
||||
frame->scale[0] = os::Byteswap::byteswap(frame->scale[0]);
|
||||
frame->scale[1] = os::Byteswap::byteswap(frame->scale[1]);
|
||||
frame->scale[2] = os::Byteswap::byteswap(frame->scale[2]);
|
||||
frame->translate[0] = os::Byteswap::byteswap(frame->translate[0]);
|
||||
frame->translate[1] = os::Byteswap::byteswap(frame->translate[1]);
|
||||
frame->translate[2] = os::Byteswap::byteswap(frame->translate[2]);
|
||||
#endif
|
||||
//
|
||||
// store frame data
|
||||
//
|
||||
|
||||
CAnimatedMeshMD2::SAnimationData adata;
|
||||
adata.begin = i;
|
||||
adata.end = i;
|
||||
adata.fps = 7;
|
||||
|
||||
// Add new named animation if necessary
|
||||
if (frame->name[0])
|
||||
{
|
||||
// get animation name
|
||||
for (s32 s = 0; s < 16 && frame->name[s]!=0 && (frame->name[s] < '0' || frame->name[s] > '9'); ++s)
|
||||
{
|
||||
adata.name += frame->name[s];
|
||||
}
|
||||
|
||||
// Does this keyframe have the same animation name as the current animation?
|
||||
if (!mesh->AnimationData.empty() && mesh->AnimationData[mesh->AnimationData.size()-1].name == adata.name)
|
||||
{
|
||||
// Increase the length of the animation
|
||||
++mesh->AnimationData[mesh->AnimationData.size() - 1].end;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Add the new animation
|
||||
mesh->AnimationData.push_back(adata);
|
||||
}
|
||||
}
|
||||
|
||||
// save keyframe scale and translation
|
||||
|
||||
mesh->FrameTransforms[i].scale.X = frame->scale[0];
|
||||
mesh->FrameTransforms[i].scale.Z = frame->scale[1];
|
||||
mesh->FrameTransforms[i].scale.Y = frame->scale[2];
|
||||
mesh->FrameTransforms[i].translate.X = frame->translate[0];
|
||||
mesh->FrameTransforms[i].translate.Z = frame->translate[1];
|
||||
mesh->FrameTransforms[i].translate.Y = frame->translate[2];
|
||||
|
||||
// add vertices
|
||||
for (s32 j=0; j<header.numTriangles; ++j)
|
||||
{
|
||||
for (u32 ti=0; ti<3; ++ti)
|
||||
{
|
||||
CAnimatedMeshMD2::SMD2Vert v;
|
||||
u32 num = triangles[j].vertexIndices[ti];
|
||||
v.Pos.X = frame->vertices[num].vertex[0];
|
||||
v.Pos.Z = frame->vertices[num].vertex[1];
|
||||
v.Pos.Y = frame->vertices[num].vertex[2];
|
||||
v.NormalIdx = frame->vertices[num].lightNormalIndex;
|
||||
|
||||
mesh->FrameList[i].push_back(v);
|
||||
}
|
||||
}
|
||||
|
||||
// calculate bounding boxes
|
||||
if (header.numVertices)
|
||||
{
|
||||
core::aabbox3d<f32> box;
|
||||
core::vector3df pos;
|
||||
pos.X = f32(mesh->FrameList[i] [0].Pos.X) * mesh->FrameTransforms[i].scale.X + mesh->FrameTransforms[i].translate.X;
|
||||
pos.Y = f32(mesh->FrameList[i] [0].Pos.Y) * mesh->FrameTransforms[i].scale.Y + mesh->FrameTransforms[i].translate.Y;
|
||||
pos.Z = f32(mesh->FrameList[i] [0].Pos.Z) * mesh->FrameTransforms[i].scale.Z + mesh->FrameTransforms[i].translate.Z;
|
||||
|
||||
box.reset(pos);
|
||||
|
||||
for (s32 j=1; j<header.numTriangles*3; ++j)
|
||||
{
|
||||
pos.X = f32(mesh->FrameList[i] [j].Pos.X) * mesh->FrameTransforms[i].scale.X + mesh->FrameTransforms[i].translate.X;
|
||||
pos.Y = f32(mesh->FrameList[i] [j].Pos.Y) * mesh->FrameTransforms[i].scale.Y + mesh->FrameTransforms[i].translate.Y;
|
||||
pos.Z = f32(mesh->FrameList[i] [j].Pos.Z) * mesh->FrameTransforms[i].scale.Z + mesh->FrameTransforms[i].translate.Z;
|
||||
|
||||
box.addInternalPoint(pos);
|
||||
}
|
||||
mesh->BoxList.push_back(box);
|
||||
}
|
||||
}
|
||||
|
||||
// populate interpolation buffer with texture coordinates and colours
|
||||
if (header.numFrames)
|
||||
{
|
||||
f32 dmaxs = 1.0f/(header.skinWidth);
|
||||
f32 dmaxt = 1.0f/(header.skinHeight);
|
||||
|
||||
for (s32 t=0; t<header.numTriangles; ++t)
|
||||
{
|
||||
for (s32 n=0; n<3; ++n)
|
||||
{
|
||||
mesh->InterpolationBuffer->Vertices[t*3 + n].TCoords.X = (textureCoords[triangles[t].textureIndices[n]].s + 0.5f) * dmaxs;
|
||||
mesh->InterpolationBuffer->Vertices[t*3 + n].TCoords.Y = (textureCoords[triangles[t].textureIndices[n]].t + 0.5f) * dmaxt;
|
||||
mesh->InterpolationBuffer->Vertices[t*3 + n].Color = video::SColor(255,255,255,255);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// clean up
|
||||
delete [] triangles;
|
||||
delete [] textureCoords;
|
||||
|
||||
// return
|
||||
|
||||
mesh->calculateBoundingBox();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // end namespace scene
|
||||
} // end namespace irr
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -178,7 +178,7 @@ void COpenGLTexture::copyTexture(bool newTexture)
|
|||
break;
|
||||
}
|
||||
|
||||
glBindTexture(GL_TEXTURE_2D, TextureName);
|
||||
Driver->setTexture(0, this);
|
||||
if (Driver->testGLError())
|
||||
os::Printer::log("Could not bind Texture", ELL_ERROR);
|
||||
|
||||
|
@ -416,7 +416,7 @@ void COpenGLTexture::bindRTT()
|
|||
//! Unbind Render Target Texture
|
||||
void COpenGLTexture::unbindRTT()
|
||||
{
|
||||
glBindTexture(GL_TEXTURE_2D, getOpenGLTextureName());
|
||||
Driver->setTexture(0, this);
|
||||
|
||||
// Copy Our ViewPort To The Texture
|
||||
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 0, 0, getSize().Width, getSize().Height);
|
||||
|
@ -456,7 +456,7 @@ COpenGLFBOTexture::COpenGLFBOTexture(const core::dimension2d<s32>& size,
|
|||
|
||||
// generate color texture
|
||||
glGenTextures(1, &TextureName);
|
||||
glBindTexture(GL_TEXTURE_2D, TextureName);
|
||||
Driver->setTexture(0, this);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
|
|
@ -48,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;
|
||||
|
|
286
tests/main.cpp
286
tests/main.cpp
|
@ -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 |
|
@ -59,6 +59,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="..\lib\Win32-visualstudio\Irrlicht.lib"
|
||||
OutputFile="..\bin\Win32-VisualStudio\$(ProjectName).exe"
|
||||
GenerateDebugInformation="true"
|
||||
TargetMachine="1"
|
||||
|
@ -129,6 +130,7 @@
|
|||
/>
|
||||
<Tool
|
||||
Name="VCLinkerTool"
|
||||
AdditionalDependencies="..\lib\Win32-visualstudio\Irrlicht.lib"
|
||||
OutputFile="..\bin\Win32-VisualStudio\$(ProjectName).exe"
|
||||
GenerateDebugInformation="true"
|
||||
OptimizeReferences="2"
|
||||
|
@ -246,6 +248,10 @@
|
|||
RelativePath=".\testVector3d.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\textureRenderStates.cpp"
|
||||
>
|
||||
</File>
|
||||
<File
|
||||
RelativePath=".\vectorPositionDimension2d.cpp"
|
||||
>
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
// Copyright (C) 2008 Christian Stehno, Colin MacDonald
|
||||
// No rights reserved: this software is in the public domain.
|
||||
|
||||
#include "irrlicht.h"
|
||||
#include "testUtils.h"
|
||||
|
||||
using namespace irr;
|
||||
using namespace core;
|
||||
using namespace scene;
|
||||
using namespace video;
|
||||
using namespace io;
|
||||
using namespace gui;
|
||||
|
||||
//! Tests interleaved loading and rendering of textures
|
||||
/** The test loads a texture, renders it using draw2dimage, loads another
|
||||
texture and renders the first one again. Due to the texture cache this
|
||||
can lead to rendering of the second texture in second place. */
|
||||
static bool runTestWithDriver(E_DRIVER_TYPE driverType)
|
||||
{
|
||||
IrrlichtDevice *device = createDevice( driverType, dimension2d<s32>(160, 120), 32);
|
||||
if (!device)
|
||||
return true; // Treat a failure to create a driver as benign; this saves a lot of #ifdefs
|
||||
|
||||
IVideoDriver* driver = device->getVideoDriver();
|
||||
ISceneManager * smgr = device->getSceneManager();
|
||||
|
||||
ITexture* tex1 = driver->getTexture("../media/wall.bmp");
|
||||
|
||||
(void)smgr->addCameraSceneNode();
|
||||
|
||||
driver->beginScene(true, true, SColor(255,100,101,140));
|
||||
driver->draw2DImage(tex1, position2di(0,0));
|
||||
driver->endScene();
|
||||
|
||||
driver->getTexture("../media/tools.png");
|
||||
|
||||
driver->beginScene(true, true, SColor(255,100,101,140));
|
||||
driver->draw2DImage(tex1, position2di(0,0));
|
||||
driver->endScene();
|
||||
|
||||
bool result = takeScreenshotAndCompareAgainstReference(driver, "-textureRenderStates.png", 100);
|
||||
|
||||
device->drop();
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
bool textureRenderStates(void)
|
||||
{
|
||||
bool passed = true;
|
||||
|
||||
passed &= runTestWithDriver(EDT_SOFTWARE);
|
||||
passed &= runTestWithDriver(EDT_BURNINGSVIDEO);
|
||||
passed &= runTestWithDriver(EDT_DIRECT3D9);
|
||||
passed &= runTestWithDriver(EDT_DIRECT3D8);
|
||||
passed &= runTestWithDriver(EDT_OPENGL);
|
||||
|
||||
return passed;
|
||||
}
|
||||
|
|
@ -860,13 +860,11 @@ void CGUIEditWorkspace::PasteXMLToSelectedElement()
|
|||
// rewind file
|
||||
memWrite->seek(0, false);
|
||||
|
||||
io::IXMLReader* xmlReader = (io::IXMLReader*) Environment->getFileSystem()->createXMLReader(memWrite);
|
||||
|
||||
// read xml
|
||||
Environment->readGUIElement(xmlReader, SelectedElement);
|
||||
Environment->loadGUI(memWrite, SelectedElement);
|
||||
|
||||
// drop the xml reader
|
||||
xmlReader->drop();
|
||||
// reset focus
|
||||
Environment->setFocus(this);
|
||||
|
||||
// drop the read file
|
||||
memWrite->drop();
|
||||
|
|
Loading…
Reference in New Issue