Iterate layers in z-order with entity-slot split; multi-layer draw_map
Adds LAYER_ORDER_PRE/POST_ENTITIES constants, iterate_layers_pre/post_entities helpers, draw_layer and draw_v1_legacy locals, and draw_map_pre/post_entities public functions. draw_map becomes a backward-compat wrapper over both. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
158
init.lua
158
init.lua
@@ -99,6 +99,10 @@ end
|
|||||||
-- Schema-v2 Layer-Whitelist + Validation
|
-- Schema-v2 Layer-Whitelist + Validation
|
||||||
-- =====================================================================
|
-- =====================================================================
|
||||||
|
|
||||||
|
-- Layer z-order (back-to-front) split at entity slot
|
||||||
|
local LAYER_ORDER_PRE_ENTITIES = { "foundation", "subsurface", "surface", "topsurface" }
|
||||||
|
local LAYER_ORDER_POST_ENTITIES = { "lower_wall", "wall", "upper_wall", "canopy" }
|
||||||
|
|
||||||
local VALID_LAYER_NAMES = {
|
local VALID_LAYER_NAMES = {
|
||||||
foundation = true,
|
foundation = true,
|
||||||
subsurface = true,
|
subsurface = true,
|
||||||
@@ -289,6 +293,80 @@ local function build_map_v2(t_map, resolved_atlases)
|
|||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- =====================================================================
|
||||||
|
-- Internal render helpers (draw_layer, draw_v1_legacy)
|
||||||
|
-- These must be declared before the public draw_map* functions that call them.
|
||||||
|
-- =====================================================================
|
||||||
|
|
||||||
|
local function draw_layer(m, layer_name)
|
||||||
|
local layer = m.layers[layer_name]
|
||||||
|
if not layer then return end
|
||||||
|
local sz = m.size
|
||||||
|
local ts = m.tile_size
|
||||||
|
for y = 0, sz.h - 1 do
|
||||||
|
for x = 0, sz.w - 1 do
|
||||||
|
local idx = y * sz.w + x + 1
|
||||||
|
local gid = layer.tiles[idx] or 0
|
||||||
|
if gid ~= 0 then
|
||||||
|
local atlas_idx, tile_id, rot_quad = decode_gid(gid)
|
||||||
|
local atlas = m.atlases[atlas_idx + 1]
|
||||||
|
if atlas then
|
||||||
|
local tile = atlas.tiles[tile_id]
|
||||||
|
if tile then
|
||||||
|
local px = x * ts
|
||||||
|
local py = y * ts
|
||||||
|
local rot_deg = rot_quad * 90.0
|
||||||
|
if tile.texture_handle then
|
||||||
|
engine.render.draw_sprite_transform(
|
||||||
|
tile.texture_handle,
|
||||||
|
px + ts / 2, py + ts / 2,
|
||||||
|
math.rad(rot_deg),
|
||||||
|
1.0, 1.0,
|
||||||
|
ts / 2, ts / 2,
|
||||||
|
0xFFFFFFFF
|
||||||
|
)
|
||||||
|
else
|
||||||
|
local c = tile.color or { 100, 100, 100 }
|
||||||
|
engine.render.draw_rect(px, py, ts, ts,
|
||||||
|
engine.render.rgb(c[1], c[2], c[3]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function draw_v1_legacy(m)
|
||||||
|
local tm = m.tilemap
|
||||||
|
if not tm then return end
|
||||||
|
local ts = tm.tile_size
|
||||||
|
for y = 0, m.size.h - 1 do
|
||||||
|
for x = 0, m.size.w - 1 do
|
||||||
|
local idx = y * m.size.w + x + 1
|
||||||
|
local tile_id = m.tiles[idx]
|
||||||
|
local tile = tm.tiles[tile_id]
|
||||||
|
local rot_deg = (m.tile_rotations and m.tile_rotations[idx]) or 0
|
||||||
|
local px = x * ts
|
||||||
|
local py = y * ts
|
||||||
|
if tile.texture_handle then
|
||||||
|
engine.render.draw_sprite_transform(
|
||||||
|
tile.texture_handle,
|
||||||
|
px + ts / 2, py + ts / 2,
|
||||||
|
math.rad(rot_deg),
|
||||||
|
1.0, 1.0,
|
||||||
|
ts / 2, ts / 2,
|
||||||
|
0xFFFFFFFF
|
||||||
|
)
|
||||||
|
else
|
||||||
|
local c = tile.color or { 100, 100, 100 }
|
||||||
|
engine.render.draw_rect(px, py, ts, ts,
|
||||||
|
engine.render.rgb(c[1], c[2], c[3]))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
-- =====================================================================
|
-- =====================================================================
|
||||||
-- Public API
|
-- Public API
|
||||||
-- =====================================================================
|
-- =====================================================================
|
||||||
@@ -549,37 +627,57 @@ function M.load_textures(asset_aliases)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function M.iterate_layers_pre_entities(fn, map_id)
|
||||||
|
local id = map_id or current_map_id
|
||||||
|
if not id then error("maps.iterate_layers_pre_entities: no current map") end
|
||||||
|
local m = map_registry[id]
|
||||||
|
if m.schema_version ~= 2 then
|
||||||
|
-- v1 (legacy): only surface conceptually
|
||||||
|
fn("surface")
|
||||||
|
return
|
||||||
|
end
|
||||||
|
for _, name in ipairs(LAYER_ORDER_PRE_ENTITIES) do
|
||||||
|
if m.layers[name] then fn(name) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.iterate_layers_post_entities(fn, map_id)
|
||||||
|
local id = map_id or current_map_id
|
||||||
|
if not id then error("maps.iterate_layers_post_entities: no current map") end
|
||||||
|
local m = map_registry[id]
|
||||||
|
if m.schema_version ~= 2 then return end -- v1 has nothing post
|
||||||
|
for _, name in ipairs(LAYER_ORDER_POST_ENTITIES) do
|
||||||
|
if m.layers[name] then fn(name) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.draw_map_pre_entities()
|
||||||
|
local id = current_map_id
|
||||||
|
if id == nil then return end
|
||||||
|
local m = map_registry[id]
|
||||||
|
if m.schema_version ~= 2 then
|
||||||
|
draw_v1_legacy(m)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
for _, name in ipairs(LAYER_ORDER_PRE_ENTITIES) do
|
||||||
|
if m.layers[name] then draw_layer(m, name) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function M.draw_map_post_entities()
|
||||||
|
local id = current_map_id
|
||||||
|
if id == nil then return end
|
||||||
|
local m = map_registry[id]
|
||||||
|
if m.schema_version ~= 2 then return end
|
||||||
|
for _, name in ipairs(LAYER_ORDER_POST_ENTITIES) do
|
||||||
|
if m.layers[name] then draw_layer(m, name) end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
-- Backward-compat: draw_map renders everything (pre + post, no entity slot)
|
||||||
function M.draw_map()
|
function M.draw_map()
|
||||||
local map_id = M.current()
|
M.draw_map_pre_entities()
|
||||||
if map_id == nil then return end
|
M.draw_map_post_entities()
|
||||||
local m = map_registry[map_id]
|
|
||||||
local tm = m.tilemap
|
|
||||||
local ts = tm.tile_size
|
|
||||||
for y = 0, m.size.h - 1 do
|
|
||||||
for x = 0, m.size.w - 1 do
|
|
||||||
local idx = y * m.size.w + x + 1
|
|
||||||
local tile_id = m.tiles[idx]
|
|
||||||
local tile = tm.tiles[tile_id]
|
|
||||||
local rot_deg = (m.tile_rotations and m.tile_rotations[idx]) or 0
|
|
||||||
local px = x * ts
|
|
||||||
local py = y * ts
|
|
||||||
if tile.texture_handle then
|
|
||||||
-- Sprite mode: draw_sprite_transform with rotation about tile center.
|
|
||||||
engine.render.draw_sprite_transform(
|
|
||||||
tile.texture_handle,
|
|
||||||
px + ts / 2, py + ts / 2,
|
|
||||||
math.rad(rot_deg),
|
|
||||||
1.0, 1.0,
|
|
||||||
ts / 2, ts / 2,
|
|
||||||
0xFFFFFFFF
|
|
||||||
)
|
|
||||||
else
|
|
||||||
-- Color fallback (Phase 1 mode).
|
|
||||||
local c = tile.color or { 100, 100, 100 }
|
|
||||||
engine.render.draw_rect(px, py, ts, ts, engine.render.rgb(c[1], c[2], c[3]))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Forward-compat stubs (DEPRECATED-MVP — implemented in later slices)
|
-- Forward-compat stubs (DEPRECATED-MVP — implemented in later slices)
|
||||||
|
|||||||
Reference in New Issue
Block a user