1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     demo_CameraController.cpp
4 
5   Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc.  All rights reserved.
6 
7   These coded instructions, statements, and computer programs contain proprietary
8   information of Nintendo and/or its licensed developers and are protected by
9   national and international copyright laws. They may not be disclosed to third
10   parties or copied or duplicated in any form, in whole or in part, without the
11   prior written consent of Nintendo.
12 
13   The content herein is highly confidential and should be handled accordingly.
14 
15   $Revision: $
16  *---------------------------------------------------------------------------*/
17 
18 #include <nw/demo/demo_CameraController.h>
19 #include <nw/demo/demo_Pad.h>
20 
21 #include <nn/os.h>
22 
23 
24 namespace nw
25 {
26 namespace demo
27 {
28 
29 //----------------------------------------
30 const f32 CameraController::CameraEntry::DOLLY_SPEED_BASE = 30.0f / 60.0f;
31 const f32 CameraController::CameraEntry::TUMBLE_SPEED = 128.0f / 60.0f;
32 const f32 CameraController::CameraEntry::MOVE_SPEED_BASE = 5.0f / 60.0f;
33 const f32 CameraController::CameraEntry::ROTATE_X_LIMIT = 64.f - TUMBLE_SPEED;
34 const f32 CameraController::CameraEntry::DEFAULT_DISTANCE = 10.0f;
35 
36 //----------------------------------------
37 CameraController*
Create(os::IAllocator * allocator)38 CameraController::Builder::Create(
39     os::IAllocator* allocator
40 )
41 {
42     NW_POINTER_ASSERT(allocator);
43 
44     void* memory = allocator->Alloc(sizeof(CameraController));
45     NW_POINTER_ASSERT(memory);
46 
47     CameraController* demoCamera =
48         new(memory) CameraController(allocator, m_Description);
49 
50     return demoCamera;
51 }
52 
53 //----------------------------------------
CameraController(os::IAllocator * allocator,const Description & description)54 CameraController::CameraController(
55     os::IAllocator* allocator,
56     const Description& description
57 )
58 : m_Allocator(allocator),
59   m_Description(description),
60   m_UsagePrinted(false)
61 {
62     NW_POINTER_ASSERT(allocator);
63 
64     m_CameraEntries = nw::ut::MoveArray<CameraEntry*>(
65         m_Description.maxCameraCount, allocator, nw::ut::ARRAY_WRAPPER);
66     m_CameraEntries.Assign(m_Description.maxCameraCount, NULL);
67 }
68 
69 //----------------------------------------
~CameraController()70 CameraController::~CameraController()
71 {
72     for (nw::ut::MoveArray<CameraEntry*>::iterator cameraEntry = m_CameraEntries.begin();
73         cameraEntry != m_CameraEntries.end(); ++cameraEntry)
74     {
75         if (*cameraEntry)
76         {
77             (*cameraEntry)->~CameraEntry();
78             m_Allocator->Free(*cameraEntry);
79         }
80     }
81 }
82 
83 //----------------------------------------
84 void
Destroy()85 CameraController::Destroy()
86 {
87     os::IAllocator* allocator = m_Allocator;
88 
89     this->~CameraController();
90     allocator->Free(this);
91 }
92 
93 
94 //----------------------------------------
95 void
Register(nw::gfx::Camera * camera,unsigned int cameraIndex)96 CameraController::Register(
97     nw::gfx::Camera* camera,
98     unsigned int cameraIndex
99 )
100 {
101     NW_MINMAXLT_ASSERT(cameraIndex, 0, m_Description.maxCameraCount);
102     NW_POINTER_ASSERT(camera);
103 
104     void* memory = m_Allocator->Alloc(sizeof(CameraEntry));
105     NW_POINTER_ASSERT(memory);
106 
107     NW_ASSERT(m_CameraEntries[cameraIndex] == NULL);
108     m_CameraEntries[cameraIndex] = new(memory) CameraEntry(camera);
109 
110     if (!m_UsagePrinted)
111     {
112         m_UsagePrinted = true;
113         NW_LOG("[camera controller usage]\n");
114         NW_LOG("stick     : rotation\n");
115         NW_LOG("stick + a : forward / backward\n");
116         NW_LOG("stick + b : translation\n");
117         NW_LOG("stick + y : upward / downward\n");
118         NW_LOG("x         : reset\n");
119     }
120 }
121 
122 //----------------------------------------
123 void
Update(unsigned int cameraIndex)124 CameraController::Update(unsigned int cameraIndex)
125 {
126     NW_MINMAXLT_ASSERT(cameraIndex, 0, m_Description.maxCameraCount);
127     NW_POINTER_ASSERT(m_CameraEntries[cameraIndex]);
128 
129     m_CameraEntries[cameraIndex]->Update();
130 }
131 
132 //----------------------------------------
CameraEntry(nw::gfx::Camera * camera)133 CameraController::CameraEntry::CameraEntry(
134     nw::gfx::Camera* camera
135 )
136 : m_Camera(camera)
137 {
138     NW_POINTER_ASSERT(camera);
139 
140     nw::gfx::ResCameraViewUpdater resViewUpdater = m_Camera->GetViewUpdater()->GetResource();
141 
142     nw::gfx::ResAimTargetViewUpdater resAimTargetViewUpdater =
143         nw::gfx::ResDynamicCast<nw::gfx::ResAimTargetViewUpdater>(resViewUpdater);
144     nw::gfx::ResLookAtTargetViewUpdater resLookAtTargetViewUpdater =
145         nw::gfx::ResDynamicCast<nw::gfx::ResLookAtTargetViewUpdater>(resViewUpdater);
146     nw::gfx::ResRotateViewUpdater resRotateViewUpdater =
147         nw::gfx::ResDynamicCast<nw::gfx::ResRotateViewUpdater>(resViewUpdater);
148 
149     // TODO: 除数が0に近いときを考慮していないので対策する
150     nw::math::VEC3 cameraPos;
151     m_Camera->Transform().GetTranslate(&cameraPos);
152     if (resAimTargetViewUpdater.IsValid())
153     {
154         m_TargetPos = resAimTargetViewUpdater.GetTargetPosition();
155         m_TargetDistance = nw::math::VEC3Dist(m_TargetPos, cameraPos);
156 
157         const nw::math::VEC3 lookReverse = (cameraPos - m_TargetPos) / m_TargetDistance;
158         m_Rotate.x = nw::math::AsinFIdx(-lookReverse.y);
159         m_Rotate.y = nw::math::Atan2FIdx(-lookReverse.x, lookReverse.z);
160         m_Rotate.z = resAimTargetViewUpdater.GetTwist();
161     }
162     else if (resLookAtTargetViewUpdater.IsValid())
163     {
164         m_TargetPos = resLookAtTargetViewUpdater.GetTargetPosition();
165         m_TargetDistance = nw::math::VEC3Dist(m_TargetPos, cameraPos);
166 
167         const nw::math::VEC3 lookReverse = (cameraPos - m_TargetPos) / m_TargetDistance;
168         m_Rotate.x = nw::math::AsinFIdx(-lookReverse.y);
169         m_Rotate.y = nw::math::Atan2FIdx(-lookReverse.x, lookReverse.z);
170         m_Rotate.z = 0.0f;
171     }
172     else if (resRotateViewUpdater.IsValid())
173     {
174         m_Rotate = resRotateViewUpdater.GetViewRotate();
175         m_TargetDistance = DEFAULT_DISTANCE;
176 
177         f32 xs = nw::math::SinFIdx(m_Rotate.x);
178         f32 xc = nw::math::CosFIdx(m_Rotate.x);
179         f32 ys = nw::math::SinFIdx(m_Rotate.y);
180         f32 yc = nw::math::CosFIdx(m_Rotate.y);
181 
182         m_TargetPos.x = cameraPos.x + m_TargetDistance * xc * ys;
183         m_TargetPos.y = cameraPos.y + m_TargetDistance * xs;
184         m_TargetPos.z = cameraPos.z - m_TargetDistance * xc * yc;
185     }
186     else
187     {
188         NW_FATAL_ERROR("Invalid type of resource view updater");
189     }
190 
191     m_InitialRotate = m_Rotate;
192     m_InitialTargetPos = m_TargetPos;
193     m_InitialTargetDistance = m_TargetDistance;
194 }
195 
196 //----------------------------------------
197 void
Update()198 CameraController::CameraEntry::Update()
199 {
200     nw::demo::Pad* pad = nw::demo::PadFactory::GetPad();
201 
202     const nw::math::VEC2 stick = pad->GetAnalogStick();
203 
204     if ( pad->IsButtonPress(nw::demo::Pad::BUTTON_X) )
205     {
206         m_Rotate = m_InitialRotate;
207         m_TargetPos = m_InitialTargetPos;
208         m_TargetDistance = m_InitialTargetDistance;
209     }
210     else if (stick.x != 0.0f || stick.y != 0.0f)
211     {
212         if ( pad->IsButtonPress(nw::demo::Pad::BUTTON_A) )
213         {
214             f32 dollySpeed = DOLLY_SPEED_BASE * nw::math::FSqrt(nw::math::FAbs(m_TargetDistance));
215             m_TargetDistance -= (stick.x + stick.y) * dollySpeed;
216         }
217         else if ( pad->IsButtonPress(nw::demo::Pad::BUTTON_B) )
218         {
219             f32 moveSpeed = MOVE_SPEED_BASE * nw::math::FSqrt(nw::math::FAbs(m_TargetDistance));
220             nw::math::VEC3 dScreen(stick.x * moveSpeed, 0.0f, -stick.y * moveSpeed);
221             nw::math::VEC3 dWorld;
222             nw::math::MTX34 screenToWorld;
223 
224             nw::math::MTX34RotXYZDeg(&screenToWorld, 0.0f, m_Rotate.y, m_Rotate.z);
225             nw::math::VEC3TransformNormal(&dWorld, &screenToWorld, &dScreen);
226 
227             m_TargetPos.x += dWorld.x;
228             m_TargetPos.z += dWorld.z;
229         }
230         else if ( pad->IsButtonPress(nw::demo::Pad::BUTTON_Y) )
231         {
232             f32 moveSpeed = MOVE_SPEED_BASE * nw::math::FSqrt(nw::math::FAbs(m_TargetDistance));
233 
234             m_TargetPos.y += (stick.x + stick.y);
235         }
236         else
237         {
238             m_Rotate.x += stick.y * TUMBLE_SPEED;
239             m_Rotate.y += stick.x * TUMBLE_SPEED;
240 
241             m_Rotate.x = nw::ut::Clamp(m_Rotate.x, -ROTATE_X_LIMIT, ROTATE_X_LIMIT);
242         }
243     }
244 
245     UpdateCamera();
246 }
247 
248 //----------------------------------------
249 void
UpdateCamera()250 CameraController::CameraEntry::UpdateCamera()
251 {
252     nw::gfx::ResCameraViewUpdater resViewUpdater = m_Camera->GetViewUpdater()->GetResource();
253 
254     nw::gfx::ResAimTargetViewUpdater resAimTargetViewUpdater =
255         nw::gfx::ResDynamicCast<nw::gfx::ResAimTargetViewUpdater>(resViewUpdater);
256     nw::gfx::ResLookAtTargetViewUpdater resLookAtTargetViewUpdater =
257         nw::gfx::ResDynamicCast<nw::gfx::ResLookAtTargetViewUpdater>(resViewUpdater);
258     nw::gfx::ResRotateViewUpdater resRotateViewUpdater =
259         nw::gfx::ResDynamicCast<nw::gfx::ResRotateViewUpdater>(resViewUpdater);
260 
261     if (resAimTargetViewUpdater.IsValid())
262     {
263         resAimTargetViewUpdater.SetTargetPosition(m_TargetPos);
264         resAimTargetViewUpdater.SetTwist(m_Rotate.z);
265     }
266     else if (resLookAtTargetViewUpdater.IsValid())
267     {
268         resLookAtTargetViewUpdater.SetTargetPosition(m_TargetPos);
269     }
270     else if (resRotateViewUpdater.IsValid())
271     {
272         resRotateViewUpdater.SetViewRotate(m_Rotate);
273     }
274     else
275     {
276         NW_FATAL_ERROR("Invalid type of resource view updater");
277     }
278 
279 
280     f32 xs = nw::math::SinFIdx(m_Rotate.x);
281     f32 xc = nw::math::CosFIdx(m_Rotate.x);
282     f32 ys = nw::math::SinFIdx(m_Rotate.y);
283     f32 yc = nw::math::CosFIdx(m_Rotate.y);
284 
285     m_Camera->Transform().SetTranslate(nw::math::VEC3(
286         m_TargetPos.x - m_TargetDistance * xc * ys,
287         m_TargetPos.y - m_TargetDistance * xs,
288         m_TargetPos.z + m_TargetDistance * xc * yc
289     ));
290 }
291 
292 
293 } // namespace nw::demo
294 } // namespace nw
295