mirror of
https://github.com/fail0verflow/hbc.git
synced 2024-11-17 15:19:22 +01:00
263 lines
5.2 KiB
C
263 lines
5.2 KiB
C
#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);
|
|
}
|
|
|