WIP
DirectOutput framework for virtual pinball cabinets WIP
Go to:
Overview 
MatrixFlickerEffectBase.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
7 
8 namespace DirectOutput.FX.MatrixFX
9 {
13  public abstract class MatrixFlickerEffectBase<MatrixElementType> : MatrixEffectBase<MatrixElementType>
14  {
15  private const int RefreshIntervalMs = 30;
16 
17 
18 
19 
20 
21 
22 
23  private int _Density = 10;
24 
32  public int Density
33  {
34  get { return _Density; }
35  set { _Density = value.Limit(0, 100); }
36  }
37 
38 
39  private int _MinFlickerDurationMs = 60;
40 
47  public int MinFlickerDurationMs
48  {
49  get { return _MinFlickerDurationMs; }
50  set { _MinFlickerDurationMs = value.Limit(1, int.MaxValue); }
51  }
52 
53  private int _MaxFlickerDurationMs = 150;
54 
61 
62  public int MaxFlickerDurationMs
63  {
64  get { return _MaxFlickerDurationMs; }
65  set { _MaxFlickerDurationMs = value.Limit(1, int.MaxValue); }
66  }
67 
68  private int _FlickerFadeUpDurationMs = 0;
69 
76 
77  public int FlickerFadeUpDurationMs
78  {
79  get { return _FlickerFadeUpDurationMs; }
80  set { _FlickerFadeUpDurationMs = value.Limit(1, int.MaxValue); }
81  }
82 
83  private int _FlickerFadeDownDurationMs = 0;
84 
91 
92  public int FlickerFadeDownDurationMs
93  {
94  get { return _FlickerFadeDownDurationMs; }
95  set { _FlickerFadeDownDurationMs = value.Limit(1, int.MaxValue); }
96  }
97 
98 
105  private bool Active { get; set; }
106 
107 
108  private int CurrentValue = 0;
109 
110  private Random R = new Random();
111 
112  private void DoFlicker()
113  {
114 
115  MatrixElementType I = GetEffectValue(0);
116 
117  int V = CurrentValue.Limit(0, 255);
118  if (V > 0)
119  {
120 
121  if (!Active)
122  {
123  Table.Pinball.Alarms.RegisterIntervalAlarm(RefreshIntervalMs, DoFlicker);
124  Active = true;
125 
126 
127  }
128 
129  //Effect is active (V>0)
130  if (V > 0 && FadeMode == FadeModeEnum.OnOff) { V = 255; }
131 
132  int NumberOfLeds = AreaWidth * AreaHeight;
133  int FlickerLeds = ((int)((double)NumberOfLeds / 100 * Density)).Limit(1, NumberOfLeds);
134 
135 
136  int Min = MinFlickerDurationMs;
137  int Max = MaxFlickerDurationMs;
138  if (Max < Min)
139  {
140  int Tmp = Min; Min = Max; Max = Tmp;
141  }
142 
143  //if (Min != Max && ActiveFlickerObjects.Count.IsBetween(0,FlickerLeds-1))
144  //{
145  // int Avg = (Min + Max / 2) - Min;
146  // int NewObjectsAvg = ((FlickerLeds * Avg) - ActiveFlickerObjects.Sum(FO => FO.DurationMs)) / (FlickerLeds - ActiveFlickerObjects.Count);
147  // int NewObjectsAvgChange = Avg - NewObjectsAvg;
148 
149  // if (NewObjectsAvgChange < 0)
150  // {
151  // //Increase min
152  // Min = (Min + Math.Abs(NewObjectsAvgChange) * 2).Limit(Min, Max);
153 
154  // }
155  // else
156  // {
157  // //Decrease max
158  // Max = (Max - NewObjectsAvgChange * 2).Limit(Min, Max);
159  // }
160  //}
161 
162 
163  while (ActiveFlickerObjects.Count < FlickerLeds && InactiveFlickerObjects.Count > 0)
164  {
165  FlickerObject FO = InactiveFlickerObjects[R.Next(InactiveFlickerObjects.Count)];
166  InactiveFlickerObjects.Remove(FO);
167 
168  FO.StartTimestamp = DateTime.Now;
169  FO.DurationMs = R.Next(Min, Max)+ FlickerFadeDownDurationMs;
170  ActiveFlickerObjects.Add(FO);
171  }
172 
173  DateTime CurrentTimestamp = DateTime.Now;
174 
175  for (int i = ActiveFlickerObjects.Count - 1; i >= 0; i--)
176  {
177  FlickerObject FO = ActiveFlickerObjects[i];
178 
179  int FV;
180  int AgeMs = (int)(DateTime.Now - FO.StartTimestamp).TotalMilliseconds;
181  if (AgeMs > FO.DurationMs + FlickerFadeDownDurationMs)
182  {
183 
184 
185  if (AgeMs > (FO.DurationMs + FlickerFadeDownDurationMs) * 2 || R.NextDouble()>.5)
186  {
187  //Remove element
188  ActiveFlickerObjects.Remove(FO);
189  InactiveFlickerObjects.Add(FO);
190  }
191  FV = 0;
192  }
193  else if (FlickerFadeUpDurationMs > 0 && AgeMs < FlickerFadeUpDurationMs && AgeMs < FO.DurationMs)
194  {
195  //Fade up
196  FV = (int)((double)V / FlickerFadeUpDurationMs * AgeMs);
197  //Log.Write("U: " + FV.ToString());
198 
199  }
200  else if (AgeMs > FO.DurationMs && FlickerFadeDownDurationMs > 0)
201  {
202  //Fade down
203  if (FO.DurationMs < FlickerFadeUpDurationMs)
204  {
205  FV = (int)((double)V / FlickerFadeUpDurationMs * FO.DurationMs);
206  }
207  else
208  {
209  FV = V;
210  }
211  FV = FV - (int)((double)FV / FlickerFadeDownDurationMs * (AgeMs - FO.DurationMs));
212  //Log.Write("D: " + FV.ToString());
213 
214  }
215  else
216  {
217  //Full on
218  FV = V;
219 
220  //Log.Write("F: " + FV.ToString());
221 
222  }
223  FV = FV.Limit(0, 255);
224 
225  MatrixLayer[FO.X, FO.Y] = GetEffectValue(FV);
226  }
227 
228  }
229  else
230  {
231 
232  foreach (FlickerObject FO in ActiveFlickerObjects)
233  {
234  MatrixLayer[FO.X, FO.Y] = I;
235  }
236  InactiveFlickerObjects.AddRange(ActiveFlickerObjects);
237  ActiveFlickerObjects.Clear();
238  Table.Pinball.Alarms.UnregisterIntervalAlarm(DoFlicker);
239  Active = false;
240 
241  }
242 
243  }
244 
245 
246 
247 
248 
253  public override void Trigger(Table.TableElementData TableElementData)
254  {
255  if (MatrixLayer != null)
256  {
257  CurrentValue = TableElementData.Value;
258  if (CurrentValue > 0 && !Active)
259  {
260  DoFlicker();
261  }
262  }
263  }
264 
269  public override void Init(DirectOutput.Table.Table Table)
270  {
271  base.Init(Table);
272 
273  BuildFlickerObjects();
274  }
275 
276  public override void Finish()
277  {
278  if (Active)
279  {
280  CurrentValue = 0;
281  DoFlicker();
282  }
283  ActiveFlickerObjects.Clear();
284  InactiveFlickerObjects.Clear();
285  base.Finish();
286  }
287 
288  private void BuildFlickerObjects()
289  {
290  ActiveFlickerObjects = new List<FlickerObject>();
291  InactiveFlickerObjects = new List<FlickerObject>();
292 
293 
294  for (int Y = AreaTop; Y <= AreaBottom; Y++)
295  {
296  for (int X = AreaLeft; X <= AreaRight; X++)
297  {
298  InactiveFlickerObjects.Add(new FlickerObject() { X = X, Y = Y });
299  }
300  }
301 
302  }
303 
304  private List<FlickerObject> ActiveFlickerObjects = new List<FlickerObject>();
305 
306  private List<FlickerObject> InactiveFlickerObjects = new List<FlickerObject>();
307 
308  private class FlickerObject
309  {
310 
311  public int X { get; set; }
312  public int Y { get; set; }
313 
314  public int DurationMs { get; set; }
315  public DateTime StartTimestamp { get; set; }
316 
317  }
318 
319 
320 
327  protected abstract MatrixElementType GetEffectValue(int TriggerValue);
328 
329  }
330 }
override void Trigger(Table.TableElementData TableElementData)
Triggers the effect with the given TableElementData.
The namespace DirectOutput.Cab.Toys contains all toy related classes.
Base class for effects targeting a matrix of toys (e.g. addressable ledstrip)
The namespace DirectOutput.Cab contains all cabinet related classes like the Cabinet class itself...
Definition: Cab.cs:16
override void Finish()
Finishes the effect and releases object references
override void Init(DirectOutput.Table.Table Table)
Initializes the effect.
FadeModeEnum
Defines the fading behaviour.
Definition: FadeModeEnum.cs:11
Namespace for objects dealing with layers
The Table namespace contains all table specific classes like the Table class itself, TableElement and effect assigment classes.
Definition: Table.cs:14
Holds all table specific information and handles all TableElements
Definition: Table.cs:20
Does create random flickering with a defineable density, durations and value within the spefied area ...
The namespace DirectOutput.General contains classes for general use.