DirectOuput Framework R2
DirectOutput framework R2 for virtual pinball cabinets
Go to:
Overview 
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Properties Events Macros Pages
LedStrip.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
5 using DirectOutput.Cab.Out;
6 using System.Xml.Serialization;
7 using DirectOutput.General;
8 using DirectOutput.Cab.Toys.Layer;
9 using DirectOutput.General.Color;
10 
11 namespace DirectOutput.Cab.Toys.Hardware
12 {
18  public class LedStrip : ToyBaseUpdatable, IToy, IMatrixToy<RGBAColor>
19  {
20  #region Config properties
21  private int _Width = 1;
22 
29  public int Width
30  {
31  get { return _Width; }
32  set { _Width = value.Limit(0, int.MaxValue); }
33  }
34 
35  private int _Height = 1;
36 
43  public int Height
44  {
45  get { return _Height; }
46  set { _Height = value.Limit(0, int.MaxValue); }
47  }
48 
49 
56  public int NumberOfLeds
57  {
58  get { return Width * Height; }
59  }
60 
61 
68  public int NumberOfOutputs
69  {
70  get { return NumberOfLeds * 3; }
71  }
72 
73 
74  private LedStripArrangementEnum _LedStripAranggement = LedStripArrangementEnum.LeftRightTopDown;
75 
84  public LedStripArrangementEnum LedStripArrangement
85  {
86  get { return _LedStripAranggement; }
87  set { _LedStripAranggement = value; }
88  }
89 
90 
91 
92  private RGBOrderEnum _ColorOrder = RGBOrderEnum.RBG;
93 
101  public RGBOrderEnum ColorOrder
102  {
103  get { return _ColorOrder; }
104  set { _ColorOrder = value; }
105  }
106 
107 
108  private int _FirstLedNumber = 1;
115  public int FirstLedNumber
116  {
117  get { return _FirstLedNumber; }
118  set { _FirstLedNumber = value.Limit(1, int.MaxValue); }
119  }
120 
121  private string _FadingCurveName = "Linear";
122  private Curve FadingCurve = null;
123 
131  public string FadingCurveName
132  {
133  get { return _FadingCurveName; }
134  set { _FadingCurveName = value; }
135  }
136 
137  private void InitFadingCurve(Cabinet Cabinet)
138  {
139  if (Cabinet.Curves.Contains(FadingCurveName))
140  {
141  FadingCurve = Cabinet.Curves[FadingCurveName];
142  }
143  else if (!FadingCurveName.IsNullOrWhiteSpace())
144  {
145  if (Enum.GetNames(typeof(Curve.CurveTypeEnum)).Contains(FadingCurveName))
146  {
148  Enum.TryParse(FadingCurveName, out T);
149  FadingCurve = new Curve(T);
150  }
151  else
152  {
153  FadingCurve = new Curve(Curve.CurveTypeEnum.Linear) { Name = FadingCurveName };
154  Cabinet.Curves.Add(FadingCurveName);
155  }
156  }
157  else
158  {
159  FadingCurve = new Curve(Curve.CurveTypeEnum.Linear);
160  }
161 
162  }
163 
164 
171  public string OutputControllerName { get; set; }
172 
173  private ISupportsSetValues OutputController;
174 
175  #endregion
176 
177 
184  [XmlIgnore]
185  public MatrixDictionaryBase<RGBAColor> Layers { get; private set; }
186 
187 
188  #region IToy methods
189 
190  Cabinet Cabinet;
195  public override void Init(Cabinet Cabinet)
196  {
197  this.Cabinet = Cabinet;
198 
199  if (Cabinet.OutputControllers.Contains(OutputControllerName) && Cabinet.OutputControllers[OutputControllerName] is ISupportsSetValues)
200  {
201  OutputController = (ISupportsSetValues)Cabinet.OutputControllers[OutputControllerName];
202  }
203 
204  BuildMappingTables();
205  OutputData = new byte[NumberOfOutputs];
206  InitFadingCurve(Cabinet);
207 
208  Layers = new MatrixDictionaryBase<RGBAColor>() { Width = Width, Height = Height };
209  }
210 
211 
212 
216  public override void Reset()
217  {
218  OutputController.SetValues((FirstLedNumber-1) * 3, new byte[NumberOfLeds]);
219  }
220 
224  public override void UpdateOutputs()
225  {
226  if (OutputController != null && Layers.Count > 0)
227  {
228  SetOutputData();
229  OutputController.SetValues((FirstLedNumber-1)*3, OutputData);
230 
231  };
232  }
233 
234  #endregion
235 
246  public RGBAColor[,] GetLayer(int LayerNr)
247  {
248  return Layers[LayerNr];
249  }
250 
251 
252 
253 
254  //private int[,] LedMappingTable = new int[0, 0];
255  private int[,] OutputMappingTable = new int[0, 0];
256 
257  private void BuildMappingTables()
258  {
259  //LedMappingTable = new int[Width, Height];
260  OutputMappingTable = new int[Width, Height];
261  bool FirstException = true;
262  int LedNr = 0;
263 
264  for (int Y = 0; Y < Height; Y++)
265  {
266  for (int X = 0; X < Width; X++)
267  {
268 
269  switch (LedStripArrangement)
270  {
271  case LedStripArrangementEnum.LeftRightTopDown:
272  LedNr = (Y * Width) + X;
273  break;
274  case LedStripArrangementEnum.LeftRightBottomUp:
275  LedNr = ((Height - 1 - Y) * Width) + X;
276  break;
277  case LedStripArrangementEnum.RightLeftTopDown:
278  LedNr = (Y * Width) + (Width - 1 - X);
279  break;
280  case LedStripArrangementEnum.RightLeftBottomUp:
281  LedNr = ((Height - 1 - Y) * Width) + (Width - 1 - X);
282  break;
283  case LedStripArrangementEnum.TopDownLeftRight:
284  LedNr = X * Height + Y;
285  break;
286  case LedStripArrangementEnum.TopDownRightLeft:
287  LedNr = ((Width - 1 - X) * Height) + Y;
288  break;
289  case LedStripArrangementEnum.BottomUpLeftRight:
290  LedNr = (X * Height) + (Height - 1 - Y);
291  break;
292  case LedStripArrangementEnum.BottomUpRightLeft:
293  LedNr = ((Width - 1 - X) * Height) + (Height - 1 - Y);
294  break;
295  case LedStripArrangementEnum.LeftRightAlternateTopDown:
296  LedNr = (Width * Y) + ((Y & 1) == 0 ? X : (Width - 1 - X));
297  break;
298  case LedStripArrangementEnum.LeftRightAlternateBottomUp:
299  LedNr = (Width * (Height - 1 - Y)) + (((Height - 1 - Y) & 1) == 0 ? X : (Width - 1 - X));
300  break;
301  case LedStripArrangementEnum.RightLeftAlternateTopDown:
302  LedNr = (Width * Y) + ((Y & 1) == 1 ? X : (Width - 1 - X));
303  break;
304  case LedStripArrangementEnum.RightLeftAlternateBottomUp:
305  LedNr = (Width * (Height - 1 - Y)) + (((Height - 1 - Y) & 1) == 1 ? X : (Width - 1 - X));
306  break;
307  case LedStripArrangementEnum.TopDownAlternateLeftRight:
308  LedNr = (Height * X) + ((X & 1) == 0 ? Y : (Height - 1 - Y));
309  break;
310  case LedStripArrangementEnum.TopDownAlternateRightLeft:
311  LedNr = (Height * (Width - 1 - X)) + ((X & 1) == 1 ? Y : (Height - 1 - Y));
312  break;
313  case LedStripArrangementEnum.BottomUpAlternateLeftRight:
314  LedNr = (Height * X) + ((X & 1) == 1 ? Y : (Height - 1 - Y));
315  break;
316  case LedStripArrangementEnum.BottomUpAlternateRightLeft:
317  LedNr = (Height * (Width - 1 - X)) + ((X & 1) == 0 ? Y : (Height - 1 - Y));
318  break;
319  default:
320  if (FirstException)
321  {
322  Log.Exception("Unknow LedStripArrangement value ({0}) found. Will use LeftRightTopDown mapping as fallback.".Build(LedStripArrangement.ToString()));
323  FirstException = false;
324  };
325  LedNr = (Y * Width) + X;
326  break;
327  }
328  //LedMappingTable[X, Y] = LedNr;
329  OutputMappingTable[X, Y] = LedNr * 3;
330  }
331  }
332 
333  }
334 
335  //Array for output data is not in GetResultingValues to avoid reinitiaslisation of the array
336  byte[] OutputData = new byte[0];
337 
342  private void SetOutputData()
343  {
344  if (Layers.Count > 0)
345  {
346  //Blend layers
347  float[, ,] Value = new float[Width, Height, 3];
348 
349  foreach (KeyValuePair<int, RGBAColor[,]> KV in Layers)
350  {
351  RGBAColor[,] D = KV.Value;
352 
353  int Nr = 0;
354  for (int y = 0; y < Height; y++)
355  {
356  for (int x = 0; x < Width; x++)
357  {
358  int Alpha = D[x, y].Alpha.Limit(0, 255);
359  if (Alpha != 0)
360  {
361  Value[x, y, 0] = AlphaMappingTable.AlphaMapping[255 - Alpha, (int)Value[x, y, 0]] + AlphaMappingTable.AlphaMapping[Alpha, D[x, y].Red.Limit(0, 255)];
362  Value[x, y, 1] = AlphaMappingTable.AlphaMapping[255 - Alpha, (int)Value[x, y, 1]] + AlphaMappingTable.AlphaMapping[Alpha, D[x, y].Green.Limit(0, 255)];
363  Value[x, y, 2] = AlphaMappingTable.AlphaMapping[255 - Alpha, (int)Value[x, y, 2]] + AlphaMappingTable.AlphaMapping[Alpha, D[x, y].Blue.Limit(0, 255)];
364  }
365  Nr++;
366  }
367  }
368  }
369 
370 
371 
372 
373  //The following code mapps the led data to the outputs of the stripe
374  byte[] FadingTable = FadingCurve.Data;
375  switch (ColorOrder)
376  {
377  case RGBOrderEnum.RBG:
378  for (int y = 0; y < Height; y++)
379  {
380  for (int x = 0; x < Width; x++)
381  {
382  int OutputNumber = OutputMappingTable[x, y];
383  OutputData[OutputNumber] = FadingTable[(int)Value[x, y, 0]];
384  OutputData[OutputNumber + 2] = FadingTable[(int)Value[x, y, 1]];
385  OutputData[OutputNumber + 1] = FadingTable[(int)Value[x, y, 2]];
386  }
387  }
388  break;
389  case RGBOrderEnum.GRB:
390  for (int y = 0; y < Height; y++)
391  {
392  for (int x = 0; x < Width; x++)
393  {
394  int OutputNumber = OutputMappingTable[x, y];
395  OutputData[OutputNumber + 1] = FadingTable[(int)Value[x, y, 0]];
396  OutputData[OutputNumber] = FadingTable[(int)Value[x, y, 1]];
397  OutputData[OutputNumber + 2] = FadingTable[(int)Value[x, y, 2]];
398  }
399  }
400  break;
401  case RGBOrderEnum.GBR:
402  for (int y = 0; y < Height; y++)
403  {
404  for (int x = 0; x < Width; x++)
405  {
406  int OutputNumber = OutputMappingTable[x, y];
407  OutputData[OutputNumber + 1] = FadingTable[(int)Value[x, y, 0]];
408  OutputData[OutputNumber + 2] = FadingTable[(int)Value[x, y, 1]];
409  OutputData[OutputNumber] = FadingTable[(int)Value[x, y, 2]];
410  }
411  }
412  break;
413  case RGBOrderEnum.BRG:
414  for (int y = 0; y < Height; y++)
415  {
416  for (int x = 0; x < Width; x++)
417  {
418  int OutputNumber = OutputMappingTable[x, y];
419  OutputData[OutputNumber + 2] = FadingTable[(int)Value[x, y, 0]];
420  OutputData[OutputNumber] = FadingTable[(int)Value[x, y, 1]];
421  OutputData[OutputNumber + 1] = FadingTable[(int)Value[x, y, 2]];
422  }
423  }
424  break;
425  case RGBOrderEnum.BGR:
426  for (int y = 0; y < Height; y++)
427  {
428  for (int x = 0; x < Width; x++)
429  {
430  int OutputNumber = OutputMappingTable[x, y];
431  OutputData[OutputNumber + 2] = FadingTable[(int)Value[x, y, 0]];
432  OutputData[OutputNumber + 1] = FadingTable[(int)Value[x, y, 1]];
433  OutputData[OutputNumber] = FadingTable[(int)Value[x, y, 2]];
434  }
435  }
436  break;
437  case RGBOrderEnum.RGB:
438  default:
439  for (int y = 0; y < Height; y++)
440  {
441  for (int x = 0; x < Width; x++)
442  {
443  int OutputNumber = OutputMappingTable[x, y];
444  OutputData[OutputNumber] = FadingTable[(int)Value[x, y, 0]];
445  OutputData[OutputNumber + 1] = FadingTable[(int)Value[x, y, 1]];
446  OutputData[OutputNumber + 2] = FadingTable[(int)Value[x, y, 2]];
447  }
448  }
449  break;
450  }
451  }
452 
453 
454  }
455 
456  #region Constructor
457 
458 
459 
460  public LedStrip()
461  {
462  Layers = new MatrixDictionaryBase<RGBAColor>();
463 
464 
465  }
466  #endregion
467 
468  }
469 }