# HG changeset patch # User Tero Marttila # Date 1262045487 -7200 # Node ID 3576e00388fd151abe17e932b7829903f9fc85c3 # Parent eb2a1472f08476e02c49075dfa0044779693373e draw clipped tiles by filling in a zeros for the background pixels diff -r eb2a1472f084 -r 3576e00388fd src/lib/cache.c --- a/src/lib/cache.c Tue Dec 29 01:06:52 2009 +0200 +++ b/src/lib/cache.c Tue Dec 29 02:11:27 2009 +0200 @@ -398,8 +398,99 @@ return 0; } +/** + * Return a pointer to the pixel data on \a row, starting at \a col. + */ +static inline void* tile_row_col (struct pt_cache *cache, size_t row, size_t col) +{ + return cache->data + (row * cache->header->row_bytes) + (col * cache->header->col_bytes); +} + +/** + * Fill in a clipped region of \a width_px pixels at the given row segment + */ +static inline void tile_row_fill_clip (struct pt_cache *cache, png_byte *row, size_t width_px) +{ + // XXX: use a defined background color, or full transparency? + memset(row, 0, width_px * cache->header->col_bytes); +} + +/** + * Write raw tile image data, directly from the cache + */ +static int write_png_data_direct (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_tile_info *ti) +{ + for (size_t row = ti->y; row < ti->y + ti->height; row++) + // write data directly + png_write_row(png, tile_row_col(cache, row, ti->x)); + + return 0; +} + +/** + * Write clipped tile image data (a tile that goes over the edge of the actual image) by aligning the data from the cache as needed + */ +static int write_png_data_clipped (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_tile_info *ti) +{ + png_byte *rowbuf; + size_t row; + + // image data goes from (ti->x ... clip_x, ti->y ... clip_y), remaining region is filled + size_t clip_x, clip_y; + + + // figure out if the tile clips over the right edge + // XXX: use min() + if (ti->x + ti->width > cache->header->width) + clip_x = cache->header->width; + else + clip_y = ti->x + ti->width; + + // figure out if the tile clips over the bottom edge + // XXX: use min() + if (ti->y + ti->height > cache->header->height) + clip_y = cache->header->height; + else + clip_y = ti->y + ti->height; + + + // allocate buffer for a single row of image data + if ((rowbuf = malloc(ti->width * cache->header->col_bytes)) == NULL) + return -1; + + // how much data we actually have for each row, in px and bytes + // from [(tile x)---](clip x) + size_t row_px = clip_x - ti->x; + size_t row_bytes = row_px * cache->header->col_bytes; + + // write the rows that we have + // from [(tile y]---](clip y) + for (row = ti->y; row < clip_y; row++) { + // copy in the actual tile data... + memcpy(rowbuf, tile_row_col(cache, row, ti->x), row_bytes); + + // generate the data for the remaining, clipped, columns + tile_row_fill_clip(cache, rowbuf + row_bytes, (ti->width - row_px)); + + // write + png_write_row(png, rowbuf); + } + + // generate the data for the remaining, clipped, rows + tile_row_fill_clip(cache, rowbuf, ti->width); + + // write out the remaining rows as clipped data + for (; row < ti->y + ti->height; row++) + png_write_row(png, rowbuf); + + // ok + return 0; +} + int pt_cache_tile_png (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_tile_info *ti) { + int err; + // ensure open if (pt_cache_open(cache)) return -1; @@ -416,17 +507,21 @@ // write meta-info png_write_info(png, info); - // pixel data is packed into 1 pixel per byte + // our pixel data is packed into 1 pixel per byte (8bpp or 16bpp) png_set_packing(png); - // write image data - for (size_t row = ti->y; row < ti->y + ti->height; row++) { - size_t col = ti->x; - - // XXX: fill out-of-range regions in some background color - png_write_row(png, cache->data + (row * cache->header->row_bytes) + (col * cache->header->col_bytes)); - } + // figure out if the tile clips + if (ti->x + ti->width <= cache->header->width && ti->y + ti->height <= cache->header->height) + // doesn't clip, just use the raw data + err = write_png_data_direct(cache, png, info, ti); + else + // fill in clipped regions + err = write_png_data_clipped(cache, png, info, ti); + + if (err) + return -1; + // done, flush remaining output png_write_flush(png);