示例#1
0
        //Thread to generate a number of lines of a mandelbrot figure
        //Which lines is specified by the context that is passed through the arg parameter
        private unsafe void MandelbrotThread(object arg)
        {
            Thread.CurrentThread.Priority = ThreadPriority.Lowest;
            MandelbrotContext c = (MandelbrotContext)arg;
            //Make copies of a couple of settings to prevent problems
            //when they are changed during the generating
            int maxmandel = MandelbrotStyle == MandelbrotColorStyle.Paletted ? MandlebrotMaxCount : 512;

            Color[] paletteCopy = new Color[MandelbrotPalette.Count];
            MandelbrotPalette.CopyTo(paletteCopy, 0);
            uint * pBitmap = c.bitmapPtr;
            double xStep   = MandelbrotWidth / c.width;
            double yStep   = MandelbrotHeight / c.height;
            double yreal   = c.startLine * yStep + MandelbrotY;

            for (int y = c.startLine; y < c.startLine + c.nrLines; y++)
            {
                //make it possible to cancel generating
                if (mCancelMandelbrot)
                {
                    return;
                }
                uint * curLine = pBitmap;
                double xreal   = MandelbrotX;
                for (int x = 0; x < c.width; x++)
                {
                    //calculate the mandelbrot number (count)
                    double a     = 0;
                    double b     = 0;
                    int    count = 0;
                    do
                    {
                        double a_old = a;
                        a = a * a - b * b + xreal;
                        b = 2 * a_old * b + yreal;
                        count++;
                    }
                    //instead of using sqrt (which is slow), simply square the other side of the equation
                    while (a * a + b * b <= 2 * 2 && count < (maxmandel - 1));
                    if (MandelbrotStyle == MandelbrotColorStyle.Paletted)
                    {
                        int   idx = count * (paletteCopy.Length - 1) / maxmandel;
                        int   rem = (count * (paletteCopy.Length - 1) % maxmandel) / (paletteCopy.Length - 1);
                        Color col = paletteCopy[idx];
                        if (rem != 0)
                        {
                            //Interpolate between two palette colors
                            Color col2 = paletteCopy[idx + 1];
                            col = Color.FromArgb(
                                col.R + (col2.R - col.R) * rem / (maxmandel / (paletteCopy.Length - 1)),
                                col.G + (col2.G - col.G) * rem / (maxmandel / (paletteCopy.Length - 1)),
                                col.B + (col2.B - col.B) * rem / (maxmandel / (paletteCopy.Length - 1)));
                        }
                        *curLine++ = (uint)col.ToArgb();
                    }
                    else
                    {
                        //Make the maximum value (which depicts infinity to some extend) black,
                        //because it looks better
                        if (count == 511)
                        {
                            count = 0;
                        }
                        //Extract some bits and use them as r, g and b values (after scaling)
                        uint r  = (uint)(count & 7) * 32;
                        uint g  = (uint)((count >> 3) & 7) * 32;
                        uint b_ = (uint)((count >> 6) & 7) * 32;
                        //Set the current pixel in ARGB format
                        *curLine++ = 0xFF000000u | (r << 16) | (g << 8) | b_;
                    }
                    //next mandelbrot coordinate
                    xreal += xStep;
                }
                //next line (sometimes there is padding at the end, so use the stride and divide by 4, because it's a uint pointer)
                pBitmap += c.stride / 4;
                yreal   += yStep;
            }
        }
示例#2
0
        public unsafe void StartGenerateMandelbrot(bool generate2Times = false)
        {
            //When another mandelbrot is already being generated,
            //cancel it when a new mandelbrot is requested.
            //This is useful when a 2x version is generated in the bg,
            //while the use wants to zoom in already
            if (mIsGeneratingMandlebrot)
            {
                mCancelMandelbrot = true;
                //Wait till the currently being generated mandelbrot is canceled
                while (mIsGeneratingMandlebrot)
                {
                    Thread.Sleep(1); //And sleep this thread for a little while, to give the mandelbrot threads a chance to cancel themselves
                }
            }
            mCancelMandelbrot       = false;
            mIsGeneratingMandlebrot = true;
            //make sure the palette contains at least 2 entries when using the paletted mandelbrot style
            if (MandelbrotStyle == MandelbrotColorStyle.Paletted && MandelbrotPalette.Count < 2)
            {
                BeginUpdatePalette();
                MandelbrotPalette.Clear();
                MandelbrotPalette.Add(Color.DarkBlue);
                MandelbrotPalette.Add(Color.White);
                MandelbrotPalette.Add(Color.Orange);
                MandelbrotPalette.Add(Color.White);
                MandelbrotPalette.Add(Color.Black);
                EndUpdatePalette();
            }
            //use a bitmap and pointers to it's data for much faster drawing
            int    multiplier = generate2Times ? 2 : 1;
            Bitmap bitmap     = new Bitmap(Width * multiplier, Height * multiplier);
            //Lock the bits of the bitmap to access the pixels using a pointer directly
            BitmapData bitmapData = bitmap.LockBits(new Rectangle(0, 0, bitmap.Width, bitmap.Height), ImageLockMode.WriteOnly, PixelFormat.Format32bppPArgb);
            uint *     pBitmap    = (uint *)bitmapData.Scan0;
            //start multiple threads for much faster generating
            int nrthreads = 64;

            Task[] tasks = new Task[nrthreads];
            //calculate the number of lines that are calculated by each thread
            int nrlinesperthread = bitmap.Height / nrthreads;
            int y = 0;

            for (int i = 0; i < nrthreads; i++)
            {
                //Setup the params for the mandelbrot thread
                MandelbrotContext c = new MandelbrotContext();
                c.width     = bitmap.Width;
                c.height    = bitmap.Height;
                c.bitmapPtr = pBitmap;
                c.startLine = y;
                //In case of the last thread, make sure all lines left are being calculated,
                //because nrlinesperthread is always a whole number of lines. When the image
                //isn't a multiple of nrthreads, a couple of lines wouldn't be calculated otherwise
                if (i == nrthreads - 1)
                {
                    c.nrLines = bitmap.Height - y;
                }
                else
                {
                    c.nrLines = nrlinesperthread;
                }
                c.stride     = bitmapData.Stride;
                c.multiplier = multiplier;
                y           += nrlinesperthread;
                //Skip the number of lines that are calculated by this thread
                pBitmap += bitmapData.Stride / 4 * nrlinesperthread;
                //Start the thread (task)
                tasks[i] = Task.Factory.StartNew(MandelbrotThread, c);
            }
            //Wait for all tasks to be completed in a new thread,
            //to return from this method immediately
            new Thread((ThreadStart) delegate
            {
                Task.WaitAll(tasks);
                //Unlock the bitmap again (would cause a memory leak otherwise)
                bitmap.UnlockBits(bitmapData);
                if (!mCancelMandelbrot)
                {
                    mIsGeneratingMandlebrot = false;
                    //Invoke the ready event
                    if (MandlebrotReady != null)
                    {
                        MandlebrotReady.Invoke(bitmap, generate2Times);
                    }
                }
                else
                {
                    mIsGeneratingMandlebrot = false;
                }
            }).Start();
        }