Skip to content

Commit e97ebd6

Browse files
committed
fix(armory): match the client's real composite icon slot, drop guessing
RE'd the client's own composite-model loader (CICompositePlayer, used by the character-creation dress-up doll - the actual in-game analog of this feature): it walks every populated file_ids slot to gather ALL of them as required texture layers for the 3D worn model. There is no per-slot priority and no slot that means "the icon" - slot 0xa was an unverified assumption, not real client behavior, and trying arbitrary other slots as fallbacks risks showing the wrong image (a normal map, a specular mask, etc.) rather than the correct one. Resources::GetItemImage now only ever tries the given gender's model slot (file_ids[0] male, file_ids[5] female), falling back to that same file's own stream 0 (already handled by DecodeItemToArgb) and nothing further. A handful of items with no icon data on that slot (e.g. Elite Fur-Lined Boots) will show the placeholder again rather than a guessed-at image from an unrelated slot.
1 parent f19f023 commit e97ebd6

2 files changed

Lines changed: 20 additions & 46 deletions

File tree

GWToolboxdll/Modules/GwDatModule.cpp

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -145,12 +145,11 @@ namespace {
145145
};
146146

147147
// Item icon to A8R8G8B8: stream 1 base, stream 0xc dye mask; masked pixels use the averaged dye matrices (`dyes` = up to 4 GW::DyeColor, one per byte).
148-
// Some items (composite armor pieces whose gendered model has no icon substream at all, or plain
149-
// weapon skins that were simply never given one) have no stream 1. Fall back to the file's own
150-
// stream 0: either a standalone ATEX/ATTX/DDS icon file some composite slots point at directly,
151-
// or - for a model (ffna) file - its own inline surface texture, which is usually small enough to
152-
// stand in as an icon and is strictly better than showing nothing. Either way it's undyeable:
153-
// there's no separate stream 0xc mask to blend for it.
148+
// Some items (a composite piece's gendered model, or a plain weapon skin) were simply never given
149+
// a stream 1 icon substream. Fall back to that same file's stream 0: for a model (ffna) file,
150+
// that's its own inline surface texture, which is usually small enough to stand in as an icon and
151+
// is strictly better than showing nothing. Undyeable either way: there's no separate stream 0xc
152+
// mask to blend for it. This is the only fallback - if it also fails, there is no icon.
154153
bool DecodeItemToArgb(uint32_t file_id, uint32_t dyes, std::vector<uint32_t>& base, Vec2i& dims)
155154
{
156155
if (!file_id)

GWToolboxdll/Modules/Resources.cpp

Lines changed: 15 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -1366,49 +1366,24 @@ IDirect3DTexture9** Resources::GetItemImage(uint32_t model_file_id, uint32_t int
13661366
if (!model_file_id)
13671367
return nullptr;
13681368

1369-
// Composite items (armor/runes) can carry their icon in any of the 11 file_ids slots - most
1370-
// commonly slot 0xa (an explicit "icon override") or the given gender's model slot, but a few
1371-
// items (some elite armor pieces observed) have no icon substream on either gendered model file
1372-
// at all, and instead point straight at a standalone icon file in some other slot. Try every
1373-
// populated slot, favouring the usual ones, rather than giving up after just one or two.
1374-
std::vector<uint32_t> candidates;
1369+
// Composite items (armor/runes) point at the given gender's model slot (file_ids[0] male,
1370+
// file_ids[5] female) - confirmed against the client's own composite-model loader
1371+
// (CICompositePlayer, used by the character-creation dress-up doll): it walks every populated
1372+
// file_ids slot to gather ALL of them as required texture layers for the 3D worn model, with no
1373+
// per-slot priority or "alternate icon" concept - there is no slot that means "the icon". So
1374+
// there's nothing to gain by trying other slots as fallbacks; if the gendered slot has no icon,
1375+
// there isn't one. LoadItemImage/DecodeItemToArgb already covers "check the same file another
1376+
// way" by falling back to that file's own stream 0 when stream 1 (the usual icon substream)
1377+
// doesn't exist. Beyond that, give up - don't guess at unrelated slots.
1378+
uint32_t candidate = model_file_id;
13751379
if (interaction & 4) {
13761380
const auto model_file_info = GW::Items::GetCompositeModelInfo(model_file_id);
1377-
if (model_file_info) {
1378-
const auto try_add = [&](size_t idx) {
1379-
if (model_file_info->file_ids[idx])
1380-
candidates.push_back(model_file_info->file_ids[idx]);
1381-
};
1382-
try_add(0xa);
1383-
try_add(is_female ? 5 : 0);
1384-
try_add(is_female ? 0 : 5);
1385-
for (size_t i = 0; i < 11; ++i)
1386-
try_add(i);
1387-
}
1388-
}
1389-
if (candidates.empty())
1390-
candidates.push_back(model_file_id);
1391-
1392-
// Kick off a load for every candidate (a no-op once cached) and use the first one that has
1393-
// actually produced a texture. If none have, failed_out is only set once every candidate has
1394-
// actually finished decoding and failed - while any are still pending, the caller should treat
1395-
// this as "no icon yet" rather than a permanent failure.
1396-
IDirect3DTexture9** first_result = nullptr;
1397-
bool any_pending = false;
1398-
for (const uint32_t candidate : candidates) {
1399-
bool candidate_failed = false;
1400-
// The UI icon is normally stream 1 of the model file; recolour its stream 0xc mask for the dyes.
1401-
IDirect3DTexture9** result = GwDatModule::LoadItemImage(candidate, dyes, &candidate_failed);
1402-
if (*result)
1403-
return result;
1404-
if (!candidate_failed)
1405-
any_pending = true;
1406-
if (!first_result)
1407-
first_result = result;
1381+
const uint32_t gendered = model_file_info ? model_file_info->file_ids[is_female ? 5 : 0] : 0;
1382+
if (gendered)
1383+
candidate = gendered;
14081384
}
1409-
if (failed_out)
1410-
*failed_out = !any_pending;
1411-
return first_result;
1385+
1386+
return GwDatModule::LoadItemImage(candidate, dyes, failed_out);
14121387
}
14131388

14141389
IDirect3DTexture9** Resources::GetItemImage(GW::Item* item)

0 commit comments

Comments
 (0)