/*---------------------------------------------------------------------------* Project: NintendoWare File: SmCamera.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/SmCamera.h" namespace { // Viewerから拝借したカメラ情報構造体 CameraInfo::CameraInfo() { Fovy = 37.8f; Near = 0.05f; Far = 10000.0f; RotationInit = 0.05f; RotationStep = 0.0f; RotationMax = 0.1f; TranslationInit = 0.004f; TranslationStep = 0.001f; TranslationMax = 0.01f; TiltInit = 0.005f; DollyInit = 0.01f; TumbleXInverse = false; TumbleYInverse = false; TrackXInverse = false; TrackYInverse = false; DollyInverse = false; DollyTargetInverse = false; TiltXInverse = false; TiltYInverse = false; } //---------------------------------------- // コンストラクタ SmCamera::SmCamera( nw::gfx::SceneNode* parent, nw::gfx::Camera* camera ) : SmMessage(NULL), m_Parent(parent), m_Camera(camera), m_PadCamera(NULL), m_PadCameraAttached(false), m_IsAnimPlaying(true), m_AnimationFrame(0.f), m_CurrentAnimEvNo(0), mRotation(0.0f), mTranslation(0.0f), mTouchPanelX(0), mTouchPanelY(0), m_IsGrab(false) { NW_NULL_ASSERT( parent ); // 初期値 m_Position.x = 30.f; m_Position.y = 25.f; m_Position.z = 120.f; m_Target.x = 0.f; m_Target.y = 0.f; m_Target.z = 20.f; // カメラズームインアウト用のコリジョン m_Collision.SetRect( 0, 40, 100, 280 ); // カメラをセット if ( m_Camera ) { this->SetGxCamera( m_Camera ); } // パッド用カメラを生成します。 { nw::math::VEC3 mCameraPos; nw::math::VEC3 mCameraTarget; nw::math::VEC3 mCameraUp; mCameraPos.Set( 0.0f, 0.0f, 50.f ); mCameraTarget.Set( 0.0f, 0.0f, 0.f ); mCameraUp.Set( 0.0f, 1.0f, 0.f ); // カメラの生成 nw::os::IAllocator* pAllocator = m_Allocator; nw::gfx::LookAtTargetViewUpdater* viewUpdater = nw::gfx::LookAtTargetViewUpdater::Create(pAllocator); nw::gfx::ResLookAtTargetViewUpdater resViewUpdater = nw::gfx::ResStaticCast(viewUpdater->GetResource()); resViewUpdater.SetTargetPosition(mCameraTarget); resViewUpdater.SetUpwardVector(mCameraUp); nw::gfx::PerspectiveProjectionUpdater* projectionUpdater = nw::gfx::PerspectiveProjectionUpdater::Create(pAllocator); nw::gfx::ResPerspectiveProjectionUpdater resProjectionUpdater = nw::gfx::ResStaticCast( projectionUpdater->GetResource()); resProjectionUpdater.SetNear(0.1f); resProjectionUpdater.SetFar(1000.0f); resProjectionUpdater.SetFovy(0.821342f);//NW_MATH_DEG_TO_RAD(60.0f)); m_PadCamera = nw::gfx::Camera::DynamicBuilder() .MaxChildren(0) .MaxCallbacks(0) .ViewUpdater(viewUpdater) .ProjectionUpdater(projectionUpdater) .Create(pAllocator); m_PadCamera->Transform().SetTranslate(mCameraPos); m_PadCamera->SetWScale(1.f/1000.0f); // パッドカメラをアタッチする。 m_Parent->AttachChild(m_PadCamera); m_PadCameraAttached = true; } m_CameraAnimEvaluatorArray.clear(); } //---------------------------------------- // デストラクタ SmCamera::~SmCamera() { } //---------------------------------------- // カメラセット void SmCamera::SetGxCamera( nw::gfx::Camera* camera ) { NW_NULL_ASSERT( camera ); NW_ASSERT( !m_Camera ); // パッドカメラをデタッチする m_PadCameraAttached = false; // アサインされたカメラをアタッチする m_Camera = camera; m_Parent->AttachChild( camera ); // パッドカメラにwScaleと画角を継承させる // f32 wScale = camera->GetWScale(); // m_PadCamera->SetWScale( wScale ); } //---------------------------------------- // カメラを取得します。 nw::gfx::Camera* SmCamera::GetGxCamera() { if (m_PadCameraAttached) { return m_PadCamera; } else { return m_Camera; } } //---------------------------------------- // アニメーション設定解除する bool SmCamera::DetachAnimEvaluator() { if ( m_CurrentAnimEvNo >= GetAnimEvaluatorNum() ) return false; if ( !m_Camera ) return false; m_CameraAnimEvaluatorArray[m_CurrentAnimEvNo]->Release(); m_Camera->SetAnimObject( NULL ); m_CurrentAnimEvNo = -1; return true; } //---------------------------------------- // アニメーションを追加する void SmCamera::AddAnimEvaluator( nw::gfx::AnimEvaluator* animEvaluator ) { m_CameraAnimEvaluatorArray.push_back( animEvaluator ); } //---------------------------------------- // アニメーション数を取得する uint SmCamera::GetAnimEvaluatorNum() const { return m_CameraAnimEvaluatorArray.size(); } //---------------------------------------- // アニメーションを設定する bool SmCamera::SetAnimEvaluatorNo( uint animEvaluatorNo ) { if ( animEvaluatorNo >= GetAnimEvaluatorNum() ) return false; if ( !m_Camera ) return false; nw::gfx::AnimGroup* animGroup = m_Camera->GetAnimGroup(); // if (animGroup == NULL){ NW_FATAL_ERROR("Dont have AnimGroup");; } if (animGroup == NULL){ NW_DEV_LOG("SmCamera:Dont have AnimGroup"); } // アニメーションをバインドします。 m_CameraAnimEvaluatorArray[animEvaluatorNo]->Release(); bool bindResult = m_CameraAnimEvaluatorArray[animEvaluatorNo]->Bind(animGroup); // アニメーションをカメラに登録します。 m_Camera->SetAnimObject(m_CameraAnimEvaluatorArray[animEvaluatorNo]); // 番号を保持 m_CurrentAnimEvNo = animEvaluatorNo; return true; } //---------------------------------------- // アニメーションフレームを設定する void SmCamera::SetAnimationFrame( f32 setFrame ) { if ( m_CurrentAnimEvNo >= GetAnimEvaluatorNum() ) return; if ( !m_Camera ) return; m_AnimationFrame = setFrame; if ( m_CurrentAnimEvNo == -1 ) return; // フレーム数をセット m_CameraAnimEvaluatorArray[m_CurrentAnimEvNo]->SetFrame(m_AnimationFrame); } //---------------------------------------- // アニメーションフレームを進める // 最終フレームに到達した場合は、trueを返す bool SmCamera::AddAnimationFrame( f32 addFrame, bool loop ) { if ( m_CurrentAnimEvNo >= GetAnimEvaluatorNum() ) return false; if ( !m_Camera ) return false; bool ret = false; m_AnimationFrame += addFrame; // 最終フレームで固定 f32 endFrame = m_CameraAnimEvaluatorArray[m_CurrentAnimEvNo]->AnimFrameController().GetEndFrame(); if ( m_AnimationFrame > endFrame ) { if ( loop ) { m_AnimationFrame = 0.f; } else { m_AnimationFrame = endFrame; } ret = true; } // フレーム数をセット m_CameraAnimEvaluatorArray[m_CurrentAnimEvNo]->SetFrame(m_AnimationFrame); return ret; } //---------------------------------------- // アニメーションフレームを取得する f32 SmCamera::GetAnimationFrame() const { return m_AnimationFrame; } //---------------------------------------- // メッセージ受信 bool SmCamera::ReceveMessage( SmMessageType type, void* object, uint targetId ) { NW_UNUSED_VARIABLE(targetId); SmTouchPanelStatus* touchPanelStaus = NULL; switch( type ) { case SM_MESSAGE_PAD_UPDATE: { SmPadStatus* padStaus = static_cast(object); // スタートボタンでカメラアニメーションのオンオフ if ( padStaus->IsTrigger( SmPadStatus::SM_BUTTON_START ) ) { if (m_PadCameraAttached) { m_PadCameraAttached = false; } else { m_PadCameraAttached = true; } } if (m_PadCameraAttached) { MoveCamera3D( padStaus, NULL ); } } break; case SM_MESSAGE_TUCHPANEL_PRESS: { if (!m_PadCameraAttached) break; touchPanelStaus = static_cast(object); NW_NULL_ASSERT( touchPanelStaus ); if ( m_Collision.CheckInner( touchPanelStaus->GetX(), touchPanelStaus->GetY() ) ) { // 他処理で使用中でなければ if ( !touchPanelStaus->IsGrab() ) { // 掴む touchPanelStaus->Grab(); m_IsGrab = true; } } } break; case SM_MESSAGE_TUCHPANEL_MOTION: { if (!m_PadCameraAttached) break; touchPanelStaus = static_cast(object); NW_NULL_ASSERT( touchPanelStaus ); MoveCamera3D( NULL, touchPanelStaus ); } break; case SM_MESSAGE_TUCHPANEL_RELEASE: { touchPanelStaus = static_cast(object); NW_NULL_ASSERT( touchPanelStaus ); // 放す if ( m_IsGrab ) { touchPanelStaus->UnGrab(); m_IsGrab = false; mTouchPanelX = -1; mTouchPanelY = -1; } } break; default: break; } return false; } //---------------------------------------- // カメラマトリクスを更新する void SmCamera::UpdateMatrix() { m_Camera->UpdateCameraMatrix(); m_PadCamera->UpdateCameraMatrix(); } //---------------------------------------- // Viewerと同カメラ操作 void SmCamera::MoveCamera3D( SmPadStatus* padStatus, SmTouchPanelStatus* panelStatus ) { nw::gfx::Camera* camera = m_PadCamera; f32 stickX = 0.0f; f32 stickY = 0.0f; f32 lookatX = 0.0f; f32 lookatY = 0.0f; f32 expansion = 0.0f; f32 translationX = 0.0f; f32 translationY = 0.0f; f32 tiltX = 0.0f; f32 tiltY = 0.0f; if (padStatus) { stickX = padStatus->GetStickX(); stickY = padStatus->GetStickY(); if (stickX != 0.0f || stickY != 0.0f) { lookatX =mRotation * stickX; lookatY =mRotation * stickY; mRotation += mCameraInfo.RotationStep; if (mRotation > mCameraInfo.RotationMax) { mRotation = mCameraInfo.RotationMax; } } else { mRotation = mCameraInfo.RotationInit; mTranslation = mCameraInfo.TranslationInit; } } // タッチパッドでの前後移動処理 if (m_IsGrab && panelStatus) { u16 x = panelStatus->GetX(); u16 y = panelStatus->GetY(); const u16 width = 320 / 5; // 下液晶幅320の1/5を使用 64pixel if (x < width) { if (-1 != mTouchPanelY) { int trans = y-mTouchPanelY; expansion -= trans; } }else{ if (-1 != mTouchPanelX && -1 != mTouchPanelY) { int rotX = x-mTouchPanelX; int rotY = y-mTouchPanelY; tiltX = rotX * mCameraInfo.TiltInit; tiltY = rotY * mCameraInfo.TiltInit; } } mTouchPanelX = x; mTouchPanelY = y; } // 操作系の反転処理 if (mCameraInfo.TumbleXInverse) { lookatX = -lookatX; } if (mCameraInfo.TumbleYInverse) { lookatY = -lookatY; } if (mCameraInfo.TrackXInverse) { translationX = -translationX; } if (mCameraInfo.TrackYInverse) { translationY = -translationY; } if (mCameraInfo.TiltXInverse) { tiltX = -tiltX; } if (mCameraInfo.TiltYInverse) { tiltY = -tiltY; } nw::gfx::LookAtTargetViewUpdater* viewUpdater = nw::ut::DynamicCast(camera->GetViewUpdater()); nw::gfx::ResLookAtTargetViewUpdater resViewUpdater = nw::gfx::ResStaticCast(viewUpdater->GetResource()); nw::math::VEC3 position; camera->Transform().GetTranslate(&position); nw::math::VEC3 direction = resViewUpdater.GetTargetPosition() - position; nw::math::VEC3Normalize(&direction, &direction); nw::math::VEC3 right; nw::math::VEC3Cross(&right, &resViewUpdater.GetUpwardVector(), &direction); nw::math::VEC3Normalize(&right, &right); // 回転 if (lookatX != 0.0f || lookatY != 0.0f) { nw::math::VEC3 translate; camera->Transform().GetTranslate(&translate); translate -= resViewUpdater.GetTargetPosition(); nw::math::MTX34 rotateV; nw::math::MTX34 rotateH; MTX34RotAxisRad(&rotateV, &right, lookatY); MTX34RotXYZRad(&rotateH, 0.0f, lookatX, 0.0f); VEC3Transform(&translate, &rotateH, &translate); VEC3Transform(&translate, &rotateV, &translate); translate += resViewUpdater.GetTargetPosition(); camera->Transform().SetTranslate(translate); nw::math::VEC3 upVector; VEC3Transform( &upVector, &rotateH, &resViewUpdater.GetUpwardVector()); VEC3Transform( &upVector, &rotateV, &upVector); // 回転後のY軸とZ軸からX軸を算出 VEC3Cross(&right,&upVector,&direction); // X軸ベクトルのy成分を0にし、正規化することでカメラを水平に保つ right.y = 0.0f; nw::math::VEC3Normalize(&right, &right); // 新しいZ軸とX軸からY軸を算出 VEC3Cross(&upVector,&direction,&right); resViewUpdater.SetUpwardVector(upVector); } if (expansion != 0.0f) { // 注視点とともに前後移動 /* if (padStatus.hold & nn::hid::CTR::BUTTON_L) { if (mCameraInfo.DollyTargetInverse) { expansion = -expansion; } nw::math::VEC3 translate = expansion * direction * VEC3Len(resViewUpdater.GetTargetPosition() - position) * mCameraInfo.DollyInit; resViewUpdater.SetTargetPosition( resViewUpdater.GetTargetPosition() + translate); nw::math::VEC3 pos; camera->Transform().GetTranslate(&pos); pos += translate; camera->Transform().SetTranslate(pos); } else */ { if (mCameraInfo.DollyInverse) { expansion = -expansion; } // ドリー(前後移動) nw::math::VEC3 translate; camera->Transform().GetTranslate(&translate); translate += expansion * direction * VEC3Len(resViewUpdater.GetTargetPosition() - translate) * mCameraInfo.DollyInit; camera->Transform().SetTranslate(translate); } } // 首ふり回転(tilt) if (tiltX != 0.0f || tiltY != 0.0f) { nw::math::VEC3 translate; camera->Transform().GetTranslate(&translate); translate = resViewUpdater.GetTargetPosition() - translate; nw::math::MTX34 rotateV; nw::math::MTX34 rotateH; MTX34RotAxisRad(&rotateV, &right, tiltY); MTX34RotXYZRad(&rotateH, 0.0f, -tiltX, 0.0f); VEC3Transform(&translate, &rotateH, &translate); VEC3Transform(&translate, &rotateV, &translate); nw::math::VEC3 upVector, targetPos; VEC3Transform( &upVector, &rotateH, &resViewUpdater.GetUpwardVector()); VEC3Transform( &upVector, &rotateV, &upVector); VEC3Cross(&right,&upVector,&direction); right.y = 0.0f; nw::math::VEC3Normalize(&right, &right); VEC3Cross(&upVector,&direction,&right); resViewUpdater.SetUpwardVector(upVector); nw::math::VEC3 pos; camera->Transform().GetTranslate(&pos); targetPos = translate + pos; resViewUpdater.SetTargetPosition(targetPos); } // トラック(平行移動) if (translationX != 0.0f || translationY != 0.0f) { resViewUpdater.SetTargetPosition( resViewUpdater.GetTargetPosition() + right * translationX + resViewUpdater.GetUpwardVector() * translationY); nw::math::VEC3 translate; camera->Transform().GetTranslate(&translate); translate += right * translationX + resViewUpdater.GetUpwardVector() * translationY; camera->Transform().SetTranslate(translate); } } } // namespace