From 93c17ecbeeddaa4438a2dea0f65e6f3e3cee163d Mon Sep 17 00:00:00 2001 From: Le Duy Thuc Date: Tue, 10 Nov 2026 15:01:10 +0700 Subject: [PATCH 1/5] Fix expanded inventory background for controller UI Controller inventory backgrounds are centered in the panel, so sprite coordinates differ from panel coordinates. Offset the copied frames accordingly, include their borders, and draw the belt frames. The game draws its own panel behind the controller inventory, so keep the expanded background transparent instead of filling it with stone, which covered the top menu. Center the equipment, grid and belt row in the panel. Co-Authored-By: Claude Opus 5.5 --- src/CoreLib/Image.cpp | 30 ++++++++++ src/CoreLib/Image.hpp | 2 + .../Modules/ModuleExpandedInventory.cpp | 59 +++++++++++++++---- 3 files changed, 78 insertions(+), 13 deletions(-) diff --git a/src/CoreLib/Image.cpp b/src/CoreLib/Image.cpp index 5087564..2794801 100644 --- a/src/CoreLib/Image.cpp +++ b/src/CoreLib/Image.cpp @@ -308,6 +308,13 @@ Point& Point::operator+=(const Point& r) return *this; } +Point& Point::operator-=(const Point& r) +{ + x -= r.x; + y -= r.y; + return *this; +} + Point& Point::operator/=(int downscale) { x /= downscale; @@ -626,6 +633,29 @@ void Bitmap::draw(Point destPoint, const Bitmap& src, Point srcPoint, Size size) } } +void Bitmap::drawBlended(Point destPoint, const Bitmap& src, Point srcPoint, Size size) +{ + for (int y = 0; y < size.height; ++y) { + for (int x = 0; x < size.width; ++x) { + auto* destPixel = getPixel(destPoint + Point{ x, y }); + const auto* srcPixel = src.getPixel(srcPoint + Point{ x, y }); + if (!destPixel || !srcPixel) + continue; + + if (destPixel[3] == 0) { + memcpy(destPixel, srcPixel, 4); + continue; + } + + const int alpha = srcPixel[3]; + for (int channel = 0; channel < 3; ++channel) + destPixel[channel] = uint8_t((srcPixel[channel] * alpha + destPixel[channel] * (255 - alpha)) / 255); + if (alpha > destPixel[3]) + destPixel[3] = uint8_t(alpha); + } + } +} + void Bitmap::tileWith(const Bitmap& tile) { const int w = tile.size.width - 1; diff --git a/src/CoreLib/Image.hpp b/src/CoreLib/Image.hpp index 08d58d9..ad2f530 100644 --- a/src/CoreLib/Image.hpp +++ b/src/CoreLib/Image.hpp @@ -22,6 +22,7 @@ struct Point { Point operator+(const Point& s); Point& operator+=(const Point& r); + Point& operator-=(const Point& r); Point& operator/=(int downscale); std::string toString() const; }; @@ -157,6 +158,7 @@ struct MODGENCORE_EXPORT Bitmap { void linedRect(Rect rect); void draw(Point destPoint, const Bitmap& src, Point srcPoint, Size size); + void drawBlended(Point destPoint, const Bitmap& src, Point srcPoint, Size size); void tileWith(const Bitmap& tile); diff --git a/src/CoreLib/Modules/ModuleExpandedInventory.cpp b/src/CoreLib/Modules/ModuleExpandedInventory.cpp index 0e4c7b0..ec138ae 100644 --- a/src/CoreLib/Modules/ModuleExpandedInventory.cpp +++ b/src/CoreLib/Modules/ModuleExpandedInventory.cpp @@ -114,6 +114,16 @@ const auto s_rectsCorrectionMKBD = std::map{ const Point ctrl1{ -99, -60 }; const Point ctrl2{ 123, -62 }; +// Controller backgrounds are anchored at the panel center, so their sprites do not start at the panel origin. +const Point s_ctrlPanelCenter{ 1408 / 2, 1486 / 2 }; +const Point s_ctrlBackgroundRectOrig{ -508, -700 }; +const Point s_ctrlBackgroundRectExpanded{ -789, -860 }; +const Point s_ctrlSpriteOriginOrig{ s_ctrlPanelCenter.x + s_ctrlBackgroundRectOrig.x, s_ctrlPanelCenter.y + s_ctrlBackgroundRectOrig.y }; +const Point s_ctrlSpriteOriginExpanded{ s_ctrlPanelCenter.x + s_ctrlBackgroundRectExpanded.x, s_ctrlPanelCenter.y + s_ctrlBackgroundRectExpanded.y }; + +const int s_ctrlFrameMargin = 12; // controller frames extend past the widget rect +const Size s_ctrlBeltSize{ 505, 118 }; + const auto s_rectsCorrectionCTRL = std::map{ { "slot_right_arm", { .x = -99, .y = -60 } }, @@ -129,9 +139,9 @@ const auto s_rectsCorrectionCTRL = std::map{ { "slot_right_hand", { .x = 389, .y = -417 } }, { "slot_left_hand", { .x = 126, .y = -417 } }, - { "Belt", { .x = +15, .y = 595 } }, - { "gold_amount", { .x = -464, .y = 20 } }, - { "gold_button", { .x = -464, .y = 20 } }, + { "Belt", { .x = +223, .y = 595 } }, + { "gold_amount", { .x = -256, .y = 20 } }, + { "gold_button", { .x = -256, .y = 20 } }, { "background_right_arm", ctrl1 }, { "background_right_arm_selected", ctrl1 }, @@ -287,8 +297,8 @@ void ModuleExpandedInventory::generate() const int growWidth = growCellX * cellWidth; const int growHeight = growCellY * cellHeight; - const auto gridOffset = Point{ ((cellCountXmax - cellCountX) / 2) * cellWidth, ((cellCountYmax - cellCountY) / 2) * cellHeight }; - const auto widgetsOffset = Point{ 100, 0 }; + const auto gridOffsetMkbd = Point{ ((cellCountXmax - cellCountX) / 2) * cellWidth, ((cellCountYmax - cellCountY) / 2) * cellHeight }; + const auto gridOffsetCtrl = Point{ (cellCountXmax - cellCountX) * cellWidth / 2, gridOffsetMkbd.y }; DebugOverlayList debugOverlays; BlitDescList blitList; @@ -304,6 +314,12 @@ void ModuleExpandedInventory::generate() bd.expansion = desc.expansion; bd.controller = desc.controller; + const Point sourceOrigin = desc.controller ? s_ctrlSpriteOriginOrig : Point{}; + const Point targetOrigin = desc.controller ? s_ctrlSpriteOriginExpanded : Point{}; + + const Point widgetsOffset = desc.controller ? Point{ -15, 0 } : Point{ 100, 0 }; + const Point gridOffset = desc.controller ? gridOffsetCtrl : gridOffsetMkbd; + if (!desc.expansion && !desc.controller) json["fields"]["rect"] = Mernel::PropertyTreeScalar("$RightPanelRect_ExpandedInventory"); @@ -319,12 +335,21 @@ void ModuleExpandedInventory::generate() if (!d.read(child)) continue; + if (desc.controller && d.name == "Belt") + d.rect.size = s_ctrlBeltSize; // the layout only stores its position + bd.rect = d.rect; d.rect.topLeft += correction; d.rect.topLeft += widgetsOffset; // @todo: future uncollapsing bd.moveTo = d.rect.topLeft; - bd.rect.expand(10); - bd.moveTo += Point{ -10, -10 }; // extra borders + + if (!desc.controller || bd.rect.size.width > 0) { + const int margin = desc.controller ? s_ctrlFrameMargin : 10; // extra borders + bd.rect.expand(margin); + bd.moveTo -= Point{ margin, margin }; + } + bd.rect.topLeft -= sourceOrigin; + bd.moveTo -= targetOrigin; d.write(child); blitList.push_back(bd); @@ -332,17 +357,19 @@ void ModuleExpandedInventory::generate() //Logger() << d.name << " " << bd.rect.toString() << " -> " << bd.moveTo.toString(); } else if (d.name == "grid") { - Point correction = desc.controller ? Point{ -132, -344 } : Point{ -37, -229 }; + Point correction = desc.controller ? Point{ -247, -344 } : Point{ -37, -229 }; if (!d.read(child)) continue; bd.rect = d.rect; + bd.rect.topLeft -= sourceOrigin; d.rect.topLeft += correction; d.rect.topLeft += gridOffset; bd.rect.size.width = cellWidth; bd.rect.size.height = cellHeight; bd.moveTo = d.rect.topLeft; + bd.moveTo -= targetOrigin; bd.repeatX = cellCountX; bd.repeatY = cellCountY; @@ -368,8 +395,8 @@ void ModuleExpandedInventory::generate() child["fields"]["filename"] = Mernel::PropertyTreeScalar("Controller/Panel/InventoryPanel/V2/InventoryBG_Expanded"); if (!desc.expansion) { child["fields"]["filename"] = Mernel::PropertyTreeScalar("Controller/Panel/InventoryPanel/V2/InventoryBG_Classic_Expanded"); - child["fields"]["rect"]["x"] = Mernel::PropertyTreeScalar(-674); - child["fields"]["rect"]["y"] = Mernel::PropertyTreeScalar(-860); + child["fields"]["rect"]["x"] = Mernel::PropertyTreeScalar(s_ctrlBackgroundRectExpanded.x); + child["fields"]["rect"]["y"] = Mernel::PropertyTreeScalar(s_ctrlBackgroundRectExpanded.y); } } else { child["fields"]["filename"] = Mernel::PropertyTreeScalar("PANEL\\Inventory\\Background_Expanded"); @@ -411,8 +438,9 @@ void ModuleExpandedInventory::generate() cornerSize /= downscale; bmp.resize(newSize); bmp.frameWidth = newSize.width; - if (!desc.controller) { - // controller use transparent back + if (desc.controller) { + bmp.rgba.assign(bmp.rgba.size(), 0); // the game draws its own panel behind the controller background + } else { bmp.tileWith(stone); bmp.copyBorders(origBmp, cornerSize); } @@ -425,7 +453,10 @@ void ModuleExpandedInventory::generate() bd /= downscale; for (int x = 0, offsetX = 0; x < bd.repeatX; x++, offsetX += bd.rect.size.width) { for (int y = 0, offsetY = 0; y < bd.repeatY; y++, offsetY += bd.rect.size.height) { - bmp.draw(bd.moveTo + Point(offsetX, offsetY), origBmp, bd.rect.topLeft, bd.rect.size); + if (bd.controller) + bmp.drawBlended(bd.moveTo + Point(offsetX, offsetY), origBmp, bd.rect.topLeft, bd.rect.size); + else + bmp.draw(bd.moveTo + Point(offsetX, offsetY), origBmp, bd.rect.topLeft, bd.rect.size); } } } @@ -438,6 +469,8 @@ void ModuleExpandedInventory::generate() if (!desc.expansion && overlay.expansion) continue; + if (overlay.controller) + overlay.rect.topLeft -= s_ctrlSpriteOriginExpanded; overlay /= desc.lowres ? 2 : 1; overlay.paintTo(bmp); } From fa29158c7132ef7fbbfe478356a2200080395b85 Mon Sep 17 00:00:00 2001 From: Le Duy Thuc Date: Thu, 12 Nov 2026 12:42:11 +0700 Subject: [PATCH 2/5] Use controller panel art for expanded inventory background Replace background of MKB with controller mainpanelbg.sprite, scaled with panel size --- src/CoreLib/Image.cpp | 200 +++--------------- src/CoreLib/Image.hpp | 3 +- .../Modules/ModuleExpandedInventory.cpp | 15 +- src/CoreLib/Storage/IStorage.cpp | 3 + src/CoreLib/Storage/IStorage.hpp | 6 +- 5 files changed, 52 insertions(+), 175 deletions(-) diff --git a/src/CoreLib/Image.cpp b/src/CoreLib/Image.cpp index 2794801..4136f8c 100644 --- a/src/CoreLib/Image.cpp +++ b/src/CoreLib/Image.cpp @@ -7,7 +7,7 @@ #include "MernelPlatform/ByteOrderStream.hpp" -#include +#include #include namespace D2ModGen::Image { @@ -67,158 +67,6 @@ uint8_t s_defaultPaletteGBR[768] = { // clang-format on }; -class StoneTextureGenerator { -private: - int p[512]; - - // Standard Fade function for smooth transitions - double fade(double t) { return t * t * t * (t * (t * 6 - 15) + 10); } - - // Linear interpolation - double lerp(double t, double a, double b) { return a + t * (b - a); } - - // Gradient calculation - double grad(int hash, double x, double y) - { - int h = hash & 7; - double u = h < 4 ? x : y; - double v = h < 4 ? y : x; - return ((h & 1) ? -u : u) + ((h & 2) ? -2.0 * v : 2.0 * v); - } - -public: - StoneTextureGenerator(unsigned int seed = 42) - { - // Initialize permutation table with a standard shuffle sequence - int base_p[256]; - std::iota(std::begin(base_p), std::end(base_p), 0); - - // Simple LCG deterministic shuffle using the seed - for (int i = 255; i > 0; --i) { - seed = seed * 1103515245 + 12345; - int j = (seed / 65536) % (i + 1); - std::swap(base_p[i], base_p[j]); - } - - // Duplicate the array to avoid buffer overflows during interpolation - for (int i = 0; i < 256; i++) { - p[i] = base_p[i]; - p[i + 256] = base_p[i]; - } - } - - // 2D Perlin Noise implementation returning range [-1.0, 1.0] - double noise(double x, double y) - { - int X = (int) std::floor(x) & 255; - int Y = (int) std::floor(y) & 255; - - x -= std::floor(x); - y -= std::floor(y); - - double u = fade(x); - double v = fade(y); - - int A = p[X] + Y; - int B = p[X + 1] + Y; - - return lerp(v, lerp(u, grad(p[A], x, y), grad(p[B], x - 1, y)), lerp(u, grad(p[A + 1], x, y - 1), grad(p[B + 1], x - 1, y - 1))); - } - - // Generates a 32-bit RGBA color buffer matching the UI element dimensions - void generateStoneTexture(Bitmap& bitmap, double scale = 0.03) - { - int width = bitmap.size.width; - int height = bitmap.size.height; - - for (int y = 0; y < height; ++y) { - for (int x = 0; x < width; ++x) { - double sampleX = x * scale; - double sampleY = y * scale; - - double totalHeight = 0.0; - double slopeX = 0.0; - double slopeY = 0.0; - - double amplitude = 1.0; - double frequency = 1.0; - double maxValue = 0.0; - - // 3 octaves for high speed while preserving micro-cracks - for (int octave = 0; octave < 3; ++octave) { - double nx = sampleX * frequency; - double ny = sampleY * frequency; - - // --- FAST ANALYTICAL INLINE DERIVATIVE --- - int X = (int) std::floor(nx) & 255; - int Y = (int) std::floor(ny) & 255; - double fx = nx - std::floor(nx); - double fy = ny - std::floor(ny); - - // Inline fade curves and their exact derivatives - double u = fx * fx * fx * (fx * (fx * 6 - 15) + 10); - double v = fy * fy * fy * (fy * (fy * 6 - 15) + 10); - double du = 30.0 * fx * fx * (fx * (fx - 2.0) + 1.0); - double dv = 30.0 * fy * fy * (fy * (fy - 2.0) + 1.0); - - int A = p[X] + Y; - int B = p[X + 1] + Y; - double g00 = grad(p[A], fx, fy); - double g10 = grad(p[B], fx - 1, fy); - double g01 = grad(p[A + 1], fx, fy - 1); - double g11 = grad(p[B + 1], fx - 1, fy - 1); - - // Calculate smooth height - double r = lerp(v, lerp(u, g00, g10), lerp(u, g01, g11)); - - // Transform to Ridged/Craggy profile mathematically - double crag = 1.0 - std::abs(r); - double cragSq = crag * crag; - - totalHeight += cragSq * amplitude; - maxValue += amplitude; - - // Chain rule to extract matching slopes instantly without extra noise calls - double dNdx = lerp(v, g10 - g00, g11 - g01) * du; - double dNdy = (lerp(u, g01, g11) - lerp(u, g00, g10)) * dv; - - // Sign correction based on the absolute value flip - double sign = (r < 0.0) ? 1.0 : -1.0; - slopeX += 2.0 * crag * sign * dNdx * amplitude * frequency; - slopeY += 2.0 * crag * sign * dNdy * amplitude * frequency; - - amplitude *= 0.45; - frequency *= 2.2; - } - - totalHeight /= maxValue; - - // --- FAKE LIGHTING CALCULATIONS --- - double lightX = -0.5; - double lightY = -0.5; - double lightZ = 0.8; - double rsq = slopeX * slopeX + slopeY * slopeY + 1.0; - double inv_len = 1.0 / std::sqrt(rsq); - - double light = (slopeX * inv_len) * lightX + (slopeY * inv_len) * lightY + inv_len * lightZ; - light = std::max(0.0, light); - - double rockPattern = std::pow(totalHeight, 2.5); - double finalShade = rockPattern * (0.3 + 0.7 * light); - - // --- COMPATIBILITY WITH YOUR BITMAP API --- - Color c; - c.r = static_cast(12 + finalShade * 40); // Range ~12 to 52 (Dark Charcoal) - c.g = static_cast(14 + finalShade * 42); - c.b = static_cast(16 + finalShade * 45); - c.a = 255; - - bitmap.putDot({ x, y }, c); - } - } - } -}; - void makeBorderImage(Bitmap& dest, const Bitmap& src, Size cornerSize) { const int srcW = src.size.width; @@ -613,12 +461,6 @@ void Bitmap::fill() } } -void Bitmap::fillWithStone() -{ - StoneTextureGenerator gen; - gen.generateStoneTexture(*this); -} - void Bitmap::copyBorders(const Bitmap& src, Size cornerSize) { makeBorderImage(*this, src, cornerSize); @@ -656,16 +498,40 @@ void Bitmap::drawBlended(Point destPoint, const Bitmap& src, Point srcPoint, Siz } } -void Bitmap::tileWith(const Bitmap& tile) +void Bitmap::drawScaled(Rect destRect, const Bitmap& src, Rect srcRect) { - const int w = tile.size.width - 1; - const int h = tile.size.height - 1; - for (int x = 0; x < size.width; x++) { - const int srcX = x % w; - for (int y = 0; y < size.height; y++) { - const int srcY = y % h; + if (destRect.size.width <= 0 || destRect.size.height <= 0 || srcRect.size.width <= 0 || srcRect.size.height <= 0) + return; - drawDot({ x, y }, tile, { srcX, srcY }); + const double scaleX = double(srcRect.size.width) / destRect.size.width; + const double scaleY = double(srcRect.size.height) / destRect.size.height; + const int maxX = srcRect.size.width - 1; + const int maxY = srcRect.size.height - 1; + + for (int y = 0; y < destRect.size.height; ++y) { + const double sy = std::clamp((y + 0.5) * scaleY - 0.5, 0.0, double(maxY)); + const int y0 = int(sy); + const int y1 = std::min(y0 + 1, maxY); + const double fy = sy - y0; + for (int x = 0; x < destRect.size.width; ++x) { + const double sx = std::clamp((x + 0.5) * scaleX - 0.5, 0.0, double(maxX)); + const int x0 = int(sx); + const int x1 = std::min(x0 + 1, maxX); + const double fx = sx - x0; + + auto* destPixel = getPixel(destRect.topLeft + Point{ x, y }); + const uint8_t* p00 = src.getPixel(srcRect.topLeft + Point{ x0, y0 }); + const uint8_t* p10 = src.getPixel(srcRect.topLeft + Point{ x1, y0 }); + const uint8_t* p01 = src.getPixel(srcRect.topLeft + Point{ x0, y1 }); + const uint8_t* p11 = src.getPixel(srcRect.topLeft + Point{ x1, y1 }); + if (!destPixel || !p00 || !p10 || !p01 || !p11) + continue; + + for (int channel = 0; channel < 4; ++channel) { + const double top = p00[channel] + (p10[channel] - p00[channel]) * fx; + const double bottom = p01[channel] + (p11[channel] - p01[channel]) * fx; + destPixel[channel] = uint8_t(std::lround(top + (bottom - top) * fy)); + } } } } diff --git a/src/CoreLib/Image.hpp b/src/CoreLib/Image.hpp index ad2f530..6988542 100644 --- a/src/CoreLib/Image.hpp +++ b/src/CoreLib/Image.hpp @@ -151,7 +151,6 @@ struct MODGENCORE_EXPORT Bitmap { void paintLineV(Point point, int height); void fill(); - void fillWithStone(); void copyBorders(const Bitmap& src, Size cornerSize); void fillRect(Rect rect); @@ -160,7 +159,7 @@ struct MODGENCORE_EXPORT Bitmap { void draw(Point destPoint, const Bitmap& src, Point srcPoint, Size size); void drawBlended(Point destPoint, const Bitmap& src, Point srcPoint, Size size); - void tileWith(const Bitmap& tile); + void drawScaled(Rect destRect, const Bitmap& src, Rect srcRect); // bilinear void drawDot(Point destPoint, const Bitmap& src, Point srcPoint); }; diff --git a/src/CoreLib/Modules/ModuleExpandedInventory.cpp b/src/CoreLib/Modules/ModuleExpandedInventory.cpp index ec138ae..b44ea0a 100644 --- a/src/CoreLib/Modules/ModuleExpandedInventory.cpp +++ b/src/CoreLib/Modules/ModuleExpandedInventory.cpp @@ -121,6 +121,9 @@ const Point s_ctrlBackgroundRectExpanded{ -789, -860 }; const Point s_ctrlSpriteOriginOrig{ s_ctrlPanelCenter.x + s_ctrlBackgroundRectOrig.x, s_ctrlPanelCenter.y + s_ctrlBackgroundRectOrig.y }; const Point s_ctrlSpriteOriginExpanded{ s_ctrlPanelCenter.x + s_ctrlBackgroundRectExpanded.x, s_ctrlPanelCenter.y + s_ctrlBackgroundRectExpanded.y }; +// Stone area of the biggest panel in controller mainpanelbg.sprite, without its frame and corner ornaments. +const Rect s_panelBgStoneRect{ .topLeft = { 645, 202 }, .size = { 1590, 1366 } }; + const int s_ctrlFrameMargin = 12; // controller frames extend past the widget rect const Size s_ctrlBeltSize{ 505, 118 }; @@ -343,7 +346,7 @@ void ModuleExpandedInventory::generate() d.rect.topLeft += widgetsOffset; // @todo: future uncollapsing bd.moveTo = d.rect.topLeft; - if (!desc.controller || bd.rect.size.width > 0) { + if (bd.rect.size.width > 0) { const int margin = desc.controller ? s_ctrlFrameMargin : 10; // extra borders bd.rect.expand(margin); bd.moveTo -= Point{ margin, margin }; @@ -417,9 +420,9 @@ void ModuleExpandedInventory::generate() } } - Bitmap stone; - stone.resize({ 1600, 800 }); - stone.fillWithStone(); + Bitmap panelBgHighre, panelBgLowend; + panelBgHighre.readFromSprite(output.blobs[BlobId::OrignCtrlMainPanelBgSpriteHighre]); + panelBgLowend.readFromSprite(output.blobs[BlobId::OrignCtrlMainPanelBgSpriteLowend]); for (const auto& desc : s_spriteDescs) { const auto& origSpriteBlob = output.blobs[desc.orig]; @@ -441,7 +444,9 @@ void ModuleExpandedInventory::generate() if (desc.controller) { bmp.rgba.assign(bmp.rgba.size(), 0); // the game draws its own panel behind the controller background } else { - bmp.tileWith(stone); + Rect stoneRect = s_panelBgStoneRect; + stoneRect /= downscale; + bmp.drawScaled({ .topLeft = {}, .size = newSize }, desc.lowres ? panelBgLowend : panelBgHighre, stoneRect); bmp.copyBorders(origBmp, cornerSize); } diff --git a/src/CoreLib/Storage/IStorage.cpp b/src/CoreLib/Storage/IStorage.cpp index e1f3d2a..ead5ef8 100644 --- a/src/CoreLib/Storage/IStorage.cpp +++ b/src/CoreLib/Storage/IStorage.cpp @@ -96,6 +96,9 @@ const std::array s_blobpaths{ "data\\hd\\global\\ui\\controller\\panel\\inventorypanel\\v2\\inventorybg.sprite", "data\\hd\\global\\ui\\controller\\panel\\inventorypanel\\v2\\inventorybg.lowend.sprite", + "data\\hd\\global\\ui\\controller\\panel\\mainpanelbg.sprite", + "data\\hd\\global\\ui\\controller\\panel\\mainpanelbg.lowend.sprite", + "data\\hd\\global\\ui\\spells\\amazon\\amskillicon.sprite", "data\\hd\\global\\ui\\spells\\amazon\\amskillicon.lowend.sprite", "data\\hd\\global\\ui\\spells\\sorceress\\soskillicon.sprite", diff --git a/src/CoreLib/Storage/IStorage.hpp b/src/CoreLib/Storage/IStorage.hpp index eca0af1..0f87ece 100644 --- a/src/CoreLib/Storage/IStorage.hpp +++ b/src/CoreLib/Storage/IStorage.hpp @@ -114,6 +114,10 @@ enum class BlobId OrignCtrlInventoryExpansnSpriteHighre, OrignCtrlInventoryExpansnSpriteLowend, + // fullscreen controller panel background, used as base for all expanded inventory backgrounds + OrignCtrlMainPanelBgSpriteHighre, + OrignCtrlMainPanelBgSpriteLowend, + IconAmaHighre, IconAmaLowres, IconSorHighre, @@ -151,7 +155,7 @@ enum class BlobId ResurrectedLast = IconWarLowres, SkipWriteFirst = OrignMnkbInventoryClassicSpriteHighre, - SkipWriteLast = OrignCtrlInventoryExpansnSpriteLowend, + SkipWriteLast = OrignCtrlMainPanelBgSpriteLowend, }; inline auto getBlobIdsLegacy() From b0baf0eb97cadc0d3059bb7ab914fa8af755d7e0 Mon Sep 17 00:00:00 2001 From: Le Duy Thuc Date: Thu, 12 Nov 2026 12:57:14 +0700 Subject: [PATCH 3/5] Center expanded inventory grid --- src/CoreLib/Modules/ModuleExpandedInventory.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/CoreLib/Modules/ModuleExpandedInventory.cpp b/src/CoreLib/Modules/ModuleExpandedInventory.cpp index b44ea0a..0ceabdd 100644 --- a/src/CoreLib/Modules/ModuleExpandedInventory.cpp +++ b/src/CoreLib/Modules/ModuleExpandedInventory.cpp @@ -300,8 +300,7 @@ void ModuleExpandedInventory::generate() const int growWidth = growCellX * cellWidth; const int growHeight = growCellY * cellHeight; - const auto gridOffsetMkbd = Point{ ((cellCountXmax - cellCountX) / 2) * cellWidth, ((cellCountYmax - cellCountY) / 2) * cellHeight }; - const auto gridOffsetCtrl = Point{ (cellCountXmax - cellCountX) * cellWidth / 2, gridOffsetMkbd.y }; + const auto gridOffset = Point{ (cellCountXmax - cellCountX) * cellWidth / 2, (cellCountYmax - cellCountY) * cellHeight / 2 }; DebugOverlayList debugOverlays; BlitDescList blitList; @@ -321,7 +320,6 @@ void ModuleExpandedInventory::generate() const Point targetOrigin = desc.controller ? s_ctrlSpriteOriginExpanded : Point{}; const Point widgetsOffset = desc.controller ? Point{ -15, 0 } : Point{ 100, 0 }; - const Point gridOffset = desc.controller ? gridOffsetCtrl : gridOffsetMkbd; if (!desc.expansion && !desc.controller) json["fields"]["rect"] = Mernel::PropertyTreeScalar("$RightPanelRect_ExpandedInventory"); From 7eea37c20df1d7d30fff3b197175508d20550099 Mon Sep 17 00:00:00 2001 From: Le Duy Thuc Date: Thu, 12 Nov 2026 13:06:42 +0700 Subject: [PATCH 4/5] Add Point - operator, fix lint --- src/CoreLib/Image.cpp | 8 ++++++++ src/CoreLib/Image.hpp | 1 + src/CoreLib/Modules/ModuleExpandedInventory.cpp | 6 ++---- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/src/CoreLib/Image.cpp b/src/CoreLib/Image.cpp index 4136f8c..6e40eb3 100644 --- a/src/CoreLib/Image.cpp +++ b/src/CoreLib/Image.cpp @@ -149,6 +149,14 @@ Point Point::operator+(const Point& s) return result; } +Point Point::operator-(const Point& s) const +{ + Point result = *this; + result.x -= s.x; + result.y -= s.y; + return result; +} + Point& Point::operator+=(const Point& r) { x += r.x; diff --git a/src/CoreLib/Image.hpp b/src/CoreLib/Image.hpp index 6988542..770ed17 100644 --- a/src/CoreLib/Image.hpp +++ b/src/CoreLib/Image.hpp @@ -20,6 +20,7 @@ struct Point { void read(const Mernel::PropertyTree& data); void write(Mernel::PropertyTree& data) const; Point operator+(const Point& s); + Point operator-(const Point& s) const; Point& operator+=(const Point& r); Point& operator-=(const Point& r); diff --git a/src/CoreLib/Modules/ModuleExpandedInventory.cpp b/src/CoreLib/Modules/ModuleExpandedInventory.cpp index 0ceabdd..5940797 100644 --- a/src/CoreLib/Modules/ModuleExpandedInventory.cpp +++ b/src/CoreLib/Modules/ModuleExpandedInventory.cpp @@ -342,7 +342,7 @@ void ModuleExpandedInventory::generate() bd.rect = d.rect; d.rect.topLeft += correction; d.rect.topLeft += widgetsOffset; // @todo: future uncollapsing - bd.moveTo = d.rect.topLeft; + bd.moveTo = d.rect.topLeft - targetOrigin; if (bd.rect.size.width > 0) { const int margin = desc.controller ? s_ctrlFrameMargin : 10; // extra borders @@ -350,7 +350,6 @@ void ModuleExpandedInventory::generate() bd.moveTo -= Point{ margin, margin }; } bd.rect.topLeft -= sourceOrigin; - bd.moveTo -= targetOrigin; d.write(child); blitList.push_back(bd); @@ -369,8 +368,7 @@ void ModuleExpandedInventory::generate() bd.rect.size.width = cellWidth; bd.rect.size.height = cellHeight; - bd.moveTo = d.rect.topLeft; - bd.moveTo -= targetOrigin; + bd.moveTo = d.rect.topLeft - targetOrigin; bd.repeatX = cellCountX; bd.repeatY = cellCountY; From 57db83cdd3e0705b69a3518aa9e77d4331a56e9c Mon Sep 17 00:00:00 2001 From: Le Duy Thuc Date: Thu, 12 Nov 2026 13:08:46 +0700 Subject: [PATCH 5/5] follow format for operator --- src/CoreLib/Image.cpp | 2 +- src/CoreLib/Image.hpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/CoreLib/Image.cpp b/src/CoreLib/Image.cpp index 6e40eb3..d0bb6ff 100644 --- a/src/CoreLib/Image.cpp +++ b/src/CoreLib/Image.cpp @@ -149,7 +149,7 @@ Point Point::operator+(const Point& s) return result; } -Point Point::operator-(const Point& s) const +Point Point::operator-(const Point& s) { Point result = *this; result.x -= s.x; diff --git a/src/CoreLib/Image.hpp b/src/CoreLib/Image.hpp index 770ed17..aa4678b 100644 --- a/src/CoreLib/Image.hpp +++ b/src/CoreLib/Image.hpp @@ -20,7 +20,7 @@ struct Point { void read(const Mernel::PropertyTree& data); void write(Mernel::PropertyTree& data) const; Point operator+(const Point& s); - Point operator-(const Point& s) const; + Point operator-(const Point& s); Point& operator+=(const Point& r); Point& operator-=(const Point& r);