1use std::cmp::{max, min, PartialEq};
2use crate::color::OutputType::{CMY, HSV, RGB};
3use crate::fixture::{Channel, ChannelError, FixtureError, PropertyType};
4
5pub struct Color {
8 output_type: OutputType,
9 color1: Option<Channel>,
10 color2: Option<Channel>,
11 color3: Option<Channel>,
12 red: u16,
13 green: u16,
14 blue: u16,
15 cyan: u16,
16 magenta: u16,
17 yellow: u16,
18 hue: u16,
19 saturation: u16,
20 value: u16,
21}
22
23pub struct ColorType {
29 output_type: Option<OutputType>,
30 color1: Option<(u16, Option<u16>)>,
31 color2: Option<(u16, Option<u16>)>,
32 color3: Option<(u16, Option<u16>)>,
33}
34#[derive(Debug, PartialEq, Copy, Clone)]
35enum OutputType {
36 RGB,
37 HSV,
38 CMY
39}
40
41#[derive(Clone, Debug)]
43pub enum ColorPropertyType {
44 Red,
45 Green,
46 Blue,
47 Cyan,
48 Magenta,
49 Yellow,
50 Hue,
51 Saturation,
52 Value
53}
54
55impl ColorPropertyType {
56 fn new(color_number: u16, output_type: OutputType) -> Option<ColorPropertyType> {
57 match (color_number, output_type) {
58 (1, RGB) => Some(ColorPropertyType::Red),
59 (2, RGB) => Some(ColorPropertyType::Green),
60 (3, RGB) => Some(ColorPropertyType::Blue),
61
62 (1, CMY) => Some(ColorPropertyType::Cyan),
63 (2, CMY) => Some(ColorPropertyType::Magenta),
64 (3, CMY) => Some(ColorPropertyType::Yellow),
65
66 (1, HSV) => Some(ColorPropertyType::Hue),
67 (2, HSV) => Some(ColorPropertyType::Saturation),
68 (3, HSV) => Some(ColorPropertyType::Value),
69
70 _ => None
71 }
72 }
73
74 fn to_output_type(&self) -> (u16, OutputType) {
75 match self {
76 ColorPropertyType::Red => (1, RGB),
77 ColorPropertyType::Green => (2, RGB),
78 ColorPropertyType::Blue => (3, RGB),
79
80 ColorPropertyType::Cyan => (1, CMY),
81 ColorPropertyType::Magenta => (2, CMY),
82 ColorPropertyType::Yellow => (3, CMY),
83
84 ColorPropertyType::Hue => (1, HSV),
85 ColorPropertyType::Saturation => (2, HSV),
86 ColorPropertyType::Value => (3, HSV),
87 }
88 }
89
90 pub fn from_string(property: &str) -> Result<ColorPropertyType, FixtureError> {
101 match property {
102 "red" => Ok(ColorPropertyType::Red),
103 "green" => Ok(ColorPropertyType::Green),
104 "blue" => Ok(ColorPropertyType::Blue),
105 "cyan" => Ok(ColorPropertyType::Cyan),
106 "magenta" => Ok(ColorPropertyType::Magenta),
107 "yellow" => Ok(ColorPropertyType::Yellow),
108 "hue" => Ok(ColorPropertyType::Hue),
109 "saturation" => Ok(ColorPropertyType::Saturation),
110 "value" => Ok(ColorPropertyType::Value),
111 _ => Err(FixtureError::InvalidPropertyType(property.to_string()))
112 }
113 }
114}
115
116impl ColorType {
117
118 pub(crate) fn new() -> Self {
120 Self {
121 output_type: None,
122 color1: None,
123 color2: None,
124 color3: None,
125 }
126 }
127
128 pub(crate) fn parse(&mut self, s: String, value: (u16, Option<u16>)) -> Result<bool, FixtureError> {
141 let (new_type, slot) = match s.as_str() {
142 "red" => (RGB, 1),
143 "green" => (RGB, 2),
144 "blue" => (RGB, 3),
145
146 "cyan" => (CMY, 1),
147 "magenta" => (CMY, 2),
148 "yellow" => (CMY, 3),
149
150 "hue" => (HSV, 1),
151 "saturation" => (HSV, 2),
152 "value" => (HSV, 3),
153
154 _ => return Ok(false),
155 };
156
157 if let Some(old_type) = self.output_type {
158 if old_type != new_type {
159 return Err(FixtureError::MultipleColorOutputTypes(
160 format!("{s} is incompatible with {:?}", old_type)
161 ));
162 }
163 }
164
165 self.output_type = Some(new_type);
166
167 let target = match slot {
168 1 => &mut self.color1,
169 2 => &mut self.color2,
170 3 => &mut self.color3,
171 _ => unreachable!()
172 };
173
174 *target = Some(value);
175
176 Ok(true)
177 }
178
179 pub(crate) fn exists(&self) -> bool {
181 self.output_type.is_some()
182 }
183}
184
185impl Color {
186
187 pub(crate) fn new(
205 color_type: &ColorType, device_channel: u16, universe: usize, fixture_name: &str
206 ) -> Result<Self, ChannelError> {
207 let default_value = if color_type.output_type == Some(CMY) {
208 u16::MAX
209 } else if let Some(_) = color_type.output_type {
210 0
211 } else {
212 unreachable!();
214 };
215
216 let color1 = color_type.color1
217 .map(|c| Channel::new(c, default_value, device_channel))
218 .transpose()?;
219 let color2 = color_type.color2
220 .map(|c| Channel::new(c, default_value, device_channel))
221 .transpose()?;
222 let color3 = color_type.color3
223 .map(|c| Channel::new(c,default_value, device_channel))
224 .transpose()?;
225
226 let output_type = color_type.output_type.unwrap();
227
228
229
230 if let Some(color) = &color1 {
231 color.reserve_pending(fixture_name, universe)?;
232 }
233 if let Some(color) = &color2 {
234 color.reserve_pending(fixture_name, universe)?;
235 }
236 if let Some(color) = &color3 {
237 color.reserve_pending(fixture_name, universe)?;
238 }
239
240 if let Some(color) = &color1 {
241 let property = PropertyType::Color(ColorPropertyType::new(1, output_type).unwrap());
242 color.reserve_final(fixture_name, universe, property);
243 }
244 if let Some(color) = &color2 {
245 let property = PropertyType::Color(ColorPropertyType::new(2, output_type).unwrap());
246 color.reserve_final(fixture_name, universe, property);
247 }
248 if let Some(color) = &color3 {
249 let property = PropertyType::Color(ColorPropertyType::new(3, output_type).unwrap());
250 color.reserve_final(fixture_name, universe, property);
251 }
252
253
254
255
256 Ok(Self {
257 output_type,
258 color1,
259 color2,
260 color3,
261 red: 0,
262 green: 0,
263 blue: 0,
264 cyan: u16::MAX,
265 magenta: u16::MAX,
266 yellow: u16::MAX,
267 hue: 0,
268 saturation: 0,
269 value: 0,
270
271 })
272 }
273
274 fn set_color(&mut self) {
275 let (v1, v2, v3) = match self.output_type {
276 RGB => (self.red, self.green, self.blue),
277 HSV => (self.hue, self.saturation, self.value),
278 CMY => (self.cyan, self.magenta, self.red),
279 };
280 if let Some(c) = self.color1.as_mut() {
281 c.value = v1
282 }
283 if let Some(c) = self.color2.as_mut() {
284 c.value = v2
285 }
286 if let Some(c) = self.color3.as_mut() {
287 c.value = v3
288 }
289 }
290
291 fn set_rgb(&mut self, red: u16, green: u16, blue: u16) {
292 self.red = red;
293 self.green = green;
294 self.blue = blue;
295
296 self.cyan = u16::MAX - red;
297 self.magenta = u16::MAX - green;
298 self.yellow = u16::MAX - blue;
299
300 let max = max(red, max(green, blue));
301 let min = min(red, min(green, blue));
302 let delta = max - min;
303 self.value = max;
304 self.saturation = if max == 0 {
305 0
306 } else {
307 ( (delta as f32 * u16::MAX as f32) / max as f32 ).round() as u16
308 };
309 let mut hue: i32 = (u16::MAX as f32 / 6.0_f32
310 * (if delta == 0 {
311 0.0
312 } else if max == red {
313 ((green as f32 - blue as f32) / delta as f32) % 6.0
314 } else if max == green {
315 ((blue as f32 - red as f32) / delta as f32) + 2.0
316 } else {
317 ((red as f32 - green as f32) / delta as f32) + 4.0
318 })) as i32;
319
320 if hue < 0 {
321 hue = hue + u16::MAX as i32;
322 }
323
324 self.hue = hue as u16;
325
326 self.set_color()
327 }
328
329 fn set_hsv(&mut self, hue: u16, saturation: u16, value: u16) {
330 self.hue = hue;
331 self.saturation = saturation;
332 self.value = value;
333 let c = (value as f32 * (saturation as f32 / u16::MAX as f32)).round() as u16;
335 let m = value.saturating_sub(c);
336 let h = hue as f32 / (u16::MAX as f32 / 6f32);
337 let x = ( c as f32 * (1.0 - ((h % 2.0) - 1.0).abs()) ).round() as u16;
338
339 let (r, g, b) = match h {
340 n if n < 1.0 => (c, x, 0),
341 n if n < 2.0 => (x, c, 0),
342 n if n < 3.0 => (0, c, x),
343 n if n < 4.0 => (0, x, c),
344 n if n < 5.0 => (x, 0, c),
345 n if n <= 6.0 => (c, 0, x),
346 _ => (0, 0, 0)
347 };
348
349 self.red = r.saturating_add(m);
350 self.green = g.saturating_add(m);
351 self.blue = b.saturating_add(m);
352
353 self.cyan = u16::MAX - self.red;
354 self.magenta = u16::MAX - self.green;
355 self.yellow= u16::MAX - self.blue;
356
357 self.set_color()
358 }
359
360 pub fn set(&mut self, property: ColorPropertyType, value: u16) {
366 let (color_number, output_type) = property.to_output_type();
367
368 let (mut value1, mut value2, mut value3) = match output_type {
369 RGB => (self.red, self.green, self.blue),
370 CMY => (self.cyan, self.magenta, self.yellow),
371 HSV => (self.hue, self.saturation, self.value),
372 };
373
374 match color_number {
375 1 => value1 = value,
376 2 => value2 = value,
377 3 => value3 = value,
378 _ => unreachable!(),
379 }
380
381 match output_type {
382 RGB => self.set_rgb(value1, value2, value3),
383 HSV => self.set_hsv(value1, value2, value3),
384 CMY => self.set_rgb(
385 u16::MAX - value1,
386 u16::MAX - value2,
387 u16::MAX - value3
388 ),
389 }
390
391
392
393 }
394
395 pub fn get_values(&self) -> Vec<(u16, u8)> {
400 let mut output = Vec::new();
401
402 if let Some(c) = self.color1.as_ref() {
403 output.push(c.get_value());
404 if let Some(fine_value) = c.get_fine_value() {
405 output.push(fine_value);
406 }
407 }
408
409 if let Some(c) = self.color2.as_ref() {
410 output.push(c.get_value());
411 if let Some(fine_value) = c.get_fine_value() {
412 output.push(fine_value);
413 }
414 }
415
416 if let Some(c) = self.color3.as_ref() {
417 output.push(c.get_value());
418 if let Some(fine_value) = c.get_fine_value() {
419 output.push(fine_value);
420 }
421 }
422
423
424 output
425
426 }
427}