mirror of
https://github.com/DramaticShape/DramaticShapeVoxelMod.git
synced 2026-08-12 21:00:51 +02:00
66 lines
2.5 KiB
Lua
66 lines
2.5 KiB
Lua
-- Voxel world mode: decoded pixels, kept.
|
|
--
|
|
-- Assets.imageData is deliberately uncached upstream -- "pixel-level reads
|
|
-- resolve the same way but stay uncached: the caller keeps the derived
|
|
-- product" (src/render/Assets.lua) -- which is the right contract for the
|
|
-- flat renderer, whose one caller decodes a strip once and keeps the strip.
|
|
--
|
|
-- This mod is not that caller. It reads the same handful of images over and
|
|
-- over, from several places that do not know about each other:
|
|
--
|
|
-- * the tileset atlas, decoded by Structures (its own cache), by
|
|
-- TerrainAtlas twice (the SGB bake and the RED++ rebake), by
|
|
-- TerrainAtlas again to learn a tile's shades, and by GlassMask;
|
|
-- * the FLOWER FRAME files, decoded inside patch() -- which runs every
|
|
-- time the animation step turns over, about three times a second, for
|
|
-- as long as the map is on screen. That one is not a load cost at all,
|
|
-- it is a recurring per-second cost on the render thread, and it was
|
|
-- the single clearest waste the first profile turned up.
|
|
--
|
|
-- So: one table, keyed by the path as the CALLER gave it, holding the
|
|
-- decoded ImageData. Registered with Assets.invalidate so a hot reload
|
|
-- drops it alongside every other downstream cache.
|
|
--
|
|
-- The entries are never evicted by size. That is deliberate and bounded:
|
|
-- what lands here is tileset art and animation frames -- a few dozen small
|
|
-- images for a whole session, tens of kilobytes each -- not per-map bakes,
|
|
-- which have their own eviction in TerrainAtlas.setLive.
|
|
|
|
-- the mod namespace (see main.lua): V.require loads a sibling module
|
|
local V = ...
|
|
|
|
local Assets = require("src.render.Assets")
|
|
local Perf = V.require("Perf")
|
|
|
|
local ImageCache = {}
|
|
|
|
local cache = {}
|
|
|
|
-- The decoded pixels for `path`, or nil when it cannot be read.
|
|
--
|
|
-- `false` is cached for an unreadable path, so a missing or corrupt asset
|
|
-- costs one failed decode for the session rather than one per frame -- the
|
|
-- same sticky-failure shape the rest of this mod uses for GPU objects.
|
|
function ImageCache.get(path)
|
|
if not path then return nil end
|
|
local hit = cache[path]
|
|
if hit ~= nil then
|
|
Perf.count("imageCache.hit")
|
|
return hit or nil
|
|
end
|
|
local t0 = Perf.now()
|
|
local ok, data = pcall(Assets.imageData, path)
|
|
Perf.add("ImageCache.decode", t0)
|
|
Perf.count("imageCache.miss")
|
|
cache[path] = (ok and data) or false
|
|
return cache[path] or nil
|
|
end
|
|
|
|
function ImageCache.invalidate()
|
|
cache = {}
|
|
end
|
|
|
|
Assets.register(ImageCache.invalidate)
|
|
|
|
return ImageCache
|