/*---------------------------------------------------------------------------* Project: NintendoWare File: SmPrimitive.cpp 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: $ *---------------------------------------------------------------------------*/ #include #include #include //#include #include #include #include #include "../include/SmDef.h" #include "../include/SmPrimitive.h" // Singleton SmOgl* s_SmOgl = NULL; namespace { //---------------------------------------- // SmOgl の初期化 SmOgl* SmOgl::InitializeSmOgl( const wchar_t* shaderName ) { if ( s_SmOgl ) { NW_FATAL_ERROR("SmOgl instance is exsit.\n"); } s_SmOgl = new SmOgl( shaderName ); NW_NULL_ASSERT( s_SmOgl ); return s_SmOgl; } //---------------------------------------- // SmOgl の終了 void SmOgl::TerminateSmOgl() { if ( !s_SmOgl ) { NW_FATAL_ERROR("SmOgl instance is not exsit.\n"); } delete s_SmOgl; s_SmOgl = NULL; } //---------------------------------------- // コンストラクタ SmOgl::SmOgl( const wchar_t* shaderName ) : m_ProgramID( 0 ), m_ShaderID( 0 ) { NW_NULL_ASSERT( shaderName ); m_ProjectionMatrix.Identity(); m_ViewMatrix.Identity(); if ( s_SmOgl ) { NW_FATAL_ERROR("SmOgl instance is exsit.\n"); } // シェーダファイルをロード if ( !m_ShaderFile.Read( shaderName, m_Allocator ) ) { NW_FATAL_ERROR("can not read shader file."); } if ( m_ProgramID == 0 ) { m_ProgramID = glCreateProgram(); } if ( m_ShaderID == 0 ) { m_ShaderID = glCreateShader( GL_VERTEX_SHADER ); } glShaderBinary( 1, &m_ShaderID, GL_PLATFORM_BINARY_DMP, m_ShaderFile.Buffer(), m_ShaderFile.Size() ); NW_GL_ASSERT(); glAttachShader( m_ProgramID, m_ShaderID ); glAttachShader( m_ProgramID, GL_DMP_FRAGMENT_SHADER_DMP ); glBindAttribLocation(m_ProgramID, SMP_ATTR_POSITION, "aPosition"); glBindAttribLocation(m_ProgramID, SMP_ATTR_COLOR, "aColor"); glBindAttribLocation(m_ProgramID, SMP_ATTR_OFFSET, "aOffset"); glLinkProgram(m_ProgramID); glUseProgram(m_ProgramID); glEnableVertexAttribArray( SMP_ATTR_POSITION ); glDisableVertexAttribArray( SMP_ATTR_COLOR ); glDisableVertexAttribArray( SMP_ATTR_TEXCOORD0 ); NW_GL_ASSERT(); // todo:understand SetupMaterial(); SetupTexEnv(); // インスタンスを登録 s_SmOgl = this; // 正射影マトリクスの生成 { nw::math::MTX44OrthoPivot( &m_ProjectionMatrix, 0.f, SM_LOWER_SCREEN_SIZE_W, SM_LOWER_SCREEN_SIZE_H, 0.f, -100.f, 100.f, nw::math::PIVOT_UPSIDE_TO_TOP); } // ビューマトリクス { const nw::math::VEC3 camPos(0.0f, 0.0f, 1.0f); const nw::math::VEC3 aimPos(0.0f, 0.0f, 0.0f); const nw::math::VEC3 camUp(0.0f, 1.0f, 0.0f); nw::math::MTX34LookAt( reinterpret_cast(&m_ViewMatrix), &camPos, &camUp, &aimPos ); } } //---------------------------------------- // デストラクタ SmOgl::~SmOgl() { s_SmOgl = NULL; // メモリを解放 m_ShaderFile.Release(); SmStaticCommandCache::DestroyCopiedCmdCache( m_CopiedCmdCache ); // todo:glDeleteProgoram 等 } //-------------------------------------------------------------------------- void SmOgl::SetupMaterial() { glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); glDisable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } //-------------------------------------------------------------------------- void SmOgl::SetupTexEnv() { glUniform3i(glGetUniformLocation(m_ProgramID, "dmp_TexEnv[0].srcRgb"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR); glUniform3i(glGetUniformLocation(m_ProgramID, "dmp_TexEnv[0].srcAlpha"), GL_PRIMARY_COLOR, GL_PRIMARY_COLOR, GL_PRIMARY_COLOR); } //---------------------------------------- // 2D エントリ開始 void SmOgl::SetBegin2D() { if ( !m_CopiedCmdCache.IsCopied() ) { // まずはキャッシュを生成 SmStaticCommandCache::StartStaticCmdCache( m_SetBeginCmd ); { // シェーダプログラム変更 glUseProgram(m_ProgramID); // ビューやプロジェクションの変更 { GLint location; location = glGetUniformLocation( m_ProgramID, "uProjection" ); glUniform4fv( location, 4, m_ProjectionMatrix ); location = glGetUniformLocation( m_ProgramID, "uModelView" ); glUniform4fv( location, 4, m_ViewMatrix ); NW_GL_ASSERT(); } glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); glDisable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } SmStaticCommandCache::EndStaticCmdCache( m_SetBeginCmd ); // キャッシュのコピーを生成 SmStaticCommandCache::CreateCopiedCmdCache( m_CopiedCmdCache ); } // todo:キャッシュに入れると、処理バーが描画されない { // バッファの整理 glBindBuffer(GL_ARRAY_BUFFER, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0); // 有効/無効 glEnableVertexAttribArray( SmOgl::SMP_ATTR_POSITION ); glEnableVertexAttribArray( SmOgl::SMP_ATTR_COLOR ); glDisableVertexAttribArray( SmOgl::SMP_ATTR_TEXCOORD0 ); } // コマンドキャッシュを利用してセット if ( m_CopiedCmdCache.IsCopied() ) { SmStaticCommandCache::UseCopiedCmdCache( m_CopiedCmdCache ); } } //---------------------------------------- // コンストラクタ Sm2DPrimPC::Sm2DPrimPC( uint vertexCnt ) : m_pVertex( NULL ), m_VertexCnt( vertexCnt ), m_VertexUpdate( false ) { // ASSERT:m_VertexCnt != 0 NW_NULL_ASSERT( m_Allocator ); m_CopiedCmdCache.Init(); m_pVertex = static_cast(m_Allocator->Alloc( sizeof( SmVertexPC ) * m_VertexCnt )); NW_NULL_ASSERT( m_pVertex ); } //---------------------------------------- // デストラクタ Sm2DPrimPC::~Sm2DPrimPC() { SmStaticCommandCache::DestroyCopiedCmdCache( m_CopiedCmdCache ); nw::os::SafeFree( m_pVertex, m_Allocator ); } //---------------------------------------- // 現在積まれている頂点で更新する void Sm2DPrimPC::Update() { } //---------------------------------------- // 描画 void Sm2DPrimPC::Render( GLenum entryMode, f32 posX, f32 posY ) { // オフセット位置 { nw::math::VEC4 offset; offset.x = posX; offset.y = posY; offset.z = 0.f; offset.w = 0.f; glVertexAttrib4fv( SmOgl::SMP_ATTR_OFFSET, offset ); } // コマンドキャッシュコピーを生成する if ( m_VertexUpdate ) { // まずはキャッシュを生成 SmStaticCommandCache::StartStaticCmdCache( m_CmdCache ); { RenderSub( entryMode ); } SmStaticCommandCache::EndStaticCmdCache( m_CmdCache ); // 生成済みがあれば破棄 if ( m_CopiedCmdCache.IsCopied() ) { SmStaticCommandCache::DestroyCopiedCmdCache( m_CopiedCmdCache ); } // キャッシュのコピーを生成 SmStaticCommandCache::CreateCopiedCmdCache( m_CopiedCmdCache ); m_VertexUpdate = false; } // コマンドキャッシュを利用して描画 if ( m_CopiedCmdCache.IsCopied() ) { SmStaticCommandCache::UseCopiedCmdCache( m_CopiedCmdCache ); } else { RenderSub( entryMode ); } NW_GL_ASSERT(); } //---------------------------------------- // 描画 下請け void Sm2DPrimPC::RenderSub( GLenum entryMode ) { // 基準のアドレス const u8* basePtr = reinterpret_cast(m_pVertex); // position glVertexAttribPointer( SmOgl::SMP_ATTR_POSITION, 2, GL_FLOAT, GL_FALSE, sizeof(SmVertexPC), basePtr ); // color glVertexAttribPointer( SmOgl::SMP_ATTR_COLOR, 4, GL_UNSIGNED_BYTE, GL_FALSE, sizeof(SmVertexPC), basePtr + offsetof(SmVertexPC, color) ); // draw glDrawArrays( entryMode, 0, m_VertexCnt ); NW_GL_ASSERT(); } //---------------------------------------- // 頂点を登録する void Sm2DPrimPC::SetVertex( uint vertexIdx, f32 x, f32 y, nw::ut::Color8 color ) { NW_ASSERT( m_VertexCnt > vertexIdx ); m_pVertex[vertexIdx].position.x = x; m_pVertex[vertexIdx].position.y = y; m_pVertex[vertexIdx].color = color; } //---------------------------------------- // 頂点カラーを登録する void Sm2DPrimPC::SetVertexColor( nw::ut::Color8 color ) { uint i = 0; for ( i = 0; i < m_VertexCnt; i ++ ) { m_pVertex[i].color = color; } } //---------------------------------------- // コンストラクタ Sm2DDynamicPrimPC::Sm2DDynamicPrimPC() : m_pPrimitive( NULL ), m_VertexCnt( 0 ), m_EntryCnt( 0 ), m_EntryMode( 0 ), m_OffsetX( 0.f ), m_OffsetY( 0.f ){} //---------------------------------------- // エントリ開始 bool Sm2DDynamicPrimPC::Begin( uint vertexCnt, GLenum entryMode, f32 posX, f32 posY ) { if ( m_pPrimitive ) return false; if ( vertexCnt == 0 ) return false; m_pPrimitive = new Sm2DPrimPC( vertexCnt ); NW_NULL_ASSERT( m_pPrimitive ); m_EntryCnt = 0; m_VertexCnt = vertexCnt; m_EntryMode = entryMode; m_OffsetX = posX; m_OffsetY = posY; return true; } //---------------------------------------- // 頂点を登録する void Sm2DDynamicPrimPC::SetVertex( f32 x, f32 y, nw::ut::Color8 color ) { m_pPrimitive->SetVertex( m_EntryCnt, x, y, color ); m_EntryCnt++; } //---------------------------------------- // エントリ終了 void Sm2DDynamicPrimPC::End() { if ( m_VertexCnt != m_EntryCnt ) return; m_pPrimitive->Render( m_EntryMode, m_OffsetX, m_OffsetY ); delete m_pPrimitive; m_pPrimitive = NULL; } } // namespace