voxelizer/texture_reader.lua

131 lines
4.2 KiB
Lua

local os_execute = ...
local vector = modlib.vector
function rgba_number_to_table(number)
local b = number % 256
local g = math.floor(number / 256) % 256
local r = math.floor(number / 256 / 256) % 256
local a = math.floor(number / 256 / 256 / 256) % 256
return {a, r, g, b}
end
function rgb_number_to_table(number)
local b = number % 256
local g = math.floor(number / 256) % 256
local r = math.floor(number / 256 / 256) % 256
return {r, g, b}
end
function rgba_tuple_to_number(a, r, g, b)
return a*256*256*256+r*256*256+g*256+b
end
function rgba_table_to_number(table)
return rgba_tuple_to_number(unpack(table))
end
function rgb_tuple_to_number(r, g, b)
return r*256*256+g*256+b
end
function rgb_table_to_number(table)
return rgb_tuple_to_number(unpack(table))
end
function get_texture_color_at(texture, x, y)
return texture[x+y*texture.width+1]
end
function set_texture_color_at(texture, x, y, color)
texture[x+y*texture.width+1] = color
end
function in_bounds(texture, x, y)
return x >= 0 and y >= 0 and x < texture.width and y < texture.height
end
function nearest_filtering(texture, pos_uv)
local x = math.min(math.floor(pos_uv[1]*texture.width), texture.width-1)
local y = math.min(math.floor((1-pos_uv[2])*texture.height), texture.height-1)
return get_texture_color_at(texture, x, y)
end
function bilinear_filtering(texture, pos_uv)
local x = pos_uv[1]*texture.width
local x_line = modlib.number.round(x)
local y = (1-pos_uv[2])*texture.height
local y_line = modlib.number.round(y)
local affected, affected_alpha = 0, 0
local avg_alpha = 0
local avg = {0, 0, 0}
for xf = -1, 1, 2 do
local px = x+xf*0.5
local f1 = math.max(0, xf*x_line-px)
for xf = -1, 1, 2 do
local py = y+xf*0.5
local f2 = math.max(0, xf*y_line-py)
local factor = f1 * f2
if factor > 0 then
local a, r, g, b = unpack(get_texture_color_at(texture, math.floor(px), math.floor(py)))
affected = affected + factor * a
avg = vector.add(avg, vector.multiply_scalar({r, g, b}, factor * a))
affected_alpha = affected_alpha + factor
avg_alpha = avg_alpha + factor * a
end
end
end
avg_alpha = avg_alpha / affected_alpha
avg = vector.divide_scalar(avg, affected)
local color = {avg_alpha, unpack(avg)}
return color
end
local errors = {
"Output and input path need to be given",
"Couldn't create output file",
"Output or input file doesn't exist or can't be read/written",
"File couldn't be written"
}
function read_texture(path_to_texture)
local last_dot
for i = path_to_texture:len(), 1, -1 do
if path_to_texture:sub(i, i) == "." then
last_dot = i
break
elseif path_to_texture:sub(i, i) == "/" then
break
end
end
local path_to_output
if path_to_texture:sub(last_dot+1):lower() == "sif" then -- we can assume it's already .sif
path_to_output = path_to_texture
else -- else, convert
if not last_dot then
path_to_output = path_to_texture..".sif"
else
path_to_output = path_to_texture:sub(1, last_dot-1)..".sif"
end
local response_code = os_execute("java", "-classpath", minetest.get_modpath("voxelizer").."/production", "TextureLoader", path_to_texture, path_to_output)
if response_code ~= 0 then
return errors[response_code] or "Texture couldn't be converted"
end
end
local texture_content = io.open(path_to_output, "rb")
-- Image ending : .sif (Simple Image Format)
-- 4 bytes image header (2 bytes width, 2 bytes height)
-- Content : 4 byte ARGB colors
local image={}
image.width = texture_content:read(1):byte()*255+texture_content:read(1):byte()
image.height = texture_content:read(1):byte()*255+texture_content:read(1):byte()
local bytes = texture_content:read("*all")
for i=1, bytes:len(), 4 do
table.insert(image, rgba_tuple_to_number(bytes:byte(i), bytes:byte(i+1), bytes:byte(i+2), bytes:byte(i+3)))
end
texture_content:close()
return image
end