From fc6f7d3051323eeeb6eec5fc5081a44abeec6b24 Mon Sep 17 00:00:00 2001 From: Lephe Date: Sat, 14 May 2022 12:54:59 +0100 Subject: [PATCH] image: remove alpha field of images --- CMakeLists.txt | 1 + include/gint/image.h | 79 ++++++++++++--------- src/image/image_alloc.c | 4 +- src/image/image_alpha.c | 15 ++++ src/image/image_clear.c | 2 +- src/image/image_copy.c | 10 +-- src/image/image_create.c | 3 +- src/image/image_create_vram.c | 2 +- src/image/image_get_pixel.c | 2 +- src/image/image_sub.c | 1 - src/render-cg/image/image_p4.c | 2 +- src/render-cg/image/image_p4_dye.c | 2 +- src/render-cg/image/image_p4_swapcolor.c | 2 +- src/render-cg/image/image_p8.c | 2 +- src/render-cg/image/image_p8_dye.c | 2 +- src/render-cg/image/image_p8_swapcolor.c | 2 +- src/render-cg/image/image_rgb16.c | 2 +- src/render-cg/image/image_rgb16_dye.c | 2 +- src/render-cg/image/image_rgb16_swapcolor.c | 2 +- 19 files changed, 79 insertions(+), 58 deletions(-) create mode 100644 src/image/image_alpha.c diff --git a/CMakeLists.txt b/CMakeLists.txt index 4df5e69..ff71315 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -159,6 +159,7 @@ set(SOURCES_CG src/r61524/r61524.c # Image library src/image/image_alloc.c + src/image/image_alpha.c src/image/image_clear.c src/image/image_copy.c src/image/image_copy_palette.c diff --git a/include/gint/image.h b/include/gint/image.h index 20d5731..ae17acc 100644 --- a/include/gint/image.h +++ b/include/gint/image.h @@ -12,7 +12,7 @@ // // This module supports 3 bit depths: full-color 16-bit (RGB565), indexed 8-bit // (P8) and indexed 4-bit (P4). All three have an "alpha" variation where one -// color is treated as transparent, leading to 6 total formats. +// color is treated as transparent, leading to 6 total formats. // // The image renderers support so-called *dynamic effects*, which are image // transformations performed on-the-fly while rendering, without generating an @@ -92,8 +92,10 @@ typedef struct uint8_t format; /* Additional flags, a combination of IMAGE_FLAGS_* values */ uint8_t flags; - /* For formats with alpha, value or index used for transparency */ - uint16_t alpha; + /* For P8 and P4, number of colors in the palette; this includes alpha for + transparent images, since alpha is always the first entry. For valid P4 + images this is always 16, while for P8 it ranges between 1 and 256. */ + int16_t color_count; /* Full width and height, in pixels */ uint16_t width; uint16_t height; @@ -107,17 +109,15 @@ typedef struct - Each 2-byte value is an RGB565 color P8: - 1 byte per entry - - Each byte is a shifted palette index (to access the palette, use: - palette.colors[+128]) + - Each byte is a palette index shifted by 128 (to access the color, use + palette[+128]) P4: - 4 bits per entry, each row padded to a full byte - Each entry is a palette index (0...15) */ void *data; - /* For P8 and P4, palette. The color count does not account for alpha - (which is usually the last entry, but not materialized) and instead - indicates how much memory is allocated. */ - int color_count; + /* For P8 and P4, color palette. The number of entries allocated in the + array is equal to the color_count attribute. */ uint16_t *palette; } GPACKED(4) image_t; @@ -183,26 +183,23 @@ enum { By default, a new palette is allocated for formats with palettes; the new image owns the palette and frees it when freed. This can be overriden by - setting the [palette] pointer to the desired palette; in this case, the new - image does not own the palette and does not free it when freed. + setting the [palette] argument to the desired palette; in this case, the new + image does not own the palette and does not free it when freed. For formats + with alpha the first entry of the palette is the alpha color. Regardless of whether the palette is allocated or specified by hand, for P8 the palette size must be indicated. A value of -1 can be specified to use the default (256 colors). For all other formats, set a value of -1. - For images with alpha, the last parameter [alpha] indicates the palette - index or color value that denotes transparent pixels. - The returned image structure must be freed with image_free() after use. @width Width of the new image @height Height of the new image @format Pixel format; one of the IMAGE_* formats defined above @palette If not NULL, specifies the palette instead of allocating it - @palette_size For P8, indicates the palette size to use - @alpha For formats with alpha, color or index denoting alpha */ + @palette_size For P8, indicates the palette size to use */ image_t *image_alloc(int width, int height, int format, - void *palette, int palette_size, int alpha); + void *palette, int palette_size); /* image_create(): Create a bare image with no data/palette @@ -217,11 +214,8 @@ image_t *image_alloc(int width, int height, int format, the image if the user wishes for the image to free its data and palette when freed. - For images with alpha, the last parameter [alpha] indicates the palette - index or color value that denotes transparent pixels. - The returned image structure must be freed with image_free() after use. */ -image_t *image_create(int width, int height, int format, int alpha); +image_t *image_create(int width, int height, int format); /* image_create_vram(): Create a reference to gint_vram @@ -234,7 +228,7 @@ image_t *image_create(int width, int height, int format, int alpha); account for this option. (Using this function twice then replacing one of the [data] pointers is allowed.) - The VRAM image ows no data but it does own its own structure so it must + The VRAM image owns no data but it does own its own structure so it must still be freed with image_free() after use. */ image_t *image_create_vram(void); @@ -269,6 +263,17 @@ uint16_t *image_copy_palette(image_t const *img); pointer, and for palette formats a valid palette pointer. */ bool image_valid(image_t const *img); +/* image_alpha(): Get the alpha value for an image format + + This function returns the alpha value for any specific image format: + * RGB16: 0x0001 + * P8: -128 (0x80) + * P4: 0 + For non-transparent formats, it returns a value that is different from all + valid pixel values of the format, which means it is always safe to compare a + pixel value to the image_alpha() of the format. */ +int image_alpha(int format); + /* image_get_pixel(): Read a pixel from the data array This function reads a pixel from the image's data array at position (x,y). @@ -318,11 +323,10 @@ int image_palette_size(image_t const *img); Formats: RGB16, P8, P4 */ void image_set_pixel(image_t const *img, int x, int y, int value); -/* image_copy(): Copy an image into another one +/* image_copy(): Convert and copy an image - This function copies an image into another image. The target must be a valid - image with the same format as the source, otherwise this function is a - no-op. Unlike transforms, this function does clip, so there are no + This function copies an image into another image while converting certain + formats. Unlike transforms, this function does clip, so there are no conditions on the size of the target. If [copy_alpha] is true, transparent pixels are copied verbatim, which @@ -330,14 +334,23 @@ void image_set_pixel(image_t const *img, int x, int y, int value); transparent pixels of [src] are skipped, effectively rendering [src] over the top-left corner of [src]. - The color scheme of src and dst should normally match. In RGB16, if - src->alpha and dst->alpha differ, this function adopts a resonable behavior; - inputs of value src->alpha are turned into dst->alpha if copy_alpha is true, - ignored otherwise; and opaque inputs of value dst->alpha are turned into - [dst->alpha ^ 1] to keep the visuals consistent. In P8, no attempt is made - to merge the palettes. + This function converts between all formats except from RGB16 to P8/P4, since + this requires generating a palette (which is a complex endeavour). + Conversions from P8/P4 to RGB16 simply decode the palette. Conversions + between P8/P4 preserve the contents but renumber the palette entries. From + P4 to P8, the image is always preserved. From P8 to P4, the image is only + preserved if it has less than 16 colors (this is intended to allow P4 images + to be converted to P8 for edition by this library, and then back to P4). The + following table summarizes the conversions: - Formats: RGB16, P8 */ + Source format → RGB16 P8 P4 + Target format ↓ +-----------+----------------+------------------+ + RGB16 | Copy Decode palette Decode palette | + P8 | - Copy Enlarge palette | + P4 | - Narrow palette Copy | + +-----------+----------------+------------------+ + + Formats: RGB16 → RGB16, P8 → Anything, P4 → Anything */ void image_copy(image_t const *src, image_t *dst, bool copy_alpha); /* image_fill(): Fill an image with a single pixel value */ diff --git a/src/image/image_alloc.c b/src/image/image_alloc.c index 940089a..5856f81 100644 --- a/src/image/image_alloc.c +++ b/src/image/image_alloc.c @@ -3,9 +3,9 @@ #include image_t *image_alloc(int width, int height, int format, - void *palette, int palette_size, int alpha) + void *palette, int palette_size) { - image_t *img = image_create(width, height, format, alpha); + image_t *img = image_create(width, height, format); if(!img) return NULL; diff --git a/src/image/image_alpha.c b/src/image/image_alpha.c new file mode 100644 index 0000000..baa45e6 --- /dev/null +++ b/src/image/image_alpha.c @@ -0,0 +1,15 @@ +#include + +int image_alpha(int format) +{ + switch(format) { + case IMAGE_RGB565A: + return 0x0001; + case IMAGE_P8_RGB565A: + return -128; + case IMAGE_P4_RGB565A: + return 0; + default: + return 0x10000; + } +} diff --git a/src/image/image_clear.c b/src/image/image_clear.c index e5b86a4..1144e02 100644 --- a/src/image/image_clear.c +++ b/src/image/image_clear.c @@ -5,5 +5,5 @@ void image_clear(image_t *img) if(!IMAGE_IS_ALPHA(img->format)) return; - image_fill(img, img->alpha); + image_fill(img, image_alpha(img->format)); } diff --git a/src/image/image_copy.c b/src/image/image_copy.c index f813227..8825d28 100644 --- a/src/image/image_copy.c +++ b/src/image/image_copy.c @@ -16,26 +16,20 @@ void image_copy(image_t const *src, image_t *dst, bool copy_alpha) void *src_px = src->data; void *dst_px = dst->data; + int src_alpha = copy_alpha ? 0x10000 : image_alpha(src->format); if(IMAGE_IS_RGB16(src->format)) { - int src_alpha = copy_alpha ? -1 : src->alpha; - int dst_alpha = IMAGE_IS_ALPHA(dst->format) ? -1 : dst->alpha; - do { for(int x = 0; x < w; x++) { int px = ((uint16_t *)src_px)[x]; - if(px != src_alpha) { - px ^= (px == dst_alpha); + if(px != src_alpha) ((uint16_t *)dst_px)[x] = px; - } } src_px += src->stride; dst_px += dst->stride; } while(--h > 0); } else if(IMAGE_IS_P8(src->format)) { - int src_alpha = copy_alpha ? 256 : src->alpha; - do { for(int x = 0; x < w; x++) { int px = ((int8_t *)src_px)[x]; diff --git a/src/image/image_create.c b/src/image/image_create.c index 82332f8..f36c49f 100644 --- a/src/image/image_create.c +++ b/src/image/image_create.c @@ -1,7 +1,7 @@ #include #include -image_t *image_create(int width, int height, int format, int alpha) +image_t *image_create(int width, int height, int format) { if(!IMAGE_IS_RGB16(format) && !IMAGE_IS_P8(format) && !IMAGE_IS_P4(format)) return NULL; @@ -14,7 +14,6 @@ image_t *image_create(int width, int height, int format, int alpha) img->format = format; img->flags = 0; - img->alpha = alpha; img->width = width; img->height = height; diff --git a/src/image/image_create_vram.c b/src/image/image_create_vram.c index e7c697b..03e7fdc 100644 --- a/src/image/image_create_vram.c +++ b/src/image/image_create_vram.c @@ -3,7 +3,7 @@ image_t *image_create_vram(void) { - image_t *img = image_create(DWIDTH, DHEIGHT, IMAGE_RGB565, 0); + image_t *img = image_create(DWIDTH, DHEIGHT, IMAGE_RGB565); if(!img) return NULL; diff --git a/src/image/image_get_pixel.c b/src/image/image_get_pixel.c index ab9fb4f..9e36b74 100644 --- a/src/image/image_get_pixel.c +++ b/src/image/image_get_pixel.c @@ -13,7 +13,7 @@ int image_get_pixel(image_t const *img, int x, int y) return data_u16[x]; } else if(IMAGE_IS_P8(img->format)) { - return data_u8[x]; + return (int8_t)data_u8[x]; } else if(IMAGE_IS_P4(img->format)) { if(x & 1) diff --git a/src/image/image_sub.c b/src/image/image_sub.c index f548c67..7e55646 100644 --- a/src/image/image_sub.c +++ b/src/image/image_sub.c @@ -24,7 +24,6 @@ image_t *image_sub(image_t const *src, int left, int top, int w, int h, int const ro_flags = IMAGE_FLAGS_DATA_RO | IMAGE_FLAGS_PALETTE_RO; dst->format = src->format; dst->flags = src->flags & ro_flags; - dst->alpha = src->alpha; dst->stride = src->stride; dst->width = box.w; dst->height = box.h; diff --git a/src/render-cg/image/image_p4.c b/src/render-cg/image/image_p4.c index e637c0d..d29fe4f 100644 --- a/src/render-cg/image/image_p4.c +++ b/src/render-cg/image/image_p4.c @@ -11,7 +11,7 @@ void dsubimage_p4(int x, int y, image_t const *img, { if(img->format == IMAGE_P4_RGB565A) return dsubimage_p4_clearbg(x, y, img, left, top, w, h, eff, - img->alpha); + image_alpha(img->format)); struct gint_image_box box = { x, y, w, h, left, top }; struct gint_image_cmd cmd; diff --git a/src/render-cg/image/image_p4_dye.c b/src/render-cg/image/image_p4_dye.c index f47adeb..d0393a5 100644 --- a/src/render-cg/image/image_p4_dye.c +++ b/src/render-cg/image/image_p4_dye.c @@ -15,7 +15,7 @@ void dsubimage_p4_dye(int x, int y, image_t const *img, if(!gint_image_mkcmd(&box, img, eff, true, true, &cmd, DWIDTH, DHEIGHT)) return; - cmd.color_1 = img->alpha; + cmd.color_1 = image_alpha(img->format); cmd.color_2 = dye_color; cmd.loop = gint_image_p4_dye; gint_image_p4_loop(DWIDTH, &cmd); diff --git a/src/render-cg/image/image_p4_swapcolor.c b/src/render-cg/image/image_p4_swapcolor.c index cd2e2d1..9010afa 100644 --- a/src/render-cg/image/image_p4_swapcolor.c +++ b/src/render-cg/image/image_p4_swapcolor.c @@ -37,7 +37,7 @@ void dsubimage_p4_addbg(int x, int y, image_t const *img, if(!gint_image_mkcmd(&box, img, eff, true, true, &cmd, DWIDTH, DHEIGHT)) return; - cmd.color_1 = img->alpha; + cmd.color_1 = image_alpha(img->format); cmd.color_2 = bg_color; cmd.loop = gint_image_p4_swapcolor; gint_image_p4_loop(DWIDTH, &cmd); diff --git a/src/render-cg/image/image_p8.c b/src/render-cg/image/image_p8.c index ae62ec5..89c6bc3 100644 --- a/src/render-cg/image/image_p8.c +++ b/src/render-cg/image/image_p8.c @@ -11,7 +11,7 @@ void dsubimage_p8(int x, int y, image_t const *img, { if(img->format == IMAGE_P8_RGB565A) return dsubimage_p8_clearbg(x, y, img, left, top, w, h, eff, - img->alpha); + image_alpha(img->format)); struct gint_image_box box = { x, y, w, h, left, top }; struct gint_image_cmd cmd; diff --git a/src/render-cg/image/image_p8_dye.c b/src/render-cg/image/image_p8_dye.c index 38b9d77..3fc9e68 100644 --- a/src/render-cg/image/image_p8_dye.c +++ b/src/render-cg/image/image_p8_dye.c @@ -15,7 +15,7 @@ void dsubimage_p8_dye(int x, int y, image_t const *img, if(!gint_image_mkcmd(&box, img, eff, false, true, &cmd, DWIDTH, DHEIGHT)) return; - cmd.color_1 = img->alpha; + cmd.color_1 = image_alpha(img->format); cmd.color_2 = dye_color; cmd.loop = gint_image_p8_dye; gint_image_p8_loop(DWIDTH, &cmd); diff --git a/src/render-cg/image/image_p8_swapcolor.c b/src/render-cg/image/image_p8_swapcolor.c index 2c85409..fddb7c9 100644 --- a/src/render-cg/image/image_p8_swapcolor.c +++ b/src/render-cg/image/image_p8_swapcolor.c @@ -37,7 +37,7 @@ void dsubimage_p8_addbg(int x, int y, image_t const *img, if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH, DHEIGHT)) return; - cmd.color_1 = img->alpha; + cmd.color_1 = image_alpha(img->format); cmd.color_2 = bg_color; cmd.loop = gint_image_p8_swapcolor; gint_image_p8_loop(DWIDTH, &cmd); diff --git a/src/render-cg/image/image_rgb16.c b/src/render-cg/image/image_rgb16.c index 9b9e6b2..83550f6 100644 --- a/src/render-cg/image/image_rgb16.c +++ b/src/render-cg/image/image_rgb16.c @@ -11,7 +11,7 @@ void dsubimage_rgb16(int x, int y, image_t const *img, { if(img->format == IMAGE_RGB565A) return dsubimage_rgb16_clearbg(x, y, img, left, top, w, h, eff, - img->alpha); + image_alpha(img->format)); struct gint_image_box box = { x, y, w, h, left, top }; struct gint_image_cmd cmd; diff --git a/src/render-cg/image/image_rgb16_dye.c b/src/render-cg/image/image_rgb16_dye.c index 4fc19c9..bfc884c 100644 --- a/src/render-cg/image/image_rgb16_dye.c +++ b/src/render-cg/image/image_rgb16_dye.c @@ -15,7 +15,7 @@ void dsubimage_rgb16_dye(int x, int y, image_t const *img, if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH, DHEIGHT)) return; - cmd.color_1 = img->alpha; + cmd.color_1 = image_alpha(img->format); cmd.color_2 = dye_color; cmd.loop = gint_image_rgb16_dye; gint_image_rgb16_loop(DWIDTH, &cmd); diff --git a/src/render-cg/image/image_rgb16_swapcolor.c b/src/render-cg/image/image_rgb16_swapcolor.c index 74322ff..71e71a5 100644 --- a/src/render-cg/image/image_rgb16_swapcolor.c +++ b/src/render-cg/image/image_rgb16_swapcolor.c @@ -37,7 +37,7 @@ void dsubimage_rgb16_addbg(int x, int y, image_t const *img, if(!gint_image_mkcmd(&box, img, eff, false, false, &cmd, DWIDTH, DHEIGHT)) return; - cmd.color_1 = img->alpha; + cmd.color_1 = image_alpha(img->format); cmd.color_2 = bg_color; cmd.loop = gint_image_rgb16_swapcolor; gint_image_rgb16_loop(DWIDTH, &cmd);