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