Beispiel #1
0
 internal static Bitmap RenderFractal(Size imageSize, RectangleD complexArea, int maximumIterations, Func<int, double, Color> colorFunction)
 {
     var fractalBitmap = new Bitmap(imageSize.Width, imageSize.Height, PixelFormat.Format24bppRgb);
     // Use LockBits and pointers for faster image processing. GetPixel and SetPixel are slow.
     BitmapData fractalBitmapData = fractalBitmap.LockBits(new Rectangle(0, 0, imageSize.Width, imageSize.Height), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
     // Process each row of the image in parallel.
     Parallel.For(0, imageSize.Height, yPixelCoord =>
     {
         for (long xPixelCoord = 0; xPixelCoord < imageSize.Width; xPixelCoord++)
         {
             unsafe
             {
                 // 24bit bitmaps store color bytes in BGR order, not RGB.
                 byte* pointerBGR = (byte*)((long)fractalBitmapData.Scan0 + (yPixelCoord * fractalBitmapData.Stride) + (xPixelCoord * 3));
                 // Convert pixel coords to complex plane coords, using the center of the pixel, not the upper left corner.
                 double x = (complexArea.Width * ((xPixelCoord + 0.5D) / imageSize.Width)) + complexArea.Left;
                 double y = (complexArea.Height * ((yPixelCoord + 0.5D) / imageSize.Height)) + complexArea.Top;
                 // Color pixel based on number of iterations and escape magnitude
                 double finalMagnitude;
                 Color color = colorFunction(CountIterations(x, y, maximumIterations, out finalMagnitude), finalMagnitude);
                 *pointerBGR = color.B;
                 *++pointerBGR = color.G;
                 *++pointerBGR = color.R;
             }
         }
     });
     fractalBitmap.UnlockBits(fractalBitmapData);
     return fractalBitmap;
 }
Beispiel #2
0
 internal static RectangleD GetNextZoomArea(Size screenSize, Point zoomLocation, RectangleD currentArea)
 {
     // Convert pixel coords of next zoom area into complex coords.
     double newLeft = (((double)zoomLocation.X / screenSize.Width) * currentArea.Width) + currentArea.Left;
     double newTop = (((double)zoomLocation.Y / screenSize.Height) * currentArea.Height) + currentArea.Top;
     return new RectangleD(newLeft, newTop, currentArea.Width / 10D, currentArea.Height / 10D);
 }
Beispiel #3
0
 internal static RectangleD GetInitialArea(Size screenSize)
 {
     // Adjust viewing area to contain the whole Mandelbrot set while matching the screen's aspect ratio.
     var rectangle = new RectangleD(-2, -1, 3, 2);
     double scalar = (screenSize.Width / 3D) / (screenSize.Height / 2D);
     if (scalar > 1)
     {
         rectangle.Width *= scalar;
         rectangle.Left = -0.5 - (rectangle.Width / 2D);
     }
     else
     {
         rectangle.Height /= scalar;
         rectangle.Top = 0 - (rectangle.Height / 2D);
     }
     return rectangle;
 }
Beispiel #4
0
        private void ScreenSaverForm_Shown(object sender, EventArgs e)
        {
            Graphics formGraphics = this.CreateGraphics();

            formGraphics.DrawImageUnscaled(this.initialFractalBitmap, 0, 0);
            this.stopwatch.Restart();
            Task.Run(() =>
            {
                while (true)
                {
                    RectangleD fractalArea = this.initialFractalArea;
                    var currentBitmap      = this.initialFractalBitmap.Clone() as Bitmap;
                    for (int zoom = 1; zoom < 10; zoom++)
                    {
                        Rectangle zoomRectangle = Mandelbrot.GetNextZoomRectangle(currentBitmap);
                        // If couldn't find suitable area to zoom in, zoom out to starting fractal and start over.
                        if (zoomRectangle == Rectangle.Empty)
                        {
                            break;
                        }
                        fractalArea       = Mandelbrot.GetNextZoomArea(this.Size, zoomRectangle.Location, fractalArea);
                        Bitmap nextBitmap = Mandelbrot.RenderFractal(this.Size, fractalArea, BaseMaximumIterations * (zoom + 1), this.colorFunction);
                        IntPtr[] nativeZoomInBitmapHandles = CreateNativeZoomInBitmaps(currentBitmap, nextBitmap, zoomRectangle.Location);
                        // Wait a bit between zooms, even if all computations are complete.
                        this.stopwatch.Stop();
                        if (this.stopwatch.ElapsedMilliseconds < WaitMilliseconds)
                        {
                            Thread.Sleep(WaitMilliseconds - (int)this.stopwatch.ElapsedMilliseconds);
                        }
                        AnimateBlink(formGraphics, currentBitmap, zoomRectangle);
                        AnimateZoomIn(formGraphics, nativeZoomInBitmapHandles, this.Size);
                        this.stopwatch.Restart();
                        // Clean up animation bitmaps after use.
                        foreach (IntPtr nativeZoomInBitmapHandle in nativeZoomInBitmapHandles)
                        {
                            NativeMethods.GDI32.DeleteObject(nativeZoomInBitmapHandle);
                        }
                        currentBitmap.Dispose();
                        currentBitmap = nextBitmap;
                    }
                    // After 10 zoom-ins, zoom out to starting fractal and start over.
                    double percentX = ((fractalArea.Left + (fractalArea.Width / 2D)) - this.initialFractalArea.Left) / this.initialFractalArea.Width;
                    double percentY = ((fractalArea.Top + (fractalArea.Height / 2D)) - this.initialFractalArea.Top) / this.initialFractalArea.Height;
                    var zoomPoint   = new Point((int)(this.Width * percentX), (int)(this.Height * percentY));
                    IntPtr[] nativeZoomOutBitmapHandles = CreateNativeZoomOutBitmaps(currentBitmap, this.initialFractalBitmap, zoomPoint);
                    currentBitmap.Dispose();
                    // Wait a bit between zooms, even if all computations are complete.
                    this.stopwatch.Stop();
                    if (this.stopwatch.ElapsedMilliseconds < WaitMilliseconds)
                    {
                        Thread.Sleep(WaitMilliseconds - (int)this.stopwatch.ElapsedMilliseconds);
                    }
                    AnimateZoomOut(formGraphics, nativeZoomOutBitmapHandles, this.Size);
                    this.stopwatch.Restart();
                    // Clean up animation bitmaps after use.
                    foreach (IntPtr nativeZoomOutBitmapHandle in nativeZoomOutBitmapHandles)
                    {
                        NativeMethods.GDI32.DeleteObject(nativeZoomOutBitmapHandle);
                    }
                }
            });
        }
Beispiel #5
0
 private void ScreenSaverForm_Load(object sender, EventArgs e)
 {
     this.AssignColorScheme();
     this.initialFractalArea   = Mandelbrot.GetInitialArea(this.Size);
     this.initialFractalBitmap = Mandelbrot.RenderInitialFractal(this.Size, this.initialFractalArea, BaseMaximumIterations, this.colorFunction);
 }
Beispiel #6
0
 internal static Bitmap RenderInitialFractal(Size imageSize, RectangleD complexArea, int maximumIterations, Func<int, double, Color> colorFunction)
 {
     var fractalBitmap = new Bitmap(imageSize.Width, imageSize.Height, PixelFormat.Format24bppRgb);
     // Use LockBits and pointers for faster image processing. GetPixel and SetPixel are slow.
     BitmapData fractalBitmapData = fractalBitmap.LockBits(new Rectangle(Point.Empty, imageSize), ImageLockMode.ReadWrite, PixelFormat.Format24bppRgb);
     // Process each row of the image in parallel, using multiple CPU cores for speed.
     Parallel.For(0, imageSize.Height / 2, yPixelCoord =>
     {
         for (long xPixelCoord = 0; xPixelCoord < imageSize.Width; xPixelCoord++)
         {
             unsafe
             {
                 // 24bit bitmaps store color bytes in BGR order, not RGB.
                 byte* pointerBGR = (byte*)((long)fractalBitmapData.Scan0 + (yPixelCoord * fractalBitmapData.Stride) + (xPixelCoord * 3));
                 // For initial fractal image, the bottom half is a mirror of top half.
                 byte* mirrorBGR = (byte*)((long)fractalBitmapData.Scan0 + (((imageSize.Height - 1) - yPixelCoord) * fractalBitmapData.Stride) + (xPixelCoord * 3));
                 // Convert pixel coords to complex plane coords, using the center of the pixel, not the upper left corner.
                 double x = (complexArea.Width * ((xPixelCoord + 0.5D) / imageSize.Width)) + complexArea.Left;
                 double y = (complexArea.Height * ((yPixelCoord + 0.5D) / imageSize.Height)) + complexArea.Top;
                 // Color pixel based on number of iterations and escape magnitude
                 // Save time by only calculating iterations for points not in one of the large bulbs, as many pixels in the initial fractal are.
                 double finalMagnitude;
                 var color = (IsInCardioid(x, y) || IsInPeriod2Bulb(x, y)) ? Color.Black : colorFunction(CountIterations(x, y, maximumIterations, out finalMagnitude), finalMagnitude);
                 *mirrorBGR = *pointerBGR = color.B;
                 *++mirrorBGR = *++pointerBGR = color.G;
                 *++mirrorBGR = *++pointerBGR = color.R;
             }
         }
     });
     fractalBitmap.UnlockBits(fractalBitmapData);
     return fractalBitmap;
 }
Beispiel #7
0
        internal static RectangleD GetNextZoomArea(Size screenSize, Point zoomLocation, RectangleD currentArea)
        {
            // Convert pixel coords of next zoom area into complex coords.
            double newLeft = (((double)zoomLocation.X / screenSize.Width) * currentArea.Width) + currentArea.Left;
            double newTop  = (((double)zoomLocation.Y / screenSize.Height) * currentArea.Height) + currentArea.Top;

            return(new RectangleD(newLeft, newTop, currentArea.Width / 10D, currentArea.Height / 10D));
        }
 private void ScreenSaverForm_Load(object sender, EventArgs e)
 {
     this.AssignColorScheme();
     this.initialFractalArea = Mandelbrot.GetInitialArea(this.Size);
     this.initialFractalBitmap = Mandelbrot.RenderInitialFractal(this.Size, this.initialFractalArea, BaseMaximumIterations, this.colorFunction);
 }