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