/*---------------------------------------------------------------------------* Project: NintendoWare File: demo_GraphicsDrawing.cpp 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: 24774 $ *---------------------------------------------------------------------------*/ #include #include #include #include #include #include namespace nw { namespace demo { enum { VTXATTR_POSITION = 0, VTXATTR_COLOR, VTXATTR_TEXCOORD0 }; //-------------------------------------------------------------------------- /* ctor */ GraphicsDrawing::GraphicsDrawing() : m_ScreenSize( f32(DEFAULT_SCREEN_WIDTH), f32(DEFAULT_SCREEN_HEIGHT) ), m_LineWidth( 2.0f ), m_ProgramID( 0 ), m_ShaderID( 0 ), m_pShaderBinary( NULL ), m_MaxTextCount( DEFAULT_MAX_TEXT_COUNT ), m_FontCommandBuffer( NULL ), m_FontAllocator( NULL ), m_ShapeAllocator( NULL ) { } //-------------------------------------------------------------------------- GraphicsDrawing::~GraphicsDrawing() { } //-------------------------------------------------------------------------- void GraphicsDrawing::Finalize() { this->DestroyFont(); if ( m_pShaderBinary && m_ShapeAllocator ) { os::SafeFree(m_pShaderBinary, m_ShapeAllocator); } m_FontAllocator = NULL; m_ShapeAllocator = NULL; } //-------------------------------------------------------------------------- bool GraphicsDrawing::InitializeShader(void* pShaderBinary, size_t binarySize) { bool result = true; const void* prev = m_pShaderBinary; m_pShaderBinary = pShaderBinary; NW_GL_ASSERT(); 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, pShaderBinary, binarySize); NW_GL_ASSERT(); glAttachShader(m_ProgramID, m_ShaderID); glAttachShader(m_ProgramID, GL_DMP_FRAGMENT_SHADER_DMP); glBindAttribLocation(m_ProgramID, VTXATTR_POSITION, "aPosition"); glBindAttribLocation(m_ProgramID, VTXATTR_COLOR, "aColor"); glLinkProgram(m_ProgramID); glUseProgram(m_ProgramID); glEnableVertexAttribArray( VTXATTR_POSITION ); glDisableVertexAttribArray( VTXATTR_COLOR ); glDisableVertexAttribArray( VTXATTR_TEXCOORD0 ); NW_GL_ASSERT(); return true; } //-------------------------------------------------------------------------- bool GraphicsDrawing::InitializeShader( os::IAllocator* allocator, const wchar_t* shaderPath ) { m_ShapeAllocator = allocator; ut::MoveArray buffer = nw::demo::Utility::LoadFile( allocator, shaderPath ); if ( buffer.empty() ) { return false; } s32 size = buffer.size(); void* pBuffer = buffer.release(); return InitializeShader( pBuffer, size ); } //-------------------------------------------------------------------------- void GraphicsDrawing::Setup() { glUseProgram(m_ProgramID); this->SetupMaterial(); this->SetupTexEnv(); } //-------------------------------------------------------------------------- void GraphicsDrawing::SetupMaterial() { glDisable(GL_CULL_FACE); glDisable(GL_DEPTH_TEST); glDisable(GL_STENCIL_TEST); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); } //-------------------------------------------------------------------------- void GraphicsDrawing::SetupTexEnv() { #define TEXENV_LAST_STAGE "dmp_TexEnv[2]" // プライマリカラーの設定をそのまま出力します。 glUniform3i( glGetUniformLocation( m_ProgramID, TEXENV_LAST_STAGE ".srcRgb"), GL_PRIMARY_COLOR, GL_PREVIOUS, GL_PREVIOUS ); glUniform3i( glGetUniformLocation( m_ProgramID, TEXENV_LAST_STAGE ".srcAlpha"), GL_PRIMARY_COLOR, GL_PREVIOUS, GL_PREVIOUS ); glUniform1i( glGetUniformLocation( m_ProgramID, TEXENV_LAST_STAGE ".combineRgb"), GL_REPLACE ); glUniform1i( glGetUniformLocation( m_ProgramID, TEXENV_LAST_STAGE ".combineAlpha"), GL_REPLACE ); glUniform3i( glGetUniformLocation( m_ProgramID, TEXENV_LAST_STAGE ".operandRgb"), GL_SRC_COLOR, GL_SRC_COLOR, GL_SRC_COLOR ); glUniform3i( glGetUniformLocation( m_ProgramID, TEXENV_LAST_STAGE ".operandAlpha"), GL_SRC_ALPHA, GL_SRC_ALPHA, GL_SRC_ALPHA ); glUniform1f( glGetUniformLocation( m_ProgramID, TEXENV_LAST_STAGE ".scaleRgb"), 1.0f ); glUniform1f( glGetUniformLocation( m_ProgramID, TEXENV_LAST_STAGE ".scaleAlpha"), 1.0f ); #undef TEXENV_LAST_STAGE } //-------------------------------------------------------------------------- void GraphicsDrawing::BeginDrawingShape() { glUseProgram(m_ProgramID); this->SendMatrix(); } //-------------------------------------------------------------------------- void GraphicsDrawing::SendMatrix() { nw::math::MTX44 projMtx; nw::math::MTX44 viewMtx; 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); const f32 width = m_ScreenSize.y; const f32 height = m_ScreenSize.x; const f32 left = 0.f; const f32 right = m_ScreenSize.x; const f32 bottom = m_ScreenSize.y; const f32 top = 0.f; math::MTX44OrthoPivot(&projMtx, left, right, bottom, top, -100.f, 100.f, math::PIVOT_UPSIDE_TO_TOP); math::MTX44Identity(&viewMtx); math::MTX34LookAt(reinterpret_cast(&viewMtx), &camPos, &camUp, &aimPos); GLint location; location = glGetUniformLocation( m_ProgramID, "uProjection" ); glUniform4fv(location, 4, projMtx); location = glGetUniformLocation( m_ProgramID, "uModelView" ); glUniform4fv(location, 4, viewMtx); NW_GL_ASSERT(); glViewport(0, 0, static_cast(width), static_cast(height)); } //-------------------------------------------------------------------------- void GraphicsDrawing::DrawLine( const math::VEC2& p1, const math::VEC2& p2, ut::Color8 color ) { ut::FloatColor floatColor = color; glVertexAttrib4fv( VTXATTR_COLOR, floatColor ); s32 count = this->BuildLine(p1, p2, m_LineWidth, &m_PositionStream[0]); glVertexAttribPointer( VTXATTR_POSITION, 2, GL_FLOAT, GL_FALSE, 0, static_cast(m_PositionStream[0]) ); glDrawArrays ( GL_TRIANGLES, 0, count); } //-------------------------------------------------------------------------- void GraphicsDrawing::DrawRectangle( const math::VEC2& pos, const math::VEC2& size, ut::Color8 color ) { ut::FloatColor floatColor = color; glVertexAttrib4fv( VTXATTR_COLOR, floatColor ); s32 count = 0; count += this->BuildLine(pos, math::VEC2(pos.x + size.x, pos.y), m_LineWidth, &m_PositionStream[count]); count += this->BuildLine(math::VEC2(pos.x + size.x, pos.y), pos + size, m_LineWidth, &m_PositionStream[count]); count += this->BuildLine(pos + size, math::VEC2(pos.x, pos.y + size.y), m_LineWidth, &m_PositionStream[count]); count += this->BuildLine(math::VEC2(pos.x, pos.y + size.y), pos, m_LineWidth, &m_PositionStream[count]); NW_ASSERT( count <= VERTEX_STREAM_SIZE ); glVertexAttribPointer( VTXATTR_POSITION, 2, GL_FLOAT, GL_FALSE, 0, static_cast(m_PositionStream[0]) ); glDrawArrays ( GL_TRIANGLES, 0, count); } //-------------------------------------------------------------------------- void GraphicsDrawing::FillRectangle( const math::VEC2& pos, const math::VEC2& size, ut::Color8 color ) { ut::FloatColor floatColor = color; glVertexAttrib4fv( VTXATTR_COLOR, floatColor ); s32 count = this->BuildRectangle(pos, size, &m_PositionStream[0]); glEnableVertexAttribArray( VTXATTR_POSITION ); glVertexAttribPointer( VTXATTR_POSITION, 2, GL_FLOAT, GL_FALSE, 0, static_cast(m_PositionStream[0]) ); glDrawArrays ( GL_TRIANGLES, 0, count); } //-------------------------------------------------------------------------- void GraphicsDrawing::FillTriangle( const math::VEC2& pt1, const math::VEC2& pt2, const math::VEC2& pt3, ut::Color8 color ) { ut::FloatColor floatColor = color; glVertexAttrib4fv( VTXATTR_COLOR, floatColor ); s32 count = this->BuildTriangle(pt1, pt2, pt3, &m_PositionStream[0]); glVertexAttribPointer( VTXATTR_POSITION, 2, GL_FLOAT, GL_FALSE, 0, static_cast(m_PositionStream[0]) ); glDrawArrays ( GL_TRIANGLES, 0, count); } //-------------------------------------------------------------------------- void GraphicsDrawing::FillTriangles( const math::VEC2* pPointArray, s32 pointCount, ut::Color8 color ) { NW_NULL_ASSERT( pPointArray ); NW_ASSERT( pointCount > 0 ); ut::FloatColor floatColor = color; glVertexAttrib4fv( VTXATTR_COLOR, floatColor ); glVertexAttribPointer( VTXATTR_POSITION, 2, GL_FLOAT, GL_FALSE, 0, static_cast(pPointArray[0]) ); glDrawArrays ( GL_TRIANGLES, 0, pointCount); } //-------------------------------------------------------------------------- s32 GraphicsDrawing::BuildTriangle( const math::VEC2& pt1, const math::VEC2& pt2, const math::VEC2& pt3, math::VEC2 *pVecArray ) { NW_NULL_ASSERT( pVecArray ); pVecArray[ 0 ] = pt1; pVecArray[ 1 ] = pt2; pVecArray[ 2 ] = pt3; return 3; } //-------------------------------------------------------------------------- s32 GraphicsDrawing::BuildRectangle( const math::VEC2& pt1, const math::VEC2& pt2, const math::VEC2& pt3, const math::VEC2& pt4, math::VEC2 *pVecArray ) { NW_NULL_ASSERT( pVecArray ); s32 count = 0; count += this->BuildTriangle( pt1, pt2, pt3, &pVecArray[count] ); count += this->BuildTriangle( pt1, pt3, pt4, &pVecArray[count] ); return count; } //-------------------------------------------------------------------------- s32 GraphicsDrawing::BuildRectangle( const math::VEC2& pos, const math::VEC2& size, math::VEC2 *pVecArray ) { NW_NULL_ASSERT( pVecArray ); s32 count = 0; count += this->BuildRectangle( pos, math::VEC2(pos.x + size.x, pos.y), pos + size, math::VEC2(pos.x, pos.y + size.y), pVecArray ); return count; } //-------------------------------------------------------------------------- s32 GraphicsDrawing::BuildLine( const math::VEC2& pt1, const math::VEC2& pt2, f32 lineWidth, math::VEC2 *pVecArray ) { NW_ASSERT( lineWidth >= 0.f ); NW_NULL_ASSERT( pVecArray ); math::VEC2 direction = pt1 + pt2; math::VEC2 ortho = math::VEC2(direction.y, -direction.x); VEC2Normalize( &ortho, &ortho ); ortho *= lineWidth; s32 count = 0; count += this->BuildRectangle( pt1 - ortho / 2, pt1 + ortho / 2, pt2 + ortho / 2, pt2 - ortho / 2, pVecArray ); return count; } //-------------------------------------------------------------------------- bool GraphicsDrawing::InitializeFont( os::IAllocator* allocator, const wchar_t* fontShaderPath, const wchar_t* fontPath ) { m_FontAllocator = allocator; // フォントリソースをロードします。 ut::MoveArray fontData = nw::demo::Utility::LoadFile( allocator, fontPath, nw::font::GlyphDataAlignment ); ut::MoveArray fontShaderData = nw::demo::Utility::LoadFile( allocator, fontShaderPath ); s32 fontSize = fontData.size(); void* fontBuffer = fontData.release(); s32 shaderSize = fontShaderData.size(); void* shaderBuffer = fontShaderData.release(); const u32 vtxBufCmdBufSize = nw::font::RectDrawer::GetVertexBufferCommandBufferSize(shaderBuffer, shaderSize); m_FontCommandBuffer = allocator->Alloc(vtxBufCmdBufSize); NN_NULL_ASSERT(m_FontCommandBuffer); const u32 drawBufferSize = nw::font::ResFont::GetDrawBufferSize(fontBuffer); void* drawBuffer = allocator->Alloc(drawBufferSize, 4); NW_NULL_ASSERT(drawBuffer); const u32 stringBufferSize = nw::font::CharWriter::GetDispStringBufferSize(m_MaxTextCount); void *const stringBuffer = allocator->Alloc(stringBufferSize); NN_NULL_ASSERT(stringBuffer); bool result = false; if ( fontBuffer != NULL && shaderBuffer != NULL ) { result = this->InitializeFont( shaderBuffer, shaderSize, fontBuffer, fontSize, drawBuffer, stringBuffer ); } os::SafeFree(shaderBuffer, allocator); if ( ! result ) { os::SafeFree(fontBuffer, allocator); } return result; } //-------------------------------------------------------------------------- bool GraphicsDrawing::InitializeFont( void* shaderBinary, size_t shaderSize, void* fontBinary, size_t fontSize, void* drawBuffer, void* stringBuffer ) { if ( ! this->InitializeFontResource( fontBinary, fontSize ) ) { return false; } if ( ! this->InitializeFontShader( shaderBinary, shaderSize ) ) { return false; } // 描画用バッファを設定します。 m_Font.SetDrawBuffer(drawBuffer); m_TextWriter.SetFont( &m_Font ); m_TextWriter.EnableFixedWidth( true ); m_TextWriter.SetFixedWidth( 8.5f ); nw::font::DispStringBuffer *const pDrawStringBuf = nw::font::CharWriter::InitDispStringBuffer(stringBuffer, m_MaxTextCount); m_TextWriter.SetDispStringBuffer(pDrawStringBuf); return true; } //-------------------------------------------------------------------------- bool GraphicsDrawing::InitializeFontResource( void* fontData, size_t fontSize ) { NW_UNUSED_VARIABLE( fontSize ); // フォントリソースをセットします。 return m_Font.SetResource( fontData ); } //-------------------------------------------------------------------------- bool GraphicsDrawing::InitializeFontShader( void* shaderBinary, size_t shaderSize ) { m_Drawer.Initialize(m_FontCommandBuffer, shaderBinary, shaderSize); return true; } //-------------------------------------------------------------------------- void GraphicsDrawing::DestroyFont() { m_Drawer.Finalize(); os::SafeFree(m_FontCommandBuffer, m_FontAllocator); nw::font::DispStringBuffer* stringBuffer = m_TextWriter.GetDispStringBuffer(); os::SafeFree(stringBuffer, m_FontAllocator); // フォントの破棄 if (!m_Font.IsManaging(NULL)) { void* drawBuffer = m_Font.SetDrawBuffer(NULL); void* resource = m_Font.RemoveResource(); os::SafeFree(resource, m_FontAllocator); os::SafeFree(drawBuffer, m_FontAllocator); } } //-------------------------------------------------------------------------- void GraphicsDrawing::SendFontMatrix() { //---- 射影行列を正射影に設定 { // 左上原点とし、Y軸とZ軸の向きが逆になるように設定します。 math::MTX44 proj; f32 znear = 0.0f; f32 zfar = -1.0f; f32 t = 0; f32 b = static_cast(m_ScreenSize.y); f32 l = 0; f32 r = static_cast(m_ScreenSize.x); math::MTX44OrthoPivot(&proj, l, r, b, t, znear, zfar, math::PIVOT_UPSIDE_TO_TOP); m_Drawer.SetProjectionMtx( proj ); } //---- モデルビュー行列を単位行列に設定 { nn::math::MTX34 mv; nn::math::MTX34Identity(&mv); m_Drawer.SetViewMtxForText(mv); } } //-------------------------------------------------------------------------- void GraphicsDrawing::BeginDrawingString() { // カラーバッファ情報 // LCDの向きに合わせて、幅と高さを入れ替えています。 const nw::font::ColorBufferInfo colBufInfo = { m_ScreenSize.y, m_ScreenSize.x, PICA_DATA_DEPTH24_STENCIL8_EXT }; const u32 screenSettingCommands[] = { // ビューポートの設定 NW_FONT_CMD_SET_VIEWPORT( 0, 0, colBufInfo.width, colBufInfo.height ), // シザー処理を無効 NW_FONT_CMD_SET_DISABLE_SCISSOR( colBufInfo ), // wバッファの無効化 // デプスレンジの設定 // ポリゴンオフセットの無効化 NW_FONT_CMD_SET_WBUFFER_DEPTHRANGE_POLYGONOFFSET( 0.0f, // wScale : 0.0 でWバッファが無効 0.0f, // depth range near 1.0f, // depth range far 0, // polygon offset units : 0.0 で ポリゴンオフセットが無効 colBufInfo), }; nngxAdd3DCommand(screenSettingCommands, sizeof(screenSettingCommands), true); static const u32 s_InitCommands[] = { // カリングを無効 NW_FONT_CMD_SET_CULL_FACE( NW_FONT_CMD_CULL_FACE_DISABLE ), // ステンシルテストを無効 NW_FONT_CMD_SET_DISABLE_STENCIL_TEST(), // デプステストを無効 // カラーバッファの全ての成分を書き込み可 NW_FONT_CMD_SET_DEPTH_FUNC_COLOR_MASK( false, // isDepthTestEnabled 0, // depthFunc true, // depthMask true, // red true, // green true, // blue true), // alpha // アーリーデプステストを無効 NW_FONT_CMD_SET_ENABLE_EARLY_DEPTH_TEST( false ), // フレームバッファアクセス制御 NW_FONT_CMD_SET_FBACCESS( true, // colorRead true, // colorWrite false, // depthRead false, // depthWrite false, // stencilRead false), // stencilWrite }; nngxAdd3DCommand(s_InitCommands, sizeof(s_InitCommands), true); m_Drawer.DrawBegin(); this->SendFontMatrix(); m_TextWriter.SetCursor( 0, 0 ); } //-------------------------------------------------------------------------- f32 GraphicsDrawing::DrawString( const char* format, ... ) { NW_NULL_ASSERT( format ); std::va_list vargs; va_start(vargs, format); m_TextWriter.StartPrint(); f32 width = m_TextWriter.VPrintf(format, vargs); m_TextWriter.EndPrint(); m_Drawer.BuildTextCommand(&m_TextWriter); m_TextWriter.UseCommandBuffer(); va_end(vargs); return width; } //-------------------------------------------------------------------------- f32 GraphicsDrawing::DrawString( s32 posh, s32 posv, const char* format, ... ) { NW_NULL_ASSERT( format ); m_TextWriter.SetCursor( static_cast(posh), static_cast(posv) ); std::va_list vargs; va_start(vargs, format); f32 width = this->DrawStringArgs( posh, posv, format, vargs); va_end(vargs); return width; } //-------------------------------------------------------------------------- f32 GraphicsDrawing::DrawStringArgs( s32 posh, s32 posv, const char* format, std::va_list args ) { NW_NULL_ASSERT( format ); m_TextWriter.SetCursor( static_cast(posh), static_cast(posv) ); m_TextWriter.StartPrint(); f32 width = m_TextWriter.VPrintf(format, args); m_TextWriter.EndPrint(); m_Drawer.BuildTextCommand(&m_TextWriter); m_TextWriter.UseCommandBuffer(); return width; } //-------------------------------------------------------------------------- void GraphicsDrawing::FlushDrawing() { m_Drawer.DrawEnd(); } } /* namespace demo */ } /* namespace nw */