diff --git a/stepmania/src/ActorUtil.cpp b/stepmania/src/ActorUtil.cpp index 1345c31534..29c5dc6e5e 100644 --- a/stepmania/src/ActorUtil.cpp +++ b/stepmania/src/ActorUtil.cpp @@ -194,23 +194,9 @@ Actor* ActorUtil::LoadFromNode( const CString& sDir, const XNode* pNode ) ActorUtil::ResolvePath( sNewPath, sDir ); - pReturn = ActorUtil::MakeActor( sNewPath ); + pReturn = ActorUtil::MakeActor( sNewPath, pNode ); if( pReturn == NULL ) goto all_done; - - /* - * Hack: take attributes from the file loading the new actor, - * and load them on top of the new file. This way, you can do - * eg: - * - * file1.xml: - * file2.xml: - * - * Be sure to only run the low-level load, to pull in commands; - * don't reload the high-level actor, and don't rerun Init (which - * has already been run). - */ - pReturn->Actor::LoadFromNode( sDir, pNode ); } all_done: @@ -235,20 +221,69 @@ all_done: return pReturn; } -Actor* ActorUtil::MakeActor( const CString &sPath_ ) +/* + * Merge a parent and child XML. For example, + * + * parent.xml: + * child.xml: + * + * results in: + * + * + * + * The result is a copy of the child, with attributes and children + * from the parent merged, excluding the attribute "File". Warn + * about duplicate attributes. + */ +static void MergeActorXML( XNode *pChild, const XNode *pParent ) { + FOREACH_CONST_Child( pParent, p ) + pChild->AppendChild( new XNode(*p) ); + + FOREACH_CONST_Attr( pParent, p ) + { + if( p->first == "File" ) + continue; + + CString sOld; + if( pChild->GetChildValue(p->first, sOld) ) + { + CString sWarning = + ssprintf( "Overriding \"%s\" (\"%s\") in XML node \"%s\" with \"%s\" in XML node \"%s\"", + p->first.c_str(), + p->second.c_str(), + pChild->m_sName.c_str(), + sOld.c_str(), + pParent->m_sName.c_str() ); + Dialog::OK( sWarning, "XML_ATTRIB_OVERRIDE" ); + } + pChild->AppendAttr( p->first, p->second ); + } +} + +/* + * If pParent is non-NULL, it's the parent node when nesting XML, which is + * used only by ActorUtil::LoadFromNode. + */ +Actor* ActorUtil::MakeActor( const CString &sPath_, const XNode *pParent ) +{ + static const XNode dummy; + if( pParent == NULL ) + pParent = &dummy; + CString sPath( sPath_ ); /* If @ expressions are allowed through this path, we've already * evaluated them. Make sure we don't allow double-evaluation. */ ASSERT_M( sPath.empty() || sPath[0] != '@', sPath ); + CString sDir = Dirname( sPath ); FileType ft = GetFileType( sPath ); switch( ft ) { case FT_Directory: { - CString sDir = sPath; + sDir = sPath; if( sDir.Right(1) != "/" ) sDir += '/'; @@ -270,21 +305,26 @@ Actor* ActorUtil::MakeActor( const CString &sPath_ ) // XNode will warn about the error return new Actor; } - CString sDir = Dirname( sPath ); + + MergeActorXML( &xml, pParent ); return ActorUtil::LoadFromNode( sDir, &xml ); } case FT_Bitmap: case FT_Movie: { - Sprite* pSprite = new Sprite; - pSprite->Load( sPath ); - return pSprite; + XNode xml( *pParent ); + xml.AppendAttr( "Texture", sPath ); + + return ActorUtil::Create( "Sprite", sDir, &xml ); } case FT_Model: { - Model* pModel = new Model; - pModel->Load( sPath ); - return pModel; + XNode xml( *pParent ); + xml.AppendAttr( "Meshes", sPath ); + xml.AppendAttr( "Materials", sPath ); + xml.AppendAttr( "Bones", sPath ); + + return ActorUtil::Create( "Model", sDir, &xml ); } default: RageException::Throw("File \"%s\" has unknown type, \"%s\"", diff --git a/stepmania/src/ActorUtil.h b/stepmania/src/ActorUtil.h index 7b43914e50..5f4f8d5054 100644 --- a/stepmania/src/ActorUtil.h +++ b/stepmania/src/ActorUtil.h @@ -67,7 +67,7 @@ namespace ActorUtil // Return a Sprite, BitmapText, or Model depending on the file type Actor* LoadFromNode( const CString& sAniDir, const XNode* pNode ); - Actor* MakeActor( const CString &sPath ); + Actor* MakeActor( const CString &sPath, const XNode *pParent = NULL ); void ResolvePath( CString &sPath, const CString &sName );