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