/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_ActivateCommand.h Copyright (C)2009-2010 Nintendo Co., Ltd./HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo of America Inc. and/or Nintendo Company Ltd., and are protected by Federal copyright law. They may not be disclosed to third parties or copied or duplicated in any form, in whole or in part, without the prior written consent of Nintendo. $Revision: 25269 $ *---------------------------------------------------------------------------*/ #ifndef NW_GFX_ACTIVATE_COMMAND_H_ #define NW_GFX_ACTIVATE_COMMAND_H_ #include #include #include #include #include #include #include #include #include namespace nw { namespace gfx { class ShaderProgram; namespace internal { class CommandCacheHelper { public: //-------------------------------------------------------------------------- //! @brief U32 で表されたカラーを掛けます。 //! //! @param[in] lhs 乗算を行う U32 カラー値です。 //! @param[in] rhs 乗算を行う U32 カラー値です。 //! //! @return 乗算後の値を返します。 //--------------------------------------------------------------------------- static NW_INLINE u32 MultU32Color(u32 lhs, u32 rhs) { const u32 MASK = 0xff; u8 r = ((lhs & MASK) * (rhs & MASK)) >> 8; u8 g = (((lhs >> 8) & MASK) * ((rhs >> 8) & MASK)) >> 8; u8 b = (((lhs >> 16) & MASK) * ((rhs >> 16) & MASK)) >> 8; return (static_cast(r) << 20) | (static_cast(g) << 10) | (static_cast(b)); } //-------------------------------------------------------------------------- //! @brief U32 で表されたカラーを掛けた後に加算を行います。 //! //! @param[in] lhs 乗算を行う U32 カラー値です。 //! @param[in] rhs 乗算を行う U32 カラー値です。 //! @param[in] add 加算を行う U32 カラー値です。 //! //! @return 乗算後の値を返します。 //--------------------------------------------------------------------------- static NW_INLINE u32 MultAddU32Color(u32 lhs, u32 rhs, u32 add) { const u32 MASK = 0xff; u8 r = ut::Clamp((((lhs & MASK) * (rhs & MASK)) >> 8) + (add & MASK), 0, 255); u8 g = ut::Clamp(((((lhs >> 8) & MASK) * ((rhs >> 8) & MASK)) >> 8) + ((add >> 8) & MASK), 0, 255); u8 b = ut::Clamp(((((lhs >> 16) & MASK) * ((rhs >> 16) & MASK)) >> 8) + ((add >> 16) & MASK), 0, 255); return (static_cast(r) << 20) | (static_cast(g) << 10) | (static_cast(b)); } //-------------------------------------------------------------------------- //! @brief 頂点ストリームの型と要素数から、HWの頂点フォーマット設定を取得します。 //! //! @param[in] dimension 頂点属性の要素数です。 //! @param[in] format 頂点属性のフォーマットです。 //! //! @return ハードに設定する頂点フォーマット定数を返します。 //--------------------------------------------------------------------------- static NW_INLINE u32 GetVertexFormat(s32 dimension, GLuint format) { u32 result = 0; switch ( format ) { case GL_BYTE: result = 0; break; case GL_UNSIGNED_BYTE: result = 1; break; case GL_SHORT: result = 2; break; case GL_FLOAT: result = 3; break; default: NW_FATAL_ERROR("unknown format"); } return result + ((dimension - 1) << 2); } //-------------------------------------------------------------------------- //! @brief 頂点ストリームの型と要素数から、頂点サイズを取得します。 //! //! @param[in] dimension 頂点属性の要素数です。 //! @param[in] format 頂点属性のフォーマットです。 //! //! @return ハードに設定する頂点サイズを返します。 //--------------------------------------------------------------------------- static NW_INLINE u32 GetVertexSize(s32 dimension, GLuint format) { u32 result = 0; switch ( format ) { case GL_BYTE: return dimension; case GL_UNSIGNED_BYTE: return dimension; case GL_SHORT: return dimension * 2; case GL_FLOAT: return dimension * 4; default: NW_FATAL_ERROR("unknown format"); } return 0; } }; //-------------------------------------------------------------------------- //! @brief フラグメントライト数を設定します。 //! //! @param[in] count 有効なライトの数です。 //--------------------------------------------------------------------------- NW_INLINE void ActivateFragmentLightCount(s32 count) { enum { REG_FRAGMENT_LIGHT_COUNT = 0x1c2, REG_FRAGMENT_LIGHT_MASK = 0x1d9 }; const u32 COUNT_HEADER = internal::MakeCommandHeader(REG_FRAGMENT_LIGHT_COUNT, 1, false, 0x1); const u32 LIGHT_MASK_HEADER = internal::MakeCommandHeader(REG_FRAGMENT_LIGHT_MASK, 1, false, 0xF); u32 LIGHT_COUNT_COMMAND[] = { 0, COUNT_HEADER #if defined(NW_TARGET_CTR_GL_FINAL) ,0, LIGHT_MASK_HEADER #endif }; LIGHT_COUNT_COMMAND[0] = (count > 0) ? count - 1 : 0; #if defined(NW_TARGET_CTR_GL_FINAL) for (int i = 0; i < count; ++i) { LIGHT_COUNT_COMMAND[2] |= i << (4 * i); } #endif internal::NWUseCmdlist( &LIGHT_COUNT_COMMAND[0] ); } //-------------------------------------------------------------------------- //! @brief フラグメントライトレジスタの設定をおこないます。 //! //! @param[in] index ライトを設定するインデックス番号です。 //! @param[in] materialColor マテリアルカラーです。 //! @param[in] light フラグメントライトセットです。 //! @param[in] useReflection 反射テーブルが有効かどうかを表すフラグです。 //--------------------------------------------------------------------------- NW_INLINE void ActivateFragmentLight(s32 index, ResMaterialColor materialColor, const FragmentLight* light, bool useReflection) { enum { REG_FRAGMENT_COLOR_BASE = 0x140 }; const u32 HEADER = internal::MakeCommandHeader(REG_FRAGMENT_COLOR_BASE, 4, true, 0xF); NW_NULL_ASSERT( light ); ResFragmentLight resLight = light->GetResFragmentLight(); u32 specular0U32 = CommandCacheHelper::MultU32Color(resLight.GetSpecular0U32(), materialColor.GetSpecular0U32()); u32 diffuseU32 = CommandCacheHelper::MultU32Color(resLight.GetDiffuseU32(), materialColor.GetDiffuseU32()); u32 ambientU32 = CommandCacheHelper::MultU32Color(resLight.GetAmbientU32(), materialColor.GetAmbientU32()); u32 specular1U32 = resLight.GetSpecular1U32(); if (useReflection) { const u32 MASK = 0xff; u8 r = (specular1U32 & MASK); u8 g = ((specular1U32 >> 8) & MASK); u8 b = ((specular1U32 >> 16) & MASK); specular1U32 = (static_cast(r) << 20) | (static_cast(g) << 10) | (static_cast(b)); } else { specular1U32 = CommandCacheHelper::MultU32Color(resLight.GetSpecular1U32(), materialColor.GetSpecular1U32()); } u32 LIGHT_COMMAND[6] = { specular0U32, HEADER + (0x10 * index), specular1U32, diffuseU32, ambientU32, 0 // padding }; internal::NWUseCmdlist( &LIGHT_COMMAND[0] ); } //-------------------------------------------------------------------------- //! @brief アンビエントライト用のコマンドを設定します。 //! //! @param[in] materialColor マテリアルカラーの情報です。 //! @param[in] light アンビエントライトの情報です。 //--------------------------------------------------------------------------- NW_INLINE void ActivateFragmentAmbientLight(ResMaterialColor materialColor, const AmbientLight* light) { enum { REG_FRAGMENT_COLOR_AMBIENT = 0x1c0 }; u32 ambientU32 = 0x0; const u32 HEADER = internal::MakeCommandHeader(REG_FRAGMENT_COLOR_AMBIENT, 1, false, 0xF); if (light) { ResAmbientLight resLight = light->GetResAmbientLight(); ambientU32 = CommandCacheHelper::MultAddU32Color(resLight.GetAmbientU32(), materialColor.GetAmbientU32(), materialColor.GetEmissionU32()); } else { u32 emissionU32 = materialColor.GetEmissionU32(); const u32 MASK = 0xff; u8 r = (emissionU32 & MASK); u8 g = ((emissionU32 >> 8) & MASK); u8 b = ((emissionU32 >> 16) & MASK); ambientU32 = (static_cast(r) << 20) | (static_cast(g) << 10) | (static_cast(b)); } u32 LIGHT_COMMAND[2] = { ambientU32, HEADER }; internal::NWUseCmdlist( &LIGHT_COMMAND[0] ); } //-------------------------------------------------------------------------- //! @brief フラグメントライトのパラメータを設定します。 //! //! @param[in] index ライトのインデックスを設定します。 //! @param[in] isDirectional ディレクショナルライトかどうかのフラグです。 //! @param[in] twoSided 2 sided ライティングのフラグです。 //! @param[in] geomFactor0 ジオメトリックファクタ0を使用するかどうかのフラグです。 //! @param[in] geomFactor1 ジオメトリックファクタ1を使用するかどうかのフラグです。 //--------------------------------------------------------------------------- NW_INLINE void ActivateFragmentLightParameters(s32 index, bool isDirectional, bool twoSided, bool geomFactor0, bool geomFactor1) { enum { REG_FRAGMENT_LIGHT_TYPE = 0x149 }; const u32 HEADER = internal::MakeCommandHeader(REG_FRAGMENT_LIGHT_TYPE, 1, false, 0x1); u32 LIGHT_COMMAND[2] = { 0, HEADER + 0x10 * index }; if (isDirectional) { LIGHT_COMMAND[0] |= 0x1; } if (twoSided) { LIGHT_COMMAND[0] |= 0x2; } if (geomFactor0) { LIGHT_COMMAND[0] |= 0x4; } if (geomFactor1) { LIGHT_COMMAND[0] |= 0x8; } internal::NWUseCmdlist( &LIGHT_COMMAND[0] ); } //-------------------------------------------------------------------------- //! @brief フラグメントライティングの設定をおこないます。 //! //! @param[in] fragmentLighting フラグメントライティング設定です。 //--------------------------------------------------------------------------- NW_INLINE void ActivateFragmentLighting(const ResFragmentLighting fragmentLighting) { const u32 REG_LIGHT_ENV = 0x1c3; const u32 REG_LIGHT_ENV2 = 0x1c4; const u32 HEADER = internal::MakeCommandHeader(REG_LIGHT_ENV, 1, false, 0xf); const u32 HEADER2 = internal::MakeCommandHeader(REG_LIGHT_ENV2, 1, false, 0x4); u32 LIGHT_COMMAND[4] = { 0, HEADER, 0, HEADER2 }; // TODO: Shadow には未対応。 // 0x1c3 LightEnv.FUNC_MODE1のマッピング // shadowEnable [0] // fresnelSelector[3:2] // layerConfig [7:4] // shadowPrimary [16] // shadowSecondary[17] // invertShadow [18] // shadowAlpha [19] // bumpSelector [23:22] // shadowSelector [25:24] // clampHighlights[27] // bumpMode [29:28] // bumpRenorm [30] // 必ず1を設定 [31] // tex0 remapping [9:8] 0 としておけば問題ない。 // tex1 remapping [11:10] 1としておけば問題ない u32 layerConfig = fragmentLighting.GetLayerConfig(); u32 fresnelSelector = fragmentLighting.GetFresnelConfig(); u32 bumpSelector = fragmentLighting.GetBumpTextureIndex(); u32 bumpMode = fragmentLighting.GetBumpMode(); // bumpMode が BUMP_NOT_USED の場合と bumpRenorm が true の場合に 0に設定する。 bool bumpRenorm = fragmentLighting.IsBumpRenormalize() || (bumpMode == 0); bool clampHighlights = ut::CheckFlag(fragmentLighting.GetFlags(), ResFragmentLightingData::FLAG_CLAMP_HIGH_LIGHT); LIGHT_COMMAND[0] = fresnelSelector << 2 | layerConfig << 4 | bumpSelector << 22 | (clampHighlights ? 1 : 0) << 27 | bumpMode << 28 | 0x1u << 10 | (bumpRenorm ? 0 : 1) << 30 | 0x1u << 31; // 0x1c4 LightEnv.FUNC_MODE2のマッピング // sourceShadowed [7:0] // lutEnabledD0 [16] // lutEnabledD1 [17] // lutEnabledSP [18] 常に1 // fresnelSelector [19] GL_LIGHT_ENV_NO_FRESNEL_DMP の場合1 // lutEnabledRefl [22:20] // spotEnabled [15:8] TSのみの設定。 // distanceAttnEnabled [31:24] TSのみの設定。 bool lutEnabledD0 = ut::CheckFlag(fragmentLighting.GetFlags(), ResFragmentLightingData::FLAG_DISTRIBUTION0_ENABLED); bool lutEnabledD1 = ut::CheckFlag(fragmentLighting.GetFlags(), ResFragmentLightingData::FLAG_DISTRIBUTION1_ENABLED); bool lutEnabledRefl = ut::CheckFlag(fragmentLighting.GetFlags(), ResFragmentLightingData::FLAG_REFLECTION_ENABLED); LIGHT_COMMAND[2] = (lutEnabledD0 ? 0 : 1) << 16 | (lutEnabledD1 ? 0 : 1) << 17 | 1 << 18 | ((fresnelSelector == 0) ? 1 : 0) << 19 | ((lutEnabledRefl ? 0 : 7) << 20); internal::NWUseCmdlist( &LIGHT_COMMAND[0] ); } //-------------------------------------------------------------------------- //! @brief 頂点属性の設定をクリアします。 //--------------------------------------------------------------------------- void ClearVertexAttribute(); //-------------------------------------------------------------------------- //! @brief 頂点属性の設定をおこないます。 //! //! @param[in] shape シェイプクラスです。 //! @param[in] shaderProgramDesc シェーダープログラムの詳細設定を表すバイナリリソースクラスです。 //--------------------------------------------------------------------------- void SetupVertexAttributeCommand( ResSeparateDataShape shape, ResShaderProgramDescription shaderProgramDesc ); void SetupVertexAttributeCommand( ResParticleShape shape, ResShaderProgramDescription shaderProgramDesc ); //-------------------------------------------------------------------------- //! @brief 頂点属性の非アクティブ化設定をおこないます。 //! //! @param[in] shape シェイプクラスです。 //! @param[in] shaderProgramDesc シェーダープログラムの詳細設定を表すバイナリリソースクラスです。 //--------------------------------------------------------------------------- void SetupDeactivateVertexAttributeCommand( ResSeparateDataShape shape, ResShaderProgramDescription shaderProgramDesc ); void SetupDeactivateVertexAttributeCommand( ResParticleShape shape, ResShaderProgramDescription shaderProgramDesc ); //-------------------------------------------------------------------------- //! @brief シェーダモードの設定をおこないます。 //! //! @param[in] useGeometry ジオメトリシェーダの有無です。 //--------------------------------------------------------------------------- void SetupShaderProgramMode(bool useGeometry); //-------------------------------------------------------------------------- //! @brief DrawElementsのコマンドを生成します。 //! //! @param[in] shaderProgramDescription シェーダープログラムの詳細設定を表すバイナリリソースクラスです。 //! @param[in] indexStream 頂点ストリームによる頂点属性を表すバイナリリソースクラスです。 //--------------------------------------------------------------------------- void SetupDrawElementsCommand(const ResShaderProgramDescription shaderProgramDescription, ResIndexStream indexStream); } // namespace internal } // namespace gfx } // namespace nw #endif // NW_GFX_ACTIVATE_COMMAND_H_