1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_Fog.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: 31311 $
16 *---------------------------------------------------------------------------*/
17
18 #include "precompiled.h"
19
20 #include <nw/os/os_Memory.h>
21
22 #include <nw/gfx/gfx_Fog.h>
23 #include <nw/gfx/gfx_ISceneVisitor.h>
24 #include <nw/gfx/gfx_Camera.h>
25
26 namespace nw
27 {
28 namespace gfx
29 {
30
31 NW_UT_RUNTIME_TYPEINFO_DEFINITION(Fog, TransformNode);
32 const float Fog::FOG_DENSITY = 0.0f;
33 const ResFogUpdater::FogUpdaterType Fog::FOG_UPDATER_TYPE = ResFogUpdater::FOG_UPDATER_TYPE_NONE;
34 const float Fog::FOG_MAX_DEPTH = 0.0f;
35 const float Fog::FOG_MIN_DEPTH = 0.0f;
36
37 //----------------------------------------
38 Fog*
Create(os::IAllocator * allocator)39 Fog::DynamicBuilder::Create(
40 os::IAllocator* allocator
41 )
42 {
43 NW_NULL_ASSERT(allocator);
44
45 ResPtr resource(
46 CreateResFog(allocator),
47 ResFogDataDestroyer(allocator));
48
49 void* memory = allocator->Alloc(sizeof(Fog));
50 NW_NULL_ASSERT(memory);
51 Fog* fog = new(memory) Fog(
52 allocator,
53 resource,
54 m_Description);
55 Result result = fog->Initialize(allocator);
56 NW_ASSERT(result.IsSuccess());
57
58 return fog;
59 }
60
61 //----------------------------------------------------------
62 size_t
GetMemorySize(size_t alignment) const63 Fog::DynamicBuilder::GetMemorySize( size_t alignment ) const
64 {
65 NW_ASSERT(this->m_Description.isFixedSizeMemory);
66
67 os::MemorySizeCalculator size(alignment);
68
69 // Fog::CreateResFox
70 size += sizeof(ResFogData);
71 size += sizeof(ResImageLookupTableData);
72 size += sizeof(ResFogUpdaterData);
73 size += sizeof(u32) * NW_FOG_TABLE_COMMAND_NUM;
74
75 size += sizeof(Fog);
76
77 // Fog::Initialize
78 TransformNode::GetMemorySizeForInitialize(
79 &size,
80 ResTransformNode(),
81 m_Description);
82
83 // Fog::CreateResFogUpdater
84 size += sizeof(ResFogUpdaterData);
85
86 // Fog::CreateAnimGroup
87 // DynamicBuilder 使用時には何も行なわれない。
88
89 // Fog::CreateOriginalValue
90 size += sizeof(ResFogData);
91
92 return size.GetSizeWithPadding(alignment);
93 }
94
95 //----------------------------------------
96 void
Accept(ISceneVisitor * visitor)97 Fog::Accept(
98 ISceneVisitor* visitor
99 )
100 {
101 visitor->VisitFog(this);
102 AcceptChildren(visitor);
103 }
104
105 //----------------------------------------
106 /* static */ Fog*
Create(SceneNode * parent,ResSceneObject resource,const Fog::Description & description,os::IAllocator * allocator)107 Fog::Create(
108 SceneNode* parent,
109 ResSceneObject resource,
110 const Fog::Description& description,
111 os::IAllocator* allocator
112 )
113 {
114 NW_NULL_ASSERT(allocator);
115
116 ResFog resNode = ResDynamicCast<ResFog>(resource);
117 NW_ASSERT(resNode.IsValid());
118 NW_ASSERT( internal::ResCheckRevision( resNode ) );
119
120 void* memory = allocator->Alloc(sizeof(Fog));
121 NW_NULL_ASSERT(memory);
122
123 Fog* fog = new(memory) Fog(
124 allocator,
125 resNode,
126 description);
127 Result result = fog->Initialize(allocator);
128 NW_ASSERT(result.IsSuccess());
129
130 if (parent)
131 {
132 bool isAttached = parent->AttachChild(fog);
133 NW_ASSERT(isAttached);
134 }
135
136 return fog;
137 }
138
139 //-----------------------------------------
140 /* static*/ ResFogData*
CreateResFog(os::IAllocator * allocator,const char * name)141 Fog::CreateResFog(os::IAllocator* allocator, const char* name /* = NULL */)
142 {
143 // TODO: 細かくアロケートする実装になっているが、まとめて確保できる仕組みも追加予定。
144
145 ResFogData* resFog =
146 AllocateAndFillN<ResFogData>(allocator, sizeof(ResFogData), 0);
147
148 //--------------------------------
149 // ResSceneObjectData のメンバ初期化
150 resFog->typeInfo = ResFog::TYPE_INFO;
151 resFog->m_Header.revision = ResFog::BINARY_REVISION;
152 resFog->m_Header.signature = ResFog::SIGNATURE;
153
154 resFog->m_UserDataDicCount = 0;
155 resFog->toUserDataDic.set_ptr( NULL );
156
157 resFog->toName.set_ptr(AllocateAndCopyString(name, allocator, MAX_NAME_LENGTH));
158
159 //--------------------------------
160 // ResSceneNodeData のメンバ初期化
161 resFog->m_ChildrenTableCount = 0;
162 resFog->toChildrenTable.set_ptr( NULL );
163 resFog->m_AnimGroupsDicCount = NULL;
164 resFog->toAnimGroupsDic.set_ptr( NULL );
165
166 //--------------------------------
167 // ResTransformNode のメンバ初期化
168 const math::VEC3 scale(1.0f, 1.0f, 1.0f);
169 const math::VEC3 rotate(0.0f, 0.0f, 0.0f);
170 const math::VEC3 translate(0.0f, 0.0f, 0.0f);
171 resFog->m_Transform = math::Transform3(scale, rotate, translate);
172 resFog->m_WorldMatrix = math::MTX34::Identity();
173 ResTransformNode(resFog).SetBranchVisible(true);
174
175 //--------------------------------
176 // ResFogData のメンバ初期化
177 ResImageLookupTableData* fogSampler =
178 AllocateAndFill<ResImageLookupTableData>(allocator, 0);
179
180 ResFogUpdaterData* fogUpdater =
181 AllocateAndFill<ResFogUpdaterData>(allocator, 0);
182
183 resFog->toFogUpdater.set_ptr( fogUpdater );
184 resFog->toFogSampler.set_ptr( fogSampler );
185
186 //--------------------------------
187 // ResImageLookupTableData のメンバ初期化
188 fogSampler->typeInfo = ResImageLookupTable::TYPE_INFO;
189
190 void* tableMemory = allocator->AllocAndFill<u32>(NW_FOG_TABLE_COMMAND_NUM, 0);
191 fogSampler->m_CommandCacheTableCount = NW_FOG_TABLE_COMMAND_SIZE;
192 fogSampler->toCommandCacheTable.set_ptr( tableMemory );
193
194 return resFog;
195 }
196
197 //-----------------------------------------
198 /* static */ void
DestroyResFog(os::IAllocator * allocator,ResFogData * resFog)199 Fog::DestroyResFog(os::IAllocator* allocator, ResFogData* resFog)
200 {
201 NW_NULL_ASSERT( allocator );
202 NW_NULL_ASSERT( resFog );
203
204 if ( resFog->toName.to_ptr() != NULL )
205 {
206 allocator->Free( const_cast<char*>( resFog->toName.to_ptr() ) );
207 }
208
209 if (resFog->toFogUpdater.to_ptr() != NULL)
210 {
211 allocator->Free( resFog->toFogUpdater.to_ptr() );
212 }
213
214 if (resFog->toFogSampler.to_ptr() != NULL)
215 {
216 ResImageLookupTable fogSampler = ResImageLookupTable(resFog->toFogSampler.to_ptr());
217 if (fogSampler.ref().toCommandCacheTable.to_ptr() != NULL)
218 {
219 allocator->Free( fogSampler.ref().toCommandCacheTable.to_ptr() );
220 }
221
222 allocator->Free( resFog->toFogSampler.to_ptr() );
223 }
224
225 allocator->Free( resFog );
226 }
227 //-----------------------------------------
228 /* static*/ ResFogUpdaterData*
CreateResFogUpdater(os::IAllocator * allocator)229 Fog::CreateResFogUpdater(os::IAllocator* allocator)
230 {
231 ResFogUpdaterData* fogUpdater =
232 AllocateAndFill<ResFogUpdaterData>(allocator, 0);
233
234 NW_NULL_ASSERT(fogUpdater);
235
236 return fogUpdater;
237 }
238
239 //-----------------------------------------
240 /* static */ void
DestroyResFogUpdater(os::IAllocator * allocator,ResFogUpdaterData * resFogUpdater)241 Fog::DestroyResFogUpdater(os::IAllocator* allocator, ResFogUpdaterData* resFogUpdater)
242 {
243 NW_NULL_ASSERT( allocator );
244 NW_NULL_ASSERT( resFogUpdater );
245
246
247 allocator->Free( resFogUpdater );
248 }
249
250 //-----------------------------------------
251 void
Update(const Camera * camera)252 Fog::Update(const Camera* camera)
253 {
254 NW_ASSERT(this->GetResFog().IsValid());
255 ResFogUpdater fogUpdater = this->GetResFog().GetFogUpdater();
256 NW_ASSERT(fogUpdater.IsValid());
257 ResImageLookupTable fogSampler = this->GetResFog().GetFogSampler();
258 NW_ASSERT(fogSampler.IsValid());
259 NW_ASSERT(fogSampler.GetCommandCacheCount() == NW_FOG_TABLE_COMMAND_SIZE);
260
261 ResCameraProjectionUpdater resProjectionUpdater =
262 camera->GetProjectionUpdater()->GetResource();
263 NW_ASSERT(resProjectionUpdater.IsValid());
264 f32 near = resProjectionUpdater.GetNear();
265 f32 far = resProjectionUpdater.GetFar();
266 f32 wscale = camera->GetWScale();
267
268 // フォグの参照テーブルはニアクリップとファークリップとフォグアップデータから再計算されるために
269 // ニアクリップとファークリップとフォグアップデータに変更がなければ参照テーブルは計算しません。
270
271 ResFogUpdaterData* updaterData = m_UpdaterCache.Get();
272 if (!ut::FloatEqualsWeak(m_Near, near) ||
273 !ut::FloatEqualsWeak(m_Far, far) ||
274 !ut::FloatEqualsWeak(m_WScale, wscale) ||
275 !ut::FloatEqualsWeak(updaterData->m_Density, fogUpdater.GetDensity()) ||
276 !(updaterData->m_FogUpdaterType == fogUpdater.GetFogUpdaterType()) ||
277 !ut::FloatEqualsWeak(updaterData->m_MaxFogDepth, fogUpdater.GetMaxFogDepth()) ||
278 !ut::FloatEqualsWeak(updaterData->m_MinFogDepth, fogUpdater.GetMinFogDepth()))
279 {
280 m_Near = near;
281 m_Far = far;
282 m_WScale = wscale;
283 updaterData->m_Density = fogUpdater.GetDensity();
284 updaterData->m_FogUpdaterType = fogUpdater.GetFogUpdaterType();
285 updaterData->m_MaxFogDepth = fogUpdater.GetMaxFogDepth();
286 updaterData->m_MinFogDepth = fogUpdater.GetMinFogDepth();
287
288 this->SetupFogSampler(
289 fogSampler,
290 fogUpdater,
291 camera->InverseProjectionMatrix());
292 }
293 }
294
295 //-----------------------------------------
296 void
SetupFogSampler(ResImageLookupTable fogSampler,ResFogUpdater fogUpdater,const math::MTX44 & inverseProjectionMatrix)297 Fog::SetupFogSampler(
298 ResImageLookupTable fogSampler,
299 ResFogUpdater fogUpdater,
300 const math::MTX44& inverseProjectionMatrix)
301 {
302 const uint HALF_TABLE_SIZE = FOG_TABLE_SIZE / 2;
303
304
305 enum
306 {
307 REG_FOG_TABLE_INDEX = 0xe6,
308 REG_FOG_TABLE_PARAM = 0xe8
309 };
310
311 const u32 HEADER_FOG_TABLE_INDEX = internal::MakeCommandHeader(REG_FOG_TABLE_INDEX, 1, false, 0xF);
312 const u32 HEADER_FOG_TABLE_PARAM = internal::MakeCommandHeader(REG_FOG_TABLE_PARAM, 128, false, 0xF);
313
314 fogSampler.SetCommandCache(0, 0);
315 fogSampler.SetCommandCache(1, HEADER_FOG_TABLE_INDEX);
316 fogSampler.SetCommandCache(3, HEADER_FOG_TABLE_PARAM);
317
318 uint index = 0;
319 math::VEC4 viewPos;
320 f32 prevLut = 0.0f;
321
322 for (int i = 0; i <= HALF_TABLE_SIZE; ++i)
323 {
324 if (m_WScale == 0.0f)
325 {
326 f32 depth = -(f32)i / (f32)( HALF_TABLE_SIZE );
327 viewPos.w = inverseProjectionMatrix.f._32 * depth + inverseProjectionMatrix.f._33;
328 viewPos.z = -(inverseProjectionMatrix.f._22 * depth + inverseProjectionMatrix.f._23) / viewPos.w;
329 }
330 else
331 {
332 viewPos.z = ((f32)i / (f32)HALF_TABLE_SIZE) * (m_Far - m_Near) + m_Near;
333 }
334
335 if (viewPos.z <= fogUpdater.GetMinFogDepth())
336 {
337 viewPos.z = 1.0f;
338 }
339 else if (viewPos.z > fogUpdater.GetMaxFogDepth())
340 {
341 viewPos.z = 0.0f;
342 }
343 else
344 {
345 if (fogUpdater.GetFogUpdaterType() == ResFogUpdater::FOG_UPDATER_TYPE_LINEAR)
346 {
347 viewPos.z =
348 (fogUpdater.GetMaxFogDepth() - viewPos.z) / (fogUpdater.GetMaxFogDepth() - fogUpdater.GetMinFogDepth());
349 }
350 else if (fogUpdater.GetFogUpdaterType() == ResFogUpdater::FOG_UPDATER_TYPE_EXPONENT)
351 {
352 viewPos.z =
353 math::FExp(
354 -fogUpdater.GetDensity() *
355 (viewPos.z - fogUpdater.GetMinFogDepth()) / (fogUpdater.GetMaxFogDepth() - fogUpdater.GetMinFogDepth()));
356 }
357 else if (fogUpdater.GetFogUpdaterType() == ResFogUpdater::FOG_UPDATER_TYPE_EXPONENT_SQUARE)
358 {
359 f32 viewDepth = fogUpdater.GetDensity() *
360 (viewPos.z - fogUpdater.GetMinFogDepth()) / (fogUpdater.GetMaxFogDepth() - fogUpdater.GetMinFogDepth());
361 viewPos.z =
362 math::FExp( - viewDepth * viewDepth );
363 }
364 else
365 {
366 NW_ASSERTMSG(false, "Unknown FogUpdater type.");
367 }
368 }
369
370 if ( i > 0 )
371 {
372 u32 value = nw::ut::Fixed13::Float32ToFixed13(viewPos.z - prevLut) | (nw::ut::Fixed11::Float32ToFixed11(prevLut) << 13);
373 u32 commandIndex = (index == 0) ? 2 : index + 3;
374
375 fogSampler.SetCommandCache(commandIndex, value );
376
377 ++index;
378 }
379
380 prevLut = viewPos.z;
381 }
382 }
383
384 //----------------------------------------
385 Result
Initialize(os::IAllocator * allocator)386 Fog::Initialize(os::IAllocator* allocator)
387 {
388 Result result = INITIALIZE_RESULT_OK;
389
390 result |= TransformNode::Initialize(allocator);
391 NW_ENSURE_AND_RETURN(result);
392
393 ResFogUpdaterData* resFogUpdater = CreateResFogUpdater(allocator);
394 if (resFogUpdater != NULL)
395 {
396 m_UpdaterCache = ResUpdaterPtr(
397 resFogUpdater,
398 ResFogUpdaterDataDestroyer(allocator));
399 }
400 else
401 {
402 result |= Result::MASK_FAIL_BIT;
403 }
404 NW_ENSURE_AND_RETURN(result);
405
406 result |= CreateOriginalValue(allocator);
407 NW_ENSURE_AND_RETURN(result);
408
409 result |= CreateAnimGroup(allocator);
410 NW_ENSURE_AND_RETURN(result);
411
412 return result;
413 }
414
415 //----------------------------------------
416 Result
CreateAnimGroup(os::IAllocator * allocator)417 Fog::CreateAnimGroup(os::IAllocator* allocator)
418 {
419 Result result = INITIALIZE_RESULT_OK;
420
421 AnimBinding* animBinding = GetAnimBinding();
422 if (animBinding == NULL)
423 {
424 return result;
425 }
426
427 ResFog resFog = GetResFog();
428 NW_ASSERT(resFog.IsValid());
429
430 NW_ASSERT(resFog.GetAnimGroupsCount() == 1);
431 anim::ResAnimGroup resAnimGroup = resFog.GetAnimGroups(0);
432
433 NW_ASSERT(resAnimGroup.GetTargetType() == anim::ResGraphicsAnimGroup::TARGET_TYPE_FOG);
434
435 AnimGroup* animGroup = AnimGroup::Builder()
436 .ResAnimGroup(resAnimGroup)
437 .SetSceneNode(this)
438 .UseOriginalValue(true)
439 .Create(allocator);
440
441 if (animGroup == NULL)
442 {
443 result |= Result::MASK_FAIL_BIT;
444 }
445
446 NW_ENSURE_AND_RETURN(result);
447
448 BindAnim(animGroup);
449
450 animBinding->SetAnimGroup(0, animGroup);
451 m_AnimGroup = animGroup;
452
453 return result;
454 }
455
456 //----------------------------------------
457 Result
CreateOriginalValue(os::IAllocator * allocator)458 Fog::CreateOriginalValue(os::IAllocator* allocator)
459 {
460 Result result = INITIALIZE_RESULT_OK;
461
462 void* buffer = allocator->Alloc(sizeof(ResFogData));
463 NW_NULL_ASSERT(buffer);
464
465 // リソースをコピー
466 ResFogData* originalValue = new(buffer) ResFogData(GetResFog().ref());
467 m_OriginalValue = ResFog(originalValue);
468
469 return result;
470 }
471
472 //----------------------------------------
473 void
BindAnim(AnimGroup * animGroup)474 Fog::BindAnim(AnimGroup* animGroup)
475 {
476 using namespace anim;
477
478 const int animMemberCount = animGroup->GetMemberCount();
479 for (int memberIdx = 0; memberIdx < animMemberCount; ++memberIdx)
480 {
481 anim::ResAnimGroupMember resAnimGroupMember =
482 animGroup->GetResAnimGroupMember(memberIdx);
483
484 switch(resAnimGroupMember.GetObjectType())
485 {
486 case anim::ResAnimGroupMember::OBJECT_TYPE_FOG:
487 {
488 void* object = GetResFog().ptr();
489 animGroup->SetTargetObject(memberIdx, object);
490 u8* target = static_cast<u8*>(object);
491 target += resAnimGroupMember.GetMemberOffset();
492
493 animGroup->SetTargetPtr(memberIdx, target);
494
495 u8* originalValue = reinterpret_cast<u8*>(m_OriginalValue.ptr());
496 originalValue += resAnimGroupMember.GetMemberOffset();
497 animGroup->SetOriginalValue(memberIdx, originalValue);
498 }
499 break;
500 default:
501 {
502 NW_FATAL_ERROR("Unknown animation member type");
503 }
504 break;
505 }
506
507 animGroup->SetTargetObjectIndex(memberIdx, 0);
508 }
509 }
510
511 //----------------------------------------------------------
512 void
GetMemorySizeInternal(os::MemorySizeCalculator * pSize,ResFog resFog,Description description)513 Fog::GetMemorySizeInternal(
514 os::MemorySizeCalculator* pSize,
515 ResFog resFog,
516 Description description
517 )
518 {
519 NW_ASSERT(description.isFixedSizeMemory);
520
521 os::MemorySizeCalculator& size = *pSize;
522
523 size += sizeof(Fog);
524
525 // FragmentLight::Initialize
526 TransformNode::GetMemorySizeForInitialize(
527 &size,
528 resFog,
529 description);
530
531 // Fog::CreateResFogUpdater
532 size += sizeof(ResFogUpdaterData);
533
534 if (description.isAnimationEnabled &&
535 resFog.GetAnimGroupsCount() > 0)
536 {
537 AnimGroup::Builder()
538 .ResAnimGroup(resFog.GetAnimGroups(0))
539 .UseOriginalValue(true)
540 .GetMemorySizeInternal(&size);
541 }
542
543 // Fog::CreateOriginalValue
544 size += sizeof(ResFogData);
545 }
546
547 } // namespace gfx
548 } // namespace nw
549