### GDI Mandelbrot Set generator not working...

Pages: 12
I'm trying to create a Mandelbrot Set generator based on the pseudocode from the Wikipedia article. All it's doing is drawing black pixels in the whole client area (save for a few rows at the top).

Here's the relevant portion of the drawing code:

 ``123456789101112131415161718192021222324252627282930`` ``````for(int vPos= cr.top; vPos < cr.bottom; vPos++) { for(int hPos= cr.left; hPos < cr.right; hPos++) { COLORREF color= NULL; int x0= hPos,y0= vPos; int x= x0,y= y0; int iteration= 0; int maxIterations= 10; while((x*x) + (y*y) <= 4 && iteration < maxIterations) { double xTemp= x*x - y*y + x0; vPos= 2*x*y + y0; x= xTemp; iteration++; } if(iteration == maxIterations) color= RGB(0,0,0); else color= RGB(iteration,0,0); SetPixel(hdc,hPos,vPos,color); } }``````

Yes, I know, I'm being bad and using SetPixel(), which is very slow, but at this point my brain would probably explode if I tried to do it using BitBlt(), ;). In fact, I'm not sure if that's even possible...

I have yet to understand what the simplest form of the Mandelbrot formula is (Wikipedia slams you with loads upon loads of Greek symbols and *shudder* calculus... DX ), so if someone could help me with the math, that would be cool, too.

I'm thinking it might be because I'm putting the procedure in the wrong place, but I don't know where else to put it!

Just for clarification, here's Wikipedia's pseudocode:

 ``1234567891011121314151617181920212223242526`` ``````For each pixel on the screen do: { x = x0 = x co-ordinate of pixel y = y0 = y co-ordinate of pixel iteration = 0 max_iteration = 1000 while ( x*x + y*y <= (2*2) AND iteration < max_iteration ) { xtemp = x*x - y*y + x0 y = 2*x*y + y0 x = xtemp iteration = iteration + 1 } if ( iteration == max_iteration ) then color = black else color = iteration plot(x0,y0,color) }``````
Last edited on
You have:
 `` `` ``vPos= 2*x*y + y0;``

You mean:
 `` `` ``y= 2*x*y + y0;``

I think SetPixelV is a little faster.
Last edited on
Oops... I guess I missed that little detail; thanks. Fixing it hasn't changed it much, though. All it did was fill in the missing rows at the top of the client rectangle.

As for SetPixelV() being faster than SetPixel(), according to MSDN, it's faster because "it does not need to return the color value of the point actually painted.", although I can't really see any visibly significant speed difference. Thanks for the suggestion, though; I might start using that more often (I don't think I'll really need the color from SetPixel's return value anytime soon, anyway, unless it's for some complex (and slow) graphics operation).

I think the problem is in my math (ugh!). Wikipedia's pseudocode is really vague about the variable declarations. I know it's supposed to be pseudocode, not a full example in C, but I'm talking about the way variables are supposed to be associated with each other. When they say "x = x0 = x coordinate of pixel", do they mean that you should declare a variable x0 that is equal to the x coordinate of the pixel, then declare one called x, and have it equal to x0, which is equal to the x coord of the pixel? Seems kinda redundant if you ask me.

Oh well. In the meantime, I'll try Googling around for some *simplified* equation for the Mandelbrot Set.

Although if anyone wants to pitch in with the math, that'd be very much appreciated.

EDIT: Found a pdf on the set, but it just gives me the same eq'n as what I got (in essence) from the pseudocode. Now I'm really stumped...
Last edited on
 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122`` ``````///////////////////////////////////////////////////////////////////////////// // CMandelbrotView message handlers // -------------------------------------------------------------------------------------------------------- // CDrawItView::mandel_iterC // -------------------------------------------------------------------------------------------------------- // Parameter : double x, y = Position in Gauss'schen Plain // int maxiter = maximum number of iterartions // -------------------------------------------------------------------------------------------------------- // mandel_iterC() does the underlying/actual Mandelbrot-Calculation and returns the number of // executed iterations // -------------------------------------------------------------------------------------------------------- // Return-Value : int i = Number of Iteration Steps // -------------------------------------------------------------------------------------------------------- int CMandelbrotView::mandel_iterC (double x, double y, int maxiter) { // initialisiere temporäre Variablen double sx, sy, zx, zy; int i; zx = x; zy = y; sx = zx * zx; sy = zy * zy; i = 0; // calculate iterations while ((i <= maxiter) && (sx+sy<=4.0)) { zy = (zx+zx)*zy + y; zx = sx - sy + x; sx = zx * zx; sy = zy * zy; i = i+1; } // Gebe Anzahl der Iterationsschritte zurück return (i); } ///////////////////////////////////////////////////////////////////////////// // CMandelbrotView drawing void CMandelbrotView::OnDraw(CDC* pDC) { // Zugriff auf das Dokument erlangen CMandelbrotDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); // TODO: add draw code for native data here // Erzeuge Stift und speichere den bisher aktuellen CPen plotPen(PS_SOLID,1, RGB(0,0,0)); CPen *pOldPen = pDC->SelectObject(&plotPen); // initialisiere temporäre Variablen long double dx, dy, x, y; int anzahl_gitterpunkte, iterationswert, aufloesung; int farbvorberechnung = (255 / pDoc->getMaxIter()); POINT bildposition; CRect clientRect; GetClientRect(clientRect); // get resolution to be used aufloesung = (clientRect.Width() > clientRect.Height()) ? clientRect.Width() : clientRect.Height(); // number of of points to be calculated is resolution(aufloesung) + 1 anzahl_gitterpunkte = aufloesung+1; // calculate value range of pixel dx = (pDoc->getXEndPosition()-pDoc->getXStartPosition()) / long double(aufloesung); dy = (pDoc->getYEndPosition()-pDoc->getYStartPosition()) / long double(aufloesung); // setze die Y-Werte auf START y = pDoc->getYStartPosition(); bildposition.y = 1; // machine all rows while (bildposition.y <= anzahl_gitterpunkte) { // setze die X-Werte auf START x = pDoc->getXStartPosition(); bildposition.x = 1; // machine every pixel while (bildposition.x <= anzahl_gitterpunkte) { // calculate iteration-value iterationswert = mandel_iterC(x,y,pDoc->getMaxIter()); // wurde die Iterationsgrenze überschritten? if (iterationswert >= pDoc->getMaxIter()) { // ja, zeichne einen schwarzen Punkt pDC->SetPixel(bildposition, RGB(0,0,0)); } else { // befinden wir uns im Farbmodus? if (pDoc->inColorMode()) { // ja, zeichne einen passenden farbigen Punkt int farbe = 255 - (farbvorberechnung * iterationswert); pDC->SetPixel(bildposition, RGB(255,farbe,farbe)); } } // rücke zum nächsten Pixel vor x += dx; bildposition.x += 1; } // rücke zur nächsten Zeile vor y += dy; bildposition.y += 1; } // setze den Stift auf den Ausgangsstift zurück pDC->SelectObject(&pOldPen); }``````

I hope this helps a bit... im sorry if u there is not everything translated^^...

well... but i have to say that its slow, too - at least when u increase the max_iter^^...

(and pssst: it uses MFC:P - but that should not bother u^^)
Last edited on
This color would be very dark (almost black) color= RGB(iteration,0,0);
Try changing it (for now at least) to RGB(255,255,255).
Well, sorry to seem picky, but I really would rather not re-write my program to use MFC (I don't even know MFC anyways; I got what I know from theForger's Win API tutorial ( http://www.winprog.org/tutorial/ ) and MSDN). I'm looking at the code, though to see if I can adapt it to API.

Also, regarding Hammurabi's post, changing the iteration color to white just gives me all white pixels... I think I'm doing something wrong procedure-wise, but I don't know what. Still looking into it.

EDIT: trying to adapt the MFC code is turning out to be way harder than I expected (and frankly I'm starting to get frustrated)... maybe clarification on some of the functions would help? For instance, could I just use the client rect's right and bottom members for pDoc->getX/YEndPosition when initializing dx/y? And what's up with the "?" operator... isn't that bad usage? (it doesn't have the " x (condition) y ? a:b" format...)

I apologize for sounding like a n00b... I'm really not all that experienced...
Last edited on
Your x and y positions need to be doubles. They also must have values within the range of the Mandelbrot set, which is between -2 and .5 for x and -1.25 and 1.25 for y. So for instance if vPos is a pixel offset (an integer between 0 and whatever) then you cannot simply assign it to y. You must translate it to the Mandelbrot coords.

You should post your entire program, as one file preferably.
Ok, so I've tried revising my code, and I think I might be starting to make a little headway with it, but now I'm seeing all white pixels. I've changed the x and y to long doubles, just to be on the safe side. Now the thing is, I can't figure out how to get the range of -2 to 0.5 for x and -1.25 and 1.25 for y. There are a couple of functions in Incubbus's code that seem to be specific to the CMandelbrotView class pointer he's declared (pDoc->getMaxIter() and pDoc->inColorMode()) that apparently get the maximum number of iterations and set the x and y ranges(?).

In any case, here's my revised (albeit still non-functioning) code:

 ``123456789101112131415161718192021`` ``````for(int vPos= cr.top; vPos < cr.bottom; vPos++) //for each line { for(int hPos= cr.left; hPos < cr.right; hPos++) //for each pixel { COLORREF color= NULL; long double x= hPos,y= vPos; int maxIterations= 1000; float colorCalc= 255 / (float)maxIterations; int iterations= CalcPixel(x,y,maxIterations); if(iterations >= maxIterations) SetPixel(hdc,hPos,vPos,RGB(0,0,0)); else { float colorRange= 255 - (colorCalc * iterations); SetPixel(hdc,hPos,vPos,RGB(255,(int)colorRange,(int)colorRange)); } } }``````

I apologize for the long address URL, I can't get [url] tags to work in the UBBcode.

The implementation of CalcPixel is the same as Incubbus's CMandelbrotView::mandel_iterC() function, just renamed, so I'll give him the credit for it... I really don't feel like re-writing a function that is basically the same thing, just with different variable names and such just to avoid copying issues (because it's really still outright copying anyway, even if you change the variable names, am I right?)

Also note: the typecasting was done to stop VC++ nagging me about "possible loss of data". I know I should be compiling it as C rather than C++, but I was being lazy when I first created the project (I let VC++ do the extension appendage), so now I have to do typecasting manually. I don't think that's going to cause any major problems, other than it being a little less accurate than it could be...
Last edited on
There's no reason to use long doubles, regular doubles are fine. You just can't use int. But you're still just using pixel numbers for x and y. That won't work. The Mandelbrot set is a set of numbers in the complex plane. You need to translate your pixel numbers to complex numbers. Something like this (just whipped up, untested code, probably has errors):

 ``123456789101112131415161718192021222324252627282930313233343536373839404142`` ``````struct DRect { double left, top, right, bottom; }; void drawMandelbrot( HDC hdc, // HDC of window to draw to. RECT& cr, // Client rect. DRect& disp // Area of the complex plane to display. ){ const int MaxCount = 200; double stepX = (disp.right - disp.left) / cr.right; double stepY = (disp.botom - disp.top) / cr.bottom; double cx = disp.left; double cy = disp.top; for( int y = 0; y < cr.right; ++y ){ for( int x = 0; x < cr.bottom; ++x ){ double zx = 0, zy = 0; int count; for( count = 0; count < MaxCount; ++count ){ double oldX = zx; zx = oldX * oldX - zy * zy + cx; zy = 2 * oldX * zy + cy; if( zx * zx + zy * zy > 4.0 ) break; } // Display in grayscale int n = 0; if( count < MaxCount ) n = count * 256 / MaxCount; SetPixelV( hdc, x, y, RGB( n, n, n )); cx += stepX; } cx = disp.left; cy += stepY; } } // wherever RECT cr; GetClientRect( hwnd, &cr ); DRect disp = { -2, -1.25, .5, 1.25 }; drawMandelbrot( hdc, cr, disp );``````

Note that in C++ you could use the complex type (might be slower, though):

 ``1234`` `````` for( count = 0; count < MaxCount; ++count ){ z = z * z + c; if( abs( z ) > 2.0 ) break; }``````

Last edited on
Here's a runnable example.

 ``12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394`` ``````#include #define CLIENT_SIZE_X 400 #define CLIENT_SIZE_Y 400 struct DRect { double left, top, right, bottom; }; struct WndSize { int horz, vert; }; void drawMandelbrot( HDC hdc, const DRect& loc, const WndSize& pixels ){ const int MaxCount = 256; double xstep = (loc.right - loc.left) / pixels.horz; double ystep = (loc.bottom - loc.top) / pixels.vert; double cx, cy; int x, y; for( y = 0, cy = loc.top; y < pixels.vert; ++y, cy += ystep ) for( x = 0, cx = loc.left; x < pixels.horz; ++x, cx += xstep ){ double zx = 0, zy = 0; double zx2 = 0, zy2 = 0; // zx and zy squared int count; for( count = 0; count < MaxCount; ++count ){ zy = 2 * zx * zy + cy; // must be before zx is changed zx = zx2 - zy2 + cx; zx2 = zx * zx; zy2 = zy * zy; if( zx2 + zy2 > 4.0 ) break; } int n = 0; if( count < MaxCount ) n = 255 - count * 256 / MaxCount; SetPixelV( hdc, x, y, RGB( n, n, n )); } } void wmPaint( HWND hwnd, WPARAM wp, LPARAM lp ){ PAINTSTRUCT ps; HDC hdc = BeginPaint( hwnd, &ps ); DRect loc = { -2.0, 1.25, 0.5, -1.25 }; WndSize wndSize = { CLIENT_SIZE_X, CLIENT_SIZE_Y }; drawMandelbrot( hdc, loc, wndSize ); EndPaint( hwnd, &ps ); } LRESULT CALLBACK mainWndProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ){ switch( msg ){ case WM_PAINT: wmPaint (hwnd, wp, lp); break; case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc (hwnd, msg, wp, lp); } return 0; } void registerWindow( HINSTANCE hinst, char *appname, WNDPROC wp ){ WNDCLASSEX wc = {sizeof(wc)}; // set first member, zero the rest wc.style = CS_HREDRAW|CS_VREDRAW; wc.lpfnWndProc = wp; wc.hInstance = hinst; wc.hIcon = LoadIcon( hinst, appname ); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = (HBRUSH) GetStockObject( BLACK_BRUSH ); wc.lpszMenuName = appname; wc.lpszClassName = appname; wc.hIconSm = LoadIcon( hinst, appname ); RegisterClassEx( &wc ); } int WINAPI WinMain( HINSTANCE hinst, HINSTANCE unused, PSTR cmd, int show ){ char *appName = "Mandelbrot"; MSG msg; DWORD style = WS_POPUPWINDOW|WS_CAPTION; RECT rect = {0, 0, CLIENT_SIZE_X, CLIENT_SIZE_Y}; registerWindow( hinst, appName, mainWndProc ); AdjustWindowRect( &rect, style, FALSE ); CreateWindowEx( 0, appName, appName, style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hinst, NULL ); while( GetMessage( &msg, NULL, 0, 0 )){ TranslateMessage( &msg ); DispatchMessage( &msg ); } return msg.wParam; }``````

*sigh*, I can't get it to work, and I probably never will... at least until I get a good understanding of the math behind it. I couldn't get the first example to work (apparently it does have errors, which I won't be able to figure out anytime soon), and the second one, being a full program, would require me to completely re-think my WndProc structure. My math really isn't that good; I don't know why I'm even attempting this, considering I really don't know the (apparently) intricate details of complex numbers required to pull this off (all I really know is that i is just an abstract representation of sqrt(-1); everything else is just guesswork for me). As far as recursive graphical routines, I think I'm better suited to LOGO or just very basic GDI fractals (i.e. ones that involve boolean logic, rather than "numbers on the complex plane").

I guess I just got too enthusiastic about wanting to do this and took a bigger bite than I could chew. I tried to dive straight into complex mathematics without having a proper knowledge of the subject. I apologize if I've wasted anyone's time.

I think I'll just go ahead and put this off for now, until I can really get a better grasp on the math...
: I found your mistake. You are not scaling your pixels! [Edit:] Just saw Hammurabi pointed that out too... Well below is how to modify your original post's code:

 ``123456789101112131415161718192021222324252627`` ``````int middleX = cr.right- cr.left; int middleY = cr.bottom- cr.top; for(int vPos= cr.top; vPos < cr.bottom; vPos++) { for(int hPos= cr.left; hPos < cr.right; hPos++) { COLORREF color= NULL; double x0= (hPos-middleX)/200,y0= (vPos- middleY)/200; double x= x0,y= y0; int iteration= 0; int maxIterations= 10; while((x*x) + (y*y) <= 4 && iteration < maxIterations) { double xTemp= x*x - y*y + x0; y= 2*x*y + y0;//originally it was wrong: hPos= 2*x*y + y0. x= xTemp; iteration++; } if(iteration == maxIterations) color= RGB(0,0,0); else color= RGB(255,255,255);//you can simply make it black and white to begin with. //as soon as you get something that looks like the Mandelbrot set you can play with the colors:) SetPixel(hdc,hPos,vPos,color); } }``````

A math question to you: what will happen when you change that number 200 I put in there?
Last edited on
@ Hammurabi: Tried your program, looks beautiful :)
wow... impressive.
Here's an updated version. It displays in color and allows you to zoom in. Hold the left mouse button down to draw a selection rectangle. If you press the right button before you let the left button up, it will cancel the selection rectangle. Double click to reset to the original view.

 ``123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219`` ``````#include const int CLIENT_SIZE_X = 400; const int CLIENT_SIZE_Y = 400; const int SELECTION_TOO_SMALL = 4; struct DRect { double left, top, right, bottom; }; struct WndSize { int horz, vert; }; const DRect INIT_LOCATION = { -2.0, 1.25, 0.5, -1.25 }; DRect g_location = INIT_LOCATION; RECT g_selection; void drawMandelbrot( HDC hdc, const DRect& loc, const WndSize& pixels ){ const double saturation = 0.5; const double value = 0.7; const double rotation = 20.0; // adjusts hue const int MaxCount = 100; COLORREF color; double hue, f; int p, q, t; double xstep = (loc.right - loc.left) / pixels.horz; double ystep = (loc.bottom - loc.top) / pixels.vert; double cx, cy; int x, y; for( y = 0, cy = loc.top; y < pixels.vert; ++y, cy += ystep ) for( x = 0, cx = loc.left; x < pixels.horz; ++x, cx += xstep ){ double zx = 0, zy = 0; double zx2 = 0, zy2 = 0; // zx and zy squared int count; for( count = 0; count < MaxCount; ++count ){ zy = 2 * zx * zy + cy; // must be before zx is changed zx = zx2 - zy2 + cx; zx2 = zx * zx; zy2 = zy * zy; if( zx2 + zy2 > 4.0 ) break; } color = RGB( 0, 0, 0 ); // Points in the set are black if( count < MaxCount ){ // Points outside the set are colored hue = count * 360.0 / MaxCount + rotation; while( hue >= 360.0 ) hue -= 360.0; // Convert HSV to RGB f = hue / 60 - (int)(hue / 60); p = (int) (value * (1 - saturation) * 255); q = (int) (value * (1 - f * saturation) * 255); t = (int) (value * (1 - (1 - f) * saturation) * 255); switch( (int)(hue / 60) % 6 ) { case 0: color = RGB( value, t, p ); break; case 1: color = RGB( q, value, p ); break; case 2: color = RGB( p, value, t ); break; case 3: color = RGB( p, q, value ); break; case 4: color = RGB( t, p, value ); break; case 5: color = RGB( value, p, q ); break; } } SetPixelV( hdc, x, y, color ); } } void normalizeRect( RECT *rect ){ LONG temp; if( rect->top > rect->bottom ){ temp = rect->top; rect->top = rect->bottom; rect->bottom = temp; } if( rect->left > rect->right ){ temp = rect->left; rect->left = rect->right; rect->right = temp; } } void setSelectRect( LONG l, LONG t, LONG r, LONG b ){ g_selection.left = l; g_selection.top = t; g_selection.right = r; g_selection.bottom = b; } void drawSelectRect( HWND hwnd ){ HDC hdc = GetDC( hwnd ); RECT rect = g_selection; normalizeRect( &rect ); DrawFocusRect( hdc, &rect ); ReleaseDC( hwnd, hdc ); } void endSelection( HWND hwnd ){ HDC hdc = GetDC( hwnd ); normalizeRect( &g_selection ); DrawFocusRect( hdc, &g_selection ); ReleaseDC( hwnd, hdc ); ReleaseCapture(); } BOOL isSelectionTooSmall( void ){ return( g_selection.right - g_selection.left < SELECTION_TOO_SMALL || g_selection.bottom - g_selection.top < SELECTION_TOO_SMALL ); } void updateLocation( void ){ double size = g_location.right - g_location.left; double temp = g_location.left + size * g_selection.left / CLIENT_SIZE_X; g_location.right = g_location.left + size * g_selection.right / CLIENT_SIZE_X; g_location.left = temp; size = g_location.bottom - g_location.top; temp = g_location.top + size * g_selection.top / CLIENT_SIZE_Y; g_location.bottom = g_location.top + size * g_selection.bottom / CLIENT_SIZE_Y; g_location.top = temp; } void wmLButtonDown( HWND hwnd, WPARAM wp, LPARAM lp ){ SetCapture( hwnd ); setSelectRect( LOWORD( lp ), HIWORD( lp ), LOWORD( lp ), HIWORD( lp )); drawSelectRect( hwnd ); } void wmMouseMove( HWND hwnd, WPARAM wp, LPARAM lp ){ if( GetCapture() != hwnd ) return; drawSelectRect( hwnd ); g_selection.right = LOWORD( lp ); g_selection.bottom = HIWORD( lp ); drawSelectRect( hwnd ); } void wmLButtonUp( HWND hwnd, WPARAM wp, LPARAM lp ){ if( GetCapture() != hwnd ) return; endSelection( hwnd ); if( isSelectionTooSmall() ) return; updateLocation(); InvalidateRect( hwnd, 0, 1 ); } void wmRButtonDown( HWND hwnd, WPARAM wp, LPARAM lp ){ if( GetCapture() == hwnd ) // If in capture mode endSelection( hwnd ); // cancel selection rect } void wmLButtonDblClk( HWND hwnd, WPARAM wp, LPARAM lp ){ g_location = INIT_LOCATION; InvalidateRect( hwnd, 0, TRUE ); } void wmPaint( HWND hwnd, WPARAM wp, LPARAM lp ){ PAINTSTRUCT ps; HDC hdc = BeginPaint( hwnd, &ps ); WndSize wndSize = { CLIENT_SIZE_X, CLIENT_SIZE_Y }; drawMandelbrot( hdc, g_location, wndSize ); EndPaint( hwnd, &ps ); } LRESULT CALLBACK mainWndProc( HWND hwnd, UINT msg, WPARAM wp, LPARAM lp ){ switch( msg ){ case WM_PAINT: wmPaint (hwnd, wp, lp); break; case WM_LBUTTONDOWN: wmLButtonDown (hwnd, wp, lp); break; case WM_MOUSEMOVE: wmMouseMove (hwnd, wp, lp); break; case WM_LBUTTONUP: wmLButtonUp (hwnd, wp, lp); break; case WM_RBUTTONDOWN: wmRButtonDown (hwnd, wp, lp); break; case WM_LBUTTONDBLCLK: wmLButtonDblClk(hwnd, wp, lp); break; case WM_DESTROY: PostQuitMessage( 0 ); break; default: return DefWindowProc (hwnd, msg, wp, lp); } return 0; } void registerWindow( HINSTANCE hinst, char *appname, WNDPROC wp ){ WNDCLASSEX wc = {sizeof(wc)}; // set first member, zero the rest wc.style = CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS; wc.lpfnWndProc = wp; wc.hInstance = hinst; wc.hIcon = LoadIcon( hinst, appname ); wc.hCursor = LoadCursor( NULL, IDC_ARROW ); wc.hbrBackground = (HBRUSH) GetStockObject( BLACK_BRUSH ); wc.lpszMenuName = appname; wc.lpszClassName = appname; wc.hIconSm = LoadIcon( hinst, appname ); RegisterClassEx( &wc ); } int WINAPI WinMain( HINSTANCE hinst, HINSTANCE unused, PSTR cmd, int show ){ char *appName = "Mandelbrot"; MSG msg; DWORD style = WS_POPUPWINDOW|WS_CAPTION; RECT rect = {0, 0, CLIENT_SIZE_X, CLIENT_SIZE_Y}; registerWindow( hinst, appName, mainWndProc ); AdjustWindowRect( &rect, style, FALSE ); CreateWindowEx( 0, appName, appName, style | WS_VISIBLE, CW_USEDEFAULT, CW_USEDEFAULT, rect.right - rect.left, rect.bottom - rect.top, NULL, NULL, hinst, NULL ); while( GetMessage( &msg, NULL, 0, 0 )){ TranslateMessage( &msg ); DispatchMessage( &msg ); } return msg.wParam; }``````

That's awesome. I need to learn how to do this. What would be interesting is if you could zoom in with the mouse scroll bar wherever the pointer was located. :)
Ultra cool :))))
You should post this in the code section!
Last edited on
 You should post this in the code section!