sources:
Fraktal.cpp (8.0k)


binaries:
Release/Fraktal.exe (4.0k)


website:
more info here


screenshot:
studies/betriebssysteme/Betriebssysteme-Code4/Fraktal.cpp
download file

  1 ///////////////////////////////////////////////////////////
  2 // Betriebssysteme I - Windows 2000
  3 // Assignment 4.2: A multi-threaded fractal generator
  4 //
  5 // author: Stephan Brumme
  6 // last changes: December 31, 2001
  7
  8
  9 // include Win32-API
 10 #include <windows.h>
 11 // C library
 12 #include <stdio.h>
 13
 14
 15 // let's cut down the exe's size !!!
 16 // no 4k alignment
 17 #pragma comment(linker, "/OPT:NOWIN98")
 18 // use system's dll instead of statically linking da code
 19 #pragma comment(linker, "/NODEFAULTLIB:libc.lib")
 20 #pragma comment(linker, "/NODEFAULTLIB:libcd.lib")
 21 #pragma comment(lib, "msvcrt.lib")
 22 #pragma comment(lib, "gdi32.lib")
 23 // watermark
 24 #pragma comment(exestr, "(C)2001-2002 by Stephan Brumme")
 25
 26
 27 // parameter that are passed to each thread
 28 struct TFractalParameters
 29 {
 30     COLORREF* arImage;
 31     unsigned int nWidth;
 32     unsigned int nHeight;
 33     double dLeft;
 34     double dRight;
 35     double dTop;
 36     double dBottom;
 37     unsigned int nMaxDepth;
 38 };
 39
 40
 41
 42 // save image as 24-bit-BMP
 43 bool WriteBMP(const char* strFilename, unsigned int nWidth, unsigned int nHeight, const COLORREF arImage[])
 44 {
 45     // in the beginning there was nothing - except a bitmap info header !
 46
 47     // code taken from MSDN (see GDI: "Storing an Image"), simplified
 48     BITMAPINFO bmpInfo;
 49     bmpInfo.bmiHeader.biSize          = sizeof(BITMAPINFOHEADER);
 50     bmpInfo.bmiHeader.biWidth         = nWidth;
 51     bmpInfo.bmiHeader.biHeight        = nHeight; // bottom-up DIB !
 52     bmpInfo.bmiHeader.biPlanes        = 1;
 53     bmpInfo.bmiHeader.biBitCount      = 32; // bit depth: RGB+reserved
 54     bmpInfo.bmiHeader.biClrUsed       = 0; // true color !
 55     bmpInfo.bmiHeader.biClrImportant  = 0;
 56     bmpInfo.bmiHeader.biCompression   = BI_RGB;
 57     bmpInfo.bmiHeader.biSizeImage     = ((nWidth*32+31) & ~31) / 8 * nHeight;
 58     bmpInfo.bmiHeader.biXPelsPerMeter =
 59     bmpInfo.bmiHeader.biYPelsPerMeter = 3780; // 96 dpi
 60
 61     // create header out of the info structure
 62     BITMAPFILEHEADER bmpHeader;
 63     // magic bytes "BM"
 64     bmpHeader.bfType = 0x4d42;
 65     // offset to the raw image data
 66     bmpHeader.bfOffBits   = sizeof(BITMAPFILEHEADER) + bmpInfo.bmiHeader.biSize; +
 67     // size of the entire file
 68     bmpHeader.bfSize = bmpHeader.bfOffBits + bmpInfo.bmiHeader.biSizeImage;
 69     // reserved fields
 70     bmpHeader.bfReserved1 = 0;
 71     bmpHeader.bfReserved2 = 0;
 72
 73
 74     // create new file, overwrite if neccessary
 75     HANDLE hFile;
 76     if (strFilename != NULL)
 77         hFile = CreateFile(strFilename, GENERIC_WRITE, 0, NULL,
 78                                         CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL)
;
 79     else
 80         hFile = GetStdHandle(STD_OUTPUT_HANDLE);
 81    
 82     // failed to create file ?
 83     if (hFile == INVALID_HANDLE_VALUE)
 84         return false;
 85
 86
 87     DWORD dwBytesWritten;
 88     // write file header
 89     if (!WriteFile(hFile, &bmpHeader, sizeof(bmpHeader), &dwBytesWritten, NULL))
 90         return false;
 91     // write info header
 92     if (!WriteFile(hFile, &bmpInfo,   sizeof(bmpInfo),   &dwBytesWritten, NULL))
 93         return false;
 94
 95     // write image
 96     if (!WriteFile(hFile, arImage, bmpInfo.bmiHeader.biSizeImage, &dwBytesWritten, NULL))
 97         return false;
 98
 99     // close file and: DONE !
100     CloseHandle(hFile);
101     return true;
102 }
103
104
105 // generate mandelbrot image
106 DWORD WINAPI Calculate(void *pParameter)
107 {
108     // cast
109     TFractalParameters *param = (TFractalParameters*) pParameter;
110
111     // walk through the image
112     COLORREF* pImageCursor = param->arImage;
113
114     // process all points
115     // remind that BMPs are built bottom-up !
116     for (unsigned int nRow = 0; nRow < param->nHeight; nRow++)
117     {
118         for (unsigned int nColumn = 0; nColumn < param->nWidth; nColumn++)
119         {
120             // get current coordinates
121             const double dX = nColumn/(param->nWidth -1.0) * (param->dRight - param->dLeft  ) + param->dLeft;
122             const double dY = nRow   /(param->nHeight-1.0) * (param->dTop   - param->dBottom) + param->dBottom;
123
124             // initialize
125             unsigned int nDepth = 0;
126             double wx = dX;
127             double wy = dY;
128
129             // calculate point's color
130             do
131             {
132                 const double old_wx = wx;
133                 nDepth++;
134
135                 wx = wx*wx - wy*wy + dX;
136                 wy = 2*old_wx * wy + dY;
137             } while (wx*wx + wy*wy <= 4 && nDepth <= param->nMaxDepth);
138
139             // we counted once too much
140             nDepth--;
141
142             // convert iteration depth to grey and save it
143             nDepth = int((param->nMaxDepth-nDepth) * 255.0 / param->nMaxDepth);
144             *pImageCursor = RGB(nDepth, nDepth, nDepth);
145             pImageCursor++;
146         }
147     }
148
149     return 0;
150 }
151
152
153
154 // here we go !
155 int main(int argc, char* argv[])
156 {
157     // default fractal parameters
158     unsigned int nWidth  = 512;
159     unsigned int nHeight = 512;
160     double dLeft   =  -2.0;
161     double dRight  =   0.5;
162     double dTop    =   1.25;
163     double dBottom =  -1.25;
164     unsigned int nMaxDepth = 25;
165     const char* strFilename = NULL;
166     unsigned int nThreads = 1;
167
168     // no command line parameters or help requested ?
169     if (argc == 1)
170     {
171         printf("options:\n"
172                " /f:image.bmp output file (default: standard output)\n"
173                " /m:1 no. of threads (default: 1 thread)\n"
174                " /x:512 set width (default: 512 pixel)\n"
175                " /y:512 set height (default: 512 pixel)\n"
176                " /l:-2.0 left border (default: -2.0)\n"
177                " /r:0.5 right border (default: 0.5)\n"
178                " /t:1.25 top border (default: 1.25)\n"
179                " /b:-1.25 bottom border (default: -1.25)\n"
180                " /d:25 iteration depth (default: 25, must be 0..255)\n"
181                )
;
182
183         return 1;
184     }
185
186     // parse command line
187     int nParameter = 1;
188     while (nParameter < argc)
189     {
190         // parse one parameter
191         const char* strOption = argv[nParameter];
192
193         // simple verification
194         if (strOption == NULL      ||
195             strlen(strOption) < 4  ||
196             strOption[0] != '/'    ||
197             strOption[2] != ':')

198         {
199             printf("unknown option '%s'\n", strOption);
200             return 1;
201         }
202
203         // value the parameter should contain
204         const char* strValue = &(strOption[3]);
205
206         // set parameters
207         switch(strOption[1])
208         {
209         // filename
210         case 'f':
211         case 'F': strFilename = strValue; break;
212
213         // image size
214         case 'x':
215         case 'X': nWidth  = atoi(strValue); break;
216         case 'y':
217         case 'Y': nHeight = atoi(strValue); break;
218
219         // borders
220         case 'l':
221         case 'L': dLeft   = atof(strValue); break;
222         case 'r':
223         case 'R': dRight  = atof(strValue); break;
224         case 't':
225         case 'T': dTop    = atof(strValue); break;
226         case 'b':
227         case 'B': dBottom = atof(strValue); break;
228
229         // iteration depth
230         case 'd':
231         case 'D': nMaxDepth = atoi(strValue); break;
232
233         // threads
234         case 'm':
235         case 'M': nThreads = atoi(strValue); break;
236
237         // error
238         default:  printf("unknown option '%s'\n", strOption);
239                   return 1;
240         }
241
242         // next one
243         nParameter++;
244     }
245
246    
247     // allocate memory
248     COLORREF* arImage = new COLORREF[nWidth*nHeight];
249
250     // store thread handles
251     HANDLE* arhThread = new HANDLE[nThreads];
252     DWORD   dwThreadID;
253
254     // thread parameters
255     TFractalParameters* param = new TFractalParameters[nThreads];
256     const double dHeightDelta = (dTop - dBottom)/nThreads;
257
258     // launch threads
259     for (unsigned int i=0; i<nThreads; i++)
260     {
261         // pixel area
262         param[i].nWidth    = nWidth;
263         param[i].nHeight   = nHeight*(i+1)/nThreads - nHeight*i/nThreads;
264         // image storage, take offset into account
265         param[i].arImage   = arImage;
266         param[i].arImage  += (nHeight-nHeight*i/nThreads-param[i].nHeight)*nWidth;
267         // mandelbrot area
268         param[i].dLeft     = dLeft;
269         param[i].dRight    = dRight;
270         param[i].dTop      = dTop-i*dHeightDelta;
271         param[i].dBottom   = param[i].dTop-dHeightDelta*param[i].nHeight/(nHeight/(double)nThreads);
272         // iteration depth
273         param[i].nMaxDepth = nMaxDepth;
274
275         // start thread
276         arhThread[i] = CreateThread(NULL, 0, Calculate, &(param[i]), 0, &dwThreadID);
277         if (strFilename != NULL)
278             printf("starting thread %d (ID: %d)\n", i+1, dwThreadID);
279     }
280
281     // wait for threads to finish
282     WaitForMultipleObjects(nThreads, arhThread, true, INFINITE);
283
284     // write to file
285     if (strFilename != NULL)
286         printf("writing to %s ... ", strFilename);
287     if (!WriteBMP(strFilename, nWidth, nHeight, arImage))
288         printf("FAILURE !!!\n");
289
290     // free memory
291     delete arImage;
292     for (i=0; i<nThreads; i++)
293         CloseHandle(arhThread[i]);
294     delete arhThread;
295
296     // done
297     return 0;
298 }
299