/*---------------------------------------------------------------------------* Project: NintendoWare File: SmModel.cpp Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 1 $ *---------------------------------------------------------------------------*/ #include "../include/SmModel.h" namespace { //---------------------------------------- // コンストラクタ SmModel::SmModel() : m_pParentNode( NULL ), m_pSceneNode( NULL ), m_Model( NULL ), m_SkeletalModel( NULL ), m_AnimationFrame( 0.f ), m_CurrentAnimEvNo( -1 ), m_CostrainId( -1 ), m_Duplicated( false ) { m_AnimEvaluatorArray.clear(); } //---------------------------------------- // SmModel::~SmModel() { } //---------------------------------------- // ノードをセットする void SmModel::SetSceneNode( nw::gfx::SceneNode* pParentNode, nw::gfx::SceneNode* pSceneNode ) { NW_NULL_ASSERT(pParentNode); m_pParentNode = pParentNode; if ( pSceneNode ) { m_pSceneNode = pSceneNode; } } //---------------------------------------- // モデルをセットする void SmModel::SetModel( nw::gfx::Model* pModel, nw::gfx::SkeletalModel* pSkelModel ) { m_Model = pModel; m_SkeletalModel = pSkelModel; } //---------------------------------------- // アップデート、コンストレイン等の解決を行う void SmModel::Update() { // 親子関係の解決 updateConstrain(); } //---------------------------------------- // 位置 void SmModel::SetPosition( f32 x, f32 y, f32 z ) { nw::gfx::TransformNode* transformNode = nw::ut::DynamicCast(m_pSceneNode); NW_NULL_ASSERT(transformNode); transformNode->Transform().SetTranslate( x, y, z ); } //---------------------------------------- // 拡縮 void SmModel::SetScale( f32 x, f32 y, f32 z ) { nw::gfx::TransformNode* transformNode = nw::ut::DynamicCast(m_pSceneNode); NW_NULL_ASSERT(transformNode); transformNode->Transform().SetScale( x, y, z ); } //---------------------------------------- // 回転 Degree void SmModel::SetRotate( f32 x, f32 y, f32 z ) { nw::gfx::TransformNode* transformNode = nw::ut::DynamicCast(m_pSceneNode); NW_NULL_ASSERT(transformNode); transformNode->Transform().SetRotateXYZ( NW_MATH_DEG_TO_RAD(x), NW_MATH_DEG_TO_RAD(y), NW_MATH_DEG_TO_RAD(z) ); } //---------------------------------------- // マトリクス void SmModel::SetMatrix( const nw::math::MTX34* matrix ) { NW_NULL_ASSERT( matrix ); nw::gfx::TransformNode* transformNode = nw::ut::DynamicCast(m_pSceneNode); NW_NULL_ASSERT(transformNode); transformNode->Transform().SetTransformMatrix( *matrix ); } void SmModel::SetWorldMatrix( const nw::math::MTX34* matrix ) { NW_NULL_ASSERT( matrix ); nw::gfx::TransformNode* transformNode = nw::ut::DynamicCast(m_pSceneNode); NW_NULL_ASSERT(transformNode); transformNode->WorldMatrix() = *matrix; } //---------------------------------------- // 表示/非表示 void SmModel::SetVisible( bool visible ) { if ( !m_SkeletalModel ) return; m_SkeletalModel->SetVisible( visible ); // 親が居る居ないでシーンツーリーに登録されているか判断する。 if ( !visible ) { if ( m_pSceneNode->GetParent() ) { m_pParentNode->DetachChild( m_pSceneNode ); } } else { if ( !m_pSceneNode->GetParent() ) { m_pParentNode->AttachChild( m_pSceneNode ); } } } void SmModel::SwapVisible() { if ( !m_SkeletalModel ) return; // 親が居る居ないでシーンツーリーに登録されているか判断する。 if ( m_SkeletalModel->IsVisible() ) { m_SkeletalModel->SetVisible( false ); if ( m_pSceneNode->GetParent() ) { m_pParentNode->DetachChild( m_pSceneNode ); } } else { m_SkeletalModel->SetVisible( true ); if ( !m_pSceneNode->GetParent() ) { m_pParentNode->AttachChild( m_pSceneNode ); } } } bool SmModel::IsVisible() { if ( !m_SkeletalModel ) return false; return m_SkeletalModel->IsVisible(); } //---------------------------------------- // 複製する SmModel* SmModel::Duplicate() { SmModel* model = new SmModel(); #if 1 // スケルトン共有ナシ nw::gfx::SkeletalModel* skeletalModel = nw::gfx::SkeletalModel::Builder() .Create( NULL, nw::gfx::ResSceneObject( m_SkeletalModel->GetResModel() ), m_Allocator ); #else // スケルトン共有アリ nw::gfx::SkeletalModel* skeletalModel = nw::gfx::SkeletalModel::Builder() .SharedSkeleton( m_SkeletalModel->GetSkeleton() ) .Create(NULL, nw::gfx::ResSceneObject(m_SkeletalModel->GetResModel()), m_Allocator); #endif NW_NULL_ASSERT(skeletalModel); // コピー元モデルから値のコピー model->m_SkeletalModel = skeletalModel; model->m_Duplicated = true; model->m_pSceneNode = static_cast(model->m_SkeletalModel); model->SetLayerId( this->GetLayerId() ); // todo:パラでアニメーションさせるには、 // アニメーションをコピーする必要がアリ。 model->m_AnimEvaluatorArray.CopyFrom( m_AnimEvaluatorArray ); return model; } //---------------------------------------- // アニメーションを追加する void SmModel::AddAnimEvaluator( nw::gfx::TransformAnimEvaluator* animEvaluator ) { m_AnimEvaluatorArray.push_back( animEvaluator ); } //---------------------------------------- // アニメーション数を取得する uint SmModel::GetAnimEvaluatorNum() const { return m_AnimEvaluatorArray.size(); } //---------------------------------------- // アニメーションを設定する bool SmModel::SetAnimEvaluatorNo( uint animEvaluatorNo ) { if ( animEvaluatorNo >= GetAnimEvaluatorNum() ) return false; if ( !m_SkeletalModel ) return false; nw::gfx::AnimGroup* animGroup = m_SkeletalModel->GetSkeletalAnimGroup(); if (animGroup == NULL){ NW_FATAL_ERROR("Dont have AnimGroup");; } // アニメーションをバインドします。 m_AnimEvaluatorArray[animEvaluatorNo]->Release(); bool bindResult = m_AnimEvaluatorArray[animEvaluatorNo]->Bind(animGroup); // アニメーションをモデルに登録します。 m_SkeletalModel->SetSkeletalAnimObject(m_AnimEvaluatorArray[animEvaluatorNo]); // 番号を保持 m_CurrentAnimEvNo = animEvaluatorNo; return true; } //---------------------------------------- // アニメーションフレームを設定する void SmModel::SetAnimationFrame( f32 setFrame ) { m_AnimationFrame = setFrame; if ( m_CurrentAnimEvNo == -1 ) return; // 非表示であればアニメーションは更新しません if ( !this->IsVisible() ) return; // フレーム数をセット m_AnimEvaluatorArray[m_CurrentAnimEvNo]->SetFrame(m_AnimationFrame); } //---------------------------------------- // アニメーションフレームを進める // 最終フレームに到達した場合は、trueを返す bool SmModel::AddAnimationFrame( f32 addFrame, bool loop ) { bool ret = false; m_AnimationFrame += addFrame; if ( m_CurrentAnimEvNo == -1 ) return ret; // 最終フレームで固定 f32 endFrame = m_AnimEvaluatorArray[m_CurrentAnimEvNo]->AnimFrameController().GetEndFrame(); if ( m_AnimationFrame > endFrame ) { if ( loop ) { m_AnimationFrame = 0.f; } else { m_AnimationFrame = endFrame; } ret = true; } // 非表示であればアニメーションは更新しません if ( !this->IsVisible() ) return ret; // フレーム数をセットします m_AnimEvaluatorArray[m_CurrentAnimEvNo]->SetFrame(m_AnimationFrame); return ret; } //---------------------------------------- // アニメーションフレームを取得する f32 SmModel::GetAnimationFrame() const { return m_AnimationFrame; } //---------------------------------------- // 設定されているアニメーションの最大フレームを取得する f32 SmModel::GetAnimationMaxFrame() const { if ( m_CurrentAnimEvNo == -1 ) return 0.f; return m_AnimEvaluatorArray[m_CurrentAnimEvNo]->AnimFrameController().GetEndFrame(); } //---------------------------------------- // マテリアルアニメーションを設定する bool SmModel::SetMaterialAnim( nw::gfx::AnimEvaluator* animEvaluator ) { nw::gfx::AnimGroup* animGroup = m_Model->GetMaterialAnimGroup(); if ( !animGroup ) return false; bool bindResult = animEvaluator->Bind( animGroup ); if ( !bindResult ) return false; // アニメーションをモデルに登録します。 m_Model->SetMaterialAnimObject( animEvaluator ); return true; } //---------------------------------------- // 親のノードIDを指定する void SmModel::SetConstrainId( s32 boneId ) { m_CostrainId = boneId; nw::gfx::TransformNode* transformNode = nw::ut::DynamicCast(m_pSceneNode); NW_NULL_ASSERT(transformNode); // -1 でキャンセル if ( m_CostrainId == -1 ) { // FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED フラグを立てる transformNode->Transform().EnableFlags(nw::gfx::CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED); transformNode->Transform().DisableFlags(nw::gfx::CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED); } else { // FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED フラグを下げる transformNode->Transform().DisableFlags(nw::gfx::CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED); transformNode->Transform().EnableFlags(nw::gfx::CalculatedTransform::FLAG_IS_WORLDMATRIX_CALCULATION_ENABLED); } } //---------------------------------------- // 親子継承を解決 void SmModel::updateConstrain() { if ( m_CostrainId == -1 ) return; // 親が骨構造を持つか? nw::gfx::SkeletalModel* pParentSkeletalModel = nw::ut::DynamicCast(m_pParentNode); if ( pParentSkeletalModel ) { // Skeleton を取得 nw::gfx::Skeleton* pSkeleton = pParentSkeletalModel->GetSkeleton(); NW_NULL_ASSERT(pSkeleton); nw::gfx::Skeleton::TransformPose& transformPose = pSkeleton->WorldTransformPose(); // nw::gfx::Skeleton::TransformPose& transformPose = pSkeleton->LocalTransformPose(); if ( transformPose.GetBonesCount() < m_CostrainId ) return; // 指定ノードのマトリクスを取得して、自分にワールドマトリクスへセットする nw::gfx::Skeleton::TransformPose::Transform* transForm = transformPose.GetTransform( m_CostrainId ); // this->SetWorldMatrix( &transForm->TransformMatrix() ); this->SetMatrix( &transForm->TransformMatrix() ); } else { // 骨なしの場合は何もしない } } //---------------------------------------- // テスト機能 // モデル内メッシュを0~1で表示/非表示する void SmModel::SetVisibleZone( f32 term ) { if ( !m_SkeletalModel ) return; nw::gfx::ResMeshArray meshArray = m_SkeletalModel->GetResMeshes(); s32 visibleNum = meshArray.size() * term; for ( int i = 0; i < meshArray.size(); i++ ) { if ( i < visibleNum ) { meshArray[i].SetVisible( true ); } else { meshArray[i].SetVisible( false ); } } } } // namespace