From eec04b3a0b9fa01229948b6ee9716a58bd6918b7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Mart=C3=ADn=20Lucas=20Golini?= Date: Thu, 25 Aug 2022 02:59:20 -0300 Subject: [PATCH] TerminalDisplay: Rendering performance improvements. VertexBuffer: Added some helper functions to add and set quads. GlyphDrawable: Added a function to draw the glyph into a VertexBuffer. --- include/eepp/graphics/glyphdrawable.hpp | 5 + include/eepp/graphics/vertexbuffer.hpp | 16 + src/eepp/graphics/glyphdrawable.cpp | 22 ++ src/eepp/graphics/vertexbuffer.cpp | 156 +++++++++ .../eterm/terminal/iterminaldisplay.hpp | 2 +- .../eterm/terminal/terminaldisplay.hpp | 33 +- .../src/eterm/terminal/terminaldisplay.cpp | 302 ++++++++++++------ src/tools/eterm/eterm.cpp | 2 +- 8 files changed, 442 insertions(+), 96 deletions(-) diff --git a/include/eepp/graphics/glyphdrawable.hpp b/include/eepp/graphics/glyphdrawable.hpp index a1a672243..e7785ec58 100644 --- a/include/eepp/graphics/glyphdrawable.hpp +++ b/include/eepp/graphics/glyphdrawable.hpp @@ -7,6 +7,8 @@ namespace EE { namespace Graphics { +class VertexBuffer; + class EE_API GlyphDrawable : public DrawableResource { public: static GlyphDrawable* New( Texture* texture, const Rect& srcRect, @@ -27,6 +29,9 @@ class EE_API GlyphDrawable : public DrawableResource { virtual void draw( const Vector2f& position, const Sizef& size ); + virtual void drawIntoVertexBuffer( VertexBuffer* vbo, const Vector2u& gridPos, + const Vector2f& pos, const Uint32& textureLevel = 0 ); + virtual bool isStateful(); /** @return The texture instance used by the GlyphDrawable. */ diff --git a/include/eepp/graphics/vertexbuffer.hpp b/include/eepp/graphics/vertexbuffer.hpp index f90173bd1..c255e7d66 100644 --- a/include/eepp/graphics/vertexbuffer.hpp +++ b/include/eepp/graphics/vertexbuffer.hpp @@ -109,6 +109,21 @@ class EE_API VertexBuffer { */ void resizeIndices( const Uint32& size ); + void addQuad( const Vector2f& pos, const Sizef& size, const Color& color ); + + void setQuad( const Vector2u& gridPos, const Vector2f& pos, const Sizef& size, + const Color& color ); + + void setQuadColor( const Vector2u& gridPos, const Color& color ); + + void setQuadFree( const Vector2u& gridPos, const Vector2f& pos0, const Vector2f& pos1, + const Vector2f& pos2, const Vector2f& pos3, const Color& color ); + + void setQuadTexCoords( const Vector2u& gridPos, const Rectf& coords, + const Uint32& textureLevel ); + + void setGridSize( const Sizei& size ); + /** @return The position array */ std::vector& getPositionArray(); @@ -177,6 +192,7 @@ class EE_API VertexBuffer { std::vector mTexCoordArray[4]; std::vector mColorArray; std::vector mIndexArray; + Sizei mGridSize; VertexBuffer( const Uint32& VertexFlags = VERTEX_FLAGS_DEFAULT, PrimitiveType DrawType = PRIMITIVE_QUADS, const Int32& ReserveVertexSize = 0, diff --git a/src/eepp/graphics/glyphdrawable.cpp b/src/eepp/graphics/glyphdrawable.cpp index cf7ee547b..536cb484f 100644 --- a/src/eepp/graphics/glyphdrawable.cpp +++ b/src/eepp/graphics/glyphdrawable.cpp @@ -1,6 +1,7 @@ #include #include #include +#include namespace EE { namespace Graphics { @@ -51,6 +52,27 @@ void GlyphDrawable::draw( const Vector2f& position, const Sizef& size ) { BR->drawOpt(); } +void GlyphDrawable::drawIntoVertexBuffer( VertexBuffer* vbo, const Vector2u& gridPos, + const Vector2f& pos, const Uint32& textureLevel ) { + vbo->setQuadTexCoords( gridPos, + Rectf( mSrcRect.Left, mSrcRect.Top, mSrcRect.Left + mSrcRect.Right, + mSrcRect.Top + mSrcRect.Bottom ), + textureLevel ); + Sizef size( mSrcRect.Right, mSrcRect.Bottom ); + if ( mDrawMode == DrawMode::Image ) { + vbo->setQuad( gridPos, pos, Sizef( mSrcRect.Right, mSrcRect.Bottom ), mColor ); + } else if ( mDrawMode == DrawMode::TextItalic ) { + Float x = pos.x + mGlyphOffset.x; + Float y = pos.y + mGlyphOffset.y; + Float italic = 0.208f * size.getWidth(); // 12 degrees + vbo->setQuadFree( gridPos, { x + italic, y }, { x, y + size.getHeight() }, + { x + size.getWidth(), y + size.getHeight() }, + { x + size.getWidth() + italic, y }, mColor ); + } else { + vbo->setQuad( gridPos, pos + mGlyphOffset, size, mColor ); + } +} + bool GlyphDrawable::isStateful() { return false; } diff --git a/src/eepp/graphics/vertexbuffer.cpp b/src/eepp/graphics/vertexbuffer.cpp index 35763ceda..62dce8d19 100644 --- a/src/eepp/graphics/vertexbuffer.cpp +++ b/src/eepp/graphics/vertexbuffer.cpp @@ -149,6 +149,162 @@ void VertexBuffer::resizeIndices( const Uint32& size ) { mIndexArray.resize( size ); } +void VertexBuffer::addQuad( const Vector2f& pos, const Sizef& size, const Color& color ) { + if ( GLi->quadVertexs() == 6 ) { + addColor( color ); + addColor( color ); + addColor( color ); + addColor( color ); + addColor( color ); + addColor( color ); + addVertex( { pos.x, pos.y + size.y } ); + addVertex( { pos.x, pos.y } ); + addVertex( { pos.x + size.x, pos.y } ); + addVertex( { pos.x, pos.y + size.y } ); + addVertex( { pos.x + size.x, pos.y + size.y } ); + addVertex( { pos.x + size.x, pos.y } ); + } else { + addColor( color ); + addColor( color ); + addColor( color ); + addColor( color ); + addVertex( { pos.x, pos.y } ); + addVertex( { pos.x, pos.y + size.y } ); + addVertex( { pos.x + size.x, pos.y + size.y } ); + addVertex( { pos.x + size.x, pos.y } ); + } +} + +void VertexBuffer::setQuad( const Vector2u& gridPos, const Vector2f& pos, const Sizef& size, + const Color& color ) { + eeASSERT( mDrawType == PrimitiveType::PRIMITIVE_QUADS || + mDrawType == PrimitiveType::PRIMITIVE_QUAD_STRIP ); + eeASSERT( mGridSize != Sizei::Zero ); + eeASSERT( static_cast( gridPos.x * GLi->quadVertexs() + + gridPos.y * mGridSize.x * GLi->quadVertexs() + + GLi->quadVertexs() - 1 ) < mPosArray.size() ); + eeASSERT( static_cast( gridPos.x * GLi->quadVertexs() + + gridPos.y * mGridSize.x * GLi->quadVertexs() + + GLi->quadVertexs() - 1 ) < mColorArray.size() ); + int idx = ( gridPos.x * GLi->quadVertexs() + gridPos.y * mGridSize.x * GLi->quadVertexs() ); + if ( GLi->quadVertexs() == 6 ) { + setColor( idx + 0, color ); + setColor( idx + 1, color ); + setColor( idx + 2, color ); + setColor( idx + 3, color ); + setColor( idx + 4, color ); + setColor( idx + 5, color ); + setVertex( idx + 0, { pos.x, pos.y + size.y } ); + setVertex( idx + 1, { pos.x, pos.y } ); + setVertex( idx + 2, { pos.x + size.x, pos.y } ); + setVertex( idx + 3, { pos.x, pos.y + size.y } ); + setVertex( idx + 4, { pos.x + size.x, pos.y + size.y } ); + setVertex( idx + 5, { pos.x + size.x, pos.y } ); + } else { + setColor( idx + 0, color ); + setColor( idx + 1, color ); + setColor( idx + 2, color ); + setColor( idx + 3, color ); + setVertex( idx + 0, { pos.x, pos.y } ); + setVertex( idx + 1, { pos.x, pos.y + size.y } ); + setVertex( idx + 2, { pos.x + size.x, pos.y + size.y } ); + setVertex( idx + 3, { pos.x + size.x, pos.y } ); + } +} + +void VertexBuffer::setQuadColor( const Vector2u& gridPos, const Color& color ) { + eeASSERT( mDrawType == PrimitiveType::PRIMITIVE_QUADS || + mDrawType == PrimitiveType::PRIMITIVE_QUAD_STRIP ); + eeASSERT( mGridSize != Sizei::Zero ); + eeASSERT( static_cast( gridPos.x * GLi->quadVertexs() + + gridPos.y * mGridSize.x * GLi->quadVertexs() + + GLi->quadVertexs() - 1 ) < mPosArray.size() ); + eeASSERT( static_cast( gridPos.x * GLi->quadVertexs() + + gridPos.y * mGridSize.x * GLi->quadVertexs() + + GLi->quadVertexs() - 1 ) < mColorArray.size() ); + int idx = ( gridPos.x * GLi->quadVertexs() + gridPos.y * mGridSize.x * GLi->quadVertexs() ); + if ( GLi->quadVertexs() == 6 ) { + setColor( idx + 0, color ); + setColor( idx + 1, color ); + setColor( idx + 2, color ); + setColor( idx + 3, color ); + setColor( idx + 4, color ); + setColor( idx + 5, color ); + } else { + setColor( idx + 0, color ); + setColor( idx + 1, color ); + setColor( idx + 2, color ); + setColor( idx + 3, color ); + } +} + +void VertexBuffer::setQuadFree( const Vector2u& gridPos, const Vector2f& pos0, const Vector2f& pos1, + const Vector2f& pos2, const Vector2f& pos3, const Color& color ) { + eeASSERT( mDrawType == PrimitiveType::PRIMITIVE_QUADS || + mDrawType == PrimitiveType::PRIMITIVE_QUAD_STRIP ); + eeASSERT( mGridSize != Sizei::Zero ); + eeASSERT( static_cast( gridPos.x * GLi->quadVertexs() + + gridPos.y * mGridSize.x * GLi->quadVertexs() + + GLi->quadVertexs() - 1 ) < mPosArray.size() ); + eeASSERT( static_cast( gridPos.x * GLi->quadVertexs() + + gridPos.y * mGridSize.x * GLi->quadVertexs() + + GLi->quadVertexs() - 1 ) < mColorArray.size() ); + int idx = ( gridPos.x * GLi->quadVertexs() + gridPos.y * mGridSize.x * GLi->quadVertexs() ); + if ( GLi->quadVertexs() == 6 ) { + setColor( idx + 0, color ); + setColor( idx + 1, color ); + setColor( idx + 2, color ); + setColor( idx + 3, color ); + setColor( idx + 4, color ); + setColor( idx + 5, color ); + setVertex( idx + 0, pos1 ); + setVertex( idx + 1, pos0 ); + setVertex( idx + 2, pos3 ); + setVertex( idx + 3, pos1 ); + setVertex( idx + 4, pos2 ); + setVertex( idx + 5, pos3 ); + } else { + setColor( idx + 0, color ); + setColor( idx + 1, color ); + setColor( idx + 2, color ); + setColor( idx + 3, color ); + setVertex( idx + 0, pos0 ); + setVertex( idx + 1, pos1 ); + setVertex( idx + 2, pos2 ); + setVertex( idx + 3, pos3 ); + } +} + +void VertexBuffer::setQuadTexCoords( const Vector2u& gridPos, const Rectf& coords, + const Uint32& textureLevel ) { + eeASSERT( mDrawType == PrimitiveType::PRIMITIVE_QUADS || + mDrawType == PrimitiveType::PRIMITIVE_QUAD_STRIP ); + eeASSERT( mGridSize != Sizei::Zero ); + eeASSERT( static_cast( gridPos.x * GLi->quadVertexs() + + gridPos.y * mGridSize.x * GLi->quadVertexs() + + GLi->quadVertexs() - 1 ) < mTexCoordArray[textureLevel].size() ); + int idx = ( gridPos.x * GLi->quadVertexs() + gridPos.y * mGridSize.x * GLi->quadVertexs() ); + if ( GLi->quadVertexs() == 6 ) { + // 1 0 3 1 2 3 + setTextureCoord( idx + 0, { coords.Left, coords.Bottom }, textureLevel ); + setTextureCoord( idx + 1, { coords.Left, coords.Top }, textureLevel ); + setTextureCoord( idx + 2, { coords.Right, coords.Top }, textureLevel ); + setTextureCoord( idx + 3, { coords.Left, coords.Bottom }, textureLevel ); + setTextureCoord( idx + 4, { coords.Right, coords.Bottom }, textureLevel ); + setTextureCoord( idx + 5, { coords.Right, coords.Top }, textureLevel ); + } else { + // 0 1 2 3 + setTextureCoord( idx + 0, { coords.Left, coords.Top }, textureLevel ); + setTextureCoord( idx + 1, { coords.Left, coords.Bottom }, textureLevel ); + setTextureCoord( idx + 2, { coords.Right, coords.Bottom }, textureLevel ); + setTextureCoord( idx + 3, { coords.Right, coords.Top }, textureLevel ); + } +} + +void VertexBuffer::setGridSize( const Sizei& size ) { + mGridSize = size; +} + std::vector& VertexBuffer::getPositionArray() { return mPosArray; } diff --git a/src/modules/eterm/include/eterm/terminal/iterminaldisplay.hpp b/src/modules/eterm/include/eterm/terminal/iterminaldisplay.hpp index 0b8dc5317..33d08492a 100644 --- a/src/modules/eterm/include/eterm/terminal/iterminaldisplay.hpp +++ b/src/modules/eterm/include/eterm/terminal/iterminaldisplay.hpp @@ -70,7 +70,7 @@ class ITerminalDisplay { virtual const char* getClipboard() const; - virtual bool drawBegin( int columns, int rows ) = 0; + virtual bool drawBegin( Uint32 columns, Uint32 rows ) = 0; virtual void drawLine( Line line, int x1, int y, int x2 ) = 0; diff --git a/src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp b/src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp index 1bdad8ba4..2e8f5f3f3 100644 --- a/src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp +++ b/src/modules/eterm/include/eterm/terminal/terminaldisplay.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include #include @@ -24,6 +25,10 @@ using namespace EE::System; using namespace eterm::System; using namespace eterm::Terminal; +namespace EE { namespace Graphics { +class VertexBuffer; +}} // namespace EE::Graphics + namespace eterm { namespace Terminal { enum class TerminalShortcutAction { @@ -163,7 +168,7 @@ class TerminalDisplay : public ITerminalDisplay { virtual void setClipboard( const char* text ); virtual const char* getClipboard() const; - virtual bool drawBegin( int columns, int rows ); + virtual bool drawBegin( Uint32 columns, Uint32 rows ); virtual void drawLine( Line line, int x1, int y, int x2 ); virtual void drawCursor( int cx, int cy, TerminalGlyph g, int ox, int oy, TerminalGlyph og ); virtual void drawEnd(); @@ -285,11 +290,17 @@ class TerminalDisplay : public ITerminalDisplay { bool mKeepAlive{ true }; Clock mClock; Clock mLastDoubleClick; - int mColumns{ 0 }; - int mRows{ 0 }; + Uint32 mColumns{ 0 }; + Uint32 mRows{ 0 }; Uint32 mClickStep{ 5 }; FrameBuffer* mFrameBuffer{ nullptr }; + VertexBuffer* mVBBackground{ nullptr }; + VertexBuffer* mVBForeground{ nullptr }; + std::vector mVBStyles; TerminalColorScheme mColorScheme; + Uint32 mQuadVertexs{ 6 }; + Primitives mPrimitives; + Vector2u mCurGridPos; std::string mProgram; std::vector mArgs; @@ -315,6 +326,22 @@ class TerminalDisplay : public ITerminalDisplay { void createFrameBuffer(); void drawFrameBuffer(); + + void createVBO( VertexBuffer** vbo, bool usesTexCoords ); + + VertexBuffer* createRowVBO( bool usesTexCoords ); + + void initVBOs(); + + void drawbox( float x, float y, float w, float h, Color fg, Color bg, ushort bd ); + + void drawrect( const Color& col, const float& x, const float& y, const float& w, + const float& h ); + + void drawpoint( const Color& col, const float& x, const float& y, const float& w, + const float& h ); + + void drawboxlines( float x, float y, float w, float h, Color fg, ushort bd ); }; }} // namespace eterm::Terminal diff --git a/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp b/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp index 6248a6487..ca11ce5a4 100644 --- a/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp +++ b/src/modules/eterm/src/eterm/terminal/terminaldisplay.cpp @@ -1,7 +1,8 @@ #include #include -#include +#include #include +#include #include #include #include @@ -446,6 +447,10 @@ TerminalDisplay::create( EE::Window::Window* window, Font* font, const Float& fo } TerminalDisplay::~TerminalDisplay() { + eeSAFE_DELETE( mVBBackground ); + eeSAFE_DELETE( mVBForeground ); + for ( VertexBuffer* vb : mVBStyles ) + eeSAFE_DELETE( vb ); eeSAFE_DELETE( mFrameBuffer ); } @@ -468,8 +473,12 @@ TerminalDisplay::TerminalDisplay( EE::Window::Window* window, Font* font, const Sizei gridSize( gridSizeFromTermDimensions( mFont, mFontSize, mSize - mPadding * 2.f ) ); mDirtyLines.resize( gridSize.getHeight(), 1 ); + mQuadVertexs = GLi->quadVertexs(); + if ( mUseFrameBuffer ) createFrameBuffer(); + else + initVBOs(); } void TerminalDisplay::resetColors() { @@ -702,12 +711,16 @@ const char* TerminalDisplay::getClipboard() const { return mClipboardUtf8.c_str(); } -bool TerminalDisplay::drawBegin( int columns, int rows ) { +bool TerminalDisplay::drawBegin( Uint32 columns, Uint32 rows ) { if ( columns != mColumns || rows != mRows ) { TerminalGlyph defaultGlyph{}; mBuffer.resize( columns * rows, defaultGlyph ); mColumns = columns; mRows = rows; + + if ( !mUseFrameBuffer ) + initVBOs(); + invalidateLines(); invalidateCursor(); } @@ -853,20 +866,31 @@ static inline Color termColor( unsigned int terminalColor, const std::vector> 25 ) & 0xFF ) ) & 0xFF ); } -inline static void drawrect( const Color& col, const float& x, const float& y, const float& w, - const float& h, Primitives& p ) { - p.setColor( col ); - p.drawRectangle( { { eefloor( x ), eefloor( y ) }, { eeceil( w ), eeceil( h ) } } ); +void TerminalDisplay::drawrect( const Color& col, const float& x, const float& y, const float& w, + const float& h ) { + if ( mVBStyles.empty() ) { + mPrimitives.setColor( col ); + mPrimitives.drawRectangle( + { { eefloor( x ), eefloor( y ) }, { eeceil( w ), eeceil( h ) } } ); + } else { + mVBStyles[mCurGridPos.y]->addQuad( { eefloor( x ), eefloor( y ) }, + { eeceil( w ), eeceil( h ) }, col ); + } } -inline static void drawpoint( const Color& col, const float& x, const float& y, const float& w, - const float& h, Primitives& p ) { - p.setColor( col ); - p.drawPoint( { eefloor( x ), eefloor( y ) }, eemin( w / 2.f, h / 2.f ) ); +void TerminalDisplay::drawpoint( const Color& col, const float& x, const float& y, const float& w, + const float& h ) { + if ( mVBStyles.empty() ) { + mPrimitives.setColor( col ); + mPrimitives.drawPoint( { eefloor( x ), eefloor( y ) }, eemin( w / 2.f, h / 2.f ) ); + } else { + Float s = eemin( w / 2.f, h / 2.f ); + mVBStyles[mCurGridPos.y]->addQuad( { eefloor( x ), eefloor( y ) }, + { eefloor( s ), eefloor( s ) }, col ); + } } -inline static void drawboxlines( float x, float y, float w, float h, Color fg, ushort bd, - Primitives& pr ) { +void TerminalDisplay::drawboxlines( float x, float y, float w, float h, Color fg, ushort bd ) { /* s: stem thickness. width/8 roughly matches underscore thickness. */ /* We draw bold as 1.5 * normal-stem and at least 1px thicker. */ /* doubles draw at least 3px, even when w or h < 3. bold needs 6px. */ @@ -891,13 +915,13 @@ inline static void drawboxlines( float x, float y, float w, float h, Color fg, u float d = arc || ( multi_double && !multi_light ) ? -s : 0.0f; if ( bd & LL ) - drawrect( fg, x, y + h2, w2 + s + d, s, pr ); + drawrect( fg, x, y + h2, w2 + s + d, s ); if ( bd & LU ) - drawrect( fg, x + w2, y, s, h2 + s + d, pr ); + drawrect( fg, x + w2, y, s, h2 + s + d ); if ( bd & LR ) - drawrect( fg, x + w2 - d, y + h2, w - w2 + d, s, pr ); + drawrect( fg, x + w2 - d, y + h2, w - w2 + d, s ); if ( bd & LD ) - drawrect( fg, x + w2, y + h2 - d, s, h - h2 + d, pr ); + drawrect( fg, x + w2, y + h2 - d, s, h - h2 + d ); } /* double lines - also align with light to form heavy when combined */ @@ -912,58 +936,57 @@ inline static void drawboxlines( float x, float y, float w, float h, Color fg, u int dl = bd & DL, du = bd & DU, dr = bd & DR, dd = bd & DD; if ( dl ) { float p = dd ? -s : 0.0f, n = du ? -s : dd ? s : 0.0f; - drawrect( fg, x, y + h2 + s, w2 + s + p, s, pr ); - drawrect( fg, x, y + h2 - s, w2 + s + n, s, pr ); + drawrect( fg, x, y + h2 + s, w2 + s + p, s ); + drawrect( fg, x, y + h2 - s, w2 + s + n, s ); } if ( du ) { float p = dl ? -s : 0.0f, n = dr ? -s : dl ? s : 0.0f; - drawrect( fg, x + w2 - s, y, s, h2 + s + p, pr ); - drawrect( fg, x + w2 + s, y, s, h2 + s + n, pr ); + drawrect( fg, x + w2 - s, y, s, h2 + s + p ); + drawrect( fg, x + w2 + s, y, s, h2 + s + n ); } if ( dr ) { float p = du ? -s : 0.0f, n = dd ? -s : du ? s : 0.0f; - drawrect( fg, x + w2 - p, y + h2 - s, w - w2 + p, s, pr ); - drawrect( fg, x + w2 - n, y + h2 + s, w - w2 + n, s, pr ); + drawrect( fg, x + w2 - p, y + h2 - s, w - w2 + p, s ); + drawrect( fg, x + w2 - n, y + h2 + s, w - w2 + n, s ); } if ( dd ) { float p = dr ? -s : 0.0f, n = dl ? -s : dr ? s : 0.0f; - drawrect( fg, x + w2 + s, y + h2 - p, s, h - h2 + p, pr ); - drawrect( fg, x + w2 - s, y + h2 - n, s, h - h2 + n, pr ); + drawrect( fg, x + w2 + s, y + h2 - p, s, h - h2 + p ); + drawrect( fg, x + w2 - s, y + h2 - n, s, h - h2 + n ); } } } -inline static void drawbox( float x, float y, float w, float h, Color fg, Color bg, ushort bd, - Primitives& p ) { +void TerminalDisplay::drawbox( float x, float y, float w, float h, Color fg, Color bg, ushort bd ) { ushort cat = bd & ~( BDB | 0xff ); /* mask out bold and data */ if ( bd & ( BDL | BDA ) ) { /* lines (light/double/heavy/arcs) */ - drawboxlines( x, y, w, h, fg, bd, p ); + drawboxlines( x, y, w, h, fg, bd ); } else if ( cat == BBD ) { /* lower (8-X)/8 block */ float d = DIV( ( bd & 0xFF ) * h, 8.0f ); - drawrect( fg, x, y + d, w, h - d, p ); + drawrect( fg, x, y + d, w, h - d ); } else if ( cat == BBU ) { /* upper X/8 block */ - drawrect( fg, x, y, w, DIV( ( bd & 0xFF ) * h, 8 ), p ); + drawrect( fg, x, y, w, DIV( ( bd & 0xFF ) * h, 8 ) ); } else if ( cat == BBL ) { /* left X/8 block */ - drawrect( fg, x, y, DIV( ( bd & 0xFF ) * w, 8 ), h, p ); + drawrect( fg, x, y, DIV( ( bd & 0xFF ) * w, 8 ), h ); } else if ( cat == BBR ) { /* right (8-X)/8 block */ float d = DIV( ( bd & 0xFF ) * w, 8.0f ); - drawrect( fg, x + d, y, w - d, h, p ); + drawrect( fg, x + d, y, w - d, h ); } else if ( cat == BBQ ) { /* Quadrants */ float w2 = DIV( w, 2.0f ), h2 = DIV( h, 2.0f ); if ( bd & TL ) - drawrect( fg, x, y, w2, h2, p ); + drawrect( fg, x, y, w2, h2 ); if ( bd & TR ) - drawrect( fg, x + w2, y, w - w2, h2, p ); + drawrect( fg, x + w2, y, w - w2, h2 ); if ( bd & BL ) - drawrect( fg, x, y + h2, w2, h - h2, p ); + drawrect( fg, x, y + h2, w2, h - h2 ); if ( bd & BR ) - drawrect( fg, x + w2, y + h2, w - w2, h - h2, p ); + drawrect( fg, x + w2, y + h2, w - w2, h - h2 ); } else if ( bd & BBS ) { /* Shades - data is 1/2/3 for 25%/50%/75% alpha, respectively */ int d = ( bd & 0xFF ); @@ -979,28 +1002,28 @@ inline static void drawbox( float x, float y, float w, float h, Color fg, Color 4 ); Color drawcol = Color( red, green, blue, 0xFF ); - drawrect( drawcol, x, y, w, h, p ); + drawrect( drawcol, x, y, w, h ); } else if ( cat == BRL ) { /* braille, each data bit corresponds to one dot at 2x4 grid */ float w1 = DIV( w, 2.0f ); float h1 = DIV( h, 4.0f ), h2 = DIV( h, 2.0f ), h3 = DIV( 3.0f * h, 4.0f ); if ( bd & 1 ) - drawpoint( fg, x, y, w1, h1, p ); + drawpoint( fg, x, y, w1, h1 ); if ( bd & 2 ) - drawpoint( fg, x, y + h1, w1, h2 - h1, p ); + drawpoint( fg, x, y + h1, w1, h2 - h1 ); if ( bd & 4 ) - drawpoint( fg, x, y + h2, w1, h3 - h2, p ); + drawpoint( fg, x, y + h2, w1, h3 - h2 ); if ( bd & 8 ) - drawpoint( fg, x + w1, y, w - w1, h1, p ); + drawpoint( fg, x + w1, y, w - w1, h1 ); if ( bd & 16 ) - drawpoint( fg, x + w1, y + h1, w - w1, h2 - h1, p ); + drawpoint( fg, x + w1, y + h1, w - w1, h2 - h1 ); if ( bd & 32 ) - drawpoint( fg, x + w1, y + h2, w - w1, h3 - h2, p ); + drawpoint( fg, x + w1, y + h2, w - w1, h3 - h2 ); if ( bd & 64 ) - drawpoint( fg, x, y + h3, w1, h - h3, p ); + drawpoint( fg, x, y + h3, w1, h - h3 ); if ( bd & 128 ) - drawpoint( fg, x + w1, y + h3, w - w1, h - h3, p ); + drawpoint( fg, x + w1, y + h3, w - w1, h - h3 ); } } @@ -1020,21 +1043,25 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { Rectf xBounds = mFont->getGlyph( L'x', mFontSize, false ).bounds; Float strikeThroughOffset = lineHeight + xBounds.Top + cursorThickness; - Primitives p; - p.setForceDraw( false ); + mPrimitives.setForceDraw( false ); - for ( int j = 0; j < mRows; j++ ) { + bool dirtyBG = false; + if ( mVBBackground ) + mVBBackground->bind(); + + for ( Uint32 j = 0; j < mRows; j++ ) { x = std::floor( pos.x ); if ( pos.y + lineHeight * j > pos.y + mSize.getHeight() ) break; - if ( mFrameBuffer && !mDirtyLines[j] ) { + if ( !mDirtyLines[j] ) { y += lineHeight; continue; } - for ( int i = 0; i < mColumns; i++ ) { + for ( Uint32 i = 0; i < mColumns; i++ ) { + mCurGridPos = { i, j }; auto& glyph = mBuffer[j * mColumns + i]; auto fg = termColor( glyph.fg, mColors ); auto bg = termColor( glyph.bg, mColors ); @@ -1054,12 +1081,16 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { auto advanceX = spaceCharAdvanceX * ( isWide ? 2.0f : 1.0f ); - if ( glyph.mode & ATTR_WDUMMY ) { + if ( glyph.mode & ATTR_WDUMMY ) continue; - } - p.setColor( bg ); - p.drawRectangle( Rectf( { x, y }, { advanceX, lineHeight } ) ); + if ( mVBBackground ) { + mVBBackground->setQuad( mCurGridPos, { x, y }, { advanceX, lineHeight }, bg ); + dirtyBG = true; + } else { + mPrimitives.setColor( bg ); + mPrimitives.drawRectangle( Rectf( { x, y }, { advanceX, lineHeight } ) ); + } x += advanceX; } @@ -1067,22 +1098,37 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { y += lineHeight; } + if ( mVBBackground ) { + if ( dirtyBG ) + mVBBackground->update( VERTEX_FLAGS_PRIMITIVE, false ); + mVBBackground->draw(); + mVBBackground->unbind(); + } + y = std::floor( pos.y ); - for ( int j = 0; j < mRows; j++ ) { + bool dirtyFG = false; + + for ( Uint32 j = 0; j < mRows; j++ ) { x = std::floor( pos.x ); if ( pos.y + lineHeight * j > pos.y + mSize.getHeight() ) break; - if ( mFrameBuffer && !mDirtyLines[j] ) { + if ( ( mFrameBuffer || mVBForeground ) && !mDirtyLines[j] ) { y += lineHeight; continue; } mDirtyLines[j] = false; - for ( int i = 0; i < mColumns; i++ ) { + if ( !mVBStyles.empty() ) { + eeSAFE_DELETE( mVBStyles[j] ); + mVBStyles[j] = createRowVBO( false ); + } + + for ( Uint32 i = 0; i < mColumns; i++ ) { + mCurGridPos = { i, j }; auto& glyph = mBuffer[j * mColumns + i]; auto fg = termColor( glyph.fg, mColors ); auto bg = termColor( glyph.bg, mColors ); @@ -1118,9 +1164,18 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { if ( glyph.mode & ATTR_WDUMMY ) continue; + if ( glyph.u == 32 ) { + x += advanceX; + if ( mVBForeground ) + mVBForeground->setQuadColor( mCurGridPos, Color::Transparent ); + continue; + } + if ( glyph.mode & ATTR_BOXDRAW ) { auto bd = TerminalEmulator::boxdrawindex( &glyph ); - drawbox( x, y, advanceX, lineHeight, fg, bg, bd, p ); + drawbox( x, y, advanceX, lineHeight, fg, bg, bd ); + if ( mVBForeground ) + mVBForeground->setQuadColor( mCurGridPos, Color::Transparent ); } else { auto* gd = mFont->getGlyphDrawable( glyph.u, mFontSize, glyph.mode & ATTR_BOLD ); @@ -1141,18 +1196,31 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { gd->setColor( fg ); } - gd->draw( { x, y } ); - - if ( glyph.mode & ATTR_UNDERLINE ) { - p.setColor( fg ); - p.drawRectangle( Rectf( { x, y + lineHeight - cursorThickness }, - { advanceX, cursorThickness } ) ); + if ( mVBForeground ) { + gd->drawIntoVertexBuffer( mVBForeground, mCurGridPos, { x, y } ); + } else { + gd->draw( { x, y } ); } + dirtyFG = true; - if ( glyph.mode & ATTR_STRUCK ) { - p.setColor( fg ); - p.drawRectangle( - Rectf( { x, y + strikeThroughOffset }, { advanceX, cursorThickness } ) ); + if ( mVBStyles.empty() ) { + if ( glyph.mode & ATTR_UNDERLINE ) { + mPrimitives.setColor( fg ); + mPrimitives.drawRectangle( Rectf( { x, y + lineHeight - cursorThickness }, + { advanceX, cursorThickness } ) ); + } else if ( glyph.mode & ATTR_STRUCK ) { + mPrimitives.setColor( fg ); + mPrimitives.drawRectangle( Rectf( { x, y + strikeThroughOffset }, + { advanceX, cursorThickness } ) ); + } + } else { + if ( glyph.mode & ATTR_UNDERLINE ) { + mVBStyles[j]->addQuad( { x, y + lineHeight - cursorThickness }, + { advanceX, cursorThickness }, fg ); + } else if ( glyph.mode & ATTR_STRUCK ) { + mVBStyles[j]->addQuad( { x, y + strikeThroughOffset }, + { advanceX, cursorThickness }, fg ); + } } } @@ -1162,6 +1230,27 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { y += lineHeight; } + if ( mVBForeground ) { + mFont->getTexture( mFontSize )->bind(); + if ( dirtyFG ) + mVBForeground->update( VERTEX_FLAGS_DEFAULT, false ); + mVBForeground->bind(); + mVBForeground->draw(); + mVBForeground->unbind(); + } + + if ( !mVBStyles.empty() ) { + if ( dirtyFG ) { + for ( auto& vbo : mVBStyles ) + vbo->update( VERTEX_FLAGS_PRIMITIVE, false ); + } + for ( auto& vbo : mVBStyles ) { + vbo->bind(); + vbo->draw(); + vbo->unbind(); + } + } + if ( !mEmulator->isScrolling() && !IS_SET( MODE_HIDE ) && ( !mUseFrameBuffer || mDirtyCursor ) ) { mDirtyCursor = false; @@ -1177,56 +1266,55 @@ void TerminalDisplay::drawGrid( const Vector2f& pos ) { : mColorScheme.getCursor(); } - Vector2f a{}, b{}, c{}, d{}; - - p.setColor( drawcol ); + mPrimitives.setColor( drawcol ); /* draw the new one */ if ( IS_SET( MODE_FOCUSED ) ) { switch ( mCursorMode ) { - case 7: /* st extension */ - mCursorGlyph.u = 0x2603; /* snowman (U+2603) */ - /* FALLTHROUGH */ - case 0: /* Blinking Block */ - case 1: { /* Blinking Block (Default) */ - if ( !( mMode & MODE_BLINK ) ) - break; - } - case 2: { /* Steady Block */ - auto* gd = mFont->getGlyphDrawable( mCursorGlyph.u, mFontSize ); + case StExtension: + case SteadyBlock: { + auto* gd = mFont->getGlyphDrawable( + mCursorMode == StExtension ? 0xFB04 /* TUX */ : mCursorGlyph.u, mFontSize ); gd->setColor( termColor( mCursorGlyph.fg, mColors ) ); gd->setDrawMode( GlyphDrawable::DrawMode::Text ); gd->draw( { pos.x + mCursor.x * spaceCharAdvanceX, pos.y + mCursor.y * lineHeight } ); break; } - case 3: { /* Blinking Underline */ + case BlinkUnderline: { if ( !( mMode & MODE_BLINK ) ) break; } - case 4: /* Steady Underline */ - p.drawRectangle( + case SteadyUnderline: + mPrimitives.drawRectangle( Rectf( { pos.x + mCursor.x * spaceCharAdvanceX, pos.y + ( mCursor.y + 1 ) * lineHeight - cursorThickness }, { spaceCharAdvanceX, cursorThickness } ) ); break; - case 5: { /* Blinking bar */ + case BlinkingBlock: + case BlinkingBlockDefault: + case BlinkBar: { if ( !( mMode & MODE_BLINK ) ) break; } - case 6: /* Steady bar */ + case SteadyBar: case TerminalCursorMode::MAX_CURSOR: - p.drawRectangle( Rectf( + mPrimitives.drawRectangle( Rectf( { pos.x + mCursor.x * spaceCharAdvanceX, pos.y + mCursor.y * lineHeight }, { spaceCharAdvanceX, lineHeight } ) ); break; } } else { Vector2f cpos{ pos.x + mCursor.x * spaceCharAdvanceX, pos.y + mCursor.y * lineHeight }; - drawrect( drawcol, cpos.x, cpos.y, spaceCharAdvanceX, cursorThickness, p ); - drawrect( drawcol, cpos.x, cpos.y, cursorThickness, lineHeight, p ); - drawrect( drawcol, cpos.x + spaceCharAdvanceX, cpos.y, cursorThickness, lineHeight, p ); - drawrect( drawcol, cpos.x, cpos.y + lineHeight - cursorThickness, spaceCharAdvanceX, - cursorThickness, p ); + mPrimitives.setColor( drawcol ); + mPrimitives.drawRectangle( + Rectf( Vector2f( cpos.x, cpos.y ), { spaceCharAdvanceX, cursorThickness } ) ); + mPrimitives.drawRectangle( + Rectf( Vector2f( cpos.x, cpos.y ), { cursorThickness, lineHeight } ) ); + mPrimitives.drawRectangle( Rectf( Vector2f( cpos.x + spaceCharAdvanceX, cpos.y ), + { cursorThickness, lineHeight } ) ); + mPrimitives.drawRectangle( + Rectf( Vector2f( cpos.x, cpos.y + lineHeight - cursorThickness ), + { spaceCharAdvanceX, cursorThickness } ) ); } } @@ -1545,4 +1633,36 @@ void TerminalDisplay::drawFrameBuffer() { } } +VertexBuffer* TerminalDisplay::createRowVBO( bool usesTexCoords ) { + auto* VBO = VertexBuffer::New( + usesTexCoords ? VERTEX_FLAGS_DEFAULT : VERTEX_FLAGS_PRIMITIVE, + mQuadVertexs == 6 ? EE::Graphics::PRIMITIVE_TRIANGLES : EE::Graphics::PRIMITIVE_QUADS, + mRows * mColumns * mQuadVertexs, 0, VertexBufferUsageType::Stream ); + VBO->setGridSize( Sizei( mColumns, 1 ) ); + return VBO; +} + +void TerminalDisplay::createVBO( VertexBuffer** vbo, bool usesTexCoords ) { + eeSAFE_DELETE( ( *vbo ) ); + ( *vbo ) = VertexBuffer::New( + usesTexCoords ? VERTEX_FLAGS_DEFAULT : VERTEX_FLAGS_PRIMITIVE, + mQuadVertexs == 6 ? EE::Graphics::PRIMITIVE_TRIANGLES : EE::Graphics::PRIMITIVE_QUADS, + mRows * mColumns * mQuadVertexs, 0, VertexBufferUsageType::Stream ); + ( *vbo )->resizeArray( VERTEX_FLAG_POSITION, mRows * mColumns * mQuadVertexs ); + ( *vbo )->resizeArray( VERTEX_FLAG_COLOR, mRows * mColumns * mQuadVertexs ); + ( *vbo )->setGridSize( Sizei( mColumns, mRows ) ); + if ( usesTexCoords ) + ( *vbo )->resizeArray( VERTEX_FLAG_TEXTURE0, mRows * mColumns * mQuadVertexs ); +} + +void TerminalDisplay::initVBOs() { + createVBO( &mVBBackground, false ); + createVBO( &mVBForeground, true ); + for ( VertexBuffer* vb : mVBStyles ) + eeSAFE_DELETE( vb ); + mVBStyles.clear(); + for ( Uint32 i = 0; i < mRows; ++i ) + mVBStyles.emplace_back( createRowVBO( false ) ); +} + }} // namespace eterm::Terminal diff --git a/src/tools/eterm/eterm.cpp b/src/tools/eterm/eterm.cpp index c17a63295..f0b3e0cd5 100644 --- a/src/tools/eterm/eterm.cpp +++ b/src/tools/eterm/eterm.cpp @@ -131,7 +131,7 @@ EE_MAIN_FUNC int main( int argc, char* argv[] ) { args::Flag vsync( parser, "vsync", "Enable vsync", { "vsync" } ); args::ValueFlag maxFPS( parser, "max-fps", "Maximum rendering frames per second of the terminal", - { "--max-fps" }, 60 ); + { "max-fps" }, 60 ); args::Flag benchmarkModeFlag( parser, "benchmark-mode", "Render as much as possible.", { "benchmark-mode" } );