/////////////////////////////////////////////////////////// // Betriebssysteme I - Windows 2000 // Assignment 4.2: A multi-threaded fractal generator // // author: Stephan Brumme // last changes: December 31, 2001 // include Win32-API #include // C library #include // let's cut down the exe's size !!! // no 4k alignment #pragma comment(linker, "/OPT:NOWIN98") // use system's dll instead of statically linking da code #pragma comment(linker, "/NODEFAULTLIB:libc.lib") #pragma comment(linker, "/NODEFAULTLIB:libcd.lib") #pragma comment(lib, "msvcrt.lib") #pragma comment(lib, "gdi32.lib") // watermark #pragma comment(exestr, "(C)2001-2002 by Stephan Brumme") // parameter that are passed to each thread struct TFractalParameters { COLORREF* arImage; unsigned int nWidth; unsigned int nHeight; double dLeft; double dRight; double dTop; double dBottom; unsigned int nMaxDepth; }; // save image as 24-bit-BMP bool WriteBMP(const char* strFilename, unsigned int nWidth, unsigned int nHeight, const COLORREF arImage[]) { // in the beginning there was nothing - except a bitmap info header ! // code taken from MSDN (see GDI: "Storing an Image"), simplified BITMAPINFO bmpInfo; bmpInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER); bmpInfo.bmiHeader.biWidth = nWidth; bmpInfo.bmiHeader.biHeight = nHeight; // bottom-up DIB ! bmpInfo.bmiHeader.biPlanes = 1; bmpInfo.bmiHeader.biBitCount = 32; // bit depth: RGB+reserved bmpInfo.bmiHeader.biClrUsed = 0; // true color ! bmpInfo.bmiHeader.biClrImportant = 0; bmpInfo.bmiHeader.biCompression = BI_RGB; bmpInfo.bmiHeader.biSizeImage = ((nWidth*32+31) & ~31) / 8 * nHeight; bmpInfo.bmiHeader.biXPelsPerMeter = bmpInfo.bmiHeader.biYPelsPerMeter = 3780; // 96 dpi // create header out of the info structure BITMAPFILEHEADER bmpHeader; // magic bytes "BM" bmpHeader.bfType = 0x4d42; // offset to the raw image data bmpHeader.bfOffBits = sizeof(BITMAPFILEHEADER) + bmpInfo.bmiHeader.biSize; + // size of the entire file bmpHeader.bfSize = bmpHeader.bfOffBits + bmpInfo.bmiHeader.biSizeImage; // reserved fields bmpHeader.bfReserved1 = 0; bmpHeader.bfReserved2 = 0; // create new file, overwrite if neccessary HANDLE hFile; if (strFilename != NULL) hFile = CreateFile(strFilename, GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); else hFile = GetStdHandle(STD_OUTPUT_HANDLE); // failed to create file ? if (hFile == INVALID_HANDLE_VALUE) return false; DWORD dwBytesWritten; // write file header if (!WriteFile(hFile, &bmpHeader, sizeof(bmpHeader), &dwBytesWritten, NULL)) return false; // write info header if (!WriteFile(hFile, &bmpInfo, sizeof(bmpInfo), &dwBytesWritten, NULL)) return false; // write image if (!WriteFile(hFile, arImage, bmpInfo.bmiHeader.biSizeImage, &dwBytesWritten, NULL)) return false; // close file and: DONE ! CloseHandle(hFile); return true; } // generate mandelbrot image DWORD WINAPI Calculate(void *pParameter) { // cast TFractalParameters *param = (TFractalParameters*) pParameter; // walk through the image COLORREF* pImageCursor = param->arImage; // process all points // remind that BMPs are built bottom-up ! for (unsigned int nRow = 0; nRow < param->nHeight; nRow++) { for (unsigned int nColumn = 0; nColumn < param->nWidth; nColumn++) { // get current coordinates const double dX = nColumn/(param->nWidth -1.0) * (param->dRight - param->dLeft ) + param->dLeft; const double dY = nRow /(param->nHeight-1.0) * (param->dTop - param->dBottom) + param->dBottom; // initialize unsigned int nDepth = 0; double wx = dX; double wy = dY; // calculate point's color do { const double old_wx = wx; nDepth++; wx = wx*wx - wy*wy + dX; wy = 2*old_wx * wy + dY; } while (wx*wx + wy*wy <= 4 && nDepth <= param->nMaxDepth); // we counted once too much nDepth--; // convert iteration depth to grey and save it nDepth = int((param->nMaxDepth-nDepth) * 255.0 / param->nMaxDepth); *pImageCursor = RGB(nDepth, nDepth, nDepth); pImageCursor++; } } return 0; } // here we go ! int main(int argc, char* argv[]) { // default fractal parameters unsigned int nWidth = 512; unsigned int nHeight = 512; double dLeft = -2.0; double dRight = 0.5; double dTop = 1.25; double dBottom = -1.25; unsigned int nMaxDepth = 25; const char* strFilename = NULL; unsigned int nThreads = 1; // no command line parameters or help requested ? if (argc == 1) { printf("options:\n" " /f:image.bmp output file (default: standard output)\n" " /m:1 no. of threads (default: 1 thread)\n" " /x:512 set width (default: 512 pixel)\n" " /y:512 set height (default: 512 pixel)\n" " /l:-2.0 left border (default: -2.0)\n" " /r:0.5 right border (default: 0.5)\n" " /t:1.25 top border (default: 1.25)\n" " /b:-1.25 bottom border (default: -1.25)\n" " /d:25 iteration depth (default: 25, must be 0..255)\n" ); return 1; } // parse command line int nParameter = 1; while (nParameter < argc) { // parse one parameter const char* strOption = argv[nParameter]; // simple verification if (strOption == NULL || strlen(strOption) < 4 || strOption[0] != '/' || strOption[2] != ':') { printf("unknown option '%s'\n", strOption); return 1; } // value the parameter should contain const char* strValue = &(strOption[3]); // set parameters switch(strOption[1]) { // filename case 'f': case 'F': strFilename = strValue; break; // image size case 'x': case 'X': nWidth = atoi(strValue); break; case 'y': case 'Y': nHeight = atoi(strValue); break; // borders case 'l': case 'L': dLeft = atof(strValue); break; case 'r': case 'R': dRight = atof(strValue); break; case 't': case 'T': dTop = atof(strValue); break; case 'b': case 'B': dBottom = atof(strValue); break; // iteration depth case 'd': case 'D': nMaxDepth = atoi(strValue); break; // threads case 'm': case 'M': nThreads = atoi(strValue); break; // error default: printf("unknown option '%s'\n", strOption); return 1; } // next one nParameter++; } // allocate memory COLORREF* arImage = new COLORREF[nWidth*nHeight]; // store thread handles HANDLE* arhThread = new HANDLE[nThreads]; DWORD dwThreadID; // thread parameters TFractalParameters* param = new TFractalParameters[nThreads]; const double dHeightDelta = (dTop - dBottom)/nThreads; // launch threads for (unsigned int i=0; i