/*---------------------------------------------------------------------------* Project: NintendoWare File: demo_CameraController.cpp Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. 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. The content herein is highly confidential and should be handled accordingly. $Revision: $ *---------------------------------------------------------------------------*/ #include #include #include namespace nw { namespace demo { //---------------------------------------- const f32 CameraController::CameraEntry::DOLLY_SPEED_BASE = 30.0f / 60.0f; const f32 CameraController::CameraEntry::TUMBLE_SPEED = 128.0f / 60.0f; const f32 CameraController::CameraEntry::MOVE_SPEED_BASE = 5.0f / 60.0f; const f32 CameraController::CameraEntry::ROTATE_X_LIMIT = 64.f - TUMBLE_SPEED; const f32 CameraController::CameraEntry::DEFAULT_DISTANCE = 10.0f; //---------------------------------------- CameraController* CameraController::Builder::Create( os::IAllocator* allocator ) { NW_POINTER_ASSERT(allocator); void* memory = allocator->Alloc(sizeof(CameraController)); NW_POINTER_ASSERT(memory); CameraController* demoCamera = new(memory) CameraController(allocator, m_Description); return demoCamera; } //---------------------------------------- CameraController::CameraController( os::IAllocator* allocator, const Description& description ) : m_Allocator(allocator), m_Description(description), m_UsagePrinted(false) { NW_POINTER_ASSERT(allocator); m_CameraEntries = nw::ut::MoveArray( m_Description.maxCameraCount, allocator, nw::ut::ARRAY_WRAPPER); m_CameraEntries.Assign(m_Description.maxCameraCount, NULL); } //---------------------------------------- CameraController::~CameraController() { for (nw::ut::MoveArray::iterator cameraEntry = m_CameraEntries.begin(); cameraEntry != m_CameraEntries.end(); ++cameraEntry) { if (*cameraEntry) { (*cameraEntry)->~CameraEntry(); m_Allocator->Free(*cameraEntry); } } } //---------------------------------------- void CameraController::Destroy() { os::IAllocator* allocator = m_Allocator; this->~CameraController(); allocator->Free(this); } //---------------------------------------- void CameraController::Register( nw::gfx::Camera* camera, unsigned int cameraIndex ) { NW_MINMAXLT_ASSERT(cameraIndex, 0, m_Description.maxCameraCount); NW_POINTER_ASSERT(camera); void* memory = m_Allocator->Alloc(sizeof(CameraEntry)); NW_POINTER_ASSERT(memory); NW_ASSERT(m_CameraEntries[cameraIndex] == NULL); m_CameraEntries[cameraIndex] = new(memory) CameraEntry(camera); if (!m_UsagePrinted) { m_UsagePrinted = true; NW_LOG("[camera controller usage]\n"); NW_LOG("stick : rotation\n"); NW_LOG("stick + a : forward / backward\n"); NW_LOG("stick + b : translation\n"); NW_LOG("stick + y : upward / downward\n"); NW_LOG("x : reset\n"); } } //---------------------------------------- void CameraController::Update(unsigned int cameraIndex) { NW_MINMAXLT_ASSERT(cameraIndex, 0, m_Description.maxCameraCount); NW_POINTER_ASSERT(m_CameraEntries[cameraIndex]); m_CameraEntries[cameraIndex]->Update(); } //---------------------------------------- CameraController::CameraEntry::CameraEntry( nw::gfx::Camera* camera ) : m_Camera(camera) { NW_POINTER_ASSERT(camera); nw::gfx::ResCameraViewUpdater resViewUpdater = m_Camera->GetViewUpdater()->GetResource(); nw::gfx::ResAimTargetViewUpdater resAimTargetViewUpdater = nw::gfx::ResDynamicCast(resViewUpdater); nw::gfx::ResLookAtTargetViewUpdater resLookAtTargetViewUpdater = nw::gfx::ResDynamicCast(resViewUpdater); nw::gfx::ResRotateViewUpdater resRotateViewUpdater = nw::gfx::ResDynamicCast(resViewUpdater); // TODO: 除数が0に近いときを考慮していないので対策する nw::math::VEC3 cameraPos; m_Camera->Transform().GetTranslate(&cameraPos); if (resAimTargetViewUpdater.IsValid()) { m_TargetPos = resAimTargetViewUpdater.GetTargetPosition(); m_TargetDistance = nw::math::VEC3Dist(m_TargetPos, cameraPos); const nw::math::VEC3 lookReverse = (cameraPos - m_TargetPos) / m_TargetDistance; m_Rotate.x = nw::math::AsinFIdx(-lookReverse.y); m_Rotate.y = nw::math::Atan2FIdx(-lookReverse.x, lookReverse.z); m_Rotate.z = resAimTargetViewUpdater.GetTwist(); } else if (resLookAtTargetViewUpdater.IsValid()) { m_TargetPos = resLookAtTargetViewUpdater.GetTargetPosition(); m_TargetDistance = nw::math::VEC3Dist(m_TargetPos, cameraPos); const nw::math::VEC3 lookReverse = (cameraPos - m_TargetPos) / m_TargetDistance; m_Rotate.x = nw::math::AsinFIdx(-lookReverse.y); m_Rotate.y = nw::math::Atan2FIdx(-lookReverse.x, lookReverse.z); m_Rotate.z = 0.0f; } else if (resRotateViewUpdater.IsValid()) { m_Rotate = resRotateViewUpdater.GetViewRotate(); m_TargetDistance = DEFAULT_DISTANCE; f32 xs = nw::math::SinFIdx(m_Rotate.x); f32 xc = nw::math::CosFIdx(m_Rotate.x); f32 ys = nw::math::SinFIdx(m_Rotate.y); f32 yc = nw::math::CosFIdx(m_Rotate.y); m_TargetPos.x = cameraPos.x + m_TargetDistance * xc * ys; m_TargetPos.y = cameraPos.y + m_TargetDistance * xs; m_TargetPos.z = cameraPos.z - m_TargetDistance * xc * yc; } else { NW_FATAL_ERROR("Invalid type of resource view updater"); } m_InitialRotate = m_Rotate; m_InitialTargetPos = m_TargetPos; m_InitialTargetDistance = m_TargetDistance; } //---------------------------------------- void CameraController::CameraEntry::Update() { nw::demo::Pad* pad = nw::demo::PadFactory::GetPad(); const nw::math::VEC2 stick = pad->GetAnalogStick(); if ( pad->IsButtonPress(nw::demo::Pad::BUTTON_X) ) { m_Rotate = m_InitialRotate; m_TargetPos = m_InitialTargetPos; m_TargetDistance = m_InitialTargetDistance; } else if (stick.x != 0.0f || stick.y != 0.0f) { if ( pad->IsButtonPress(nw::demo::Pad::BUTTON_A) ) { f32 dollySpeed = DOLLY_SPEED_BASE * nw::math::FSqrt(nw::math::FAbs(m_TargetDistance)); m_TargetDistance -= (stick.x + stick.y) * dollySpeed; } else if ( pad->IsButtonPress(nw::demo::Pad::BUTTON_B) ) { f32 moveSpeed = MOVE_SPEED_BASE * nw::math::FSqrt(nw::math::FAbs(m_TargetDistance)); nw::math::VEC3 dScreen(stick.x * moveSpeed, 0.0f, -stick.y * moveSpeed); nw::math::VEC3 dWorld; nw::math::MTX34 screenToWorld; nw::math::MTX34RotXYZDeg(&screenToWorld, 0.0f, m_Rotate.y, m_Rotate.z); nw::math::VEC3TransformNormal(&dWorld, &screenToWorld, &dScreen); m_TargetPos.x += dWorld.x; m_TargetPos.z += dWorld.z; } else if ( pad->IsButtonPress(nw::demo::Pad::BUTTON_Y) ) { f32 moveSpeed = MOVE_SPEED_BASE * nw::math::FSqrt(nw::math::FAbs(m_TargetDistance)); m_TargetPos.y += (stick.x + stick.y); } else { m_Rotate.x += stick.y * TUMBLE_SPEED; m_Rotate.y += stick.x * TUMBLE_SPEED; m_Rotate.x = nw::ut::Clamp(m_Rotate.x, -ROTATE_X_LIMIT, ROTATE_X_LIMIT); } } UpdateCamera(); } //---------------------------------------- void CameraController::CameraEntry::UpdateCamera() { nw::gfx::ResCameraViewUpdater resViewUpdater = m_Camera->GetViewUpdater()->GetResource(); nw::gfx::ResAimTargetViewUpdater resAimTargetViewUpdater = nw::gfx::ResDynamicCast(resViewUpdater); nw::gfx::ResLookAtTargetViewUpdater resLookAtTargetViewUpdater = nw::gfx::ResDynamicCast(resViewUpdater); nw::gfx::ResRotateViewUpdater resRotateViewUpdater = nw::gfx::ResDynamicCast(resViewUpdater); if (resAimTargetViewUpdater.IsValid()) { resAimTargetViewUpdater.SetTargetPosition(m_TargetPos); resAimTargetViewUpdater.SetTwist(m_Rotate.z); } else if (resLookAtTargetViewUpdater.IsValid()) { resLookAtTargetViewUpdater.SetTargetPosition(m_TargetPos); } else if (resRotateViewUpdater.IsValid()) { resRotateViewUpdater.SetViewRotate(m_Rotate); } else { NW_FATAL_ERROR("Invalid type of resource view updater"); } f32 xs = nw::math::SinFIdx(m_Rotate.x); f32 xc = nw::math::CosFIdx(m_Rotate.x); f32 ys = nw::math::SinFIdx(m_Rotate.y); f32 yc = nw::math::CosFIdx(m_Rotate.y); m_Camera->Transform().SetTranslate(nw::math::VEC3( m_TargetPos.x - m_TargetDistance * xc * ys, m_TargetPos.y - m_TargetDistance * xs, m_TargetPos.z + m_TargetDistance * xc * yc )); } } // namespace nw::demo } // namespace nw