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