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