DramaticShapeVoxelMod archival mirror · read-only
lib/VoxelGrid.lua

VoxelGrid.lua

lib/VoxelGrid.lua3.7 KB100644fdaf68c087
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90
-- Voxel world mode: the voxel wireframe, 3D Dot Game Heroes style.
--
-- Every mesh in this mode is built on a one-unit-per-voxel grid in its OWN
-- model space -- terrain in world pixels, a character card in the sprite's
-- own pixels. So the seams are simply the
-- integer planes of that space, and drawing them is a pixel-shader job:
-- measure how far the fragment is from the nearest integer plane, in
-- DISPLAY pixels, and darken the ones within half a pixel of it. Sitting in
-- model space is what keeps the wireframe glued to a thing however it is
-- posed -- a character's card leans back by the camera's pitch and its
-- seams lean with it, instead of the world's grid sliding across the
-- sprite.
--
-- Deriving "in display pixels" needs shader derivatives (fwidth), which is
-- the one part of this that a driver can refuse. So the grid is a SECOND
-- COMPILATION of the scene shader rather than a branch inside the first
-- one: if it will not build, the mod loses the wireframe and nothing else
-- (see Voxel3D.shader).
--
-- This file owns the toggle rather than the drawing: the level, where it
-- persists, and the row the player finds it on.

-- the mod namespace (see main.lua): V.require loads a sibling module
local V = ...

local ModSetting = V.require("ModSetting")

local VoxelGrid = {}

-- the key under options.modOptions.DRAMATIC_SHAPE, shared by the row in
-- OPTIONS and the mod manager's own settings page for this mod
VoxelGrid.KEY = "grid"
VoxelGrid.LABEL = "V-GRID"

-- How far toward black a seam pulls the surface it cuts across. The
-- wireframe reads as a shading of the model rather than an overlay drawn
-- on top of it, so it darkens what is already there instead of painting a
-- colour -- a seam across dark grass and one across a white roof both stay
-- in the palette they belong to.
VoxelGrid.DARK = 0.45

-- Line width, in display pixels. The scene canvas renders at window
-- resolution and composites 1:1, so a canvas pixel IS a display pixel and
-- 1.0 here is the one-pixel wireframe.
VoxelGrid.WIDTH = 1.0

-- The same width in the CANVAS pixels the shader measures in, which is what
-- every sender of it actually wants.
--
-- The two are the same number until AA renders the pass larger than the
-- window (see AntiAlias): there a canvas pixel is a fraction of a display
-- one, and a width left at 1.0 would come out a half or a quarter of a line
-- after the fold -- the wireframe fading as the smoothing goes up, which
-- reads as one row breaking the other. Scaled, it stays a one-pixel seam and
-- simply gains the antialiasing everything else in the frame just gained.
function VoxelGrid.width()
  return VoxelGrid.WIDTH * V.require("AntiAlias").factor()
end

-- where it persists and the rows that cycle it (see ModSetting)
VoxelGrid.setting = ModSetting.new(VoxelGrid.KEY, VoxelGrid.LABEL,
                                   { false, true }, { "OFF", "ON" })

-- The row is the whole answer, everywhere: free-roam and the battle arena
-- alike. The battle used to force the seams on regardless -- a fight is a
-- STAGED shot, and the seams are what make it read as constructed rather
-- than photographed -- but a player who turns the wireframe off means the
-- whole mod, and a mode that came back for every fight read as the row not
-- working rather than as a deliberate framing.
function VoxelGrid.enabled()
  return VoxelGrid.setting:get() and true or false
end

function VoxelGrid.set(enabled, game)
  return VoxelGrid.setting:setIndex(enabled and 2 or 1, game)
end

function VoxelGrid.toggle(game)
  return VoxelGrid.setting:cycle(game)
end

function VoxelGrid.sync(value)
  VoxelGrid.setting:sync(value and true or false)
end

function VoxelGrid.row()
  return VoxelGrid.setting:row()
end

return VoxelGrid