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