This repository was archived by the owner on Mar 21, 2025. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathicons.lua
More file actions
123 lines (114 loc) · 4.37 KB
/
Copy pathicons.lua
File metadata and controls
123 lines (114 loc) · 4.37 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
--[[icons contains helper functions for building icons]]
do
---@class IconTransform
---@field scale? double
---@field shift? data.Vector
---@field tint? data.Color
data_IconTransform = {}
end
-- Extract the icons from a prototype's icon fields or its icons field, from a single icon
-- or from a list of icons, and returns the result as a list of icons.
---@param proto data.IconData|data.IconData[]|data.ItemPrototype|data.TechnologyPrototype|data.VirtualSignalPrototype
---@return data.IconData[]?
function get_icons(proto)
if not proto then return end
if proto.icons then
return table.deepcopy(proto.icons)
end
if proto.icon then
return { {
icon = proto.icon,
icon_size = proto.icon_size,
icon_mipmaps = proto.icon_mipmaps,
scale = proto.scale,
shift = proto.shift,
tint = proto.tint,
} }
end
if proto[1] and proto[1].icon then
return table.deepcopy(proto)
end
end
local function vector_mul(vectors)
local res = table.deepcopy(table.remove(vectors, 1))
for _, vec in pairs(vectors) do
if type(vec) == "number" then vec = { vec, vec } end -- allow scalars
for k in pairs(vec) do
res[k] = res[k] * vec[k]
end
end
return res
end
local function vector_add(vectors)
local res = table.deepcopy(table.remove(vectors, 1))
for _, vec in pairs(vectors) do
if type(vec) == "number" then vec = { vec, vec } end -- allow scalars
for k in pairs(vec) do
res[k] = res[k] + vec[k]
end
end
return res
end
--[[
icon_combinator combines layers of icons, where each layer may be a one or more
icons, applying an abstract transform to each layer as a group.
- The first icon in the first layer (called "base" in the code) is pased through
unaltered.
- Add a 0px or fully transparent dummy icon file as the first icon if you want
to apply a tranform to every icon.
- Unlike the data.IconData scale and shift fields, IconTransform inputs are
adjusted so the numbers are relative to the final icon size. e.g. a scale of
0.5 scales the length of the sides of the icons down by 50%, and a shift of
{0.2, 0.2} moves the icons down and to the right by 20% of the width of the
final icon.
- The output of icon_combinator can be fed back into icon_combinator again as an
icon layer. A transform applied to such a layer of icons is correctly shifted
and scaled as a group as if it were a single icon.
- If you use the same base icon in multiple nested calls to icon_combinator, and
add the `.base_icon=true` field to it, all but the first instance of the base
icon is filtered out. This is a bit of a hack, but it is helpful for combining
nested icon definitions.
These features hopefully make it easy to generically combine prototype icons,
programatically building up a new icon from arbitrary pieces.
]]
---@param layers { [1]:data.IconData|data.IconData[]|data.ItemPrototype|data.TechnologyPrototype, [2]: IconTransform}[]
---@return data.IconData[]
function icon_combinator(layers)
local icons = {}
local base, base_size
for _, layer in pairs(layers) do
local icons_to_add = get_icons(layer[1]) or error("failed to get icons from: " .. serpent.dump(layer))
local scale = layer[2].scale or 1
local shift = layer[2].shift or { 0, 0 }
local tint = layer[2].tint or { r = 1, g = 1, b = 1, a = 1 }
if not base then
base = table.remove(icons_to_add, 1)
if not base.scale then base.scale = 32.0 / base.icon_size end
base_size = base.scale * base.icon_size
table.insert(icons, base)
end
for _, icon_to_add in pairs(icons_to_add) do
if icon_to_add.base_icon then goto continue end
if icon_to_add.shift then
icon_to_add.shift = vector_mul { vector_add { vector_mul { icon_to_add.shift, scale / (base_size) }, shift }, base_size }
else
icon_to_add.shift = vector_mul { shift, base_size }
end
if icon_to_add.scale then
icon_to_add.scale = icon_to_add.scale * scale
else
icon_to_add.scale = scale * base_size / icon_to_add.icon_size
end
table.insert(icons, {
icon = icon_to_add.icon,
icon_mipmaps = icon_to_add.icon_mipmaps,
icon_size = icon_to_add.icon_size,
scale = icon_to_add.scale,
shift = icon_to_add.shift,
tint = util.mix_color(icon_to_add.tint or { 1, 1, 1, 1 }, tint),
})
::continue::
end
end
return icons
end