Sign in to follow this  
EonStrife

OpenGL Mandelbrot Set, help !

Recommended Posts

Hi, I tried to make a simple application generating Mandelbrot set. I used OpenGL (as graphic API), glee (for the extension), and glfw (for the framework), VC++ 2005 (compiler). When I ran the program, I only saw blank screen with a faint large black box hanging in the upper left. Can anyone tell me what mistake I made and give correction ? Here's the source code :
[source="C"]
#include "stdafx.h"
#include "4.h"
#include <GL/glee.h>
#include <GL/glfw.h>
#include <cmath>
using namespace std;

//Define
#define MAX_ITERATION 1000
#define RES_X	1024
#define RES_Y	768
//Global Variables
bool running=true;
bool keyboardKeys[255]={false};
int	g_width;
int g_height;
GLfloat onePix[3];
GLfloat screen[sizeof(GLfloat)*3*RES_X*RES_Y];

struct coordinate
{
	GLdouble x;
	GLdouble y;
}upperLeft, lowerRight;


//Callbacks
void keyCallBack(int key, int state)
{
	if(state==GLFW_PRESS)
		keyboardKeys[key]=true;
	else if(state==GLFW_RELEASE)
		keyboardKeys[key]=false;
}

void calcHSV(int iteration, GLdouble x, GLdouble y)
{
/*
	GLint Hi;
	GLdouble H, f, p, q, t, h, s, v;
	GLdouble xn;
	h=((GLdouble)iteration/(GLdouble)MAX_ITERATION)*360.0f;
	
	xn=x/(double)pow((double)(x*x+y*y),(double)0.5f);
	s=acos(xn)/360.0f;

	v=pow((double)x*x+y*y,(double)0.5f)/1.41421356238f;
	Hi=((int)floor(h/60.0f))%6;
	f=h/360.0f-Hi;
	p=v*(1.0f-s);
	q=v*(1.0f-f*s);
	t=v*(1.0f-(1.0f-f)*s);
	switch(Hi)
	{
	case 0 : onePix[0]=v; onePix[1]=t; onePix[2]=p;break;
	case 1 : onePix[0]=q; onePix[1]=v; onePix[2]=p;break;
	case 2 : onePix[0]=p; onePix[1]=v; onePix[2]=t;break;
	case 3 : onePix[0]=p; onePix[1]=q; onePix[2]=v;break;
	case 4 : onePix[0]=t; onePix[1]=p; onePix[2]=v;break;
	case 5 : onePix[0]=v; onePix[1]=p; onePix[2]=q;break;
	}
	H=0;
*/
	onePix[0]=(GLdouble)iteration/(GLdouble)MAX_ITERATION;
	onePix[1]=(GLdouble)iteration/(GLdouble)MAX_ITERATION;
	onePix[2]=(GLdouble)iteration/(GLdouble)MAX_ITERATION;
}
void gambarUlang()
{
	int i, j, iteration;
	GLdouble x0, y0, x2, y2, x_t, y_t;
	GLdouble step_x, step_y;
	step_x=(lowerRight.x-upperLeft.x)/((GLdouble)g_width);
	step_y=(upperLeft.y-lowerRight.y)/((GLdouble)g_height);
	for(i=0; i<g_width; i++)
	{
		for(j=0; j<g_height; j++)
		{
			x0=((GLdouble)i)*step_x+upperLeft.x;
			y0=upperLeft.y-((GLdouble)j)*step_y;
			x2 = x0 * x0;
			y2 = y0 * y0;
			iteration=0;
			while((x2 + y2 < 2.0f)&& (iteration<MAX_ITERATION))
			{
				x_t=x2+x0;
				y_t=y2+y0;
				x2=x_t*x_t;
				y2=y_t*y_t;
				iteration++;
			}

			if(iteration==MAX_ITERATION)
			{
				onePix[0]=0.0f;onePix[1]=0.0f;onePix[2]=0.0f;
			}
			else
				calcHSV(iteration, x0, y0);

			glWindowPos2i(i, j);
			glDrawPixels(1, 1, GL_RGB, GL_FLOAT, &onePix);

		}
	}
	
	glReadPixels(0, 0, g_width, g_height, GL_RGB, GL_FLOAT, &screen);
}

void WindowResizeCallback(int width, int height)
{
	if (height==0)									
	{
		height=1;								
	}

	glViewport(0,0,width,height);						

	glMatrixMode(GL_PROJECTION);						
	glLoadIdentity();								


	gluOrtho2D(0.0f, (GLdouble) width, 0.0f, (GLdouble) height);
	glMatrixMode(GL_MODELVIEW);							
	glLoadIdentity();								
	g_width=width;
	g_height=height;
	gambarUlang();
}

void MousePosCallback(int x, int y)
{
}

void MouseButtonCallback(int button, int action)
{
}

int WindowsCloseCallback()
{	
	running=false;
	return GL_TRUE;
}

void initGL()
{
//	glShadeModel(GL_SMOOTH);							// Enable Smooth Shading
//	glClearColor(0.0f, 0.0f, 0.0f, 0.5f);				// Black Background
//	glClearDepth(1.0f);									// Depth Buffer Setup
//	glEnable(GL_DEPTH_TEST);							// Enables Depth Testing
//	glDepthFunc(GL_LEQUAL);								// The Type Of Depth Testing To Do
	glHint(GL_PERSPECTIVE_CORRECTION_HINT, GL_NICEST);	// Really Nice Perspective Calculations
														// Initialization Went OK

}
void DrawGLScene()
{
//	glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);	// Clear Screen And Depth Buffer
	glLoadIdentity();									// Reset The Current Modelview Matrix
														// Keep Going
	glWindowPos2i(0, 0);
	glDrawPixels(g_width, g_height, GL_RGB, GL_FLOAT, &screen);
}

void keyboardProcess()
{
	if(keyboardKeys[GLFW_KEY_ESC]==true) running=false;
	if(keyboardKeys[GLFW_KEY_SPACE]==true) gambarUlang();
}

//Main
int APIENTRY _tWinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPTSTR    lpCmdLine,
                     int       nCmdShow)
{

	glfwInit();
	
	if(!glfwOpenWindow(800, 600, 8, 8, 8, 0, 0, 0, GLFW_WINDOW))
	{
		glfwTerminate();
		return 0;
	}

	////////////////
	upperLeft.x=-1.0f;
	upperLeft.y=1.0f;
	lowerRight.x=1.0f;
	lowerRight.y=-1.0f;
	////////////////
	glfwSetWindowTitle("Mandelbrot Set");
	glfwSetWindowSizeCallback(&WindowResizeCallback);
	glfwSetKeyCallback(&keyCallBack);
	glfwSetMousePosCallback(&MousePosCallback);
	glfwSetMouseButtonCallback(&MouseButtonCallback);
	glfwSetWindowCloseCallback(&WindowsCloseCallback);

	initGL();
	while(running)
	{
		DrawGLScene();
		glfwSwapBuffers();
		keyboardProcess();
	}

	glfwTerminate();
	return 0;
}



Thanks :)

Share this post


Link to post
Share on other sites
Was WindowResizeCallback() really called ?

When calculating a mandelbrot set, you have to test if the complex number is in a circle of radius 2 in the complex plane (i.e. if 'x^2 + y^2 < 4'), but you check if 'x^2 + y^2 < 2'. Also the initial value of z in the mandelbrot formula 'z = z^2 + c' is zero and c is the position of the pixel you want to calculate the color for.

Calculation with complex numbers is also different, since you would write (to calculate: z = z^2 + c):

t = zr*zr - zi*zi;
zi = 2*zr*zi;
zr = t;
zr += cr;
zi += ci;


[Edited by - nmi on December 14, 2006 8:48:01 AM]

Share this post


Link to post
Share on other sites
Thanks nmi,
I have made the corrections. However, the mandelbrot set still doesn't look right :
http://img.photobucket.com/albums/v708/EonStrife/mandelbrot1.jpg

Here is the corrected version of the source:
[source="c"]
// 4.cpp : Defines the entry point for the application.
//
#include "stdafx.h"
#include "4.h"
#include <GL/glee.h>
#include <GL/glfw.h>
#include <cmath>
using namespace std;

//Define
#define MAX_ITERATION 18
#define RES_X 1024
#define RES_Y 768
//Global Variables
bool running=true;
bool keyboardKeys[255]={false};
int g_width;
int g_height;
GLfloat onePix[3];
GLfloat screen[sizeof(GLfloat)*3*RES_X*RES_Y];

struct coordinate
{
GLdouble x;
GLdouble y;
}upperLeft, lowerRight;



void calcHSV(int iteration, GLdouble x, GLdouble y)
{
/*
GLint Hi;
GLdouble H, f, p, q, t, h, s, v;
GLdouble xn;
GLdouble mu;
mu=(GLdouble)iteration+1.0-log((double)log((double)(x*x+y*y)))/log(2.0);

//h=((GLdouble)iteration/(GLdouble)MAX_ITERATION)*360.0f;
h=mu*360.0;

xn=x/(double)pow((double)(x*x+y*y),(double)0.5);
s=acos(xn)/360.0;

v=pow((double)x*x+y*y,(double)0.5)/1.41421356238;
Hi=((int)floor(h/60.0))%6;
f=h/360.0-Hi;
p=v*(1.0-s);
q=v*(1.0-f*s);
t=v*(1.0-(1.0-f)*s);
switch(Hi)
{
case 0 : onePix[0]=v; onePix[1]=t; onePix[2]=p;break;
case 1 : onePix[0]=q; onePix[1]=v; onePix[2]=p;break;
case 2 : onePix[0]=p; onePix[1]=v; onePix[2]=t;break;
case 3 : onePix[0]=p; onePix[1]=q; onePix[2]=v;break;
case 4 : onePix[0]=t; onePix[1]=p; onePix[2]=v;break;
case 5 : onePix[0]=v; onePix[1]=p; onePix[2]=q;break;
}
H=0;
*/

GLdouble mu;
mu=(GLdouble)iteration+1.0-log((double)log((double)(x*x+y*y)))/log(2.0);
onePix[0]=mu;
onePix[1]=mu;
onePix[2]=mu;
//onePix[0]=1.0f-(GLdouble)iteration/(GLdouble)MAX_ITERATION;
//onePix[1]=1.0f-(GLdouble)iteration/(GLdouble)MAX_ITERATION;
//onePix[2]=1.0f-(GLdouble)iteration/(GLdouble)MAX_ITERATION;
}
void gambarUlang()
{
int i, j, iteration;
GLdouble x0, y0, x2, y2, x, y;
GLdouble step_x, step_y;
step_x=(lowerRight.x-upperLeft.x)/((GLdouble)g_width);
step_y=(upperLeft.y-lowerRight.y)/((GLdouble)g_height);
for(i=0; i<g_width; i++)
{
for(j=0; j<g_height; j++)
{
x0=((GLdouble)i)*step_x+upperLeft.x;
y0=upperLeft.y-((GLdouble)j)*step_y;
x=0;y=0;x2=0;y2=0;
iteration=0;
while((x2 + y2 < 4.0)&& (iteration<MAX_ITERATION))
{
y=2*x*y+y0;
x=x*x-y*y+x0;
x2=x*x;
y2=y*y;
iteration++;
}

if(iteration==MAX_ITERATION)
{
onePix[0]=0.0f;onePix[1]=0.0f;onePix[2]=0.0f;
}
else
calcHSV(iteration, x, y);

glWindowPos2i(i, j);
glDrawPixels(1, 1, GL_RGB, GL_FLOAT, onePix);

}
}

glReadPixels(0, 0, g_width, g_height, GL_RGB, GL_FLOAT, screen);
}

//Callbacks
void keyCallBack(int key, int state)
{
if(state==GLFW_PRESS)
keyboardKeys[key]=true;
else if(state==GLFW_RELEASE)
keyboardKeys[key]=false;
}

void WindowResizeCallback(int width, int height)
{
if (height==0)
height=1;


glViewport(0,0,width,height);

glMatrixMode(GL_PROJECTION);
glLoadIdentity();

gluOrtho2D(0.0f, (GLdouble) width, 0.0f, (GLdouble) height);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
g_width=width;
g_height=height;
gambarUlang();
}

void MousePosCallback(int x, int y)
{
}

void MouseButtonCallback(int button, int action)
{
}

int WindowsCloseCallback()
{
running=false;
return GL_TRUE;
}

void initGL()
{

}

void DrawGLScene()
{

glLoadIdentity();
glWindowPos2i(0, 0);
glDrawPixels(g_width, g_height, GL_RGB, GL_FLOAT, screen);
}

void keyboardProcess()
{
if(keyboardKeys[GLFW_KEY_ESC]==true) running=false;
if(keyboardKeys[GLFW_KEY_SPACE]==true) gambarUlang();
}

//Main
int APIENTRY _tWinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPTSTR lpCmdLine,
int nCmdShow)
{

glfwInit();

if(!glfwOpenWindow(800, 600, 8, 8, 8, 0, 0, 0, GLFW_WINDOW))
{
glfwTerminate();
return 0;
}

////////////////
upperLeft.x=-1.0;
upperLeft.y=1.0;
lowerRight.x=1.0;
lowerRight.y=-1.0;
////////////////
glfwSetWindowTitle("Mandelbrot Set");
glfwSetWindowSizeCallback(&WindowResizeCallback);
glfwSetKeyCallback(&keyCallBack);
glfwSetMousePosCallback(&MousePosCallback);
glfwSetMouseButtonCallback(&MouseButtonCallback);
glfwSetWindowCloseCallback(&WindowsCloseCallback);

initGL();
while(running)
{
DrawGLScene();
glfwSwapBuffers();
keyboardProcess();
}

glfwTerminate();
return 0;
}


Share this post


Link to post
Share on other sites
This one won't work either:

while((x2 + y2 < 4.0)&& (iteration<MAX_ITERATION))
{
y=2*x*y+y0;
x=x*x-y*y+x0;
x2=x*x;
y2=y*y;
iteration++;
}



Try this instead:

x = y = x2 = y2 = iteration = 0;
while((x2 + y2 < 4.0)&& (iteration++ < MAX_ITERATION))
{
x2 = x*x;
y2 = y*y;
y = 2*x*y + y0;
x = x2 - y2 + x0;
}


This also avoids a temporary by calculating the squares and reusing them for the calculation of the next x.

Share this post


Link to post
Share on other sites
BTW, my simple mandelbrot program is available at :
http://www.geocities.com/eon_strife/Mandelbrot.zip

Left-click -> to zoom
Right-click -> to cancel zoom
backspace -> to return to previous zoom state

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this