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