165 lines
4.8 KiB
Lua
165 lines
4.8 KiB
Lua
local bar_size = 1 / 16
|
|
local bar_width = bar_size * 256 --[[px]]
|
|
assert(bar_width % 1 == 0)
|
|
local c_comp = { "r", "g", "g", "b", "b", "r" }
|
|
local x_comp = { "g", "r", "b", "g", "r", "b" }
|
|
|
|
local function get_gradient_texture(hue)
|
|
hue = hue * 6
|
|
local idx = 1 + math.floor(hue)
|
|
local mul_color = { r = 0, g = 0, b = 0 }
|
|
mul_color[c_comp[idx]] = 255
|
|
mul_color[x_comp[idx]] = math.floor(255 * (1 - math.abs(hue % 2 - 1)) + 0.5)
|
|
return ("epidermis_gradient_field_chroma.png^[multiply:%s^epidermis_gradient_field_m.png"):format(
|
|
modlib.minetest.colorspec.new(mul_color):to_string()
|
|
)
|
|
end
|
|
|
|
local function get_texture(hue)
|
|
return ("[combine:%dx256:0,0="):format(256 + bar_width)
|
|
.. get_gradient_texture(hue):gsub("[\\^:]", function(char)
|
|
return "\\" .. char
|
|
end) -- escape
|
|
.. ([[:256,0=epidermis_gradient_hue.png\^[transformR270\^[resize\:%dx256]]):format(bar_width)
|
|
end
|
|
|
|
local function get_uv(self, user)
|
|
if not (user and user:is_player()) then
|
|
return
|
|
end
|
|
local direction = modlib.vector.from_minetest(user:get_look_dir())
|
|
local rotation = self.object:get_rotation()
|
|
local rotation_axis, rotation_angle = epidermis.vector_axis_angle(rotation)
|
|
local normal = modlib.vector.new({ 0, 0, -1 }):rotate3(rotation_axis, rotation_angle)
|
|
if vector.dot(direction, normal) < 0 then
|
|
return -- Backface
|
|
end
|
|
local pos = self.object:get_pos()
|
|
local visual_size = modlib.vector.from_minetest(self.object:get_properties().visual_size)
|
|
local parent, _, position, _ = self.object:get_attach()
|
|
if parent then
|
|
pos = modlib.vector.from_minetest(vector.add(parent:get_pos(), vector.divide(position, 10)))
|
|
visual_size = visual_size * modlib.vector.from_minetest(parent:get_properties().visual_size)
|
|
end
|
|
local relative = modlib.vector.from_minetest(vector.subtract(moblib.get_eye_pos(user), pos))
|
|
local function transform(vertex)
|
|
return modlib.vector.rotate3(modlib.vector.multiply(vertex, visual_size), rotation_axis, rotation_angle)
|
|
end
|
|
local pos_on_ray, u, v = modlib.vector.ray_parallelogram_intersection(relative, direction, {
|
|
transform { -0.5, -0.5, 0.5 },
|
|
transform { 0.5, -0.5, 0.5 },
|
|
transform { -0.5, 0.5, 0.5 },
|
|
})
|
|
if pos_on_ray then
|
|
return u, v
|
|
end
|
|
end
|
|
|
|
local function vector_combine(v, w, func)
|
|
return vector.new(func(v.x, w.x), func(v.y, w.y), func(v.z, w.z))
|
|
end
|
|
|
|
local function rotate_boxes(self)
|
|
local collisionbox = self.initial_properties.collisionbox
|
|
local rotation = self.object:get_rotation()
|
|
local min, max = vector.new(math.huge, math.huge, math.huge), vector.new(-math.huge, -math.huge, -math.huge)
|
|
for index_x = 1, 1 + 3, 3 do
|
|
for index_y = 2, 2 + 3, 3 do
|
|
for index_z = 3, 3 + 3, 3 do
|
|
local pos = vector.rotate(
|
|
vector.new(collisionbox[index_x], collisionbox[index_y], collisionbox[index_z]),
|
|
rotation
|
|
)
|
|
min = vector_combine(min, pos, math.min)
|
|
max = vector_combine(max, pos, math.max)
|
|
end
|
|
end
|
|
end
|
|
local box = { min.x, min.y, min.z, max.x, max.y, max.z }
|
|
self.object:set_properties {
|
|
collisionbox = box,
|
|
selectionbox = box,
|
|
}
|
|
end
|
|
|
|
local colorpicker = {}
|
|
|
|
local thickness = 0.01
|
|
colorpicker._thickness = thickness
|
|
local height = 1 / (1 + bar_size)
|
|
local box = { -0.5, -height / 2, -thickness / 2, 0.5, height / 2, thickness / 2 }
|
|
colorpicker.initial_properties = {
|
|
visual = "cube",
|
|
visual_size = vector.new(1, height, thickness),
|
|
selectionbox = box,
|
|
collisionbox = box,
|
|
static_save = true,
|
|
physical = true,
|
|
infotext = "HSV colorpicker",
|
|
}
|
|
|
|
colorpicker.lua_properties = {
|
|
staticdata = "lua",
|
|
}
|
|
|
|
function colorpicker:_set_hue(hue)
|
|
self._.hue = hue
|
|
self.object:set_properties {
|
|
textures = {
|
|
"epxb.png",
|
|
"epxb.png",
|
|
"epxb.png",
|
|
"epxb.png",
|
|
get_texture(hue),
|
|
"epxb.png",
|
|
},
|
|
}
|
|
end
|
|
|
|
function colorpicker:_set_rotation(rotation)
|
|
self.object:set_rotation(rotation)
|
|
rotate_boxes(self)
|
|
self._.rotation = rotation
|
|
end
|
|
|
|
function colorpicker:on_activate()
|
|
self:_set_hue(self._.hue or math.random())
|
|
self:_set_rotation(self._.rotation or vector.new(0, 0, 0))
|
|
local object = self.object
|
|
object:set_acceleration(vector.new(0, -0.981, 0))
|
|
object:set_armor_groups { immortal = 1, punch_operable = 1 }
|
|
end
|
|
|
|
function colorpicker:_get_color(user)
|
|
local u, v = get_uv(self, user)
|
|
if not u then
|
|
return
|
|
end
|
|
local hue = self._.hue
|
|
local saturation, value = 1 - v, (1 - u) * (1 + bar_size)
|
|
if value > 1 then -- hue bar
|
|
hue = saturation
|
|
saturation, value = 1, 1
|
|
end
|
|
return modlib.minetest.colorspec.from_hsv(hue, saturation, value)
|
|
end
|
|
|
|
function colorpicker:on_punch(puncher)
|
|
local u, v = get_uv(self, puncher)
|
|
if u then
|
|
local hue, value = 1 - v, (1 - u) * (1 + bar_size)
|
|
if value > 1 then -- hue bar
|
|
self:_set_hue(hue)
|
|
return
|
|
end
|
|
end
|
|
local inventory = puncher:get_inventory()
|
|
if not inventory:room_for_item("main", "epidermis:spawner_colorpicker") then
|
|
return
|
|
end
|
|
self.object:remove()
|
|
inventory:add_item("main", "epidermis:spawner_colorpicker")
|
|
end
|
|
|
|
moblib.register_entity("epidermis:colorpicker", colorpicker)
|