Allow to draw produced-item icons in recipe dialog and game world

This commit is contained in:
2026-07-23 20:54:04 +02:00
parent 8b71fe1a03
commit f766ae4a86
12 changed files with 258 additions and 29 deletions

View File

@@ -49,6 +49,7 @@
#include "GameOverEvent.h"
#include "HealthComponent.h"
#include "HqProxyComponent.h"
#include "ItemIconCache.h"
#include "PositionComponent.h"
#include "RepairBehavior.h"
#include "SalvageScrapBehavior.h"
@@ -222,6 +223,11 @@ GameWorldView::GameWorldView(Simulation* sim, const GameConfig* config,
loadBuildingIcons(configDir);
// Item icons live beside the config dir, mirroring the building icons
// (REQ-UI-ITEM-ICON, REQ-UI-WORLD-ICON).
m_itemIcons = std::make_unique<ItemIconCache>(QDir::cleanPath(
QString::fromStdString(configDir) + "/../icons/items"));
m_renderTimer = new QTimer(this);
m_renderTimer->setInterval(16);
connect(m_renderTimer, &QTimer::timeout, this, &GameWorldView::onFrame);
@@ -1597,23 +1603,15 @@ void GameWorldView::drawPortItems(QPainter& painter)
}
}
// Shared with belt items (REQ-GW-TILE-SIZE): a half-tile filled square + outline.
// Shared with belt items (REQ-GW-TILE-SIZE): a half-tile item icon, or the
// colored-square fallback (REQ-UI-ITEM-ICON), via the same draw path.
const std::function<void(const ItemType&, QPointF)> drawItem =
[&](const ItemType& type, QPointF worldPos)
{
const std::map<std::string, ItemVisuals>::const_iterator it =
m_visuals->items.find(type.id);
if (it == m_visuals->items.end()) { return; }
const QPointF center = worldToWidget(
QVector2D(static_cast<float>(worldPos.x()),
static_cast<float>(worldPos.y())));
const QRectF itemRect(center.x() - halfPx, center.y() - halfPx,
halfPx * 2, halfPx * 2);
painter.fillRect(itemRect, it->second.fill);
painter.setPen(QPen(it->second.outline, 1));
painter.setBrush(Qt::NoBrush);
painter.drawRect(itemRect);
drawWorldItem(painter, type.id, center, halfPx);
};
painter.save();
@@ -1623,6 +1621,33 @@ void GameWorldView::drawPortItems(QPainter& painter)
painter.restore();
}
void GameWorldView::drawWorldItem(QPainter& painter, const std::string& itemId,
QPointF center, float halfPx)
{
const QRectF itemRect(center.x() - halfPx, center.y() - halfPx,
halfPx * 2, halfPx * 2);
// Prefer the item's icon (REQ-UI-ITEM-ICON); it is rasterized once at the current
// half-tile pixel size and cached, so this is a plain pixmap blit per frame.
if (m_itemIcons && m_itemIcons->hasIcon(itemId))
{
int sizePx = qRound(static_cast<qreal>(halfPx * 2.0f));
if (sizePx < 1) { sizePx = 1; }
painter.drawPixmap(itemRect, m_itemIcons->getPixmap(itemId, sizePx),
QRectF(0, 0, sizePx, sizePx));
return;
}
// Fallback: the colored square from visuals.toml (REQ-GW-TILE-SIZE).
const std::map<std::string, ItemVisuals>::const_iterator it =
m_visuals->items.find(itemId);
if (it == m_visuals->items.end()) { return; }
painter.fillRect(itemRect, it->second.fill);
painter.setPen(QPen(it->second.outline, 1));
painter.setBrush(Qt::NoBrush);
painter.drawRect(itemRect);
}
void GameWorldView::drawBeltItems(QPainter& painter)
{
const float halfPx = getTilePx() * 0.5f * 0.5f;
@@ -1630,19 +1655,10 @@ void GameWorldView::drawBeltItems(QPainter& painter)
m_sim->getBelts().forEachVisualItem(vr, [&](const VisualItem& vi)
{
const std::map<std::string, ItemVisuals>::const_iterator it =
m_visuals->items.find(vi.type.id);
if (it == m_visuals->items.end()) { return; }
const QPointF center = worldToWidget(
QVector2D(static_cast<float>(vi.worldPos.x()),
static_cast<float>(vi.worldPos.y())));
const QRectF rect(center.x() - halfPx, center.y() - halfPx,
halfPx * 2, halfPx * 2);
painter.fillRect(rect, it->second.fill);
painter.setPen(QPen(it->second.outline, 1));
painter.setBrush(Qt::NoBrush);
painter.drawRect(rect);
drawWorldItem(painter, vi.type.id, center, halfPx);
});
}