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