Skip to content
Snippets Groups Projects
Commit ff0a0d05 authored by Tazpn's avatar Tazpn
Browse files

Miscellaneous fixes:

1. Update NiStencilProperty based on Shon's changes
2. Rewrote large chunks of WriteFileGroup related routines.
3. Added a WriteNifTree which allows for multiple roots (not exposed publically)
4. Added option to BindSkin to scene instead of skeleton root.
5. Fixed bug in RemoveController
6. Added helpers to NiControllerManager for sequence management
7. Propegated user_version in routines which take a version
parent e9473017
No related branches found
No related tags found
No related merge requests found
......@@ -209,7 +209,7 @@ NIFLIB_API void WriteNifTree( ostream & stream, Ref<NiObject> const & root, unsi
* \param export_files What files to write: NIF, NIF + KF + KFM, NIF + KF's + KFM, KF only, KF's only
* \param kf_type The KF type (Morrowind style, DAoC style, CivIV style, ...)
*/
NIFLIB_API void WriteFileGroup( string const & file_name, Ref<NiObject> const & root, unsigned int version, ExportOptions export_files, NifGame kf_type );
NIFLIB_API void WriteFileGroup( string const & file_name, Ref<NiObject> const & root, unsigned int version = VER_4_0_0_2, unsigned int user_version = 0, ExportOptions export_files = EXPORT_NIF, NifGame kf_type = KF_MW);
/*!
* Creates a clone of an entire tree of objects.
......
......@@ -50,6 +50,9 @@ public:
*/
vector<Ref<NiControllerSequence > > GetControllerSequences() const;
void SetControllerSequences( const vector<Ref<NiControllerSequence > >& value );
void AddSequence( Ref<NiControllerSequence > & obj );
void RemoveSequence( Ref<NiControllerSequence > obj );
void ClearSequences();
/*!
* Refers to a NiDefaultAVObjectPalette.
......
......@@ -139,7 +139,10 @@ public:
void SetTargetName( const string & value );
protected:
NiControllerManager * NiControllerSequence::Parent() const;
friend class NiControllerManager;
NiControllerManager * GetParent() const;
void SetParent(NiControllerManager *parent);
NI_CONTROLLER_SEQUENCE_MEMBERS
STANDARD_INTERNAL_METHODS
};
......
......@@ -47,7 +47,7 @@ public:
* NiSkinInstance and NiSkinData class. The bones must have a common
* ancestor in the scenegraph. This becomes the skeleton root.
*/
void BindSkin( vector< Ref<NiNode> > bone_nodes );
void BindSkin( vector< Ref<NiNode> > bone_nodes, bool bind_to_scene = false );
void UnbindSkin();
/*!
* Sets the skin weights in the attached NiSkinData object.
......
......@@ -15,6 +15,7 @@ All rights reserved. Please see niflib.h for licence. */
#include "../include/obj/NiAVObject.h"
#include "../include/obj/NiTextKeyExtraData.h"
#include "../include/obj/NiSequenceStreamHelper.h"
#include "../include/obj/NiControllerManager.h"
#include "../include/obj/NiControllerSequence.h"
#include "../include/obj/NiStringPalette.h"
#include "../include/obj/NiSkinPartition.h"
......@@ -23,6 +24,9 @@ All rights reserved. Please see niflib.h for licence. */
#include "../include/obj/NiInterpolator.h"
#include "../include/obj/NiKeyframeController.h"
#include "../include/obj/NiKeyframeData.h"
#include "../include/obj/NiTransformInterpolator.h"
#include "../include/obj/NiTransformController.h"
#include "../include/obj/NiTransformData.h"
#include "../include/obj/NiStringExtraData.h"
#include "../include/obj/NiExtraData.h"
#include "../include/obj/bhkRigidBody.h"
......@@ -285,19 +289,8 @@ vector<NiObjectRef> ReadNifList( istream & in ) {
return blocks;
}
// Writes a valid Nif File given a file name, a pointer to the root block of a file tree
void WriteNifTree( string const & file_name, NiObjectRef const & root_block, unsigned int version, unsigned int user_version ) {
//Open output file
ofstream out( file_name.c_str(), ofstream::binary );
WriteNifTree( out, root_block, version, user_version );
//Close file
out.close();
}
// Writes a valid Nif File given an ostream, a pointer to the root block of a file tree
void WriteNifTree( ostream & out, NiObjectRef const & root, unsigned int version, unsigned int user_version ) {
// Writes a valid Nif File given an ostream, a list to the root objects of a file tree
void WriteNifTree( ostream & out, list<NiObjectRef> const & roots, unsigned int version, unsigned int user_version ) {
// Walk tree, resetting all block numbers
//int block_count = ResetBlockNums( 0, root_block );
......@@ -305,7 +298,9 @@ void WriteNifTree( ostream & out, NiObjectRef const & root, unsigned int version
map<Type*,uint> type_map;
map<NiObjectRef, uint> link_map;
EnumerateObjects( root, type_map, link_map );
for (list<NiObjectRef>::const_iterator it = roots.begin(); it != roots.end(); ++it) {
EnumerateObjects( (*it), type_map, link_map );
}
//Build vectors for reverse look-up
vector<NiObjectRef> objects(link_map.size());
......@@ -365,22 +360,58 @@ void WriteNifTree( ostream & out, NiObjectRef const & root, unsigned int version
//--Write Footer--//
Footer footer;
footer.numRoots = 0;
if (root->IsDerivedType(NiAVObject::TypeConst())) {
// Handle most NIF file formats
footer.numRoots = 1;
footer.roots.resize(1);
footer.roots[0] = StaticCast<NiAVObject>(root);
} else if (root->IsDerivedType(NiControllerSequence::TypeConst())) {
// KF animation files allow for multiple roots of type NiControllerSequence
for ( uint i = 0; i < objects.size(); ++i ) {
if (objects[i]->IsDerivedType(NiControllerSequence::TypeConst())) {
footer.roots.push_back(objects[i]);
if (roots.size() == 1) {
const NiObjectRef& root = roots.front();
if (root->IsDerivedType(NiAVObject::TypeConst())) {
// Handle most NIF file formats
footer.numRoots = 1;
footer.roots.resize(1);
footer.roots[0] = StaticCast<NiObject>(root);
} else if (root->IsDerivedType(NiControllerSequence::TypeConst())) {
// KF animation files allow for multiple roots of type NiControllerSequence
for ( uint i = 0; i < objects.size(); ++i ) {
if (objects[i]->IsDerivedType(NiControllerSequence::TypeConst())) {
footer.roots.push_back(objects[i]);
}
}
}
} else {
footer.numRoots = roots.size();
footer.roots.insert(footer.roots.end(), roots.begin(), roots.end());
}
footer.Write( out, link_map, version, user_version );
}
// Writes a valid Nif File given a file name, a pointer to the root block of a file tree
void WriteNifTree( string const & file_name, NiObjectRef const & root_block, unsigned int version, unsigned int user_version ) {
//Open output file
ofstream out( file_name.c_str(), ofstream::binary );
list<NiObjectRef> roots;
roots.push_back(root_block);
WriteNifTree( out, roots, version, user_version );
//Close file
out.close();
}
void WriteNifTree( string const & file_name, list<NiObjectRef> const & roots, unsigned int version, unsigned int user_version ) {
//Open output file
ofstream out( file_name.c_str(), ofstream::binary );
WriteNifTree( out, roots, version, user_version );
//Close file
out.close();
}
// Writes a valid Nif File given an ostream, a pointer to the root object of a file tree
void WriteNifTree( ostream & out, NiObjectRef const & root, unsigned int version, unsigned int user_version ) {
list<NiObjectRef> roots;
roots.push_back(root);
WriteNifTree( out, roots, version, user_version );
}
void EnumerateObjects( NiObjectRef const & root, map<Type*,uint> & type_map, map<NiObjectRef, uint> & link_map, bool reverse ) {
//Ensure that this object has not already been visited
if ( link_map.find( root ) != link_map.end() ) {
......@@ -500,16 +531,31 @@ list<NiObjectRef> GetAllObjectsByType( NiObjectRef const & root, const Type & ty
// return result;
//};
// Create a valid
static std::string CreateFileName(std::string name) {
std::string retname = name;
std::string::size_type off = 0;
std::string::size_type pos = 0;
for (;;) {
pos = retname.find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789_^$~!#%&-{}()@'` ", off);
if (pos == std::string::npos)
break;
retname[pos] = '_';
off = pos;
}
return retname;
}
//TODO: This was written by Amorilia. Figure out how to fix it.
/*!
* Helper function to split off animation from a nif tree. If no animation groups are defined, then both xnif_root and xkf_root will be null blocks.
* \param root_block The root block of the full tree.
* \param xnif_root The root block of the tree without animation.
* \param xkf_root The root block of the animation tree.
* \param xnif_root The root object of the tree without animation.
* \param xkf_roots The root objects of the animation trees.
* \param kfm The KFM structure (if required by style).
* \param kf_type What type of keyframe tree to write (Morrowind style, DAoC style, ...).
*/
void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, NiObjectRef & xkf_root, Kfm & kfm, int kf_type ) {
static void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, list<NiObjectRef> & xkf_roots, Kfm & kfm, int kf_type, unsigned int version, unsigned int user_version ) {
// Do we have animation groups (a NiTextKeyExtraData block)?
// If so, create XNif and XKf trees.
NiObjectRef txtkey = GetObjectByType( root_block, NiTextKeyExtraData::TypeConst() );
......@@ -520,29 +566,34 @@ void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, NiOb
if ( txtkey_block != NULL ) {
if ( kf_type == KF_MW ) {
// Construct the XNif file...
// We are lazy. (TODO: clone & remove keyframe controllers & keyframe data)
xnif_root = root_block;
xnif_root = CloneNifTree(root_block, version, user_version);
// Now search and locate newer timeframe controllers and convert to keyframecontrollers
list<NiObjectRef> mgrs = GetAllObjectsByType( xnif_root, NiControllerManager::TypeConst() );
for ( list<NiObjectRef>::iterator it = mgrs.begin(); it != mgrs.end(); ++it) {
NiControllerManagerRef mgr = DynamicCast<NiControllerManager>(*it);
if ( mgr == NULL ) {
continue;
}
NiObjectNETRef target = mgr->GetTarget();
target->RemoveController( StaticCast<NiTimeController>(mgr) );
vector<NiControllerSequenceRef> seqs = mgr->GetControllerSequences();
for (vector<NiControllerSequenceRef>::iterator itr = seqs.begin(); itr != seqs.end(); ++itr) {
NiControllerSequenceRef seq = (*itr);
MergeNifTrees(DynamicCast<NiNode>(target), seq, version, user_version);
}
}
// Now the XKf file...
// Create xkf root header.
NiSequenceStreamHelperRef xkf_stream_helper = new NiSequenceStreamHelper;
xkf_root = xkf_stream_helper;
// Add a copy of the NiTextKeyExtraData block to the XKf header.
NiTextKeyExtraDataRef xkf_txtkey_block = new NiTextKeyExtraData;
//TODO: Have Amorilia fix this
xkf_stream_helper->AddExtraData( StaticCast<NiExtraData>(xkf_txtkey_block) );
//ITextKeyExtraData const *itxtkey_block = QueryTextKeyExtraData(txtkey_block);
//ITextKeyExtraData *ixkf_txtkey_block = QueryTextKeyExtraData(xkf_txtkey_block);
xkf_txtkey_block->SetKeys( txtkey_block->GetKeys() );
xkf_roots.push_back( StaticCast<NiObject>(xkf_stream_helper) );
// Append NiNodes with a NiKeyFrameController as NiStringExtraData blocks.
list< pair< NiNodeRef, NiKeyframeControllerRef> > node_controllers;
list<NiObjectRef> nodes = GetAllObjectsByType( root_block, NiNode::TypeConst() );
list<NiObjectRef> nodes = GetAllObjectsByType( xnif_root, NiNode::TypeConst() );
for ( list<NiObjectRef>::iterator it = nodes.begin(); it != nodes.end(); ++it) {
NiNodeRef node = DynamicCast<NiNode>(*it);
if ( node == NULL ) {
......@@ -552,58 +603,89 @@ void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, NiOb
//Find the first NiKeyframeController in the controller list, if any
list<NiTimeControllerRef> controllers = node->GetControllers();
NiKeyframeControllerRef key_controller;
for ( list<NiTimeControllerRef>::iterator controller = controllers.begin(); controller != controllers.end(); ++controller ) {
key_controller = DynamicCast<NiKeyframeController>(*it);
if ( key_controller != NULL ) {
break;
}
for ( list<NiTimeControllerRef>::iterator it = controllers.begin(); it != controllers.end(); ++it ) {
if ((*it)->IsDerivedType(NiKeyframeController::TypeConst())) {
key_controller = StaticCast<NiKeyframeController>(*it);
} else if ((*it)->IsDerivedType(NiTransformController::TypeConst())) {
NiTransformControllerRef trans = StaticCast<NiTransformController>(*it);
NiTransformInterpolatorRef interp = DynamicCast<NiTransformInterpolator>(trans->GetInterpolator());
if (interp != NULL) {
NiTransformDataRef transData = interp->GetData();
if (transData != NULL) {
NiKeyframeDataRef data = new NiKeyframeData();
data->SetRotateType( transData->GetRotateType() );
data->SetTranslateType( transData->GetTranslateType() );
data->SetScaleType( transData->GetScaleType() );
data->SetXRotateType( transData->GetXRotateType() );
data->SetYRotateType( transData->GetYRotateType() );
data->SetZRotateType( transData->GetZRotateType() );
data->SetTranslateKeys( transData->GetTranslateKeys() );
data->SetQuatRotateKeys( transData->GetQuatRotateKeys() );
data->SetScaleKeys( transData->GetScaleKeys() );
data->SetXRotateKeys( transData->GetXRotateKeys() );
data->SetYRotateKeys( transData->GetYRotateKeys() );
data->SetZRotateKeys( transData->GetZRotateKeys() );
key_controller = new NiKeyframeController();
key_controller->SetFlags( trans->GetFlags() );
key_controller->SetFrequency( trans->GetFrequency() );
key_controller->SetPhase( trans->GetPhase() );
key_controller->SetStartTime( trans->GetStartTime() );
key_controller->SetStopTime( trans->GetStopTime() );
key_controller->SetData( data );
break;
}
}
}
}
//If this node has no keyframe controller, put it in the list
if ( key_controller != NULL ) {
node_controllers.push_back( pair<NiNodeRef,NiKeyframeControllerRef>( node, key_controller ) );
}
};
}
for ( list< pair< NiNodeRef, NiKeyframeControllerRef> >::iterator it = node_controllers.begin(); it != node_controllers.end(); ++it ) {
//Add string data
NiStringExtraDataRef nodextra = new NiStringExtraData;
nodextra->SetData( it->first->GetName() );
xkf_stream_helper->AddExtraData( StaticCast<NiExtraData>(nodextra) );
// Add controllers & controller data.
NiKeyframeControllerRef controller = it->second;
NiKeyframeControllerRef xkf_controller = new NiKeyframeController;
xkf_controller->SetFlags( controller->GetFlags() );
xkf_controller->SetFrequency( controller->GetFrequency() );
xkf_controller->SetPhase( controller->GetPhase() );
xkf_controller->SetStartTime( controller->GetStartTime() );
xkf_controller->SetStopTime( controller->GetStopTime() );
NiKeyframeDataRef xkf_data = new NiKeyframeData;
NiKeyframeDataRef kfdata = controller->GetData();
xkf_controller->SetData( xkf_data );
xkf_data->SetRotateType( kfdata->GetRotateType() );
xkf_data->SetTranslateType( kfdata->GetTranslateType() );
xkf_data->SetScaleType( kfdata->GetScaleType() );
xkf_data->SetQuatRotateKeys( kfdata->GetQuatRotateKeys() );
xkf_data->SetXRotateKeys( kfdata->GetXRotateKeys() );
xkf_data->SetYRotateKeys( kfdata->GetYRotateKeys() );
xkf_data->SetZRotateKeys( kfdata->GetZRotateKeys() );
xkf_data->SetTranslateKeys( kfdata->GetTranslateKeys() );
xkf_data->SetScaleKeys( kfdata->GetScaleKeys() );
xkf_stream_helper->AddExtraData( StaticCast<NiExtraData>(nodextra), version );
NiKeyframeControllerRef controller = it->second;
(it->first)->RemoveController( StaticCast<NiTimeController>(controller) );
xkf_stream_helper->AddController( StaticCast<NiTimeController>(controller) );
};
} else // TODO other games
}
// Add a copy of the NiTextKeyExtraData block to the XKf header.
NiTextKeyExtraDataRef xkf_txtkey_block = new NiTextKeyExtraData;
xkf_stream_helper->AddExtraData( StaticCast<NiExtraData>(xkf_txtkey_block), version );
xkf_txtkey_block->SetKeys( txtkey_block->GetKeys() );
} else if (kf_type == KF_CIV4) {
// Construct the Nif file without transform controllers ...
xnif_root = CloneNifTree(root_block, version, user_version);
list<NiObjectRef> mgrs = GetAllObjectsByType( xnif_root, NiControllerManager::TypeConst() );
for ( list<NiObjectRef>::iterator it = mgrs.begin(); it != mgrs.end(); ++it) {
NiControllerManagerRef mgr = DynamicCast<NiControllerManager>(*it);
if ( mgr == NULL ) {
continue;
}
NiObjectNETRef target = mgr->GetTarget();
target->RemoveController( StaticCast<NiTimeController>(mgr) );
vector<NiControllerSequenceRef> seqs = mgr->GetControllerSequences();
for (vector<NiControllerSequenceRef>::iterator itr = seqs.begin(); itr != seqs.end(); ++itr) {
xkf_roots.push_back( StaticCast<NiObject>(*itr) );
}
}
} else
throw runtime_error("KF splitting for the requested game is not yet implemented.");
} else {
// no animation groups: nothing to do
xnif_root = NULL;
xkf_root = NULL;
xnif_root = root_block;
};
}
......@@ -618,7 +700,7 @@ void SplitNifTree( NiObjectRef const & root_block, NiObjectRef & xnif_root, NiOb
//};
//TODO: This was written by Amorilia. Figure out how to fix it.
void WriteFileGroup( string const & file_name, NiObjectRef const & root_block, unsigned int version, ExportOptions export_files, NifGame kf_type ) {
void WriteFileGroup( string const & file_name, NiObjectRef const & root_block, unsigned int version, unsigned int user_version, ExportOptions export_files, NifGame kf_type ) {
// Get base filename.
uint file_name_slash = uint(file_name.rfind("\\") + 1);
string file_name_path = file_name.substr(0, file_name_slash);
......@@ -628,23 +710,43 @@ void WriteFileGroup( string const & file_name, NiObjectRef const & root_block, u
// Deal with the simple case first
if ( export_files == EXPORT_NIF )
WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version ); // simply export the NIF file!
WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version, user_version ); // simply export the NIF file!
// Now consider all other cases
else if ( kf_type == KF_MW ) {
if ( export_files == EXPORT_NIF_KF ) {
// for Morrowind we must also write the full NIF file
WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version ); // simply export the NIF file!
WriteNifTree( file_name_path + file_name_base + ".nif", root_block, version, user_version ); // simply export the NIF file!
NiObjectRef xnif_root;
NiObjectRef xkf_root;
list<NiObjectRef> xkf_roots;
Kfm kfm; // dummy
SplitNifTree( root_block, xnif_root, xkf_root, kfm, KF_MW );
if ( xnif_root != NULL ) {
WriteNifTree( file_name_path + "x" + file_name_base + ".nif", xnif_root, version );
WriteNifTree( file_name_path + "x" + file_name_base + ".kf", xkf_root, version );
SplitNifTree( root_block, xnif_root, xkf_roots, kfm, kf_type, version, user_version );
if ( xnif_root != NULL && !xkf_roots.empty()) {
WriteNifTree( file_name_path + "x" + file_name_base + ".nif", xnif_root, version, user_version );
WriteNifTree( file_name_path + "x" + file_name_base + ".kf", xkf_roots.front(), version, user_version );
};
} else
throw runtime_error("Invalid export option.");
} else
} else if (kf_type == KF_CIV4) {
NiObjectRef xnif_root;
list<NiObjectRef> xkf_roots;
Kfm kfm; // dummy
SplitNifTree( root_block, xnif_root, xkf_roots, kfm, kf_type, version, user_version );
if ( export_files == EXPORT_NIF || export_files == EXPORT_NIF_KF || export_files == EXPORT_NIF_KF_MULTI ) {
WriteNifTree( file_name_path + file_name_base + ".nif", xnif_root, version, user_version );
}
if ( export_files == EXPORT_NIF_KF || export_files == EXPORT_KF ) {
WriteNifTree( file_name_path + file_name_base + ".kf", xkf_roots, version, user_version );
} else if ( export_files == EXPORT_NIF_KF_MULTI || export_files == EXPORT_KF_MULTI ) {
for ( list<NiObjectRef>::iterator it = xkf_roots.begin(); it != xkf_roots.end(); ++it ) {
NiControllerSequenceRef seq = DynamicCast<NiControllerSequence>(*it);
if (seq == NULL)
continue;
string path = file_name_path + file_name_base + "_" + CreateFileName(seq->GetTargetName()) + "_" + CreateFileName(seq->GetName()) + ".kf";
WriteNifTree( path, StaticCast<NiObject>(seq), version, user_version );
}
}
} else
throw runtime_error("Not yet implemented.");
};
......@@ -780,7 +882,7 @@ void MergeNifTrees( const Ref<NiNode> & target, const Ref<NiControllerSequence>
NiObjectRef tx_clone = txt_key->Clone( version, user_version );
NiExtraDataRef ext_dat = DynamicCast<NiExtraData>(tx_clone);
if ( ext_dat != NULL ) {
target->AddExtraData( ext_dat );
target->AddExtraData( ext_dat, version );
}
}
......
......@@ -4,6 +4,7 @@ All rights reserved. Please see niflib.h for licence. */
#include "../../include/obj/NiControllerManager.h"
#include "../../include/obj/NiControllerSequence.h"
#include "../../include/obj/NiDefaultAVObjectPalette.h"
#include <algorithm>
using namespace Niflib;
//Definition of TYPE constant
......@@ -50,9 +51,41 @@ vector<Ref<NiControllerSequence > > NiControllerManager::GetControllerSequences(
}
void NiControllerManager::SetControllerSequences( const vector<Ref<NiControllerSequence > >& value ) {
ClearSequences();
controllerSequences = value;
for (vector<NiControllerSequenceRef>::iterator it = controllerSequences.begin(); it != controllerSequences.end(); ++it) {
(*it)->SetParent(this);
}
}
void NiControllerManager::AddSequence( Ref<NiControllerSequence > & obj ) {
vector<NiControllerSequenceRef>::iterator begin = controllerSequences.begin();
vector<NiControllerSequenceRef>::iterator end = controllerSequences.end();
vector<NiControllerSequenceRef>::iterator it = std::find(begin, end, obj);
if (it == end) {
controllerSequences.insert(end, obj);
obj->SetParent(this);
}
}
void NiControllerManager::RemoveSequence( Ref<NiControllerSequence > obj ) {
vector<NiControllerSequenceRef>::iterator begin = controllerSequences.begin();
vector<NiControllerSequenceRef>::iterator end = controllerSequences.end();
vector<NiControllerSequenceRef>::iterator it = std::find(begin, end, obj);
if (it != end) {
(*it)->SetParent(NULL);
controllerSequences.erase(it);
}
}
void NiControllerManager::ClearSequences() {
for (vector<NiControllerSequenceRef>::iterator it = controllerSequences.begin(); it != controllerSequences.end(); ++it) {
(*it)->SetParent(NULL);
}
controllerSequences.clear();
}
Ref<NiDefaultAVObjectPalette > NiControllerManager::GetObjectPalette() const {
return objectPalette;
}
......
......@@ -47,7 +47,14 @@ const Type & NiControllerSequence::GetType() const {
return TYPE;
};
NiControllerManager * NiControllerSequence::Parent() const { return NULL; }
NiControllerManager * NiControllerSequence::GetParent() const {
return manager;
}
void NiControllerSequence::SetParent(NiControllerManager * parent) {
manager = parent;
}
void NiControllerSequence::SetTextKey( const Ref<NiTextKeyExtraData> & txt_key ) {
//Set new name
......
......@@ -140,15 +140,19 @@ void NiObjectNET::AddController( Ref<NiTimeController> & obj ) {
}
void NiObjectNET::RemoveController( Ref<NiTimeController> obj ) {
NiTimeControllerRef * cont = &controller;
while ( (*cont) != NULL ) {
if ( (*cont) == obj ) {
for(NiTimeControllerRef last = controller, cont = last, next; cont != NULL; cont = next ) {
next = cont->GetNextController();
if ( cont == obj ) {
//Cut this reference out of the list
(*cont)->SetTarget( NULL );
(*cont) = (*cont)->GetNextController();
cont->SetTarget( NULL );
cont->SetNextController( NiTimeControllerRef() );
if (cont == controller)
controller = next;
else
last->SetNextController(next);
} else {
//Advance to the next controller
cont = &((*cont)->GetNextController());
//Advance last to current controller
last = cont;
}
}
}
......
......@@ -74,7 +74,7 @@ Ref<NiSkinInstance> NiTriBasedGeom::GetSkinInstance() const {
return skinInstance;
}
void NiTriBasedGeom::BindSkin( vector< Ref<NiNode> > bone_nodes ) {
void NiTriBasedGeom::BindSkin( vector< Ref<NiNode> > bone_nodes, bool bind_to_scene ) {
//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.");
......@@ -110,58 +110,70 @@ void NiTriBasedGeom::BindSkin( vector< Ref<NiNode> > bone_nodes ) {
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 = ancestors[0].front();
//Make sure bone and shapes are part of the same tree
for ( int i = 1; i < num_lists; ++i ) {
if ( ancestors[i].size() == 0 ) {
throw runtime_error("Shape and all skin influence bones must be part of the same tree before skin bind can take place.");
}
if ( ancestors[i].front() != skeleton_root ) {
throw runtime_error("Shape and all skin influence bones must be part of the same tree before skin bind can take place.");
}
}
//Since the first items have been shown to match, pop all the stacks
for ( int i = 0; i < num_lists; ++i ) {
ancestors[i].pop_front();
}
//Now search for the common ancestor
while(true) {
bool all_same = true;
if ( ancestors[0].size() == 0 ) {
//This list is over, so the last top is the common ancestor
//break out of the loop
break;
}
NiNodeRef first_ancestor = ancestors[0].front();
for ( int i = 1; i < num_lists; ++i ) {
if ( ancestors[i].size() == 0 ) {
//This list is over, so the last top is the common ancestor
//break out of the loop
all_same = false;
break;
}
if ( ancestors[i].front() != first_ancestor ) {
all_same = false;
}
}
NiNodeRef skeleton_root;
if (bind_to_scene) {
// Just parent to the scene
NiNodeRef parent = GetParent();
while (parent != NULL) {
skeleton_root = parent;
parent = parent->GetParent();
}
if ( all_same == true ) {
//They're all the same, so set the top, pop all the stacks
//and look again
skeleton_root = ancestors[0].front();
for ( int i = 0; i < num_lists; ++i ) {
ancestors[i].pop_front();
}
} else {
//One is different, so the last top is the common ancestor.
//break out of the loop
break;
}
}
} else {
skeleton_root = ancestors[0].front();
//Make sure bone and shapes are part of the same tree
for ( int i = 1; i < num_lists; ++i ) {
if ( ancestors[i].size() == 0 ) {
throw runtime_error("Shape and all skin influence bones must be part of the same tree before skin bind can take place.");
}
if ( ancestors[i].front() != skeleton_root ) {
throw runtime_error("Shape and all skin influence bones must be part of the same tree before skin bind can take place.");
}
}
//Since the first items have been shown to match, pop all the stacks
for ( int i = 0; i < num_lists; ++i ) {
ancestors[i].pop_front();
}
//Now search for the common ancestor
while(true) {
bool all_same = true;
if ( ancestors[0].size() == 0 ) {
//This list is over, so the last top is the common ancestor
//break out of the loop
break;
}
NiNodeRef first_ancestor = ancestors[0].front();
for ( int i = 1; i < num_lists; ++i ) {
if ( ancestors[i].size() == 0 ) {
//This list is over, so the last top is the common ancestor
//break out of the loop
all_same = false;
break;
}
if ( ancestors[i].front() != first_ancestor ) {
all_same = false;
}
}
if ( all_same == true ) {
//They're all the same, so set the top, pop all the stacks
//and look again
skeleton_root = ancestors[0].front();
for ( int i = 0; i < num_lists; ++i ) {
ancestors[i].pop_front();
}
} else {
//One is different, so the last top is the common ancestor.
//break out of the loop
break;
}
}
}
if ( skeleton_root == NULL ) {
throw runtime_error("Failed to find suitable skeleton root.");
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment