WIP
DirectOutput framework for virtual pinball cabinets WIP
Go to:
Overview 
MatrixShiftEffectBase.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 {
14  public abstract class MatrixShiftEffectBase<MatrixElementType> : MatrixEffectBase<MatrixElementType>
15  {
16  private const int RefreshIntervalMs = 30;
17 
18 
19  private MatrixShiftDirectionEnum _ShiftDirection = MatrixShiftDirectionEnum.Right;
20 
27  public MatrixShiftDirectionEnum ShiftDirection
28  {
29  get { return _ShiftDirection; }
30  set { _ShiftDirection = value; }
31  }
32 
33  private float _ShiftSpeed = 200;
34 
43  public float ShiftSpeed
44  {
45  get { return _ShiftSpeed; }
46  set { _ShiftSpeed = value.Limit(1, 10000); }
47  }
48 
49 
50  private float _ShiftAcceleration = 0;
58  public float ShiftAcceleration
59  {
60  get { return _ShiftAcceleration; }
61  set { _ShiftAcceleration = value; }
62  }
63 
64 
65 
66  private void BuildStep2ElementTable()
67  {
68  List<float> L = new List<float>();
69 
70  float NumberOfElements = (ShiftDirection == MatrixShiftDirectionEnum.Left || ShiftDirection == MatrixShiftDirectionEnum.Right ? AreaWidth : AreaHeight);
71  float Position = 0;
72  float Speed = NumberOfElements / 100 * (ShiftSpeed / (1000 / RefreshIntervalMs));
73  float Acceleration = NumberOfElements / 100 * (ShiftAcceleration / (1000 / RefreshIntervalMs));
74  while (Position <= NumberOfElements)
75  {
76  L.Add(Position.Limit(0, NumberOfElements));
77  Position += Speed;
78  Speed = (Speed + Acceleration).Limit(NumberOfElements / 100 * (1 / (1000 / RefreshIntervalMs)), 10000);
79  }
80  L.Add(Position.Limit(0, NumberOfElements));
81 
82 
83  Step2Element = L.ToArray();
84  }
85 
86  float[] Step2Element = null;
87 
88  private void DoStep()
89  {
90  if (!Active)
91  {
92  Table.Pinball.Alarms.RegisterIntervalAlarm(RefreshIntervalMs, DoStep);
93  Active = true;
94  }
95 
96 
97  int NumberOfElements = (ShiftDirection == MatrixShiftDirectionEnum.Left || ShiftDirection == MatrixShiftDirectionEnum.Right ? AreaWidth : AreaHeight);
98 
99 
100  float FromElementNr = NumberOfElements;
101  float ToElementNr = 0;
102  float[] Value = new float[NumberOfElements + 1];
103 
104  int LastValue = LastDiscardedValue;
105 
106  int ToNr;
107  foreach (KeyValuePair<int, int> KV in TriggerValueBuffer)
108  {
109  ToElementNr = Step2Element[(CurrentStep - KV.Key)];
110 
111  if (FromElementNr.Floor() == ToElementNr.Floor())
112  {
113  Value[(int)FromElementNr.Floor()] += (FromElementNr - ToElementNr) * LastValue;
114  }
115  else
116  {
117  if (!FromElementNr.IsIntegral())
118  {
119  Value[(int)FromElementNr.Floor()] += (FromElementNr - FromElementNr.Floor()) * LastValue;
120  }
121 
122  ToNr = (int)(ToElementNr.Ceiling());
123  for (int i = (int)FromElementNr.Floor() - 1; i >= ToNr; i--)
124  {
125  Value[i] = LastValue;
126  }
127  if (!ToElementNr.IsIntegral())
128  {
129  Value[(int)ToElementNr.Floor()] += (ToElementNr.Ceiling() - ToElementNr) * LastValue;
130  }
131 
132  }
133  FromElementNr = ToElementNr;
134  LastValue = KV.Value;
135  }
136  ToElementNr = 0;
137  if (FromElementNr != ToElementNr)
138  {
139  if (!FromElementNr.IsIntegral() && FromElementNr.Floor() < Width - 1)
140  {
141  Value[(int)FromElementNr.Floor()] += (FromElementNr - FromElementNr.Floor()) * LastValue;
142  }
143 
144  ToNr = (int)(ToElementNr.Ceiling()).Limit(0, int.MaxValue);
145  for (int i = (int)FromElementNr.Floor() - 1; i >= ToNr; i--)
146  {
147  Value[i] = LastValue;
148  }
149  if (!ToElementNr.IsIntegral())
150  {
151  Value[(int)ToElementNr.Floor()] += (ToElementNr.Ceiling() - ToElementNr) * LastValue;
152  }
153  }
154 
155 
156  #region Data ouput
157  switch (ShiftDirection)
158  {
159  case MatrixShiftDirectionEnum.Right:
160  for (int i = 0; i < NumberOfElements; i++)
161  {
162  int V = ((int)Value[i]).Limit(0, 255);
163  if (V > 0 && FadeMode == FadeModeEnum.OnOff) { V = 255; }
164  MatrixElementType D = GetEffectValue(V);
165 
166  for (int y = AreaTop; y <= AreaBottom; y++)
167  {
168  MatrixLayer[AreaLeft + i, y] = D;
169  }
170  }
171  break;
172  case MatrixShiftDirectionEnum.Down:
173  for (int i = 0; i < NumberOfElements; i++)
174  {
175  int V = ((int)Value[i]).Limit(0, 255);
176  if (V > 0 && FadeMode == FadeModeEnum.OnOff) { V = 255; }
177  MatrixElementType D = GetEffectValue(V);
178 
179  for (int x = AreaLeft; x <= AreaRight; x++)
180  {
181  MatrixLayer[x, AreaTop + i] = D;
182  }
183  }
184  break;
185  case MatrixShiftDirectionEnum.Up:
186  for (int i = 0; i < NumberOfElements; i++)
187  {
188  int V = ((int)Value[i]).Limit(0, 255);
189  if (V > 0 && FadeMode == FadeModeEnum.OnOff) { V = 255; }
190  MatrixElementType D = GetEffectValue(V);
191 
192  for (int x = AreaLeft; x <= AreaRight; x++)
193  {
194  MatrixLayer[x, AreaBottom - i] = D;
195  }
196  }
197  break;
198  case MatrixShiftDirectionEnum.Left:
199  default:
200  for (int i = 0; i < NumberOfElements; i++)
201  {
202  int V = ((int)Value[i]).Limit(0, 255);
203  if (V > 0 && FadeMode == FadeModeEnum.OnOff) { V = 255; }
204  MatrixElementType D = GetEffectValue(V);
205 
206  for (int y = AreaTop; y <= AreaBottom; y++)
207  {
208  MatrixLayer[AreaRight - i, y] = D;
209  }
210  }
211  break;
212  }
213  #endregion
214 
215 
216 
217 
218 
219  int DropKey = CurrentStep - (Step2Element.Length - 1);
220  if (TriggerValueBuffer.ContainsKey(DropKey))
221  {
222  LastDiscardedValue = TriggerValueBuffer[DropKey];
223  TriggerValueBuffer.Remove(DropKey);
224  };
225 
226  if (TriggerValueBuffer.Count > 0 || LastDiscardedValue != 0)
227  {
228  CurrentStep++;
229  }
230  else
231  {
232  Table.Pinball.Alarms.UnregisterIntervalAlarm(DoStep);
233  LastDiscardedValue = 0;
234  CurrentStep = 0;
235  Active = false;
236  }
237  }
238 
239  int LastDiscardedValue = 0;
240  bool Active = false;
241 
242  SortedDictionary<int, int> TriggerValueBuffer = new SortedDictionary<int, int>();
243  int LastTriggerValue = 0;
244 
245 
246  int CurrentStep = 0;
247 
248 
249 
256  protected abstract MatrixElementType GetEffectValue(int TriggerValue);
257 
258 
259  public override void Trigger(Table.TableElementData TableElementData)
260  {
261  if (LastTriggerValue != TableElementData.Value && MatrixLayer != null)
262  {
263  LastTriggerValue = TableElementData.Value;
264 
265 
266  if (TriggerValueBuffer.ContainsKey(CurrentStep))
267  {
268  TriggerValueBuffer[CurrentStep] = LastTriggerValue;
269  }
270  else
271  {
272  TriggerValueBuffer.Add(CurrentStep, LastTriggerValue);
273  }
274 
275  if (!Active)
276  {
277  DoStep();
278  }
279 
280  }
281 
282 
283  }
284 
285 
286 
287 
288 
289  public override void Init(Table.Table Table)
290  {
291  base.Init(Table);
292  BuildStep2ElementTable();
293  }
294 
295  public override void Finish()
296  {
297  try
298  {
299  Table.Pinball.Alarms.UnregisterIntervalAlarm(DoStep);
300  }
301  catch { };
302  base.Finish();
303  }
304 
305  }
306 }
The namespace DirectOutput.Cab.Toys contains all toy related classes.
Base class for effects targeting a matrix of toys (e.g. addressable ledstrip)
override void Finish()
Finishes the effect and releases object references
The namespace DirectOutput.Cab contains all cabinet related classes like the Cabinet class itself...
Definition: Cab.cs:16
FadeModeEnum
Defines the fading behaviour.
Definition: FadeModeEnum.cs:11
override void Trigger(Table.TableElementData TableElementData)
Namespace for objects dealing with layers
MatrixShiftDirectionEnum
Shift directions for LedStrip effects
The namespace DirectOutput.General contains classes for general use.
Base class for effects shift values through a matrix of elements.