Commit afa978f2 authored by hybrid's avatar hybrid

Merge from 1.7 branch, revisions 3877-3908. Fix for...

Merge from 1.7 branch, revisions 3877-3908. Fix for getSphericalCoordinateAngles, some warnign fixes, md2 normal fix, several GUI fixes, isPointInside fix, zip endianess fix.

git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@3909 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 5d7b7931
...@@ -289,6 +289,16 @@ The following names can be queried for the given types: ...@@ -289,6 +289,16 @@ The following names can be queried for the given types:
----------------------------- -----------------------------
Changes in 1.7.3 (??.??.2011) Changes in 1.7.3 (??.??.2011)
- editbox no longer moves text into next line when it fails wrapping creating senseless empty lines which mess up scrolling.
- Fix crash in editbox when scrolling up with empty first lines caused by textwrapping.
- triangle3d::isPointInside can now work with larger integers, old version failed already with values in the 3-digit range. It got also faster. (thx @ Eigen for report + testcase and REDDemon for patch proposal).
- Fix focus problem when removing an unfocused modal dialog reported by Reiko here: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=44358
- Add integer template specialization for vector3d::getSphericalCoordinateAngles which rounds angles to nearest integer now.
- Recalculate FrameRect and ScrollPos in CGUIEditBox when AbsoluteRect gets changed (thx @ serengeor for report + testcase) - Recalculate FrameRect and ScrollPos in CGUIEditBox when AbsoluteRect gets changed (thx @ serengeor for report + testcase)
- Fix 'k' in bigfont.png (thx @ Scrappi for reporting) - Fix 'k' in bigfont.png (thx @ Scrappi for reporting)
......
...@@ -90,7 +90,7 @@ namespace scene ...@@ -90,7 +90,7 @@ namespace scene
//! Transparent effect scene nodes, drawn after Transparent nodes. They are sorted from back to front and drawn in that order. //! Transparent effect scene nodes, drawn after Transparent nodes. They are sorted from back to front and drawn in that order.
ESNRP_TRANSPARENT_EFFECT =32, ESNRP_TRANSPARENT_EFFECT =32,
//! Drawn after the transparent nodes, the time for drawing shadow volumes //! Drawn after the solid nodes, before the transparent nodes, the time for drawing shadow volumes
ESNRP_SHADOW =64 ESNRP_SHADOW =64
}; };
......
...@@ -81,21 +81,39 @@ namespace core ...@@ -81,21 +81,39 @@ namespace core
return d2 < d3 ? rbc : rca; return d2 < d3 ? rbc : rca;
} }
//! Check if a point is inside the triangle //! Check if a point is inside the triangle (border-points count also as inside)
/** \param p Point to test. Assumes that this point is already /** \param p Point to test. Assumes that this point is already
on the plane of the triangle. on the plane of the triangle.
\return True if the point is inside the triangle, otherwise false. */ \return True if the point is inside the triangle, otherwise false. */
bool isPointInside(const vector3d<T>& p) const bool isPointInside(const vector3d<T>& p) const
{ {
return (isOnSameSide(p, pointA, pointB, pointC) && const vector3d<T> a = pointC - pointA;
isOnSameSide(p, pointB, pointA, pointC) && const vector3d<T> b = pointB - pointA;
isOnSameSide(p, pointC, pointA, pointB)); const vector3d<T> c = p - pointA;
const f64 dotAA = a.dotProduct( a);
const f64 dotAB = a.dotProduct( b);
const f64 dotAC = a.dotProduct( c);
const f64 dotBB = b.dotProduct( b);
const f64 dotBC = b.dotProduct( c);
// get coordinates in barycentric coordinate system
const f64 invDenom = 1/(dotAA * dotBB - dotAB * dotAB);
const f64 u = (dotBB * dotAC - dotAB * dotBC) * invDenom;
const f64 v = (dotAA * dotBC - dotAB * dotAC ) * invDenom;
// We count border-points as inside to keep downward compatibility.
// That's why we use >= and <= instead of > and < as more commonly seen on the web.
return (u >= 0) && (v >= 0) && (u + v <= 1);
} }
//! Check if a point is inside the triangle. //! Check if a point is inside the triangle.
/** This method is an implementation of the example used in a /** This method is an implementation of the example used in a
paper by Kasper Fauerby original written by Keidy from paper by Kasper Fauerby original written by Keidy from
Mr-Gamemaker. Mr-Gamemaker.
This was once faster than an old isPointInside implementation, but the
current isPointInside is usualy as fast, sometimes even faster.
Border-points in isPointInsideFast are not defined, some are inside and some outside.
\param p Point to test. Assumes that this point is already \param p Point to test. Assumes that this point is already
on the plane of the triangle. on the plane of the triangle.
\return True if point is inside the triangle, otherwise false. */ \return True if point is inside the triangle, otherwise false. */
......
...@@ -246,7 +246,7 @@ public: ...@@ -246,7 +246,7 @@ public:
if (tmp < 0.0) if (tmp < 0.0)
tmp = -tmp; tmp = -tmp;
if ( tmp > 1.0 ) // avoid floating-point trouble if ( tmp > 1.0 ) // avoid floating-point trouble
tmp = 1.0; tmp = 1.0;
return atan(sqrt(1 - tmp*tmp) / tmp) * RADTODEG64; return atan(sqrt(1 - tmp*tmp) / tmp) * RADTODEG64;
} }
......
...@@ -421,6 +421,26 @@ namespace core ...@@ -421,6 +421,26 @@ namespace core
template <> template <>
inline vector3d<s32>& vector3d<s32>::operator /=(s32 val) {X/=val;Y/=val;Z/=val; return *this;} inline vector3d<s32>& vector3d<s32>::operator /=(s32 val) {X/=val;Y/=val;Z/=val; return *this;}
template <>
inline vector3d<s32> vector3d<s32>::getSphericalCoordinateAngles()
{
vector3d<s32> angle;
const f64 length = X*X + Y*Y + Z*Z;
if (length)
{
if (X!=0)
{
angle.Y = round32((f32)(atan2((f64)Z,(f64)X) * RADTODEG64));
}
else if (Z<0)
angle.Y=180;
angle.X = round32((f32)(acos(Y * core::reciprocal_squareroot(length)) * RADTODEG64));
}
return angle;
}
//! Typedef for a f32 3d vector. //! Typedef for a f32 3d vector.
typedef vector3d<f32> vector3df; typedef vector3d<f32> vector3df;
......
...@@ -15,8 +15,7 @@ namespace scene ...@@ -15,8 +15,7 @@ namespace scene
{ {
const s32 MD2_FRAME_SHIFT = 2; const s32 MD2_FRAME_SHIFT = 2;
const f32 MD2_FRAME_SHIFT_RECIPROCAL = 1.f / ( 1 << MD2_FRAME_SHIFT ); const f32 MD2_FRAME_SHIFT_RECIPROCAL = 1.f / (1 << MD2_FRAME_SHIFT);
const s32 Q2_VERTEX_NORMAL_TABLE_SIZE = 162; const s32 Q2_VERTEX_NORMAL_TABLE_SIZE = 162;
...@@ -194,27 +193,27 @@ struct SMD2AnimationType ...@@ -194,27 +193,27 @@ struct SMD2AnimationType
static const SMD2AnimationType MD2AnimationTypeList[21] = static const SMD2AnimationType MD2AnimationTypeList[21] =
{ {
{ 0, 39, 9 }, // STAND { 0, 39, 9}, // STAND
{ 40, 45, 10 }, // RUN { 40, 45, 10}, // RUN
{ 46, 53, 10 }, // ATTACK { 46, 53, 10}, // ATTACK
{ 54, 57, 7 }, // PAIN_A { 54, 57, 7}, // PAIN_A
{ 58, 61, 7 }, // PAIN_B { 58, 61, 7}, // PAIN_B
{ 62, 65, 7 }, // PAIN_C { 62, 65, 7}, // PAIN_C
{ 66, 71, 7 }, // JUMP { 66, 71, 7}, // JUMP
{ 72, 83, 7 }, // FLIP { 72, 83, 7}, // FLIP
{ 84, 94, 7 }, // SALUTE { 84, 94, 7}, // SALUTE
{ 95, 111, 10 }, // FALLBACK { 95, 111, 10}, // FALLBACK
{ 112, 122, 7 }, // WAVE {112, 122, 7}, // WAVE
{ 123, 134, 6 }, // POINT {123, 134, 6}, // POINT
{ 135, 153, 10 }, // CROUCH_STAND {135, 153, 10}, // CROUCH_STAND
{ 154, 159, 7 }, // CROUCH_WALK {154, 159, 7}, // CROUCH_WALK
{ 160, 168, 10 }, // CROUCH_ATTACK {160, 168, 10}, // CROUCH_ATTACK
{ 169, 172, 7 }, // CROUCH_PAIN {169, 172, 7}, // CROUCH_PAIN
{ 173, 177, 5 }, // CROUCH_DEATH {173, 177, 5}, // CROUCH_DEATH
{ 178, 183, 7 }, // DEATH_FALLBACK {178, 183, 7}, // DEATH_FALLBACK
{ 184, 189, 7 }, // DEATH_FALLFORWARD {184, 189, 7}, // DEATH_FALLFORWARD
{ 190, 197, 7 }, // DEATH_FALLBACKSLOW {190, 197, 7}, // DEATH_FALLBACKSLOW
{ 198, 198, 5 }, // BOOM {198, 198, 5}, // BOOM
}; };
...@@ -238,6 +237,7 @@ CAnimatedMeshMD2::~CAnimatedMeshMD2() ...@@ -238,6 +237,7 @@ CAnimatedMeshMD2::~CAnimatedMeshMD2()
InterpolationBuffer->drop(); InterpolationBuffer->drop();
} }
//! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh. //! returns the amount of frames in milliseconds. If the amount is 1, it is a static (=non animated) mesh.
u32 CAnimatedMeshMD2::getFrameCount() const u32 CAnimatedMeshMD2::getFrameCount() const
{ {
...@@ -294,7 +294,6 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, ...@@ -294,7 +294,6 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop,
{ {
u32 firstFrame, secondFrame; u32 firstFrame, secondFrame;
f32 div; f32 div;
core::vector3df* NormalTable = (core::vector3df*)&Q2_VERTEX_NORMAL_TABLE;
// TA: resolve missing ipol in loop between end-start // TA: resolve missing ipol in loop between end-start
...@@ -311,10 +310,10 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, ...@@ -311,10 +310,10 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop,
u32 e = endFrameLoop >> MD2_FRAME_SHIFT; u32 e = endFrameLoop >> MD2_FRAME_SHIFT;
firstFrame = frame >> MD2_FRAME_SHIFT; firstFrame = frame >> MD2_FRAME_SHIFT;
secondFrame = core::if_c_a_else_b ( firstFrame + 1 > e, s, firstFrame + 1 ); secondFrame = core::if_c_a_else_b(firstFrame + 1 > e, s, firstFrame + 1);
firstFrame = core::s32_min ( FrameCount - 1, firstFrame ); firstFrame = core::s32_min(FrameCount - 1, firstFrame);
secondFrame = core::s32_min ( FrameCount - 1, secondFrame ); secondFrame = core::s32_min(FrameCount - 1, secondFrame);
//div = (frame % (1<<MD2_FRAME_SHIFT)) / (f32)(1<<MD2_FRAME_SHIFT); //div = (frame % (1<<MD2_FRAME_SHIFT)) / (f32)(1<<MD2_FRAME_SHIFT);
frame &= (1<<MD2_FRAME_SHIFT) - 1; frame &= (1<<MD2_FRAME_SHIFT) - 1;
...@@ -322,24 +321,29 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop, ...@@ -322,24 +321,29 @@ void CAnimatedMeshMD2::updateInterpolationBuffer(s32 frame, s32 startFrameLoop,
} }
video::S3DVertex* target = static_cast<video::S3DVertex*>(InterpolationBuffer->getVertices()); video::S3DVertex* target = static_cast<video::S3DVertex*>(InterpolationBuffer->getVertices());
SMD2Vert* first = FrameList[firstFrame].pointer(); SMD2Vert* first = FrameList[firstFrame].pointer();
SMD2Vert* second = FrameList[secondFrame].pointer(); SMD2Vert* second = FrameList[secondFrame].pointer();
// interpolate both frames // interpolate both frames
const u32 count = FrameList[firstFrame].size(); const u32 count = FrameList[firstFrame].size();
for (u32 i=0; i<count; ++i) for (u32 i=0; i<count; ++i)
{ {
core::vector3df one, two; const core::vector3df one = core::vector3df(f32(first->Pos.X) * FrameTransforms[firstFrame].scale.X + FrameTransforms[firstFrame].translate.X,
one.X = f32(first->Pos.X) * FrameTransforms[firstFrame].scale.X + FrameTransforms[firstFrame].translate.X; f32(first->Pos.Y) * FrameTransforms[firstFrame].scale.Y + FrameTransforms[firstFrame].translate.Y,
one.Y = f32(first->Pos.Y) * FrameTransforms[firstFrame].scale.Y + FrameTransforms[firstFrame].translate.Y; f32(first->Pos.Z) * FrameTransforms[firstFrame].scale.Z + FrameTransforms[firstFrame].translate.Z);
one.Z = f32(first->Pos.Z) * FrameTransforms[firstFrame].scale.Z + FrameTransforms[firstFrame].translate.Z; const core::vector3df two = core::vector3df(f32(second->Pos.X) * FrameTransforms[secondFrame].scale.X + FrameTransforms[secondFrame].translate.X,
two.X = f32(second->Pos.X) * FrameTransforms[secondFrame].scale.X + FrameTransforms[secondFrame].translate.X; f32(second->Pos.Y) * FrameTransforms[secondFrame].scale.Y + FrameTransforms[secondFrame].translate.Y,
two.Y = f32(second->Pos.Y) * FrameTransforms[secondFrame].scale.Y + FrameTransforms[secondFrame].translate.Y; f32(second->Pos.Z) * FrameTransforms[secondFrame].scale.Z + FrameTransforms[secondFrame].translate.Z);
two.Z = f32(second->Pos.Z) * FrameTransforms[secondFrame].scale.Z + FrameTransforms[secondFrame].translate.Z; target->Pos = two.getInterpolated(one, div);
target->Pos = (two - one) * div + one; const core::vector3df n1(
Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][0],
target->Normal = (NormalTable[second->NormalIdx] - NormalTable[first->NormalIdx]) * div Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][2],
+ NormalTable[first->NormalIdx]; Q2_VERTEX_NORMAL_TABLE[first->NormalIdx][1]);
const core::vector3df n2(
Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][0],
Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][2],
Q2_VERTEX_NORMAL_TABLE[second->NormalIdx][1]);
target->Normal = n2.getInterpolated(n1, div);
++target; ++target;
++first; ++first;
++second; ++second;
...@@ -381,7 +385,7 @@ const core::aabbox3d<f32>& CAnimatedMeshMD2::getBoundingBox() const ...@@ -381,7 +385,7 @@ const core::aabbox3d<f32>& CAnimatedMeshMD2::getBoundingBox() const
//! set user axis aligned bounding box //! set user axis aligned bounding box
void CAnimatedMeshMD2::setBoundingBox( const core::aabbox3df& box) void CAnimatedMeshMD2::setBoundingBox(const core::aabbox3df& box)
{ {
InterpolationBuffer->BoundingBox = box; InterpolationBuffer->BoundingBox = box;
} }
...@@ -396,7 +400,7 @@ E_ANIMATED_MESH_TYPE CAnimatedMeshMD2::getMeshType() const ...@@ -396,7 +400,7 @@ E_ANIMATED_MESH_TYPE CAnimatedMeshMD2::getMeshType() const
//! Returns frame loop data for a special MD2 animation type. //! Returns frame loop data for a special MD2 animation type.
void CAnimatedMeshMD2::getFrameLoop(EMD2_ANIMATION_TYPE l, void CAnimatedMeshMD2::getFrameLoop(EMD2_ANIMATION_TYPE l,
s32& outBegin, s32& outEnd, s32& outFPS) const s32& outBegin, s32& outEnd, s32& outFPS) const
{ {
if (l < 0 || l >= EMAT_COUNT) if (l < 0 || l >= EMAT_COUNT)
return; return;
...@@ -405,7 +409,7 @@ void CAnimatedMeshMD2::getFrameLoop(EMD2_ANIMATION_TYPE l, ...@@ -405,7 +409,7 @@ void CAnimatedMeshMD2::getFrameLoop(EMD2_ANIMATION_TYPE l,
outEnd = MD2AnimationTypeList[l].end << MD2_FRAME_SHIFT; outEnd = MD2AnimationTypeList[l].end << MD2_FRAME_SHIFT;
// correct to anim between last->first frame // correct to anim between last->first frame
outEnd += MD2_FRAME_SHIFT == 0 ? 1 : ( 1 << MD2_FRAME_SHIFT ) - 1; outEnd += MD2_FRAME_SHIFT == 0 ? 1 : (1 << MD2_FRAME_SHIFT) - 1;
outFPS = MD2AnimationTypeList[l].fps << MD2_FRAME_SHIFT; outFPS = MD2AnimationTypeList[l].fps << MD2_FRAME_SHIFT;
} }
...@@ -420,7 +424,7 @@ bool CAnimatedMeshMD2::getFrameLoop(const c8* name, ...@@ -420,7 +424,7 @@ bool CAnimatedMeshMD2::getFrameLoop(const c8* name,
{ {
outBegin = AnimationData[i].begin << MD2_FRAME_SHIFT; outBegin = AnimationData[i].begin << MD2_FRAME_SHIFT;
outEnd = AnimationData[i].end << MD2_FRAME_SHIFT; outEnd = AnimationData[i].end << MD2_FRAME_SHIFT;
outEnd += MD2_FRAME_SHIFT == 0 ? 1 : ( 1 << MD2_FRAME_SHIFT ) - 1; outEnd += MD2_FRAME_SHIFT == 0 ? 1 : (1 << MD2_FRAME_SHIFT) - 1;
outFPS = AnimationData[i].fps << MD2_FRAME_SHIFT; outFPS = AnimationData[i].fps << MD2_FRAME_SHIFT;
return true; return true;
} }
......
...@@ -520,7 +520,7 @@ bool CGUIEditBox::processKey(const SEvent& event) ...@@ -520,7 +520,7 @@ bool CGUIEditBox::processKey(const SEvent& event)
{ {
s32 cp = CursorPos - BrokenTextPositions[lineNo]; s32 cp = CursorPos - BrokenTextPositions[lineNo];
if ((s32)BrokenText[lineNo-1].size() < cp) if ((s32)BrokenText[lineNo-1].size() < cp)
CursorPos = BrokenTextPositions[lineNo-1] + (s32)BrokenText[lineNo-1].size()-1; CursorPos = BrokenTextPositions[lineNo-1] + core::max_((u32)1, BrokenText[lineNo-1].size())-1;
else else
CursorPos = BrokenTextPositions[lineNo-1] + cp; CursorPos = BrokenTextPositions[lineNo-1] + cp;
} }
...@@ -551,7 +551,7 @@ bool CGUIEditBox::processKey(const SEvent& event) ...@@ -551,7 +551,7 @@ bool CGUIEditBox::processKey(const SEvent& event)
{ {
s32 cp = CursorPos - BrokenTextPositions[lineNo]; s32 cp = CursorPos - BrokenTextPositions[lineNo];
if ((s32)BrokenText[lineNo+1].size() < cp) if ((s32)BrokenText[lineNo+1].size() < cp)
CursorPos = BrokenTextPositions[lineNo+1] + BrokenText[lineNo+1].size()-1; CursorPos = BrokenTextPositions[lineNo+1] + core::max_((u32)1, BrokenText[lineNo+1].size())-1;
else else
CursorPos = BrokenTextPositions[lineNo+1] + cp; CursorPos = BrokenTextPositions[lineNo+1] + cp;
} }
...@@ -1135,7 +1135,7 @@ void CGUIEditBox::breakText() ...@@ -1135,7 +1135,7 @@ void CGUIEditBox::breakText()
s32 whitelgth = font->getDimension(whitespace.c_str()).Width; s32 whitelgth = font->getDimension(whitespace.c_str()).Width;
s32 worldlgth = font->getDimension(word.c_str()).Width; s32 worldlgth = font->getDimension(word.c_str()).Width;
if (WordWrap && length + worldlgth + whitelgth > elWidth) if (WordWrap && length + worldlgth + whitelgth > elWidth && line.size() > 0)
{ {
// break to next line // break to next line
length = worldlgth; length = worldlgth;
......
...@@ -33,7 +33,7 @@ bool CGUIModalScreen::canTakeFocus(IGUIElement* target) const ...@@ -33,7 +33,7 @@ bool CGUIModalScreen::canTakeFocus(IGUIElement* target) const
{ {
return (target && ((const IGUIElement*)target == this // this element can take it return (target && ((const IGUIElement*)target == this // this element can take it
|| isMyChild(target) // own children also || isMyChild(target) // own children also
|| (target->getType() == EGUIET_MODAL_SCREEN )// other modals also fine || (target->getType() == EGUIET_MODAL_SCREEN ) // other modals also fine (is now on top or explicitely requested)
|| (target->getParent() && target->getParent()->getType() == EGUIET_MODAL_SCREEN ))) // children of other modals will do || (target->getParent() && target->getParent()->getType() == EGUIET_MODAL_SCREEN ))) // children of other modals will do
; ;
} }
...@@ -86,6 +86,13 @@ bool CGUIModalScreen::OnEvent(const SEvent& event) ...@@ -86,6 +86,13 @@ bool CGUIModalScreen::OnEvent(const SEvent& event)
switch(event.GUIEvent.EventType) switch(event.GUIEvent.EventType)
{ {
case EGET_ELEMENT_FOCUSED: case EGET_ELEMENT_FOCUSED:
if ( event.GUIEvent.Caller == this && isMyChild(event.GUIEvent.Element) )
{
Environment->removeFocus(0); // can't setFocus otherwise at it still has focus here
Environment->setFocus(event.GUIEvent.Element);
MouseDownTime = os::Timer::getTime();
return true;
}
if ( !canTakeFocus(event.GUIEvent.Caller)) if ( !canTakeFocus(event.GUIEvent.Caller))
{ {
if ( !Children.empty() ) if ( !Children.empty() )
......
...@@ -104,7 +104,7 @@ IFileArchive* CArchiveLoaderZIP::createArchive(io::IReadFile* file, bool ignoreC ...@@ -104,7 +104,7 @@ IFileArchive* CArchiveLoaderZIP::createArchive(io::IReadFile* file, bool ignoreC
file->read(&sig, 2); file->read(&sig, 2);
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
os::Byteswap::byteswap(sig); sig = os::Byteswap::byteswap(sig);
#endif #endif
file->seek(0); file->seek(0);
...@@ -126,7 +126,7 @@ bool CArchiveLoaderZIP::isALoadableFileFormat(io::IReadFile* file) const ...@@ -126,7 +126,7 @@ bool CArchiveLoaderZIP::isALoadableFileFormat(io::IReadFile* file) const
file->read( &header.Sig, 4 ); file->read( &header.Sig, 4 );
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
os::Byteswap::byteswap(header.Sig); header.Sig = os::Byteswap::byteswap(header.Sig);
#endif #endif
return header.Sig == 0x04034b50 || // ZIP return header.Sig == 0x04034b50 || // ZIP
...@@ -192,8 +192,8 @@ bool CZipReader::scanGZipHeader() ...@@ -192,8 +192,8 @@ bool CZipReader::scanGZipHeader()
{ {
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
os::Byteswap::byteswap(header.sig); header.sig = os::Byteswap::byteswap(header.sig);
os::Byteswap::byteswap(header.time); header.time = os::Byteswap::byteswap(header.time);
#endif #endif
// check header value // check header value
...@@ -209,7 +209,7 @@ bool CZipReader::scanGZipHeader() ...@@ -209,7 +209,7 @@ bool CZipReader::scanGZipHeader()
File->read(&dataLen, 2); File->read(&dataLen, 2);
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
os::Byteswap::byteswap(dataLen); dataLen = os::Byteswap::byteswap(dataLen);
#endif #endif
// skip it // skip it
...@@ -274,8 +274,8 @@ bool CZipReader::scanGZipHeader() ...@@ -274,8 +274,8 @@ bool CZipReader::scanGZipHeader()
File->read(&entry.header.DataDescriptor.UncompressedSize, 4); File->read(&entry.header.DataDescriptor.UncompressedSize, 4);
#ifdef __BIG_ENDIAN__ #ifdef __BIG_ENDIAN__
os::Byteswap::byteswap(entry.header.DataDescriptor.CRC32); entry.header.DataDescriptor.CRC32 = os::Byteswap::byteswap(entry.header.DataDescriptor.CRC32);
os::Byteswap::byteswap(entry.header.DataDescriptor.UncompressedSize); entry.header.DataDescriptor.UncompressedSize = os::Byteswap::byteswap(entry.header.DataDescriptor.UncompressedSize);
#endif #endif
// now we've filled all the fields, this is just a standard deflate block // now we've filled all the fields, this is just a standard deflate block
......
...@@ -5,49 +5,43 @@ ...@@ -5,49 +5,43 @@
using namespace irr; using namespace irr;
using namespace core; using namespace core;
using namespace scene;
using namespace video;
using namespace io;
using namespace gui;
namespace
{
// Tests MD2 animations. // Tests MD2 animations.
/** At the moment, this just verifies that the last frame of the animation produces the expected bitmap. */ /** At the moment, this just verifies that the last frame of the animation produces the expected bitmap. */
bool md2Animation(void) bool testLastFrame()
{ {
// Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions. // Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions.
IrrlichtDevice *device = createDevice( EDT_BURNINGSVIDEO, dimension2d<u32>(160, 120), 32); IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, dimension2d<u32>(160, 120), 32);
assert(device);
if (!device) if (!device)
return false; return false;
IVideoDriver* driver = device->getVideoDriver(); video::IVideoDriver* driver = device->getVideoDriver();
ISceneManager * smgr = device->getSceneManager(); scene::ISceneManager * smgr = device->getSceneManager();
IAnimatedMesh* mesh = smgr->getMesh("../media/sydney.md2"); scene::IAnimatedMesh* mesh = smgr->getMesh("../media/sydney.md2");
IAnimatedMeshSceneNode* node;
assert(mesh);
bool result = (mesh != 0); bool result = (mesh != 0);
if(mesh) if (mesh)
{ {
node = smgr->addAnimatedMeshSceneNode(mesh); scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
assert(node);
if(node) if (node)
{ {
node->setPosition(vector3df(20, 0, 30)); node->setPosition(vector3df(20, 0, 30));
node->setMaterialFlag(EMF_LIGHTING, false); node->setMaterialFlag(video::EMF_LIGHTING, false);
node->setMaterialTexture(0, driver->getTexture("../media/sydney.bmp")); node->setMaterialTexture(0, driver->getTexture("../media/sydney.bmp"));
node->setLoopMode(false); node->setLoopMode(false);
(void)smgr->addCameraSceneNode(); (void)smgr->addCameraSceneNode();
// Just jump to the last frame since that's all we're interested in. // Just jump to the last frame since that's all we're interested in.
node->setMD2Animation(EMAT_DEATH_FALLBACK); node->setMD2Animation(scene::EMAT_DEATH_FALLBACK);
node->setCurrentFrame((f32)(node->getEndFrame())); node->setCurrentFrame((f32)(node->getEndFrame()));
node->setAnimationSpeed(0); node->setAnimationSpeed(0);
device->run(); device->run();
driver->beginScene(true, true, SColor(255, 255, 255, 0)); driver->beginScene(true, true, video::SColor(255, 255, 255, 0));
smgr->drawAll(); smgr->drawAll();
driver->endScene(); driver->endScene();
if (mesh->getBoundingBox() != mesh->getMesh(node->getEndFrame())->getBoundingBox()) if (mesh->getBoundingBox() != mesh->getMesh(node->getEndFrame())->getBoundingBox())
...@@ -79,3 +73,56 @@ bool md2Animation(void) ...@@ -79,3 +73,56 @@ bool md2Animation(void)
return result; return result;
} }
// Tests MD2 normals.
bool testNormals()
{
// Use EDT_BURNINGSVIDEO since it is not dependent on (e.g.) OpenGL driver versions.
IrrlichtDevice *device = createDevice(video::EDT_BURNINGSVIDEO, dimension2d<u32>(160, 120), 32);
if (!device)
return false;
video::IVideoDriver* driver = device->getVideoDriver();
scene::ISceneManager * smgr = device->getSceneManager();
scene::IAnimatedMesh* mesh = smgr->getMesh("../media/sydney.md2");
bool result = (mesh != 0);
if (mesh)
{
scene::IAnimatedMeshSceneNode* node = smgr->addAnimatedMeshSceneNode(mesh);
if (node)
{
node->setPosition(vector3df(20, 0, 30));
node->setMaterialFlag(video::EMF_LIGHTING, false);
node->setDebugDataVisible(scene::EDS_NORMALS);
node->setMaterialTexture(0, driver->getTexture("../media/sydney.bmp"));
node->setLoopMode(false);
(void)smgr->addCameraSceneNode();
node->setMD2Animation(scene::EMAT_STAND);
node->setAnimationSpeed(0);
device->run();
driver->beginScene(true, true, video::SColor(255, 255, 255, 0));
smgr->drawAll();
driver->endScene();
}
}
result &= takeScreenshotAndCompareAgainstReference(driver, "-md2Normals.png");
device->closeDevice();
device->run();
device->drop();
return result;
}
}
// test md2 features
bool md2Animation(void)
{
bool result = testLastFrame();
result &= testNormals();
return result;
}
...@@ -59,6 +59,164 @@ static bool testGetIntersectionWithLine(core::triangle3d<T>& triangle, const cor ...@@ -59,6 +59,164 @@ static bool testGetIntersectionWithLine(core::triangle3d<T>& triangle, const cor
return allExpected; return allExpected;
} }
// modifying the same triangle in diverse ways get some more test-cases automatically
template<class T>
static bool stageModifications(int stage, triangle3d<T>& triangle)
{
switch ( stage )
{
case 0:
return true;
case 1:
swap(triangle.pointB, triangle.pointC);
return true;
case 2:
swap(triangle.pointA, triangle.pointC);
return true;
case 3:
triangle.pointA.Z += 1000;
triangle.pointB.Z += 1000;
triangle.pointC.Z += 1000;
return true;
case 4:
swap(triangle.pointA.Y, triangle.pointA.Z);
swap(triangle.pointB.Y, triangle.pointB.Z);
swap(triangle.pointC.Y, triangle.pointC.Z);
return true;
}
return false;
}
template<class T>
static void stageModifications(int stage, vector3d<T>& point)
{
switch ( stage )
{
case 3:
point.Z += 1000;
break;
case 4:
swap(point.Y, point.Z);
break;
}
}
template<class T>
static bool isPointInside(triangle3d<T> triangleOrig)
{
bool allExpected=true;
array< vector3d<T> > pointsInside;
pointsInside.push_back( vector3d<T>(0,0,0) );
pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointB + triangleOrig.pointC) / 3 );
pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 + vector3d<T>(0,1,0) );
pointsInside.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 + vector3d<T>(1,0,0) );
pointsInside.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 - vector3d<T>(1,0,0) );
for (u32 stage=0; ; ++stage)
{
triangle3d<T> triangle = triangleOrig;
if ( !stageModifications(stage, triangle) )
break;
for ( u32 i=0; i < pointsInside.size(); ++i )
{
vector3d<T> point = pointsInside[i];
stageModifications(stage, point);
allExpected &= triangle.isPointInside( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInside pointsInside test failed in stage %d point %d\n", stage, i);
return false;
}
allExpected &= triangle.isPointInsideFast( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInsideFast pointsInside test failed in stage %d point %d\n", stage, i);
return false;
}
}
}
array< vector3d<T> > pointsOutside;
pointsOutside.push_back( triangleOrig.pointA - vector3d<T>(1,0,0) );
pointsOutside.push_back( triangleOrig.pointA - vector3d<T>(0,1,0) );
pointsOutside.push_back( triangleOrig.pointB + vector3d<T>(1,0,0) );
pointsOutside.push_back( triangleOrig.pointB - vector3d<T>(0,1,0) );
pointsOutside.push_back( triangleOrig.pointC - vector3d<T>(1,0,0) );
pointsOutside.push_back( triangleOrig.pointC + vector3d<T>(1,0,0) );
pointsOutside.push_back( triangleOrig.pointC + vector3d<T>(0,1,0) );
pointsOutside.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 - vector3d<T>(0,1,0) );
pointsOutside.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 - vector3d<T>(1,0,0) );
pointsOutside.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 + vector3d<T>(1,0,0) );
for (u32 stage=0; ; ++stage)
{
triangle3d<T> triangle = triangleOrig;
if ( !stageModifications(stage, triangle) )
break;
for ( u32 i=0; i < pointsOutside.size(); ++i )
{
vector3d<T> point = pointsOutside[i];
stageModifications(stage, point);
allExpected &= !triangle.isPointInside( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInside pointsOutside test failed in stage %d point %d\n", stage, i);
return false;
}
allExpected &= !triangle.isPointInsideFast( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInsideFast pointsOutside test failed in stage %d point %d\n", stage, i);
return false;
}
}
}
array< vector3d<T> > pointsBorder;
pointsBorder.push_back( triangleOrig.pointA );
pointsBorder.push_back( triangleOrig.pointB );
pointsBorder.push_back( triangleOrig.pointC );
pointsBorder.push_back( (triangleOrig.pointA + triangleOrig.pointB)/2 );
pointsBorder.push_back( (triangleOrig.pointA + triangleOrig.pointC)/2 );
pointsBorder.push_back( (triangleOrig.pointB + triangleOrig.pointC)/2 );
for (u32 stage=0; ; ++stage)
{
triangle3d<T> triangle = triangleOrig;
if ( !stageModifications(stage, triangle) )
break;
for ( u32 i=0; i < pointsBorder.size(); ++i )
{
vector3d<T> point = pointsBorder[i];
stageModifications(stage, point);
allExpected &= triangle.isPointInside( point );
if ( !allExpected )
{
logTestString("triangle3d::isPointInside pointsBorder test failed in stage %d point %d\n", stage, i);
return false;
}
/* results for isPointInsideFast are mixed for border cases, but I guess that's fine.
if ( triangle.isPointInsideFast( point ) )
logTestString("+ triangle3d::isPointInsideFast pointsBorder stage %d point %d is INSIDE\n", stage, i);
else
logTestString("- triangle3d::isPointInsideFast pointsBorder stage %d point %d is NOT inside\n", stage, i);
*/
}
}
return allExpected;
}
// Test the functionality of triangle3d<T> // Test the functionality of triangle3d<T>
/** Validation is done with asserts() against expected results. */ /** Validation is done with asserts() against expected results. */
...@@ -89,6 +247,29 @@ bool testTriangle3d(void) ...@@ -89,6 +247,29 @@ bool testTriangle3d(void)
allExpected &= testGetIntersectionWithLine(triangle, ray); allExpected &= testGetIntersectionWithLine(triangle, ray);
} }
bool testEigen = triangle3di(vector3di(250, 0, 0), vector3di(0, 0, 500), vector3di(500, 0, 500)).isPointInside(vector3di(300,0,300));
if ( !testEigen ) // test from Eigen from here: http://irrlicht.sourceforge.net/forum/viewtopic.php?f=7&t=44372&p=254331#p254331
logTestString("Test isPointInside fails with integers\n");
allExpected &= testEigen;
logTestString("Test isPointInside with f32\n");
{
triangle3d<f32> t(vector3d<f32>(-1000,-1000,0), vector3d<f32>(1000,-1000,0), vector3d<f32>(0,1000,0));
allExpected &= isPointInside(t);
}
logTestString("Test isPointInside with f64\n");
{
triangle3d<f64> t(vector3d<f64>(-1000,-1000,0), vector3d<f64>(1000,-1000,0), vector3d<f64>(0,1000,0));
allExpected &= isPointInside(t);
}
logTestString("Test isPointInside with s32\n");
{
triangle3d<s32> t(vector3d<s32>(-1000,-1000,0), vector3d<s32>(1000,-1000,0), vector3d<s32>(0,1000,0));
allExpected &= isPointInside(t);
}
if(allExpected) if(allExpected)
logTestString("\nAll tests passed\n"); logTestString("\nAll tests passed\n");
else else
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment