Click here to Skip to main content
15,867,594 members
Articles / Desktop Programming / Win32

A Mandelbrot Explorer/Zoom with Julia Walkabout

Rate me:
Please Sign up or sign in to vote.
4.33/5 (5 votes)
29 May 2010CPOL2 min read 25K   327   14   2
A Mandelbrot Explorer/Zoom with Julia walkabout
Image 1

Introduction

This simple app and article demonstrate Windows Message Handling and painting on a Win32 device context. A device context is a structure that defines a set of graphic objects and their associated attributes, as well as the graphic modes that affect output.

The graphics objects include a pen for line drawing, a brush for painting and filling, a bitmap for copying or scrolling parts of the screen, a palette for defining the set of available colors, a region for clipping and other operations.

We will start off by declaring our variables.

C++
//*********************************************************************
//* Defines                                                           *
//*********************************************************************

#define  pi 3.1415926
#define  WIDTH 400
#define  HEIGHT 400
#define  WEXT 380
#define  HEXT 210
#define  MAGNITUDE_CUTOFF 100
#define  NUMCOLOURS 256
#define  ID_TIMER 1
#define  DIVFACTOR 1

#define  XMin   -1.4
#define  XMax    1.4
#define  YMin   -1.4
#define  YMax    1.4
#define  Iter   32
#define  Scal   32767
#define  ResX 150
#define  ResY 150

// **************************************************************************
// **                      Global Variables                                **
// **************************************************************************

bool xorDone=false;
char title[]="MandelZoom / Julia Walkabout      by Topcoder",buffer[80],String[40];
int max_iterations,mousex,mousey,xorEx=0,xorEy=0,MouseX,MouseY;
double xmin = -2.10, xmax = 0.75, ymin = -1.5 , ymax = 1.5;
double  width_fact, height_fact;
double midx,midy,dx,dy;
double dxx,dyy,px,py,zsx,zsy,zex,zey;
int xp,yp,random=0;
float jdx=0,jdy=0,r=0,theta=0,jx=0,jy=0,tempx,tempy;
rektangel rekt;
POINT start,end;
HDC hdc;
HWND Button[2],Edit,StatusBar;

HDC          hdcMem;
HBITMAP      hbmMem;
HANDLE       hOld;
RECT rect;
HBRUSH hbrush = CreateSolidBrush(RGB(0,0,128));

Then we register our window by using RegisterClassEx():

C++
int WINAPI WinMain (HINSTANCE hinst, HINSTANCE hprevinst, LPSTR lpCmdLine,int cmdShow)
{
	if (hprevinst == NULL)
	{
		WNDCLASSEX wclass;
		wclass.cbSize = sizeof(WNDCLASSEX);
		wclass.hInstance = hinst;
		wclass.lpfnWndProc = (WNDPROC)WndProc;
		wclass.style = CS_HREDRAW | CS_VREDRAW;
		wclass.hIcon = LoadIcon(hinst, IDC_ARROW);
		wclass.hIconSm = NULL;
		wclass.hCursor = LoadCursor(NULL, IDC_ARROW);
		wclass.lpszMenuName = NULL;
		wclass.cbClsExtra = 0;
		wclass.cbWndExtra = 0;
		wclass.hbrBackground = (HBRUSH)GetStockObject(GRAY_BRUSH);
		wclass.lpszClassName = "BASIC2";

		if(!RegisterClassEx(&wclass))   return 0;

Then we create the actual window and show it using CreateWindowEx() and ShowWindow().

C++
HWND hwnd = CreateWindowEx(
	WS_EX_WINDOWEDGE,   // extended window style
	"BASIC2",           // registered class name
	title,              // window name
	WS_OVERLAPPEDWINDOW,// window style
	CW_USEDEFAULT,      // horizontal position of window
	CW_USEDEFAULT,      // vertical position of window
	WIDTH+WEXT,		    // window width
	HEIGHT+32,	        // window height
	NULL,				// handle to parent or owner window
	NULL,				// menu handle or child identifier
	hinst,				// handle to application instance
	NULL);				// window-creation data

	ShowWindow(hwnd, cmdShow);
	UpdateWindow(hwnd); 

Now, we start the Win32 message pump with the code below. A Windows application processes messages from the operating system, and most Win32 applications have to be able to translate and dispatch windows messages.

Now we can send and receive windows messages using TranslateMessage() and DispatchMessage().

C++
while (GetMessage(&msg, NULL, 0, 0))
{
	TranslateMessage (&msg) ;
	DispatchMessage(&msg);	// send the message to the window proc
}

return msg.wParam;

}//  End int WINAPI WinMain ( 

The WM_CREATE Message

The WM_CREATE message is called upon when the application is being created and instantized. In this code section, controls such as buttons, listboxes, comboboxes are created using the CreateWindow() function.

C++
LRESULT CALLBACK WndProc(HWND hwnd, UINT msg, WPARAM wparam, LPARAM lparam)
{
	 	switch(msg)
	 	{

case WM_CREATE:
	Button[0] = CreateWindow (
		"button",
		"reset",
		WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
		WIDTH+5,		//Button position x
		 HEIGHT-48,  	//Button position y
		 WIDTH/2, 	//Button Dimension x
		 30,  		//Button Dimension y
		 hwnd,
		 (HMENU) 5 ,
		 ((LPCREATESTRUCT) lparam)->hInstance,
		NULL);

	Button[1] = CreateWindow (
		"button",
		"Exit",
		WS_CHILD|WS_VISIBLE|BS_PUSHBUTTON,
		WIDTH+(WIDTH/2)+5,	//Button position x
		 HEIGHT-48,  	//Button position y
		 (WIDTH/2)-48, 	//Button Dimension x
		 30,  		//Button Dimension y
		 hwnd,
		 (HMENU) 6,
		 ((LPCREATESTRUCT) lparam)->hInstance,
		NULL);

	   SetTimer(hwnd,ID_TIMER,1,NULL);
break;

The WM_PAINT Message

The WM_PAINT message is called upon if an area on the application needs to be updated.
We place our paint and update functions in this code section.

C++
case WM_PAINT:
	Paint(hwnd);
	initWalk();
	putCursor();
	walkabout();
break;

The WM_LBUTTONDOWN Message

The WM_LBUTTONDOWN message is called upon when the left button is pressed down. When the user presses down the left mouse button, our application stores the mouse's current x and y coordinates in the variables start.x and start.y. As the user drags the mouse, a rectangle is drawn, it defines the size of the region of the mandelbrot on which to zoom in on.

C++
case WM_LBUTTONDOWN:
{
	if (mouse_x>=0 && mouse_x<=WIDTH && mouse_y>=0 && mouse_y<=HEIGHT)
	{
		rekt.visa = true;
		rekt.sx = (float)mouse_x;
		rekt.sy = (float)mouse_y;
		rekt.ex = (float)mouse_x;
		rekt.ey = (float)mouse_y;

		xorEx=(int)rekt.sx+100;
		xorEy=(int)rekt.sy+100;
		end.x=0;
		end.y=0;
		start.x=mouse_x;
		start.y=mouse_y;
		MoveToEx (hdc, start.x, start.y, NULL) ;

		zsx=(xmin+(xmax-xmin)*((mousex)-px)/(WIDTH-1));
		zsy=(ymin+(ymax-ymin)*((mousey)-py)/(HEIGHT-1));
		zex=(xmin+(xmax-xmin)*((mousex)-px)/(WIDTH-1));
		zey=(ymin+(ymax-ymin)*((mousey)-py)/(HEIGHT-1));

		tempx=xmin;
		tempy=ymin;
		xmin=zsx;
		ymin=zsy;

		textout();
	}
} break; 

The WM_MOUSEMOVE Message

The WM_MOUSEMOVE message is called upon when the user drags the mouse. As the mouse is being dragged, a rectangular box is drawn to show where the next zoom region will be.

C++
case WM_MOUSEMOVE:
{
	if (mouse_x>=0 && mouse_x<=WIDTH && mouse_y>=0 && mouse_y<=HEIGHT)
	{
		if (mouse_x>=rekt.sx && mouse_y >=rekt.sy )
		{
			rekt.ex = (float)mouse_x;
			rekt.ey = (float)mouse_y;
			dx=zex-zsx;
			dy=zey-zsy;
		}

		if (rekt.visa )
		{
			BitBlt(hdc, 0, 0, WIDTH, HEIGHT, hdcMem, 0, 0, SRCCOPY);
			SetROP2(hdc,R2_NOTXORPEN);
			int DrawMode = GetROP2(hdc);
			MoveToEx (hdc, (int)rekt.sx, (int)rekt.sy, NULL) ;
			LineTo (hdc, (int)rekt.ex ,(int)rekt.sy) ;
			LineTo (hdc, (int)rekt.ex ,(int)rekt.ey) ;
			LineTo (hdc, (int)rekt.sx ,(int)rekt.ey) ;
			LineTo (hdc, (int)rekt.sx ,(int)rekt.sy) ;
			SetROP2(hdc,R2_COPYPEN);

		}
	mousex=mouse_x;
	mousey=mouse_y;
	textout();
	}

} break; 

The WM_LBUTTONUP Message

The WM_LBUTTONUP message is called upon when the left button is released. Once the user releases the left mouse button, our application stores the mouse's current x and y coordinates in the variables end.x and end.y. Our application now calculates the new interpolants on which to calculate the mandelbrot from.

C++
case WM_LBUTTONUP:
{
	if (mouse_x>=0 && mouse_x<=WIDTH && mouse_y>=0 && mouse_y<=HEIGHT)
	{

		rekt.visa = false;
		end.x=mouse_x;
		end.y=mouse_y;
		rekt.ex =(float)mousex;
		rekt.ey =(float)mousey;
		if (end.x >start.x+5 && end.y >start.y +5)
		{

			// Free-up the off-screen DC
			initWalk();
			MouseX=WIDTH/2;
			MouseY=HEIGHT/2;

			SelectObject(hdcMem, hOld);
			DeleteObject(hbmMem);
			DeleteDC(hdcMem);

			dx=zex-zsx;
			dy=zey-zsy;

			if (mouse_x>=rekt.sx && mouse_y >=rekt.sy )
			{
				zex=(xmin+(xmax-xmin)*((mousex)-px)/(WIDTH-1));
				zey=(ymin+(ymax-ymin)*((mousey)-py)/(HEIGHT-1));

				xmax=zex;
				ymax=zey;
				dx=zex-zsx;
				dy=zey-zsy;
				textout();
				//if (rekt.sx!=rekt.ex && rekt.sy!=rekt.ey)
				 fract(/*hdc*/);
				 putCursor();
				 walkabout();
			}

			}
			else
			{
				BitBlt(hdc, 0, 0, WIDTH, 
					HEIGHT, hdcMem, 0, 0, SRCCOPY);
				xmin=tempx;
				ymin=tempy;

		       }
	}
} break; 

The WM_KEYDOWN Message

The WM_KEYDOWN message is called upon when a key is pressed down.

C++
case WM_KEYDOWN:
{
	int virtual_code = (int) wparam;
	int key_bits     = (int) lparam;

	switch (virtual_code)
	{
		case 27: {
					PostQuitMessage(0); //<esc> quits
				} break;

		case 13: {
					//<enter>
				resetFrac();
				fract(/*hdc*/);
				} break;
		case 32:{
				}break;

		case VK_RIGHT: { } break;
		case VK_LEFT: { } break;
	default: break;
}

} break;

The WM_QUIT and WM_DESTROY Message

The WM_QUIT and WM_DESTROY message is called upon when the application is signalling it wants to quit.

C++
		WM_QUIT:
		case WM_DESTROY:
			KillTimer(hwnd,ID_TIMER);
			PostQuitMessage(0);
		break;

		return 0;

		default:
		return DefWindowProc(hwnd, msg, wparam, lparam);
		}

	ReleaseDC(hwnd, hdc);
	return 0;
} // end  LRESULT CALLBACK WndProc()

And that is all that is required to create a Win32 application that draws and zooms a mandelbrot on a Win32 device context.

Thanks for reading.

History

  • 2010-05-08 Updates made
  • 2002-06-22 Code complete

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Sweden Sweden
About me:
I attended programming college and I have a degree in three most famous and successful programming languages. C/C++, Visual Basic and Java. So i know i can code. And there is a diploma hanging on my wall to prove it.
.
I am a professional, I am paid tons of cash to teach or do software development. I am roughly 30 years old .

I hold lectures in programming. I have also coached students in C++, Java and Visual basic.

In my spare time i do enjoy developing computer games, and i am developing a rather simple flight simulator game
in the c++ programming language using the openGL graphics libray.

I've written hundreds of thousands of code syntax lines for small simple applications and games.

Comments and Discussions

 
GeneralClean up after using a logical brush Pin
David MacDermot11-May-10 6:27
David MacDermot11-May-10 6:27 
GeneralGDI Objects Leak! Pin
kacza11-May-10 0:55
kacza11-May-10 0:55 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.