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

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