From 4a14b71a28aacaa302dfcd66eeb5e83d2f1de7de Mon Sep 17 00:00:00 2001 From: Tazpn <tazpn@users.sourceforge.net> Date: Sun, 13 Aug 2006 20:42:07 +0000 Subject: [PATCH] 1. Update bounding sphere info. on skin so not unknown anymore 2. Put back changes that Shon rolled back to so that exporter compiles again 3. Put in new typesafe helper for creating nodes so we dont have to rely on strings. --- gen/SkinData.cpp | 2 +- gen/SkinData.h | 12 ++++-- gen/obj_impl.cpp | 19 +++----- niflib.h | 21 +++++++++ obj/NiAVObject.cpp | 18 ++++++++ obj/NiAVObject.h | 7 +++ obj/NiSkinData.cpp | 8 ++-- obj/NiSkinData.h | 2 +- obj/NiSkinInstance.cpp | 2 +- obj/NiTriBasedGeom.cpp | 98 ++++++++++++++++++++++++++---------------- 10 files changed, 128 insertions(+), 61 deletions(-) diff --git a/gen/SkinData.cpp b/gen/SkinData.cpp index 540d1b34..07ca9a47 100644 --- a/gen/SkinData.cpp +++ b/gen/SkinData.cpp @@ -6,7 +6,7 @@ All rights reserved. Please see niflib.h for licence. */ using namespace Niflib; //Constructor -SkinData::SkinData() : scale(0.0f), numVertices((ushort)0) {}; +SkinData::SkinData() : scale(0.0f), boundingSphereRadius(0.0f), numVertices((ushort)0) {}; //Destructor SkinData::~SkinData() {}; diff --git a/gen/SkinData.h b/gen/SkinData.h index f33f32b2..bf55b03b 100644 --- a/gen/SkinData.h +++ b/gen/SkinData.h @@ -33,11 +33,15 @@ struct NIFLIB_API SkinData { */ float scale; /*! - * This has been verified not to be a normalized quaternion. They may or - * may not be related to each other so their specification as an array of - * 4 floats may be misleading. + * Translation offset of a bounding sphere holding all vertices. (Note + * that its a Sphere Containing Axis Aligned Box not a minimum volume + * Sphere) */ - array<float,4> unknown4Floats; + Vector3 boundingSphereOffset; + /*! + * Radius for bounding sphere holding all vertices. + */ + float boundingSphereRadius; /*! * Number of weighted vertices. */ diff --git a/gen/obj_impl.cpp b/gen/obj_impl.cpp index a6d907e3..cd507bb0 100644 --- a/gen/obj_impl.cpp +++ b/gen/obj_impl.cpp @@ -10442,9 +10442,8 @@ void NiSkinData::InternalRead( istream& in, list<uint> & link_stack, unsigned in NifStream( boneList[i1].rotation, in, version ); NifStream( boneList[i1].translation, in, version ); NifStream( boneList[i1].scale, in, version ); - for (uint i2 = 0; i2 < 4; i2++) { - NifStream( boneList[i1].unknown4Floats[i2], in, version ); - }; + NifStream( boneList[i1].boundingSphereOffset, in, version ); + NifStream( boneList[i1].boundingSphereRadius, in, version ); NifStream( boneList[i1].numVertices, in, version ); boneList[i1].vertexWeights.resize(boneList[i1].numVertices); for (uint i2 = 0; i2 < boneList[i1].vertexWeights.size(); i2++) { @@ -10475,9 +10474,8 @@ void NiSkinData::InternalWrite( ostream& out, map<NiObjectRef,uint> link_map, un NifStream( boneList[i1].rotation, out, version ); NifStream( boneList[i1].translation, out, version ); NifStream( boneList[i1].scale, out, version ); - for (uint i2 = 0; i2 < 4; i2++) { - NifStream( boneList[i1].unknown4Floats[i2], out, version ); - }; + NifStream( boneList[i1].boundingSphereOffset, out, version ); + NifStream( boneList[i1].boundingSphereRadius, out, version ); NifStream( boneList[i1].numVertices, out, version ); for (uint i2 = 0; i2 < boneList[i1].vertexWeights.size(); i2++) { NifStream( boneList[i1].vertexWeights[i2].index, out, version ); @@ -10501,13 +10499,8 @@ std::string NiSkinData::InternalAsString( bool verbose ) const { out << " Rotation: " << boneList[i1].rotation << endl; out << " Translation: " << boneList[i1].translation << endl; out << " Scale: " << boneList[i1].scale << endl; - for (uint i2 = 0; i2 < 4; i2++) { - if ( !verbose && ( i2 > MAXARRAYDUMP ) ) { - out << "<Data Truncated. Use verbose mode to see complete listing.>" << endl; - break; - }; - out << " Unknown 4 Floats[" << i2 << "]: " << boneList[i1].unknown4Floats[i2] << endl; - }; + out << " Bounding Sphere Offset: " << boneList[i1].boundingSphereOffset << endl; + out << " Bounding Sphere Radius: " << boneList[i1].boundingSphereRadius << endl; out << " Num Vertices: " << boneList[i1].numVertices << endl; for (uint i2 = 0; i2 < boneList[i1].vertexWeights.size(); i2++) { out << " Index: " << boneList[i1].vertexWeights[i2].index << endl; diff --git a/niflib.h b/niflib.h index 3fca3a49..79784c85 100644 --- a/niflib.h +++ b/niflib.h @@ -264,6 +264,27 @@ NIFLIB_API void SendNifTreeToBindPos( const Ref<NiNode> & root ); */ NIFLIB_API Ref<NiObject> CreateBlock( string block_type ); + +/*! +* Creates a new block of the given type and returns a reference to it +* \param T – The type of block you want to create. Ex. NiNode, NiTriShapeData, NiParticleSystemController, etc. +* \return This function will return a newly created block of the requested type. +* +* <b>Example:</b> +* \code +* NiNodeRef my_block = CreateNiObject<NiNode>(); +* \endcode +* +* sa BlocksInMemory +*/ +#ifndef SWIG +template<typename T> +inline Ref<T> CreateNiObject() { + return DynamicCast<T>(CreateBlock(T::TypeConst().GetTypeName())); +} +#endif + + /*! * Returns whether the requested version is supported. * \param version The version of the nif format to test for availablity. diff --git a/obj/NiAVObject.cpp b/obj/NiAVObject.cpp index 409e7002..c7d47443 100644 --- a/obj/NiAVObject.cpp +++ b/obj/NiAVObject.cpp @@ -168,6 +168,24 @@ bool NiAVObject::GetHidden() return (bool)NIFLIB_GET_FLAG(flags, 0, 0x01); } +Ref<NiCollisionData > NiAVObject::GetCollisionData() const { + return collisionData; +} + +void NiAVObject::SetCollisionData( Ref<NiCollisionData > value ) { + collisionData = value; +} + + +ef<NiCollisionObject > NiAVObject::GetCollisionObject() const { + + return collisionObject; +} + +void NiAVObject::SetCollisionObject( Ref<NiCollisionObject > value ) { + collisionObject = value; +} + void NiAVObject::SetHidden(bool value) { flags = NIFLIB_MASK_FLAG(flags, value, 0, 0x01); diff --git a/obj/NiAVObject.h b/obj/NiAVObject.h index 55e37a30..159311d7 100644 --- a/obj/NiAVObject.h +++ b/obj/NiAVObject.h @@ -102,6 +102,12 @@ public: Ref<NiCollisionObject > GetCollisionObject() const; void SetCollisionObject( Ref<NiCollisionObject> value ); + /*! + * Bounding box: refers to NiCollisionData + */ + Ref<NiCollisionData > GetCollisionData() const; + void SetCollisionData( Ref<NiCollisionData> value ); + bool GetHidden(); void SetHidden(bool value); @@ -113,6 +119,7 @@ public: CollisionType GetCollision(); void SetCollsion(CollisionType value); + protected: NiNode * parent; NI_A_V_OBJECT_MEMBERS diff --git a/obj/NiSkinData.cpp b/obj/NiSkinData.cpp index 0bf29e75..877b4fc2 100644 --- a/obj/NiSkinData.cpp +++ b/obj/NiSkinData.cpp @@ -67,10 +67,8 @@ void NiSkinData::SetBoneWeights( uint bone_index, const vector<SkinWeight> & n, } boneList[bone_index].vertexWeights = n; - boneList[bone_index].unknown4Floats[0] = center.x; - boneList[bone_index].unknown4Floats[1] = center.y; - boneList[bone_index].unknown4Floats[2] = center.z; - boneList[bone_index].unknown4Floats[3] = radius; + boneList[bone_index].boundingSphereOffset = center; + boneList[bone_index].boundingSphereRadius = radius; } Matrix44 NiSkinData::GetOverallTransform() const { @@ -121,4 +119,4 @@ NiSkinData::NiSkinData( const Ref<NiTriBasedGeom> & owner ) { //Store result res_mat.Decompose( boneList[i].translation, boneList[i].rotation, boneList[i].scale ); } -} \ No newline at end of file +} diff --git a/obj/NiSkinData.h b/obj/NiSkinData.h index 9d7cc5ff..101ead61 100644 --- a/obj/NiSkinData.h +++ b/obj/NiSkinData.h @@ -51,7 +51,7 @@ public: uint GetBoneCount() const; Matrix44 GetBoneTransform( uint bone_index ) const; vector<SkinWeight> GetBoneWeights( uint bone_index ) const; - void SetBoneWeights( uint bone_index, const vector<SkinWeight> & n, Vector3 center, float radius ); + void SetBoneWeights( uint bone_index, const vector<SkinWeight> & n, Vector3 center, float radius ); protected: NI_SKIN_DATA_MEMBERS diff --git a/obj/NiSkinInstance.cpp b/obj/NiSkinInstance.cpp index 8b8f8857..62a326cf 100644 --- a/obj/NiSkinInstance.cpp +++ b/obj/NiSkinInstance.cpp @@ -126,4 +126,4 @@ uint NiSkinInstance::GetBoneCount() const { Ref<NiNode> NiSkinInstance::GetSkeletonRoot() const { return skeletonRoot; -} \ No newline at end of file +} diff --git a/obj/NiTriBasedGeom.cpp b/obj/NiTriBasedGeom.cpp index 6274fc4c..a5b75d1b 100644 --- a/obj/NiTriBasedGeom.cpp +++ b/obj/NiTriBasedGeom.cpp @@ -261,6 +261,65 @@ vector<Vector3> NiTriBasedGeom::GetSkinInfluencedVertices() const { return skin_verts; } +// Calculate bounding sphere using minimum-volume axis-align bounding box. Its fast but not a very good fit. +static void CalcAxisAlignedBox(const vector<SkinWeight> & n, const vector<Vector3>& vertices, Vector3& center, float& radius) +{ + //--Calculate center & radius--// + + //Set lows and highs to first vertex + Vector3 lows = vertices[ n[0].index ]; + Vector3 highs = vertices[ n[0].index ]; + + //Iterate through the vertices, adjusting the stored values + //if a vertex with lower or higher values is found + for ( unsigned int i = 0; i < n.size(); ++i ) { + const Vector3 & v = vertices[ n[i].index ]; + + if ( v.x > highs.x ) highs.x = v.x; + else if ( v.x < lows.x ) lows.x = v.x; + + if ( v.y > highs.y ) highs.y = v.y; + else if ( v.y < lows.y ) lows.y = v.y; + + if ( v.z > highs.z ) highs.z = v.z; + else if ( v.z < lows.z ) lows.z = v.z; + } + + //Now we know the extent of the shape, so the center will be the average + //of the lows and highs + center = (highs + lows) / 2.0f; + + //The radius will be the largest distance from the center + Vector3 diff; + float dist2(0.0f), maxdist2(0.0f); + for ( unsigned int i = 0; i < n.size(); ++i ) { + const Vector3 & v = vertices[ n[i].index ]; + + diff = center - v; + dist2 = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z; + if ( dist2 > maxdist2 ) maxdist2 = dist2; + }; + radius = sqrt(maxdist2); +} + +// Calculate bounding sphere using average position of the points. Better fit but slower. +static void CalcCenteredSphere(const vector<SkinWeight> & n, const vector<Vector3>& vertices, Vector3& center, float& radius) +{ + size_t nv = n.size(); + Vector3 sum; + for (size_t i=0; i<nv; ++i) + sum += vertices[ n[i].index ]; + center = sum / float(nv); + radius = 0.0f; + for (size_t i=0; i<nv; ++i){ + Vector3 diff = vertices[ n[i].index ] - center; + float mag = diff.Magnitude(); + radius = max(radius, mag); + } +} + + + void NiTriBasedGeom::SetBoneWeights( uint bone_index, const vector<SkinWeight> & n ) { if ( n.size() == 0 ) { @@ -288,42 +347,9 @@ void NiTriBasedGeom::SetBoneWeights( uint bone_index, const vector<SkinWeight> & //Get vertex array vector<Vector3> vertices = geomData->GetVertices(); - //--Calculate center & radius--// - - //Set lows and highs to first vertex - Vector3 lows = vertices[ n[0].index ]; - Vector3 highs = vertices[ n[0].index ]; - - //Iterate through the vertices, adjusting the stored values - //if a vertex with lower or higher values is found - for ( unsigned int i = 0; i < n.size(); ++i ) { - const Vector3 & v = vertices[ n[i].index ]; - - if ( v.x > highs.x ) highs.x = v.x; - else if ( v.x < lows.x ) lows.x = v.x; - - if ( v.y > highs.y ) highs.y = v.y; - else if ( v.y < lows.y ) lows.y = v.y; - - if ( v.z > highs.z ) highs.z = v.z; - else if ( v.z < lows.z ) lows.z = v.z; - } - - //Now we know the extent of the shape, so the center will be the average - //of the lows and highs - Vector3 center = highs + lows / 2.0f; - - //The radius will be the largest distance from the center - Vector3 diff; - float dist2(0.0f), maxdist2(0.0f); - for ( unsigned int i = 0; i < n.size(); ++i ) { - const Vector3 & v = vertices[ n[i].index ]; - - diff = center - v; - dist2 = diff.x * diff.x + diff.y * diff.y + diff.z * diff.z; - if ( dist2 > maxdist2 ) maxdist2 = dist2; - }; - float radius = sqrt(maxdist2); + Vector3 center; float radius; + //CalcCenteredSphere(n, vertices, center, radius); + CalcAxisAlignedBox(n, vertices, center, radius); //Translate center by bone matrix center = skinData->GetBoneTransform( bone_index ) * center; -- GitLab