Skip to content

Add high-resolution rendering support and shared map zoom - #218

Merged
genixpro merged 4 commits into
masterfrom
codex/hd-renderer-zoom
Sep 9, 2026
Merged

Add high-resolution rendering support and shared map zoom#218
genixpro merged 4 commits into
masterfrom
codex/hd-renderer-zoom

Conversation

@genixpro

@genixpro genixpro commented Sep 9, 2026

Copy link
Copy Markdown
Contributor

Splits the engine changes out of #207. Adds 50%–300% map zoom to gameplay, replays and the editor, and separates physical texture resolution from unchanged logical sprite geometry. No replacement artwork, recovered source archive, or AI assets/tooling are included.

  • Shared presentation-only camera; Alt+wheel pointer anchoring and sidebar controls.
  • Toroidal map repetition, matching input conversions, minimap navigation and culling.
  • Direct OpenGL world transform, HD textures/mips, lazy team caches and complete-frame fallback.
  • Classic software rendering remains at 100%; original data/gfx is unchanged.
  • HD preference defaults on but missing packs simply use classic frames.

Based on current master, preserving its save/network/pathfinding changes. The build-target conflict was resolved by retaining both existing regression targets and the new integration harness.

Validation: clean optimized game/harness build passes against current master. Gameplay/editor/replay integration passes with no artwork pack installed; software mode passes. Tests cover zoom/picking, Alt-wheel order isolation, current-version replay recording/loading, matching simulation checksums and resource release. The test was updated for master’s renamed map accessor and intentionally newer replay version.

This is part 1 of a three-PR stack; original-source artwork and AI artwork are separate dependent PRs. Broader platform/performance review remains required.

Review stack

  1. Add high-resolution rendering support and shared map zoom #218 — engine support and zoom
  2. Organize original artwork and ship original-derived HD sprites #219 — original sources and original-derived artwork (base: Add high-resolution rendering support and shared map zoom #218)
  3. Add approved AI-enhanced artwork and staging pipeline #220 — AI-enhanced finals and candidate pipeline (base: Organize original artwork and ship original-derived HD sprites #219)

After a parent merges, retarget its child to master. #207 retains the prior discussion and is superseded by this stack.

Scope and build guide.

@genixpro
genixpro merged commit 3ad40cf into master Sep 9, 2026
3 checks passed
@genixpro
genixpro deleted the codex/hd-renderer-zoom branch September 9, 2026 16:15
Giszmo added a commit that referenced this pull request Sep 9, 2026
The HD-rendering work (#218) rewrote both game.drawMap call sites in
GameGUI::drawAll to size the viewport from the camera, colliding with
the `gamePaused` argument added here. Took master's call and kept the
argument.

Opus 5 helped authoring this commit.
genixpro added a commit that referenced this pull request Sep 9, 2026
)

* Anchor an entering unit's sprite on its own tile, not its map slot

PR #218 changed Game::drawUnit to derive the sprite origin from the tile the
draw loop found the unit on (`px = x * 32`) instead of converting
unit->posX/posY, so that a unit sitting on a map seam keeps the copy at
the opposite screen edge instead of collapsing to one occurrence.

Those two tiles agree for every action that clears the old map slot and
claims the destination one. Entering a building is the deliberate
exception: Unit::handleActionEnteringBuilding leaves the map slot on the
tile the unit is leaving so the unit stays drawable, while posX/posY
already name the building tile. Game::integrity() enforces exactly this
(test/EnteringUnitSaveHarness.cpp: "entering unit registered at
destination is invalid"). Anchoring on the stale slot ran the arrival
interpolation `px -= dx*(255-delta)>>3` one square early, so a glob
snapped back a square and walked into the tile it came from.

Keep the per-occurrence anchor and recover the unit's own tile from it by
folding in the signed wrapped offset to posX/posY — the same
anchor-recovery idiom PR #218 uses for building footprints in
drawMapGroundBuildings, but signed, because a unit's slot can sit one
square behind its position as well as ahead of it.

The arithmetic lives in src/render/UnitDrawGeometry.h so it can be tested
without a GraphicContext; UnitDrawGeometryTest covers the coinciding
case, all eight entry directions, and the seam occurrences on their own
and combined with an entry across the seam.

Fixes #230.

Opus 5 helped authoring this commit.

* Render the enter-the-building step and compare it against the same walk

UnitDrawGeometryTest pins the arithmetic, but nothing checked that the real
render path puts the glob where the arithmetic says. This adds a GL harness
that draws the state issue #230 is about and compares framebuffers.

A unit on its final step into a building keeps its map slot on the tile it is
leaving while posX/posY already name the building tile, so the draw loop visits
it one square behind itself. Nothing in Game::drawUnit reads displacement, so at
equal delta that state must render pixel-for-pixel like the same step expressed
as an ordinary walk onto the destination tile. The harness renders both over
five points of one step and reports any difference in pixels against the 32 px
tile size.

Against the pre-fix anchor it reports exactly -32 px at delta 0 — one tile
backwards, which is the reported symptom. With the fix all five deltas match.

The comparison uses the unit-only render, which has no animated water or clouds
to make two frames differ by themselves; a second pass captures terrain, glob
and inn together as scene-delta<N>.png purely so the animation can be looked at
by eye.

CI already installs xvfb and mesa for the fullscreen aspect harness, so wiring
this in is a two-liner; test/README.md carries the step verbatim. It is not
applied here because the push token has no workflow scope.

Opus 5 helped authoring this commit.

---------

Co-authored-by: Bradley Arsenault <brad@bradleyarsenault.me>
genixpro added a commit that referenced this pull request Sep 10, 2026
Giszmo's smoke test found units carrying a visible dark square in software
rendering, worse at high game speed. The manual per-pixel blend in
DrawableSurface::drawSurface computed x>>8 (divide by 256) instead of an
accurate x/255 wherever it combined a source/dest channel pair, including
when the source pixel's own alpha is 0. A single blend's ~0.4% bias is
invisible, but each motion-blur shutter step is one more `drawSurface` call
onto the same footprint, and at a wide shutter (high game speed) dozens of
these compound multiplicatively -- darkening the sprite's whole bounding
box, transparent edges included, into the reported square.

Replaced the >>8 with the standard (x+1+(x>>8))>>8 identity, which equals
round(x/255) exactly for x in [0, 65025]; applied per-lane with the same
0x00FF00FF masking the existing code already uses to keep the two packed
channels from carrying into each other. Verified directly: 60 stacked
partial-alpha draws over an opaque background drifted from 200 to 140
before this fix and hold exactly at 200 after. New DrawableSurfaceBlendTest
(wired into unit-blur-tests and CI) checks both that fully-transparent
pixels never perturb the destination under many stacked draws, and that a
half-opaque source converges to a stable value rather than drifting.

Checked the other bug from the same review round (illegible "GL only" zoom
label on high-res screens, MapZoomControls.h): that file predates this PR
entirely (`3ad40cf3b`, already on master via #218), matching Giszmo's own
"probably independent bug of this branch" note -- left alone here rather
than folding an unrelated fix into this PR's diff.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01TU4ZDnBKJKtfgGUNgsx194
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant