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