mirror of
https://github.com/etlegacy/Update-Installer.git
synced 2024-12-11 04:40:53 +00:00
5360d05867
This saves the need to install Boost::Thread on each of the build systems.
261 lines
6.7 KiB
C++
261 lines
6.7 KiB
C++
/*
|
|
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 BGR 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 = thread::hardware_concurrency();
|
|
if(numThreads < 1)
|
|
numThreads = 1;
|
|
}
|
|
else
|
|
numThreads = 1;
|
|
|
|
// 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;
|
|
}
|