Skip to content

Commit

Permalink
Refactored imtui to use multiple windows when drawing to prevent it c…
Browse files Browse the repository at this point in the history
…orrupting the play area, and other issues
  • Loading branch information
katemonster33 committed Apr 25, 2024
1 parent 10efed6 commit 01255e2
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 131 deletions.
21 changes: 11 additions & 10 deletions src/cata_imgui.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ struct pairs {
std::array<RGBTuple, color_loader<RGBTuple>::COLOR_NAMES_COUNT> rgbPalette;
std::array<pairs, 100> colorpairs; //storage for pair'ed colored

ImTui::TScreen *imtui_screen = nullptr;
std::vector<std::pair<int, ImTui::mouse_event>> imtui_events;

cataimgui::client::client()
Expand All @@ -44,7 +43,7 @@ cataimgui::client::client()
IMGUI_CHECKVERSION();
ImGui::CreateContext();

imtui_screen = ImTui_ImplNcurses_Init();
ImTui_ImplNcurses_Init();
ImTui_ImplText_Init();

ImGui::GetIO().ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard;
Expand Down Expand Up @@ -73,7 +72,7 @@ void cataimgui::client::end_frame()
{
ImGui::Render();

ImTui_ImplText_RenderDrawData( ImGui::GetDrawData(), imtui_screen );
ImTui_ImplText_RenderDrawData( ImGui::GetDrawData() );
ImTui_ImplNcurses_DrawScreen();
}

Expand Down Expand Up @@ -449,13 +448,6 @@ class cataimgui::window_impl
window_adaptor->is_imgui = true;
window_adaptor->on_redraw( [this]( ui_adaptor & ) {
win_base->draw();
point catapos;
point catasize;
ImVec2 impos = ImGui::GetWindowPos();
ImVec2 imsize = ImGui::GetWindowSize();
imvec2_to_point( &impos, &catapos );
imvec2_to_point( &imsize, &catasize );
window_adaptor->position_absolute( catapos, catasize );
} );
window_adaptor->on_screen_resize( [this]( ui_adaptor & ) {
is_resized = true;
Expand Down Expand Up @@ -581,6 +573,15 @@ void cataimgui::window::draw()
if( p_impl->window_adaptor->is_on_top && !force_to_back ) {
ImGui::BringWindowToDisplayFront( ImGui::GetCurrentWindow() );
}
if( handled_resize ) {
point catapos;
point catasize;
ImVec2 impos = ImGui::GetWindowPos();
ImVec2 imsize = ImGui::GetWindowSize();
imvec2_to_point( &impos, &catapos );
imvec2_to_point( &imsize, &catasize );
p_impl->window_adaptor->position_absolute( catapos, catasize );
}
}
ImGui::End();
if( handled_resize ) {
Expand Down
177 changes: 80 additions & 97 deletions src/third-party/imtui/imtui-impl-ncurses.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,19 @@
#include <string>
#include <thread>

WINDOW* imtui_win = nullptr;
// SDL_Renderer data
struct ImTui_ImplNCurses_Data
{
std::vector<WINDOW*> imtui_wins;
ImTui_ImplNCurses_Data() { memset((void*)this, 0, sizeof(*this)); }
};

// Backend data stored in io.BackendRendererUserData to allow support for multiple Dear ImGui contexts
// It is STRONGLY preferred that you use docking branch with multi-viewports (== single Dear ImGui context + multiple windows) instead of multiple Dear ImGui contexts.
static ImTui_ImplNCurses_Data* ImTui_ImplNCurses_GetBackendData()
{
return ImGui::GetCurrentContext() ? (ImTui_ImplNCurses_Data*)ImGui::GetIO().BackendRendererUserData : nullptr;
}

namespace
{
Expand All @@ -60,17 +72,6 @@ struct VSync {
auto tNextCur_us = tNext_us + tStep_us;

while( tNow_us < tNextCur_us - 100 ) {
if( tNow_us + 0.5 * tStepActive_us < tNextCur_us ) {
int ch = wgetch( imtui_win );

if( ch != ERR ) {
ungetch( ch );
tNextCur_us = tNow_us;

return;
}
}

std::this_thread::sleep_for( std::chrono::microseconds(
std::min( ( uint64_t )( 0.9 * tStepActive_us ),
( uint64_t )( 0.9 * ( tNextCur_us - tNow_us ) )
Expand All @@ -93,12 +94,14 @@ struct VSync {
}

static VSync g_vsync;
static ImTui::TScreen *g_screen = nullptr;

ImTui::TScreen *ImTui_ImplNcurses_Init( float fps_active, float fps_idle )
void ImTui_ImplNcurses_Init( float fps_active, float fps_idle )
{
if( g_screen == nullptr ) {
g_screen = new ImTui::TScreen();
if( ImGui::GetCurrentContext()->IO.BackendPlatformUserData == nullptr ) {
ImGui::GetCurrentContext()->IO.BackendPlatformUserData = new ImTui::ImplImtui_Data();
}
if(ImGui::GetIO().BackendRendererUserData == nullptr) {
ImGui::GetIO().BackendRendererUserData = new ImTui_ImplNCurses_Data();
}

if( fps_idle < 0.0 ) {
Expand All @@ -107,7 +110,7 @@ ImTui::TScreen *ImTui_ImplNcurses_Init( float fps_active, float fps_idle )
fps_idle = std::min( fps_active, fps_idle );
g_vsync = VSync( fps_active, fps_idle );

imtui_win = newwin(LINES, COLS, 0, 0);
//imtui_win = newwin(LINES, COLS, 0, 0);
ImGui::GetIO().KeyMap[ImGuiKey_Tab] = 9;
ImGui::GetIO().KeyMap[ImGuiKey_LeftArrow] = 260;
ImGui::GetIO().KeyMap[ImGuiKey_RightArrow] = 261;
Expand Down Expand Up @@ -139,20 +142,18 @@ ImTui::TScreen *ImTui_ImplNcurses_Init( float fps_active, float fps_idle )

getmaxyx( stdscr, screenSizeY, screenSizeX );
ImGui::GetIO().DisplaySize = ImVec2( screenSizeX, screenSizeY );

return g_screen;
}

void ImTui_ImplNcurses_Shutdown()
{
// ref #11 : https://github.com/ggerganov/imtui/issues/11
printf( "\033[?1003l\n" ); // Disable mouse movement events, as l = low

if( g_screen ) {
delete g_screen;
ImTui_ImplNCurses_Data* data = ImTui_ImplNCurses_GetBackendData();
if( data ) {
delete data;
ImGui::GetIO().BackendRendererUserData = nullptr;
}

g_screen = nullptr;
}

bool ImTui_ImplNcurses_NewFrame( std::vector<std::pair<int, ImTui::mouse_event>> key_events )
Expand Down Expand Up @@ -284,23 +285,6 @@ static int nActiveFrames = 10;
static ImTui::TScreen screenPrev;
static std::array<std::pair<bool, int>, 256 * 256> colPairs;

bool is_in_bounds( int x, int y )
{
ImGuiContext *ctxt = ImGui::GetCurrentContext();
// skip the first window, since ImGui seems to always have a "dummy" window that takes up most of the screen
for( int index = 1; index < ctxt->Windows.size(); index++ ) {
ImGuiWindow *win = ctxt->Windows[index];
if(win->Collapsed || !win->Active) {
continue;
}
if( x >= win->Pos.x && x < ( win->Pos.x + win->Size.x ) &&
y >= win->Pos.y && y < ( win->Pos.y + win->Size.y ) ) {
return true;
}
}
return false;
}

void ImTui_ImplNcurses_UploadColorPair( short p, short f, short b )
{
uint16_t imtui_p = b * 256 + f;
Expand All @@ -315,73 +299,72 @@ void ImTui_ImplNcurses_SetAllocedPairCount( short p )

void ImTui_ImplNcurses_DrawScreen( bool active )
{
ImTui::ImplImtui_Data* bd = ImTui::ImTui_Impl_GetBackendData();
ImTui_ImplNCurses_Data* rd = ImTui_ImplNCurses_GetBackendData();
if( active ) {
nActiveFrames = 10;
}


std::vector<ImRect> window_bounds;
for( ImGuiWindow *win : ImGui::GetCurrentContext()->Windows ) {
window_bounds.push_back( win->OuterRectClipped );
}
int nx = g_screen->nx;
int ny = g_screen->ny;

bool compare = true;

if( screenPrev.nx != nx || screenPrev.ny != ny ) {
screenPrev.resize( nx, ny );
compare = false;
}

int ic = 0;
wmove(imtui_win, 0, 0);
for( int y = 0; y < ny; ++y ) {
bool wmove_needed = true;
constexpr int no_lastp = 0x7FFFFFFF;
int lastp = no_lastp;
for( int x = 0; x < nx; ++x ) {
if( !is_in_bounds( x, y ) ) {
wmove_needed = true;
continue;
}
const auto cell = g_screen->data[y * nx + x];
const uint16_t f = ( cell & 0x00FF0000 ) >> 16;
const uint16_t b = ( cell & 0xFF000000 ) >> 24;
const uint16_t p = b * 256 + f;

if( wmove_needed ) {
wmove( imtui_win, y, x );
}
if( lastp != ( int ) p ) {
if( colPairs[p].first == false ) {
init_pair( nColPairs, f, b );
colPairs[p].first = true;
colPairs[p].second = nColPairs;
++nColPairs;
}
wattron( imtui_win, COLOR_PAIR( colPairs[p].second ) );
lastp = p;
}

const uint16_t c = cell & 0x0000FFFF;
waddch( imtui_win, c );
ImTui::TScreen& g_screen = bd->Screen;
size_t index = 0;
for(; index < g_screen.windows.size(); index++) {
ImTui::TWindow& window = g_screen.windows[index];
if(rd->imtui_wins.size() <= index) {
rd->imtui_wins.push_back(newwin(window.maxy - window.y + 1, window.maxx - window.x + 1, window.y, window.x));
}
if( lastp != no_lastp ) {
wattroff( imtui_win, COLOR_PAIR( colPairs[lastp].second ) );
WINDOW* win = rd->imtui_wins[index];

if(win == nullptr) {
continue;
} else if(win->_begx != window.x || win->_begy != window.y || (win->_maxx + win->_begx) != window.maxx || (win->_maxy + win->_begy) != window.maxy) {
delwin(win);
rd->imtui_wins[index] = win = newwin(window.maxy - window.y + 1, window.maxx - window.x + 1, window.y, window.x);
}
int nx = g_screen.nx;
int ny = g_screen.ny;

for( int y = window.y; y <= window.maxy; ++y ) {
constexpr int no_lastp = 0x7FFFFFFF;
int lastp = no_lastp;
wmove(win, y - window.y, 0);
for( int x = window.x; x <= window.maxx; ++x ) {
const auto cell = g_screen.data[y * nx + x];
const uint16_t f = ( cell & 0x00FF0000 ) >> 16;
const uint16_t b = ( cell & 0xFF000000 ) >> 24;
const uint16_t p = b * 256 + f;

if( lastp != ( int ) p ) {
if( colPairs[p].first == false ) {
init_pair( nColPairs, f, b );
colPairs[p].first = true;
colPairs[p].second = nColPairs;
++nColPairs;
}
wattron( win, COLOR_PAIR( colPairs[p].second ) );
lastp = p;
}

if( compare ) {
memcpy( screenPrev.data + y * nx, g_screen->data + y * nx, nx * sizeof( ImTui::TCell ) );
const uint16_t c = cell & 0x0000FFFF;
waddch( win, c );
}
if( lastp != no_lastp ) {
wattroff( win, COLOR_PAIR( colPairs[lastp].second ) );
}
}

wnoutrefresh(win);
}
wrefresh(imtui_win);

if( !compare ) {
memcpy( screenPrev.data, g_screen->data, nx * ny * sizeof( ImTui::TCell ) );
if(index < rd->imtui_wins.size()) {
size_t lastIndex = index;
for(; index < rd->imtui_wins.size(); index++) {
WINDOW *lastWin = rd->imtui_wins.back();
if(lastWin != nullptr) {
delwin(lastWin);
}
}
rd->imtui_wins.erase(rd->imtui_wins.begin() + lastIndex, rd->imtui_wins.end());
}

//g_vsync.wait( nActiveFrames -- > 0 );

}

bool ImTui_ImplNcurses_ProcessEvent()
Expand Down
2 changes: 1 addition & 1 deletion src/third-party/imtui/imtui-impl-ncurses.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ struct mouse_event {

// fps_active - specify the redraw rate when the application is active
// fps_idle - specify the redraw rate when the application is not active
ImTui::TScreen *ImTui_ImplNcurses_Init( float fps_active = 60.0, float fps_idle = -1.0 );
void ImTui_ImplNcurses_Init( float fps_active = 60.0, float fps_idle = -1.0 );

void ImTui_ImplNcurses_Shutdown();

Expand Down
Loading

0 comments on commit 01255e2

Please sign in to comment.