/*---------------------------------------------------------------------------* Project: NintendoWare File: gfx_RenderContext.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: 26943 $ *---------------------------------------------------------------------------*/ #ifndef NW_GFX_RENDERCONTEXT_H_ #define NW_GFX_RENDERCONTEXT_H_ #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace nw { namespace gfx { class IRenderTarget; class Camera; class Model; class LookupTableCache; class Light; class FragmentLight; class VertexLight; class AmbientLight; class HemiSphereLight; class Fog; class ShaderProgram; //--------------------------------------------------------------------------- //! @brief 描画プロセスを制御する情報を格納するクラスです。 //--------------------------------------------------------------------------- class RenderContext : public GfxObject { private: NW_DISALLOW_COPY_AND_ASSIGN(RenderContext); public: //! @details :private enum { DEFAULT_MAX_CAMERAS = 32, //!< カメラのデフォルト最大数です。 DEFAULT_MAX_LIGHT_SETS = 128, //!< ライトセットのデフォルト最大数です。 DEFAULT_MAX_FOGS = 32, //!< フォグのデフォルト最大数です。 ATTRIBUTE_SCALES_VECTOR_COUNT = 3, VERTEX_LIGHT_SET_COUNT = 6, VERTEX_LIGHT_AMBIENT = 0, VERTEX_LIGHT_DIFFUSE = 1, VERTEX_LIGHT_POSITION = 2, VERTEX_LIGHT_SPOT_DIRECTION = 3, VERTEX_LIGHT_DISTANCE_ATTENUATION = 4, VERTEX_LIGHT_SPOT_FACTOR = 5 }; //! @brief 描画モードの定義です。 //! //! 描画モードを変更することでレンダーコンテキストの挙動を変更することができます。 enum RenderMode { //! 標準の描画モードです。 RENDERMODE_DEFAULT = 0, //! マテリアルの設定を無視します。 RENDERMODE_IGNORE_MATERIAL = 0x1 << 0 }; //! @brief リセットを行うステートの定義です。 //! //! ResetState の引数に渡すことで特定のステートのみリセットできます。 enum ResetStateMode { //! 設定されたモデルのワールド行列を表すステートです。 RESETSTATEMODE_MODEL_CACHE = 0x1 << 0, //! ActivateMaterial を行った場合に設定するマテリアルを表すステートです。 RESETSTATEMODE_MATERIAL = 0x1 << 1, //! 設定されたマテリアルを表すステートです。 RESETSTATEMODE_MATERIAL_CACHE = 0x1 << 2, //! 設定された描画に用いるカメラを表すステートです。 RESETSTATEMODE_CAMERA_CACHE = 0x1 << 3, //! 設定されたシーン環境を表すステートです。 RESETSTATEMODE_SCENE_ENVIRONMENT = 0x1 << 4, //! 設定されたシェーダープログラムを表すステートです。 RESETSTATEMODE_SHADER_PROGRAM = 0x1 << 5, //! 設定された参照テーブルを表すステートです。 RESETSTATEMODE_LOOK_UP_TABLE = 0x1 << 6, //! マテリアルのハッシュを表すステートです。 RESETSTATEMODE_HASH = 0x1 << 7, //! 設定された頂点属性を表すステートです。 RESETSTATEMODE_VERTEX_ATTRIBUTE = 0x1 << 8, //! 全てのステートを表します。 RESETSTATEMODE_ALL = RESETSTATEMODE_MODEL_CACHE | RESETSTATEMODE_MATERIAL | RESETSTATEMODE_MATERIAL_CACHE | RESETSTATEMODE_CAMERA_CACHE | RESETSTATEMODE_SCENE_ENVIRONMENT | RESETSTATEMODE_SHADER_PROGRAM | RESETSTATEMODE_LOOK_UP_TABLE | RESETSTATEMODE_HASH | RESETSTATEMODE_VERTEX_ATTRIBUTE }; struct MaterialHash { MaterialHash() { ResetMaterialHash(Model::MULTI_FLAG_BUFFER_MATERIAL); } u32 shaderParameter; u32 shadingParameter; u32 materialColor; u32 rasterization; u32 textureCoordinator; u32 textureMapper; u32 fragmentLighting; u32 fragmentLightingTable; u32 textureCombiner; u32 fragmentOperation; u32 alphaTest; //! @brief マテリアルのハッシュを無効化します。 //! //! @param[in] hashMask リセットを行うハッシュを表すマスクです。 //! NW_INLINE void ResetMaterialHash(s32 hashMask); }; //! @brief 頂点属性の配列です。 typedef ut::FixedSizeArray VertexAttributeArray; //! @brief 頂点属性のスケール値の配列です。 typedef ut::FixedSizeArray AttributeScaleArray; //---------------------------------------- //! @name 作成 //@{ //! @brief レンダーコンテキストを構築するためのクラスです。 class Builder { public: //! @brief コンストラクタです。 Builder() : m_MaxCameras(DEFAULT_MAX_CAMERAS), m_MaxLightSets(DEFAULT_MAX_LIGHT_SETS), m_MaxFogs(DEFAULT_MAX_FOGS), m_MaxVertexLights(LightSet::DEFAULT_MAX_VERTEX_LIGHTS), m_ParticleMaterialActivator(NULL) {} //! @brief デストラクタです。 ~Builder() {} //! @brief カメラの最大数を設定します。 Builder& MaxCameras(int maxCamera) { m_MaxCameras = maxCamera; return *this; } //! @brief ライトセットの最大数を設定します。 Builder& MaxLights(s32 max) { m_MaxLightSets = max; return *this; } //! @brief フォグの最大数を設定します。 Builder& MaxFogs(s32 max) { m_MaxFogs = max; return *this; } //! @brief 頂点ライトの最大数を設定します。 Builder& MaxVertexLights(int maxVertexLights) { m_MaxVertexLights = maxVertexLights; return *this; } //! @brief パーティクル用マテリアルの有効化クラスを設定します。 //! //! RenderContext に所有権を移動しますので注意してください。 Builder& ParticleMaterialActivator(IMaterialActivator* particleMaterialActivator) { m_ParticleMaterialActivator = particleMaterialActivator; return *this; } //! @brief レンダーコンテキストを生成します。 //! //! @param[in] allocator 使用するアロケータを指定します。 //! //! @return 生成されたレンダーコンテキストです。 //! RenderContext* Create(os::IAllocator* allocator); private: int m_MaxCameras; int m_MaxLightSets; int m_MaxFogs; int m_MaxVertexLights; IMaterialActivator* m_ParticleMaterialActivator; }; //@} //---------------------------------------- //! @name 基本的な描画 //@{ //! @brief 描画対象を設定します。 //! //! @param[in] renderTarget 描画対象です。 //! @param[in] viewport ビューポートです。 //! void SetRenderTarget(IRenderTarget* renderTarget, const Viewport& viewport); //! @brief 描画対象を設定します。 //! //! @param[in] renderTarget 描画対象です。 //! void SetRenderTarget(IRenderTarget* renderTarget); //! @brief 描画環境を初期化します。各フレームの描画後に呼び出すことを推奨します。 //! void ResetState(); //! @brief 描画環境を初期化します。各フレームの描画後に呼び出すことを推奨します。 //! //! @param[in] resetStateMode ResetStateMode でリセットを行うステートを指定します。 //! @param[in] hashMask リセットを行うハッシュを表すマスクです。 //! void ResetState(s32 resetStateMode, s32 hashMask); //! @brief 描画環境を初期化します。各フレームの描画開始時に呼び出すことを推奨します。 //! 廃止予定ですので、void ResetState(s32 resetStateMode, s32 hashMask) を使用してください。 //! //! @param[in] hashMask リセットを行うハッシュを表すマスクです。 //! NW_DEPRECATED_FUNCTION(void ResetState(s32 hashMask)); //! @brief バッファをクリアします。 //! //! @param[in] mask //! @param[in] color //! @param[in] depth //! void ClearBuffer(GLbitfield mask, const nw::ut::FloatColor& color, f32 depth); //! @brief レンダーターゲットを取得します。 IRenderTarget* GetRenderTarget() { return this->m_RenderTarget; } //! @brief レンダーターゲットを取得します。 const IRenderTarget* GetRenderTarget() const { return this->m_RenderTarget; } //! @brief コンテキストを有効化します。 //! //! @details レンダーコンテキストに設定されている //! ライト・カメラ・フォグ・マテリアルを有効化します。 //! void ActivateContext(); //! @brief パーティクル版のコンテキストを有効化します。 //! パーティクルを有効にする場合は必ずこちらを呼び出してください。 //! //! @details レンダーコンテキストに設定されている //! ライト・カメラ・フォグ・マテリアルを有効化します。 //! void ActivateParticleContext(); //! @brief プリミティブを描画します。 //! //! @param[in] primitive プリミティブです。 //! void RenderPrimitive(ResPrimitive primitive); //@} //---------------------------------------- //! @name 描画内容設定・取得 //@{ //! @brief インデックスを指定してカメラを有効にします。 //! //! ライトや環境マップの計算に用いられます。 //! ResetState でリセットされますので、毎フレーム設定を行う必要があります。 //! //! @param[in] index 設定するカメラのインデックス番号です。 //! void SetActiveCamera(int index) { NW_MINMAXLT_ASSERT(index, 0, m_SceneEnvironment.m_Cameras.size()); Camera* camera = m_SceneEnvironment.m_Cameras[index]; m_SceneEnvironment.m_CameraIndex = index; if (m_SceneEnvironment.m_Camera != camera) { m_SceneEnvironment.m_Camera = camera; m_SceneEnvironment.m_CameraDirty = true; // wScale を設定します。 GraphicsDevice::SetWScale(camera->GetWScale()); } } //! @brief 現在有効なカメラを取得します。 Camera* GetActiveCamera() { return m_SceneEnvironment.m_Camera; } //! @brief 現在有効なカメラを取得します。 const Camera* GetActiveCamera() const { return m_SceneEnvironment.m_Camera; } //! @brief 現在有効なカメラインデクスを取得します。 s32 GetActiveCameraIndex() const { return m_SceneEnvironment.m_CameraIndex; } //! @brief カメラのマトリクスを設定します。 //! //! 内部でカメラをキャッシュして、同じカメラを設定した場合は、 //! マトリクスの設定を行わない最適化を行います。 //! //! @param camera 設定するカメラクラスです。 //! @param isForce キャッシュを無視して強制的に設定します。 //! void SetCameraMatrix(Camera* camera, bool isForce = false); //! @brief モデルのマトリクスを設定します。 //! //! 内部でモデルをキャッシュして、同じモデルを設定した場合は、 //! マトリクスの設定を行わない最適化を行います。 //! //! @param[in] model 設定するモデルクラスです。 //! void SetModelMatrix(Model* model); //! @brief モデルのキャッシュを取得します。 //! //! @return モデルキャッシュのポインタを返します。 //! Model* GetModelCache() { return this->m_ModelCache; } //! @brief モデルのキャッシュを取得します。 //! //! @return モデルキャッシュのポインタを返します。 //! const Model* GetModelCache() const { return this->m_ModelCache; } //! @brief マテリアルを取得します。 //! //! @return マテリアルのポインタを返します。 Material* GetMaterial() { return this->m_Material; } //! @brief マテリアルを取得します。 //! //! @return マテリアルのポインタを返します。 const Material* GetMaterial() const { return this->m_Material; } //! @brief マテリアルを設定します。 //! //! @param[in] material 設定するマテリアルです。 //! void SetMaterial(Material* material) { NW_NULL_ASSERT(material); m_Material = material; } //! @brief マテリアルのキャッシュを取得します。 //! //! 最後に ActivateMaterial を行ったマテリアルです。 //! //! @return マテリアルキャッシュのポインタを返します。 Material* GetMaterialCache() { return this->m_MaterialCache; } //! @brief マテリアルのキャッシュを取得します。 //! //! 最後に ActivateMaterial を行ったマテリアルです。 //! //! @return マテリアルキャッシュのポインタを返します。 const Material* GetMaterialCache() const { return this->m_MaterialCache; } //! @brief シェーダープログラムを取得します。 //! //! @return シェーダープログラムを返します。 ShaderProgram* GetShaderProgram() { return this->m_ShaderProgram.Get(); } //! @brief シェーダープログラムを取得します。 //! //! @return シェーダープログラムを返します。 const ShaderProgram* GetShaderProgram() const { return this->m_ShaderProgram.Get(); } //! @brief レンダーコンテキストに設定された環境を取得します。 SceneEnvironment& GetSceneEnvironment() { return this->m_SceneEnvironment; } //! @brief レンダーコンテキストに設定された環境を取得します。 const SceneEnvironment& GetSceneEnvironment() const { return this->m_SceneEnvironment; } //! @brief マトリクスパレットの数を設定します。 void SetMatrixPaletteCount(int count) { m_MatrixPaletteCount = count; } //! @brief マテリアルハッシュを取得します。 void SetMaterialHash(const MaterialHash& materialHash) { this->m_MaterialHash = materialHash; } //! @brief マテリアルハッシュを取得します。 MaterialHash GetMaterialHash() { return this->m_MaterialHash; } //! @brief マテリアルハッシュを取得します。 const MaterialHash* GetMaterialHash() const { return &this->m_MaterialHash; } //! @brief 描画モードを取得します。 u32 GetRenderMode() const { return this->m_RenderMode; } //! @brief 描画モードを設定します。 void SetRenderMode(u32 renderMode) { this->m_RenderMode = renderMode; } //! @brief シェーダープログラムが変更されているかどうかのフラグを取得します。 bool IsShaderProgramDirty() const { return this->m_IsShaderProgramDirty; } #ifdef NW_GFX_MODEL_TRANSLATE_OFFSET_ENABLED //! @brief モデルの平行移動値に加えるオフセット値を取得または設定します。 math::VEC3& ModelTranslateOffset() { return m_ModelTranslateOffset; } //! @brief モデルの平行移動値に加えるオフセット値を取得します。 const math::VEC3& ModelTranslateOffset() const { return m_ModelTranslateOffset; } #endif //--------------------------------------------------------------------------- //! @brief 頂点属性の設定を GPU に設定します。 //! //! @param[in] mesh 描画対象のメッシュデータです。 //--------------------------------------------------------------------------- void ActivateVertexAttribute( ResMesh mesh ); //--------------------------------------------------------------------------- //! @brief GPU の頂点属性を無効に設定します。 //! //! @param[in] mesh 描画対象のメッシュデータです。 //--------------------------------------------------------------------------- void DeactivateVertexAttribute( ResMesh mesh ); //@} private: static const ut::FloatColor NULL_AMBIENT; //! @brief コンストラクタです。 RenderContext( nw::os::IAllocator* pAllocator, GfxPtr shaderProgram, GfxPtr particleMaterialActivator, const SceneEnvironment::Description& description); //! @brief InverseScale と MatrixCount の値を更新します。 void ActivateInverseScaleAndMatrixCount(); //! @brief シェーダープログラムを有効化します。 void ActivateShaderProgram(); //! @brief 環境設定を有効化します。 void ActivateSceneEnvironment(); //! @brief マテリアルを有効化します。 void ActivateMaterial() { if (!ut::CheckFlag(m_RenderMode, RenderContext::RENDERMODE_IGNORE_MATERIAL)) { IMaterialActivator* materialActivator = this->m_Material->GetOwnerModel()->GetMaterialActivator(); NW_NULL_ASSERT(materialActivator); materialActivator->Activate(this, this->m_Material); } } //! @brief パーティクル版の簡易マテリアルを有効化します。 void ActivateParticleMaterial() { if (!ut::CheckFlag(m_RenderMode, RenderContext::RENDERMODE_IGNORE_MATERIAL)) { m_ParticleMaterialActivator.Get()->Activate(this, this->m_Material); } } //! @brief フォグを有効にします。 void ActivateFog(); //! @brief アンビエントライトを有効化します。 void ActivateAmbientLight(); //! @brief 半球ライトを有効化します。 void ActivateHemiSphereLight(); //! @brief フラグメントライトを有効化します。 void ActivateFragmentLights(); //! @brief フラグメントライトを有効化します。 void ActivateFragmentLight(int index, const FragmentLight* light); //! @brief 頂点ライトを有効化します。 void ActivateVertexLights(); //! @brief 頂点ライトを有効化します。 void ActivateVertexLight(int index, const VertexLight* light); //! @brief ベクトルをビュー座標系に変換します。 void TransformToViewCoordinate( math::VEC4* out, const math::MTX34* view, const math::VEC4* v); //! @brief インデックス番号を LUT のテクスチャインデックスの定義に変換します。 u32 ToLutTexture(s32 index) { NW_ASSERT(0 <= index && index < LOOKUP_TABLE_COUNT); return index + GL_LUT_TEXTURE0_DMP; } NW_INLINE GLuint ToPrimitiveModeGL(u8 mode, bool isGeometryShaderEnabled); GfxPtr m_ShaderProgram; s32 m_MatrixPaletteCount; bool m_IsVertexAlphaEnabled; bool m_IsBoneWeightWEnabled; bool m_IsVertexAttributeDirty; bool m_IsShaderProgramDirty; u32 m_RenderMode; IRenderTarget* m_RenderTarget; Model* m_ModelCache; Material* m_Material; Material* m_MaterialCache; Camera* m_CameraCache; SceneEnvironment m_SceneEnvironment; MaterialHash m_MaterialHash; GfxPtr m_ParticleMaterialActivator; #ifdef NW_GFX_MODEL_TRANSLATE_OFFSET_ENABLED math::VEC3 m_ModelTranslateOffset; #endif }; //---------------------------------------- NW_INLINE void RenderContext::MaterialHash::ResetMaterialHash(s32 hashMask) { NW_UNUSED_VARIABLE(hashMask); const u32 resetValue = ~(0x0); if (ut::CheckFlag(hashMask, Model::FLAG_BUFFER_SHADER_PARAMETER)) { shaderParameter = resetValue; } if (ut::CheckFlag(hashMask, Model::FLAG_BUFFER_SHADING_PARAMETER)) { shadingParameter = resetValue; } if (ut::CheckFlag(hashMask, Model::FLAG_BUFFER_MATERIAL_COLOR)) { materialColor = resetValue; } if (ut::CheckFlag(hashMask, Model::FLAG_BUFFER_RASTERIZATION)) { rasterization = resetValue; } if (ut::CheckFlag(hashMask, Model::FLAG_BUFFER_TEXTURE_COORDINATOR)) { textureCoordinator = resetValue; } if (ut::CheckFlag(hashMask, Model::FLAG_BUFFER_TEXTURE_MAPPER)) { textureMapper = resetValue; } if (ut::CheckFlag(hashMask, Model::FLAG_BUFFER_FRAGMENT_LIGHTING)) { fragmentLighting = resetValue; } if (ut::CheckFlag(hashMask, Model::FLAG_BUFFER_FRAGMENT_LIGHTING_TABLE)) { fragmentLightingTable = resetValue; } if (ut::CheckFlag(hashMask, Model::FLAG_BUFFER_TEXTURE_COMBINER)) { textureCombiner = resetValue; } if (ut::CheckFlag(hashMask, Model::FLAG_BUFFER_FRAGMENT_OPERATION)) { fragmentOperation = resetValue; } if (ut::CheckFlag(hashMask, Model::FLAG_BUFFER_ALPHA_TEST)) { alphaTest = resetValue; } } //--------------------------------------------------------------------------- //! @brief GL のモードを取得します。 //! //! @param[in] mode 描画モードです。 //! @param[in] isGeometryShaderEnabled ジオメトリシェーダーが有効かどうかを指定します。 //! //! @return GL のモードです。 //--------------------------------------------------------------------------- NW_INLINE GLuint RenderContext::ToPrimitiveModeGL(u8 mode, bool isGeometryShaderEnabled) { static const GLuint PRIM_MODE_TABLE[] = { GL_TRIANGLES, // Triangles GL_TRIANGLE_STRIP, // TriangleStrip GL_TRIANGLE_FAN // TriangleFan }; NW_ASSERT( mode < (sizeof(PRIM_MODE_TABLE) / sizeof(GLuint)) ); GLuint glMode = PRIM_MODE_TABLE[ mode ]; if (isGeometryShaderEnabled) { glMode = GL_GEOMETRY_PRIMITIVE_DMP; } return glMode; } //--------------------------------------------------------------------------- NW_INLINE void RenderContext::DeactivateVertexAttribute( ResMesh mesh ) { NW_NULL_ASSERT( mesh.ref().m_DeactivateCommandCache ); internal::NWUseCmdlist( mesh.ref().m_DeactivateCommandCache, mesh.ref().m_DeactivateCommandCacheSize ); } } // namespace gfx } // namespace nw #endif // NW_GFX_RENDERCONTEXT_H_