add img_{left,right,top,bottom} and img_{x,y}_step to struct render and change render_mandelbrot/slices to use them
committer: Tero Marttila <terom@fixme.fi>
#include <stdlib.h>
#include <assert.h>
#include "common.h"
#include "render_struct.h"
#include "render_slices_struct.h"
#include "render_slices.h"
void render_slices_free (struct render_slices *ctx) {
render_slices_deinit(ctx);
if (ctx->owned_by_me)
free(ctx);
}
void render_slices_deinit (struct render_slices *ctx) {
if (ctx->rowbuf) {
free(ctx->rowbuf);
ctx->rowbuf = NULL;
}
render_png_deinit(&ctx->png_info);
}
#define HALF(a, b) (( a + b) / 2)
int render_slices_init (struct render_slices *ctx, struct render *render) {
// initialize the slices
// for now, just split it in half into two render_ts
ctx->slices[0].info.index = 0;
ctx->slices[0].info.render_info = &ctx->slices[0].render_info;
ctx->slices[0].self = ctx;
ctx->slices[0].row_offset = 0;
ctx->slices[1].info.index = 1;
ctx->slices[1].info.render_info = &ctx->slices[1].render_info;
ctx->slices[1].self = ctx;
ctx->slices[1].row_offset = render->img_w / 2;
ctx->num_slices = 2;
ctx->render_row = 0;
ctx->done_row = -1;
assert(RENDER_SLICES_MAX >= 2);
// should probably use memcpy instead...
if (
render_init (&ctx->slices[0].render_info, RENDER_RAW)
|| render_init (&ctx->slices[1].render_info, RENDER_RAW)
|| render_set_size (&ctx->slices[0].render_info, render->img_w, render->img_h)
|| render_set_size (&ctx->slices[1].render_info, render->img_w, render->img_h)
|| render_region_raw (&ctx->slices[0].render_info, render->x1, render->y1, render->x2, render->y2)
|| render_region_raw (&ctx->slices[1].render_info, render->x1, render->y1, render->x2, render->y2)
)
ERROR("render_{init,set_size,set_region_raw}");
// set the offsets
ctx->slices[0].render_info.img_left = 0;
ctx->slices[0].render_info.img_right = render->img_w / 2;
ctx->slices[1].render_info.img_left = render->img_w / 2;
ctx->slices[1].render_info.img_right = render->img_w;
// allocate the rowbuf
if (!(ctx->rowbuf = malloc(render->img_w * 2)))
ERROR("malloc");
// update the slice_buf pointers
ctx->rows[0] = ctx->rowbuf;
ctx->rows[1] = ctx->rowbuf + render->img_w;
ctx->slices[0].info.render_buf = ctx->rows[ctx->render_row] + ctx->slices[0].row_offset;
ctx->slices[1].info.render_buf = ctx->rows[ctx->render_row] + ctx->slices[1].row_offset;
// png info
if (render_png_init(&ctx->png_info, render))
ERROR("render_png_init");
// great success!
return 0;
error:
render_slices_deinit(ctx);
return -1;
}
struct render_slices *render_slices_alloc (struct render *render) {
struct render_slices *ctx = NULL;
// allocate it
if (!(ctx = calloc(1, sizeof(*ctx))))
ERROR("calloc");
// mark it for free()ing
ctx->owned_by_me = 1;
// initialize it
if (render_slices_init(ctx, render))
goto error;
return ctx;
error :
render_slices_free(ctx);
return NULL;
}
int render_slices_get_count (struct render_slices *ctx) {
return ctx->num_slices;
}
struct render_slice_info *render_slices_get_slice_info (struct render_slices *ctx, int index) {
assert(index >= 0 && index < ctx->num_slices);
return &ctx->slices[index].info;
}
int render_slices_segment_done (struct render_slices *ctx, int index) {
assert(index >= 0 && index < ctx->num_slices);
assert(ctx->render_row >= 0);
assert(ctx->segments_done >= 0 && ctx->segments_done < ctx->num_slices);
// our return status
int i, status = 0;
// is this row now complete?
if (++ctx->segments_done == ctx->num_slices) {
// the row is complete
ctx->segments_done = 0;
// once we fill up a row we can always call process_row
status |= SLICE_PROCESS_ROW;
// is the other row already rendered?
if (ctx->done_row < 0) {
// yes, point the done_row at this row, point the render buffers to the unused row
ctx->done_row = ctx->render_row;
ctx->render_row = (ctx->render_row == 0 ? 1 : 0);
// can now continue rendering as well as call process_row
status |= SLICE_CONTINUE;
// update the remaining render buffers
for (i = 0; i < ctx->num_slices; i++) {
ctx->slices[i].info.render_buf = ctx->rows[ctx->render_row] + ctx->slices[i].row_offset;
}
} else {
// cannot continue rendering, need to have process_row complete first
ctx->render_row = -1;
}
} else {
// the row is not complete, do not render the next segment, do not call process_row
}
return status;
}
int render_slices_process_row (struct render_slices *ctx) {
assert(ctx->done_row >= 0);
int i;
// pass the data to render_png, this results in calls to _render_multi_png_data
if (render_png_row(&ctx->png_info, ctx->rows[ctx->done_row]))
ERROR("render_png_row");
// is the other row still in the process of being assembled?
if (ctx->render_row == -1) {
// no, both rows were full
ctx->render_row = ctx->done_row;
ctx->done_row = (ctx->done_row == 0 ? 1 : 0);
// update the remaining render buffers
for (i = 0; i < ctx->num_slices; i++) {
ctx->slices[i].info.render_buf = ctx->rows[ctx->render_row] + ctx->slices[i].row_offset;
}
// you can call me again, but also segment_done
return SLICE_PROCESS_ROW | SLICE_CONTINUE;
} else {
// yes, so that still needs to be finished
ctx->done_row = -1;
if (ctx->segments_done == 0) {
// that row is empty, then we can continue
return SLICE_CONTINUE;
} else {
// that row is partially built, so some segment is still on the way - don't resume the other slices until that's arrived!
return 0;
}
}
error:
// user needs to deinit/free us
return -1;
}
int render_slices_done (struct render_slices *ctx) {
// finish off render_png
if (render_png_done(&ctx->png_info))
goto error;
return 0;
error:
render_slices_free(ctx);
return -1;
}