fractal.cpp
上传用户:sunlush021
上传日期:2022-06-22
资源大小:90k
文件大小:7k
源码类别:

操作系统开发

开发平台:

C/C++

  1. /*
  2. Copyright (c) 2010 Marcus Geelnard
  3. This software is provided 'as-is', without any express or implied
  4. warranty. In no event will the authors be held liable for any damages
  5. arising from the use of this software.
  6. Permission is granted to anyone to use this software for any purpose,
  7. including commercial applications, and to alter it and redistribute it
  8. freely, subject to the following restrictions:
  9.     1. The origin of this software must not be misrepresented; you must not
  10.     claim that you wrote the original software. If you use this software
  11.     in a product, an acknowledgment in the product documentation would be
  12.     appreciated but is not required.
  13.     2. Altered source versions must be plainly marked as such, and must not be
  14.     misrepresented as being the original software.
  15.     3. This notice may not be removed or altered from any source
  16.     distribution.
  17. */
  18. #include <stdexcept>
  19. #include <iostream>
  20. #include <fstream>
  21. #include <string>
  22. #include <list>
  23. #include <cmath>
  24. #include <tinythread.h>
  25. using namespace std;
  26. using namespace tthread;
  27. // Mandelbrot fractal settings #define MAND_MID_RE -0.69795
  28. #define MAND_MID_IM -0.34865
  29. #define MAND_SIZE 0.003 #define MAND_MAX_ITER 4000 #define MAND_RESOLUTION 1024
  30. /// BGR pixel class.
  31. class Pixel {
  32.   public:
  33.     Pixel() : r(0), g(0), b(0) {}
  34.     Pixel(unsigned char red, unsigned char green, unsigned char blue)
  35.     {
  36.       r = red;
  37.       g = green;
  38.       b = blue;
  39.     }
  40.     unsigned char b, g, r;
  41. };
  42. /// Simple 2D RGB image class.
  43. class Image {
  44.   public:
  45.     /// Create a new image with the dimensions aWidth x aHeight.
  46.     Image(int aWidth, int aHeight)
  47.     {
  48.       mData = new Pixel[aWidth * aHeight];
  49.       mWidth = aWidth;
  50.       mHeight = aHeight;
  51.     }
  52.     ~Image()
  53.     {
  54.       delete mData;
  55.     }
  56.     /// Write the image to a TGA file.
  57.     void WriteToTGAFile(const char * aFileName)
  58.     {
  59.       // Prepare TGA file header
  60.       unsigned char header[18] = {0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,24,0};
  61.       header[12] = mWidth & 255;         // Image width (16 bits)
  62.       header[13] = (mWidth >> 8) & 255;  // -"-
  63.       header[14] = mHeight & 255;        // Image width (16 bits)
  64.       header[15] = (mHeight >> 8) & 255; // -"-
  65.       // Write output file
  66.       ofstream f(aFileName, ios_base::out | ios_base::binary);
  67.       f.write((const char *) header, 18);
  68.       f.write((const char *) mData, (mWidth * mHeight) * 3);
  69.     }
  70.     Pixel& operator[](const int idx)
  71.     {
  72.       return mData[idx];
  73.     }
  74.     inline int Width() const
  75.     {
  76.       return mWidth;
  77.     }
  78.     inline int Height() const
  79.     {
  80.       return mHeight;
  81.     }
  82.   private:
  83.     int mWidth;    ///< Image width.
  84.     int mHeight;   ///< Image height.
  85.     Pixel * mData; ///< Data pointer.
  86. };
  87. /// The RowDispatcher class manages the "job pool" for the fractal /// calculation threads. class RowDispatcher {   public:     RowDispatcher(Image * aImage) : mNextRow(0)     {       mImage = aImage;     }     Image * GetImage()     {       return mImage;     }     int NextRow()     {       lock_guard<mutex> guard(mMutex);       if(mNextRow >= mImage->Height())         return -1;       int result = mNextRow;       ++ mNextRow;       return result;     }   private:     mutex mMutex;     int mNextRow;     Image * mImage; }; // Core iteration function
  88. Pixel Iterate(const double &cre, const double &cim, int aIterMax)
  89. {
  90.   double zre = 0.0;
  91.   double zim = 0.0;
  92.   int n = 0;
  93.   double absZSqr = 0.0;
  94.   while((absZSqr < 4.0) && (n < aIterMax))
  95.   {
  96.     double tmp = zre * zre - zim * zim + cre;
  97.     zim = 2.0 * zre * zim + cim;
  98.     zre = tmp;
  99.     absZSqr = zre * zre + zim * zim;
  100.     ++ n;
  101.   }
  102.   if(n >= aIterMax)
  103.     return Pixel(0,0,0);
  104.   else
  105.   {
  106.     double nSmooth = n + 1 - log(log(sqrt(absZSqr))) / log(2.0);
  107.     return Pixel(
  108.              (unsigned char)(128.0 - 127.0 * cos(0.02 * nSmooth + 0.3)),
  109.              (unsigned char)(128.0 - 127.0 * cos(0.016 * nSmooth + 1.2)),
  110.              (unsigned char)(128.0 - 127.0 * cos(0.013 * nSmooth + 2.6))
  111.            );
  112.   }
  113. }
  114. // Calculation thread void CalcThread(void * arg) {   RowDispatcher * dispatcher = (RowDispatcher *) arg;   Image * img = dispatcher->GetImage();   // Set min/max interval for the fractal set
  115.   double xMin = MAND_MID_RE - MAND_SIZE * 0.5;
  116.   double yMin = MAND_MID_IM - MAND_SIZE * 0.5;
  117.   double xMax = MAND_MID_RE + MAND_SIZE * 0.5;
  118.   double yMax = MAND_MID_IM + MAND_SIZE * 0.5;
  119.   // Set step size (distance between two adjacent pixels)
  120.   double xStep = (xMax - xMin) / img->Width();
  121.   double yStep = (yMax - yMin) / img->Height();
  122.   // Until no more rows to process...   while(true)   {     // Get the next row to calculate     int y = dispatcher->NextRow();     // Done?     if(y < 0)       break;     // Generate one row of the image     Pixel * line = &(*img)[y * img->Width()];
  123.     double cim = y * yStep + yMin;
  124.     double cre = xMin;
  125.     for(int x = 0; x < img->Width(); ++ x)
  126.     {
  127.       *line ++ = Iterate(cre, cim, MAND_MAX_ITER);
  128.       cre += xStep;
  129.     }
  130.   } }
  131. int main(int argc, char **argv)
  132. {   // Show some information about this program...   cout << "This is a small multi threaded Mandelbrot fractal generator." << endl;   cout << endl;   cout << "The program will generate a " << MAND_RESOLUTION << "x" << MAND_RESOLUTION << " image, using one calculation thread per" << endl;   cout << "processor core. The result is written to a TGA format image, "fractal.tga"." << endl;   cout << endl;   cout << "Type "" << argv[0] << " -st" to force single threaded operation." << endl;   cout << endl;   // Check arguments   bool singleThreaded = false;   if((argc >= 2) && (string(argv[1]) == string("-st")))     singleThreaded = true;   // Init image and row dispatcher
  133.   Image img(MAND_RESOLUTION, MAND_RESOLUTION);   RowDispatcher dispatcher(&img);   // Determine the number of calculation threads to use   int numThreads;   if(singleThreaded)     numThreads = 1;   else     numThreads = number_of_processors();   // Start calculation threads (we run one thread on each processor core)   cout << "Running " << numThreads << " calculation thread(s)..." << flush;   list<thread *> threadList;   for(int i = 0; i < numThreads; ++ i)   {     thread * t = new thread(CalcThread, (void *) &dispatcher);     threadList.push_back(t);   }   // Wait for the threads to complete...   for(list<thread *>::iterator i = threadList.begin(); i != threadList.end(); ++ i)   {     thread * t = *i;     t->join();     delete t;   }   cout << "done!" << endl;   // Write the final image to a file
  134.   cout << "Writing final image..." << flush;   img.WriteToTGAFile("fractal.tga");
  135.   cout << "done!" << endl; }