updated code to use libevent svn (with custom modifications, need to create a git repo for that)
committer: Tero Marttila <terom@fixme.fi>
#include <stdlib.h>
#include <time.h>
#include <png.h>
#include "render.h"
#include "mandelbrot.h"
#include "common.h"
#define DETAIL 255
#define absdelta(a, b) (a>b ? a-b : b-a)
void user_write_data(png_structp png_ptr, png_bytep data, png_size_t length) {
struct render_ctx *ctx = (struct render_ctx *) png_get_io_ptr(png_ptr);
if (ctx->io_write_fn)
switch (ctx->io_write_fn(data, length, ctx->io_cb_arg)) {
case RENDER_CB_ERR :
ctx->io_error = 1;
break;
case RENDER_CB_OK :
// great!
break;
}
}
void user_flush_data(png_structp png_ptr) {
struct render_ctx *ctx = (struct render_ctx *) png_get_io_ptr(png_ptr);
if (ctx->io_flush_fn)
switch (ctx->io_flush_fn(ctx->io_cb_arg)) {
case RENDER_CB_ERR :
ctx->io_error = 1;
break;
case RENDER_CB_OK :
// great!
break;
}
}
int mandelbrot_render (render_t *ctx) {
// libpng handles
png_structp png_ptr = NULL;
png_infop info_ptr = NULL;
// render algorithm vars
u_int32_t img_x, img_y;
double x0, y0, x, y, _x, _y, w_scale, h_scale;
u_int8_t iter;
u_int8_t *row;
// clear out any potential error in ctx
ctx->io_error = 0;
// calcluate the scale factors
w_scale = ctx->img_w/absdelta(ctx->x1, ctx->x2);
h_scale = ctx->img_h/absdelta(ctx->y1, ctx->y2);
// malloc the memory used to render each row
row = (u_int8_t *) malloc(ctx->img_w);
if (!row)
goto error;
// PNG or not?
if (ctx->mode == RENDER_PNG) {
// libpng initialization
png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr)
goto error;
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr)
goto error;
// libpng error handling
if (setjmp(png_jmpbuf(png_ptr))) {
goto error;
}
if (ctx->io_stream) {
// use normal libpng I/O
png_init_io(png_ptr, ctx->io_stream);
} else {
// setup our custom I/O callbacks
png_set_write_fn(png_ptr, ctx, &user_write_data, &user_flush_data);
}
// some PNG metadata
png_set_IHDR(png_ptr, info_ptr, ctx->img_w, ctx->img_h, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
// write out the PNG header
png_write_info(png_ptr, info_ptr);
// possible error return
if (ctx->io_error)
goto error;
}
// start rendering!
for (img_y=0; img_y < ctx->img_h; img_y++) {
// render the current row
for (img_x=0; img_x < ctx->img_w; img_x++) {
x = 0;
y = 0;
x0 = img_x/w_scale + ctx->x1;
y0 = img_y/h_scale + ctx->y1;
iter = DETAIL;
while (x*x + y*y < (2*2) && iter > 0) {
_x = x*x - y*y + x0;
_y = 2*x*y + y0;
x = _x;
y = _y;
iter--;
}
row[img_x] = iter;
}
if (ctx->mode == RENDER_PNG) {
// write the raw pixels to libpng
png_write_row(png_ptr, row);
// check for user errors return
if (ctx->io_error)
goto error;
} else {
// pass on the pixels to the io callback
if (ctx->io_write_fn(row, ctx->img_w, ctx->io_cb_arg) == RENDER_CB_ERR) {
ctx->io_error = 1;
goto error;
}
}
}
if (ctx->mode == RENDER_PNG) {
// finished writing
png_write_end(png_ptr, info_ptr);
}
// clean up
png_destroy_write_struct(&png_ptr, &info_ptr);
free(row); row = NULL;
// check for user errors return
if (ctx->io_error)
goto error;
// return succesfully
return MANDELBROT_OK;
error:
if (png_ptr || info_ptr)
png_destroy_write_struct(&png_ptr, &info_ptr);
if (row)
free(row);
row = NULL;
return MANDELBROT_ERR;
}
int mandelbrot_render_timed (render_t *ctx, double *duration) {
clock_t t1 = clock();
int ret = mandelbrot_render(ctx);
clock_t t2 = clock();
*duration = ((double)(t2 - t1))/CLOCKS_PER_SEC;
return ret;
}