/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_ShaderProgram.h Copyright (C)2009-2011 Nintendo/HAL Laboratory, Inc. All rights reserved. These coded instructions, statements, and computer programs contain proprietary information of Nintendo and/or its licensed developers and are protected by national and international copyright laws. 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. The content herein is highly confidential and should be handled accordingly. $Revision: 31311 $ *---------------------------------------------------------------------------*/ #ifndef NW_GFX_SHADERPROGRAM_H_ #define NW_GFX_SHADERPROGRAM_H_ #include #include #include #include #include #include #include #include #include namespace nw { namespace gfx { class RenderContext; //! ジオメトリシェーダのモードを表す定義です。 enum GeometryShaderMode { //! ジオメトリシェーダが未初期化の状態です。 GEOMETRY_SHADER_MODE_UNINITIALIZED, //! ジオメトリシェーダを利用しません。 GEOMETRY_SHADER_MODE_NONE, //! ジオメトリシェーダを利用します。 GEOMETRY_SHADER_MODE_USED, //! ジオメトリシェーダのモードの定義の数です。 GEOMETRY_SHADER_MODE_COUNT }; //--------------------------------------------------------------------------- //! @brief 各種シェーダを組み合わせてリンクした実行可能なシェーダです。 //--------------------------------------------------------------------------- class ShaderProgram : public GfxObject { public: //---------------------------------------- //! @name 取得/設定 //@{ //! @brief 詳細設定を有効化します。 //! //! @param[in] shaderProgramDescription シェーダプログラムの詳細設定です。 //! void ActivateDescription(ResShaderProgramDescription shaderProgramDescription); //! @brief ジオメトリシェーダのモードの設定をします。 //! //! @param[in] useGeometry ジオメトリシェーダの有無です。 //! void ActivateShaderProgramMode(bool useGeometry); //! @brief 詳細設定を無効化します。 void DeactivateDescription() { // ジオメトリシェーダのモード設定をリセットします。 m_GeometryShaderMode = GEOMETRY_SHADER_MODE_UNINITIALIZED; #if defined(NW_GFX_PROGRAM_OBJECT_ENABLED) m_UniformLocation = NULL; #endif m_ProgramObject = 0; m_Description = ResShaderProgramDescription( 0 ); } //! @brief リソースを取得します。 //! //! @return シェーダプログラムの詳細設定です。 //! const ResShaderProgramDescription GetActiveDescription() const { return m_Description; } #if defined(NW_GFX_PROGRAM_OBJECT_ENABLED) //! @brief プログラムオブジェクトを取得します。 //! //! @return プログラムオブジェクトです。 //! GLuint GetProgramObject() const { return m_ProgramObject; } #endif //! @brief パーティクル用のシェーダか調べます。 //! //! @return パーティクル用のシェーダの場合はtrueを返します。 //! bool IsParticleShader() const { return m_Description.GetGeometryShaderIndex() > 0; } //@} //---------------------------------------- //! @name 頂点属性 //@{ //--------------------------------------------------------------------------- //! @brief 頂点属性のインデックスを取得します。 //! //! 無効な頂点属性の場合は-1を返します。 //! //! @param[in] usage 頂点属性のUsageです。 //! //! @return 頂点属性のインデックスです。 //--------------------------------------------------------------------------- NW_INLINE int GetVertexAttributeIndex( ResVertexAttribute::VertexAttributeUsage usage) const; //--------------------------------------------------------------------------- //! @brief 頂点属性のインデックスを取得します。 //! //! @param[in] usage 頂点属性のUsageです。 //! //! @return 頂点属性のインデックスです。 //--------------------------------------------------------------------------- int GetVertexAttributeIndex(u32 usage) const { return GetVertexAttributeIndex( static_cast(usage)); } //@} //---------------------------------------- //! @name シェーダー定数 //@{ //! @brief プロジェクションマトリクスを設定します。 //! //! @param[in] projection プロジェクションマトリクスです。 //! void SetProjection(const math::MTX44& projection) const { internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_PROJMTX_INDEX, 4, projection); } //! @brief ビューマトリクスを設定します。 //! //! @param[in] view ビューマトリクスです。 //! void SetViewMatrix(const math::MTX34& view) const { internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_VIEWMTX_INDEX, 3, view); } //! @brief ワールドマトリクスを設定します。 //! //! @param[in] world ワールドマトリクスです。 //! void SetWorldMatrix(const math::MTX34& world) const { internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_WRLDMTX_INDEX, 3, world); } //! @brief モデル法線マトリクスを設定します。 //! //! @param[in] normalMatrix モデル法線マトリクスです。 //! void SetModelNormalMatrix(const math::MTX34& normalMatrix) const { internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_NORMMTX_INDEX, 3, normalMatrix); } //! @brief ボーンで法線マトリクスを使うフラグを設定します。 //! 廃止予定です。 //! //! @param[in] use ボーンで法線マトリクスを使うフラグです。 //! NW_DEPRECATED_FUNCTION(void SetUseBoneNormalMatrix(bool use) const) { NW_UNUSED_VARIABLE(use); } //! @brief ユニバーサルレジスタに値を設定します。 //! //! @param[in] index ユニバーサルレジスタでのインデックスです。 //! @param[in] vec 設定する値です。 //! void SetUniversal(int index, const math::VEC4& vec) const { internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_UNIVREG_INDEX + index, 1, vec); } //! @brief ユニバーサルレジスタに値を設定します。 //! //! @param[in] index ユニバーサルレジスタでのインデックスです。 //! @param[in] mtx 設定する値です。 //! void SetUniversal(int index, const math::MTX34& mtx) const { internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_UNIVREG_INDEX + index, 3, mtx); } //! @brief ユニバーサルレジスタに値を設定します。 //! //! @param[in] index ユニバーサルレジスタでのインデックスです。 //! @param[in] mtx 設定する値です。 //! void SetUniversal(int index, const math::MTX44& mtx) const { internal::NWSetVertexUniform4fv(VERTEX_SHADER_UNIFORM_UNIVREG_INDEX + index, 4, mtx); } #if defined(NW_GFX_PROGRAM_OBJECT_ENABLED) //! @brief boolの値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] value 設定する値です。 //! void SetUniformBool(ShaderUniform location, bool value) const { glUniform1i(m_UniformLocation->GetUniformLocation(location), value ? 1 : 0); } //! @brief f32の値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] value 設定する値です。 //! void SetUniformFloat(ShaderUniform location, f32 value) const { glUniform1f(m_UniformLocation->GetUniformLocation(location), value); } //! @brief s32の値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] value 設定する値です。 //! void SetUniformInt(ShaderUniform location, s32 value) const { glUniform1i(m_UniformLocation->GetUniformLocation(location), value); } //! @brief s32の値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] x 設定する値です。 //! @param[in] y 設定する値です。 //! void SetUniformInt(ShaderUniform location, s32 x, s32 y) const { glUniform2i(m_UniformLocation->GetUniformLocation(location), x, y); } //! @brief s32の値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] x 設定する値です。 //! @param[in] y 設定する値です。 //! @param[in] z 設定する値です。 //! void SetUniformInt(ShaderUniform location, s32 x, s32 y, s32 z) const { glUniform3i(m_UniformLocation->GetUniformLocation(location), x, y, z); } //! @brief s32の値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] x 設定する値です。 //! @param[in] y 設定する値です。 //! @param[in] z 設定する値です。 //! @param[in] w 設定する値です。 //! void SetUniformInt(ShaderUniform location, s32 x, s32 y, s32 z, s32 w) const { glUniform4i(m_UniformLocation->GetUniformLocation(location), x, y, z, w); } //! @brief 2要素のfloatの配列を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] pointer 設定する配列です。 //! void SetUniform2(ShaderUniform location, const GLfloat* pointer) const { glUniform2fv(m_UniformLocation->GetUniformLocation(location), 1, pointer); } //! @brief 3要素のfloatの配列を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] pointer 設定する配列です。 //! void SetUniform3(ShaderUniform location, const GLfloat* pointer) const { glUniform3fv(m_UniformLocation->GetUniformLocation(location), 1, pointer); } //! @brief 4要素のfloatの配列を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] pointer 設定する配列です。 //! void SetUniform4(ShaderUniform location, const GLfloat* pointer) const { glUniform4fv(m_UniformLocation->GetUniformLocation(location), 1, pointer); } //! @brief VectorやMatrixの値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] vec 設定する値です。 //! void SetUniform(ShaderUniform location, const math::VEC2& vec) const { glUniform2fv(m_UniformLocation->GetUniformLocation(location), 1, vec); } //! @brief VectorやMatrixの値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] vec 設定する値です。 //! void SetUniform(ShaderUniform location, const math::VEC3& vec) const { glUniform3fv(m_UniformLocation->GetUniformLocation(location), 1, vec); } //! @brief VectorやMatrixの値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] vec 設定する値です。 //! void SetUniform(ShaderUniform location, const math::VEC4& vec) const { glUniform4fv(m_UniformLocation->GetUniformLocation(location), 1, vec); } //! @brief VectorやMatrixの値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] mtx 設定する値です。 //! void SetUniform(ShaderUniform location, const math::MTX22& mtx) const { glUniform2fv(m_UniformLocation->GetUniformLocation(location), 2, mtx); } //! @brief VectorやMatrixの値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] mtx 設定する値です。 //! void SetUniform(ShaderUniform location, const math::MTX23& mtx) const { glUniform3fv(m_UniformLocation->GetUniformLocation(location), 2, mtx); } //! @brief VectorやMatrixの値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] mtx 設定する値です。 //! void SetUniform(ShaderUniform location, const math::MTX34& mtx) const { glUniform4fv(m_UniformLocation->GetUniformLocation(location), 3, mtx); } //! @brief VectorやMatrixの値を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] mtx 設定する値です。 //! void SetUniform(ShaderUniform location, const math::MTX44& mtx) const { glUniform4fv(m_UniformLocation->GetUniformLocation(location), 4, mtx); } //! @brief Vectorの配列を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] vec 設定する配列です。 //! @param[in] count 設定する配列の数です。 //! void SetUniforms(ShaderUniform location, const math::VEC2* vec, int count) const { glUniform2fv(m_UniformLocation->GetUniformLocation(location), count, *vec); } //! @brief Vectorの配列を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] vec 設定する配列です。 //! @param[in] count 設定する配列の数です。 //! void SetUniforms(ShaderUniform location, const math::VEC3* vec, int count) const { glUniform3fv(m_UniformLocation->GetUniformLocation(location), count, *vec); } //! @brief Vectorの配列を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] vec 設定する配列です。 //! @param[in] count 設定する配列の数です。 //! void SetUniforms(ShaderUniform location, const math::VEC4* vec, int count) const { glUniform4fv(m_UniformLocation->GetUniformLocation(location), count, *vec); } //! @brief 配列を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] array 設定する配列です。 //! template void SetUniforms(ShaderUniform location, const ut::MoveArray* array) const { NW_NULL_ASSERT(array); if (array->empty()) { return; } this->SetUniforms(location, array->Elements(), array->size()); } //! @brief サイズを指定して配列を設定します。 //! //! @param[in] location シェーダーユニフォームのインデックス番号です。 //! @param[in] array 設定する配列です。 //! @param[in] size 配列の大きさです。 //! template void SetUniforms(ShaderUniform location, const ut::MoveArray* array, s32 size) const { NW_NULL_ASSERT(array); NW_ASSERT(size <= array->size()); this->SetUniforms(location, array->Elements(), size); } //! @brief ユーザーレジスタにパラメータを設定します。 //! //! locationにはglGetUniformLocationで取得したGLintの値を渡してください。 //! //! @param[in] location シェーダーユニフォームの場所です。 //! @param[in] parameter 設定するシェーダーパラメータです。 //! void SetUserUniform(GLint location, ResShaderParameterValue parameter) const { if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_BOOL1) { glUniform1iv(location, 1, reinterpret_cast(parameter.GetValueS32())); } else if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_FLOAT1) { glUniform1fv(location, 1, parameter.GetValueF32()); } else if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_FLOAT2) { glUniform2fv(location, 1, parameter.GetValueF32()); } else if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_FLOAT3) { glUniform3fv(location, 1, parameter.GetValueF32()); } else if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_FLOAT4) { glUniform4fv(location, 1, parameter.GetValueF32()); } } #endif // defined(NW_GFX_PROGRAM_OBJECT_ENABLED) //! @brief ユーザー頂点レジスタにパラメータを設定します。 //! //! @param[in] index 頂点シェーダーのレジスタ番号です。 //! @param[in] parameter 設定するシェーダーパラメータです。 //! void SetUserVertexUniform(s32 index, ResShaderParameterValue parameter) const { if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_BOOL1) { this->SetVertexUniformBool(index, parameter.GetValueBool()); } else if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_FLOAT1) { internal::NWSetVertexUniform1fv(index, 1, parameter.GetValueF32()); } else if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_FLOAT2) { internal::NWSetVertexUniform2fv(index, 1, parameter.GetValueF32()); } else if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_FLOAT3) { internal::NWSetVertexUniform3fv(index, 1, parameter.GetValueF32()); } else if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_FLOAT4) { internal::NWSetVertexUniform4fv(index, 1, parameter.GetValueF32()); } } //! @brief ユーザージオメトリレジスタにパラメータを設定します。 //! //! @param[in] index ジオメトリシェーダーのレジスタ番号です。 //! @param[in] parameter 設定するシェーダーパラメータです。 //! void SetUserGeometryUniform(s32 index, ResShaderParameterValue parameter) const { if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_BOOL1) { this->SetGeometryUniformBool(index, parameter.GetValueBool()); } else if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_FLOAT1) { internal::NWSetGeometryUniform1fv(index, 1, parameter.GetValueF32()); } else if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_FLOAT2) { internal::NWSetGeometryUniform2fv(index, 1, parameter.GetValueF32()); } else if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_FLOAT3) { internal::NWSetGeometryUniform3fv(index, 1, parameter.GetValueF32()); } else if (parameter.GetUniformType() == ResShaderParameterValue::TYPE_FLOAT4) { internal::NWSetGeometryUniform4fv(index, 1, parameter.GetValueF32()); } } //! @brief boolの値を設定します。 //! //! @param[in] index シェーダーユニフォームのインデックス番号です。 //! @param[in] value 設定する値です。 //! void SetVertexUniformBool(int index, bool value) const { NW_ASSERT(0 <= index && index < 16); if (value) { m_VertexIntUniforms[0] |= 0x1 << index; } else { m_VertexIntUniforms[0] &= ~(0x1 << index); } } //! @brief boolの値を設定します。 //! //! @param[in] index シェーダーユニフォームのインデックス番号です。 //! @param[in] value 設定する値です。 //! void SetGeometryUniformBool(int index, bool value) const { NW_ASSERT(0 <= index && index < 16); if (value) { m_GeometryIntUniforms[0] |= 0x1 << index; } else { m_GeometryIntUniforms[0] &= ~(0x1 << index); } } //! @brief intの値を設定します。 //! //! @param[in] index シェーダーユニフォームのインデックス番号です。 //! @param[in] value 設定する値です。 //! void SetVertexUniformInt(int index, s32 value) const { NW_ASSERT(0 <= index && index < 4); m_VertexIntUniforms[2 + index] = value & 0xFF; } //! @brief intの値を設定します。 //! //! @param[in] index シェーダーユニフォームのインデックス番号です。 //! @param[in] value 設定する値です。 //! void SetGeometryUniformInt(int index, s32 value) const { NW_ASSERT(0 <= index && index < 4); m_GeometryIntUniforms[2 + index] = value & 0xFF; } //! @brief intの値を設定します。 //! //! @param[in] index シェーダーユニフォームのインデックス番号です。 //! @param[in] x 設定する x 値です。 //! @param[in] y 設定する y 値です。 //! void SetVertexUniformInt(int index, s32 x, s32 y) const { NW_ASSERT(0 <= index && index < 4); m_VertexIntUniforms[2 + index] = (x & 0xFF) | ((y & 0xFF) << 8); } //! @brief intの値を設定します。 //! //! @param[in] index シェーダーユニフォームのインデックス番号です。 //! @param[in] x 設定する x 値です。 //! @param[in] y 設定する y 値です。 //! void SetGeometryUniformInt(int index, s32 x, s32 y) const { NW_ASSERT(0 <= index && index < 4); m_GeometryIntUniforms[2 + index] = (x & 0xFF) | ((y & 0xFF) << 8); } //! @brief intの値を設定します。 //! //! @param[in] index シェーダーユニフォームのインデックス番号です。 //! @param[in] x 設定する x 値です。 //! @param[in] y 設定する y 値です。 //! @param[in] z 設定する z 値です。 //! void SetVertexUniformInt(int index, s32 x, s32 y, s32 z) const { NW_ASSERT(0 <= index && index < 4); m_VertexIntUniforms[2 + index] = (x & 0xFF) | ((y & 0xFF) << 8) | ((z & 0xFF) << 16); } //! @brief intの値を設定します。 //! //! @param[in] index シェーダーユニフォームのインデックス番号です。 //! @param[in] x 設定する x 値です。 //! @param[in] y 設定する y 値です。 //! @param[in] z 設定する z 値です。 //! void SetGeometryUniformInt(int index, s32 x, s32 y, s32 z) const { NW_ASSERT(0 <= index && index < 4); m_GeometryIntUniforms[2 + index] = (x & 0xFF) | ((y & 0xFF) << 8) | ((z & 0xFF) << 16); } //! @brief VertexUniform と GeometryUniform の状態をコマンドへ Flush します。 void FlushUniform() const { internal::NWUseCmdlist(&m_VertexIntUniforms[0]); if (m_Description.GetGeometryShaderIndex() >= 0) { internal::NWUseCmdlist(&m_GeometryIntUniforms[0]); } } //@} //---------------------------------------- //! @name シェーダーシンボル //@{ //@} //--------------------------------------------------------------------------- //! @brief コンストラクタです。 //--------------------------------------------------------------------------- ShaderProgram(os::IAllocator* allocator); private: //--------------------------------------------------------------------------- //! @brief デストラクタです。 //--------------------------------------------------------------------------- virtual ~ShaderProgram(); ResShaderProgramDescription m_Description; #if defined(NW_GFX_PROGRAM_OBJECT_ENABLED) ShaderUniformLocation* m_UniformLocation; #endif GLuint m_ProgramObject; GeometryShaderMode m_GeometryShaderMode; mutable u32 m_VertexIntUniforms[6]; mutable u32 m_GeometryIntUniforms[6]; mutable u32 m_DisableGeometry[2]; }; NW_INLINE int ShaderProgram::GetVertexAttributeIndex( ResVertexAttribute::VertexAttributeUsage usage ) const { ResShaderProgramDescription description = this->GetActiveDescription(); NW_ASSERT(description.IsValid()); return description.GetAttributeIndices(usage); } } // namespace gfx } // namespace nw #endif // NW_GFX_SHADERPROGRAM_H_