From 48f34b7b05f992e51a62266cb02b7529c20de7fe Mon Sep 17 00:00:00 2001 From: Shon Ferguson <shonferg@users.sourceforge.net> Date: Mon, 17 Jul 2006 04:22:14 +0000 Subject: [PATCH] Created a new ComplexShape class which can currently be used to automatically split the sort of complicated mesh that contains per-point-per-face attributes into NiTriShape classes. Should support skinning as well, but has not been tested. Added TexCoord == operator. Changed type of Triangle members to unsigned short. Color4 now defaults to all zeros. NiAVObject::AddProperty now takes a const argument. Fixed exception in NiTexturingProperty to throw a runtime_error instead of a string. NiTriBasedGeom::BindSkin should now automatically finds the skeleton root by itself. The skeleton_root argument has been removed. --- ComplexShape.cpp | 458 ++++++++++++++++++++++++++++++++++++ ComplexShape.h | 88 +++++++ nif_math.cpp | 9 + nif_math.h | 18 +- niflib.h | 125 ---------- niflib.vcproj | 8 + obj/NiAVObject.cpp | 2 +- obj/NiAVObject.h | 2 +- obj/NiTexturingProperty.cpp | 2 +- obj/NiTriBasedGeom.cpp | 53 ++++- obj/NiTriBasedGeom.h | 5 +- 11 files changed, 632 insertions(+), 138 deletions(-) create mode 100644 ComplexShape.cpp create mode 100644 ComplexShape.h diff --git a/ComplexShape.cpp b/ComplexShape.cpp new file mode 100644 index 00000000..fe2220df --- /dev/null +++ b/ComplexShape.cpp @@ -0,0 +1,458 @@ +/* Copyright (c) 2006, NIF File Format Library and Tools +All rights reserved. Please see niflib.h for licence. */ + +#include "ComplexShape.h" +#include "obj/NiNode.h" +#include "obj/NiProperty.h" +#include "obj/NiAVObject.h" +#include "obj/NiTriShape.h" +#include "obj/NiTriShapeData.h" +#include "obj/NiTexturingProperty.h" +#include "obj/NiSkinInstance.h" +#include "obj/NiSkinData.h" +#include "gen/SkinWeight.h" +#include <stdlib.h> + +using namespace Niflib; + +struct CompoundVertex { + Vector3 position; + Vector3 normal; + Color4 color; + map<TexType, TexCoord> texCoords; + map<NiNodeRef, float> weights; + + CompoundVertex() {} + ~CompoundVertex() {} + CompoundVertex( const CompoundVertex & n ) { + *this = n; + } + CompoundVertex & operator=( const CompoundVertex & n ) { + position = n.position; + normal = n.normal; + color = n.color; + texCoords = n.texCoords; + weights = n.weights; + return *this; + } + bool operator==( const CompoundVertex & n ) { + if ( position != n.position ) { + return false; + } + if ( normal != n.normal ) { + return false; + } + if ( color.r != n.color.r && color.g != n.color.g && color.b != n.color.b && color.a != n.color.a ) { + return false; + } + if ( texCoords != n.texCoords ) { + return false; + } + if ( weights != n.weights ) { + return false; + } + + return true; + } +}; + +void ComplexShape::SetName( const string & n ) { + name = n; +} + +void ComplexShape::SetVertices( const vector<WeightedVertex> & n ) { + vertices = n; +} + +void ComplexShape::SetColors( const vector<Color4> & n ) { + colors = n; +} + +void ComplexShape::SetNormals( const vector<Vector3> & n ) { + normals = n; +} + +void ComplexShape::SetTexCoordSets( const vector<TexCoordSet> & n ) { + texCoordSets = n; +} + +void ComplexShape::SetFaces( const vector< ComplexFace > & n ) { + faces = n; +} + +void ComplexShape::SetPropGroups( const vector< vector< Ref<NiProperty> > > & n ) { + propGroups = n; +} + +void ComplexShape::SetSkinInfluences( const vector< Ref<NiNode> > & n ) { + skinInfluences = n; +} + + +string ComplexShape::GetName() const { + return name; +} + +vector<ComplexShape::WeightedVertex> ComplexShape::GetVertices() const { + return vertices; +} + +vector<Color4> ComplexShape::GetColors() const { + return colors; +} + +vector<Vector3> ComplexShape::GetNormals() const { + return normals; +} + +vector<ComplexShape::TexCoordSet> ComplexShape::GetTexCoordSets() const { + return texCoordSets; +} + +vector< ComplexShape::ComplexFace > ComplexShape::GetFaces() const { + return faces; +} + +vector< vector< Ref<NiProperty > > > ComplexShape::GetPropGroups() const { + return propGroups; +} + +vector< Ref<NiNode> > ComplexShape::GetSkinInfluences() const { + return skinInfluences; +} + +//void ComplexShape::CombineTriShapes( list<blk_ref> & tri_shapes ) { +// //Clear all internal datea +// _vertices.clear(); +// _colors.clear(); +// _normals.clear(); +// _materials.clear(); +// _uvs.clear(); +// _faces.clear(); +// _bones.clear(); +// +// //Create a temporary spot to hold the triangle lists from each TriShape +// vector< vector<Triangle> > ts_faces; +// +// //Create lists to hold the lookup tables +// vector<int> tri_lookup, nor_lookup, col_lookup; +// map<string, vector<int> > mat_lookup, uv_lookup; +// +// //--Cycle through all the TriShapes, adding their data to the lists--// +// list<blk_ref>::iterator it; +// +// for (it = tri_shapes.begin(); it != tri_shapes.end(); ++it) { +// ITriShapeData * data = QueryTriShapeData(*it); +// +// //Vertices +// vector<Vector3> ts_verts = data->GetVertices(); +// _vertices.insert(_vertices.end(), ts_verts.begin(), ts_verts.end(); +// +// //Normals +// vector<Vector3> ts_norms = data->GetNormals(); +// _normals.insert(_normals.end(), ts_norms.begin(), ts_norms.end(); +// +// //Colors +// vector<Colors> ts_cols = data->GetColors(); +// _colors.insert(_colors.end(), ts_colors.begin(), ts_colors.end(); +// +// //Triangles +// ts_faces[i] = data->GetTriangles(); +// +// //UV Coords +// vector< vector<TexCoords> > uvs(data->GetUVSetCount()); +// for (int i = 0; i < data->GetUVSetCount(); ++i) { +// uvs[i] = data->GetUVSet(i); +// } +// +// //Associate UV Coord Data with proper map name +// blk_ref tx_prop = par["Properties"]->FindLink( "NiTexturingProperty"); +// if ( tx_prop.is_null() == false ) { +// int uv_set = 0; +// for (int i = 0; i < 7; ++i) { +// string attr_name, map; +// switch(i) { +// case 0: attr_name = "Base Texture"; map = "map1"; break; +// case 1: attr_name = "Dark Texture"; map = "dark"; break; +// case 2: attr_name = "Detail Texture"; map = "detail"; break; +// case 3: attr_name = "Gloss Texture"; map = "gloss"; break; +// case 4: attr_name = "Glow Texture"; map = "glow"; break; +// case 5: attr_name = "Bump Map Texture"; map = "bump"; break; +// case 6: attr_name = "Decal 0 Texture"; map = "decal0"; +// } +// +// if ( tx_prop[attr_name]->asTexDesc().isUsed == true ) { +// //How to merge all UVs? +// } +// +// } +// +// +// //blk_ref material = (*it)->GetAttr("Propreties")->FindLink("NiMaterialProperty"); +// //blk_ref skin_inst = (*it)->GetAttr("Skin Instance")->asLink(); +// //blk_ref skin_data; +// //vector<blk_ref> bones; +// //map<int, float> weights; +// //if ( skin_inst.is_null() == false ) { +// // skin_block = skin_inst->GetAttr("Data"); +// // if (skin_block.is_null() == false ) { +// // ISkinData * skin_data = QuerySkinData(skin_block); +// // weights = skin_data->GetWeights(); +// // bones = skin_data->GetBones(); +// // } +// //} +// +// } +//} + +Ref<NiAVObject> ComplexShape::Split( Ref<NiNode> & parent ) const { + + //Make sure parent is not NULL + if ( parent == NULL ) { + throw runtime_error ("A parent is necessary to split a complex shape."); + } + + //There will be one NiTriShape per property group + //with a minimum of 1 + unsigned int num_shapes = unsigned int(propGroups.size()); + if ( num_shapes == 0 ) { + num_shapes = 1; + } + + vector<NiTriShapeRef> shapes(num_shapes); + + //Loop through each shape slot and create a NiTriShape + for ( unsigned int shape_num = 0; shape_num < shapes.size(); ++shape_num ) { + shapes[shape_num] = new NiTriShape; + } + + NiAVObjectRef root; + + //If there is just one shape, return it. Otherwise + //create a node, parent all shapes to it, and return + // that + if ( shapes.size() == 1 ) { + //One shape + shapes[0]->SetName(name); + root = StaticCast<NiAVObject>(shapes[0]); + } else { + //Multiple shapes + NiNodeRef niNode = new NiNode; + niNode->SetName(name); + for ( unsigned int i = 0; i < shapes.size(); ++i ) { + niNode->AddChild( StaticCast<NiAVObject>(shapes[i]) ); + + //Set Shape Name + stringstream shapeName; + shapeName << name << " " << i; + shapes[i]->SetName( shapeName.str() ); + } + root = StaticCast<NiAVObject>(niNode); + } + + parent->AddChild( root ); + + //Create NiTriShapeData and fill it out with all data that is relevant + //to this shape based on the material. + for ( unsigned int shape_num = 0; shape_num < shapes.size(); ++shape_num ) { + + NiTriShapeDataRef niData = new NiTriShapeData; + shapes[shape_num]->SetData( StaticCast<NiTriBasedGeomData>(niData) ); + + //Create a list of CompoundVertex to make it easier to + //test for the need to clone a vertex + vector<CompoundVertex> compVerts; + + //List of triangles for the final shape to use + vector<Triangle> shapeTriangles; + + //Loop through all faces, and all points on each face + //to set the vertices in the CompoundVertex list + for ( vector<ComplexFace>::const_iterator face = faces.begin(); face != faces.end(); ++face ) { + //Ignore faces with less than 3 vertices + if ( face->points.size() < 3 ) { + continue; + } + + //Skip this face if the material does not relate to this shape + if ( face->propGroupIndex != shape_num ) { + continue; + } + + vector<unsigned short> shapeFacePoints; + for ( vector<ComplexPoint>::const_iterator point = face->points.begin(); point != face->points.end(); ++point ) { + + //--Set up Compound vertex--// + CompoundVertex cv; + + if ( vertices.size() > 0 ) { + const WeightedVertex & wv = vertices[point->vertexIndex]; + cv.position = wv.position; + + if ( skinInfluences.size() > 0 ) { + for ( unsigned int i = 0; i < wv.weights.size(); ++i ) { + const SkinInfluence & inf = wv.weights[i]; + + cv.weights[ skinInfluences[inf.influenceIndex] ] = inf.weight; + } + } + } + + if ( normals.size() > 0 ) { + cv.normal = normals[point->normalIndex]; + } + if ( colors.size() > 0 ) { + cv.color = colors[point->colorIndex]; + } + + if ( texCoordSets.size() > 0 ) { + for ( unsigned int i = 0; i < point->texCoordIndices.size(); ++i ) { + const TexCoordSet & set = texCoordSets[ point->texCoordIndices[i].texCoordSetIndex ]; + + cv.texCoords[ set.texType ] = set.texCoords[ point->texCoordIndices[i].texCoordIndex ]; + } + } + + bool found_match = false; + //Search for an identical vertex in the list + for ( unsigned short cv_index = 0; cv_index < compVerts.size(); ++cv_index ) { + if ( compVerts[cv_index] == cv ) { + //We found a match, push its index into the face list + found_match = true; + shapeFacePoints.push_back(cv_index); + break; + } + } + + //If no match was found, append this vertex to the list + if ( found_match == false ) { + compVerts.push_back(cv); + //put the new vertex into the face point list + shapeFacePoints.push_back( unsigned int(compVerts.size()) - 1 ); + } + + //Next Point + } + + //Starting from vertex 0, create a fan of triangles to fill + //in non-triangle polygons + Triangle new_face; + for ( unsigned int i = 0; i < shapeFacePoints.size() - 2; ++i ) { + new_face[0] = shapeFacePoints[0]; + new_face[1] = shapeFacePoints[i+1]; + new_face[2] = shapeFacePoints[i+2]; + + //Push the face into the face list + shapeTriangles.push_back(new_face); + } + + //Next Face + } + + //Attatch properties if any + if ( propGroups.size() > 0 ) { + for ( vector<NiPropertyRef>::const_iterator prop = propGroups[shape_num].begin(); prop != propGroups[shape_num].end(); ++prop ) { + shapes[shape_num]->AddProperty( *prop ); + } + } + + //--Set Shape Data--// + + //lists to hold data + vector<Vector3> shapeVerts( compVerts.size() ); + vector<Vector3> shapeNorms( compVerts.size() ); + vector<Color4> shapeColors( compVerts.size() ); + vector< vector<TexCoord> > shapeTCs; + list<int> shapeTexCoordSets; + map<NiNodeRef, vector<SkinWeight> > shapeWeights; + + //Search for a NiTexturingProperty to build list of + //texture cooridinate sets to create + NiPropertyRef niProp = shapes[shape_num]->GetPropertyByType( NiTexturingProperty::TypeConst() ); + NiTexturingPropertyRef niTexProp; + if ( niProp != NULL ) { + niTexProp = DynamicCast<NiTexturingProperty>(niProp); + } + if ( niTexProp != NULL ) { + for ( int tex_num = 0; tex_num < 8; ++tex_num ) { + if (niTexProp->HasTexture(tex_num)) { + shapeTexCoordSets.push_back(tex_num); + } + } + } else { + //Always include the base map if it's there, whether there's a + //texture or not + shapeTexCoordSets.push_back( BASE_MAP ); + } + shapeTCs.resize( shapeTexCoordSets.size() ); + for ( vector< vector<TexCoord> >::iterator set = shapeTCs.begin(); set != shapeTCs.end(); ++set ) { + set->resize( compVerts.size() ); + } + + //Loop through all compound vertices, adding the data + //to the correct arrays. + uint vert_index = 0; + for ( vector<CompoundVertex>::iterator cv = compVerts.begin(); cv != compVerts.end(); ++cv ) { + shapeVerts[vert_index] = cv->position; + shapeColors[vert_index] = cv->color; + shapeNorms[vert_index] = cv->normal; + shapeNorms[vert_index] = cv->normal; + uint tex_index = 0; + for ( list<int>::iterator tex = shapeTexCoordSets.begin(); tex != shapeTexCoordSets.end(); ++tex ) { + if ( cv->texCoords.find( TexType(*tex) ) != cv->texCoords.end() ) { + shapeTCs[tex_index][vert_index] = cv->texCoords[ TexType(*tex) ]; + } + tex_index++; + } + SkinWeight sk; + for ( map<NiNodeRef, float>::iterator wt = cv->weights.begin(); wt != cv->weights.end(); ++wt ) { + //Only record influences that make a noticable contribution + if ( wt->second > 0.001f ) { + sk.index = vert_index; + sk.weight = wt->second; + shapeWeights[wt->first].push_back( sk ); + } + } + + ++vert_index; + } + + //Finally, set the data into the NiTriShapeData + if ( vertices.size() > 0 ) { + niData->SetVertices( shapeVerts ); + niData->SetTriangles( shapeTriangles ); + } + if ( normals.size() > 0 ) { + niData->SetNormals( shapeNorms ); + } + if ( colors.size() > 0 ) { + niData->SetVertexColors( shapeColors ); + } + if ( texCoordSets.size() > 0 ) { + niData->SetUVSetCount( int(shapeTCs.size()) ); + for ( unsigned int tex_index = 0; tex_index < shapeTCs.size(); ++tex_index ) { + niData->SetUVSet( tex_index, shapeTCs[tex_index] ); + } + } + + //If there are any skin influences, bind the skin + if ( shapeWeights.size() > 0 ) { + vector<NiNodeRef> shapeInfluences; + for ( map<NiNodeRef, vector<SkinWeight> >::iterator inf = shapeWeights.begin(); inf != shapeWeights.end(); ++inf ) { + shapeInfluences.push_back( inf->first ); + } + + shapes[shape_num]->BindSkin( shapeInfluences ); + + NiSkinDataRef skinData = shapes[shape_num]->GetSkinInstance()->GetSkinData(); + + for ( unsigned int inf = 0; inf < shapeInfluences.size(); ++inf ) { + skinData->SetBoneWeights( inf, shapeWeights[ shapeInfluences[inf] ] ); + } + } + + //Next Shape + } + + return root; +} \ No newline at end of file diff --git a/ComplexShape.h b/ComplexShape.h new file mode 100644 index 00000000..83dec729 --- /dev/null +++ b/ComplexShape.h @@ -0,0 +1,88 @@ +/* Copyright (c) 2006, NIF File Format Library and Tools +All rights reserved. Please see niflib.h for licence. */ + +#ifndef _COMPLEX_SHAPE_H_ +#define _COMPLEX_SHAPE_H_ + +#include "Ref.h" +#include "nif_math.h" +#include "nif_basic_types.h" + +namespace Niflib { + +// Forward define of referenced classes +class NiProperty; +class NiNode; +class NiAVObject; + +class ComplexShape { +public: + + struct SkinInfluence { + unsigned int influenceIndex; + float weight; + }; + + struct WeightedVertex { + Vector3 position; + vector<SkinInfluence> weights; + }; + + struct TexCoordIndex { + unsigned int texCoordSetIndex; + unsigned int texCoordIndex; + }; + + struct ComplexPoint { + unsigned int vertexIndex; + unsigned int normalIndex; + unsigned int colorIndex; + vector<TexCoordIndex> texCoordIndices; + }; + + struct ComplexFace { + vector<ComplexPoint> points; + unsigned int propGroupIndex; + }; + + struct TexCoordSet { + TexType texType; + vector<TexCoord> texCoords; + }; + + Ref<NiAVObject> Split( Ref<NiNode> & parent ) const; + + //Setters + void SetName( const string & n ); + void SetVertices( const vector<WeightedVertex> & n ); + void SetColors( const vector<Color4> & n ); + void SetNormals( const vector<Vector3> & n ); + void SetTexCoordSets( const vector<TexCoordSet> & n ); + void SetFaces( const vector<ComplexFace> & n ); + void SetPropGroups( const vector< vector< Ref<NiProperty> > > & n ); + void SetSkinInfluences( const vector< Ref<NiNode> > & n ); + + //Getters + string GetName() const; + vector<WeightedVertex> GetVertices() const; + vector<Color4> GetColors() const; + vector<Vector3> GetNormals() const; + vector<TexCoordSet> GetTexCoordSets() const; + vector<ComplexFace> GetFaces() const; + vector< vector< Ref<NiProperty> > > GetPropGroups() const; + vector< Ref<NiNode> > GetSkinInfluences() const; + +private: + vector<WeightedVertex> vertices; + vector<Color4> colors; + vector<Vector3> normals; + vector<TexCoordSet> texCoordSets; + vector<ComplexFace> faces; + vector< vector< Ref<NiProperty> > > propGroups; + vector< Ref<NiNode> > skinInfluences; + string name; +}; + +} + +#endif \ No newline at end of file diff --git a/nif_math.cpp b/nif_math.cpp index a6c3d6bd..19c59a7c 100644 --- a/nif_math.cpp +++ b/nif_math.cpp @@ -19,6 +19,15 @@ const Matrix33 Matrix33::IDENTITY( 1.0f, 0.0f, 0.0f, const Matrix22 Matrix22::IDENTITY( 1.0f, 0.0f, 0.0f, 1.0f ); +/* TexCoord Methods + * + */ + +bool TexCoord::operator==( const TexCoord & n ) const { + return ( u == n.u && v == n.v ); +} + + /* * Vector3 Methods */ diff --git a/nif_math.h b/nif_math.h index 413a82e0..7e3d21e7 100644 --- a/nif_math.h +++ b/nif_math.h @@ -55,13 +55,15 @@ struct NIFLIB_API TexCoord { this->u = u; this->v = v; } + + bool operator==( const TexCoord & n ) const; }; /*! Represents a triangle face formed between three vertices referenced by number */ struct NIFLIB_API Triangle { - short v1; /*!< The index of the first vertex. */ - short v2; /*!< The index of the second vertex. */ - short v3; /*!< The index of the third vertex. */ + unsigned short v1; /*!< The index of the first vertex. */ + unsigned short v2; /*!< The index of the second vertex. */ + unsigned short v3; /*!< The index of the third vertex. */ /*! Default constructor */ Triangle() {} @@ -71,7 +73,7 @@ struct NIFLIB_API Triangle { * \param v2 The index of the second vertex. * \param v3 The index of the third vertex. */ - Triangle(short v1, short v2, short v3) { + Triangle(unsigned short v1, unsigned short v2, unsigned short v3) { this->v1 = v1; this->v2 = v2; this->v3 = v3; @@ -82,7 +84,7 @@ struct NIFLIB_API Triangle { * \param v2 The index of the second vertex. * \param v3 The index of the third vertex. */ - void Set(short v1, short v2, short v3) { + void Set(unsigned short v1, unsigned short v2, unsigned short v3) { this->v1 = v1; this->v2 = v2; this->v3 = v3; @@ -94,7 +96,7 @@ struct NIFLIB_API Triangle { * \param n The index into the data array. Should be 0, 1, or 2. * \return The value at the given array index by reference so it can be read or set via the bracket operator. */ - short & operator[](int n) { + unsigned short & operator[](int n) { switch (n) { case 0: return v1; break; case 1: return v2; break; @@ -102,7 +104,7 @@ struct NIFLIB_API Triangle { default: throw std::out_of_range("Index out of range for Triangle"); }; } - short operator[](int n) const { + unsigned short operator[](int n) const { switch (n) { case 0: return v1; break; case 1: return v2; break; @@ -827,7 +829,7 @@ struct NIFLIB_API Color4 { float a; /*!< The alpha translucency component of this color. Should be between 0.0f and 1.0f. */ /*! Default constructor */ - Color4() {} + Color4() : r(0.0f), g(0.0f), b(0.0f), a(0.0f) {} /*! This constructor can be used to set all values in this structure during initialization * \param r The value to set the red component of this color to. Should be between 0.0f and 1.0f. diff --git a/niflib.h b/niflib.h index 083e1409..f39e2f64 100644 --- a/niflib.h +++ b/niflib.h @@ -270,131 +270,6 @@ NIFLIB_API bool IsVersionSupported(unsigned int ver); */ NIFLIB_API unsigned int GetVersion(string version); -//TODO: This is planned functionality but is unfinished -//struct ComplexVertex { -// ComplexVertex() : has_color(false), has_normal(false), vertex_index(0), normal_index(0), color_index(0) {} -// ~ComplexVertex(); -// bool has_color, has_normal; -// int vertex_index, color_index, normal_index; -// bool has_base_uv, has_glow_uv; -// int base_uv_index, glow_uv_index; -//} -// -//struct ComplexFace { -// vector<ComplexVertex> points; -// int base_map_index; -// int glow_map_index; -//}; -// -//class ComplexShape { -// void SetVertices( vector<Vector3> & vertices ); -// void SetUVs( vector<TexCoord> & uvs ); -// void SetColors( vector<Color4> & colors ); -// void SetNormals( vector<Vector3> & normals ); -// void SetBones( vector<blk_ref> & bones ); -// void SetFaces( list< vector< ComplexVertex > > & faces ); -// -// vector<Vector3> GetVertices(); -// vector<TexCoord> GetUVs(); -// vector<Color4> GetColors(); -// vector<Vector3> GetNormals(); -// vector<blk_ref> GetBones(); -// list< vector< ComplexVertex > > GetFaces(); -// -//private: -// vector<Vector3> _vertices; -// vector<Color4> _colors; -// vector<Vector3> _normals; -// list<ComplexFace> _faces; -// map<string, blk_ref> _materials; -// map<string, vector<TexCoord> > _uvs; -// map<blk_ref, map<int, float> > _bones; -//}; -// -//void ComplexShape::CombineTriShapes( list<blk_ref> & tri_shapes ) { -// //Clear all internal datea -// _vertices.clear(); -// _colors.clear(); -// _normals.clear(); -// _materials.clear(); -// _uvs.clear(); -// _faces.clear(); -// _bones.clear(); -// -// //Create a temporary spot to hold the triangle lists from each TriShape -// vector< vector<Triangle> > ts_faces; -// -// //Create lists to hold the lookup tables -// vector<int> tri_lookup, nor_lookup, col_lookup; -// map<string, vector<int> > mat_lookup, uv_lookup; -// -// //--Cycle through all the TriShapes, adding their data to the lists--// -// list<blk_ref>::iterator it; -// -// for (it = tri_shapes.begin(); it != tri_shapes.end(); ++it) { -// ITriShapeData * data = QueryTriShapeData(*it); -// -// //Vertices -// vector<Vector3> ts_verts = data->GetVertices(); -// _vertices.insert(_vertices.end(), ts_verts.begin(), ts_verts.end(); -// -// //Normals -// vector<Vector3> ts_norms = data->GetNormals(); -// _normals.insert(_normals.end(), ts_norms.begin(), ts_norms.end(); -// -// //Colors -// vector<Colors> ts_cols = data->GetColors(); -// _colors.insert(_colors.end(), ts_colors.begin(), ts_colors.end(); -// -// //Triangles -// ts_faces[i] = data->GetTriangles(); -// -// //UV Coords -// vector< vector<TexCoords> > uvs(data->GetUVSetCount()); -// for (int i = 0; i < data->GetUVSetCount(); ++i) { -// uvs[i] = data->GetUVSet(i); -// } -// -// //Associate UV Coord Data with proper map name -// blk_ref tx_prop = par["Properties"]->FindLink( "NiTexturingProperty"); -// if ( tx_prop.is_null() == false ) { -// int uv_set = 0; -// for (int i = 0; i < 7; ++i) { -// string attr_name, map; -// switch(i) { -// case 0: attr_name = "Base Texture"; map = "map1"; break; -// case 1: attr_name = "Dark Texture"; map = "dark"; break; -// case 2: attr_name = "Detail Texture"; map = "detail"; break; -// case 3: attr_name = "Gloss Texture"; map = "gloss"; break; -// case 4: attr_name = "Glow Texture"; map = "glow"; break; -// case 5: attr_name = "Bump Map Texture"; map = "bump"; break; -// case 6: attr_name = "Decal 0 Texture"; map = "decal0"; -// } -// -// if ( tx_prop[attr_name]->asTexDesc().isUsed == true ) { -// //How to merge all UVs? -// } -// -// } -// -// -// //blk_ref material = (*it)->GetAttr("Propreties")->FindLink("NiMaterialProperty"); -// //blk_ref skin_inst = (*it)->GetAttr("Skin Instance")->asLink(); -// //blk_ref skin_data; -// //vector<blk_ref> bones; -// //map<int, float> weights; -// //if ( skin_inst.is_null() == false ) { -// // skin_block = skin_inst->GetAttr("Data"); -// // if (skin_block.is_null() == false ) { -// // ISkinData * skin_data = QuerySkinData(skin_block); -// // weights = skin_data->GetWeights(); -// // bones = skin_data->GetBones(); -// // } -// //} -// -// } -//} - //--USER GUIDE DOCUMENTATION--// /*! \mainpage Niflib Documentation diff --git a/niflib.vcproj b/niflib.vcproj index 6ce39fc8..563cf0b7 100644 --- a/niflib.vcproj +++ b/niflib.vcproj @@ -355,6 +355,10 @@ Filter="cpp;c;cxx;def;odl;idl;hpj;bat;asm;asmx" UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" > + <File + RelativePath=".\ComplexShape.cpp" + > + </File> <File RelativePath=".\kfm.cpp" > @@ -1394,6 +1398,10 @@ Filter="h;hpp;hxx;hm;inl;inc;xsd" UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" > + <File + RelativePath=".\ComplexShape.h" + > + </File> <File RelativePath=".\dll_export.h" > diff --git a/obj/NiAVObject.cpp b/obj/NiAVObject.cpp index e621bf72..af1ffccb 100644 --- a/obj/NiAVObject.cpp +++ b/obj/NiAVObject.cpp @@ -80,7 +80,7 @@ Ref<NiNode> NiAVObject::GetParent() const { return parent; } -void NiAVObject::AddProperty( Ref<NiProperty> & obj ) { +void NiAVObject::AddProperty( const Ref<NiProperty> & obj ) { properties.push_back( obj ); } diff --git a/obj/NiAVObject.h b/obj/NiAVObject.h index 582b362f..c888a860 100644 --- a/obj/NiAVObject.h +++ b/obj/NiAVObject.h @@ -68,7 +68,7 @@ public: Ref<NiNode> GetParent() const; - void AddProperty( Ref<NiProperty> & obj ); + void AddProperty( const Ref<NiProperty> & obj ); void RemoveProperty( Ref<NiProperty> obj ); void ClearProperties(); vector< Ref<NiProperty> > GetProperties() const; diff --git a/obj/NiTexturingProperty.cpp b/obj/NiTexturingProperty.cpp index 1c5c03f7..7d83ef6d 100644 --- a/obj/NiTexturingProperty.cpp +++ b/obj/NiTexturingProperty.cpp @@ -222,7 +222,7 @@ bool NiTexturingProperty::HasTexture( int n ) const { case DECAL_1_MAP: return hasDecal1Texture; default: - throw("You have specified an invalid texture type."); + throw runtime_error("You have specified an invalid texture type."); }; } diff --git a/obj/NiTriBasedGeom.cpp b/obj/NiTriBasedGeom.cpp index ed34038c..bfd7f39e 100644 --- a/obj/NiTriBasedGeom.cpp +++ b/obj/NiTriBasedGeom.cpp @@ -73,12 +73,31 @@ Ref<NiSkinInstance> NiTriBasedGeom::GetSkinInstance() const { return skinInstance; } -void NiTriBasedGeom::BindSkin( Ref<NiNode> skeleton_root, vector< Ref<NiNode> > bone_nodes ) { +void NiTriBasedGeom::BindSkin( vector< Ref<NiNode> > bone_nodes ) { //Ensure skin is not aleady bound if ( skinInstance != 0 ) { throw runtime_error("You have attempted to re-bind a skin that is already bound. Unbind it first."); } + //--Find a suitable skeleton root--// + + //create a list of nodes that have an influence or this TriBasedGeom + //as decendents + list<NiAVObjectRef> ancestors; + + NiAVObjectRef shape_tree_top = ListAncestors( StaticCast<NiAVObject>(this), ancestors ); + NiAVObjectRef bone_tree_top; + + for ( unsigned int i = 0; i < bone_nodes.size(); ++i ) { + bone_tree_top = ListAncestors( StaticCast<NiAVObject>(bone_nodes[i]), ancestors ); + //Make sure bone and shapre are part of the same tree + if ( bone_tree_top != shape_tree_top ) { + throw runtime_error("Shape and all skin influence bones must be part of the same tree before skin bind can take place."); + } + } + + NiNodeRef skeleton_root = FindFirstCommonAncestor( shape_tree_top, ancestors ); + //Create a skin instance using the bone and root data skinInstance = new NiSkinInstance( skeleton_root, bone_nodes ); @@ -86,6 +105,38 @@ void NiTriBasedGeom::BindSkin( Ref<NiNode> skeleton_root, vector< Ref<NiNode> > skinInstance->SetSkinData( new NiSkinData( this ) ); }; +Ref<NiAVObject> NiTriBasedGeom::ListAncestors( const Ref<NiAVObject> & leaf, list< Ref<NiAVObject> > & ancestors ) const { + NiAVObjectRef avObj = leaf; + while ( avObj->GetParent() != NULL ) { + ancestors.push_back(avObj); + avObj = avObj->GetParent(); + } + + //Return top of tree + return avObj; +} + +Ref<NiNode> NiTriBasedGeom::FindFirstCommonAncestor( const Ref<NiAVObject> & avObj, const list< Ref<NiAVObject> > & ancestors ) const { + //See if we've found the common ancestor yet + for ( list<NiAVObjectRef>::const_iterator ancestor = ancestors.begin(); ancestor != ancestors.end(); ++ancestor ) { + if ( *ancestor == avObj ) { + //We found the common ancestor, return it. + return DynamicCast<NiNode>(avObj); + } + } + + //Call this function on any children + NiNodeRef niNode = DynamicCast<NiNode>(avObj); + if ( niNode != NULL ) { + vector<NiAVObjectRef> children = niNode->GetChildren(); + for ( uint i = 0; i < children.size(); ++i ) { + return FindFirstCommonAncestor( children[i], ancestors ); + } + } else { + return NULL; + } +} + void NiTriBasedGeom::UnbindSkin() { //Clear skin instance skinInstance = NULL; diff --git a/obj/NiTriBasedGeom.h b/obj/NiTriBasedGeom.h index b12c5be5..82d28da5 100644 --- a/obj/NiTriBasedGeom.h +++ b/obj/NiTriBasedGeom.h @@ -46,7 +46,7 @@ public: * NiSkinInstance and NiSkinData class. The bones must have a common * ancestor in the scenegraph. This becomes the skeleton root. */ - void BindSkin( Ref<NiNode> skeleton_root, vector< Ref<NiNode> > bone_nodes ); + void BindSkin( vector< Ref<NiNode> > bone_nodes ); void UnbindSkin(); Ref<NiSkinInstance> GetSkinInstance() const; @@ -62,6 +62,9 @@ public: vector<Vector3> GetSkinInfluencedVertices() const; protected: + Ref<NiAVObject> ListAncestors( const Ref<NiAVObject> & leaf, list< Ref<NiAVObject> > & ancestors ) const; + Ref<NiNode> FindFirstCommonAncestor( const Ref<NiAVObject> & avObj, const list< Ref<NiAVObject> > & ancestors ) const; + NI_TRI_BASED_GEOM_MEMBERS STANDARD_INTERNAL_METHODS }; -- GitLab