Skip to content

Instantly share code, notes, and snippets.

@mgdm
Created February 25, 2015 21:20
Show Gist options
  • Save mgdm/31c8ceb27802d2ef6606 to your computer and use it in GitHub Desktop.
Save mgdm/31c8ceb27802d2ef6606 to your computer and use it in GitHub Desktop.
/* Compile with:
* gcc -O3 -o basic-mandelbrot basic-mandelbrot.c -lpng
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#include <png.h>
#define MAXITERS 4096
typedef struct _complex {
double real;
double imaginary;
} complex;
void mandelbrot(long dest[], double xmin, double xmax, double ymin, double ymax, long xpx, long ypx) {
long ni, ix, iy, m;
complex c;
complex original;
double dx, dy, tmp;
long *current;
dx = (xmax - xmin) / (double) xpx;
dy = (ymax - ymin) / (double) ypx;
current = dest;
for ( iy = 0; iy < ypx; iy++ ) {
for ( ix = 0; ix < xpx; ix += 1 ) {
c.real = xmin + ix * dx;
c.imaginary = ymax - iy * dy;
original.real = c.real;
original.imaginary = c.imaginary;
ni = 0;
while ( ni < MAXITERS && (c.real * c.real * c.imaginary * c.imaginary < 4.0 ) ) {
tmp = c.real * c.real - c.imaginary * c.imaginary + original.real;
c.imaginary = c.imaginary * c.real * 2 + original.imaginary;
c.real = tmp;
ni++;
}
*current++ = ni;
}
}
}
void render(long data[], unsigned char pixels[], long xpx, long ypx) {
long x, y, iterations, *iteration;
unsigned char *colour = pixels;
iteration = data;
for (y = 0; y < ypx; y++) {
for (x = 0; x < xpx; x++) {
iterations = *iteration;
if (iterations == MAXITERS) {
colour[0] = 0;
colour[1] = 0;
colour[2] = 0;
} else if (iterations < 64) {
colour[0] = iterations * 2;
colour[1] = 0;
colour[2] = 0;
} else if (iterations < 128) {
colour[0] = (((iterations - 64) * 128) / 126) + 128; /* 0x0080 to 0x00C0 */
colour[1] = 0;
colour[2] = 0;
} else if (iterations < 256) {
colour[0] = (((iterations - 128) * 62) / 127) + 193; /* 0x00C1 to 0x00FF */
colour[1] = 0;
colour[2] = 0;
} else if (iterations < 512) {
colour[0] = 255;
colour[1] = (((iterations - 256) * 62) / 255) + 1; /* 0x01FF to 0x3FFF */
colour[2] = 0;
} else if (iterations < 1024) {
colour[0] = 255;
colour[1] = (((iterations - 512) * 63) / 511) + 64; /* 0x40FF to 0x7FFF */
colour[2] = 0;
} else if (iterations < 2048) {
colour[0] = 255;
colour[1] = (((iterations - 1024) * 63) / 1023) + 128; /* 0x80FF to 0xBFFF */
colour[2] = 0;
} else if (iterations < 4096) {
colour[0] = 255;
colour[1] = (((iterations - 2048) * 63) / 2047) + 192; /* 0xC0FF to 0xFFFF */
colour[2] = 0;
} else {
colour[0] = 255;
colour[1] = 255;
colour[2] = 0;
}
colour += 4;
iteration++;
}
}
}
int write_png(const char *filename, unsigned char *pixels, long xpx, long ypx) {
int y;
unsigned char *buf_row = pixels;
png_structp png_ptr;
png_infop info_ptr;
png_byte **row_pointers = malloc(ypx * sizeof(png_byte *));
for(y = 0; y < ypx; y++) {
row_pointers[y] = (png_byte *) &pixels[xpx * y * 4];
}
if(filename == NULL) {
filename = "mb.png";
}
FILE *fp = fopen(filename, "wb");
if (fp == NULL) return -1;
/* Initialize the write struct. */
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (png_ptr == NULL) {
fclose(fp);
return -1;
}
/* Initialize the info struct. */
info_ptr = png_create_info_struct(png_ptr);
if (info_ptr == NULL) {
png_destroy_write_struct(&png_ptr, NULL);
fclose(fp);
return -1;
}
/* Set up error handling. */
if (setjmp(png_jmpbuf(png_ptr))) {
png_destroy_write_struct(&png_ptr, &info_ptr);
fclose(fp);
return -1;
}
png_init_io(png_ptr, fp);
/* Set image attributes. */
png_set_IHDR(png_ptr,
info_ptr,
xpx,
ypx,
8,
PNG_COLOR_TYPE_RGB_ALPHA,
PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT,
PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);
fclose(fp);
free(row_pointers);
return 0;
}
int main(int argc, char** argv) {
long *iterations;
unsigned char *pixels;
double xmin = -2.0;
double xmax = 1.0;
double ymin = -1.0;
double ymax = 1.0;
long xpx = 800;
long ypx = 512;
long pixelLen = xpx * ypx * 4 * sizeof(unsigned char);
float startTime, endTime;
iterations = calloc(xpx * ypx, sizeof(long));
pixels = malloc(pixelLen);
memset(pixels, 255, pixelLen);
startTime = (float) clock() / CLOCKS_PER_SEC;
mandelbrot(iterations, xmin, xmax, ymin, ymax, xpx, ypx);
endTime = (float) clock() / CLOCKS_PER_SEC;
printf("Data took %lf\n", endTime - startTime);
startTime = (float) clock() / CLOCKS_PER_SEC;
render(iterations, pixels, xpx, ypx);
endTime = (float) clock() / CLOCKS_PER_SEC;
printf("Render took %lf\n", endTime - startTime);
write_png("c.png", pixels, xpx, ypx);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment