private void swapBuffers() { Interactive8BitImage temp = renderedScene; renderedScene = nextBuffer; nextBuffer = temp; }
/// <summary> /// Creates a new SnowDrift to fit the indicated screen size. /// </summary> /// <param name="screenSize">Size of the screen to fill with snowflakes.</param> public SnowDrift(Size screenSize) { // Add in enough room so that snowflakes can drift off screen without just flashing away screenSize.Width += (int)SnowFlake.FLAKE_SIZES.Max() * 2; screenSize.Height += (int)SnowFlake.FLAKE_SIZES.Max() * 2; this.screenSize = screenSize; // Create a black and white buffer based on the adjusted screen sized nextBuffer = new Interactive8BitImage(screenSize.Width, screenSize.Height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed); nextBuffer.SetAlpha(byte.MaxValue); renderedScene = new Interactive8BitImage(screenSize.Width, screenSize.Height, System.Drawing.Imaging.PixelFormat.Format8bppIndexed); renderedScene.SetAlpha(byte.MaxValue); // Create the wind variations generalDirection = new Vector(Random.Float(-3.5f, 3.5f), Random.Float(1, 2.5f)); Vector variance = new Vector(8, 3); windVariations = new WindField[60]; for (int i = 0; i < windVariations.Length; i++) { windVariations[i] = new WindField(screenSize.Width, screenSize.Height, generalDirection, variance, new Size(15, 15)); } snowflakes = new HashSet <SnowFlake>(Properties.Settings.Default.MaximumNumberOfFlakes); }
/// <summary> /// Draws an image onto the current image. Transparencies do not apply, but it's fast. /// </summary> /// <param name="toDraw">The image to draw.</param> /// <param name="x">The location of x to draw at.</param> /// <param name="y">The location of y to draw at.</param> public void OverlayImage(Interactive8BitImage toDraw, int x, int y) { int columnWidth = toDraw.width; int rowHeight = toDraw.height; int heightCutoff = 0; int widthCutoff = 0; if (x < 0) { widthCutoff = x; columnWidth -= widthCutoff; } if (y < 0) { heightCutoff = y; rowHeight += heightCutoff; } if (x + toDraw.width > this.width) { columnWidth -= (x + toDraw.width - this.width); } if (y + toDraw.height > this.height) { rowHeight -= y + toDraw.height - this.height; } if (bytesPixel == 4 && toDraw.bytesPixel == 4 && columnWidth > 0 && rowHeight > 0) { for (int row = 0; row < rowHeight; row++) { Array.Copy(toDraw.pixels, (row - heightCutoff) * toDraw.bytesLine, this.pixels, (y + row - heightCutoff) * this.bytesLine + x * this.bytesPixel, columnWidth * toDraw.bytesPixel); } } needsRefresh = true; }
/// <summary> /// Draws an image onto the current image. Transparencies do apply but it's slower than OverlayImage. /// </summary> /// <param name="toDraw">The image to draw.</param> /// <param name="x">The location of x to draw at.</param> /// <param name="y">The location of y to draw at.</param> public void DrawImage(Interactive8BitImage toDraw, int x, int y) { //Source for blending equations //http://en.wikipedia.org/wiki/Alpha_compositing //http://en.wikipedia.org/wiki/Transparency_%28graphic%29 int columnWidth = toDraw.width; int rowHeight = toDraw.height; int heightCutoff = 0; int widthCutoff = 0; if (x < 0) { widthCutoff = x; columnWidth -= widthCutoff; } if (y < 0) { heightCutoff = y; rowHeight += heightCutoff; } if (x + toDraw.width > this.width) { columnWidth -= (x + toDraw.width - this.width); } if (y + toDraw.height > this.height) { rowHeight -= y + toDraw.height - this.height; } byte thisA; byte thatA; int A; int R; int G; int B; int sourceRow; int targetRow; int thisCurrentColor; int thatCurrentColor; if (bytesPixel == 4 && toDraw.bytesPixel == 4 && columnWidth > 0 && rowHeight > 0) { for (int row = 0; row < rowHeight; row++) { sourceRow = (row - heightCutoff) * toDraw.bytesLine; targetRow = (y + row - heightCutoff) * this.bytesLine + x * this.bytesPixel; for (int column = 0; column < columnWidth; column++) { thisCurrentColor = targetRow + column * this.bytesPixel; thatCurrentColor = sourceRow + column * toDraw.bytesPixel; thisA = this.pixels[thisCurrentColor + ALPHA_BIT]; thatA = toDraw.pixels[thatCurrentColor + ALPHA_BIT]; A = (thatA + thisA * (byte.MaxValue - thatA));// thisA + thatA; R = (this.pixels[thisCurrentColor + RED_BIT] * thisA * (byte.MaxValue - thatA) + toDraw.pixels[thatCurrentColor + RED_BIT] * thatA) / A; G = (this.pixels[thisCurrentColor + GREEN_BIT] * thisA * (byte.MaxValue - thatA) + toDraw.pixels[thatCurrentColor + GREEN_BIT] * thatA) / A; B = (this.pixels[thisCurrentColor + BLUE_BIT] * thisA * (byte.MaxValue - thatA) + toDraw.pixels[thatCurrentColor + BLUE_BIT] * thatA) / A; /* R = (this.pixels[thisCurrentColor + RED_BIT] * (byte.MaxValue - thatA) + * toDraw.pixels[thatCurrentColor + RED_BIT] * (thatA))/byte.MaxValue; * * G = (this.pixels[thisCurrentColor + GREEN_BIT] * (byte.MaxValue - thatA) + * toDraw.pixels[thatCurrentColor + GREEN_BIT] * (thatA)) / byte.MaxValue; * * B = (this.pixels[thisCurrentColor + BLUE_BIT] * (byte.MaxValue - thatA) + * toDraw.pixels[thatCurrentColor + BLUE_BIT] * (thatA)) / byte.MaxValue; * * R = (this.pixels[thisCurrentColor + RED_BIT] * thisA * (byte.MaxValue - thatA) + * toDraw.pixels[thatCurrentColor + RED_BIT] * thatA) / A; * * G = (this.pixels[thisCurrentColor + GREEN_BIT] * thisA * (byte.MaxValue - thatA) + * toDraw.pixels[thatCurrentColor + GREEN_BIT] * thatA)/A; * * B = (this.pixels[thisCurrentColor + BLUE_BIT] * thisA * (byte.MaxValue - thatA) + * toDraw.pixels[thatCurrentColor + BLUE_BIT] * thatA)/A; */ if (A > byte.MaxValue) { A = byte.MaxValue; } else if (A < byte.MinValue) { A = byte.MinValue; } this.pixels[thisCurrentColor + ALPHA_BIT] = (byte)(A); this.pixels[thisCurrentColor + BLUE_BIT] = (byte)B; this.pixels[thisCurrentColor + GREEN_BIT] = (byte)G; this.pixels[thisCurrentColor + RED_BIT] = (byte)R; } } } needsRefresh = true; }
/// <summary> /// Draws teh snowflake onto the InteractiveImage buffer for the screen. /// </summary> /// <param name="g">Graphics buffer for the screen.</param> public void Draw(Interactive8BitImage g) { Point drawPoint; // Point to draw on the buffer List <Point>[,] rotationLists = pointRotationHash[(int)rotationAngle]; List <Point> mappedPoints; // All the rotated & reflect points that are mapped to the point in the first quadrant Rectangle imageBounds; // Bounds for the image Rectangle flakeBounds; // Bounding box for all the pixels that could be in this flake imageBounds = new Rectangle(0, 0, g.Width, g.Height); flakeBounds = new Rectangle((int)position.x - MAX_FLAKE_PIXEL_DISTANCE, (int)position.y - MAX_FLAKE_PIXEL_DISTANCE, MAX_FLAKE_PIXEL_DISTANCE * 2, MAX_FLAKE_PIXEL_DISTANCE * 2); if (imageBounds.Contains(flakeBounds)) { // Draw each point in the pixel set that makes up the snowflake, offset by flakes position foreach (Point flakePixel in snowFlakePixels) { System.Diagnostics.Debug.Assert(flakePixel.Y + MAX_FLAKE_RADIUS < rotationLists.GetLength(0) && flakePixel.X + MAX_FLAKE_RADIUS < rotationLists.GetLength(1), "Pixel is outside of the rotaiton array"); mappedPoints = rotationLists[flakePixel.Y + MAX_FLAKE_RADIUS, flakePixel.X + MAX_FLAKE_RADIUS]; foreach (Point rotated in mappedPoints) { // Rotate the pixel drawPoint = rotated; // Make pixel position relative to the snowflakes position drawPoint.X = drawPoint.X + (int)position.x; drawPoint.Y = drawPoint.Y + (int)position.y; // No need to bounds check pixel, it's in the snowflake // Set pixel doesn't lock, but since we're only turning // the pixel on one way there shouldn't be any problems g.SetPixel8Bit(drawPoint.X, drawPoint.Y, byte.MaxValue); } } } else { // Draw each point in the pixel set that makes up the snowflake, offset by flakes position foreach (Point flakePixel in snowFlakePixels) { if (!(flakePixel.Y + MAX_FLAKE_RADIUS < rotationLists.GetLength(0) && flakePixel.X + MAX_FLAKE_RADIUS < rotationLists.GetLength(1))) { } System.Diagnostics.Debug.Assert(flakePixel.Y + MAX_FLAKE_RADIUS < rotationLists.GetLength(0) && flakePixel.X + MAX_FLAKE_RADIUS < rotationLists.GetLength(1), "Pixel is outside of the rotation array"); mappedPoints = rotationLists[flakePixel.Y + MAX_FLAKE_RADIUS, flakePixel.X + MAX_FLAKE_RADIUS]; foreach (Point rotated in mappedPoints) { // Rotate the pixel drawPoint = rotated; // Make pixel position relative to the snowflakes position drawPoint.X = drawPoint.X + (int)position.x; drawPoint.Y = drawPoint.Y + (int)position.y; // If pixel is in image bounds, draw it. if (drawPoint.X >= 0 && drawPoint.X < g.Width && drawPoint.Y >= 0 && drawPoint.Y < g.Height) { g.SetPixel8Bit(drawPoint.X, drawPoint.Y, byte.MaxValue); } } } } foreach (Point p in trail) { if (p.X >= 0 && p.X < g.Width && p.Y >= 0 && p.Y < g.Height) { g.SetPixel(p.X, p.Y, Color.White); } } }