don't make me start singing patriotic shit. come convert me now

This commit is contained in:
XANTRONIX Development 2021-11-30 01:19:51 -05:00
parent 8330736b1e
commit 22ce22fa4c
7 changed files with 326 additions and 415 deletions

View file

@ -7,89 +7,3 @@
#include "pnglite.h"
#include "png.h"
int cammy_png_save(const char *file,
void *buf,
size_t width,
size_t height,
int depth,
int format) {
png_t *png;
png_init(malloc, free);
if ((png = malloc(sizeof(*png))) == NULL) {
goto error_malloc_png;
}
if (png_open_file_write(png, file) < 0) {
goto error_png_open_file_write;
}
if (png_set_data(png, width, height, depth, format, buf) < 0) {
goto error_png_set_data;
}
png_close_file(png);
free(png);
return 0;
error_png_set_data:
png_close_file(png);
error_png_open_file_write:
free(png);
error_malloc_png:
return -1;
}
uint8_t *cammy_png_load(const char *file,
size_t *width,
size_t *height,
int *depth) {
png_t *png;
uint8_t *buf;
png_init(malloc, free);
if ((png = malloc(sizeof(*png))) == NULL) {
goto error_malloc_png;
}
if (png_open_file_read(png, file) < 0) {
goto error_png_open_file_read;
}
*width = png->width;
*height = png->height;
*depth = png->bpp;
if ((buf = malloc(*width * *height * *depth)) == NULL) {
goto error_malloc_buf;
}
if (png_get_data(png, buf) < 0) {
goto error_png_get_data;
}
png_close_file(png);
free(png);
return buf;
error_png_get_data:
free(buf);
error_malloc_buf:
png_close_file(png);
error_png_open_file_read:
free(png);
error_malloc_png:
return NULL;
}

View file

@ -1,10 +1,9 @@
#ifndef _CAMMY_IMAGE_H
#define _CAMMY_IMAGE_H
#include <stdint.h>
#include <sys/types.h>
#include <cammy/tile.h>
#define CAMMY_IMAGE_Y_COEFFICIENT_R 0.2126
#define CAMMY_IMAGE_Y_COEFFICIENT_G 0.7152
#define CAMMY_IMAGE_Y_COEFFICIENT_B 0.0722
@ -21,27 +20,28 @@ typedef enum {
CAMMY_IMAGE_32BPP_RGBA
} cammy_image_format;
typedef struct _cammy_image_color {
uint8_t r, g, b, a;
} cammy_image_color;
typedef struct _cammy_image {
cammy_image_format format;
cammy_image_color palette[4];
size_t size,
width,
height;
union {
uint8_t *buf;
cammy_tile *tiles;
};
char *file;
uint8_t *buf;
} cammy_image;
#define CAMMY_IMAGE_HEADER_VERSION 0x0001
typedef struct _cammy_image_header {
uint8_t magic[4];
uint8_t magic[4];
uint16_t version;
uint16_t width, height;
cammy_image_color palette[4];
} cammy_image_header;
typedef struct _cammy_image_point {
@ -53,41 +53,19 @@ typedef struct _cammy_image_region {
} cammy_image_region;
cammy_image *cammy_image_new(cammy_image_format format,
cammy_image_color *palette,
size_t width,
size_t height);
cammy_image *cammy_image_open(const char *filename);
void cammy_image_destroy(cammy_image *image);
cammy_image *cammy_image_open(const char *filename);
int cammy_image_save(cammy_image *image, const char *filename);
void cammy_image_split_to_tiles(cammy_tile *destr,
cammy_tile *destg,
cammy_tile *destb,
uint8_t *src,
size_t width,
size_t height,
int depth);
void cammy_image_merge_tiles(uint8_t *dest,
cammy_tile *srcr,
cammy_tile *srcg,
cammy_tile *srcb,
size_t width,
size_t height,
int depth);
void cammy_image_copy(cammy_image *dest,
cammy_image *src,
cammy_image_point *to,
cammy_image_region *from);
int cammy_image_slice(uint8_t *buf,
size_t width,
size_t height,
size_t x_pad,
size_t y_pad,
int depth);
#endif /* _CAMMY_IMAGE_H */

View file

@ -3,6 +3,7 @@
#include <stdint.h>
#include <cammy/image.h>
#include <cammy/tile.h>
#define CAMMY_PHOTO_TILES_WIDTH 16

View file

@ -3,6 +3,8 @@
#include <stdint.h>
#include <cammy/image.h>
#define CAMMY_TILE_SIZE 16
#define CAMMY_TILE_WIDTH 8
#define CAMMY_TILE_HEIGHT 8

View file

@ -11,7 +11,7 @@ HEADERS_LOCAL = pnglite.h
HEADERS_BUILD = $(HEADERS_LOCAL) \
$(addprefix $(INCLUDE_PATH)/$(HEADER_SUBDIR)/,$(HEADERS))
HEADERS = sram.h image.h photo.h
HEADERS = sram.h image.h photo.h tile.h
OBJS = sram.o image.o photo.o pnglite.o
VERSION_MAJOR = 0

View file

@ -77,8 +77,11 @@ static uint32_t bayer_matrix[256] = {
0x0203ffff, 0x0203ffff, 0x0203ffff, 0x0203ffff, 0x0203ffff,
};
static uint8_t level_2bpp_to_8bpp[4] = {
0, 87, 171, 255
static cammy_image_color default_palette[4] = {
{ 0, 0, 0, 0 },
{ 87, 87, 87, 0 },
{ 171, 171, 171, 0 },
{ 255, 255, 255, 0 }
};
static uint8_t rgb_to_grayscale(uint8_t r, uint8_t g, uint8_t b) {
@ -97,37 +100,6 @@ static uint8_t rgb_to_tile_2bpp(uint8_t r, uint8_t g, uint8_t b, size_t x, size_
return (slot & (0x8000 >> ((y & 3) << 2) >> (x & 3)))? to: from;
}
static inline uint8_t tile_read(cammy_tile *tiles,
size_t x,
size_t y,
int stride) {
cammy_tile *tile = CAMMY_TILE_INDEXED(tiles, x, y, stride);
int tile_x = x & 7,
tile_y = y & 7;
return
((tile->data[ tile_y<<1] & (0x80 >> tile_x)) >> (tile_x ^ 7)
| ((tile->data[(tile_y<<1)|1] & (0x80 >> tile_x)) >> (tile_x ^ 7) << 1));
}
static inline void tile_write(cammy_tile *tiles,
size_t x,
size_t y,
int stride,
uint8_t value) {
cammy_tile *tile = CAMMY_TILE_INDEXED(tiles, x, y, stride);
int tile_x = x & 7,
tile_y = y & 7;
tile->data[ tile_y<<1] &= ~(1 << (tile_x ^ 7));
tile->data[(tile_y<<1)|1] &= ~(1 << (tile_x ^ 7));
tile->data[ tile_y<<1] |= (value & 0x01) << (tile_x ^ 7);
tile->data[(tile_y<<1)|1] |= ((value & 0x02) >> 1) << (tile_x ^ 7);
}
static inline void buf_read(uint8_t *buf,
size_t x, size_t y, size_t stride,
uint8_t *r, uint8_t *g, uint8_t *b,
@ -157,6 +129,7 @@ static inline size_t size_2bpp_tile(size_t width, size_t height) {
}
cammy_image *cammy_image_new(cammy_image_format format,
cammy_image_color *palette,
size_t width,
size_t height) {
cammy_image *image;
@ -164,7 +137,12 @@ cammy_image *cammy_image_new(cammy_image_format format,
switch (format) {
case CAMMY_IMAGE_2BPP_TILE: {
if (palette == NULL) {
palette = default_palette;
}
size = size_2bpp_tile(width, height);
break;
}
@ -192,11 +170,16 @@ cammy_image *cammy_image_new(cammy_image_format format,
goto error_malloc_buf;
}
if (palette) {
memcpy(&image->palette, palette, sizeof(image->palette));
} else {
memset(&image->palette, '\0', sizeof(image->palette));
}
image->format = format;
image->size = size;
image->width = width;
image->height = height;
image->file = NULL;
return image;
@ -213,55 +196,6 @@ void cammy_image_destroy(cammy_image *image) {
free(image);
}
static cammy_image *load_png(const char *file) {
png_t png;
cammy_image *image;
cammy_image_format format = CAMMY_IMAGE_NONE;
png_init(malloc, free);
if (png_open_file_read(&png, file) < 0) {
goto error_png_open_file_read;
}
switch (png.bpp) {
case 3:
format = CAMMY_IMAGE_24BPP_RGB;
break;
case 4:
format = CAMMY_IMAGE_32BPP_RGBA;
break;
default:
errno = EINVAL;
goto error_invalid_format;
}
if ((image = cammy_image_new(format, png.width, png.height)) == NULL) {
goto error_image_new;
}
if (png_get_data(&png, image->buf) < 0) {
goto error_png_get_data;
}
png_close_file(&png);
return image;
error_png_get_data:
cammy_image_destroy(image);
error_image_new:
error_invalid_format:
png_close_file(&png);
error_png_open_file_read:
return NULL;
}
static cammy_image *load_tile(const char *filename) {
int fd;
size_t off;
@ -284,6 +218,7 @@ static cammy_image *load_tile(const char *filename) {
}
if ((image = cammy_image_new(CAMMY_IMAGE_2BPP_TILE,
header.palette,
be16toh(header.width),
be16toh(header.height))) == NULL) {
goto error_image_new;
@ -315,6 +250,58 @@ error_open:
return NULL;
}
static cammy_image *load_png(const char *file) {
png_t png;
cammy_image *image;
cammy_image_format format = CAMMY_IMAGE_NONE;
png_init(malloc, free);
if (png_open_file_read(&png, file) < 0) {
goto error_png_open_file_read;
}
switch (png.bpp) {
case 3:
format = CAMMY_IMAGE_24BPP_RGB;
break;
case 4:
format = CAMMY_IMAGE_32BPP_RGBA;
break;
default:
errno = EINVAL;
goto error_invalid_format;
}
if ((image = cammy_image_new(format,
NULL,
png.width,
png.height)) == NULL) {
goto error_image_new;
}
if (png_get_data(&png, image->buf) < 0) {
goto error_png_get_data;
}
png_close_file(&png);
return image;
error_png_get_data:
cammy_image_destroy(image);
error_image_new:
error_invalid_format:
png_close_file(&png);
error_png_open_file_read:
return NULL;
}
cammy_image *cammy_image_open(const char *file) {
cammy_image *image;
@ -361,7 +348,7 @@ error_open:
return NULL;
}
int cammy_image_save(cammy_image *image, const char *filename) {
static int save_tile(cammy_image *image, const char *filename) {
size_t off,
rest = image->size;
@ -374,6 +361,8 @@ int cammy_image_save(cammy_image *image, const char *filename) {
.height = htobe16(image->height)
};
memcpy(&header.palette, image->palette, sizeof(header.palette));
if ((fd = open(filename, O_CREAT | O_WRONLY | O_TRUNC, 0644)) < 0) {
goto error_open;
}
@ -406,154 +395,252 @@ error_open:
return -1;
}
void cammy_image_dither(uint8_t *dest,
uint8_t *src,
size_t width,
size_t height,
int depth,
cammy_tile_palette *palette) {
size_t x, y;
static inline void format_info_png(cammy_image_format format,
int *depth,
int *color) {
switch (format) {
case CAMMY_IMAGE_24BPP_RGB:
if (depth) *depth = 3;
if (color) *color = PNG_TRUECOLOR;
for (y=0; y<height; y++) {
for (x=0; x<width; x++) {
uint8_t r, g, b, value;
break;
buf_read(src, x, y, width, &r, &g, &b, depth);
case CAMMY_IMAGE_32BPP_RGBA:
if (depth) *depth = 4;
if (color) *color = PNG_TRUECOLOR_ALPHA;
value = rgb_to_tile_2bpp(r, g, b, x, y);
break;
r = palette->colors[value][0];
g = palette->colors[value][1];
b = palette->colors[value][2];
default:
if (depth) *depth = 0;
if (color) *color = 0;
buf_write(dest, x, y, width, r, g, b, 3);
}
break;
}
}
void cammy_image_split_to_tiles(cammy_tile *destr,
cammy_tile *destg,
cammy_tile *destb,
uint8_t *src,
size_t width,
size_t height,
int depth) {
size_t x, y;
static int save_png(cammy_image *image, const char *file) {
png_t png;
for (y=0; y<height; y++) {
for (x=0; x<width; x++) {
uint8_t r, g, b;
int depth, color;
buf_read(src, x, y, width, &r, &g, &b, depth);
format_info_png(image->format, &depth, &color);
tile_write(destr, x, y, width, rgb_to_tile_2bpp(r, r, r, x, y) ^ 3);
tile_write(destg, x, y, width, rgb_to_tile_2bpp(g, g, g, x, y) ^ 3);
tile_write(destb, x, y, width, rgb_to_tile_2bpp(b, b, b, x, y) ^ 3);
}
png_init(malloc, free);
if (png_open_file_write(&png, file) < 0) {
goto error_png_open_file_write;
}
if (png_set_data(&png,
image->width,
image->height,
depth,
color,
image->buf) < 0) {
goto error_png_set_data;
}
png_close_file(&png);
return 0;
error_png_set_data:
png_close_file(&png);
error_png_open_file_write:
return -1;
}
void cammy_image_copy_from_tile(uint8_t *dest,
cammy_tile *src,
size_t width,
size_t height,
int depth,
cammy_tile_palette *palette) {
size_t x, y;
int cammy_image_save(cammy_image *image, const char *filename) {
switch (image->format) {
case CAMMY_IMAGE_2BPP_TILE:
return save_tile(image, filename);
for (y=0; y<height; y++) {
for (x=0; x<width; x++) {
uint8_t value = tile_read(src, x, y, width) ^ 3;
case CAMMY_IMAGE_24BPP_RGB:
case CAMMY_IMAGE_32BPP_RGBA:
return save_png(image, filename);
buf_write(dest, x, y, width, palette->colors[value][0],
palette->colors[value][1],
palette->colors[value][2], depth);
}
default:
break;
}
errno = EINVAL;
return -1;
}
void cammy_image_merge_tiles(uint8_t *dest,
cammy_tile *srcr,
cammy_tile *srcg,
cammy_tile *srcb,
size_t width,
size_t height,
int depth) {
size_t x, y;
static inline uint8_t tile_read(cammy_tile *tiles,
size_t x,
size_t y,
int stride) {
cammy_tile *tile = CAMMY_TILE_INDEXED(tiles, x, y, stride);
for (y=0; y<height; y++) {
for (x=0; x<width; x++) {
uint8_t r = tile_read(srcr, x, y, width) ^ 3,
g = tile_read(srcg, x, y, width) ^ 3,
b = tile_read(srcb, x, y, width) ^ 3;
int tile_x = x & 7,
tile_y = y & 7;
buf_write(dest, x, y, width, level_2bpp_to_8bpp[r],
level_2bpp_to_8bpp[g],
level_2bpp_to_8bpp[b], depth);
}
}
return
((tile->data[ tile_y<<1] & (0x80 >> tile_x)) >> (tile_x ^ 7)
| ((tile->data[(tile_y<<1)|1] & (0x80 >> tile_x)) >> (tile_x ^ 7) << 1));
}
static inline void tile_write(cammy_tile *tiles,
size_t x,
size_t y,
int stride,
uint8_t value) {
cammy_tile *tile = CAMMY_TILE_INDEXED(tiles, x, y, stride);
int tile_x = x & 7,
tile_y = y & 7;
tile->data[ tile_y<<1] &= ~(1 << (tile_x ^ 7));
tile->data[(tile_y<<1)|1] &= ~(1 << (tile_x ^ 7));
tile->data[ tile_y<<1] |= (value & 0x01) << (tile_x ^ 7);
tile->data[(tile_y<<1)|1] |= ((value & 0x02) >> 1) << (tile_x ^ 7);
}
static void copy_2bpp(cammy_image *dest,
cammy_image *src,
cammy_image_point *to,
cammy_image_region *from) {
size_t x_offset,
y_offset;
size_t x,
y;
for (y_offset=0; y_offset < from->height; y_offset++) {
if (to->y + y_offset > dest->height) {
for (y=0; y < from->height; y++) {
if (to->y + y > dest->height) {
break;
}
for (x_offset=0; x_offset < from->width; x_offset++) {
uint8_t value = tile_read(src->tiles, from->x + x_offset,
from->y + y_offset,
src->width);
for (x=0; x < from->width; x++) {
uint8_t value = tile_read((cammy_tile *)src->buf,
from->x + x,
from->y + y,
src->width);
if (to->x + x_offset > dest->width) {
if (to->x + x > dest->width) {
break;
}
tile_write(dest->tiles, to->x + x_offset,
to->y + y_offset,
dest->width,
value);
tile_write((cammy_tile *)dest->buf,
to->x + x,
to->y + y,
dest->width,
value);
}
}
}
static void copy_to_2bpp_tile(cammy_image *dest,
cammy_image *src,
cammy_image_point *to,
cammy_image_region *from,
int depth) {
size_t x_offset, y_offset;
static void copy_buf(cammy_image *dest,
cammy_image *src,
cammy_image_point *to,
cammy_image_region *from) {
size_t x, y;
for (y_offset=0; y_offset < from->height; y_offset++) {
if (to->y + y_offset > dest->height) {
int depth, color;
format_info_png(dest->format, &depth, &color);
for (y=0; y < from->height; y++) {
if (to->y + y > dest->height) {
break;
}
for (x_offset=0; x_offset < from->width; x_offset++) {
for (x=0; x < from->width; x++) {
uint8_t r, g, b;
if (to->x + x_offset > from->width) {
if (to->x + x > from->width) {
break;
}
buf_read(src->buf,
from->x + x_offset,
from->y + y_offset,
from->x + x,
from->y + y,
from->width,
&r, &g, &b, depth);
tile_write(dest->tiles,
to->x + x_offset,
to->y + y_offset,
buf_write(dest->buf,
to->x + x,
to->y + y,
dest->width,
r, g, b, depth);
}
}
}
static void copy_rgb_to_2bpp_tile(cammy_image *dest,
cammy_image *src,
cammy_image_point *to,
cammy_image_region *from) {
size_t x, y;
int depth, color;
format_info_png(dest->format, &depth, &color);
for (y=0; y < from->height; y++) {
if (to->y + y > dest->height) {
break;
}
for (x=0; x < from->width; x++) {
uint8_t r, g, b;
if (to->x + x > from->width) {
break;
}
buf_read(src->buf,
from->x + x,
from->y + y,
from->width,
&r, &g, &b, depth);
tile_write((cammy_tile *)dest->buf,
to->x + x,
to->y + y,
dest->width,
rgb_to_tile_2bpp(r, g, b, to->x + x_offset,
to->y + y_offset) ^ 3);
rgb_to_tile_2bpp(r, g, b, to->x + x,
to->y + y) ^ 3);
}
}
}
static void copy_2bpp_tile_to_rgb(cammy_image *dest,
cammy_image *src,
cammy_image_point *to,
cammy_image_region *from) {
size_t x, y;
int depth, color;
format_info_png(dest->format, &depth, &color);
for (y=0; y < from->height; y++) {
if (to->y + y > dest->height) {
break;
}
for (x=0; x < from->width; x++) {
uint8_t c;
if (to->x + x > from->width) {
break;
}
c = tile_read((cammy_tile *)src->buf,
from->x + x,
from->y + y,
from->width);
buf_write(src->buf,
from->x + x,
from->y + y,
from->width,
src->palette[c].r,
src->palette[c].g,
src->palette[c].b,
depth);
}
}
}
@ -562,124 +649,43 @@ void cammy_image_copy(cammy_image *dest,
cammy_image *src,
cammy_image_point *to,
cammy_image_region *from) {
if (src->format == dest->format) {
switch (src->format) {
case CAMMY_IMAGE_2BPP_TILE:
copy_2bpp(dest, src, to, from); break;
switch (src->format) {
case CAMMY_IMAGE_2BPP_TILE:
switch (dest->format) {
case CAMMY_IMAGE_2BPP_TILE:
copy_2bpp(dest, src, to, from);
default:
break;
}
return;
return;
}
case CAMMY_IMAGE_24BPP_RGB:
case CAMMY_IMAGE_32BPP_RGBA:
copy_2bpp_tile_to_rgb(dest, src, to, from);
if (dest->format == CAMMY_IMAGE_2BPP_TILE) {
switch (src->format) {
case CAMMY_IMAGE_24BPP_RGB:
copy_to_2bpp_tile(dest, src, to, from, 3);
break;
return;
case CAMMY_IMAGE_32BPP_RGBA:
copy_to_2bpp_tile(dest, src, to, from, 4);
break;
default:
break;
}
}
}
static int save_tile_to_file(cammy_tile *tiles, size_t width,
size_t height,
int file) {
static const char *format = "slice%04d.tile";
char name[32];
int fd;
struct stat st;
if (snprintf(name, sizeof(name), format, file) < 0) {
goto error_snprintf_name;
}
if (stat(name, &st) == 0) {
errno = EEXIST;
goto error_exists;
}
if ((fd = open(name, O_CREAT | O_WRONLY, 0644)) < 0) {
goto error_open;
}
if (write(fd, tiles, (width * height) >> 2) < 0) {
goto error_write;
}
close(fd);
return 0;
error_write:
close(fd);
error_open:
error_exists:
error_snprintf_name:
return -1;
}
int cammy_image_slice(uint8_t *buf,
size_t width,
size_t height,
size_t x_pad,
size_t y_pad,
int depth) {
cammy_image src = {
.format = CAMMY_IMAGE_2BPP_TILE,
.size = size_2bpp_tile(width, height),
.width = width,
.height = height,
.buf = buf
}, *dest;
int file = 0;
size_t x, y;
if ((dest = cammy_image_new(CAMMY_IMAGE_2BPP_TILE,
width,
height
)) == NULL) {
goto error_image_new;
}
for (x=0; x<width; x+=CAMMY_SCREEN_WIDTH + (2 * x_pad)) {
for (y=0; y<height; y+=CAMMY_SCREEN_HEIGHT + y_pad) {
cammy_image_point to = {
0, 0
};
cammy_image_region from = {
x + x_pad, y, CAMMY_SCREEN_WIDTH, CAMMY_SCREEN_HEIGHT
};
cammy_image_copy(dest, &src, &to, &from);
if (save_tile_to_file(dest->tiles, CAMMY_SCREEN_WIDTH,
CAMMY_SCREEN_HEIGHT, file++) < 0) {
goto error_save_tile_to_file;
default:
break;
}
}
case CAMMY_IMAGE_24BPP_RGB:
case CAMMY_IMAGE_32BPP_RGBA:
switch (dest->format) {
case CAMMY_IMAGE_2BPP_TILE:
copy_rgb_to_2bpp_tile(dest, src, to, from);
return;
case CAMMY_IMAGE_24BPP_RGB:
case CAMMY_IMAGE_32BPP_RGBA:
copy_buf(dest, src, to, from);
return;
default:
break;
}
default:
break;
}
cammy_image_destroy(dest);
return 0;
error_save_tile_to_file:
cammy_image_destroy(dest);
error_image_new:
return -1;
}

View file

@ -10,13 +10,23 @@ cammy_image *cammy_photo_export(cammy_photo *src,
cammy_tile_palette *palette) {
cammy_image *image;
if ((image = cammy_image_))
if ((image = cammy_image_new(format,
CAMMY_PHOTO_WIDTH,
CAMMY_PHOTO_HEIGHT)) == NULL) {
goto error_image_new;
}
cammy_image_copy_from_tile(dest,
(cammy_tile *)&src->tiles,
CAMMY_PHOTO_WIDTH,
CAMMY_PHOTO_HEIGHT,
depth,
palette);
return image;
error_image_new:
return NULL;
}
void cammy_photo_merge(cammy_photo *srcr,