My mandelbrot is wonky

I am trying to render a Mandelbrot but I can't get it stop leaning over. It's warped such that the further up the image you look the set leans over to the right more and it is lumpy too. I think it has to do with the scaling.

Here is the algorithm:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
int px = 0;
	for (int py = 0; py < HEIGHT; py++) {
		if (py % 50 == 0) cout << "Pixel x = " << px << ", Pixel y = " << py << endl;
		for (px = 0; px < WIDTH; px++) {
			double x0 = (3.5 / (double)(WIDTH - MIN_X)) * (double)px - 2.5;		// x0 = ((1 - -2.5) / WIDTH)x - 2.5
			double y0 = (2.0 / (double)(HEIGHT - MIN_Y)) * (double)py - 1.0;	// y0 = ((1 - -1) / HEIGHT)y - 1
			double x = 0.0, y = 0.0;

			int iteration = 0, maxIterations = 1000;
			while (x*x + y*y <= 4.0 && iteration < maxIterations) {
				double xtemp = x * x - y * y + x0;
				y = 2.0*x*y + y0;
				x = xtemp;
				iteration++;
			}
			if (iteration == maxIterations) plot(px, py, WIDTH, Color(), mandelbrotBMP);
			else plot(px, py, WIDTH, palette[iteration % NUM_COLORS], mandelbrotBMP);
		}
	}
Last edited on
I tried to re-use your code text, verbatim, but adapted it for a console print out.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80

#include <iostream>

const int WIDTH = 80;
const int HEIGHT = 30; 

char Color()
{
    return '#';
}

void plot(int px, int py, int width, char ch, char fractal[][WIDTH])
{
    fractal[py][px] = ch;
}

void print(char fractal[][WIDTH])
{
    for (int i = 0; i < HEIGHT; i++)
    {
        for (int j = 0; j < WIDTH; j++)
        {
            std::cout << fractal[i][j];
        }
        std::cout << '\n';
    }
}

int main()
{
    using std::cout;
    using std::endl;
    
    const int MIN_X = 0;
    const int MIN_Y = 0;   
    
    const int NUM_COLORS = 26;
    char palette[NUM_COLORS] = {};
    for (int i = 0; i < NUM_COLORS; i++)
    {
        palette[i] = 'A' + i;
    }
    
    char mandelbrotBMP[HEIGHT][WIDTH] = {};
    
    
    /////////////////////////
    //////////////////////////
    ///////////////////////////
 
    int px = 0;
	for (int py = 0; py < HEIGHT; py++) {
		if (py % 50 == 0)
                cout << "Pixel x = " << px << ", Pixel y = " << py << endl;
            
		for (px = 0; px < WIDTH; px++) {
			double x0 = (3.5 / (double)(WIDTH - MIN_X)) * (double)px - 2.5;		// x0 = ((1 - -2.5) / WIDTH)x - 2.5
			double y0 = (2.0 / (double)(HEIGHT - MIN_Y)) * (double)py - 1.0;	// y0 = ((1 - -1) / HEIGHT)y - 1
			double x = 0.0, y = 0.0;

			int iteration = 0, maxIterations = 1000;
			while (x*x + y*y <= 4.0 && iteration < maxIterations) {
				double xtemp = x * x - y * y + x0;
				y = 2.0*x*y + y0;
				x = xtemp;
				iteration++;
			}
			if (iteration == maxIterations)
                plot(px, py, WIDTH, Color(), mandelbrotBMP);
			else
                plot(px, py, WIDTH, palette[iteration % NUM_COLORS], mandelbrotBMP);
		}
	}
   
    ///////////////////////////
    //////////////////////////
    /////////////////////////
    
    print(mandelbrotBMP);
}


Pixel x = 0, Pixel y = 0
BBBBBBBBBBBBBBBBBBCCCCCCDDDDDDDDDDDDDDDDDDEEEEEEEFFFGJQJLLFEEEEEDDDDDCCCCCCCCCCC
BBBBBBBBBBBBBBBBBCCCCCDDDDDDDDDDDDDDDDDDEEEEEEEEFFFGHILRJHGFEEEEEDDDDDDCCCCCCCCC
BBBBBBBBBBBBBBBBCCCCDDDDDDDDDDDDDDDDDDEEEEEEEEFFFGHJONR#MKIFFFEEEEEDDDDDCCCCCCCC
BBBBBBBBBBBBBBBBCCCDDDDDDDDDDDDDDDDDEEEEEEEEFFFGGHILD####AJHGFFFFEEEDDDDDDCCCCCC
BBBBBBBBBBBBBBBCCCDDDDDDDDDDDDDDDDDEEEEEEEFFGGGHHIJLC####ZJIHGGGGFFEEDDDDDDCCCCC
BBBBBBBBBBBBBBBCDDDDDDDDDDDDDDDDDEEEEEEFFFGNN#KJMTOPSN##XPOLQKIHHKIFEDDDDDDDCCCC
BBBBBBBBBBBBBBCCDDDDDDDDDDDDDDDEEEEFFFFFGGHKO##PA############PLPPPTGFEDDDDDDDCCC
BBBBBBBBBBBBBBCDDDDDDDDDDDDDEEEFFFFFFFFGGHIJNE###################RIGFEEDDDDDDDCC
BBBBBBBBBBBBBCDDDDDDDDDDDDEEFGFFFFFFFGGGHDYXB###################VLIGFFEDDDDDDDCC
BBBBBBBBBBBBBDDDDDDDDEEEEFFGKIHHHHHHHHHHIKQC#####################UKJHFEEDDDDDDDC
BBBBBBBBBBBBBDDDDEEEEEEFFFGGKMLMJMOJKIIJKI#########################UHFEEDDDDDDDC
BBBBBBBBBBBBCDDEEEEEEEFFFFGHIKQHTV#XBRLLMF########################YJGFEEEDDDDDDD
BBBBBBBBBBBBDEEEEEEEFFFFFGHHMNY########PQ#########################YQGFEEEDDDDDDD
BBBBBBBBBBBBDEEEEEEFFGGGIRKKMY##########Z#########################PHFFEEEDDDDDDD
BBBBBBBBBBBBEFFFFHGGGHHHJLAZX###########W########################WIGFFEEEDDDDDDD
BBBBBBBBBBBB###################################################MMJHGFFEEEDDDDDDD
BBBBBBBBBBBBEFFFFHGGGHHHJLAZX###########W########################WIGFFEEEDDDDDDD
BBBBBBBBBBBBDEEEEEEFFGGGIRKKMY##########Z#########################PHFFEEEDDDDDDD
BBBBBBBBBBBBDEEEEEEEFFFFFGHHMNY########PQ#########################YQGFEEEDDDDDDD
BBBBBBBBBBBBCDDEEEEEEEFFFFGHIKQHTV#XBRLLMF########################YJGFEEEDDDDDDD
BBBBBBBBBBBBBDDDDEEEEEEFFFGGKMLMJMOJKIIJKI#########################UHFEEDDDDDDDC
BBBBBBBBBBBBBDDDDDDDDEEEEFFGKIHHHHHHHHHHIKQC#####################UKJHFEEDDDDDDDC
BBBBBBBBBBBBBCDDDDDDDDDDDDEEFGFFFFFFFGGGHDYXB###################VLIGFFEDDDDDDDCC
BBBBBBBBBBBBBBCDDDDDDDDDDDDDEEEFFFFFFFFGGHIJNE###################RIGFEEDDDDDDDCC
BBBBBBBBBBBBBBCCDDDDDDDDDDDDDDDEEEEFFFFFGGHKO##PA############PLPPPTGFEDDDDDDDCCC
BBBBBBBBBBBBBBBCDDDDDDDDDDDDDDDDDEEEEEEFFFGNN#KJMTOPSN##XPOLQKIHHKIFEDDDDDDDCCCC
BBBBBBBBBBBBBBBCCCDDDDDDDDDDDDDDDDDEEEEEEEFFGGGHHIJLC####ZJIHGGGGFFEEDDDDDDCCCCC
BBBBBBBBBBBBBBBBCCCDDDDDDDDDDDDDDDDDEEEEEEEEFFFGGHILD####AJHGFFFFEEEDDDDDDCCCCCC
BBBBBBBBBBBBBBBBCCCCDDDDDDDDDDDDDDDDDDEEEEEEEEFFFGHJONR#MKIFFFEEEEEDDDDDCCCCCCCC
BBBBBBBBBBBBBBBBBCCCCCDDDDDDDDDDDDDDDDDDEEEEEEEEFFFGHILRJHGFEEEEEDDDDDDCCCCCCCCC



This looks OK to me. Not skewed.

I think the problem lies elsewhere in your code. Perhaps you aren't accounting for that fact that in a BMP, 3x indices make one pixel, so your indexing code would look something like this:

pixels[3 * (py * WIDTH + px) + 0] = color_green;
pixels[3 * (py * WIDTH + px) + 1] = color_red;
pixels[3 * (py * WIDTH + px) + 2] = color_blue;[/code]
Assuming GRB.
Switch the order if you want RGB.
do * 4 if there's an alpha component.
Last edited on
I think the headers are fine, I can open the image after all. But the pixel data comes right after that and as far as I could gather from the Wikipedia page on BMP it's just the bytes for the color BGR (I am using 24 bit color so it is 3 bytes per pixel). My second guess was that I was doing the bitmap wrong somehow, I've never made one before.

Here is the plot function which actually writes the pixel data:

1
2
3
4
5
6
7
void plot(int pX, int pY, const int W, Color c, ofstream & ofs) {
	ofs << c.b << c.g << c.r;
	if (pX + 1 == W && (3 * W) % 4 != 0) {		// Padding for 4 byte alignment
		for (int i = 0; i < (3 * W) % 4; i++)
			ofs << (char)0;
	}
}
here are two bitmaps. test 1 is the first one that I made which didn't color the Mandelbrot black but it was a lot less skewed until I changed something I guess, I forget what I did but the other is one I just made using the code above.
https://1drv.ms/f/s!Amwf5vbrdJHfrBymsPufFrPYCtIw
Here’s a little library that will save you a lot of grief.

http://easybmp.sourceforge.net
Sheesh!!! 105MB for a picture.

The 4-byte alignment of BMP happens at the end of each row of pixels.
RGBRGBRGBPPP

> My second guess was that I was doing the bitmap wrong somehow, I've never made one before.
So that should have been your separate practice exercise.
Making sure you understood how to create say a 10x10 BMP file, before scaling up to 1000x1000.
+1 salem c, always start small, and when dealing with an issue, leave all possibilities open.

Personally, I would skip BMPs completely and just go to PNGs.
https://github.com/nothings/stb/blob/master/stb_image.h
PNG is still lossless, if that's what you're worried about.

Look at code here for an example of usage: https://github.com/SFML/SFML/blob/489482a630c5286e488ffc270c10562809056d8e/src/SFML/Graphics/ImageLoader.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
        if (extension == "bmp")
        {
            // BMP format
            if (stbi_write_bmp(filename.c_str(), size.x, size.y, 4, &pixels[0]))
                return true;
        }
        else if (extension == "tga")
        {
            // TGA format
            if (stbi_write_tga(filename.c_str(), size.x, size.y, 4, &pixels[0]))
                return true;
        }
        else if (extension == "png")
        {
            // PNG format
            if (stbi_write_png(filename.c_str(), size.x, size.y, 4, &pixels[0], 0))
                return true;
        }
        else if (extension == "jpg" || extension == "jpeg")
        {
            // JPG format
            if (stbi_write_jpg(filename.c_str(), size.x, size.y, 4, &pixels[0], 90))
                return true;
        }
Last edited on
Ok, I figured it out.
Sheesh!!! 105MB for a picture.

LOL. It's an 8k picture of the fractal.

Making sure you understood how to create say a 10x10 BMP file, before scaling up to 1000x1000.

Yeah, I thought about doing this but I dismissed it too quickly when I got the bitmap to open. I wrote a program that makes a bitmap the same way I did in the Mandelbrot program and I found out the problem was with the padding. It was actually quite a small change but it was a big problem. I simply had to change the number of times the padding for loop ran. Before it was outputting the remainder of the row bytes (3 * Width) divide 4, when it should be 4 minus that number to get the number of bytes missing to make it divisible by 4 🤷‍♂️.

I guess it wasn't that dumb though because I thought I was scaling the coordinates wrong but I mislead myself. Thanks guys!

1
2
3
4
5
6
7
void plot(int pX, int pY, const int W, Color c, ofstream & ofs) {
	ofs << c.b << c.g << c.r;
	if (pX + 1 == W && (3 * W) % 4 != 0) {		// Padding for 4 byte alignment
		for (int i = 0; i < 4 - ((3 * W) % 4); i++) // <- corrected line
			ofs << (char)0;
	}
}
Topic archived. No new replies allowed.