From 67a7f39d9a7837695340cf8ad35fbbfa7e905a02 Mon Sep 17 00:00:00 2001 From: cam900 Date: Fri, 27 May 2022 13:38:45 +0900 Subject: [PATCH 1/6] Allow more than 64 columns in Dear ImGUI (patched) Improves Channel window displays, with System info. --- extern/imgui_patched/imgui_internal.h | 97 ++++++++++++++++++++------- extern/imgui_patched/imgui_tables.cpp | 72 ++++++++++++-------- src/engine/engine.cpp | 7 +- src/gui/channels.cpp | 18 +++-- 4 files changed, 135 insertions(+), 59 deletions(-) diff --git a/extern/imgui_patched/imgui_internal.h b/extern/imgui_patched/imgui_internal.h index 070d59f0c..3ec72742e 100644 --- a/extern/imgui_patched/imgui_internal.h +++ b/extern/imgui_patched/imgui_internal.h @@ -559,14 +559,44 @@ template struct ImBitArray { ImU32 Storage[(BITCOUNT + 31) >> 5]; - ImBitArray() { ClearAllBits(); } - void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); } - void SetAllBits() { memset(Storage, 255, sizeof(Storage)); } - bool TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } - void SetBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); } - void ClearBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArrayClearBit(Storage, n); } - void SetBitRange(int n, int n2) { n += OFFSET; n2 += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT && n2 > n && n2 <= BITCOUNT); ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2) - bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } + ImBitArray() { ClearAllBits(); } + void ClearAllBits() { memset(Storage, 0, sizeof(Storage)); } + void SetAllBits() { memset(Storage, 255, sizeof(Storage)); } + bool TestBit(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } + void SetBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); } + void ClearBit(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArrayClearBit(Storage, n); } + void SetBitRange(int n, int n2) { n += OFFSET; n2 += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT && n2 > n && n2 <= BITCOUNT); ImBitArraySetBitRange(Storage, n, n2); } // Works on range [n..n2) + bool operator[](int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } + ImBitArray& operator|=(int n) { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); ImBitArraySetBit(Storage, n); return *this; } + bool operator&(int n) const { n += OFFSET; IM_ASSERT(n >= 0 && n < BITCOUNT); return ImBitArrayTestBit(Storage, n); } + bool operator==(ImBitArray const &a) const + { + for (int i = 0; i < ((BITCOUNT + 31) >> 5); ++i) + if (Storage[i] != a.Storage[i]) + return false; + return true; + } + bool operator!=(ImBitArray const &a) const + { + for (int i = 0; i < ((BITCOUNT + 31) >> 5); ++i) + if (Storage[i] == a.Storage[i]) + return false; + return true; + } + template bool operator==(ImBitArray const &a) const + { + for (int i = 0; i < ImMin((DSTBITCOUNT + 31) >> 5, (BITCOUNT + 31) >> 5); ++i) + if (Storage[i] != a.Storage[i]) + return false; + return true; + } + template bool operator!=(ImBitArray const &a) const + { + for (int i = 0; i < ImMin((DSTBITCOUNT + 31) >> 5, (BITCOUNT + 31) >> 5); ++i) + if (Storage[i] == a.Storage[i]) + return false; + return true; + } }; // Helper: ImBitVector @@ -574,11 +604,33 @@ struct ImBitArray struct IMGUI_API ImBitVector { ImVector Storage; - void Create(int sz) { Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } - void Clear() { Storage.clear(); } - bool TestBit(int n) const { IM_ASSERT(n < (Storage.Size << 5)); return ImBitArrayTestBit(Storage.Data, n); } - void SetBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArraySetBit(Storage.Data, n); } - void ClearBit(int n) { IM_ASSERT(n < (Storage.Size << 5)); ImBitArrayClearBit(Storage.Data, n); } + int BitCount = 0; + ImBitVector(int sz = 0) { if (sz > 0) { Create(sz); } } + void Create(int sz) { BitCount = sz; Storage.resize((sz + 31) >> 5); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } + void Clear() { Storage.clear(); } + void ClearAllBits() { IM_ASSERT(Storage.Size > 0); memset(Storage.Data, 0, (size_t)Storage.Size * sizeof(Storage.Data[0])); } + void SetAllBits() { IM_ASSERT(Storage.Size > 0); memset(Storage.Data, 255, (size_t)Storage.Size * sizeof(Storage.Data[0])); } + bool TestBit(int n) const { IM_ASSERT(n >= 0 && n < BitCount); return ImBitArrayTestBit(Storage.Data, n); } + void SetBit(int n) { IM_ASSERT(n >= 0 && n < BitCount); ImBitArraySetBit(Storage.Data, n); } + void SetBitRange(int n, int n2) { IM_ASSERT(n >= 0 && n < BitCount && n2 > n && n2 <= BitCount); ImBitArraySetBitRange(Storage.Data, n, n2); } // Works on range [n..n2) + void ClearBit(int n) { IM_ASSERT(n >= 0 && n < BitCount); ImBitArrayClearBit(Storage.Data, n); } + bool operator[](int n) const { IM_ASSERT(n >= 0 && n < BitCount); return ImBitArrayTestBit(Storage.Data, n); } + ImBitVector& operator|=(int n) { IM_ASSERT(n >= 0 && n < BitCount); ImBitArraySetBit(Storage.Data, n); return *this; } + bool operator&(int n) const { IM_ASSERT(n >= 0 && n < BitCount); return ImBitArrayTestBit(Storage.Data, n); } + bool operator==(ImBitVector const &a) const + { + for (int i = 0; i < ImMin((a.BitCount + 31) >> 5, (BitCount + 31) >> 5); ++i) + if (Storage[i] != a.Storage[i]) + return false; + return true; + } + bool operator!=(ImBitVector const &a) const + { + for (int i = 0; i < ImMin((a.BitCount + 31) >> 5, (BitCount + 31) >> 5); ++i) + if (Storage[i] == a.Storage[i]) + return false; + return true; + } }; // Helper: ImSpan<> @@ -2447,13 +2499,12 @@ struct IMGUI_API ImGuiTabBar // [SECTION] Table support //----------------------------------------------------------------------------- -#define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color. -#define IMGUI_TABLE_MAX_COLUMNS 64 // sizeof(ImU64) * 8. This is solely because we frequently encode columns set in a ImU64. -#define IMGUI_TABLE_MAX_DRAW_CHANNELS (4 + 64 * 2) // See TableSetupDrawChannels() +#define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color. +#define IMGUI_TABLE_DRAW_CHANNELS(c) (4 + (c) * 2) // See TableSetupDrawChannels() -// Our current column maximum is 64 but we may raise that in the future. -typedef ImS8 ImGuiTableColumnIdx; -typedef ImU8 ImGuiTableDrawChannelIdx; +// Our current column maximum is IMGUI_TABLE_MAX_COLUMNS but we may raise that in the future. +typedef ImS32 ImGuiTableColumnIdx; +typedef ImU32 ImGuiTableDrawChannelIdx; // [Internal] sizeof() ~ 104 // We use the terminology "Enabled" to refer to a column that is not Hidden by user/api. @@ -2543,10 +2594,10 @@ struct IMGUI_API ImGuiTable ImSpan Columns; // Point within RawData[] ImSpan DisplayOrderToIndex; // Point within RawData[]. Store display order of columns (when not reordered, the values are 0...Count-1) ImSpan RowCellData; // Point within RawData[]. Store cells background requests for current row. - ImU64 EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map - ImU64 EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data - ImU64 VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect) - ImU64 RequestOutputMaskByIndex; // Column Index -> IsVisible || AutoFit (== expect user to submit items) + ImBitVector EnabledMaskByDisplayOrder; // Column DisplayOrder -> IsEnabled map + ImBitVector EnabledMaskByIndex; // Column Index -> IsEnabled map (== not hidden by user/api) in a format adequate for iterating column without touching cold data + ImBitVector VisibleMaskByIndex; // Column Index -> IsVisibleX|IsVisibleY map (== not hidden by user/api && not hidden by scrolling/cliprect) + ImBitVector RequestOutputMaskByIndex; // Column Index -> IsVisible || AutoFit (== expect user to submit items) ImGuiTableFlags SettingsLoadedFlags; // Which data were loaded from the .ini file (e.g. when order is not altered we won't save order) int SettingsOffset; // Offset in g.SettingsTables int LastFrameActive; diff --git a/extern/imgui_patched/imgui_tables.cpp b/extern/imgui_patched/imgui_tables.cpp index bf04f44b5..9b67811c7 100644 --- a/extern/imgui_patched/imgui_tables.cpp +++ b/extern/imgui_patched/imgui_tables.cpp @@ -315,7 +315,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG return false; // Sanity checks - IM_ASSERT(columns_count > 0 && columns_count <= IMGUI_TABLE_MAX_COLUMNS && "Only 1..64 columns allowed!"); + IM_ASSERT(columns_count > 0 && "Only 1..64 columns allowed!"); if (flags & ImGuiTableFlags_ScrollX) IM_ASSERT(inner_width >= 0.0f); @@ -358,6 +358,16 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG table->LastFrameActive = g.FrameCount; table->OuterWindow = table->InnerWindow = outer_window; table->ColumnsCount = columns_count; + if (table->EnabledMaskByDisplayOrder.BitCount < columns_count || + table->EnabledMaskByIndex.BitCount < columns_count || + table->VisibleMaskByIndex.BitCount < columns_count || + table->RequestOutputMaskByIndex.BitCount < columns_count) + { + table->EnabledMaskByDisplayOrder.Create(columns_count); + table->EnabledMaskByIndex.Create(columns_count); + table->VisibleMaskByIndex.Create(columns_count); + table->RequestOutputMaskByIndex.Create(columns_count); + } table->IsLayoutLocked = false; table->InnerWidth = inner_width; temp_data->UserOuterSize = outer_size; @@ -721,8 +731,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_); table->IsDefaultDisplayOrder = true; table->ColumnsEnabledCount = 0; - table->EnabledMaskByIndex = 0x00; - table->EnabledMaskByDisplayOrder = 0x00; + table->EnabledMaskByIndex.ClearAllBits(); + table->EnabledMaskByDisplayOrder.ClearAllBits(); table->LeftMostEnabledColumn = -1; table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE @@ -787,8 +797,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) else table->LeftMostEnabledColumn = (ImGuiTableColumnIdx)column_n; column->IndexWithinEnabledSet = table->ColumnsEnabledCount++; - table->EnabledMaskByIndex |= (ImU64)1 << column_n; - table->EnabledMaskByDisplayOrder |= (ImU64)1 << column->DisplayOrder; + table->EnabledMaskByIndex |= column_n; + table->EnabledMaskByDisplayOrder |= column->DisplayOrder; prev_visible_column_idx = column_n; IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder); @@ -836,7 +846,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { - if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n))) + if (!(table->EnabledMaskByIndex & column_n)) continue; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -852,7 +862,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!) if (column->AutoFitQueue != 0x00) column->WidthRequest = width_auto; - else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n))) + else if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable && (table->RequestOutputMaskByIndex & column_n)) column->WidthRequest = width_auto; // FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets @@ -899,7 +909,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { - if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n))) + if (!(table->EnabledMaskByIndex & column_n)) continue; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -926,7 +936,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths)) for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) { - if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) + if (!(table->EnabledMaskByDisplayOrder & order_n)) continue; ImGuiTableColumn* column = &table->Columns[table->DisplayOrderToIndex[order_n]]; if (!(column->Flags & ImGuiTableColumnFlags_WidthStretch)) @@ -949,8 +959,8 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1; ImRect host_clip_rect = table->InnerClipRect; //host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2; - table->VisibleMaskByIndex = 0x00; - table->RequestOutputMaskByIndex = 0x00; + table->VisibleMaskByIndex.ClearAllBits(); + table->RequestOutputMaskByIndex.ClearAllBits(); for (int order_n = 0; order_n < table->ColumnsCount; order_n++) { const int column_n = table->DisplayOrderToIndex[order_n]; @@ -967,7 +977,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) // Clear status flags column->Flags &= ~ImGuiTableColumnFlags_StatusMask_; - if ((table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)) == 0) + if ((table->EnabledMaskByDisplayOrder & order_n) == 0) { // Hidden column: clear a few fields and we are done with it for the remainder of the function. // We set a zero-width clip rect but set Min.y/Max.y properly to not interfere with the clipper. @@ -1020,12 +1030,12 @@ void ImGui::TableUpdateLayout(ImGuiTable* table) column->IsVisibleY = true; // (column->ClipRect.Max.y > column->ClipRect.Min.y); const bool is_visible = column->IsVisibleX; //&& column->IsVisibleY; if (is_visible) - table->VisibleMaskByIndex |= ((ImU64)1 << column_n); + table->VisibleMaskByIndex |= column_n; // Mark column as requesting output from user. Note that fixed + non-resizable sets are auto-fitting at all times and therefore always request output. column->IsRequestOutput = is_visible || column->AutoFitQueue != 0 || column->CannotSkipItemsQueue != 0; if (column->IsRequestOutput) - table->RequestOutputMaskByIndex |= ((ImU64)1 << column_n); + table->RequestOutputMaskByIndex |= column_n; // Mark column as SkipItems (ignoring all items/layout) column->IsSkipItems = !column->IsEnabled || table->HostSkipItems; @@ -1153,7 +1163,7 @@ void ImGui::TableUpdateBorders(ImGuiTable* table) for (int order_n = 0; order_n < table->ColumnsCount; order_n++) { - if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) + if (!(table->EnabledMaskByDisplayOrder & order_n)) continue; const int column_n = table->DisplayOrderToIndex[order_n]; @@ -1289,7 +1299,7 @@ void ImGui::EndTable() float auto_fit_width_for_stretched = 0.0f; float auto_fit_width_for_stretched_min = 0.0f; for (int column_n = 0; column_n < table->ColumnsCount; column_n++) - if (table->EnabledMaskByIndex & ((ImU64)1 << column_n)) + if (table->EnabledMaskByIndex & column_n) { ImGuiTableColumn* column = &table->Columns[column_n]; float column_width_request = ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !(column->Flags & ImGuiTableColumnFlags_NoResize)) ? column->WidthRequest : TableGetColumnWidthAuto(table, column); @@ -1480,7 +1490,7 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows) ImGuiTable* table = g.CurrentTable; IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!"); IM_ASSERT(table->IsLayoutLocked == false && "Need to call TableSetupColumn() before first row!"); - IM_ASSERT(columns >= 0 && columns < IMGUI_TABLE_MAX_COLUMNS); + IM_ASSERT(columns >= 0); IM_ASSERT(rows >= 0 && rows < 128); // Arbitrary limit table->FreezeColumnsRequest = (table->Flags & ImGuiTableFlags_ScrollX) ? (ImGuiTableColumnIdx)ImMin(columns, table->ColumnsCount) : 0; @@ -1635,7 +1645,7 @@ void ImGui::TableSetBgColor(ImGuiTableBgTarget target, ImU32 color, int column_n return; if (column_n == -1) column_n = table->CurrentColumn; - if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0) + if ((table->VisibleMaskByIndex & column_n) == 0) return; if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n) table->RowCellDataCurrent++; @@ -1910,7 +1920,7 @@ bool ImGui::TableSetColumnIndex(int column_n) // Return whether the column is visible. User may choose to skip submitting items based on this return value, // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. - return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; + return (table->RequestOutputMaskByIndex & column_n) != 0; } // [Public] Append into the next column, wrap and create a new row when already on last column @@ -1936,7 +1946,7 @@ bool ImGui::TableNextColumn() // Return whether the column is visible. User may choose to skip submitting items based on this return value, // however they shouldn't skip submitting for columns that may have the tallest contribution to row height. int column_n = table->CurrentColumn; - return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0; + return (table->RequestOutputMaskByIndex & column_n) != 0; } @@ -2349,17 +2359,23 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) { ImRect ClipRect; int ChannelsCount; - ImBitArray ChannelsMask; + ImBitVector ChannelsMask; - MergeGroup() { ChannelsCount = 0; } + MergeGroup(int sz) : ChannelsMask(sz) { ChannelsCount = 0; } }; int merge_group_mask = 0x00; - MergeGroup merge_groups[4]; + int merge_group_bitlen = IMGUI_TABLE_DRAW_CHANNELS(table->ColumnsCount); + MergeGroup merge_groups[4]{ + merge_group_bitlen, + merge_group_bitlen, + merge_group_bitlen, + merge_group_bitlen + }; // 1. Scan channels and take note of those which can be merged for (int column_n = 0; column_n < table->ColumnsCount; column_n++) { - if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0) + if ((table->VisibleMaskByIndex & column_n) == 0) continue; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -2391,7 +2407,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) } const int merge_group_n = (has_freeze_h && column_n < table->FreezeColumnsCount ? 0 : 1) + (has_freeze_v && merge_group_sub_n == 0 ? 0 : 2); - IM_ASSERT(channel_no < IMGUI_TABLE_MAX_DRAW_CHANNELS); + IM_ASSERT(channel_no < merge_group_bitlen); MergeGroup* merge_group = &merge_groups[merge_group_n]; if (merge_group->ChannelsCount == 0) merge_group->ClipRect = ImRect(+FLT_MAX, +FLT_MAX, -FLT_MAX, -FLT_MAX); @@ -2431,7 +2447,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) const int LEADING_DRAW_CHANNELS = 2; g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data; - ImBitArray remaining_mask; // We need 132-bit of storage + ImBitVector remaining_mask(merge_group_bitlen); // We need 132-bit of storage remaining_mask.SetBitRange(LEADING_DRAW_CHANNELS, splitter->_Count); remaining_mask.ClearBit(table->Bg2DrawChannelUnfrozen); IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN); @@ -2466,7 +2482,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table) GetOverlayDrawList()->AddLine(merge_group->ClipRect.Max, merge_clip_rect.Max, IM_COL32(255, 100, 0, 200)); #endif remaining_count -= merge_group->ChannelsCount; - for (int n = 0; n < IM_ARRAYSIZE(remaining_mask.Storage); n++) + for (int n = 0; n < remaining_mask.Storage.size(); n++) remaining_mask.Storage[n] &= ~merge_group->ChannelsMask.Storage[n]; for (int n = 0; n < splitter->_Count && merge_channels_count != 0; n++) { @@ -2523,7 +2539,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table) { for (int order_n = 0; order_n < table->ColumnsCount; order_n++) { - if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n))) + if (!(table->EnabledMaskByDisplayOrder & order_n)) continue; const int column_n = table->DisplayOrderToIndex[order_n]; diff --git a/src/engine/engine.cpp b/src/engine/engine.cpp index 5a17cd3c8..dd45dbd53 100644 --- a/src/engine/engine.cpp +++ b/src/engine/engine.cpp @@ -696,7 +696,7 @@ void DivEngine::initSongWithDesc(const int* description) { song.systemFlags[index]=description[i+3]; index++; chanCount+=getChannelCount(song.system[index]); - if (chanCount>=63) break; + if (chanCount>=DIV_MAX_CHANS) break; if (index>=32) break; } song.systemLen=index; @@ -886,9 +886,8 @@ bool DivEngine::addSystem(DivSystem which) { lastError="max number of systems is 32"; return false; } - // this was DIV_MAX_CHANS but I am setting it to 63 for now due to an ImGui limitation - if (chans+getChannelCount(which)>63) { - lastError="max number of total channels is 63"; + if (chans+getChannelCount(which)>DIV_MAX_CHANS) { + lastError=fmt::sprintf("max number of total channels is %d",DIV_MAX_CHANS); return false; } quitDispatch(); diff --git a/src/gui/channels.cpp b/src/gui/channels.cpp index 846fca971..65bb1a8fe 100644 --- a/src/gui/channels.cpp +++ b/src/gui/channels.cpp @@ -30,14 +30,24 @@ void FurnaceGUI::drawChannels() { } if (!channelsOpen) return; if (ImGui::Begin("Channels",&channelsOpen,globalWinFlags)) { - if (ImGui::BeginTable("ChannelList",3)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0); - ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthStretch,0.0); - ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthFixed,48.0f*dpiScale); + if (ImGui::BeginTable("ChannelList",4)) { + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0); + ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,48.0f*dpiScale); + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::Text("System"); + ImGui::TableNextColumn(); + ImGui::Text("Visible"); + ImGui::TableNextColumn(); + ImGui::Text("Name"); for (int i=0; igetTotalChannelCount(); i++) { ImGui::PushID(i); ImGui::TableNextRow(); ImGui::TableNextColumn(); + ImGui::Text("%s #%d",e->getSystemName(e->sysOfChan[i]), e->dispatchChanOfChan[i]); + ImGui::TableNextColumn(); ImGui::Checkbox("##Visible",&e->curSubSong->chanShow[i]); ImGui::SameLine(); ImGui::BeginDisabled(i==0); From 061b312943bfcadc2c9098b8a78062bc44dac8f0 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Thu, 26 May 2022 23:46:42 -0500 Subject: [PATCH 2/6] SMS: volume table is now non-float --- extern/Nuked-PSG/ympsg.c | 8 ++++---- extern/Nuked-PSG/ympsg.h | 4 ++-- src/engine/platform/sms.cpp | 2 +- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/extern/Nuked-PSG/ympsg.c b/extern/Nuked-PSG/ympsg.c index 4aaeac2df..3df4f8e39 100644 --- a/extern/Nuked-PSG/ympsg.c +++ b/extern/Nuked-PSG/ympsg.c @@ -266,7 +266,7 @@ void YMPSG_Init(ympsg_t *chip, uint8_t real_sn) chip->noise_size = real_sn ? 16383 : 32767; for (i = 0; i < 17; i++) { - chip->vol_table[i]=real_sn?tipsg_vol[i]:ympsg_vol[i]; + chip->vol_table[i]=(real_sn?tipsg_vol[i]:ympsg_vol[i]) * 8192.0f; } for (i = 0; i < 16; i++) { @@ -315,15 +315,15 @@ void YMPSG_Clock(ympsg_t *chip) } } -float YMPSG_GetOutput(ympsg_t *chip) +int YMPSG_GetOutput(ympsg_t *chip) { - float sample = 0.f; + int sample = 0; uint32_t i; YMPSG_UpdateSample(chip); if (chip->test & 1) { sample += chip->vol_table[chip->volume_out[chip->test >> 1]]; - sample += chip->vol_table[16] * 3.f; + sample += chip->vol_table[16] * 3; } else if (!chip->mute) { diff --git a/extern/Nuked-PSG/ympsg.h b/extern/Nuked-PSG/ympsg.h index 2465f5c33..c00b3d720 100644 --- a/extern/Nuked-PSG/ympsg.h +++ b/extern/Nuked-PSG/ympsg.h @@ -59,7 +59,7 @@ typedef struct { ympsg_writebuf writebuf[YMPSG_WRITEBUF_SIZE]; // - float vol_table[17]; + short vol_table[17]; uint8_t mute; @@ -71,7 +71,7 @@ uint16_t YMPSG_Read(ympsg_t *chip); void YMPSG_Init(ympsg_t *chip, uint8_t real_sn); void YMPSG_SetIC(ympsg_t *chip, uint32_t ic); void YMPSG_Clock(ympsg_t *chip); -float YMPSG_GetOutput(ympsg_t *chip); +int YMPSG_GetOutput(ympsg_t *chip); void YMPSG_Test(ympsg_t *chip, uint16_t test); diff --git a/src/engine/platform/sms.cpp b/src/engine/platform/sms.cpp index 57e868bd4..7dd5c65d7 100644 --- a/src/engine/platform/sms.cpp +++ b/src/engine/platform/sms.cpp @@ -65,7 +65,7 @@ void DivPlatformSMS::acquire_nuked(short* bufL, short* bufR, size_t start, size_ YMPSG_Clock(&sn_nuked); YMPSG_Clock(&sn_nuked); YMPSG_Clock(&sn_nuked); - o=YMPSG_GetOutput(&sn_nuked)*8192.0; + o=YMPSG_GetOutput(&sn_nuked); if (o<-32768) o=-32768; if (o>32767) o=32767; bufL[h]=o; From 5d1785fb38995e4b7e1304912d4afbcc5a37d740 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 27 May 2022 00:19:10 -0500 Subject: [PATCH 3/6] GUI: add timing debug info --- src/gui/debugWindow.cpp | 8 ++++++++ src/gui/gui.cpp | 23 +++++++++++++++++++++++ src/gui/gui.h | 4 ++++ 3 files changed, 35 insertions(+) diff --git a/src/gui/debugWindow.cpp b/src/gui/debugWindow.cpp index 41f112719..7d6d057f1 100644 --- a/src/gui/debugWindow.cpp +++ b/src/gui/debugWindow.cpp @@ -20,6 +20,7 @@ #include "gui.h" #include "debug.h" #include "IconsFontAwesome4.h" +#include #include #include @@ -370,6 +371,13 @@ void FurnaceGUI::drawDebug() { } ImGui::TreePop(); } + if (ImGui::TreeNode("Performance")) { + double perfFreq=SDL_GetPerformanceFrequency()/1000000.0; + ImGui::Text("render: %.0fµs",(double)renderTimeDelta/perfFreq); + ImGui::Text("layout: %.0fµs",(double)layoutTimeDelta/perfFreq); + ImGui::Text("event: %.0fµs",(double)eventTimeDelta/perfFreq); + ImGui::TreePop(); + } if (ImGui::TreeNode("Settings")) { if (ImGui::Button("Sync")) syncSettings(); ImGui::SameLine(); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 2aaee3300..11383b9b8 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -17,6 +17,7 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ +#include #define _USE_MATH_DEFINES #include "gui.h" #include "util.h" @@ -2411,6 +2412,7 @@ bool FurnaceGUI::loop() { drawHalt=0; if (settings.powerSave) SDL_WaitEventTimeout(NULL,500); } + eventTimeBegin=SDL_GetPerformanceCounter(); while (SDL_PollEvent(&ev)) { WAKE_UP; ImGui_ImplSDL2_ProcessEvent(&ev); @@ -2720,6 +2722,10 @@ bool FurnaceGUI::loop() { midiQueue.pop(); midiLock.unlock(); } + + eventTimeEnd=SDL_GetPerformanceCounter(); + + layoutTimeBegin=SDL_GetPerformanceCounter(); ImGui_ImplSDLRenderer_NewFrame(); ImGui_ImplSDL2_NewFrame(sdlWin); @@ -3740,6 +3746,8 @@ bool FurnaceGUI::loop() { ImGui::EndPopup(); } + layoutTimeEnd=SDL_GetPerformanceCounter(); + // backup trigger if (modified) { if (backupTimer>0) { @@ -3778,10 +3786,16 @@ bool FurnaceGUI::loop() { uiColors[GUI_COLOR_BACKGROUND].z*255, uiColors[GUI_COLOR_BACKGROUND].w*255); SDL_RenderClear(sdlRend); + renderTimeBegin=SDL_GetPerformanceCounter(); ImGui::Render(); + renderTimeEnd=SDL_GetPerformanceCounter(); ImGui_ImplSDLRenderer_RenderDrawData(ImGui::GetDrawData()); SDL_RenderPresent(sdlRend); + layoutTimeDelta=layoutTimeEnd-layoutTimeBegin; + renderTimeDelta=renderTimeEnd-renderTimeBegin; + eventTimeDelta=eventTimeEnd-eventTimeBegin; + if (--soloTimeout<0) soloTimeout=0; wheelX=0; @@ -4283,6 +4297,15 @@ FurnaceGUI::FurnaceGUI(): bindSetPending(false), nextScroll(-1.0f), nextAddScroll(0.0f), + layoutTimeBegin(0), + layoutTimeEnd(0), + layoutTimeDelta(0), + renderTimeBegin(0), + renderTimeEnd(0), + renderTimeDelta(0), + eventTimeBegin(0), + eventTimeEnd(0), + eventTimeDelta(0), transposeAmount(0), randomizeMin(0), randomizeMax(255), diff --git a/src/gui/gui.h b/src/gui/gui.h index 7d5e62a71..90b4e283c 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1189,6 +1189,10 @@ class FurnaceGUI { float nextScroll, nextAddScroll; + int layoutTimeBegin, layoutTimeEnd, layoutTimeDelta; + int renderTimeBegin, renderTimeEnd, renderTimeDelta; + int eventTimeBegin, eventTimeEnd, eventTimeDelta; + ImVec2 patWindowPos, patWindowSize; // pattern view specific From 3651027d992acbfe04158f44c45a776c37a880fa Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 27 May 2022 00:29:29 -0500 Subject: [PATCH 4/6] a --- src/gui/gui.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 11383b9b8..6790dc104 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -17,7 +17,6 @@ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. */ -#include #define _USE_MATH_DEFINES #include "gui.h" #include "util.h" From 1540705b75c87f67b0728ad5610cf16f712e223d Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 27 May 2022 00:35:35 -0500 Subject: [PATCH 5/6] WaveSynth: fix it....... again. --- src/engine/waveSynth.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/engine/waveSynth.cpp b/src/engine/waveSynth.cpp index c61fc4242..e69031686 100644 --- a/src/engine/waveSynth.cpp +++ b/src/engine/waveSynth.cpp @@ -186,7 +186,7 @@ bool DivWaveSynth::tick(bool skipSubDiv) { break; case DIV_WS_PHASE_MOD: for (int i=0; i<=state.speed; i++) { - int mod=(wave2[pos]*(state.param2-stage)*width)/512; + int mod=(wave2[pos]*(state.param2-stage)*width)/(64*(height+1)); output[pos]=wave1[(pos+mod)%width]; if (++pos>=width) { pos=0; From e8af633f1084d0cb100572d8de872abf25180483 Mon Sep 17 00:00:00 2001 From: tildearrow Date: Fri, 27 May 2022 01:04:12 -0500 Subject: [PATCH 6/6] GUI: improve channel swapping --- src/gui/channels.cpp | 33 ++++++++++++++++++++++----------- src/gui/gui.cpp | 1 + src/gui/gui.h | 2 ++ 3 files changed, 25 insertions(+), 11 deletions(-) diff --git a/src/gui/channels.cpp b/src/gui/channels.cpp index 65bb1a8fe..80cec7a68 100644 --- a/src/gui/channels.cpp +++ b/src/gui/channels.cpp @@ -31,11 +31,11 @@ void FurnaceGUI::drawChannels() { if (!channelsOpen) return; if (ImGui::Begin("Channels",&channelsOpen,globalWinFlags)) { if (ImGui::BeginTable("ChannelList",4)) { - ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthStretch,0.0); + ImGui::TableSetupColumn("c0",ImGuiTableColumnFlags_WidthFixed,0.0); ImGui::TableSetupColumn("c1",ImGuiTableColumnFlags_WidthFixed,0.0); ImGui::TableSetupColumn("c2",ImGuiTableColumnFlags_WidthStretch,0.0); ImGui::TableSetupColumn("c3",ImGuiTableColumnFlags_WidthFixed,48.0f*dpiScale); - ImGui::TableNextRow(); + ImGui::TableNextRow(ImGuiTableRowFlags_Headers); ImGui::TableNextColumn(); ImGui::Text("System"); ImGui::TableNextColumn(); @@ -50,17 +50,28 @@ void FurnaceGUI::drawChannels() { ImGui::TableNextColumn(); ImGui::Checkbox("##Visible",&e->curSubSong->chanShow[i]); ImGui::SameLine(); - ImGui::BeginDisabled(i==0); - if (ImGui::Button(ICON_FA_CHEVRON_UP)) { - e->swapChannelsP(i,i-1); + if (ImGui::Button(ICON_FA_ARROWS)) { } - ImGui::EndDisabled(); - ImGui::SameLine(); - ImGui::BeginDisabled(i==(e->getTotalChannelCount()-1)); - if (ImGui::Button(ICON_FA_CHEVRON_DOWN)) { - e->swapChannelsP(i,i+1); + if (ImGui::BeginDragDropSource()) { + chanToMove=i; + ImGui::SetDragDropPayload("FUR_CHAN",NULL,0,ImGuiCond_Once); + ImGui::Text("(release to swap channels)"); + ImGui::EndDragDropSource(); + } else if (ImGui::IsItemHovered()) { + ImGui::SetTooltip("(drag to swap channels)"); + } + if (ImGui::BeginDragDropTarget()) { + const ImGuiPayload* dragItem=ImGui::AcceptDragDropPayload("FUR_CHAN"); + if (dragItem!=NULL) { + if (dragItem->IsDataType("FUR_CHAN")) { + if (chanToMove!=i && chanToMove>=0) { + e->swapChannelsP(chanToMove,i); + } + chanToMove=-1; + } + } + ImGui::EndDragDropTarget(); } - ImGui::EndDisabled(); ImGui::TableNextColumn(); ImGui::SetNextItemWidth(ImGui::GetContentRegionAvail().x); ImGui::InputTextWithHint("##ChanName",e->getChannelName(i),&e->curSubSong->chanName[i]); diff --git a/src/gui/gui.cpp b/src/gui/gui.cpp index 6790dc104..4c8a81e33 100644 --- a/src/gui/gui.cpp +++ b/src/gui/gui.cpp @@ -4305,6 +4305,7 @@ FurnaceGUI::FurnaceGUI(): eventTimeBegin(0), eventTimeEnd(0), eventTimeDelta(0), + chanToMove(-1), transposeAmount(0), randomizeMin(0), randomizeMax(255), diff --git a/src/gui/gui.h b/src/gui/gui.h index 90b4e283c..93f4835fe 100644 --- a/src/gui/gui.h +++ b/src/gui/gui.h @@ -1193,6 +1193,8 @@ class FurnaceGUI { int renderTimeBegin, renderTimeEnd, renderTimeDelta; int eventTimeBegin, eventTimeEnd, eventTimeDelta; + int chanToMove; + ImVec2 patWindowPos, patWindowSize; // pattern view specific