1 /*---------------------------------------------------------------------------*
2 Project: NintendoWare
3 File: gfx_ActivateCommand.h
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: 28068 $
14 *---------------------------------------------------------------------------*/
15
16 #ifndef NW_GFX_ACTIVATE_COMMAND_H_
17 #define NW_GFX_ACTIVATE_COMMAND_H_
18
19 #include <nw/types.h>
20
21
22 #include <gles2/gl2.h>
23 #include <gles2/gl2ext.h>
24 #include <nn/gx.h>
25
26 #include <nw/gfx/gfx_CommandUtil.h>
27 #include <nw/gfx/gfx_FragmentLight.h>
28 #include <nw/gfx/gfx_AmbientLight.h>
29 #include <nw/gfx/res/gfx_ResMaterial.h>
30 #include <nw/gfx/res/gfx_ResParticleShape.h>
31
32 namespace nw {
33 namespace gfx {
34
35 class ShaderProgram;
36
37 namespace internal {
38
39 class CommandCacheHelper
40 {
41 public:
42
43 //--------------------------------------------------------------------------
44 //! @brief U32 で表されたカラーを掛けます。
45 //!
46 //! @param[in] lhs 乗算を行う U32 カラー値です。
47 //! @param[in] rhs 乗算を行う U32 カラー値です。
48 //!
49 //! @return 乗算後の値を返します。
50 //---------------------------------------------------------------------------
MultU32Color(u32 lhs,u32 rhs)51 static NW_INLINE u32 MultU32Color(u32 lhs, u32 rhs)
52 {
53 const u32 MASKx2 = (0xff << 1);
54
55 u32 r = ((((lhs << 1) & MASKx2) + 1) * (((rhs << 1) & MASKx2) + 1)) >> 10;
56 u32 g = ((((lhs >> 7) & MASKx2) + 1) * (((rhs >> 7) & MASKx2) + 1)) >> 10;
57 u32 b = ((((lhs >> 15) & MASKx2) + 1) * (((rhs >> 15) & MASKx2) + 1)) >> 10;
58
59 return (r << 20) | (g << 10) | b;
60 }
61
62 //--------------------------------------------------------------------------
63 //! @brief U32 で表されたカラーを掛けた後に加算を行います。
64 //!
65 //! @param[in] lhs 乗算を行う U32 カラー値です。
66 //! @param[in] rhs 乗算を行う U32 カラー値です。
67 //! @param[in] add 加算を行う U32 カラー値です。
68 //!
69 //! @return 乗算後の値を返します。
70 //---------------------------------------------------------------------------
MultAddU32Color(u32 lhs,u32 rhs,u32 add)71 static NW_INLINE u32 MultAddU32Color(u32 lhs, u32 rhs, u32 add)
72 {
73 const u32 MASK = 0xff;
74 const u32 MASKx2 = (0xff << 1);
75
76 u32 r = (((((lhs << 1) & MASKx2) + 1) * (((rhs << 1) & MASKx2) + 1)) >> 10) + (add & MASK);
77 u32 g = (((((lhs >> 7) & MASKx2) + 1) * (((rhs >> 7) & MASKx2) + 1)) >> 10) + ((add >> 8) & MASK);
78 u32 b = (((((lhs >> 15) & MASKx2) + 1) * (((rhs >> 15) & MASKx2) + 1)) >> 10) + ((add >> 16) & MASK);
79
80 return (ut::Clamp<u32>(r, 0, 255) << 20) | (ut::Clamp<u32>(g, 0, 255) << 10) | ut::Clamp<u32>(b, 0, 255);
81 }
82
83 //--------------------------------------------------------------------------
84 //! @brief 頂点ストリームの型と要素数から、HWの頂点フォーマット設定を取得します。
85 //!
86 //! @param[in] dimension 頂点属性の要素数です。
87 //! @param[in] format 頂点属性のフォーマットです。
88 //!
89 //! @return ハードに設定する頂点フォーマット定数を返します。
90 //---------------------------------------------------------------------------
GetVertexFormat(s32 dimension,GLuint format)91 static NW_INLINE u32 GetVertexFormat(s32 dimension, GLuint format)
92 {
93 u32 result = 0;
94
95 switch ( format )
96 {
97 case GL_BYTE: result = 0; break;
98 case GL_UNSIGNED_BYTE: result = 1; break;
99 case GL_SHORT: result = 2; break;
100 case GL_FLOAT: result = 3; break;
101 default: NW_FATAL_ERROR("unknown format");
102 }
103
104 return result + ((dimension - 1) << 2);
105 }
106
107 //--------------------------------------------------------------------------
108 //! @brief 頂点ストリームの型と要素数から、頂点サイズを取得します。
109 //!
110 //! @param[in] dimension 頂点属性の要素数です。
111 //! @param[in] format 頂点属性のフォーマットです。
112 //!
113 //! @return ハードに設定する頂点サイズを返します。
114 //---------------------------------------------------------------------------
GetVertexSize(s32 dimension,GLuint format)115 static NW_INLINE u32 GetVertexSize(s32 dimension, GLuint format)
116 {
117 u32 result = 0;
118
119 switch ( format )
120 {
121 case GL_BYTE: return dimension;
122 case GL_UNSIGNED_BYTE: return dimension;
123 case GL_SHORT: return dimension * 2;
124 case GL_FLOAT: return dimension * 4;
125 default: NW_FATAL_ERROR("unknown format");
126 }
127
128 return 0;
129 }
130 };
131
132
133
134 //--------------------------------------------------------------------------
135 //! @brief フラグメントライト数を設定します。
136 //!
137 //! @param[in] count 有効なライトの数です。
138 //---------------------------------------------------------------------------
139 NW_INLINE void
ActivateFragmentLightCount(s32 count)140 ActivateFragmentLightCount(s32 count)
141 {
142 enum
143 {
144 REG_FRAGMENT_LIGHT_COUNT = 0x1c2,
145 REG_FRAGMENT_LIGHT_MASK = 0x1d9
146 };
147
148 const u32 COUNT_HEADER = internal::MakeCommandHeader(REG_FRAGMENT_LIGHT_COUNT, 1, false, 0x1);
149 const u32 LIGHT_MASK_HEADER = internal::MakeCommandHeader(REG_FRAGMENT_LIGHT_MASK, 1, false, 0xF);
150
151 u32 LIGHT_COUNT_COMMAND[] =
152 {
153 0,
154 COUNT_HEADER
155 #if defined(NW_TARGET_CTR_GL_FINAL)
156 ,0,
157 LIGHT_MASK_HEADER
158 #endif
159 };
160
161 LIGHT_COUNT_COMMAND[0] = (count > 0) ? count - 1 : 0;
162
163 #if defined(NW_TARGET_CTR_GL_FINAL)
164 for (int i = 0; i < count; ++i)
165 {
166 LIGHT_COUNT_COMMAND[2] |= i << (4 * i);
167 }
168 #endif
169
170 internal::NWUseCmdlist<sizeof(LIGHT_COUNT_COMMAND)>( &LIGHT_COUNT_COMMAND[0] );
171 }
172
173 //--------------------------------------------------------------------------
174 //! @brief フラグメントライトレジスタの設定をおこないます。
175 //!
176 //! @param[in] index ライトを設定するインデックス番号です。
177 //! @param[in] materialColor マテリアルカラーです。
178 //! @param[in] light フラグメントライトセットです。
179 //! @param[in] useReflection 反射テーブルが有効かどうかを表すフラグです。
180 //---------------------------------------------------------------------------
181 NW_INLINE void
ActivateFragmentLight(s32 index,ResMaterialColor materialColor,const FragmentLight * light,bool useReflection)182 ActivateFragmentLight(s32 index, ResMaterialColor materialColor, const FragmentLight* light, bool useReflection)
183 {
184 enum { REG_FRAGMENT_COLOR_BASE = 0x140 };
185
186 const u32 HEADER = internal::MakeCommandHeader(REG_FRAGMENT_COLOR_BASE, 4, true, 0xF);
187
188 NW_NULL_ASSERT( light );
189
190 ResFragmentLight resLight = light->GetResFragmentLight();
191
192 u32 specular0U32 = CommandCacheHelper::MultU32Color(resLight.GetSpecular0U32(), materialColor.GetSpecular0U32());
193 u32 diffuseU32 = CommandCacheHelper::MultU32Color(resLight.GetDiffuseU32(), materialColor.GetDiffuseU32());
194 u32 ambientU32 = CommandCacheHelper::MultU32Color(resLight.GetAmbientU32(), materialColor.GetAmbientU32());
195 u32 specular1U32 = resLight.GetSpecular1U32();
196
197 if (useReflection)
198 {
199 const u32 MASK = 0xff;
200 u8 r = (specular1U32 & MASK);
201 u8 g = ((specular1U32 >> 8) & MASK);
202 u8 b = ((specular1U32 >> 16) & MASK);
203 specular1U32 = (static_cast<u32>(r) << 20) | (static_cast<u32>(g) << 10) | (static_cast<u32>(b));
204 }
205 else
206 {
207 specular1U32 = CommandCacheHelper::MultU32Color(resLight.GetSpecular1U32(), materialColor.GetSpecular1U32());
208 }
209
210 u32 LIGHT_COMMAND[6] =
211 {
212 specular0U32,
213 HEADER + (0x10 * index),
214 specular1U32,
215 diffuseU32,
216 ambientU32,
217 0 // padding
218 };
219
220 internal::NWUseCmdlist<sizeof(LIGHT_COMMAND)>( &LIGHT_COMMAND[0] );
221 }
222
223 //--------------------------------------------------------------------------
224 //! @brief アンビエントライト用のコマンドを設定します。
225 //!
226 //! @param[in] materialColor マテリアルカラーの情報です。
227 //! @param[in] light アンビエントライトの情報です。
228 //---------------------------------------------------------------------------
229 NW_INLINE void
ActivateFragmentAmbientLight(ResMaterialColor materialColor,const AmbientLight * light)230 ActivateFragmentAmbientLight(ResMaterialColor materialColor, const AmbientLight* light)
231 {
232 enum { REG_FRAGMENT_COLOR_AMBIENT = 0x1c0 };
233
234 u32 ambientU32 = 0x0;
235 const u32 HEADER = internal::MakeCommandHeader(REG_FRAGMENT_COLOR_AMBIENT, 1, false, 0xF);
236
237 if (light)
238 {
239 ResAmbientLight resLight = light->GetResAmbientLight();
240 ambientU32 = CommandCacheHelper::MultAddU32Color(resLight.GetAmbientU32(), materialColor.GetAmbientU32(), materialColor.GetEmissionU32());
241 }
242 else
243 {
244 u32 emissionU32 = materialColor.GetEmissionU32();
245 const u32 MASK = 0xff;
246 u8 r = (emissionU32 & MASK);
247 u8 g = ((emissionU32 >> 8) & MASK);
248 u8 b = ((emissionU32 >> 16) & MASK);
249 ambientU32 = (static_cast<u32>(r) << 20) | (static_cast<u32>(g) << 10) | (static_cast<u32>(b));
250 }
251
252 u32 LIGHT_COMMAND[2] =
253 {
254 ambientU32,
255 HEADER
256 };
257
258 internal::NWUseCmdlist<sizeof(LIGHT_COMMAND)>( &LIGHT_COMMAND[0] );
259 }
260
261 //--------------------------------------------------------------------------
262 //! @brief フラグメントライトのパラメータを設定します。
263 //!
264 //! @param[in] index ライトのインデックスを設定します。
265 //! @param[in] isDirectional ディレクショナルライトかどうかのフラグです。
266 //! @param[in] twoSided 2 sided ライティングのフラグです。
267 //! @param[in] geomFactor0 ジオメトリックファクタ0を使用するかどうかのフラグです。
268 //! @param[in] geomFactor1 ジオメトリックファクタ1を使用するかどうかのフラグです。
269 //---------------------------------------------------------------------------
270 NW_INLINE void
ActivateFragmentLightParameters(s32 index,bool isDirectional,bool twoSided,bool geomFactor0,bool geomFactor1)271 ActivateFragmentLightParameters(s32 index, bool isDirectional, bool twoSided, bool geomFactor0, bool geomFactor1)
272 {
273 enum
274 {
275 REG_FRAGMENT_LIGHT_TYPE = 0x149
276 };
277
278 const u32 HEADER = internal::MakeCommandHeader(REG_FRAGMENT_LIGHT_TYPE, 1, false, 0x1);
279
280 u32 LIGHT_COMMAND[2] =
281 {
282 0,
283 HEADER + 0x10 * index
284 };
285
286 if (isDirectional)
287 {
288 LIGHT_COMMAND[0] |= 0x1;
289 }
290
291 if (twoSided)
292 {
293 LIGHT_COMMAND[0] |= 0x2;
294 }
295
296 if (geomFactor0)
297 {
298 LIGHT_COMMAND[0] |= 0x4;
299 }
300
301 if (geomFactor1)
302 {
303 LIGHT_COMMAND[0] |= 0x8;
304 }
305
306 internal::NWUseCmdlist<sizeof(LIGHT_COMMAND)>( &LIGHT_COMMAND[0] );
307 }
308
309 //--------------------------------------------------------------------------
310 //! @brief フラグメントライティングの設定をおこないます。
311 //!
312 //! @param[in] fragmentLighting フラグメントライティング設定です。
313 //---------------------------------------------------------------------------
314 NW_INLINE void
ActivateFragmentLighting(const ResFragmentLighting fragmentLighting)315 ActivateFragmentLighting(const ResFragmentLighting fragmentLighting)
316 {
317 const u32 REG_LIGHT_ENV = 0x1c3;
318 const u32 REG_LIGHT_ENV2 = 0x1c4;
319
320 const u32 HEADER = internal::MakeCommandHeader(REG_LIGHT_ENV, 1, false, 0xf);
321 const u32 HEADER2 = internal::MakeCommandHeader(REG_LIGHT_ENV2, 1, false, 0x4);
322
323 u32 LIGHT_COMMAND[4] =
324 {
325 0,
326 HEADER,
327 0,
328 HEADER2
329 };
330
331 // TODO: Shadow には未対応。
332
333 // 0x1c3 LightEnv.FUNC_MODE1のマッピング
334 // shadowEnable [0]
335 // fresnelSelector[3:2]
336 // layerConfig [7:4]
337 // shadowPrimary [16]
338 // shadowSecondary[17]
339 // invertShadow [18]
340 // shadowAlpha [19]
341 // bumpSelector [23:22]
342 // shadowSelector [25:24]
343 // clampHighlights[27]
344 // bumpMode [29:28]
345 // bumpRenorm [30]
346 // 必ず1を設定 [31]
347 // tex0 remapping [9:8] 0 としておけば問題ない。
348 // tex1 remapping [11:10] 1としておけば問題ない
349
350 u32 layerConfig = fragmentLighting.GetLayerConfig();
351 u32 fresnelSelector = fragmentLighting.GetFresnelConfig();
352 u32 bumpSelector = fragmentLighting.GetBumpTextureIndex();
353 u32 bumpMode = fragmentLighting.GetBumpMode();
354 // bumpMode が BUMP_NOT_USED の場合と bumpRenorm が true の場合に 0に設定する。
355 bool bumpRenorm = fragmentLighting.IsBumpRenormalize() || (bumpMode == 0);
356 bool clampHighlights = ut::CheckFlag(fragmentLighting.GetFlags(), ResFragmentLightingData::FLAG_CLAMP_HIGH_LIGHT);
357
358 LIGHT_COMMAND[0] = fresnelSelector << 2 |
359 layerConfig << 4 |
360 bumpSelector << 22 |
361 (clampHighlights ? 1 : 0) << 27 |
362 bumpMode << 28 |
363 0x1u << 10 |
364 (bumpRenorm ? 0 : 1) << 30 |
365 0x1u << 31;
366
367 // 0x1c4 LightEnv.FUNC_MODE2のマッピング
368 // sourceShadowed [7:0]
369 // lutEnabledD0 [16]
370 // lutEnabledD1 [17]
371 // lutEnabledSP [18] 常に1
372 // fresnelSelector [19] GL_LIGHT_ENV_NO_FRESNEL_DMP の場合1
373 // lutEnabledRefl [22:20]
374 // spotEnabled [15:8] TSのみの設定。
375 // distanceAttnEnabled [31:24] TSのみの設定。
376
377 bool lutEnabledD0 = ut::CheckFlag(fragmentLighting.GetFlags(), ResFragmentLightingData::FLAG_DISTRIBUTION0_ENABLED);
378 bool lutEnabledD1 = ut::CheckFlag(fragmentLighting.GetFlags(), ResFragmentLightingData::FLAG_DISTRIBUTION1_ENABLED);
379 bool lutEnabledRefl = ut::CheckFlag(fragmentLighting.GetFlags(), ResFragmentLightingData::FLAG_REFLECTION_ENABLED);
380
381 LIGHT_COMMAND[2] = (lutEnabledD0 ? 0 : 1) << 16 |
382 (lutEnabledD1 ? 0 : 1) << 17 |
383 1 << 18 |
384 ((fresnelSelector == 0) ? 1 : 0) << 19 |
385 ((lutEnabledRefl ? 0 : 7) << 20);
386
387 internal::NWUseCmdlist<sizeof(LIGHT_COMMAND)>( &LIGHT_COMMAND[0] );
388 }
389
390 //--------------------------------------------------------------------------
391 //! @brief 頂点属性の設定をクリアします。
392 //---------------------------------------------------------------------------
393 void ClearVertexAttribute();
394
395 //--------------------------------------------------------------------------
396 //! @brief 頂点属性の設定をおこないます。
397 //!
398 //! @param[in] shape シェイプクラスです。
399 //! @param[in] shaderProgramDesc シェーダープログラムの詳細設定を表すバイナリリソースクラスです。
400 //!
401 //! @return 生成したコマンドのサイズです。
402 //---------------------------------------------------------------------------
403 s32 SetupVertexAttributeCommand(
404 CommandBufferInfo& bufferInfo,
405 ResSeparateDataShape shape,
406 ResShaderProgramDescription shaderProgramDesc );
407
408 s32 SetupVertexAttributeCommand(
409 CommandBufferInfo& bufferInfo,
410 ResParticleShape shape,
411 ResShaderProgramDescription shaderProgramDesc );
412
413 //--------------------------------------------------------------------------
414 //! @brief 頂点属性の非アクティブ化設定をおこないます。
415 //!
416 //! @param[in] shape シェイプクラスです。
417 //! @param[in] shaderProgramDesc シェーダープログラムの詳細設定を表すバイナリリソースクラスです。
418 //!
419 //! @return 生成したコマンドのサイズです。
420 //---------------------------------------------------------------------------
421 s32 SetupDeactivateVertexAttributeCommand(
422 CommandBufferInfo& bufferInfo,
423 ResSeparateDataShape shape,
424 ResShaderProgramDescription shaderProgramDesc );
425
426 s32 SetupDeactivateVertexAttributeCommand(
427 CommandBufferInfo& bufferInfo,
428 ResParticleShape shape,
429 ResShaderProgramDescription shaderProgramDesc );
430
431
432 //--------------------------------------------------------------------------
433 //! @brief シェーダモードの設定をおこないます。
434 //!
435 //! @param[in] useGeometry ジオメトリシェーダの有無です。
436 //!
437 //! @return 生成したコマンドのサイズです。
438 //---------------------------------------------------------------------------
439 s32 SetupShaderProgramMode(bool useGeometry);
440
441 //--------------------------------------------------------------------------
442 //! @brief インデックスストリーム単位の DrawElements のコマンドを生成します。
443 //!
444 //! @param[in] shaderProgramDescription シェーダープログラムの詳細設定を表すバイナリリソースクラスです。
445 //! @param[in] indexStream 頂点ストリームによる頂点属性を表すバイナリリソースクラスです。
446 //!
447 //! @return 生成したコマンドのサイズです。
448 //---------------------------------------------------------------------------
449 s32 SetupDrawIndexStreamCommand(
450 CommandBufferInfo& bufferInfo,
451 ResIndexStream indexStream,
452 bool hasGeometryShader );
453
454 //---------------------------------------------------------------------------
455 //! @brief インデックスストリーム単位の DrawElements のコマンドサイズを計算します。
456 //!
457 //! @param[in] indexStream 頂点ストリームによる頂点属性を表すバイナリリソースクラスです。
458 //!
459 //! @return コマンドのサイズです。
460 //---------------------------------------------------------------------------
461 s32 CalcSetupDrawIndexStreamCommand( ResIndexStream indexStream );
462
463
464 //---------------------------------------------------------------------------
465 //! @brief 頂点属性セットアップ用コマンドのコマンドサイズを計算します。
466 //! SeparateDataShape 用です。
467 //!
468 //! @param[in] shape 対象となるシェイプです。
469 //! @param[in] shaderProgramDesc 使用するシェーダプログラムです。
470 //!
471 //! @return コマンドのサイズです。
472 //---------------------------------------------------------------------------
473 s32 CalcSetupActivateVertexAttributeCommandSize(
474 ResSeparateDataShape shape,
475 ResShaderProgramDescription shaderProgramDesc );
476
477 //---------------------------------------------------------------------------
478 //! @brief 頂点属性セットアップ用コマンドのコマンドサイズを計算します。
479 //! ResParticleShape 用です。
480 //!
481 //! @param[in] shape 対象となるシェイプです。
482 //! @param[in] shaderProgramDesc 使用するシェーダプログラムです。
483 //!
484 //! @return コマンドのサイズです。
485 //---------------------------------------------------------------------------
486 s32 CalcSetupActivateVertexAttributeCommandSize(
487 ResParticleShape shape,
488 ResShaderProgramDescription shaderProgramDesc );
489
490 //---------------------------------------------------------------------------
491 //! @brief 頂点属性無効化用コマンドのコマンドサイズを計算します。
492 //! SeparateDataShape 用です。
493 //!
494 //! @param[in] shape 対象となるシェイプです。
495 //! @param[in] shaderProgramDesc 使用するシェーダプログラムです。
496 //!
497 //! @return コマンドのサイズです。
498 //---------------------------------------------------------------------------
499 s32 CalcSetupDeactivateVertexAttributeCommandSize(
500 ResSeparateDataShape shape,
501 ResShaderProgramDescription shaderProgramDesc );
502
503 //---------------------------------------------------------------------------
504 //! @brief 頂点属性無効化用コマンドのコマンドサイズを計算します。
505 //! ResParticleShape 用です。
506 //!
507 //! @param[in] shape 対象となるシェイプです。
508 //! @param[in] shaderProgramDesc 使用するシェーダプログラムです。
509 //!
510 //! @return コマンドのサイズです。
511 //---------------------------------------------------------------------------
512 s32 CalcSetupDeactivateVertexAttributeCommandSize(
513 ResParticleShape shape,
514 ResShaderProgramDescription shaderProgramDesc );
515
516
517
518 } // namespace internal
519 } // namespace gfx
520 } // namespace nw
521
522
523 #endif // NW_GFX_ACTIVATE_COMMAND_H_
524