v2 / vlib / gg / color.v
330 lines · 309 sloc · 5.87 KB · 59ec186b32b41abba9bae5e73b6897465d79d3c2
Raw
1module gg
2
3pub const black = Color{
4 r: 0
5 g: 0
6 b: 0
7}
8pub const gray = Color{
9 r: 128
10 g: 128
11 b: 128
12}
13pub const white = Color{
14 r: 255
15 g: 255
16 b: 255
17}
18pub const red = Color{
19 r: 255
20 g: 0
21 b: 0
22}
23pub const green = Color{
24 r: 0
25 g: 255
26 b: 0
27}
28pub const blue = Color{
29 r: 0
30 g: 0
31 b: 255
32}
33pub const yellow = Color{
34 r: 255
35 g: 255
36 b: 0
37}
38pub const magenta = Color{
39 r: 255
40 g: 0
41 b: 255
42}
43pub const cyan = Color{
44 r: 0
45 g: 255
46 b: 255
47}
48pub const orange = Color{
49 r: 255
50 g: 165
51 b: 0
52}
53pub const purple = Color{
54 r: 128
55 g: 0
56 b: 128
57}
58pub const indigo = Color{
59 r: 75
60 g: 0
61 b: 130
62}
63pub const pink = Color{
64 r: 255
65 g: 192
66 b: 203
67}
68pub const violet = Color{
69 r: 238
70 g: 130
71 b: 238
72}
73pub const dark_blue = Color{
74 r: 0
75 g: 0
76 b: 139
77}
78pub const dark_gray = Color{
79 r: 169
80 g: 169
81 b: 169
82}
83pub const dark_green = Color{
84 r: 0
85 g: 100
86 b: 0
87}
88pub const dark_red = Color{
89 r: 139
90 g: 0
91 b: 0
92}
93pub const light_blue = Color{
94 r: 173
95 g: 216
96 b: 230
97}
98pub const light_gray = Color{
99 r: 211
100 g: 211
101 b: 211
102}
103pub const light_green = Color{
104 r: 144
105 g: 238
106 b: 144
107}
108pub const light_red = Color{
109 r: 255
110 g: 204
111 b: 203
112}
113
114// Color represents a 32 bit color value in sRGB format
115@[markused]
116pub struct Color {
117pub mut:
118 r u8
119 g u8
120 b u8
121 a u8 = 255
122}
123
124// hex takes in a 32 bit integer and splits it into 4 byte values
125pub fn hex(color u32) Color {
126 return Color{
127 r: u8((color >> 16) & 0xFF)
128 g: u8((color >> 8) & 0xFF)
129 b: u8((color >> 0) & 0xFF)
130 }
131}
132
133// frgb builds a Color instance from the given floating point values (between 0.0 and 1.0) r, g, b
134@[inline]
135pub fn frgb[T](r T, g T, b T) Color {
136 return frgba(r, g, b, 1.0)
137}
138
139// frgba builds a Color instance from the given floating point values (between 0.0 and 1.0) r, g, b, a
140@[inline]
141pub fn frgba[T](r T, g T, b T, a T) Color {
142 return Color{
143 r: u8(r * 255.0)
144 g: u8(g * 255.0)
145 b: u8(b * 255.0)
146 a: u8(a * 255.0)
147 }
148}
149
150// rgb builds a Color instance from the given r, g, b u8 values
151@[inline]
152pub fn rgb(r u8, g u8, b u8) Color {
153 return Color{
154 r: r
155 g: g
156 b: b
157 }
158}
159
160// rgba builds a Color instance from the given r, g, b, a u8 values
161@[inline]
162pub fn rgba(r u8, g u8, b u8, a u8) Color {
163 return Color{
164 r: r
165 g: g
166 b: b
167 a: a
168 }
169}
170
171// + adds `b` to `a`, with a maximum value of 255 for each channel
172pub fn (a Color) + (b Color) Color {
173 mut na := i32(a.a) + b.a
174 mut nr := i32(a.r) + b.r
175 mut ng := i32(a.g) + b.g
176 mut nb := i32(a.b) + b.b
177 if na > 255 {
178 na = 255
179 }
180 if nr > 255 {
181 nr = 255
182 }
183 if ng > 255 {
184 ng = 255
185 }
186 if nb > 255 {
187 nb = 255
188 }
189 return Color{
190 r: u8(nr)
191 g: u8(ng)
192 b: u8(nb)
193 a: u8(na)
194 }
195}
196
197// - subtracts `b` from `a`, with a minimum value of 0 for each channel
198// the alpha channel will be set as the minimum between ``a.a`` and ``b.a``
199pub fn (a Color) - (b Color) Color {
200 mut na := if a.a > b.a { a.a } else { b.a }
201 mut nr := i32(a.r) - b.r
202 mut ng := i32(a.g) - b.g
203 mut nb := i32(a.b) - b.b
204 if na < 0 {
205 na = 0
206 }
207 if nr < 0 {
208 nr = 0
209 }
210 if ng < 0 {
211 ng = 0
212 }
213 if nb < 0 {
214 nb = 0
215 }
216 return Color{
217 r: u8(nr)
218 g: u8(ng)
219 b: u8(nb)
220 a: u8(na)
221 }
222}
223
224// * multiplies Color `c` and `c2` keeping channel values in [0, 255] range
225pub fn (c Color) * (c2 Color) Color {
226 return Color{
227 r: c.r * c2.r
228 g: c.g * c2.g
229 b: c.b * c2.b
230 a: c.a * c2.a
231 }
232}
233
234// / divides `c` by `c2` and converts each channel's value to u8(int)
235pub fn (c Color) / (c2 Color) Color {
236 return Color{
237 r: c.r / c2.r
238 g: c.g / c2.g
239 b: c.b / c2.b
240 a: c.a / c2.a
241 }
242}
243
244// over implements an `a` over `b` operation.
245// see https://keithp.com/~keithp/porterduff/p253-porter.pdf
246pub fn (a Color) over(b Color) Color {
247 aa := f32(a.a) / 255
248 ab := f32(b.a) / 255
249 ar := aa + ab * (1 - aa)
250
251 rr := (f32(a.r) * aa + f32(b.r) * ab * (1 - aa)) / ar
252 gr := (f32(a.g) * aa + f32(b.g) * ab * (1 - aa)) / ar
253 br := (f32(a.b) * aa + f32(b.b) * ab * (1 - aa)) / ar
254 return Color{
255 r: u8(rr)
256 g: u8(gr)
257 b: u8(br)
258 a: u8(ar * 255)
259 }
260}
261
262// eq checks if color `c` and `c2` are equal in every channel
263pub fn (c Color) eq(c2 Color) bool {
264 return c.r == c2.r && c.g == c2.g && c.b == c2.b && c.a == c2.a
265}
266
267// str returns a string representation of the Color `c`
268pub fn (c Color) str() string {
269 return 'Color{${c.r}, ${c.g}, ${c.b}, ${c.a}}'
270}
271
272// rgba8 converts a color value to an 32bit int in the RGBA8 order.
273// see https://developer.apple.com/documentation/coreimage/ciformat
274@[inline]
275pub fn (c Color) rgba8() i32 {
276 return i32(u32(c.r) << 24 | u32(c.g) << 16 | u32(c.b) << 8 | u32(c.a))
277}
278
279// bgra8 converts a color value to an 32bit int in the BGRA8 order.
280// see https://developer.apple.com/documentation/coreimage/ciformat
281@[inline]
282pub fn (c Color) bgra8() i32 {
283 return i32(u32(c.b) << 24 | u32(c.g) << 16 | u32(c.r) << 8 | u32(c.a))
284}
285
286// abgr8 converts a color value to an 32bit int in the ABGR8 order.
287// see https://developer.apple.com/documentation/coreimage/ciformat
288@[inline]
289pub fn (c Color) abgr8() i32 {
290 return i32(u32(c.a) << 24 | u32(c.b) << 16 | u32(c.g) << 8 | u32(c.r))
291}
292
293const string_colors = {
294 'blue': blue
295 'red': red
296 'green': green
297 'yellow': yellow
298 'orange': orange
299 'purple': purple
300 'black': black
301 'gray': gray
302 'indigo': indigo
303 'pink': pink
304 'violet': violet
305 'white': white
306 'dark_blue': dark_blue
307 'dark_gray': dark_gray
308 'dark_green': dark_green
309 'dark_red': dark_red
310 'light_blue': light_blue
311 'light_gray': light_gray
312 'light_green': light_green
313 'light_red': light_red
314}
315
316// color_from_string returns a Color, corresponding to the given string
317// or black Color if string is not found in lookup table, or a hex color if starting with #
318pub fn color_from_string(s string) Color {
319 if s.starts_with('#') {
320 mut hex_str := '0x' + s[1..]
321 return hex(hex_str.u32())
322 } else {
323 return string_colors[s]
324 }
325}
326
327// to_css_string returns a CSS compatible string e.g. `rgba(10,11,12,13)` of the color `c`.
328pub fn (c Color) to_css_string() string {
329 return 'rgba(${c.r},${c.g},${c.b},${c.a})'
330}
331