WIP
DirectOutput framework for virtual pinball cabinets WIP
Go to:
Overview 
MatrixBitmapAnimationEffectBase.cs
Go to the documentation of this file.
1 using System;
2 using System.Collections.Generic;
3 using System.Linq;
4 using System.Text;
8 
9 namespace DirectOutput.FX.MatrixFX
10 {
11  public abstract class MatrixBitmapAnimationEffectBase<MatrixElementType> : MatrixEffectBase<MatrixElementType>, IMatrixBitmapEffect
12  {
13  private MatrixAnimationStepDirectionEnum _AnimationStepDirection = MatrixAnimationStepDirectionEnum.Frame;
14 
21  public MatrixAnimationStepDirectionEnum AnimationStepDirection
22  {
23  get { return _AnimationStepDirection; }
24  set { _AnimationStepDirection = value; }
25  }
26 
27  private int _AnimationStepSize = 1;
28 
35  public int AnimationStepSize
36  {
37  get { return _AnimationStepSize; }
38  set { _AnimationStepSize = value; }
39  }
40 
41 
42  private int _AnimationFrameCount = 1;
43 
50  public int AnimationFrameCount
51  {
52  get { return _AnimationFrameCount; }
53  set { _AnimationFrameCount = value.Limit(1, int.MaxValue); }
54  }
55 
56  private AnimationBehaviourEnum _AnimationBehaviour= AnimationBehaviourEnum.Loop;
57 
64  public AnimationBehaviourEnum AnimationBehaviour
65  {
66  get { return _AnimationBehaviour; }
67  set { _AnimationBehaviour = value; }
68  }
69 
70 
71  private int _AnimationFrameDurationMs = 30;
72 
79  public int AnimationFrameDurationMs
80  {
81  get { return _AnimationFrameDurationMs; }
82  set { _AnimationFrameDurationMs = value.Limit(1,int.MaxValue); }
83  }
84 
85 
86 
87  private int _BitmapFrameNumber = 0;
88 
95  public int BitmapFrameNumber
96  {
97  get { return _BitmapFrameNumber; }
98  set { _BitmapFrameNumber = value; }
99  }
100 
101  private int _BitmapTop = 0;
102 
109  public int BitmapTop
110  {
111  get { return _BitmapTop; }
112  set { _BitmapTop = value.Limit(0,int.MaxValue); }
113  }
114 
115  private int _BitmapLeft = 0;
116 
123  public int BitmapLeft
124  {
125  get { return _BitmapLeft; }
126  set { _BitmapLeft = value.Limit(0, int.MaxValue); }
127  }
128 
129  private int _BitmapWidth = -1;
130 
137  public int BitmapWidth
138  {
139  get { return _BitmapWidth; }
140  set { _BitmapWidth = value.Limit(-1, int.MaxValue); }
141  }
142 
143  private int _BitmapHeight = -1;
144 
151  public int BitmapHeight
152  {
153  get { return _BitmapHeight; }
154  set { _BitmapHeight = value.Limit(-1, int.MaxValue); }
155  }
156 
157 
158  private FastBitmapDataExtractModeEnum _DataExtractMode = FastBitmapDataExtractModeEnum.BlendPixels;
159 
166  public FastBitmapDataExtractModeEnum DataExtractMode
167  {
168  get { return _DataExtractMode; }
169  set { _DataExtractMode = value; }
170  }
171 
172 
173 
174  private FilePattern _BitmapFilePattern;
175 
182  public FilePattern BitmapFilePattern
183  {
184  get { return _BitmapFilePattern; }
185  set { _BitmapFilePattern = value; }
186  }
187 
188  protected PixelData[][,] Pixels;
189 
190 
191  private bool AnimationActive = false;
192  private int AnimationStep = 0;
193  private int AnimationFadeValue = 0;
194  private void Animate()
195  {
196 
197 
198  for (int y = 0; y < AreaHeight; y++)
199  {
200  int yd = y + AreaTop;
201  for (int x = 0; x < AreaWidth; x++)
202  {
203  int xd = x + AreaLeft;
204  MatrixLayer[xd, yd] = GetEffectValue(AnimationFadeValue, Pixels[AnimationStep][x, y]);
205  }
206  }
207 
208 
209 
210  AnimationStep++;
211  if (AnimationStep >= Pixels.GetUpperBound(0))
212  {
213  AnimationStep = 0;
214  if (AnimationBehaviour == AnimationBehaviourEnum.Once)
215  {
216  StopAnimation();
217  }
218  }
219 
220  }
221 
222  private void Clear()
223  {
224  MatrixElementType Off = GetEffectValue(0, new PixelData());
225 
226  for (int y = AreaTop; y <= AreaBottom; y++)
227  {
228 
229  for (int x = AreaLeft; x <= AreaRight; x++)
230  {
231  MatrixLayer[x, y] = Off;
232  }
233  }
234 
235  }
236 
244  protected abstract MatrixElementType GetEffectValue(int TriggerValue, PixelData Pixel);
245 
246 
247  private void ControlAnimation(int FadeValue)
248  {
249  if (FadeValue > 0)
250  {
251  //Start animation
252  this.AnimationFadeValue = FadeValue;
253 
254  if (!AnimationActive)
255  {
256  AnimationActive = true;
257 
258  if (AnimationBehaviour != AnimationBehaviourEnum.Continue)
259  {
260  AnimationStep = 0;
261  }
262  Table.Pinball.Alarms.RegisterIntervalAlarm(AnimationFrameDurationMs, Animate);
263 
264  Animate();
265  }
266  }
267  else
268  {
269  //Stop animation
270  StopAnimation();
271  }
272 
273 
274 
275  }
276 
277  private void StopAnimation()
278  {
279  if (AnimationActive)
280  {
281 
282  try
283  {
284  Table.Pinball.Alarms.UnregisterIntervalAlarm(Animate);
285  }
286  catch { };
287 
288  AnimationActive = false;
289 
290  Clear();
291  }
292  }
293 
294 
295 
296 
301  public override void Trigger(Table.TableElementData TableElementData)
302  {
303  if (InitOK)
304  {
305  int FadeValue = TableElementData.Value;
306  if (FadeMode == FadeModeEnum.OnOff) FadeValue = (FadeValue < 1 ? 0 : 255);
307  ControlAnimation(FadeValue);
308 
309 
310  }
311 
312  }
313 
314  private bool InitOK = false;
315 
316 
322  public override void Init(Table.Table Table)
323  {
324  InitOK = false;
325  Pixels = null;
326  base.Init(Table);
327 
328  //TODO: Insert replace values for file pattern
329  if (BitmapFilePattern.IsValid)
330  {
331 
332  string Filename = BitmapFilePattern.GetFirstMatchingFile(Table.Pinball.GlobalConfig.GetReplaceValuesDictionary()).FullName;
333  if (!Filename.IsNullOrWhiteSpace())
334  {
335  FastImage BM;
336  try
337  {
338  BM = Table.Bitmaps[Filename];
339  }
340  catch (Exception E)
341  {
342  Log.Exception("MatrixBitmapAnimationEffectBase {0} cant initialize. Could not load file {1}.".Build(Name, Filename), E);
343  return;
344  }
345 
346  if (BM.Frames.ContainsKey(BitmapFrameNumber))
347  {
348  int StepCount = AnimationFrameCount;
349  switch (AnimationStepDirection)
350  {
352  if ((BitmapFrameNumber + (StepCount * AnimationStepSize)) > BM.Frames.Count)
353  {
354  StepCount = (BM.Frames.Count - BitmapFrameNumber) / AnimationStepSize;
355  }
356 
357  Pixels = new PixelData[StepCount][,];
358 
359 
360  for (int s = 0; s < StepCount; s++)
361  {
362 
363  Pixels[s] = BM.Frames[BitmapFrameNumber + s].GetClip(AreaWidth, AreaHeight, BitmapLeft, BitmapTop, BitmapWidth, BitmapHeight, DataExtractMode).Pixels;
364  }
365 
366 
367 
368  break;
370  //TODO: Check if there should be a restriction of steps for this direction
371 
372 
373  Pixels = new PixelData[StepCount][,];
374 
375  for (int s = 0; s < StepCount; s++)
376  {
377  Pixels[s] = BM.Frames[BitmapFrameNumber].GetClip(AreaWidth, AreaHeight, BitmapLeft+s*AnimationStepSize, BitmapTop, BitmapWidth, BitmapHeight, DataExtractMode).Pixels;
378  }
379 
380  break;
382  //TODO: Check if there should be a restriction of steps for this direction
383  Pixels = new PixelData[StepCount][,];
384 
385  for (int s = 0; s < StepCount; s++)
386  {
387  Pixels[s] = BM.Frames[BitmapFrameNumber].GetClip(AreaWidth, AreaHeight, BitmapLeft, BitmapTop + s * AnimationStepSize, BitmapWidth, BitmapHeight, DataExtractMode).Pixels;
388  }
389 
390  break;
391  default:
392  StepCount = 1;
393  Pixels = new PixelData[StepCount][,];
394  for (int s = 0; s < StepCount; s++)
395  {
396  Pixels[s] = BM.Frames[BitmapFrameNumber].GetClip(AreaWidth, AreaHeight, BitmapLeft, BitmapTop, BitmapWidth, BitmapHeight, DataExtractMode).Pixels;
397  }
398  break;
399  }
400 
401  Log.Debug("BitmapAnimationEffectBase. Grabbed image clips: W: {0}, H:{1}, BML: {2}, BMT: {3}, BMW: {4}, BMH: {5}, Steps: {6}".Build(new object[] { AreaWidth, AreaHeight, BitmapLeft, BitmapTop, BitmapWidth, BitmapHeight, StepCount }));
402 
403 
404  }
405  else
406  {
407  Log.Warning("MatrixBitmapAnimationEffectBase {0} cant initialize. Frame {1} does not exist in source image {2}.".Build(Name, BitmapFrameNumber, Filename));
408 
409  }
410  }
411  else
412  {
413  Log.Warning("MatrixBitmapAnimationEffectBase {0} cant initialize. No file matches the BitmapFilePattern {1} is invalid".Build(Name, BitmapFilePattern.ToString()));
414  }
415  }
416  else
417  {
418  Log.Warning("MatrixBitmapAnimationEffectBase {0} cant initialize. The BitmapFilePattern {1} is invalid".Build(Name, BitmapFilePattern.ToString()));
419  }
420 
421 
422  InitOK = (Pixels != null && MatrixLayer != null);
423 
424  }
425 
429  public override void Finish()
430  {
431  StopAnimation();
432  Pixels = null;
433  base.Finish();
434  }
435 
436 
437  }
438 }
The namespace DirectOutput.Cab.Toys contains all toy related classes.
Struct holding the data for a single pixel in a bitmap.
Definition: PixelData.cs:12
Base class for effects targeting a matrix of toys (e.g. addressable ledstrip)
static void Warning(string Message)
Writes a warning message to the log.
Definition: Log.cs:134
A simple logger used to record important events and exceptions.
Definition: Log.cs:14
override void Finish()
Finishes the effect and releases object references
static void Debug(string Message="")
Writes the specified debug message to the log file.
Definition: Log.cs:216
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
FastBitmapDataExtractModeEnum
The enum defines how the pixels are extracted from the source image.
Dictionary< int, FastBitmap > Frames
Definition: FastImage.cs:21
AnimationBehaviourEnum
This enum describes the different supported behaviours for animations.
Namespace for objects dealing with layers
override void Trigger(Table.TableElementData TableElementData)
Triggers the effect with the given data.
The namespace DirectOutput.General contains classes for general use.
A file pattern class used to lookup files matching a specified pattern.
Definition: FilePattern.cs:12
override void Init(Table.Table Table)
Initializes the effect. Resolves object references, extracts source image data.
static void Exception(string Message, Exception E=null)
Writes a exception message to the log.
Definition: Log.cs:144