src/lib/cache.c
changeset 12 3576e00388fd
parent 11 eb2a1472f084
child 13 294201975f8c
equal deleted inserted replaced
11:eb2a1472f084 12:3576e00388fd
   396 
   396 
   397     // done!
   397     // done!
   398     return 0;
   398     return 0;
   399 }
   399 }
   400 
   400 
       
   401 /**
       
   402  * Return a pointer to the pixel data on \a row, starting at \a col.
       
   403  */
       
   404 static inline void* tile_row_col (struct pt_cache *cache, size_t row, size_t col)
       
   405 {
       
   406     return cache->data + (row * cache->header->row_bytes) + (col * cache->header->col_bytes);
       
   407 }
       
   408 
       
   409 /**
       
   410  * Fill in a clipped region of \a width_px pixels at the given row segment
       
   411  */
       
   412 static inline void tile_row_fill_clip (struct pt_cache *cache, png_byte *row, size_t width_px)
       
   413 {
       
   414     // XXX: use a defined background color, or full transparency?
       
   415     memset(row, 0, width_px * cache->header->col_bytes);
       
   416 }
       
   417 
       
   418 /**
       
   419  * Write raw tile image data, directly from the cache
       
   420  */
       
   421 static int write_png_data_direct (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_tile_info *ti)
       
   422 {
       
   423     for (size_t row = ti->y; row < ti->y + ti->height; row++)
       
   424         // write data directly
       
   425         png_write_row(png, tile_row_col(cache, row, ti->x));
       
   426 
       
   427     return 0;
       
   428 }
       
   429 
       
   430 /**
       
   431  * 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
       
   432  */
       
   433 static int write_png_data_clipped (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_tile_info *ti)
       
   434 {
       
   435     png_byte *rowbuf;
       
   436     size_t row;
       
   437     
       
   438     // image data goes from (ti->x ... clip_x, ti->y ... clip_y), remaining region is filled
       
   439     size_t clip_x, clip_y;
       
   440 
       
   441 
       
   442     // figure out if the tile clips over the right edge
       
   443     // XXX: use min()
       
   444     if (ti->x + ti->width > cache->header->width)
       
   445         clip_x = cache->header->width;
       
   446     else
       
   447         clip_y = ti->x + ti->width;
       
   448     
       
   449     // figure out if the tile clips over the bottom edge
       
   450     // XXX: use min()
       
   451     if (ti->y + ti->height > cache->header->height)
       
   452         clip_y = cache->header->height;
       
   453     else
       
   454         clip_y = ti->y + ti->height;
       
   455 
       
   456 
       
   457     // allocate buffer for a single row of image data
       
   458     if ((rowbuf = malloc(ti->width * cache->header->col_bytes)) == NULL)
       
   459         return -1;
       
   460 
       
   461     // how much data we actually have for each row, in px and bytes
       
   462     // from [(tile x)---](clip x)
       
   463     size_t row_px = clip_x - ti->x;
       
   464     size_t row_bytes = row_px * cache->header->col_bytes;
       
   465 
       
   466     // write the rows that we have
       
   467     // from [(tile y]---](clip y)
       
   468     for (row = ti->y; row < clip_y; row++) {
       
   469         // copy in the actual tile data...
       
   470         memcpy(rowbuf, tile_row_col(cache, row, ti->x), row_bytes);
       
   471 
       
   472         // generate the data for the remaining, clipped, columns
       
   473         tile_row_fill_clip(cache, rowbuf + row_bytes, (ti->width - row_px));
       
   474 
       
   475         // write
       
   476         png_write_row(png, rowbuf);
       
   477     }
       
   478 
       
   479     // generate the data for the remaining, clipped, rows
       
   480     tile_row_fill_clip(cache, rowbuf, ti->width);
       
   481     
       
   482     // write out the remaining rows as clipped data
       
   483     for (; row < ti->y + ti->height; row++)
       
   484         png_write_row(png, rowbuf);
       
   485 
       
   486     // ok
       
   487     return 0;
       
   488 }
       
   489 
   401 int pt_cache_tile_png (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_tile_info *ti)
   490 int pt_cache_tile_png (struct pt_cache *cache, png_structp png, png_infop info, const struct pt_tile_info *ti)
   402 {
   491 {
       
   492     int err;
       
   493 
   403     // ensure open
   494     // ensure open
   404     if (pt_cache_open(cache))
   495     if (pt_cache_open(cache))
   405         return -1;
   496         return -1;
   406 
   497 
   407     // set basic info
   498     // set basic info
   414         png_set_PLTE(png, info, cache->header->palette, cache->header->num_palette);
   505         png_set_PLTE(png, info, cache->header->palette, cache->header->num_palette);
   415 
   506 
   416     // write meta-info
   507     // write meta-info
   417     png_write_info(png, info);
   508     png_write_info(png, info);
   418 
   509 
   419     // pixel data is packed into 1 pixel per byte
   510     // our pixel data is packed into 1 pixel per byte (8bpp or 16bpp)
   420     png_set_packing(png);
   511     png_set_packing(png);
   421     
   512     
   422     // write image data
   513     // figure out if the tile clips
   423     for (size_t row = ti->y; row < ti->y + ti->height; row++) {
   514     if (ti->x + ti->width <= cache->header->width && ti->y + ti->height <= cache->header->height)
   424         size_t col = ti->x;
   515         // doesn't clip, just use the raw data
   425         
   516         err = write_png_data_direct(cache, png, info, ti);
   426         // XXX: fill out-of-range regions in some background color
   517 
   427         png_write_row(png, cache->data + (row * cache->header->row_bytes) + (col * cache->header->col_bytes));
   518     else
   428     }
   519         // fill in clipped regions
   429 
   520         err = write_png_data_clipped(cache, png, info, ti);
       
   521 
       
   522     if (err)
       
   523         return -1;
       
   524     
   430     // done, flush remaining output
   525     // done, flush remaining output
   431     png_write_flush(png);
   526     png_write_flush(png);
   432 
   527 
   433     // ok
   528     // ok
   434     return 0;
   529     return 0;