Created
February 25, 2015 21:20
-
-
Save mgdm/31c8ceb27802d2ef6606 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* 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