--- a/Makefile Fri May 30 14:24:23 2008 +0300
+++ b/Makefile Sat May 31 02:22:27 2008 +0300
@@ -1,9 +1,12 @@
LDFLAGS = -L/usr/local/lib -levent -lpng
CFLAGS = -Wall -g
-render_file: mandelbrot.o common.o
+OBJS = common.o mandelbrot.o render.o
+HEADERS = common.h mandelbrot.h render.h
-web_main: mandelbrot.o common.o
+render_file: ${OBJS}
-render_node: mandelbrot.o common.o
+web_main: ${OBJS}
+render_node: ${OBJS}
+
--- a/mandelbrot.c Fri May 30 14:24:23 2008 +0300
+++ b/mandelbrot.c Sat May 31 02:22:27 2008 +0300
@@ -1,39 +1,23 @@
-#include <string.h>
#include <stdlib.h>
#include <time.h>
-#include <arpa/inet.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 render_ctx_set (struct render_ctx *ctx, render_ctx_write_cb write_fn, render_ctx_flush_cb flush_fn, void *arg) {
- memset(ctx, 0, sizeof(*ctx));
-
- ctx->write_fn = write_fn;
- ctx->flush_fn = flush_fn;
- ctx->cb_arg = arg;
-}
-
-void render_ctx_stream (struct render_ctx *ctx, FILE *fh) {
- memset(ctx, 0, sizeof(*ctx));
-
- ctx->stream = fh;
-}
-
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->write_fn)
- switch (ctx->write_fn(data, length, ctx->cb_arg)) {
+ if (ctx->io_write_fn)
+ switch (ctx->io_write_fn(data, length, ctx->io_cb_arg)) {
case RENDER_CB_ERR :
- ctx->_error = 1;
+ ctx->io_error = 1;
break;
case RENDER_CB_OK :
@@ -45,10 +29,10 @@
void user_flush_data(png_structp png_ptr) {
struct render_ctx *ctx = (struct render_ctx *) png_get_io_ptr(png_ptr);
- if (ctx->flush_fn)
- switch (ctx->flush_fn(ctx->cb_arg)) {
+ if (ctx->io_flush_fn)
+ switch (ctx->io_flush_fn(ctx->io_cb_arg)) {
case RENDER_CB_ERR :
- ctx->_error = 1;
+ ctx->io_error = 1;
break;
case RENDER_CB_OK :
@@ -57,94 +41,70 @@
}
}
-int _validate_render (
- u_int32_t img_w, u_int32_t img_h,
- double x1, double y1, double x2, double y2
-) {
- if (
- (img_w == 0 || img_h == 0) // zero-size image
- || (x1 >= x2 || y1 >= y2) // invalid region
- )
- return MANDELBROT_ERR_INVALID;
- else
- return MANDELBROT_OK;
-}
+int mandelbrot_render (render_t *ctx) {
+ // libpng handles
+ png_structp png_ptr = NULL;
+ png_infop info_ptr = NULL;
-
-int mandelbrot_render_region (
- struct render_ctx *ctx,
- u_int32_t img_w, u_int32_t img_h,
- double x1, double y1, double x2, double y2
-) {
+ // 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;
- // validate!
- int valid = _validate_render(img_w, img_h, x1, y1, x2, y2);
-
- if (valid != MANDELBROT_OK)
- return valid;
-
// clear out any potential error in ctx
- ctx->_error = 0;
+ ctx->io_error = 0;
// calcluate the scale factors
- w_scale = img_w/absdelta(x1, x2);
- h_scale = img_h/absdelta(y1, y2);
+ 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(img_w);
+ row = (u_int8_t *) malloc(ctx->img_w);
if (!row)
- return MANDELBROT_ERR_MALLOC;
-
- // libpng initialization
- png_structp png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
-
- if (!png_ptr) {
- free(row);
- return MANDELBROT_ERR_PNG_INIT;
- }
-
- png_infop info_ptr = png_create_info_struct(png_ptr);
-
- if (!info_ptr) {
- png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
- free(row);
- return MANDELBROT_ERR_PNG_INIT;
- }
+ goto error;
- if (ctx->stream) {
- // use normal libpng I/O
- png_init_io(png_ptr, ctx->stream);
- } else {
- // setup our custom I/O callbacks
- png_set_write_fn(png_ptr, ctx, &user_write_data, &user_flush_data);
- }
+ // PNG or not?
+ if (ctx->mode == RENDER_PNG) {
+ // libpng initialization
+ png_ptr = png_create_write_struct (PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
- // some PNG metadata
- png_set_IHDR(png_ptr, info_ptr, img_w, img_h, 8, PNG_COLOR_TYPE_GRAY, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
+ if (!png_ptr)
+ goto error;
- // write out the PNG header
- png_write_info(png_ptr, info_ptr);
+ info_ptr = png_create_info_struct(png_ptr);
- // possible error return
- if (ctx->_error) {
- free(row);
- png_destroy_write_struct(&png_ptr, &info_ptr);
- return MANDELBROT_ERR_CB;
+ if (!info_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 < img_h; img_y++) {
+ for (img_y=0; img_y < ctx->img_h; img_y++) {
// render the current row
- for (img_x=0; img_x < img_w; img_x++) {
+ for (img_x=0; img_x < ctx->img_w; img_x++) {
x = 0;
y = 0;
- x0 = img_x/w_scale + x1;
- y0 = img_y/h_scale + y1;
+ 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) {
@@ -160,40 +120,53 @@
row[img_x] = iter;
}
- // write the raw pixels to libpng
- png_write_row(png_ptr, row);
-
- // check for user errors return
- if (ctx->_error) {
- free(row);
- png_destroy_write_struct(&png_ptr, &info_ptr);
- return MANDELBROT_ERR_CB;
+ 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;
+ }
}
}
-
- // finished writing
- png_write_end(png_ptr, info_ptr);
+
+ 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);
+ free(row); row = NULL;
// check for user errors return
- if (ctx->_error)
- return MANDELBROT_ERR_CB;
+ 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_region_timed (
- struct render_ctx *ctx,
- u_int32_t img_w, u_int32_t img_h,
- double x1, double y1, double x2, double y2,
- double *duration
-) {
+int mandelbrot_render_timed (render_t *ctx, double *duration) {
clock_t t1 = clock();
- int ret = mandelbrot_render_region(ctx, img_w, img_h, x1, y1, x2, y2);
+ int ret = mandelbrot_render(ctx);
clock_t t2 = clock();
*duration = ((double)(t2 - t1))/CLOCKS_PER_SEC;
@@ -201,24 +174,3 @@
return ret;
}
-int render_cmd_set (
- struct render_cmd *cmd,
- u_int32_t img_w, u_int32_t img_h,
- double x1, double y1, double x2, double y2
-) {
- // validate!
- int valid = _validate_render(img_w, img_h, x1, y1, x2, y2);
-
- if (valid != MANDELBROT_OK)
- return valid;
-
- cmd->img_w = htonl(img_w);
- cmd->img_h = htonl(img_h);
- cmd->x1 = x1;
- cmd->y1 = y1;
- cmd->x2 = x2;
- cmd->y2 = y2;
-
- return MANDELBROT_OK;
-}
-
--- a/mandelbrot.h Fri May 30 14:24:23 2008 +0300
+++ b/mandelbrot.h Sat May 31 02:22:27 2008 +0300
@@ -1,117 +1,18 @@
-/*
- * code to render a mandelbrot
- */
-
-#include <sys/types.h>
-
-typedef int (*render_ctx_write_cb)(const unsigned char *data, size_t length, void *arg);
-typedef int (*render_ctx_flush_cb)(void *arg);
-
-#define RENDER_CB_OK 0
-#define RENDER_CB_ERR 1
-
-struct render_ctx {
- /*
- * If we just use normal FILE* stream operations
- */
- FILE *stream;
-
- /*
- * These callback functions are used to handle the PNG data as it's rendered.
- *
- * If they return RENDER_CB_OK, all is fine and rendering will continue normally.
- * If they return RENDER_CB_ERR, rendering will abort.
- */
-
- // called to handle the output data
- render_ctx_write_cb write_fn;
-
- // called when the output data should be flushed - can be safely ignored if not needed
- render_ctx_flush_cb flush_fn;
-
- // the callback argument
- void *cb_arg;
-
- // error status
- int _error;
-};
+#include "render.h"
/*
- * initialize the given struct render_ctx
+ * the mandelbrot-rendering algorithm
*/
-void render_ctx_set (struct render_ctx *ctx, render_ctx_write_cb write_fn, render_ctx_flush_cb flush_fn, void *arg);
-void render_ctx_stream (struct render_ctx *ctx, FILE *fh);
/*
* return codes for mandelbrot_render
*/
#define MANDELBROT_OK 0
-#define MANDELBROT_ERR_MALLOC 1
-#define MANDELBROT_ERR_PNG_INIT 2
-#define MANDELBROT_ERR_CB 3
-#define MANDELBROT_ERR_INVALID 4
-
-/*
- * render an <img_w>x<img_h> PNG image of the mandelbrot region bounded by (x1, y1) -> (x2, y2)
- */
-int mandelbrot_render_region (
- struct render_ctx *ctx,
- u_int32_t img_w, u_int32_t img_h,
- double x1, double y1, double x2, double y2
-);
-
-int mandelbrot_render_region_timed (
- struct render_ctx *ctx,
- u_int32_t img_w, u_int32_t img_h,
- double x1, double y1, double x2, double y2,
- double *duration
-);
+#define MANDELBROT_ERR 1
/*
- * remote rendering
+ * Render the image specified by the given render context
*/
-
-#pragma pack(push)
-#pragma pack(1)
-
-struct render_cmd {
- u_int32_t img_w;
- u_int32_t img_h;
-
- double x1;
- double y1;
- double x2;
- double y2;
-};
-
-#pragma pack(pop)
-
-#define RENDER_PORT 6159
-#define RENDER_CMD_SIZE sizeof(struct render_cmd)
+int mandelbrot_render (render_t *ctx);
+int mandelbrot_render_timed (render_t *ctx, double *duration);
-/*
- * build the command to send for remote rendering
- */
-int render_cmd_set (
- struct render_cmd *cmd,
- u_int32_t img_w, u_int32_t img_h,
- double x1, double y1, double x2, double y2
-);
-
-/*
- * The "full" mandelbrot region
- */
-#define REGION_X1 -2.0
-#define REGION_Y1 -1.5
-#define REGION_X2 1.0
-#define REGION_Y2 1.5
-
-#define mandelbrot_render_full(ctx, img_w, img_h) \
- mandelbrot_render_region(ctx, img_w, img_h, REGION_X1, REGION_Y1, REGION_X2, REGION_Y2)
-
-#define mandelbrot_render_full_timed(ctx, img_w, img_h, duration) \
- mandelbrot_render_region_timed(ctx, img_w, img_h, REGION_X1, REGION_Y1, REGION_X2, REGION_Y2, duration)
-
-#define render_cmd_set_full(cmd, img_w, img_h) \
- render_cmd_set(cmd, img_w, img_h, REGION_X1, REGION_Y1, REGION_X2, REGION_Y2)
-
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/render.c Sat May 31 02:22:27 2008 +0300
@@ -0,0 +1,77 @@
+#include <string.h>
+#include <arpa/inet.h>
+
+#include "render.h"
+
+int render_init (render_t *ctx, int mode) {
+ memset(ctx, 0, sizeof(*ctx));
+
+ return render_set_mode(ctx, mode);
+}
+
+int render_set_mode (render_t *ctx, int mode) {
+ if (mode != RENDER_RAW && mode != RENDER_PNG)
+ return RENDER_ERR;
+
+ ctx->mode = mode;
+
+ return RENDER_OK;
+}
+
+int render_set_size (render_t *ctx, u_int32_t img_w, u_int32_t img_h) {
+ if (img_w == 0 || img_h == 0)
+ return RENDER_ERR;
+
+ ctx->img_w = img_w;
+ ctx->img_h = img_h;
+
+ return RENDER_OK;
+}
+
+int render_region_full (render_t *ctx) {
+ return render_region_raw(ctx, REGION_X1, REGION_Y1, REGION_X2, REGION_Y2);
+}
+
+int render_region_raw (render_t *ctx, double x1, double y1, double x2, double y2) {
+ if ((x1 >= x2) || (y1 >= y2))
+ return RENDER_ERR;
+
+ ctx->x1 = x1;
+ ctx->y1 = y1;
+ ctx->x2 = x2;
+ ctx->y2 = y2;
+
+ return RENDER_OK;
+}
+
+int render_io_custom (render_t *ctx, render_ctx_write_cb write_fn, render_ctx_flush_cb flush_fn, void *arg) {
+ if (!write_fn)
+ return RENDER_ERR;
+
+ ctx->io_write_fn = write_fn;
+ ctx->io_flush_fn = flush_fn;
+ ctx->io_cb_arg = arg;
+
+ return RENDER_OK;
+}
+
+int render_io_stream (render_t *ctx, FILE *fh) {
+ if (!fh)
+ return RENDER_ERR;
+
+ ctx->io_stream = fh;
+
+ return RENDER_OK;
+}
+
+int render_cmd_build (render_t *ctx, struct render_cmd *cmd) {
+ cmd->img_w = htonl(ctx->img_w);
+ cmd->img_h = htonl(ctx->img_h);
+ cmd->x1 = ctx->x1;
+ cmd->y1 = ctx->y1;
+ cmd->x2 = ctx->x2;
+ cmd->y2 = ctx->y2;
+
+ return RENDER_OK;
+}
+
--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/render.h Sat May 31 02:22:27 2008 +0300
@@ -0,0 +1,120 @@
+#ifndef RENDER_H
+#define RENDER_H
+
+#include <sys/types.h>
+#include <stdio.h>
+
+/*
+ * This module provides various ways to render mandelbrot images in various formats
+ */
+
+// custom I/O callbacks function signatures
+typedef int (*render_ctx_write_cb)(const unsigned char *data, size_t length, void *arg);
+typedef int (*render_ctx_flush_cb)(void *arg);
+
+// callback return codes
+#define RENDER_CB_OK 0
+#define RENDER_CB_ERR 1
+
+#define RENDER_OK 0
+#define RENDER_ERR 1
+
+// output types
+enum {
+ RENDER_RAW, // raw pixel data
+ RENDER_PNG, // a png image
+};
+
+typedef struct render_ctx {
+/* render mode */
+ int mode;
+
+/* image size */
+ u_int32_t img_w;
+ u_int32_t img_h;
+
+/* mandelbrot region */
+ double x1;
+ double y1;
+ double x2;
+ double y2;
+
+/* I/O parameters */
+ // if this is non-NULL, use libpng's normal IO on this stream
+ FILE *io_stream;
+
+ // called to handle the output data
+ render_ctx_write_cb io_write_fn;
+
+ // called when the output data should be flushed - can be safely ignored if not needed
+ render_ctx_flush_cb io_flush_fn;
+
+ // the callback argument
+ void *io_cb_arg;
+
+ // error status
+ int io_error;
+} render_t;
+
+/*
+ * Clear out the render context and set the mode
+ */
+int render_init (render_t *ctx, int mode);
+
+/*
+ * What kind of image to render, PNG or RAW?
+ */
+int render_set_mode (render_t *ctx, int mode);
+
+/*
+ * What size of image to render
+ */
+int render_set_size (render_t *ctx, u_int32_t img_w, u_int32_t img_h);
+
+/*
+ * Select what region to render
+ */
+
+// the "full" mandelbrot region
+#define REGION_X1 -2.0
+#define REGION_Y1 -1.5
+#define REGION_X2 1.0
+#define REGION_Y2 1.5
+
+int render_region_full (render_t *ctx);
+int render_region_raw (render_t *ctx, double x1, double y1, double x2, double y2);
+
+/*
+ * How to handle the I/O
+ */
+int render_io_custom (render_t *ctx, render_ctx_write_cb write_fn, render_ctx_flush_cb flush_fn, void *arg);
+int render_io_stream (render_t *ctx, FILE *fh);
+
+/*
+ * Remote rendering
+ */
+
+#pragma pack(push)
+#pragma pack(1)
+
+struct render_cmd {
+ u_int32_t img_w;
+ u_int32_t img_h;
+
+ double x1;
+ double y1;
+ double x2;
+ double y2;
+};
+
+#pragma pack(pop)
+
+#define RENDER_PORT 6159
+#define RENDER_CMD_SIZE sizeof(struct render_cmd)
+
+/*
+ * build the command to send for remote rendering
+ */
+int render_cmd_build (render_t *ctx, struct render_cmd *cmd);
+
+#endif /* RENDER_H */
--- a/render_file.c Fri May 30 14:24:23 2008 +0300
+++ b/render_file.c Sat May 31 02:22:27 2008 +0300
@@ -11,24 +11,17 @@
static int verbose;
-int file_write (const unsigned char *data, size_t length, void *arg) {
- size_t ret = fwrite(data, length, 1, (FILE *) arg);
-
- return (ret == 1) ? RENDER_CB_OK : RENDER_CB_ERR;
-}
+void render_local (int img_w, int img_h, FILE *output) {
+ render_t ctx;
-void render_local (int img_w, int img_h, FILE *output) {
- struct render_ctx ctx;
-
- render_ctx_set(&ctx, &file_write, NULL, output);
+ render_init(&ctx, RENDER_PNG);
+ render_set_size(&ctx, img_w, img_h);
+ render_region_full(&ctx);
+ render_io_stream(&ctx, output);
double duration;
- if (mandelbrot_render_full_timed(
- &ctx,
- img_w, img_h,
- &duration
- ) != MANDELBROT_OK)
+ if (mandelbrot_render_timed(&ctx, &duration) != MANDELBROT_OK)
err_exit("mandelbrot_render_region failed");
if (verbose)
@@ -36,11 +29,15 @@
}
void render_remote (int img_w, int img_h, FILE *output, FILE *remote) {
+ render_t ctx;
struct render_cmd cmd;
- if (render_cmd_set_full(&cmd, img_w, img_h) != MANDELBROT_OK) {
+ render_init(&ctx, RENDER_PNG);
+ render_set_size(&ctx, img_w, img_h);
+ render_region_full(&ctx);
+
+ if (render_cmd_build(&ctx, &cmd))
err_exit("mandelbrot_render_remote failed");
- }
int ret = fwrite((void *) &cmd, sizeof(cmd), 1, remote);
--- a/render_node.c Fri May 30 14:24:23 2008 +0300
+++ b/render_node.c Sat May 31 02:22:27 2008 +0300
@@ -7,36 +7,37 @@
#include "mandelbrot.h"
#include "common.h"
-int read_int (FILE *fh, u_int32_t *i) {
- printf("read_int: fread(%p, %zu, 1, %p)... ", i, sizeof(*i), fh);
- fflush(stdout);
- int ret = fread(i, sizeof(*i), 1, fh);
- printf("ok: %d\n", ret);
+int my_fread(FILE *fh, void *ptr, size_t size) {
+ int ret = fread(ptr, size, 1, fh);
if (ret == 0) {
error("EOF");
return 0;
+
} else if (ret != 1) {
- perror("read_int");
+ perror("fread");
return 0;
}
+ return 1;
+}
+
+int read_byte (FILE *fh, u_int8_t *byte) {
+ return my_fread(fh, byte, sizeof(*byte));
+}
+
+int read_int (FILE *fh, u_int32_t *i) {
+ if (!my_fread(fh, i, sizeof(*i)))
+ return 0;
+
*i = ntohl(*i);
- printf("read_int: %i\n", *i);
-
return 1;
}
int read_double (FILE *fh, double *dbl) {
- int ret = fread(dbl, sizeof(*dbl), 1, fh);
-
- if (ret != 1) {
- perror("read_double");
+ if (!my_fread(fh, dbl, sizeof(*dbl)))
return 0;
- }
-
- printf("read_double: %f\n", *dbl);
return 1;
}
@@ -46,10 +47,12 @@
FILE *fh = fdopen(sock, "r+");
// read the parameters
+ u_int8_t mode;
u_int32_t img_w, img_h;
double x1, y1, x2, y2;
if (
+ !read_byte(fh, &mode) ||
!read_int(fh, &img_w) ||
!read_int(fh, &img_h) ||
!read_double(fh, &x1) ||