/NetduinoLEDControl/Program.cs
C# | 1105 lines | 794 code | 76 blank | 235 comment | 130 complexity | 182c56f05c9ef398953e081eb867fd4f MD5 | raw file
- //=======================================================================================
- //
- // Purpose: Main program for controlling a 8 x 8 x 8 LED cube using 74HC595 shift
- // registers and 74HC238 3-to-8 line multiplers using the Netduino Mini
- // microcontroller.
- //
- // Copyright (C) 2011 Mark Stevens
- //
- // This software is destributed under the MS-PL licence agreement a copy of which can
- // be found on the codeplex page http://netduinoledcontrol.codeplex.com and in the
- // Licence.txt file distributed with this project.
- //
- //=======================================================================================
- using System;
- using System.Threading;
- using Microsoft.SPOT.Hardware;
- using Microsoft.SPOT;
- using System.Collections;
-
- namespace Coding4Fun.NetduinoLEDControl
- {
- /// <summary>
- /// Main program for the Netduino cube.
- /// </summary>
- public class Program
- {
- #region Enums
-
- /// <summary>
- /// Which axis should we rotate around?
- /// </summary>
- private enum AxisOfRotation
- {
- /// <summary>
- /// Rotate around the X axis.
- /// </summary>
- X,
-
- /// <summary>
- /// Rotate arouns the Y axis.
- /// </summary>
- Y,
-
- /// <summary>
- /// Rotate around the Z axiz.
- /// </summary>
- Z
- };
-
- #endregion
-
- #region Private static variables.
-
- /// <summary>
- /// Letters holding the character set.
- /// </summary>
- private static PlanarBitmap[] characterSet = new PlanarBitmap[29];
-
- /// <summary>
- /// Set up and seed the random number generator.
- /// </summary>
- private static Random rand = new Random((int) (Utility.GetMachineTime().Ticks & 0xffffffff));
-
- /// <summary>
- /// Create a new instance of the cube.
- /// </summary>
- private static LEDCube cube = new LEDCube();
-
- /// <summary>
- /// Buffer to be used to hold the working (not displayed) copy of the cube data.
- /// </summary>
- private static byte[] newFrame = new byte[64];
-
- #endregion
-
- #region Generic support methods.
-
- /// <summary>
- /// Set or rest a specific pixel in the cube.
- /// </summary>
- /// <param name="x">X co-ordinate of the pixel to be set.</param>
- /// <param name="y">Y co-ordinate of thge pixel to be set.</param>
- /// <param name="z">Plane of the pixel to be set.</param>
- /// <param name="value">Turn the pixel on or off: true = turn on, false - turn off</param>
- private static void SetPixel(int x, int y, int z, bool value)
- {
- if ((x >= 0) && (x <= 7) && (y >= 0) && (y <= 7) && (z >= 0) && (z <= 7))
- {
- SetPixel(newFrame, x, y, z, value);
- }
- }
-
- /// <summary>
- /// Set or rest a specific pixel in the specified buffer.
- /// </summary>
- /// <param name="buffer">Buffer to set the pixel in.</param>
- /// <param name="x">X co-ordinate of the pixel to be set.</param>
- /// <param name="y">Y co-ordinate of thge pixel to be set.</param>
- /// <param name="z">Plane of the pixel to be set.</param>
- /// <param name="value">Turn the pixel on or off: true = turn on, false - turn off</param>
- private static void SetPixel(byte[] buffer, int x, int y, int z, bool value)
- {
- int whichOne = (y * 8) + z;
- if (value)
- {
- buffer[whichOne] |= (byte) ((1 << x) & 0xff);
- }
- else
- {
- buffer[whichOne] &= (byte) ((~(1 << x)) & 0xff);
- }
- }
-
- /// <summary>
- /// Get the value of a pixel
- /// </summary>
- /// <param name="x">X co-ordinate of the pixel to be set.</param>
- /// <param name="y">Y co-ordinate of thge pixel to be set.</param>
- /// <param name="z">PLane of the pixel to be set.</param>
- /// <returns>True if the pixel is turned on, false otherwise.</returns>
- private static bool GetPixel(byte[] buffer, int x, int y, int z)
- {
- int whichOne = (y * 8) + z;
- return ((buffer[whichOne] & ((byte) ((1 << x) & 0xff))) != 0);
- }
-
- /// <summary>
- /// Clear the cube.
- /// </summary>
- /// <remarks>
- /// Clear the cube of data and refresh the cube buffer.
- /// </remarks>
- private static void ClearCube()
- {
- ClearBuffer(newFrame);
- cube.ClearCube();
- }
-
- /// <summary>
- /// Clear the specified buffer (i.e. set each byte to zero).
- /// </summary>
- /// <param name="buffer">Buffer to clear.</param>
- private static void ClearBuffer(byte[] buffer)
- {
- for (int count = 0; count < buffer.Length; count++)
- {
- buffer[count] = 0;
- }
- }
-
- /// <summary>
- /// Coipy one frame (buffer) into a new frame (buffer);
- /// </summary>
- /// <param name="source">Source bytes to copy.</param>
- /// <param name="destination">Destination location for the copy of the data.</param>
- private static void CopyFrame(byte[] source, byte[] destination)
- {
- for (int count = 0; count < source.Length; count++)
- {
- destination[count] = source[count];
- }
- }
-
- #endregion
-
- #region Some test methods.
-
- /// <summary>
- /// A quick test to verify that all of the LEDs work correctly.
- /// </summary>
- private static void Test()
- {
- ClearCube();
- while (true)
- {
- for (int bit = 0; bit < 8; bit++)
- {
- byte v;
- v = (byte) ((1 << bit) & 0xff);
- for (int count = 0; count < 64; count++)
- {
- newFrame[count] = v;
- }
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(1);
- }
- }
- }
-
- /// <summary>
- /// Test all of the LEDs in the cube.
- /// </summary>
- private static void TestAllLeds()
- {
- for (int z = 0; z < 8; z++)
- {
- for (int y = 0; y < 8; y++)
- {
- for (int x = 0; x < 8; x++)
- {
- ClearCube();
- SetPixel(x, y, z, true);
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(5);
- }
- }
- }
- }
-
- /// <summary>
- /// Cycle through each LED in the specified layer.
- /// </summary>
- /// <param name="layer">Layer to test.</param>
- private static void TestLayer(int layer)
- {
- for (int z = 0; z < 8; z++)
- {
- for (int x = 0; x < 8; x++)
- {
- ClearCube();
- SetPixel(x, layer, z, true);
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(5);
- }
- }
- }
-
- #endregion
-
- #region Bouncing planes.
-
- /// <summary>
- /// Show planes moving from the bottom of the cube to the top of the cube.
- /// </summary>
- private static void BouncePlaneBottomToTop(int noCycles)
- {
- int direction = 1;
- int plane = 0;
- for (int repeat = 0; repeat < noCycles; repeat++)
- {
- for (int index = 0; index < 8; index++)
- {
- ClearCube();
- int offset = plane * 8;
- for (int counter = 0; counter < 8; counter++)
- {
- newFrame[offset + counter] = 0xff;
- }
- plane += direction;
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(100);
- }
- direction *= -1;
- if (plane == 8)
- {
- plane = 7;
- }
- if (plane < 0)
- {
- plane = 0;
- }
- }
- }
-
- /// <summary>
- /// Move a plane from the back of the cube to the front of the cube.
- /// </summary>
- private static void BouncePlaneLeftToRight(int noCycles)
- {
- for (int repeat = 0; repeat < noCycles; repeat++)
- {
- byte value = 1;
-
- for (int index = 0; index < 8; index++)
- {
- for (int counter = 0; counter < newFrame.Length; counter++)
- {
- newFrame[counter] = value;
- }
- cube.UpdateBuffer(newFrame);
- value <<= 1;
- Thread.Sleep(100);
- }
- value = 128;
- for (int index = 7; index >= 0; index--)
- {
- for (int counter = 0; counter < newFrame.Length; counter++)
- {
- newFrame[counter] = value;
- }
- cube.UpdateBuffer(newFrame);
- value >>= 1;
- Thread.Sleep(100);
- }
- }
- }
-
- /// <summary>
- /// Show a plane moving from the back to the front of the cube.
- /// </summary>
- private static void BouncePlaneBackToFront(int noCycles)
- {
- int direction = 1;
- int plane = 0;
-
- for (int repeat = 0; repeat < noCycles; repeat++)
- {
- byte value = 1;
- for (int index = 0; index < 8; index++)
- {
- ClearCube();
- for (int counter = 0; counter < 8; counter++)
- {
- newFrame[(counter * 8) + plane] = 0xff;
- }
- cube.UpdateBuffer(newFrame);
- plane += direction;
- value <<= 1;
- Thread.Sleep(100);
- }
- direction *= -1;
- if (plane == 8)
- {
- plane = 7;
- }
- if (plane < 0)
- {
- plane = 0;
- }
- }
- }
-
- #endregion
-
- #region Showing a message.
-
- /// <summary>
- /// Get the dot pattern with the specified name.
- /// </summary>
- /// <param name="name">Name of the bitmap to look up.</param>
- /// <returns>Array of bytes containing the dot patern for the character.</returns>
- private static byte[] LookupPattern(string name)
- {
- foreach (PlanarBitmap l in characterSet)
- {
- if (l.Name == name)
- {
- return (l.DotPattern);
- }
- }
- return (null);
- }
-
- /// <summary>
- /// Show the string from the back to the front of the cube.
- /// </summary>
- /// <param name="message">Message to display.</param>
- private static void ShowMessage(string message)
- {
- for (int index = 0; index < message.Length; index++)
- {
- byte[] dotPattern = LookupPattern(message[index].ToString());
- for (int plane = 0; plane < 8; plane++)
- {
- ClearCube();
- if (dotPattern != null)
- {
- for (int row = 0; row < 8; row++)
- {
- newFrame[(row * 8) + plane] = dotPattern[row];
- }
- cube.UpdateBuffer(newFrame);
- }
- Thread.Sleep(50);
- }
- ClearCube();
- }
- }
-
- #endregion
-
- #region Rain effect methods.
-
- /// <summary>
- /// Add rain drops to the cube.
- /// </summary>
- /// <remarks>
- /// The algorithm will always add the specified number of rain drops to the cube.
- /// If the selected position is already occupied then a new psoition will be
- /// selected.
- /// </remarks>
- /// <param name="count">Number of rain drops to add.</param>
- /// <param name="plane">
- /// Starting plane. -1 indicates the plane should be random otherwise the
- /// specified starting plane will be used.
- /// </param>
- private static void AddDrops(int count, int plane = -1)
- {
- for (int drops = 0; drops < count; drops++)
- {
- bool findingSpace = true;
- while (findingSpace)
- {
- int x = rand.Next() % 8;
- int y = rand.Next() % 8;
- int z;
-
- if (plane == -1)
- {
- z = rand.Next() % 8;
- }
- else
- {
- z = plane;
- }
-
- int position = (z * 8) + y;
- byte value = (byte) ((1 << x) & 0xff);
- if ((newFrame[position] & value) == 0) // Check if there is already a rain drop in this position.
- {
- newFrame[position] |= value;
- findingSpace = false;
- }
- }
- }
- }
-
- /// <summary>
- /// Produce an effect of rain falling through the cube.
- /// </summary>
- /// <remarks>
- /// The initial position of the drops is random New drops will always be
- /// added in to the top plane.
- ///
- /// The number of drops leaving the cube will be calculated and the same
- /// number of drops will always be added in at the top of the cube.
- /// </remarks>
- /// <param name="noDrops">Number of drops to start with.</param>
- /// <param name="cycles">
- /// Number of cycles to run for. One cycle represnes the movement of one
- /// drop down through the cube by one layer.
- /// </param>
- private static void Rain(int noDrops, int cycles)
- {
- ClearCube();
- AddDrops(noDrops);
- cube.UpdateBuffer(newFrame);
- for (int currentCycle = 0; currentCycle < cycles; currentCycle++)
- {
- #region Work out how many drops are on the bottom plane.
-
- int bitCount = 0;
- for (int verticalPlane = 0; verticalPlane < 8; verticalPlane++)
- {
- byte value = 1;
- for (int bit = 0; bit < 8; bit++)
- {
- if ((newFrame[verticalPlane] & value) > 0)
- {
- bitCount++;
- }
- value <<= 1;
- }
- }
-
- #endregion
-
- #region Move the drops down by one plane and clear the top plane.
-
- for (int plane = 8; plane < 64; plane++)
- {
- newFrame[plane - 8] = newFrame[plane];
- }
- for (int b = 56; b < 64; b++)
- {
- newFrame[b] = 0;
- }
-
- #endregion
-
- AddDrops(bitCount, 7); // Add in the number of drops leaving to the top plane.
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(75);
- }
- }
-
- #endregion
-
- #region Wave effects.
-
- /// <summary>
- /// Perform a Mexican wave.
- /// </summary>
- /// <param name="noCycles">Number of complete waves to perform.</param>
- private static void MexicanWave(int noCycles = 10)
- {
- ClearCube();
- for (int z = 0; z < 8; z++)
- {
- SetPixel(0, 7, z, true);
- }
- for (int cycle = 0; cycle < noCycles; cycle++)
- {
- for (int height = 7; height >= 0; height--)
- {
- for (int bytes = 0; bytes < 64; bytes++)
- {
- newFrame[bytes] <<= 1;
- }
- for (int z = 0; z < 8; z++)
- {
- SetPixel(0, height, z, true);
- }
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(100);
- }
- for (int height = 7; height >= 0; height--)
- {
- for (int bytes = 0; bytes < 64; bytes++)
- {
- newFrame[bytes] <<= 1;
- }
- for (int z = 0; z < 8; z++)
- {
- SetPixel(0, 7 - height, z, true);
- }
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(100);
- }
- }
- }
-
- /// <summary>
- /// Show a triangular wave.
- /// </summary>
- /// <param name="noCycles">Number of complete waves to perform.</param>
- private static void TriangularWave(int noCycles = 10)
- {
- ClearCube();
- for (int cycle = 0; cycle < noCycles; cycle++)
- {
- for (int height = 7; height >= 0; height--)
- {
- for (int bytes = 0; bytes < 64; bytes++)
- {
- newFrame[bytes] <<= 1;
- }
- for (int z = 0; z < 8; z++)
- {
- SetPixel(z, height, z, true);
- }
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(100);
- }
- for (int height = 7; height >= 0; height--)
- {
- for (int bytes = 0; bytes < 64; bytes++)
- {
- newFrame[bytes] <<= 1;
- }
- for (int z = 0; z < 8; z++)
- {
- SetPixel(z, 7 - height, z, true);
- }
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(100);
- }
- }
- }
-
- #endregion
-
- #region Rotation Effects.
-
- /// <summary>
- /// Rotate the source buffer around a particular point in a plane.
- /// </summary>
- /// <param name="axis">Axis to rotate arouns.</param>
- /// <param name="xOffset">X offset of the origin.</param>
- /// <param name="yOffset">Y offset of the origin.</param>
- /// <param name="zOffset">Z offset of the origin.</param>
- /// <param name="theta">angle to roate through.</param>
- /// <param name="source">Buffer holding the original data.</param>
- /// <param name="destination">New buffer holding the rotated pixels.</param>
- private static void RotateAroundAxis(AxisOfRotation axis, float xOffset, float yOffset, float zOffset, int theta, byte[] source, byte[] destination)
- {
- ClearBuffer(destination);
- float cosTheta = ((float) Microsoft.SPOT.Math.Cos(theta)) / 1000;
- float sinTheta = ((float) Microsoft.SPOT.Math.Sin(theta)) / 1000;
- for (int x = 0; x < 8; x++)
- {
- for (int y = 0; y < 8; y++)
- {
- for (int z = 0; z < 8; z++)
- {
- if (GetPixel(source, x, y, z))
- {
- float xCoord, yCoord, zCoord;
- int newX = 0, newY = 0, newZ = 0;
-
- switch (axis)
- {
- case AxisOfRotation.X:
- xCoord = x - xOffset;
- yCoord = y - yOffset;
- newX = (int) System.Math.Round(((xCoord * cosTheta) - (yCoord * sinTheta)) + xOffset);
- newY = (int) System.Math.Round(((xCoord * sinTheta) + (yCoord * cosTheta)) + yOffset);
- newZ = z;
- break;
- case AxisOfRotation.Y:
- xCoord = x - xOffset;
- zCoord = z - zOffset;
- newX = (int) System.Math.Round(((zCoord * sinTheta) + (xCoord * cosTheta)) + xOffset);
- newY = y;
- newZ = (int) System.Math.Round(((zCoord * cosTheta) - (xCoord * sinTheta)) + zOffset);
- break;
- case AxisOfRotation.Z:
- yCoord = y - yOffset;
- zCoord = z - zOffset;
- newX = x;
- newY = (int) System.Math.Round(((yCoord * cosTheta) - (zCoord * sinTheta)) + xOffset);
- newZ = (int) System.Math.Round(((yCoord * sinTheta) + (zCoord * sinTheta)) + zOffset);
- break;
- }
-
- if ((newX >= 0) && (newX <= 7) && (newY >= 0) && (newY <= 7) && (newZ >= 0) && (newZ <= 7))
- {
- SetPixel(destination, newX, newY, newZ, true);
- }
- }
- }
- }
- }
- }
-
- /// <summary>
- /// Spin the given buffer through 360 degrees for the specified number of times.
- /// </summary>
- /// <param name="buffer">Cube buffer to rotate.</param>
- /// <param name="x">x Coordinat to spin the buffer around (default = 3.5)</param>
- /// <param name="y">y Coordinat to spin the buffer around (default = 3.5)</param>
- /// <param name="z">z Coordinat to spin the buffer around (default = 3.5)</param>
- /// <returns>16 frame buffer which has been animated.</returns>
- private static byte[][] SpinBufferAroundYAxis(byte[] buffer, float x = 3.5F, float y = 3.5F, float z = 3.5F)
- {
- byte[][] frames = new byte[16][];
- frames[0] = new byte[64];
- CopyFrame(buffer, frames[0]);
- for (int iteration = 1; iteration < 16; iteration++)
- {
- frames[iteration] = new byte[64];
- RotateAroundAxis(AxisOfRotation.Y, x, y, z, (int) (22.5 * iteration), frames[0], frames[iteration]);
- }
- return (frames);
- }
-
- /// <summary>
- /// Put the requested letter in the centre of the cube and make it spin.
- /// </summary>
- /// <remarks>
- /// This method spins a character round the centre of the cube. It works but does require
- /// the viewer to squint a little to best appreciate the effect.
- /// </remarks>
- /// <param name="character">Letter to show in the cube.</param>
- /// <param name="cycles">Number of rotations to make.</param>
- /// <param name="pause">How long (in milliseconds) between the movement from one angle to the next.</param>
- /// <returns>Animation ready for playing.</returns>
- private static void PrepareSpinningLetter(ArrayList animations, string character, int cycles, int pause = 20)
- {
- Debug.Print("Preparing spinning letter - " + character.ToString());
- ClearCube();
- byte[] dotPattern = LookupPattern(character);
- if (dotPattern != null)
- {
- for (int row = 0; row < 8; row++)
- {
- newFrame[(row * 8) + 3] = dotPattern[row];
- }
- }
- Animation spinningLetter = new Animation();
- spinningLetter.Frames = SpinBufferAroundYAxis(newFrame, 3, 3, 3);
- spinningLetter.Repeat = cycles;
- spinningLetter.FrameDelay = pause;
- animations.Add(spinningLetter);
- Debug.Print("Spinning letter complete.");
- }
-
- /// <summary>
- /// Display a spinning horizontal bar.
- /// </summary>
- /// <param name="animations">Animation collection to add this animation to.</param>
- /// <param name="cycles">Number of cycles to display the bar.</param>
- /// <param name="pause">Pause between angular rotations.</param>
- private static void PrepareSpinningBar(ArrayList animations, int cycles, int pause)
- {
- Debug.Print("Preparing spinning bar.");
- ClearCube();
- for (int x = 0; x < 8; x++)
- {
- SetPixel(x, 3, 3, true);
- }
- Animation spinningBar = new Animation();
- spinningBar.Frames = SpinBufferAroundYAxis(newFrame);
- spinningBar.Repeat = cycles;
- spinningBar.FrameDelay = pause;
- animations.Add(spinningBar);
- Debug.Print("Spinning bar complete.");
- }
-
- /// <summary>
- /// Spin a vertical plane.
- /// </summary>
- /// <param name="animations">Animation collection to add this animation to.</param>
- /// <param name="cycles">Number of time to repeat the animation.</param>
- /// <param name="pause">Pause between the angular rotations.</param>
- private static void PrepareSpinningPlanes(ArrayList animations, int cycles, int pause)
- {
- Animation leadInAnimation = new Animation();
- Animation leadOutAnimation = new Animation();
- Animation spinningAnimation = new Animation();
-
- Debug.Print("Preparing spinning plane.");
- leadInAnimation.Frames = new byte[8][];
- //
- // Now slide in the layer.
- //
- ClearCube();
- for (int x = 0; x < 8; x++)
- {
- for (int y = 0; y < 8; y++)
- {
- SetPixel(x, y, 7 - x, true);
- }
- leadInAnimation.Frames[x] = new byte[64];
- CopyFrame(newFrame, leadInAnimation.Frames[x]);
- }
- animations.Add(leadInAnimation);
- //
- // Setup the spinning animation.
- //
- ClearCube();
- for (int x = 0; x < 8; x++)
- {
- for (int y = 0; y < 8; y++)
- {
- SetPixel(x, y, 7 - x, true);
- }
- }
- spinningAnimation.Frames = SpinBufferAroundYAxis(newFrame);
- spinningAnimation.Repeat = cycles;
- spinningAnimation.FrameDelay = pause;
- animations.Add(spinningAnimation);
- //
- // Slide out the layer.
- //
- leadOutAnimation.Frames = new byte[8][];
- for (int x = 0; x < 8; x++)
- {
- for (int y = 0; y < 8; y++)
- {
- SetPixel(x, y, 7 - x, false);
- }
- leadOutAnimation.Frames[x] = new byte[64];
- CopyFrame(newFrame, leadOutAnimation.Frames[x]);
- }
- animations.Add(leadOutAnimation);
- Debug.Print("Spinning plane complete.");
- }
-
- /// <summary>
- /// Place a vertical plane in the cube and then split it in two horizontally. Spin the
- /// top half of the planani-clockwise around Y and spin the bottom half of the plane
- /// clockwise around the Y axis.
- /// </summary>
- /// <param name="animations">Animation collection to add this animation to.</param>
- /// <param name="cycles">Number of time to repeat the animation.</param>
- /// <param name="pause">Pause between the angular rotations.</param>
- private static void PrepareContraRotatingPlanes(ArrayList animations, int cycles, int pause)
- {
- Animation leadInAnimation = new Animation();
- Animation leadOutAnimation = new Animation();
- Animation spinningAnimation = new Animation();
-
- Debug.Print("Preparing contra rotating planes.");
- leadInAnimation.Frames = new byte[8][];
- //
- // Slide in the layer.
- //
- ClearCube();
- for (int x = 0; x < 8; x++)
- {
- for (int y = 0; y < 8; y++)
- {
- SetPixel(x, y, 7 - x, true);
- }
- leadInAnimation.Frames[x] = new byte[64];
- CopyFrame(newFrame, leadInAnimation.Frames[x]);
- }
- animations.Add(leadInAnimation);
- //
- // Setup the spinning animation.
- //
- ClearCube();
- for (int x = 0; x < 8; x++)
- {
- for (int y = 0; y < 8; y++)
- {
- SetPixel(x, y, 7 - x, true);
- }
- }
- spinningAnimation.Frames = SpinBufferAroundYAxis(newFrame);
- for (int frame = 15; frame >= 0; frame--)
- {
- for (int y = 0; y < 4; y++)
- {
- for (int x = 0; x < 8; x++)
- {
- for (int z = 0; z < 8; z++)
- {
- SetPixel(spinningAnimation.Frames[15 - frame], x, y, z, GetPixel(spinningAnimation.Frames[frame], x, 4, z));
- }
- }
- }
- }
- spinningAnimation.Repeat = cycles;
- spinningAnimation.FrameDelay = pause;
- animations.Add(spinningAnimation);
- //
- // Slide out the layer.
- //
- leadOutAnimation.Frames = new byte[8][];
- for (int x = 0; x < 8; x++)
- {
- for (int y = 0; y < 8; y++)
- {
- SetPixel(x, y, 7 - x, false);
- }
- leadOutAnimation.Frames[x] = new byte[64];
- CopyFrame(newFrame, leadOutAnimation.Frames[x]);
- }
- animations.Add(leadOutAnimation);
- Debug.Print("Spinning plane complete.");
- }
-
- /// <summary>
- /// Prepare a spinning cross made connecting the diagonals.
- /// </summary>
- /// <param name="animations">Animation collection to add this animation to.</param>
- /// <param name="cycles">Number of times to rotate the cross.</param>
- /// <param name="pause">Pause between the angular rotations.</param>
- private static void PrepareSpinningDiagonals(ArrayList animations, int cycles, int pause)
- {
- ClearBuffer(newFrame);
- for (int counter = 0; counter < 8; counter++)
- {
- SetPixel(counter, counter, counter, true);
- SetPixel(counter, 7 - counter, 7 - counter, true);
- SetPixel(7 - counter, 7 - counter, counter, true);
- SetPixel(7 - counter, counter, 7 - counter, true);
- }
- Animation spinningDiagonals = new Animation();
- spinningDiagonals.Frames = SpinBufferAroundYAxis(newFrame, 3.5F, 3.5F, 3.5F);
- spinningDiagonals.Repeat = cycles;
- spinningDiagonals.FrameDelay = pause;
- animations.Add(spinningDiagonals);
- }
-
- #endregion
-
- #region Cube methods.
-
- /// <summary>
- /// Slide a 4 x 4 cube around the bottom layer of the cube.
- /// </summary>
- private static void SlidingCube()
- {
- ClearCube();
- for (int x = 0; x < 4; x++)
- {
- for (int y = 0; y < 4; y++)
- {
- for (int z = 0; z < 4; z++)
- {
- SetPixel(x, y, z, true);
- }
- }
- }
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(100);
- for (int x = 4; x <= 7; x++)
- {
- for (int y = 0; y < 4; y++)
- {
- for (int z = 0; z < 4; z++)
- {
- SetPixel(x, y, z, true);
- SetPixel(x - 4, y, z, false);
- }
- }
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(100);
- }
- for (int z = 4; z <= 7; z++)
- {
- for (int x = 4; x <= 7; x++)
- {
- for (int y = 0; y < 4; y++)
- {
- SetPixel(x, y, z, true);
- SetPixel(x, y, z - 4, false);
- }
- }
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(100);
- }
- for (int x = 7; x >= 4; x--)
- {
- for (int y = 0; y < 4; y++)
- {
- for (int z = 4; z <= 7; z++)
- {
- SetPixel(x, y, z, false);
- SetPixel(x - 4, y, z, true);
- }
- }
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(100);
- }
- for (int z = 7; z >= 4; z--)
- {
- for (int x = 0; x <= 4; x++)
- {
- for (int y = 0; y <= 4; y++)
- {
- SetPixel(x, y, z - 4, true);
- SetPixel(x, y, z, false);
- }
- }
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(100);
- }
- }
-
- /// <summary>
- /// Create a pulsating cube animation.
- /// </summary>
- /// <param name="animations">Animations collaction to add this animation to.</param>
- /// <param name="cycles">Number of times to repeat the animation.</param>
- /// <param name="pause">Number of milliseconds to pause between the frames.</param>
- private static void PreparePulsingCube(ArrayList animations, int cycles, int pause)
- {
- Animation pulsingCube = new Animation();
- pulsingCube.Frames = new byte[6][];
- for (int lower = 3; lower > 0; lower--)
- {
- pulsingCube.Frames[3 - lower] = new byte[64];
- for (int x = lower; x <= 7 - lower; x++)
- {
- for (int y = lower; y <= 7 - lower; y++)
- {
- for (int z = lower; z <= 7 - lower; z++)
- {
- SetPixel(pulsingCube.Frames[3 - lower], x, y, z, true);
- }
- }
- }
- }
- for (int counter = 0; counter < 3; counter++)
- {
- pulsingCube.Frames[5 - counter] = new byte[64];
- CopyFrame(pulsingCube.Frames[counter], pulsingCube.Frames[5 - counter]);
- }
- pulsingCube.Repeat = cycles;
- pulsingCube.FrameDelay = pause;
- animations.Add(pulsingCube);
- }
-
- #endregion
-
- #region Fireworks.
-
- /// <summary>
- /// Add the fireworks to the cube frame buffer.
- /// </summary>
- /// <param name="fireworks">Array of fireworks to add.</param>
- private static void AddFireworksToBuffer(Firework[] fireworks)
- {
- ClearCube();
- foreach (Firework firework in fireworks)
- {
- if (firework.IsClimbing)
- {
- SetPixel(firework.X, firework.CurrentHeight, firework.Z, true);
- }
- if (firework.IsExploding)
- {
- foreach (Point shard in firework.Shards)
- {
- SetPixel(shard.X, shard.Y, shard.Z, true);
- }
- }
- }
- }
-
- /// <summary>
- /// Create a firework display in the cube.
- /// </summary>
- /// <param name="numberOfFireworks">Number of fireworks to add to the cube.</param>
- /// <param name="noCycles">Number of cycles to run this animation for.</param>
- private static void FireworkDisplay(int numberOfFireworks, int noCycles = 10)
- {
- Firework[] fireworks = new Firework[numberOfFireworks];
- for (int counter = 0; counter < numberOfFireworks; counter++)
- {
- fireworks[counter] = new Firework();
- }
- bool processing = true;
- while (processing)
- {
- processing = false;
- for (int counter = 0; counter < numberOfFireworks; counter++)
- {
- processing |= fireworks[counter].Move();
- }
- if (processing)
- {
- AddFireworksToBuffer(fireworks);
- cube.UpdateBuffer(newFrame);
- Thread.Sleep(100);
- }
- }
- }
-
- #endregion
-
- /// <summary>
- /// Main program loop.
- /// </summary>
- public static void Main()
- {
- #region Setup the character set.
-
- characterSet[0] = new PlanarBitmap("A", new byte[] { 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x1C, 0x0 });
- characterSet[1] = new PlanarBitmap("B", new byte[] { 0x1E, 0x22, 0x22, 0x1E, 0x22, 0x22, 0x1E, 0x0 });
- characterSet[2] = new PlanarBitmap("C", new byte[] { 0x1C, 0x22, 0x2, 0x2, 0x2, 0x22, 0x1C, 0x0 });
- characterSet[3] = new PlanarBitmap("D", new byte[] { 0xE, 0x12, 0x22, 0x22, 0x22, 0x12, 0xE, 0x0 });
- characterSet[4] = new PlanarBitmap("E", new byte[] { 0x3E, 0x2, 0x2, 0x1E, 0x2, 0x2, 0x3E, 0x0 });
- characterSet[5] = new PlanarBitmap("F", new byte[] { 0x2, 0x2, 0x2, 0x1E, 0x2, 0x2, 0x3E, 0x0 });
- characterSet[6] = new PlanarBitmap("G", new byte[] { 0x1C, 0x22, 0x22, 0x3A, 0x2, 0x22, 0x1C, 0x0 });
- characterSet[7] = new PlanarBitmap("H", new byte[] { 0x22, 0x22, 0x22, 0x3E, 0x22, 0x22, 0x22, 0x0 });
- characterSet[8] = new PlanarBitmap("I", new byte[] { 0x3E, 0x8, 0x8, 0x8, 0x8, 0x8, 0x3E, 0x0 });
- characterSet[9] = new PlanarBitmap("J", new byte[] { 0xC, 0x12, 0x10, 0x10, 0x10, 0x10, 0x38, 0x0 });
- characterSet[10] = new PlanarBitmap("K", new byte[] { 0x22, 0x12, 0xA, 0x6, 0xA, 0x12, 0x22, 0x0 });
- characterSet[11] = new PlanarBitmap("L", new byte[] { 0x3E, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x0 });
- characterSet[12] = new PlanarBitmap("M", new byte[] { 0x22, 0x22, 0x22, 0x2A, 0x2A, 0x36, 0x22, 0x0 });
- characterSet[13] = new PlanarBitmap("N", new byte[] { 0x22, 0x22, 0x32, 0x2A, 0x26, 0x22, 0x22, 0x0 });
- characterSet[14] = new PlanarBitmap("O", new byte[] { 0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x1C, 0x0 });
- characterSet[15] = new PlanarBitmap("P", new byte[] { 0x2, 0x2, 0x2, 0x1E, 0x22, 0x22, 0x1E, 0x0 });
- characterSet[16] = new PlanarBitmap("Q", new byte[] { 0x2C, 0x12, 0x2A, 0x22, 0x22, 0x22, 0x1C, 0x0 });
- characterSet[17] = new PlanarBitmap("R", new byte[] { 0x22, 0x12, 0xA, 0x1E, 0x22, 0x22, 0x1E, 0x0 });
- characterSet[18] = new PlanarBitmap("S", new byte[] { 0x1E, 0x20, 0x20, 0x1C, 0x2, 0x2, 0x3C, 0x0 });
- characterSet[19] = new PlanarBitmap("T", new byte[] { 0x8, 0x8, 0x8, 0x8, 0x8, 0x8, 0x3E, 0x0 });
- characterSet[20] = new PlanarBitmap("U", new byte[] { 0x1C, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x0 });
- characterSet[21] = new PlanarBitmap("V", new byte[] { 0x8, 0x14, 0x22, 0x22, 0x22, 0x22, 0x22, 0x0 });
- characterSet[22] = new PlanarBitmap("W", new byte[] { 0x14, 0x2A, 0x2A, 0x2A, 0x22, 0x22, 0x22, 0x0 });
- characterSet[23] = new PlanarBitmap("X", new byte[] { 0x22, 0x22, 0x14, 0x8, 0x14, 0x22, 0x22, 0x0 });
- characterSet[24] = new PlanarBitmap("Y", new byte[] { 0x8, 0x8, 0x8, 0x8, 0x36, 0x22, 0x22, 0x0 });
- characterSet[25] = new PlanarBitmap("Z", new byte[] { 0x3E, 0x2, 0x4, 0x8, 0x10, 0x20, 0x3E, 0x0 });
- characterSet[26] = new PlanarBitmap("RightArrow", new byte[] { 0x10, 0x30, 0x7F, 0xFF, 0x70, 0x30, 0x10, 0x0 });
- characterSet[27] = new PlanarBitmap("Circle", new byte[] { 0x18, 0x3C, 0x7E, 0xFF, 0xFF, 0x7E, 0x3C, 0x18 });
- characterSet[28] = new PlanarBitmap("SnowFlake", new byte[] { 0x99, 0x42, 0x24, 0x99, 0x99, 0x24, 0x42, 0x99 });
-
- #endregion
-
- ClearCube();
- Thread display = new Thread(new ThreadStart(cube.DisplayBuffer));
- display.Start();
- ArrayList animations = new ArrayList();
- PreparePulsingCube(animations, 2, 200);
- PrepareSpinningLetter(animations, "S", 2, 100);
- PrepareSpinningLetter(animations, "P", 2, 100);
- PrepareSpinningLetter(animations, "I", 2, 100);
- PrepareSpinningLetter(animations, "N", 2, 100);
- PrepareSpinningPlanes(animations, 2, 100);
- PrepareContraRotatingPlanes(animations, 2, 100);
- PrepareSpinningLetter(animations, "Circle", 4, 100);
- PrepareSpinningLetter(animations, "SnowFlake", 4, 100);
- while (true)
- {
- ShowMessage("NETDUINOROCKS");
- TriangularWave(4);
- MexicanWave(4);
- foreach (Animation animation in animations)
- {
- animation.Play(cube);
- }
- Rain(10, 100);
- for (int counter = 0; counter < 10; counter++)
- {
- FireworkDisplay(1);
- }
- }
- }
- }
- }