Reveal port items in a thin margin at machine edges
This commit is contained in:
@@ -20,6 +20,7 @@
|
|||||||
#include <QPainter>
|
#include <QPainter>
|
||||||
#include <QPen>
|
#include <QPen>
|
||||||
#include <QPolygonF>
|
#include <QPolygonF>
|
||||||
|
#include <QRegion>
|
||||||
#include <QStringList>
|
#include <QStringList>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
@@ -402,12 +403,12 @@ void GameWorldView::paintGL()
|
|||||||
painter.setRenderHint(QPainter::Antialiasing, false);
|
painter.setRenderHint(QPainter::Antialiasing, false);
|
||||||
|
|
||||||
drawTiles(painter);
|
drawTiles(painter);
|
||||||
// Port items are drawn before the buildings so the building body occludes the
|
|
||||||
// portion still inside the footprint: items appear to slide out of the output
|
|
||||||
// port (REQ-MAT-OUTPUT-EMERGE) and into the input port (REQ-MAT-INPUT-INTAKE)
|
|
||||||
// rather than popping in or out of existence.
|
|
||||||
drawPortItems(painter);
|
|
||||||
drawBuildings(painter);
|
drawBuildings(painter);
|
||||||
|
// Port items are drawn over the buildings but clipped to a thin margin at each
|
||||||
|
// machine's edges (see drawPortItems), so items appear to emerge from / sink
|
||||||
|
// into the port and stay visible while crossing directly between two touching
|
||||||
|
// buildings (REQ-MAT-OUTPUT-EMERGE, REQ-MAT-INPUT-INTAKE, REQ-MAT-DIRECT-COUPLE).
|
||||||
|
drawPortItems(painter);
|
||||||
drawCopyConfigFeedback(painter);
|
drawCopyConfigFeedback(painter);
|
||||||
drawStations(painter);
|
drawStations(painter);
|
||||||
drawBeltItems(painter);
|
drawBeltItems(painter);
|
||||||
@@ -1162,9 +1163,39 @@ void GameWorldView::drawPortItems(QPainter& painter)
|
|||||||
{
|
{
|
||||||
const float halfPx = tilePx() * 0.5f * 0.5f;
|
const float halfPx = tilePx() * 0.5f * 0.5f;
|
||||||
|
|
||||||
// Shared with belt items (REQ-GW-TILE-SIZE): a half-tile filled square with an
|
// Port items are drawn over the buildings (drawBuildings runs first) but clipped
|
||||||
// outline, occluded by the building drawn afterwards so the item slides out of
|
// to a thin margin at each machine's edges: the clip region is the whole view
|
||||||
// (REQ-MAT-OUTPUT-EMERGE) or into (REQ-MAT-INPUT-INTAKE) the port.
|
// minus every machine's interior (its footprint inset by kPortMarginTiles). So a
|
||||||
|
// transiting item shows only near the port edge — appearing to emerge from / sink
|
||||||
|
// into the machine (REQ-MAT-OUTPUT-EMERGE, REQ-MAT-INPUT-INTAKE) and staying
|
||||||
|
// visible in the ~2×margin band at a seam between two touching buildings
|
||||||
|
// (REQ-MAT-DIRECT-COUPLE). Transport tiles are not machines and never occlude, so
|
||||||
|
// items on belts stay fully visible.
|
||||||
|
constexpr double kPortMarginTiles = 0.2;
|
||||||
|
const double margin = kPortMarginTiles * static_cast<double>(tilePx());
|
||||||
|
|
||||||
|
QRegion clip(rect());
|
||||||
|
for (const Building& b : m_sim->buildings().allBuildings())
|
||||||
|
{
|
||||||
|
if (b.type == BuildingType::Belt || b.type == BuildingType::Splitter
|
||||||
|
|| b.type == BuildingType::TunnelEntry || b.type == BuildingType::TunnelExit)
|
||||||
|
{
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const std::set<QPoint, QPointCompare> cells(b.bodyCells.begin(), b.bodyCells.end());
|
||||||
|
for (const QPoint& cell : b.bodyCells)
|
||||||
|
{
|
||||||
|
// Inset an edge only where the neighbouring cell is not part of the same
|
||||||
|
// building, so interior cell seams stay filled (handles L-shaped footprints).
|
||||||
|
const double l = cells.count(cell + QPoint(-1, 0)) ? 0.0 : margin;
|
||||||
|
const double t = cells.count(cell + QPoint( 0, -1)) ? 0.0 : margin;
|
||||||
|
const double r = cells.count(cell + QPoint( 1, 0)) ? 0.0 : margin;
|
||||||
|
const double d = cells.count(cell + QPoint( 0, 1)) ? 0.0 : margin;
|
||||||
|
clip = clip.subtracted(QRegion(tileRect(cell).adjusted(l, t, -r, -d).toRect()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Shared with belt items (REQ-GW-TILE-SIZE): a half-tile filled square + outline.
|
||||||
const std::function<void(const ItemType&, QPointF)> drawItem =
|
const std::function<void(const ItemType&, QPointF)> drawItem =
|
||||||
[&](const ItemType& type, QPointF worldPos)
|
[&](const ItemType& type, QPointF worldPos)
|
||||||
{
|
{
|
||||||
@@ -1175,16 +1206,19 @@ void GameWorldView::drawPortItems(QPainter& painter)
|
|||||||
const QPointF center = worldToWidget(
|
const QPointF center = worldToWidget(
|
||||||
QVector2D(static_cast<float>(worldPos.x()),
|
QVector2D(static_cast<float>(worldPos.x()),
|
||||||
static_cast<float>(worldPos.y())));
|
static_cast<float>(worldPos.y())));
|
||||||
const QRectF rect(center.x() - halfPx, center.y() - halfPx,
|
const QRectF itemRect(center.x() - halfPx, center.y() - halfPx,
|
||||||
halfPx * 2, halfPx * 2);
|
halfPx * 2, halfPx * 2);
|
||||||
painter.fillRect(rect, it->second.fill);
|
painter.fillRect(itemRect, it->second.fill);
|
||||||
painter.setPen(QPen(it->second.outline, 1));
|
painter.setPen(QPen(it->second.outline, 1));
|
||||||
painter.setBrush(Qt::NoBrush);
|
painter.setBrush(Qt::NoBrush);
|
||||||
painter.drawRect(rect);
|
painter.drawRect(itemRect);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
painter.save();
|
||||||
|
painter.setClipRegion(clip);
|
||||||
m_sim->buildings().forEachEmergingItem(drawItem);
|
m_sim->buildings().forEachEmergingItem(drawItem);
|
||||||
m_sim->buildings().forEachIncomingItem(drawItem);
|
m_sim->buildings().forEachIncomingItem(drawItem);
|
||||||
|
painter.restore();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GameWorldView::drawBeltItems(QPainter& painter)
|
void GameWorldView::drawBeltItems(QPainter& painter)
|
||||||
|
|||||||
Reference in New Issue
Block a user