fractal.cpp
上传用户:sunlush021
上传日期:2022-06-22
资源大小:90k
文件大小:7k
- /*
- Copyright (c) 2010 Marcus Geelnard
- This software is provided 'as-is', without any express or implied
- warranty. In no event will the authors be held liable for any damages
- arising from the use of this software.
- Permission is granted to anyone to use this software for any purpose,
- including commercial applications, and to alter it and redistribute it
- freely, subject to the following restrictions:
- 1. The origin of this software must not be misrepresented; you must not
- claim that you wrote the original software. If you use this software
- in a product, an acknowledgment in the product documentation would be
- appreciated but is not required.
- 2. Altered source versions must be plainly marked as such, and must not be
- misrepresented as being the original software.
- 3. This notice may not be removed or altered from any source
- distribution.
- */
- #include <stdexcept>
- #include <iostream>
- #include <fstream>
- #include <string>
- #include <list>
- #include <cmath>
- #include <tinythread.h>
- using namespace std;
- using namespace tthread;
-
// Mandelbrot fractal settings
#define MAND_MID_RE -0.69795
- #define MAND_MID_IM -0.34865
- #define MAND_SIZE 0.003
#define MAND_MAX_ITER 4000
#define MAND_RESOLUTION 1024
- /// BGR pixel class.
- class Pixel {
- public:
- Pixel() : r(0), g(0), b(0) {}
- Pixel(unsigned char red, unsigned char green, unsigned char blue)
- {
- r = red;
- g = green;
- b = blue;
- }
- unsigned char b, g, r;
- };
- /// Simple 2D RGB image class.
- class Image {
- public:
- /// Create a new image with the dimensions aWidth x aHeight.
- Image(int aWidth, int aHeight)
- {
- mData = new Pixel[aWidth * aHeight];
- mWidth = aWidth;
- mHeight = aHeight;
- }
- ~Image()
- {
- delete mData;
- }
- /// Write the image to a TGA file.
- void WriteToTGAFile(const char * aFileName)
- {
- // Prepare TGA file header
- unsigned char header[18] = {0,0,2,0,0,0,0,0,0,0,0,0,0,0,0,0,24,0};
- header[12] = mWidth & 255; // Image width (16 bits)
- header[13] = (mWidth >> 8) & 255; // -"-
- header[14] = mHeight & 255; // Image width (16 bits)
- header[15] = (mHeight >> 8) & 255; // -"-
- // Write output file
- ofstream f(aFileName, ios_base::out | ios_base::binary);
- f.write((const char *) header, 18);
- f.write((const char *) mData, (mWidth * mHeight) * 3);
- }
- Pixel& operator[](const int idx)
- {
- return mData[idx];
- }
- inline int Width() const
- {
- return mWidth;
- }
- inline int Height() const
- {
- return mHeight;
- }
- private:
- int mWidth; ///< Image width.
- int mHeight; ///< Image height.
- Pixel * mData; ///< Data pointer.
- };
-
/// 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
- Pixel Iterate(const double &cre, const double &cim, int aIterMax)
- {
- double zre = 0.0;
- double zim = 0.0;
- int n = 0;
- double absZSqr = 0.0;
- while((absZSqr < 4.0) && (n < aIterMax))
- {
- double tmp = zre * zre - zim * zim + cre;
- zim = 2.0 * zre * zim + cim;
- zre = tmp;
- absZSqr = zre * zre + zim * zim;
- ++ n;
- }
- if(n >= aIterMax)
- return Pixel(0,0,0);
- else
- {
- double nSmooth = n + 1 - log(log(sqrt(absZSqr))) / log(2.0);
- return Pixel(
- (unsigned char)(128.0 - 127.0 * cos(0.02 * nSmooth + 0.3)),
- (unsigned char)(128.0 - 127.0 * cos(0.016 * nSmooth + 1.2)),
- (unsigned char)(128.0 - 127.0 * cos(0.013 * nSmooth + 2.6))
- );
- }
- }
-
// Calculation thread
void CalcThread(void * arg)
{
RowDispatcher * dispatcher = (RowDispatcher *) arg;
Image * img = dispatcher->GetImage();
// Set min/max interval for the fractal set
- double xMin = MAND_MID_RE - MAND_SIZE * 0.5;
- double yMin = MAND_MID_IM - MAND_SIZE * 0.5;
- double xMax = MAND_MID_RE + MAND_SIZE * 0.5;
- double yMax = MAND_MID_IM + MAND_SIZE * 0.5;
- // Set step size (distance between two adjacent pixels)
- double xStep = (xMax - xMin) / img->Width();
- double yStep = (yMax - yMin) / img->Height();
- // 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()];
- double cim = y * yStep + yMin;
- double cre = xMin;
- for(int x = 0; x < img->Width(); ++ x)
- {
- *line ++ = Iterate(cre, cim, MAND_MAX_ITER);
- cre += xStep;
- }
- }
}
- int main(int argc, char **argv)
- {
// 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
- 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
- cout << "Writing final image..." << flush;
img.WriteToTGAFile("fractal.tga");
- cout << "done!" << endl;
}