Created repository.
- 256 variants of a single item "256_dyes:dye". Not useful for now. - Universal mixing craft recipe: you can mix up to 9 colors at once on the crafting grid. - In game, only the brown dye can be found in creative inventory. You can change the color by clicking: - Right click changes hue - Left click changes brightness - The `color.dat` file is used by the mixing algorithm. (compressed list of RGB color codes) - gen_palette.py: Python 3 script to run with Python Image Library to generate the palette and color.dat. Could be easily modified to generate a different palette.
This commit is contained in:
commit
076c844563
BIN
colors.dat
Normal file
BIN
colors.dat
Normal file
Binary file not shown.
77
gen_palette.py
Normal file
77
gen_palette.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
from PIL import Image
|
||||||
|
from array import array
|
||||||
|
from zlib import compress
|
||||||
|
|
||||||
|
#palette = Image.new("RGB", (16, 16))
|
||||||
|
|
||||||
|
palette_list = []
|
||||||
|
|
||||||
|
modifiers = [
|
||||||
|
(0.25, 0.00),
|
||||||
|
(0.50, 0.00),
|
||||||
|
(0.75, 0.00),
|
||||||
|
(1.00, 0.00),
|
||||||
|
(0.75, 0.25),
|
||||||
|
(0.50, 0.50),
|
||||||
|
(0.25, 0.75),
|
||||||
|
(0.25, 0.50),
|
||||||
|
(0.25, 0.25),
|
||||||
|
(0.50, 0.25),
|
||||||
|
]
|
||||||
|
|
||||||
|
def add_color(color):
|
||||||
|
global palette_list
|
||||||
|
palette_list += list(color)
|
||||||
|
|
||||||
|
def variations(color):
|
||||||
|
for mod in modifiers:
|
||||||
|
sat = mod[0]
|
||||||
|
off = mod[1]
|
||||||
|
r = int((color[0] * sat + off) * 255 + 0.5)
|
||||||
|
g = int((color[1] * sat + off) * 255 + 0.5)
|
||||||
|
b = int((color[2] * sat + off) * 255 + 0.5)
|
||||||
|
add_color((r, g, b))
|
||||||
|
|
||||||
|
hues = [
|
||||||
|
(1.00, 0.00, 0.00),
|
||||||
|
(1.00, 0.25, 0.00),
|
||||||
|
(1.00, 0.50, 0.00),
|
||||||
|
(1.00, 0.75, 0.00),
|
||||||
|
(1.00, 1.00, 0.00),
|
||||||
|
(0.75, 1.00, 0.00),
|
||||||
|
(0.50, 1.00, 0.00),
|
||||||
|
(0.25, 1.00, 0.00),
|
||||||
|
(0.00, 1.00, 0.00),
|
||||||
|
(0.00, 1.00, 0.25),
|
||||||
|
(0.00, 1.00, 0.50),
|
||||||
|
(0.00, 1.00, 0.75),
|
||||||
|
(0.00, 1.00, 1.00),
|
||||||
|
(0.00, 0.75, 1.00),
|
||||||
|
(0.00, 0.50, 1.00),
|
||||||
|
(0.00, 0.25, 1.00),
|
||||||
|
(0.00, 0.00, 1.00),
|
||||||
|
(0.25, 0.00, 1.00),
|
||||||
|
(0.50, 0.00, 1.00),
|
||||||
|
(0.75, 0.00, 1.00),
|
||||||
|
(1.00, 0.00, 1.00),
|
||||||
|
(1.00, 0.00, 0.75),
|
||||||
|
(1.00, 0.00, 0.50),
|
||||||
|
(1.00, 0.00, 0.25),
|
||||||
|
]
|
||||||
|
|
||||||
|
for hue in hues:
|
||||||
|
variations(hue)
|
||||||
|
|
||||||
|
for i in range(16):
|
||||||
|
l = i * 17
|
||||||
|
add_color((l, l, l))
|
||||||
|
|
||||||
|
palette_buffer = bytes(palette_list)
|
||||||
|
|
||||||
|
palette = Image.frombuffer("RGB", (16, 16), palette_buffer)
|
||||||
|
palette = palette.transpose(Image.FLIP_TOP_BOTTOM)
|
||||||
|
palette.save("palette.png")
|
||||||
|
|
||||||
|
color_list = open("colors.dat", "wb")
|
||||||
|
color_list.write(compress(palette_buffer))
|
||||||
|
color_list.close()
|
132
init.lua
Normal file
132
init.lua
Normal file
@ -0,0 +1,132 @@
|
|||||||
|
local modpath = minetest.get_modpath(minetest.get_current_modname())
|
||||||
|
|
||||||
|
local function change_variation(itemstack)
|
||||||
|
local meta = itemstack:get_meta()
|
||||||
|
local color = meta:get_int("palette_index")
|
||||||
|
local variation
|
||||||
|
local new_color
|
||||||
|
if color >= 240 then
|
||||||
|
if color == 255 then
|
||||||
|
new_color = 240
|
||||||
|
else
|
||||||
|
new_color = color + 1
|
||||||
|
end
|
||||||
|
else
|
||||||
|
variation = color % 10
|
||||||
|
local hue = color - variation
|
||||||
|
new_color = (variation+1) % 10 + hue
|
||||||
|
end
|
||||||
|
meta:set_int("palette_index", new_color)
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
local function change_hue(itemstack)
|
||||||
|
local meta = itemstack:get_meta()
|
||||||
|
local color = meta:get_int("palette_index")
|
||||||
|
local new_color = color + 10
|
||||||
|
if color >= 230 then
|
||||||
|
if color == 255 then
|
||||||
|
new_color = 0
|
||||||
|
else
|
||||||
|
new_color = math.max(color + 1, 240)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
meta:set_int("palette_index", new_color)
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_craftitem("256_dyes:dye", {
|
||||||
|
description = "Dye",
|
||||||
|
groups = {},
|
||||||
|
inventory_image = "256_dyes_dye.png",
|
||||||
|
wield_image = "256_dyes_dye.png",
|
||||||
|
palette = "256_dyes_palette_2.png",
|
||||||
|
stack_max = 99,
|
||||||
|
color = "#400000",
|
||||||
|
on_use = change_variation,
|
||||||
|
on_place = change_hue,
|
||||||
|
on_secondary_use = change_hue,
|
||||||
|
})
|
||||||
|
|
||||||
|
local file = io.open(modpath .. "/colors.dat", "r")
|
||||||
|
local raw_colors = minetest.decompress(file:read("*all"))
|
||||||
|
file:close()
|
||||||
|
|
||||||
|
local colors = {}
|
||||||
|
for i=0, 255 do
|
||||||
|
local pos = i * 3
|
||||||
|
raw_color = raw_colors:sub(pos+1, pos+3)
|
||||||
|
color = {raw_color:byte(1, 3)}
|
||||||
|
colors[i] = color
|
||||||
|
end
|
||||||
|
|
||||||
|
local function mix(...)
|
||||||
|
local list = {...}
|
||||||
|
local n = #list
|
||||||
|
local sum_c = 0
|
||||||
|
local sum_m = 0
|
||||||
|
local sum_y = 0
|
||||||
|
for _, i in ipairs(list) do
|
||||||
|
r, g, b = unpack(colors[i])
|
||||||
|
local c, m, y = 255-r, 255-g, 255-b
|
||||||
|
sum_c = sum_c + c^2
|
||||||
|
sum_m = sum_m + m^2
|
||||||
|
sum_y = sum_y + y^2
|
||||||
|
end
|
||||||
|
local true_color = {math.sqrt(sum_c/n), math.sqrt(sum_m/n), math.sqrt(sum_y/n)} -- I found that calculating the quadratic mean of CMY colors gives more realistic mixes because it makes the mix more sensitive to dark colors
|
||||||
|
|
||||||
|
local min_diff = 765
|
||||||
|
local nearest = 0
|
||||||
|
|
||||||
|
for i=0, 255 do
|
||||||
|
local color = colors[i]
|
||||||
|
local c, m, y = 255-color[1], 255-color[2], 255-color[3]
|
||||||
|
local diff = math.abs(c - true_color[1]) + math.abs(m - true_color[2]) + math.abs(y - true_color[3])
|
||||||
|
if diff < min_diff then
|
||||||
|
min_diff = diff
|
||||||
|
nearest = i
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return nearest
|
||||||
|
end
|
||||||
|
|
||||||
|
for i=1, 9 do
|
||||||
|
recipe = {}
|
||||||
|
for j=1, i do
|
||||||
|
table.insert(recipe, "256_dyes:dye")
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_craft({
|
||||||
|
type = "shapeless",
|
||||||
|
output = "256_dyes:dye",
|
||||||
|
recipe = recipe,
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
local function dye_craft(itemstack, player, old_craft_grid, craft_inv)
|
||||||
|
if itemstack:get_name() ~= "256_dyes:dye" then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
local list_colors = {}
|
||||||
|
for _, stack in ipairs(old_craft_grid) do
|
||||||
|
if not stack:is_empty() then
|
||||||
|
if stack:get_name() == "256_dyes:dye" then
|
||||||
|
local meta = stack:get_meta()
|
||||||
|
table.insert(list_colors, meta:get_int("palette_index"))
|
||||||
|
else
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if #list_colors == 0 then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
itemstack = ItemStack("256_dyes:dye " .. #list_colors)
|
||||||
|
local new_color = mix(unpack(list_colors))
|
||||||
|
local meta = itemstack:get_meta()
|
||||||
|
meta:set_int("palette_index", new_color)
|
||||||
|
return itemstack
|
||||||
|
end
|
||||||
|
|
||||||
|
minetest.register_craft_predict(dye_craft)
|
||||||
|
minetest.register_on_craft(dye_craft)
|
BIN
textures/256_dyes_dye.png
Normal file
BIN
textures/256_dyes_dye.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 325 B |
BIN
textures/256_dyes_palette_1.png
Normal file
BIN
textures/256_dyes_palette_1.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 432 B |
BIN
textures/256_dyes_palette_2.png
Normal file
BIN
textures/256_dyes_palette_2.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 380 B |
Loading…
x
Reference in New Issue
Block a user