Commit cc2b3716 authored by cutealien's avatar cutealien

Improve speed for finalizing skinned meshes (removal of unnecessary frames...

Improve speed for finalizing skinned meshes (removal of unnecessary frames after loading) (thx @ichtyander for the testmodel)
Down from ~20 seconds to ~0,5 seconds :-)


git-svn-id: svn://svn.code.sf.net/p/irrlicht/code/trunk@4622 dfc29bdd-3216-0410-991c-e03cc46cb475
parent 29faf510
-------------------------- --------------------------
Changes in 1.9 (not yet released) Changes in 1.9 (not yet released)
- Improve speed for finalizing skinned meshes (removal of unnecessary frames after loading) (thx @ichtyander for the testmodel)
- Collada loader now instantiates camera nodes which had been ignore so far (thx @NemoStein for the test .dae) - Collada loader now instantiates camera nodes which had been ignore so far (thx @NemoStein for the test .dae)
- line2d::intersectWith has a new parameter to allow ignoring intersections with coincident lines - line2d::intersectWith has a new parameter to allow ignoring intersections with coincident lines
- vector2d::equals now has an tolerance parameter for passing the epsilon (like vector3d had). Note that this changes the default - vector2d::equals now has an tolerance parameter for passing the epsilon (like vector3d had). Note that this changes the default
......
...@@ -24,7 +24,7 @@ namespace gui ...@@ -24,7 +24,7 @@ namespace gui
//! Validate when enter was pressed //! Validate when enter was pressed
EGUI_SBV_ENTER = 2, EGUI_SBV_ENTER = 2,
//! Validate when the editbox loses the focus //! Validate when the editbox loses the focus
EGUI_SBV_LOSE_FOCUS = 4, EGUI_SBV_LOSE_FOCUS = 4
}; };
......
...@@ -10,6 +10,80 @@ ...@@ -10,6 +10,80 @@
#include "IAnimatedMeshSceneNode.h" #include "IAnimatedMeshSceneNode.h"
#include "os.h" #include "os.h"
namespace
{
// Frames must always be increasing, so we remove objects where this isn't the case
// return number of kicked keys
template <class T> // T = objects containing a "frame" variable
irr::u32 dropBadKeys(irr::core::array<T>& array)
{
if (array.size()<2)
return 0;
irr::u32 n=1; // new index
for(irr::u32 j=1;j<array.size();++j)
{
if (array[j].frame < array[j-1].frame)
continue; //bad frame, unneeded and may cause problems
if ( n != j )
array[n] = array[j];
++n;
}
irr::u32 d = array.size()-n; // remove already copied keys
if ( d > 0 )
{
array.erase(n, d);
}
return d;
}
// drop identical middle keys - we only need the first and last
// return number of kicked keys
template <class T, typename Cmp> // Cmp = comparison for keys of type T
irr::u32 dropMiddleKeys(irr::core::array<T>& array, Cmp & cmp)
{
if ( array.size() < 3 )
return 0;
irr::u32 s = 0; // old index for current key
irr::u32 n = 1; // new index for next key
for(irr::u32 j=1;j<array.size();++j)
{
if ( cmp(array[j], array[s]) )
continue; // same key, handle later
if ( j > s+1 ) // had there been identical keys?
array[n++] = array[j-1]; // keep the last
array[n++] = array[j]; // keep the new one
s = j;
}
if ( array.size() > s+1 ) // identical keys at the array end?
array[n++] = array[array.size()-1]; // keep the last
irr::u32 d = array.size()-n; // remove already copied keys
if ( d > 0 )
{
array.erase(n, d);
}
return d;
}
bool identicalPos(const irr::scene::ISkinnedMesh::SPositionKey& a, const irr::scene::ISkinnedMesh::SPositionKey& b)
{
return a.position == b.position;
}
bool identicalScale(const irr::scene::ISkinnedMesh::SScaleKey& a, const irr::scene::ISkinnedMesh::SScaleKey& b)
{
return a.scale == b.scale;
}
bool identicalRotation(const irr::scene::ISkinnedMesh::SRotationKey& a, const irr::scene::ISkinnedMesh::SRotationKey& b)
{
return a.rotation == b.rotation;
}
};
namespace irr namespace irr
{ {
namespace scene namespace scene
...@@ -881,10 +955,10 @@ void CSkinnedMesh::checkForAnimation() ...@@ -881,10 +955,10 @@ void CSkinnedMesh::checkForAnimation()
SkinnedLastFrame=false; SkinnedLastFrame=false;
} }
//! called by loader after populating with mesh and bone data //! called by loader after populating with mesh and bone data
void CSkinnedMesh::finalize() void CSkinnedMesh::finalize()
{ {
os::Printer::log("Skinned Mesh - finalize", ELL_DEBUG);
u32 i; u32 i;
// Make sure we recalc the next frame // Make sure we recalc the next frame
...@@ -939,8 +1013,6 @@ void CSkinnedMesh::finalize() ...@@ -939,8 +1013,6 @@ void CSkinnedMesh::finalize()
Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount()); Vertices_Moved[i].set_used(LocalBuffers[i]->getVertexCount());
} }
//Todo: optimise keys here...
checkForAnimation(); checkForAnimation();
if (HasAnimation) if (HasAnimation)
...@@ -952,76 +1024,42 @@ void CSkinnedMesh::finalize() ...@@ -952,76 +1024,42 @@ void CSkinnedMesh::finalize()
core::array<SScaleKey> &ScaleKeys = AllJoints[i]->ScaleKeys; core::array<SScaleKey> &ScaleKeys = AllJoints[i]->ScaleKeys;
core::array<SRotationKey> &RotationKeys = AllJoints[i]->RotationKeys; core::array<SRotationKey> &RotationKeys = AllJoints[i]->RotationKeys;
if (PositionKeys.size()>2) // drop identical middle keys - we only need the first and last frame
irr::u32 dropped = dropMiddleKeys<SPositionKey>(PositionKeys, identicalPos);
if ( dropped > 0 )
{ {
for(u32 j=0;j<PositionKeys.size()-2;++j) os::Printer::log("Skinned Mesh - unneeded position frames kicked:", core::stringc(dropped).c_str(), ELL_DEBUG);
{
if (PositionKeys[j].position == PositionKeys[j+1].position && PositionKeys[j+1].position == PositionKeys[j+2].position)
{
PositionKeys.erase(j+1); //the middle key is unneeded
--j;
}
}
} }
if (PositionKeys.size()>1) // drop frames with bad keys (frames out of order)
dropped = dropBadKeys<SPositionKey>(PositionKeys);
if ( dropped > 0 )
{ {
for(u32 j=0;j<PositionKeys.size()-1;++j) irr::os::Printer::log("Skinned Mesh - bad position frames kicked:", irr::core::stringc(dropped).c_str(), irr::ELL_DEBUG);
{
if (PositionKeys[j].frame >= PositionKeys[j+1].frame) //bad frame, unneed and may cause problems
{
PositionKeys.erase(j+1);
--j;
}
}
} }
if (ScaleKeys.size()>2) dropped = dropMiddleKeys<SScaleKey>(ScaleKeys, identicalScale);
if ( dropped > 0 )
{ {
for(u32 j=0;j<ScaleKeys.size()-2;++j) os::Printer::log("Skinned Mesh - unneeded scale frames kicked:", core::stringc(dropped).c_str(), ELL_DEBUG);
{
if (ScaleKeys[j].scale == ScaleKeys[j+1].scale && ScaleKeys[j+1].scale == ScaleKeys[j+2].scale)
{
ScaleKeys.erase(j+1); //the middle key is unneeded
--j;
}
}
} }
if (ScaleKeys.size()>1) dropped = dropBadKeys<SScaleKey>(ScaleKeys);
if ( dropped > 0 )
{ {
for(u32 j=0;j<ScaleKeys.size()-1;++j) irr::os::Printer::log("Skinned Mesh - bad scale frames kicked:", irr::core::stringc(dropped).c_str(), irr::ELL_DEBUG);
{
if (ScaleKeys[j].frame >= ScaleKeys[j+1].frame) //bad frame, unneed and may cause problems
{
ScaleKeys.erase(j+1);
--j;
}
}
} }
if (RotationKeys.size()>2) dropped = dropMiddleKeys<SRotationKey>(RotationKeys, identicalRotation);
if ( dropped > 0 )
{ {
for(u32 j=0;j<RotationKeys.size()-2;++j) os::Printer::log("Skinned Mesh - unneeded rotation frames kicked:", core::stringc(dropped).c_str(), ELL_DEBUG);
{
if (RotationKeys[j].rotation == RotationKeys[j+1].rotation && RotationKeys[j+1].rotation == RotationKeys[j+2].rotation)
{
RotationKeys.erase(j+1); //the middle key is unneeded
--j;
}
}
} }
if (RotationKeys.size()>1) dropped = dropBadKeys<SRotationKey>(RotationKeys);
if ( dropped > 0 )
{ {
for(u32 j=0;j<RotationKeys.size()-1;++j) irr::os::Printer::log("Skinned Mesh - bad rotation frames kicked:", irr::core::stringc(dropped).c_str(), irr::ELL_DEBUG);
{
if (RotationKeys[j].frame >= RotationKeys[j+1].frame) //bad frame, unneed and may cause problems
{
RotationKeys.erase(j+1);
--j;
}
}
} }
......
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