mirror of
https://github.com/DramaticShape/DramaticShapeVoxelMod.git
synced 2026-08-12 13:00:50 +02:00
97 lines
3.9 KiB
Lua
97 lines
3.9 KiB
Lua
-- 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" })
|
|
|
|
-- A pass that needs the wireframe whatever the player left the row on sets
|
|
-- this for the length of its own draw and puts it back after. nil means
|
|
-- "follow the setting", which is every frame outside such a pass.
|
|
--
|
|
-- The overworld battle is the one user: a fight is a STAGED shot, not the
|
|
-- world being walked around in, and the seams are what make it read as
|
|
-- constructed rather than as a photograph of somewhere. The row still owns
|
|
-- what free-roam looks like, and is not written to -- switching the mode off
|
|
-- mid-battle would silently rewrite the player's own setting.
|
|
VoxelGrid.override = nil
|
|
|
|
function VoxelGrid.enabled()
|
|
if VoxelGrid.override ~= nil then return VoxelGrid.override end
|
|
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
|