Added frame buffer support to TerminalDisplay, added proper line and cursor invalidation (only redraw the lines that are actually dirty).

This commit is contained in:
Martín Lucas Golini
2022-07-03 02:25:52 -03:00
parent 621cee2dc4
commit 8c6035a0bb
6 changed files with 162 additions and 40 deletions

View File

@@ -69,7 +69,7 @@ class EE_API FrameBuffer {
Texture* getTexture() const;
/** @brief Sets the frame buffer clear color. */
void setClearColor( ColorAf Color );
void setClearColor( const ColorAf& color );
/** @return The clear color used for the frame buffer. */
ColorAf getClearColor() const;

View File

@@ -49,8 +49,8 @@ Texture* FrameBuffer::getTexture() const {
return mTexture;
}
void FrameBuffer::setClearColor( ColorAf Color ) {
mClearColor = Color;
void FrameBuffer::setClearColor( const ColorAf& color ) {
mClearColor = color;
}
ColorAf FrameBuffer::getClearColor() const {

View File

@@ -9,7 +9,7 @@
namespace EE { namespace Graphics {
bool FrameBufferFBO::isSupported() {
return 0 != GLi->isExtension( EEGL_EXT_framebuffer_object );
return GLi && 0 != GLi->isExtension( EEGL_EXT_framebuffer_object );
}
FrameBufferFBO::FrameBufferFBO( EE::Window::Window* window ) :

View File

@@ -137,6 +137,8 @@ EE_MAIN_FUNC int main( int, char*[] ) {
win->runMainLoop( &mainLoop );
}
terminal.reset();
Engine::destroySingleton();
MemoryManager::showResults();

View File

@@ -1,10 +1,11 @@
#include "terminaldisplay.hpp"
#include "../system/processfactory.hpp"
#include "boxdrawdata.hpp"
#include "eepp/graphics/fonttruetype.hpp"
#include <eepp/graphics/fontmanager.hpp>
#include <eepp/graphics/fonttruetype.hpp>
#include <eepp/graphics/primitives.hpp>
#include <eepp/graphics/text.hpp>
#include <eepp/math/math.hpp>
#include <eepp/system/color.hpp>
#include <eepp/window.hpp>
#include <eepp/window/clipboard.hpp>
@@ -360,12 +361,11 @@ static const Color colormapped[256] = {
Color( 208, 208, 208 ), Color( 218, 218, 218 ), Color( 228, 228, 228 ),
Color( 238, 238, 238 ) };
std::shared_ptr<TerminalDisplay>
TerminalDisplay::create( EE::Window::Window* window, Font* font, const Float& fontSize,
const Sizef& pixelsSize,
std::shared_ptr<TerminalEmulator>&& terminalEmulator ) {
std::shared_ptr<TerminalDisplay> TerminalDisplay::create(
EE::Window::Window* window, Font* font, const Float& fontSize, const Sizef& pixelsSize,
std::shared_ptr<TerminalEmulator>&& terminalEmulator, const bool& useFrameBuffer ) {
std::shared_ptr<TerminalDisplay> terminal = std::shared_ptr<TerminalDisplay>(
new TerminalDisplay( window, font, fontSize, pixelsSize ) );
new TerminalDisplay( window, font, fontSize, pixelsSize, useFrameBuffer ) );
terminal->mTerminal = std::move( terminalEmulator );
return terminal;
}
@@ -380,11 +380,10 @@ static Sizei gridSizeFromTermDimensions( Font* font, const Float& fontSize,
return { clipColumns, clipRows };
}
std::shared_ptr<TerminalDisplay>
TerminalDisplay::create( EE::Window::Window* window, Font* font, const Float& fontSize,
const Sizef& pixelsSize, std::string program,
const std::vector<std::string>& args, const std::string& workingDir,
const size_t& historySize, IProcessFactory* processFactory ) {
std::shared_ptr<TerminalDisplay> TerminalDisplay::create(
EE::Window::Window* window, Font* font, const Float& fontSize, const Sizef& pixelsSize,
std::string program, const std::vector<std::string>& args, const std::string& workingDir,
const size_t& historySize, IProcessFactory* processFactory, const bool& useFrameBuffer ) {
if ( program.empty() ) {
#ifdef _WIN32
program = "cmd.exe";
@@ -426,7 +425,7 @@ TerminalDisplay::create( EE::Window::Window* window, Font* font, const Float& fo
}
std::shared_ptr<TerminalDisplay> terminal = std::shared_ptr<TerminalDisplay>(
new TerminalDisplay( window, font, fontSize, pixelsSize ) );
new TerminalDisplay( window, font, fontSize, pixelsSize, useFrameBuffer ) );
terminal->mTerminal = TerminalEmulator::create( std::move( pseudoTerminal ),
std::move( process ), terminal, historySize );
@@ -440,13 +439,18 @@ TerminalDisplay::create( EE::Window::Window* window, Font* font, const Float& fo
return terminal;
}
TerminalDisplay::~TerminalDisplay() {
eeSAFE_DELETE( mFrameBuffer );
}
TerminalDisplay::TerminalDisplay( EE::Window::Window* window, Font* font, const Float& fontSize,
const Sizef& pixelsSize ) :
const Sizef& pixelsSize, const bool& useFrameBuffer ) :
ITerminalDisplay(),
mWindow( window ),
mFont( font ),
mFontSize( fontSize ),
mSize( pixelsSize ) {
mSize( pixelsSize ),
mUseFrameBuffer( useFrameBuffer ) {
TerminalGlyph defaultGlyph;
defaultGlyph.mode = ATTR_INVISIBLE;
auto defaultColor = std::make_pair<Uint32, std::string>( 0U, "" );
@@ -454,6 +458,12 @@ TerminalDisplay::TerminalDisplay( EE::Window::Window* window, Font* font, const
mColors.resize( eeARRAY_SIZE( colormapped ), defaultColor );
mBuffer.resize( mColumns * mRows, defaultGlyph );
( (int&)mMode ) |= MODE_FOCUSED;
Sizei gridSize( gridSizeFromTermDimensions( mFont, mFontSize, mSize - mPadding * 2.f ) );
mDirtyLines.resize( gridSize.getHeight(), 1 );
if ( mUseFrameBuffer )
createFrameBuffer();
}
void TerminalDisplay::resetColors() {
@@ -535,7 +545,7 @@ void TerminalDisplay::update() {
if ( mFocus && isBlinkingCursor() && mClock.getElapsedTime().asSeconds() > 0.7 ) {
mMode ^= MODE_BLINK;
mClock.restart();
invalidate();
invalidateCursor();
}
if ( mTerminal )
mTerminal->update();
@@ -638,7 +648,8 @@ bool TerminalDisplay::drawBegin( int columns, int rows ) {
mBuffer.resize( columns * rows, defaultGlyph );
mColumns = columns;
mRows = rows;
invalidate();
invalidateLines();
invalidateCursor();
}
return ( ( mMode & MODE_VISIBLE ) != 0 );
@@ -651,7 +662,7 @@ void TerminalDisplay::drawLine( Line line, int x1, int y, int x2 ) {
mBuffer[y * mColumns + i].mode |= ATTR_REVERSE;
}
}
invalidate();
invalidateLine( y );
}
void TerminalDisplay::drawCursor( int cx, int cy, TerminalGlyph g, int, int, TerminalGlyph ) {
@@ -659,14 +670,14 @@ void TerminalDisplay::drawCursor( int cx, int cy, TerminalGlyph g, int, int, Ter
mCursor.x = cx;
mCursor.y = cy;
mCursorGlyph = g;
invalidate();
invalidateCursor();
}
}
void TerminalDisplay::drawEnd() {}
void TerminalDisplay::draw() {
draw( mPosition.floor() + mPadding );
draw( nullptr != mFrameBuffer ? mPadding : mPosition.floor() + mPadding );
}
void TerminalDisplay::onMouseDoubleClick( const Vector2i& pos, const Uint32& flags ) {
@@ -678,7 +689,7 @@ void TerminalDisplay::onMouseDoubleClick( const Vector2i& pos, const Uint32& fla
mTerminal->getSelectionMode() == TerminalSelectionMode::SEL_IDLE ) ) {
auto gridPos{ positionToGrid( pos ) };
mTerminal->selstart( gridPos.x, gridPos.y, SNAP_WORD );
invalidate();
invalidateLines();
}
}
@@ -690,7 +701,7 @@ void TerminalDisplay::onMouseMotion( const Vector2i& pos, const Uint32& flags )
mTerminal->selextend(
gridPos.x, gridPos.y,
mWindow->getInput()->getModState() & KEYMOD_SHIFT ? SEL_RECTANGULAR : SEL_REGULAR, 0 );
invalidate();
invalidateLines();
}
mTerminal->mousereport( TerminalMouseEventType::MouseMotion, positionToGrid( pos ), flags,
mWindow->getInput()->getModState() );
@@ -732,7 +743,7 @@ void TerminalDisplay::onMouseDown( const Vector2i& pos, const Uint32& flags ) {
if ( mTerminal->getSelectionMode() == TerminalSelectionMode::SEL_IDLE ) {
auto gridPos{ positionToGrid( pos ) };
mTerminal->selstart( gridPos.x, gridPos.y, 0 );
invalidate();
invalidateLines();
} else if ( mTerminal->getSelectionMode() == TerminalSelectionMode::SEL_READY ) {
mTerminal->selclear();
}
@@ -918,11 +929,9 @@ inline static void drawbox( float x, float y, float w, float h, Color fg, Color
}
}
void TerminalDisplay::draw( const Vector2f& pos ) {
if ( !mEmulator )
return;
mDrawing = true;
void TerminalDisplay::drawGrid( const Vector2f& pos ) {
if ( mFrameBuffer )
mFrameBuffer->bind();
auto fontSize = (Float)mFont->getFontHeight( mFontSize );
auto spaceCharAdvanceX = mFont->getGlyph( 'A', mFontSize, false ).advance;
@@ -938,8 +947,6 @@ void TerminalDisplay::draw( const Vector2f& pos ) {
Primitives p;
p.setForceDraw( false );
p.setColor( defaultBg );
p.drawRectangle( Rectf( mPosition.asFloat(), mSize.asFloat() ) );
for ( int j = 0; j < mRows; j++ ) {
x = std::floor( pos.x );
@@ -947,6 +954,11 @@ void TerminalDisplay::draw( const Vector2f& pos ) {
if ( pos.y + lineHeight * j > pos.y + mSize.getHeight() )
break;
if ( mFrameBuffer && !mDirtyLines[j] ) {
y += lineHeight;
continue;
}
for ( int i = 0; i < mColumns; i++ ) {
auto& glyph = mBuffer[j * mColumns + i];
auto fg = termColor( glyph.fg, mColors );
@@ -988,6 +1000,13 @@ void TerminalDisplay::draw( const Vector2f& pos ) {
if ( pos.y + lineHeight * j > pos.y + mSize.getHeight() )
break;
if ( mFrameBuffer && !mDirtyLines[j] ) {
y += lineHeight;
continue;
}
mDirtyLines[j] = false;
for ( int i = 0; i < mColumns; i++ ) {
auto& glyph = mBuffer[j * mColumns + i];
auto fg = termColor( glyph.fg, mColors );
@@ -1068,7 +1087,8 @@ void TerminalDisplay::draw( const Vector2f& pos ) {
y += lineHeight;
}
if ( !mEmulator->isScrolling() && !IS_SET( MODE_HIDE ) ) {
if ( !mEmulator->isScrolling() && !IS_SET( MODE_HIDE ) && mDirtyCursor ) {
mDirtyCursor = false;
Color drawcol;
if ( IS_SET( MODE_REVERSE ) ) {
if ( mEmulator->isSelected( mCursor.x, mCursor.y ) ) {
@@ -1136,6 +1156,28 @@ void TerminalDisplay::draw( const Vector2f& pos ) {
}
}
if ( mFrameBuffer )
mFrameBuffer->unbind();
}
void TerminalDisplay::draw( const Vector2f& pos ) {
if ( !mEmulator )
return;
mDrawing = true;
auto defaultBg = termColor( mEmulator->getDefaultBackground(), mColors );
Primitives p;
p.setForceDraw( false );
p.setColor( defaultBg );
p.drawRectangle( Rectf( mPosition.asFloat(), mSize.asFloat() ) );
if ( !mFrameBuffer || mDirty )
drawGrid( pos );
if ( mFrameBuffer )
drawFrameBuffer();
mDrawing = false;
mDirty = false;
}
@@ -1168,11 +1210,23 @@ void TerminalDisplay::onSizeChange() {
if ( gridSize.getWidth() != mTerminal->getNumColumns() ||
gridSize.getHeight() != mTerminal->getNumRows() ) {
mTerminal->resize( gridSize.getWidth(), gridSize.getHeight() );
mDirtyLines.resize( gridSize.getHeight(), 1 );
}
} else if ( mEmulator ) {
if ( gridSize.getWidth() != mEmulator->getNumColumns() ||
gridSize.getHeight() != mEmulator->getNumRows() ) {
mEmulator->resize( gridSize.getWidth(), gridSize.getHeight() );
mDirtyLines.resize( gridSize.getHeight(), 1 );
}
}
if ( mFrameBuffer && ( mFrameBuffer->getWidth() < mSize.getWidth() ||
mFrameBuffer->getHeight() < mSize.getHeight() ) ) {
if ( nullptr == mFrameBuffer ) {
createFrameBuffer();
} else {
Sizei fboSize( getFrameBufferSize() );
mFrameBuffer->resize( fboSize.getWidth(), fboSize.getHeight() );
}
}
}
@@ -1202,6 +1256,7 @@ void TerminalDisplay::onProcessExit( int exitCode ) {
fprintf( stderr, "TerminalDisplay::onProcessExit: Failed to spawn process\n" );
}
mTerminal->clearHistory();
mTerminal->setPtyAndProcess( std::move( pseudoTerminal ), std::move( process ) );
eeSAFE_DELETE( processFactory );
@@ -1340,6 +1395,21 @@ void TerminalDisplay::invalidate() {
mDirty = true;
}
void TerminalDisplay::invalidateCursor() {
invalidateLine( mCursor.y );
mDirtyCursor = true;
mDirty = true;
}
void TerminalDisplay::invalidateLine( const int& line ) {
mDirtyLines[line] = true;
mDirty = true;
}
void TerminalDisplay::invalidateLines() {
mDirtyLines.assign( mDirtyLines.size(), 1 );
mDirty = true;
}
void TerminalDisplay::setFocus( bool focus ) {
if ( focus == mFocus )
return;
@@ -1355,5 +1425,33 @@ void TerminalDisplay::setFocus( bool focus ) {
} else {
mMode ^= MODE_FOCUS;
}
invalidate();
invalidateCursor();
}
Sizei TerminalDisplay::getFrameBufferSize() {
return Sizei( Math::nextPowOfTwo( (int)mSize.getWidth() ),
Math::nextPowOfTwo( (int)mSize.getHeight() ) );
}
void TerminalDisplay::createFrameBuffer() {
eeSAFE_DELETE( mFrameBuffer );
Sizei fboSize( getFrameBufferSize() );
if ( fboSize.getWidth() < 1 )
fboSize.setWidth( 1 );
if ( fboSize.getHeight() < 1 )
fboSize.setHeight( 1 );
mFrameBuffer = FrameBuffer::New( fboSize.getWidth(), fboSize.getHeight(), true );
// Frame buffer failed to create?
if ( !mFrameBuffer->created() )
eeSAFE_DELETE( mFrameBuffer );
}
void TerminalDisplay::drawFrameBuffer() {
if ( mFrameBuffer ) {
Rect r( 0, 0, mSize.getWidth(), mSize.getHeight() );
TextureRegion textureRegion( mFrameBuffer->getTexture()->getTextureId(), r,
r.getSize().asFloat() );
textureRegion.draw( mPosition.floor().x, mPosition.floor().y );
}
}

View File

@@ -6,6 +6,7 @@
#include "terminalemulator.hpp"
#include <eepp/config.hpp>
#include <eepp/graphics/font.hpp>
#include <eepp/graphics/framebuffer.hpp>
#include <eepp/system/clock.hpp>
#include <eepp/window/inputevent.hpp>
#include <eepp/window/keycodes.hpp>
@@ -139,13 +140,16 @@ class TerminalDisplay : public ITerminalDisplay {
static std::shared_ptr<TerminalDisplay>
create( EE::Window::Window* window, Font* font, const Float& fontSize, const Sizef& pixelsSize,
std::shared_ptr<TerminalEmulator>&& terminalEmulator );
std::shared_ptr<TerminalEmulator>&& terminalEmulator,
const bool& useFrameBuffer = false );
static std::shared_ptr<TerminalDisplay>
create( EE::Window::Window* window, Font* font, const Float& fontSize, const Sizef& pixelsSize,
std::string program = "", const std::vector<std::string>& args = {},
const std::string& workingDir = "", const size_t& historySize = 10000,
IProcessFactory* processFactory = nullptr );
IProcessFactory* processFactory = nullptr, const bool& useFrameBuffer = false );
virtual ~TerminalDisplay();
virtual void resetColors();
virtual int resetColor( Uint32 index, const char* name );
@@ -198,6 +202,12 @@ class TerminalDisplay : public ITerminalDisplay {
void invalidate();
void invalidateCursor();
void invalidateLine( const int& line );
void invalidateLines();
bool hasFocus() const { return mFocus; }
void setFocus( bool focus );
@@ -234,27 +244,33 @@ class TerminalDisplay : public ITerminalDisplay {
Sizef mPadding;
Vector2f mPosition;
Sizef mSize;
std::atomic<bool> mDirty{ true };
std::atomic<bool> mDrawing{ false };
std::vector<bool> mDirtyLines;
bool mDirty{ true };
bool mDirtyCursor{ true };
bool mDrawing{ false };
Vector2i mCursor;
TerminalGlyph mCursorGlyph;
bool mUseColorEmoji{ true };
bool mPasteNewlineFix{ true };
bool mFocus{ true };
bool mUseFrameBuffer{ true };
Clock mClock;
Clock mLastDoubleClick;
int mColumns{ 0 };
int mRows{ 0 };
FrameBuffer* mFrameBuffer{ nullptr };
std::string mProgram;
std::vector<std::string> mArgs;
std::string mWorkingDir;
TerminalDisplay( EE::Window::Window* window, Font* font, const Float& fontSize,
const Sizef& pixelsSize );
const Sizef& pixelsSize, const bool& useFrameBuffer );
void draw( const Vector2f& pos );
void drawGrid( const Vector2f& pos );
Vector2i positionToGrid( const Vector2i& pos );
void onSizeChange();
@@ -262,6 +278,12 @@ class TerminalDisplay : public ITerminalDisplay {
virtual void onProcessExit( int exitCode );
void sendEvent( const TerminalDisplay::Event& event );
Sizei getFrameBufferSize();
void createFrameBuffer();
void drawFrameBuffer();
};
#endif // ETERMINALDISPLAY_HPP