Skip to content

Commit 91994a5

Browse files
GWToolbox Botclaude
andcommitted
perf(account-inventory): fetch item icons lazily during draw
Applying loaded files (and adding live items) called Resources::GetItemImage for every item, each queuing a DAT icon decode onto the shared worker pool - tens of thousands of decodes for a full set of account files, the bulk of them for items that are never displayed (window closed, detailed view, filtered, or scrolled off). Fetch the icon in Draw instead, only for the item actually being rendered. The pointer GetItemImage returns is stable and cached on the Item on first draw, so it runs once per shown item rather than once per stored item on load. Store the item's dyes at add time so the on-demand fetch still gets the tinted icon. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com> (cherry picked from commit 34f0211)
1 parent 9608ec7 commit 91994a5

1 file changed

Lines changed: 14 additions & 8 deletions

File tree

GWToolboxdll/Windows/AccountInventoryWindow.cpp

Lines changed: 14 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -248,7 +248,8 @@ namespace {
248248
// display (no decoded text is persisted). .encoded() is what we save.
249249
GuiUtils::EncString description{};
250250
uint32_t item_id{}; // live-session only; 0 for items loaded from disk
251-
IDirect3DTexture9** texture = nullptr; // cache (GetItemImage), not serialized
251+
uint32_t dyes{}; // packed dye colours; 0 (undyed) for disk items
252+
IDirect3DTexture9** texture = nullptr; // GetItemImage cache, fetched lazily on first draw; not serialized
252253
};
253254

254255
// Free-slot occupancy, folded out of the old CharacterFreeSlots into the nodes.
@@ -1102,10 +1103,7 @@ namespace {
11021103
item.equipped = j.equipped.value_or(0);
11031104
const std::wstring enc = DecodeDescription(j.description);
11041105
item.description.reset(enc.c_str()); // EncString decodes lazily for display
1105-
GW::Item gw_item;
1106-
gw_item.model_file_id = item.model_file_id;
1107-
gw_item.interaction = item.interaction;
1108-
item.texture = Resources::GetItemImage(&gw_item);
1106+
// texture fetched on demand in Draw, so loading doesn't decode an icon per stored item
11091107
}
11101108

11111109
void ApplyFreeSlots(FreeSlotInfo& fs, const FreeSlotsJson& j)
@@ -1426,7 +1424,9 @@ namespace {
14261424
it.quantity = item->quantity;
14271425
it.equipped = item->equipped;
14281426
it.item_id = item->item_id;
1429-
it.texture = Resources::GetItemImage(item);
1427+
// stash dyes so Draw fetches the tinted icon lazily (see ApplyItemJson); no decode here
1428+
it.dyes = static_cast<uint32_t>(item->dye.dye1) | (static_cast<uint32_t>(item->dye.dye2) << 8)
1429+
| (static_cast<uint32_t>(item->dye.dye3) << 16) | (static_cast<uint32_t>(item->dye.dye4) << 24);
14301430
it.description.reset(GetItemEncDescription(item).c_str()); // EncString decodes for display
14311431

14321432
ItemLoc loc;
@@ -2211,8 +2211,14 @@ void AccountInventoryWindow::Draw(IDirect3DDevice9*)
22112211
}
22122212
else {
22132213
const auto pos = ImGui::GetCursorPos();
2214-
if (i_front->item->texture && *(i_front->item->texture))
2215-
clicked = ImGui::IconButton(nullptr, *i_front->item->texture, button_size, ImGuiButtonFlags_None, button_size);
2214+
const auto it = i_front->item;
2215+
// fetch+cache the icon only when drawn; stable pointer, so once per shown item
2216+
if (!it->texture) {
2217+
const auto player = GW::Agents::GetControlledCharacter();
2218+
it->texture = Resources::GetItemImage(it->model_file_id, it->interaction, it->dyes, player && player->GetIsFemale());
2219+
}
2220+
if (it->texture && *(it->texture))
2221+
clicked = ImGui::IconButton(nullptr, *(it->texture), button_size, ImGuiButtonFlags_None, button_size);
22162222
else
22172223
clicked = ImGui::Button("???", button_size);
22182224

0 commit comments

Comments
 (0)