hbc/channel/channelapp/source/tex.c

263 lines
5.2 KiB
C
Raw Normal View History

2016-11-23 06:35:12 +01:00
#include <sys/types.h>
#include <sys/stat.h>
#include <malloc.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <zlib.h>
#include <png.h>
#include "../config.h"
#include "tex.h"
#include "panic.h"
#define SCREENSHOT_FILENAME "/hbc-%03lu.png"
static u32 screenshot_index = 0;
void tex_free (gfx_entity *entity) {
if (!entity)
return;
free (entity->texture.pixels);
free (entity);
}
static void pngcb_error (png_structp png_ptr, png_const_charp error_msg) {
gprintf ("ERROR: Couldn't load PNG image: %s\n", error_msg);
}
static void pngcb_read (png_structp png_ptr, png_bytep data,
png_size_t length) {
u8 **p = (u8 **) png_get_io_ptr (png_ptr);
memcpy (data, *p, length);
*p += length;
}
gfx_entity * tex_from_png(const u8 *data, u32 size, u16 width, u16 height) {
int res;
png_structp png_ptr;
png_infop info_ptr;
png_uint_32 w, h;
png_bytepp rows;
u8 *pixels;
u8 *s, *d;
u32 x, y;
u8 r;
gfx_entity *entity;
res = png_sig_cmp ((u8 *) data, 0, 4);
if (res) {
gprintf ("png_sig_cmp failed: %d\n", res);
return NULL;
}
png_ptr = png_create_read_struct (PNG_LIBPNG_VER_STRING, NULL, pngcb_error,
NULL);
if (!png_ptr) {
gprintf ("png_create_read_struct failed\n");
return NULL;
}
info_ptr = png_create_info_struct (png_ptr);
if (!info_ptr) {
gprintf ("png_create_info_struct failed\n");
png_destroy_read_struct (&png_ptr, (png_infopp)NULL, (png_infopp)NULL);
return NULL;
}
if (setjmp (png_jmpbuf (png_ptr))) {
gprintf ("setjmp failed\n");
png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
return NULL;
}
png_set_read_fn (png_ptr, &data, pngcb_read);
png_set_user_limits (png_ptr, width, height);
png_set_add_alpha (png_ptr, 0xff, PNG_FILLER_BEFORE);
png_read_png (png_ptr, info_ptr, PNG_TRANSFORM_PACKING |
PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_SWAP_ALPHA,
(png_voidp)NULL);
w = png_get_image_width (png_ptr, info_ptr);
h = png_get_image_height (png_ptr, info_ptr);
if ((w != width) || (h != height)) {
gprintf ("invalid png dimension!\n");
png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
return NULL;
}
rows = png_get_rows (png_ptr, info_ptr);
pixels = (u8 *) pmemalign (32, w * h * 4);
d = pixels;
for (y = 0; y < h; y += 4) {
for (x = 0; x < w; x += 4) {
for (r = 0; r < 4; ++r) {
s = &rows[y + r][x << 2];
*d++ = s[0];
*d++ = s[1];
*d++ = s[4];
*d++ = s[5];
*d++ = s[8];
*d++ = s[9];
*d++ = s[12];
*d++ = s[13];
}
for (r = 0; r < 4; ++r) {
s = &rows[y + r][x << 2];
*d++ = s[2];
*d++ = s[3];
*d++ = s[6];
*d++ = s[7];
*d++ = s[10];
*d++ = s[11];
*d++ = s[14];
*d++ = s[15];
}
CHKBUFACC(d - 1, pixels, w * h * 4);
}
}
png_destroy_read_struct (&png_ptr, &info_ptr, (png_infopp)NULL);
entity = (gfx_entity *) pmalloc (sizeof (gfx_entity));
gfx_gen_tex (entity, w, h, pixels, GFXT_RGBA8);
return entity;
}
gfx_entity * tex_from_png_file(const char *fn, const struct stat *st,
u16 width, u16 height) {
u8 *buf;
int fd;
gfx_entity *entity;
fd = open (fn, O_RDONLY);
if (fd == -1)
return NULL;
buf = (u8 *) pmalloc (st->st_size);
if (st->st_size != read (fd, buf, st->st_size)) {
free (buf);
close (fd);
return NULL;
}
entity = tex_from_png (buf, st->st_size, width, height);
close (fd);
free (buf);
return entity;
}
gfx_entity * tex_from_tex_vsplit(gfx_entity *ge, u16 hstart, u16 hend)
{
gfx_entity *entity;
u16 h = hend - hstart;
entity = (gfx_entity *) pmalloc (sizeof (gfx_entity));
gfx_gen_tex (entity, ge->w, h, ge->texture.pixels + ge->w * hstart * 4, GFXT_RGBA8);
return entity;
}
void save_rgba_png(u32 *buffer, u16 x, u16 y) {
char fn[16];
struct stat st;
FILE *fp = NULL;
png_structp png_ptr = NULL;
png_infop info_ptr;
png_bytep *row_pointers;
u16 i;
while (true) {
if (screenshot_index > 999)
return;
sprintf(fn, SCREENSHOT_FILENAME, screenshot_index);
if (!stat(fn, &st)) {
screenshot_index++;
continue;
}
if (errno == ENOENT)
break;
gprintf("error looking for a screenshot spot %d\n", errno);
return;
}
row_pointers = (png_bytep *) pmalloc(y * sizeof(png_bytep));
fp = fopen(fn, "wb");
if (!fp) {
gprintf("couldnt open %s for writing\n", fn);
goto exit;
}
setbuf(fp, NULL);
png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
if (!png_ptr) {
gprintf ("png_create_write_struct failed\n");
goto exit;
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
gprintf ("png_create_info_struct failed\n");
goto exit;
}
if (setjmp(png_jmpbuf(png_ptr))) {
gprintf ("setjmp failed\n");
goto exit;
}
png_init_io(png_ptr, fp);
png_set_compression_level(png_ptr, Z_BEST_COMPRESSION);
png_set_IHDR(png_ptr, info_ptr, x, y, 8,
PNG_COLOR_TYPE_RGB_ALPHA, PNG_INTERLACE_NONE,
PNG_COMPRESSION_TYPE_DEFAULT, PNG_FILTER_TYPE_DEFAULT);
png_write_info(png_ptr, info_ptr);
for (i = 0; i < y; ++i)
row_pointers[i] = (png_bytep) (buffer + i * x);
png_set_swap_alpha(png_ptr);
png_write_image(png_ptr, row_pointers);
png_write_end(png_ptr, info_ptr);
gprintf("saved %s\n", fn);
screenshot_index++;
exit:
if (png_ptr)
png_destroy_write_struct(&png_ptr, (png_infopp)NULL);
free(row_pointers);
fclose(fp);
}