From 1b4f1b7592dfb3852c7652bcc91031e51ceb7605 Mon Sep 17 00:00:00 2001 From: orange Date: Sun, 16 Jun 2013 14:10:10 +0200 Subject: [PATCH] add unfinished multibrot --- .gitignore | 2 + Makefile | 13 +++- multibrot.c | 174 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 186 insertions(+), 3 deletions(-) create mode 100644 multibrot.c diff --git a/.gitignore b/.gitignore index 97503de..5245adb 100644 --- a/.gitignore +++ b/.gitignore @@ -11,3 +11,5 @@ bit-fuckery bit-fuckery2 ncurses-pong checkcheck +multibrot +multibrot.png diff --git a/Makefile b/Makefile index 3d8d3b0..8b48105 100644 --- a/Makefile +++ b/Makefile @@ -1,14 +1,15 @@ CFLAGS=-std=c99 -Wall -g -O2 INDENTOPTS=-kr --no-tabs --braces-on-func-def-line --indent-level2 -TARGETS=approximate-pi linked-list mandelbrot threads circular-buffer structs ncurses-pong bit-fuckery bit-fuckery2 checkcheck +TARGETS=approximate-pi linked-list mandelbrot threads circular-buffer structs ncurses-pong bit-fuckery bit-fuckery2 checkcheck multibrot +EXTRAS=mandelbrot.bmp multibrot.png .PHONY: all -all: $(TARGETS) +all: $(TARGETS) $(EXTRAS) .PHONY: clean clean: - rm -f $(TARGETS) *~ + rm -f $(TARGETS) $(EXTRAS) *~ .PHONY: indent indent: @@ -28,3 +29,9 @@ ncurses-pong: ncurses-pong.c checkcheck: checkcheck.c $(CC) $(CFLAGS) -o $@ $< -lcheck + +multibrot: multibrot.c + $(CC) $(CFLAGS) -o $@ $< -lm -lpng + +multibrot.png: multibrot + ./multibrot diff --git a/multibrot.c b/multibrot.c new file mode 100644 index 0000000..11d6554 --- /dev/null +++ b/multibrot.c @@ -0,0 +1,174 @@ +#include +#include +#include +#include +#include + +typedef uint32_t pixel_t; + +typedef struct { + pixel_t *pixels; + size_t width; + size_t height; +} bitmap_t; + +/* The maximum iteration count. */ +const int max_it = 170; + +/* Compute the out-coloring based on the iteration counter. */ +pixel_t outcolor(int it) { + /* return 0x00010001 * ((it * 0xff) / max_it); */ + return 0x00000001 * ((it * 0xff) / max_it); +} + +/* "Compute" the in-coloring. */ +pixel_t incolor() { + return 0x00000000; /* black */ +} + + +void drawmandelbrot(bitmap_t * mbrot) { + + for (size_t i = 0; i < mbrot->width * mbrot->height; i++) { + size_t y = i / mbrot->width; + size_t x = i % mbrot->width; + + float complex c = ((3.0f * x / mbrot->width) - 2.0f) + + I * ((2.0f * y / mbrot->height) - 1.0f); + + bool diverges = false; + float complex z = 0; + int it; + for (it = 1; it <= max_it; it++) { + /* z = z² + c */ + z = cpowf(z, 2) + c; + + /* If |z| ever gets greater than 2, it diverges. */ + if (cabsf(z) > 2) { + diverges = true; + break; + } + } + + uint32_t color; + if (diverges) { + color = outcolor(it); + } else { + color = incolor(); + } + + mbrot->pixels[i] = color; + } +} + + +/* Write "bitmap" to a PNG file specified by "path"; returns 0 on + success, non-zero on error. */ + +static int save_png_to_file(bitmap_t * bitmap, const char *path) { + FILE *fp; + + png_structp png_ptr = NULL; + png_infop info_ptr = NULL; + size_t x, y; + png_byte **row_pointers = NULL; + + /* "status" contains the return value of this function. At first it is set to + * a value which means 'failure'. When the routine has finished its work, it + * is set to a value which means 'success'. */ + int status = -1; + + /* FIXME The following number is set by trial and error only. I cannot see + * where it it is documented in the libpng manual. */ + int pixel_size = 3; + int depth = 8; + + fp = fopen(path, "wb"); + if (!fp) { + goto fopen_failed; + } + + png_ptr = + png_create_write_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL); + if (png_ptr == NULL) { + goto png_create_write_struct_failed; + } + + info_ptr = png_create_info_struct(png_ptr); + if (info_ptr == NULL) { + goto png_create_info_struct_failed; + } + + /*Set up error handling. */ + if (setjmp(png_jmpbuf(png_ptr))) { + goto png_failure; + } + + /* Set image attributes. */ + png_set_IHDR(png_ptr, + info_ptr, + bitmap->width, + bitmap->height, + depth, + PNG_COLOR_TYPE_RGB, + PNG_INTERLACE_NONE, + PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT); + + /* Initialize rows of PNG. */ + row_pointers = png_malloc(png_ptr, bitmap->height * sizeof(png_byte *)); + for (y = 0; y < bitmap->height; ++y) { + png_byte *row = + png_malloc(png_ptr, sizeof(uint8_t) * bitmap->width * pixel_size); + row_pointers[y] = row; + for (x = 0; x < bitmap->width; ++x) { + /* FIXME */ + pixel_t *pixel = bitmap->pixels + (y*bitmap->width + x); + *row++ = (*pixel & 0x00ff0000) >> 16; + *row++ = (*pixel & 0x0000ff00) >> 8; + *row++ = (*pixel & 0x000000ff); + } + } + + /* Write the image data to "fp". */ + png_init_io(png_ptr, fp); + png_set_rows(png_ptr, info_ptr, row_pointers); + png_write_png(png_ptr, info_ptr, PNG_TRANSFORM_IDENTITY, NULL); + + /* The routine has successfully written the file, so we set "status" to a + * value which indicates success. */ + status = 0; + + for (y = 0; y < bitmap->height; y++) { + png_free(png_ptr, row_pointers[y]); + } + png_free(png_ptr, row_pointers); + +png_failure: + /* FIXME info struct destroy? */ +png_create_info_struct_failed: + png_destroy_write_struct(&png_ptr, &info_ptr); +png_create_write_struct_failed: + fclose(fp); +fopen_failed: + return status; +} + +int main(int argc, char *argv[]) { + bitmap_t mbrot; + mbrot.width = 640; + mbrot.height = 480; /* FIXME calculate */ + mbrot.pixels = calloc(sizeof(pixel_t), mbrot.width * mbrot.height); + + /* Do the mandelbrot. */ + drawmandelbrot(&mbrot); + + /* Save PNG */ + char *file = "multibrot.png"; + if (save_png_to_file(&mbrot, file) != 0) { + fprintf(stderr, "Could not save PNG to %s.\n", file); + exit(1); + } + + /* Quit. */ + return 0; +}