From b169077a40ca0ba5b7505f155855059c586e8145 Mon Sep 17 00:00:00 2001 From: Lars Mueller Date: Wed, 24 May 2023 21:09:24 +0200 Subject: [PATCH] Refactor texmod:calc_dims to use a dispatch table --- minetest/texmod.lua | 2 +- minetest/texmod/calc_dims.lua | 127 ++++++++++++++++++++-------------- minetest/texmod/dsl.lua | 2 +- minetest/texmod/write.lua | 4 +- 4 files changed, 79 insertions(+), 56 deletions(-) diff --git a/minetest/texmod.lua b/minetest/texmod.lua index 2409708..53566f0 100644 --- a/minetest/texmod.lua +++ b/minetest/texmod.lua @@ -8,7 +8,7 @@ end local texmod, metatable = component"dsl" texmod.write = component"write" texmod.read = component("read", texmod) -texmod.calc_dims = component"calc_dims" +texmod.calc_dims = component("calc_dims", texmod) function metatable:__tostring() local rope = {} diff --git a/minetest/texmod/calc_dims.lua b/minetest/texmod/calc_dims.lua index 0c12166..a59d4eb 100644 --- a/minetest/texmod/calc_dims.lua +++ b/minetest/texmod/calc_dims.lua @@ -1,54 +1,77 @@ --- TODO ensure completeness, use table of dim calculation functions -local base_dims = modlib.table.set({ - "opacity", - "invert", - "brighten", - "noalpha", - "makealpha", - "lowpart", - "mask", - "colorize", -}) -local floor, max, clamp = math.floor, math.max, modlib.math.clamp -local function next_pow_of_2(x) - -- I don't want to use a naive 2^ceil(log(x)/log(2)) due to possible float precision issues. - local m, e = math.frexp(x) -- x = _*2^e, _ in [0.5, 1) - if m == 0.5 then e = e - 1 end -- x = 2^(e-1) - return math.ldexp(1, e) -- 2^e, premature optimization here we go +local texmod = ... + +local cd = {} + +local function calc_dims(self, get_file_dims) + return assert(cd[self.type])(self, get_file_dims) end -return function(self, get_file_dims) - local function calc_dims(self) - local type = self.type - if type == "filename" then - return get_file_dims(self.filename) - end if base_dims[type] then - return calc_dims(self.base) - end if type == "resize" or type == "combine" then - return self.w, self.h - end if type == "overlay" then - local base_w, base_h = calc_dims(self.base) - local overlay_w, overlay_h = calc_dims(self.over) - return max(base_w, overlay_w), max(base_h, overlay_h) - end if type == "transform" then - if self.rotation_deg % 180 ~= 0 then - local base_w, base_h = calc_dims(self.base) - return base_h, base_w - end - return calc_dims(self.base) - end if type == "inventorycube" then - local top_w, top_h = calc_dims(self.top) - local left_w, left_h = calc_dims(self.left) - local right_w, right_h = calc_dims(self.right) - local d = clamp(next_pow_of_2(max(top_w, top_h, left_w, left_h, right_w, right_h)), 2, 64) - return d, d - end if type == "verticalframe" or type == "crack" or type == "cracko" then - local base_w, base_h = calc_dims(self.base) - return base_w, floor(base_h / self.framecount) - end if type == "sheet" then - local base_w, base_h = calc_dims(self.base) - return floor(base_w / self.w), floor(base_h / self.h) - end - error("unsupported texture modifier: " .. type) + +function cd:file(d) + return d(self.filename) +end + +do + local function base_dim(self, get_dims) return calc_dims(self.base, get_dims) end + cd.opacity = base_dim + cd.invert = base_dim + cd.brighten = base_dim + cd.noalpha = base_dim + cd.makealpha = base_dim + cd.lowpart = base_dim + cd.mask = base_dim + cd.colorize = base_dim +end + +do + local function wh(self) return self.w, self.h end + cd.resize = wh + cd.combine = wh +end + +function cd:overlay(get_dims) + local base_w, base_h = calc_dims(self.base, get_dims) + local over_w, over_h = calc_dims(self.over, get_dims) + return math.max(base_w, over_w), math.max(base_h, over_h) +end + +function cd:transform(get_dims) + if self.rotation_deg % 180 ~= 0 then + local base_w, base_h = calc_dims(self.base, get_dims) + return base_h, base_w end - return calc_dims(self) -end \ No newline at end of file + return calc_dims(self.base, get_dims) +end + +do + local math_clamp = modlib.math.clamp + local function next_pow_of_2(x) + -- I don't want to use a naive 2^ceil(log(x)/log(2)) due to possible float precision issues. + local m, e = math.frexp(x) -- x = _*2^e, _ in [0.5, 1) + if m == 0.5 then e = e - 1 end -- x = 2^(e-1) + return math.ldexp(1, e) -- 2^e, premature optimization here we go + end + function cd:inventorycube(get_dims) + local top_w, top_h = calc_dims(self.top, get_dims) + local left_w, left_h = calc_dims(self.left, get_dims) + local right_w, right_h = calc_dims(self.right, get_dims) + local d = math_clamp(next_pow_of_2(math.max(top_w, top_h, left_w, left_h, right_w, right_h)), 2, 64) + return d, d + end +end + +do + local function frame_dims(self, get_dims) + local base_w, base_h = calc_dims(self.base, get_dims) + return base_w, math.floor(base_h / self.framecount) + end + cd.verticalframe = frame_dims + cd.crack = frame_dims + cd.cracko = frame_dims +end + +function cd:sheet(get_dims) + local base_w, base_h = calc_dims(self.base, get_dims) + return math.floor(base_w / self.w), math.floor(base_h / self.h) +end + +return calc_dims \ No newline at end of file diff --git a/minetest/texmod/dsl.lua b/minetest/texmod/dsl.lua index 791252c..7d26453 100644 --- a/minetest/texmod/dsl.lua +++ b/minetest/texmod/dsl.lua @@ -12,7 +12,7 @@ setmetatable(texmod, {__call = new}) function texmod.file(filename) return new{ - type = "filename", + type = "file", filename = filename } end diff --git a/minetest/texmod/write.lua b/minetest/texmod/write.lua index 220a37f..ab3f62e 100644 --- a/minetest/texmod/write.lua +++ b/minetest/texmod/write.lua @@ -143,7 +143,7 @@ return function(self, write_str) w.str(("%d"):format(int)) end function w.tex(tex) - if tex.type == "filename" then + if tex.type == "file" then assert(not tex.filename:find"[:^\\&{[]", "invalid character in filename") w.str(tex.filename) return @@ -153,7 +153,7 @@ return function(self, write_str) w.hat() end if tex.type == "overlay" then - if tex.over.type ~= "filename" then -- TODO also exclude [png, [combine and [inventorycube (generators) + if tex.over.type ~= "file" then -- TODO also exclude [png, [combine and [inventorycube (generators) w.str"("; w.tex(tex.over); w.str")" else w.tex(tex.over)