1 /*---------------------------------------------------------------------------*
2   Project:  NintendoWare
3   File:     gfx_ResMaterial.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: 18139 $
14  *---------------------------------------------------------------------------*/
15 
16 #include "../precompiled.h"
17 
18 #include <nw/gfx/res/gfx_ResUtil.h>
19 #include <nw/gfx/res/gfx_ResMaterial.h>
20 #include <nw/gfx/res/gfx_ResGraphicsFile.h>
21 
22 namespace nw {
23 namespace gfx {
24 namespace res {
25 
26 static Result
27 SetupTextureCoordinators(ResMaterial resMaterial);
28 
29 //----------------------------------------------------------------------------
30 Result
Setup(os::IAllocator * allocator,ResGraphicsFile graphicsFile)31 ResMaterial::Setup(os::IAllocator* allocator, ResGraphicsFile graphicsFile)
32 {
33     NW_ASSERT( internal::ResCheckRevision( graphicsFile ) );
34     NW_ASSERT( internal::ResCheckRevision( *this ) );
35 
36     NW_ASSERT( this->IsValid() );
37 
38     Result result = RESOURCE_RESULT_OK;
39 
40     result |= this->SetupTextures(allocator, *this, graphicsFile);
41 
42     // Shaderをセットアップします。
43     result |= this->SetupShader(allocator, this->GetShader(), graphicsFile);
44 
45     // ユーザーシェーダーユニフォームのインデックス番号をキャッシュします。
46     ResShader resShader = this->GetShader();
47     if (resShader.IsValid() && ((result.GetDescription() & nw::gfx::RESOURCE_RESULT_NOT_FOUND_SHADER) == 0))
48     {
49         ResBinaryShader resBinaryShader = resShader.Dereference();
50         NW_MINMAXLT_ASSERT(this->GetShaderProgramDescriptionIndex(), 0, resBinaryShader.GetDescriptionsCount());
51 
52         ResShaderProgramDescription description =
53             resBinaryShader.GetDescriptions(this->GetShaderProgramDescriptionIndex());
54         this->CacheUserUniformIndex(description.GetSymbols());
55     }
56 
57     // FragmentLightingTableをセットアップします。
58     ResFragmentShader resFragmentShader = this->GetFragmentShader();
59     NW_ASSERT(resFragmentShader.GetFragmentLightingTable().IsValid());
60     result |= resFragmentShader.Setup(allocator, graphicsFile);
61 
62     // フラグメントライティングテーブルのハッシュを計算します。
63     if ((result.GetDescription() & nw::gfx::RESOURCE_RESULT_NOT_FOUND_LUT) == 0)
64     {
65         // 必ず参照解決が完了している状態で呼び出す必要があります。
66         this->CalcFragmentLightingTableHash();
67     }
68 
69     return result;
70 }
71 
72 //----------------------------------------------------------------------------
73 void
Cleanup()74 ResMaterial::Cleanup()
75 {
76     int textureMapperNum = this->GetTextureMappersCount();
77     for ( int i = 0; i < textureMapperNum; ++i )
78     {
79         ResPixelBasedTextureMapper textureMapper = this->GetTextureMappers( i );
80         if (textureMapper.IsValid())
81         {
82             textureMapper.Cleanup();
83         }
84     }
85 
86     if (this->GetProceduralTextureMapper().IsValid())
87     {
88         this->GetProceduralTextureMapper().Cleanup();
89     }
90 
91     ResShader resShader = this->GetShader();
92     ut::SafeCleanup(resShader);
93 
94     ut::SafeCleanup(this->GetFragmentShader());
95 }
96 
97 //----------------------------------------
98 Result
SetupTextures(os::IAllocator * allocator,ResMaterial resMaterial,ResGraphicsFile graphicsFile)99 ResMaterial::SetupTextures(os::IAllocator* allocator, ResMaterial resMaterial, ResGraphicsFile graphicsFile)
100 {
101     Result result = RESOURCE_RESULT_OK;
102 
103     s32 textureMapperNum = resMaterial.GetTextureMappersCount();
104     result |= SetupTextureCoordinators(resMaterial);
105 
106     u32 textureSamplersHash = resMaterial.GetTextureSamplersHash();
107     // TextureMapper をセットアップします。
108     for ( int i = 0; i < textureMapperNum; ++i )
109     {
110         ResPixelBasedTextureMapper resTextureMapper = resMaterial.GetTextureMappers( i );
111         if (!resTextureMapper.IsValid())
112         {
113             continue;
114         }
115 
116         if (!resTextureMapper.GetTexture().IsValid())
117         {
118             continue;
119         }
120 
121         result |= resTextureMapper.Setup(allocator, graphicsFile);
122 
123         // テクスチャコーディネータを参照してテクスチャサンプラーのコマンドを設定する
124         enum
125         {
126             SAMPLER_TYPE_SHIFT = 28,
127             SAMPLER_TYPE_MASK = 0x7 << SAMPLER_TYPE_SHIFT,
128             SAMPLER_TYPE_2D = 0,
129             SAMPLER_TYPE_CUBE_MAP = 1,
130             SAMPLER_TYPE_SHADOW_2D = 2,
131             SAMPLER_TYPE_PROJECTION = 3,
132             SAMPLER_TYPE_SHADOW_CUBE = 4
133         };
134         u32* command = resTextureMapper.GetCommandCache();
135         NW_NULL_ASSERT(command);
136 
137         command[5] &= ~(SAMPLER_TYPE_MASK); // sampler_type
138         // テクスチャ0のみ複数のサンプラータイプが設定できる。
139         if ( i == 0 )
140         {
141             switch (resMaterial.GetTextureCoordinators(0).GetMappingMethod())
142             {
143             case ResTextureCoordinator::MAPPINGMETHOD_UV_COORDINATE:
144                 {
145                     command[5] |= SAMPLER_TYPE_2D << SAMPLER_TYPE_SHIFT;
146                 }
147                 break;
148             case ResTextureCoordinator::MAPPINGMETHOD_PROJECTION:
149                 {
150                     command[5] |= SAMPLER_TYPE_PROJECTION << SAMPLER_TYPE_SHIFT;
151                 }
152                 break;
153             case ResTextureCoordinator::MAPPINGMETHOD_CAMERA_CUBE_ENV:
154                 {
155                     command[5] |= SAMPLER_TYPE_CUBE_MAP << SAMPLER_TYPE_SHIFT;
156                 }
157                 break;
158             case ResTextureCoordinator::MAPPINGMETHOD_CAMERA_SPHERE_ENV:
159                 {
160                     command[5] |= SAMPLER_TYPE_2D << SAMPLER_TYPE_SHIFT;
161                 }
162                 break;
163             default:
164                 NW_FATAL_ERROR("Unsupported mapping method.");
165                 break;
166             }
167         }
168 
169         if ((result.GetDescription() & RESOURCE_RESULT_NOT_FOUND_TEXTURE) == 0)
170         {
171             ResTexture resImageTexture = resTextureMapper.GetTexture().Dereference();
172             u32 hash = 0;
173             if (i == 0)
174             {
175                 hash = (u32)resImageTexture.ptr();
176             }
177             else
178             {
179                 hash = ((u32)resImageTexture.ptr() << i * 8) | ((u32)resImageTexture.ptr() >> (32 - i * 8));
180             }
181 
182             textureSamplersHash ^= hash;
183         }
184     }
185 
186     resMaterial.SetTextureMappersHash(textureSamplersHash);
187 
188     if (resMaterial.GetProceduralTextureMapper().IsValid())
189     {
190         result |= resMaterial.GetProceduralTextureMapper().Setup(allocator, graphicsFile);
191     }
192 
193     return result;
194 }
195 
SetupTextureCoordinators(ResMaterial resMaterial)196 static Result SetupTextureCoordinators(ResMaterial resMaterial)
197 {
198     Result result = RESOURCE_RESULT_OK;
199 
200     // TextureMapper と TextureCoordinator の組み合わせを確認します。
201     s32 textureCoordinatorNum = resMaterial.GetTextureCoordinatorsCount();
202     ResMaterial::TextureCoordinateConfig config = resMaterial.GetTextureCoordinateConfig();
203     bool isProceduralTextureEnabled = resMaterial.GetProceduralTextureMapper().IsValid();
204     for ( int i = 0; i < textureCoordinatorNum; ++i )
205     {
206         ResTextureCoordinator resTextureCoordinator = resMaterial.GetTextureCoordinators(i);
207         bool isTextureMapperEnabled = resMaterial.GetTextureMappers(i).IsValid();
208         resTextureCoordinator.SetEnabled(false);
209 
210         switch(i)
211         {
212             case 0:
213             {
214                 if (isTextureMapperEnabled)
215                 {
216                     resTextureCoordinator.SetEnabled(true);
217                 }
218                 else if (config == ResMaterial::CONFIG_0120 || config == ResMaterial::CONFIG_0110)
219                 {
220                     if (isProceduralTextureEnabled)
221                     {
222                         resTextureCoordinator.SetEnabled(true);
223                     }
224                 }
225             }
226             break;
227             case 1:
228             {
229                 if (isTextureMapperEnabled)
230                 {
231                     resTextureCoordinator.SetEnabled(true);
232                 }
233                 else
234                 {
235                     if (config == ResMaterial::CONFIG_0111)
236                     {
237                         if (resMaterial.GetTextureMappers(2).IsValid() || isProceduralTextureEnabled)
238                         {
239                             resTextureCoordinator.SetEnabled(true);
240                         }
241                     }
242                     else if (config == ResMaterial::CONFIG_0110 || config == ResMaterial::CONFIG_0112)
243                     {
244                         if (resMaterial.GetTextureMappers(2).IsValid())
245                         {
246                             resTextureCoordinator.SetEnabled(true);
247                         }
248                     }
249                     else if (config == ResMaterial::CONFIG_0121)
250                     {
251                         if (isProceduralTextureEnabled)
252                         {
253                             resTextureCoordinator.SetEnabled(true);
254                         }
255                     }
256                 }
257             }
258             break;
259             case 2:
260             {
261                 if (config == ResMaterial::CONFIG_0122)
262                 {
263                     if (isTextureMapperEnabled || isProceduralTextureEnabled)
264                     {
265                         resTextureCoordinator.SetEnabled(true);
266                     }
267                 }
268                 else if (config == ResMaterial::CONFIG_0120 || config == ResMaterial::CONFIG_0121)
269                 {
270                     if (isTextureMapperEnabled)
271                     {
272                         resTextureCoordinator.SetEnabled(true);
273                     }
274                 }
275                 else if (config == ResMaterial::CONFIG_0112)
276                 {
277                     if (isProceduralTextureEnabled)
278                     {
279                         resTextureCoordinator.SetEnabled(true);
280                     }
281                 }
282             }
283             break;
284             default:
285             {
286                 NW_FATAL_ERROR("Invalid coordinator number.");
287             }
288         }
289     }
290     return result;
291 }
292 
293 //----------------------------------------
294 Result
SetupShader(os::IAllocator * allocator,ResShader resShader,ResGraphicsFile graphicsFile)295 ResMaterial::SetupShader(
296     os::IAllocator* allocator,
297     ResShader resShader,
298     ResGraphicsFile graphicsFile
299 )
300 {
301     Result result = RESOURCE_RESULT_OK;
302     ResShader setupShader;
303 
304     if (resShader.IsValid())
305     {
306         bool existShader = false;
307         ResReferenceShader refer = ResDynamicCast<ResReferenceShader>(resShader);
308         if (refer.IsValid())
309         {
310             if (refer.GetTargetShader().IsValid())
311             {
312                 setupShader = refer.GetTargetShader();
313                 existShader = true;
314             }
315             else
316             {
317                 ::std::pair<ResShader, bool> referenceResult;
318                 referenceResult = GetReferenceShaderTarget(refer, graphicsFile);
319                 if (referenceResult.second)
320                 {
321                     setupShader = referenceResult.first;
322                     existShader = true;
323                 }
324                 else
325                 {
326                     result |= Result::MASK_FAIL_BIT;
327                     result |= RESOURCE_RESULT_NOT_FOUND_SHADER;
328                 }
329             }
330         }
331         else
332         {
333             setupShader = resShader;
334             existShader = true;
335         }
336 
337         if (existShader)
338         {
339             result |= setupShader.Setup(allocator, graphicsFile);
340         }
341     }
342 
343     return result;
344 }
345 
346 //----------------------------------------
347 void
SetShader(ResShader resShader)348 ResMaterial::SetShader(ResShader resShader)
349 {
350     NW_ASSERT(resShader.IsValid());
351     ResReferenceShader referenceShader = ResStaticCast<ResReferenceShader>(this->GetShader());
352     referenceShader.ref().toTargetShader.set_ptr(resShader.Dereference().ptr());
353 }
354 
355 //----------------------------------------
356 void
CacheUserUniformIndex(ResShaderSymbolArray symbols)357 ResMaterial::CacheUserUniformIndex(ResShaderSymbolArray symbols)
358 {
359     for (int parameterIndex = 0; parameterIndex < this->GetShaderParametersCount(); ++parameterIndex)
360     {
361         ResShaderParameter parameter = this->GetShaderParameters(parameterIndex);
362         if (parameter.IsValid())
363         {
364             const char* name = parameter.GetName();
365 
366             if (name == NULL) { continue; }
367 
368             for (int symbolIndex = 0; symbolIndex < symbols.size(); ++symbolIndex)
369             {
370                 ResShaderSymbol shaderSymbol = symbols[symbolIndex];
371                 if (::std::strcmp(name, shaderSymbol.GetName()) == 0)
372                 {
373                     // ユーザーユニフォームのインデックスをキャッシュします。
374                     parameter.SetSymbolIndex(symbolIndex);
375                     break;
376                 }
377             }
378         }
379     }
380 }
381 
382 //----------------------------------------
383 void
CalcFragmentLightingTableHash()384 ResMaterial::CalcFragmentLightingTableHash()
385 {
386     enum
387     {
388         D0_SHIFT = 0,
389         D1_SHIFT = 4,
390         RR_SHIFT = 8,
391         RG_SHIFT = 12,
392         RB_SHIFT = 16,
393         FR_SHIFT = 20,
394         MAX_BITS = 32
395     };
396 
397     ResFragmentShader resFragmentShader = this->GetFragmentShader();
398     ResFragmentLightingTable resFragmentLightingTable = resFragmentShader.GetFragmentLightingTable();
399     NW_ASSERT(resFragmentLightingTable.IsValid());
400 
401     // FragmentLightingTableのハッシュ値を再計算します。
402     u32 fragmentLightingTableParametersHash = this->GetFragmentLightingTableParametersHash();
403 
404     if (resFragmentLightingTable.GetDistribution0Sampler().IsValid())
405     {
406         ResReferenceLookupTable refLut = ResDynamicCast<ResReferenceLookupTable>(resFragmentLightingTable.GetDistribution0Sampler().GetSampler());
407         if (refLut.IsValid())
408         {
409             ResImageLookupTable imageLut = refLut.Dereference();
410             fragmentLightingTableParametersHash ^= ((u32)imageLut.ptr()) << D0_SHIFT;
411         }
412     }
413 
414     if (resFragmentLightingTable.GetDistribution1Sampler().IsValid())
415     {
416         ResReferenceLookupTable refLut = ResDynamicCast<ResReferenceLookupTable>(resFragmentLightingTable.GetDistribution1Sampler().GetSampler());
417         if (refLut.IsValid())
418         {
419             ResImageLookupTable imageLut = refLut.Dereference();
420             fragmentLightingTableParametersHash ^=
421                 ((u32)imageLut.ptr() << D1_SHIFT) | ((u32)imageLut.ptr() >> (MAX_BITS - D1_SHIFT));
422         }
423     }
424 
425     if (resFragmentLightingTable.GetReflectanceRSampler().IsValid())
426     {
427         ResReferenceLookupTable refLut = ResDynamicCast<ResReferenceLookupTable>(resFragmentLightingTable.GetReflectanceRSampler().GetSampler());
428         if (refLut.IsValid())
429         {
430             ResImageLookupTable imageLut = refLut.Dereference();
431             fragmentLightingTableParametersHash ^=
432                 ((u32)imageLut.ptr() << RR_SHIFT) | ((u32)imageLut.ptr() >> (MAX_BITS - RR_SHIFT));
433         }
434     }
435 
436     if (resFragmentLightingTable.GetReflectanceGSampler().IsValid())
437     {
438         ResReferenceLookupTable refLut = ResDynamicCast<ResReferenceLookupTable>(resFragmentLightingTable.GetReflectanceGSampler().GetSampler());
439         if (refLut.IsValid())
440         {
441             ResImageLookupTable imageLut = refLut.Dereference();
442             fragmentLightingTableParametersHash ^=
443                 ((u32)imageLut.ptr() << RG_SHIFT) |
444                 ((u32)imageLut.ptr() >> (MAX_BITS - RG_SHIFT));
445         }
446     }
447 
448     if (resFragmentLightingTable.GetReflectanceBSampler().IsValid())
449     {
450         ResReferenceLookupTable refLut = ResDynamicCast<ResReferenceLookupTable>(resFragmentLightingTable.GetReflectanceBSampler().GetSampler());
451         if (refLut.IsValid())
452         {
453             ResImageLookupTable imageLut = refLut.Dereference();
454             fragmentLightingTableParametersHash ^=
455                 ((u32)imageLut.ptr() << RB_SHIFT) |
456                 ((u32)imageLut.ptr() >> (MAX_BITS - RB_SHIFT));
457         }
458     }
459 
460     if (resFragmentLightingTable.GetFresnelSampler().IsValid())
461     {
462         ResReferenceLookupTable refLut = ResDynamicCast<ResReferenceLookupTable>(resFragmentLightingTable.GetFresnelSampler().GetSampler());
463         if (refLut.IsValid())
464         {
465             ResImageLookupTable imageLut = refLut.Dereference();
466             fragmentLightingTableParametersHash ^=
467                 ((u32)imageLut.ptr() << FR_SHIFT) |
468                 ((u32)imageLut.ptr() >> (MAX_BITS - FR_SHIFT));
469         }
470     }
471 
472     this->SetFragmentLightingTableHash(fragmentLightingTableParametersHash);
473 }
474 
475 } /* namespace res */
476 } /* namespace gfx */
477 } /* namespace nw */
478 
479