mirror of
https://github.com/SpartanJ/eepp.git
synced 2026-10-01 18:50:16 +03:00
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:
@@ -137,6 +137,8 @@ EE_MAIN_FUNC int main( int, char*[] ) {
|
||||
win->runMainLoop( &mainLoop );
|
||||
}
|
||||
|
||||
terminal.reset();
|
||||
|
||||
Engine::destroySingleton();
|
||||
|
||||
MemoryManager::showResults();
|
||||
|
||||
@@ -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 );
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user