1
0
mirror of https://github.com/Tolik-Trek/DOOM2.git synced 2026-06-15 00:51:33 +03:00
DOOM2/Resources/tools/gen_d2_table/gen_d2_table.lua

179 lines
7.7 KiB
Lua
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

-- =====================================================================
-- Генератор d2_table.tbl (рейкастер DOOM2 / Sprinter Sp2000)
-- 16-шаговая ближняя зона, формат-совместимый с Bin/d2_table.tbl.
--
-- Запуск:
-- sjasmplus --nologo Resources/tools/gen_d2_table/gen_d2_table.asm
-- (из КОРНЯ проекта; эмулятор не нужен)
--
-- Вход: нет.
-- Выход: Build/d2_table.gen.tbl
-- (Bin/d2_table.tbl — канонический рабочий ассет, не трогаем).
--
-- Документация формата и математики: INFO/doom-энжин.md.
--
-- ФОРМАТ (как в оригинале):
-- * 524288 байт = 32 страницы по 16384 (PAGE).
-- * Страницы парами CORNER=0..15: чётная = «offset», нечётная = «projection».
-- * Каждая страница = 512 записей по 32 байта (REC).
-- * Запись (32 б):
-- EVEN: byte[0..15] = низкий байт адреса DDA-клетки в отн.карте
-- TABLE_W (квадрант 16×16, страйд 1, base=#2000+QUAD*256);
-- byte[16..31] = 0.
-- ODD : byte[0..15] = код высоты (индекс в table_x.tbl);
-- byte[16..31] = текстурная u-координата столбца стены.
-- * Адресация записи в кадре: H ∈ #40..#7F (6 бит = крупный угол
-- внутри квадранта), L_top3 ∈ {0,32,…,224} (3 бита = подгруппа
-- колонок); вместе 64×8 = 512 = страница. За кадр движок проходит
-- 40 H × 8 L = 320 экранных лучей (60°/90° квадранта).
--
-- МАТЕМАТИКА (см. INFO/doom-энжин.md §«Закон проекции»):
-- * supercover-DDA, tie tx<=ty -> X (как в оригинале).
-- * перспектива по перпендикулярной дистанции: N = K / perp, K=315;
-- perp = d_eucl * cos(ray_ang - view_ang) (fisheye-фикс).
-- * height_code = index в table_x.tbl, грубо A = clamp((256-N)/2, 0..127).
-- * u_col = round(u_fraction * 64) & 63.
--
-- CORNER (0..15) кодирует субпозицию игрока в клетке (4×4).
-- Запись (record_idx 0..511) кодирует «виртуальный экранный угол»
-- внутри квадранта: ray_ang = (record_idx + 0.5)/512 * (pi/2).
-- =====================================================================
local PAGES = 32
local PAGE = 16384
local REC = 32
local RECS = PAGE // REC -- 512
local STEPS = 16
local SUBPOS = 16
local GRID = 16 -- TABLE_W квадрант = 16×16
local K_PROJ = 315.0
local FOV_R = math.pi / 3.0 -- 60°
local SCR_W = 320
local QUAD = math.pi / 2.0 -- 90°
local OUT = "Build/d2_table.gen.tbl"
-- Субпозиция CORNER=0..15 -> (sx, sy) в [0..1] (углы 1/8 от стенки).
local function corner_xy(c)
local sx = (c % 4) / 4.0 + 1.0 / 8.0
local sy = (c // 4) / 4.0 + 1.0 / 8.0
return sx, sy
end
-- supercover-DDA, 16 шагов. Возвращает массив { {cx,cy,d_eucl,u}, ... }.
-- Ось +X = «вперёд» (вид игрока). cx,cy — клеточные координаты относит.
-- стартовой клетки (в которой игрок).
local function trace(sx, sy, ang)
local dx = math.cos(ang); if math.abs(dx) < 1e-9 then dx = (dx < 0 and -1e-9 or 1e-9) end
local dy = math.sin(ang); if math.abs(dy) < 1e-9 then dy = (dy < 0 and -1e-9 or 1e-9) end
local x, y = sx, sy
local cx, cy = math.floor(x), math.floor(y)
local out = {}
for _ = 1, STEPS do
local nx = cx + (dx > 0 and 1 or 0)
local ny = cy + (dy > 0 and 1 or 0)
local tx = (nx - x) / dx
local ty = (ny - y) / dy
local u
if tx <= ty then
x = nx; y = y + dy * tx; cx = cx + (dx > 0 and 1 or -1)
u = y - math.floor(y)
else
y = ny; x = x + dx * ty; cy = cy + (dy > 0 and 1 or -1)
u = x - math.floor(x)
end
local de = math.sqrt((x - sx)^2 + (y - sy)^2)
out[#out + 1] = { cx, cy, de, u }
end
return out
end
-- offset байта = (cy & (GRID-1)) * GRID + (cx & (GRID-1))
-- (вне квадранта 16×16 «оборачиваем» по 8-битной арифметике
-- движка; реальный движок попадает в нулевые ячейки relmap).
local function off_byte(cx, cy)
local oc = cx % GRID
local oy = cy % GRID
if oc < 0 then oc = oc + GRID end
if oy < 0 then oy = oy + GRID end
return (oy * GRID + oc) & 0xFF
end
local function height_code(N)
if N <= 256 then
local A = (256 - N) // 2
if A < 0 then A = 0 end
if A > 127 then A = 127 end
return A
end
-- full-screen с клипом: A = 128 + 6-битный буфер-offset (как в оригинале).
local over = (N - 256) // 8
if over > 63 then over = 63 end
return 128 + over
end
local function ucol(uf)
local v = math.floor(uf * 64.0 + 0.5)
return v & 63
end
-- Кадр движка читает 320 экранных лучей подряд из 512 записей. Поэтому
-- виртуальный угол луча в кадре = view_ang + atan2(cam_x, halfproj),
-- где cam_x шагает по 320. Но в таблице 512 записей покрывают 90° квадранта,
-- так что одной записи соответствует ray_ang = ((idx + 0.5)/512) * 90°
-- (без поправки fisheye-камеры — она применяется через perp ниже).
local function ray_angle(record_idx)
return (record_idx + 0.5) / RECS * QUAD
end
local function gen_pair(corner)
local sx, sy = corner_xy(corner)
local even = {}; for i = 1, PAGE do even[i] = 0 end
local odd = {}; for i = 1, PAGE do odd[i] = 0 end
-- view_ang = 0 (ось +X — вперёд); MAKE_MAP в движке поворачивает уровень
-- под квадрант. Луч ray_ang отсчитывается от +X.
for r = 0, RECS - 1 do
local ang = ray_angle(r)
local path = trace(sx, sy, ang)
local base = r * REC
for k = 1, STEPS do
local cx, cy, de, u = path[k][1], path[k][2], path[k][3], path[k][4]
-- EVEN: offset байт в relmap (TABLE_W) для шага k.
even[base + k] = off_byte(cx, cy)
-- ODD : код высоты + текстурная u.
local perp = de * math.cos(ang - 0.0) -- view_ang=0 -> perp=de*cos(ang)
if perp < 0.05 then perp = 0.05 end
local N = K_PROJ / perp
odd[base + k] = height_code(N) & 0xFF
odd[base + STEPS + k] = ucol(u)
end
end
return even, odd
end
local out = {}
for i = 1, PAGES * PAGE do out[i] = 0 end
for c = 0, SUBPOS - 1 do
local even, odd = gen_pair(c)
local eb = (c * 2) * PAGE
local ob = (c * 2 + 1) * PAGE
for i = 1, PAGE do
out[eb + i] = even[i]
out[ob + i] = odd[i]
end
end
do
local t = {}
for i = 1, #out do t[i] = string.char(out[i] & 0xFF) end
local w = io.open(OUT, "wb"); w:write(table.concat(t)); w:close()
end
print(string.format("[gen_d2_table] %s размер=%d б = %d страниц × %d б",
OUT, PAGES * PAGE, PAGES, PAGE))
print(string.format("[gen_d2_table] CORNER=0..15, 16 шагов, %d записей × %d б на страницу",
RECS, REC))
print("[gen_d2_table] NB: формат-совместим, но не бит-в-бит с Bin/d2_table.tbl")
print("[gen_d2_table] (оригинальный fixed-point утерян; см. INFO/doom-энжин.md).")