Repository navigation
[M2-TILE-02] Parallax tile layers + tile animation - #80
Merged
Merged
Conversation
Tile animation: TileAnimationDef (frameCount, frameTicks, the M2-SPRITE-03 sheet layout), the pre-sized animation slot table (id 0 = static sentinel; 1..maxAnimations), setAnimation (setup path: validation, phase reset, frame UV precomputation), advanceAnimations (once per sim tick, ARCH-002; frame = ticks / frameTicks mod frameCount), hasAnimation/animationAt/ animationFrame, the declared quad's current frame (static fixed UV or the animation's frame UV + frameIndex), and the animationId domain in setTile/rebuild (0..maxAnimations; whole span validated). Parallax tile layer: TileMap::declareTo overload for a ParallaxLayers Tilemap-source layer (M2-PAR-01 hook) — quads translated by the layer's worldOffset(cameraPos), keys the M2-ISO-01 keys of the translated centers at the tilemap's own layer (the def's depthLayer must equal it — scene-setup convention); built frame / unset id / non-tilemap source -> InvalidArgument; disabled layer declares nothing (OK). No GL, no per-frame allocation (FR-2.2), no budgets.json entry (part of the composite 50k budget). Tests: new ctest entry tilemap_anim (12 tests / 6 suites, both backends — validation matrix, documented-rate cycle, frame-UV goldens, golden parallax offsets at given camera positions + oracle, protocol, zero-alloc loop); tilemap_tests updated to the static-sentinel semantics. Docs: tilemap.md (major), parallax.md, coordinates.md, docs/README, module README, roadmap board + change log. laige-api.json regenerated (1315 -> 1342 symbols).
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
M2-TILE-02 · Parallax tile layers + tile animation (FR-2.6)
Depends: M2-TILE-01, M2-PAR-01 (both merged). Scope only — nothing else.
Tile animation (data-driven frame cycling)
TileAnimationDef—frameCount(1..kTileAnimMaxFrames= 64),frameTicks(the documented rate: simulation ticks per frame, ≥ 1), the tile sheet'sSpriteFrameLayout(M2-SPRITE-03, texels).TileMap::Options::maxAnimations(1..kTileMapMaxAnimations= 256, default 8) — validated FIRST increate; the animation slot table is pre-sized at creation (id 0 = the static sentinel; 1..maxAnimations = animation slots). The tile'sanimationIdis now consumed by the batch path (no longer inert data — existing tilemap goldens updated to static tiles).setAnimation(id, def)— setup/config path (the parallaxsetLayerprecedent): first-failure-wins validation (id domain → frame count → tick rate → sheet extents → frameCount ≤ sheet frames → tight-sheet float-exact domain with the adversarial-layout u64 overflow guards), no log, rejected sets leave the slot unchanged; a success resets the phase and precomputes all frame UVs (the only per-animation allocation).advanceAnimations()— called once per sim tick (ARCH-002, never per render frame): every set animation's frame steps everyframeTicksticks, wrapping atframeCount(frame(ticks) = (ticks / frameTicks) mod frameCount). O(maxAnimations), zero allocation, no GL. Per-animation phase (all tiles of one animation in phase; per-tile offsets are the M3 editor's control). Frame state is presentation state (ARCH-009).DeclareOptions::uv+frameIndex0; the animated tile carries its animation's current frame UV (precomputed) +frameIndex. An animated tile whose slot is unset fails the declare (first failure wins).setTile/rebuildgained theanimationId ≤ maxAnimationscheck (whole span validated before any write).Parallax tile layer (the M2-PAR-01 Tilemap-source hook, implemented)
TileMap::declareTo(batcher, options, layers, layerId, cameraPos)— every quad translated by the layer'sworldOffset(cameraPos)(the M2-PAR-01 formula (1)); its key is the M2-ISO-01 key of the translated center at the tilemap's ownOptions::layer(scene-setup convention: the def'sdepthLayermust equal the tilemap'slayer— bg/mid/fg tilemaps get −2/−1/+1). Translated keys computed per tile per frame (camera-dependent — O(tileCount), zero allocation; the qBase + qOffset derivation is the documented upgrade path).InvalidArgument; a disabled layer declares nothing (OK — the layer's documented skip).Constraints honored
setAnimation, slot table atcreate— zero-alloc proof test: 1000 frames × (256 + 64 parallax tiles) of advance + declare + build under the owner-thread allocation window.budgets.jsonentry (count stays 16): the per-frame cost is part of the composite 50k render-CPU budget (M2-PERF-01).Tests — new ctest entry
tilemap_anim(12 tests / 6 suites, both backends, no GL)TileMapAnimSet— thesetAnimationvalidation matrix (slot domain, frameCount [1,64] boundaries, tick rate, sheet domains, the adversarial tight-sheet overflow, rejected-set-leaves-no-state + phase reset) + no-log happy path.TileMapAnimCycle— the frame cycle at the documented rate, hand-computedframe = ticks / frameTicks mod frameCountover two independent animations.TileMapAnimDeclare— hand-computed frame-UV goldens (M2-SPRITE-03 tight-sheet formula), frameIndex, (atlas, material, blend) groups, the wrap, cross-frame bit-identical determinism.TileMapAnimParallax— golden-verified offsets at given camera positions (factor 0.25, center (4,4), offset (1,2); camera (10,6) → offset (2.5,2.5)) + hand-computed layer (−2) key goldens (0x7FA00060/0x7FA00070 — the 2^21 bias adds into bit 21) + the independent oracle (isoDepthKeyon the translated centers, both backends) + layer-dominance ordering + the protocol paths + the animated tile under the translation.TileMapAnimProtocol— theanimationIdedit/load domain (out-of-range rejected, no state change) + the unset-slot declare failure.TileMapAnimZeroAlloc— the 1000-frame advance + declare zero-allocation loop (standalone + parallax).Existing
tilemapsuites updated to the new static-sentinel semantics.Verification
tilemap_animentry).ctest -R tilemap_animgreen (12/12);ctest -R tilemapgreen (the unanchored regex also selectstilemap_anim— intended, documented in CMakeLists).laige-api.jsonregenerated last (1315 → 1342 symbols / 40 headers);api-real-tree/api-check-fresh,tools/laige-include-lint(69 files),tools/laige-determinism-lint(28 files, 0 violations) all green.docs/api/tilemap.md(major),docs/api/parallax.md+parallax.hhook comments,docs/concepts/coordinates.md(§4.9/§4.10/§5),docs/README.md,src/laige-render/README.md.