diff options
| author | Mikhail Romanko <me@blankhex.com> | 2025-08-04 12:33:44 +0300 |
|---|---|---|
| committer | Mikhail Romanko <me@blankhex.com> | 2025-08-04 12:38:17 +0300 |
| commit | 0da77c00d652c13a99961d845a0a593dc54f1e49 (patch) | |
| tree | 8a7bef35a1d52dee6613005ccd3e24211cc233f7 | |
| parent | 9c593932a371d4df6198e04544f214224050cf11 (diff) | |
| download | bhlib-0da77c00d652c13a99961d845a0a593dc54f1e49.tar.gz | |
Refactor bitmap, add new formats
Small refactoring of the bitmap module and added more indexed formats.
| -rw-r--r-- | doc/Manual/en/BH_Bitmap.pod | 43 | ||||
| -rw-r--r-- | doc/Manual/ru/BH_Bitmap.pod | 43 | ||||
| -rw-r--r-- | include/BH/Bitmap.h | 40 | ||||
| -rw-r--r-- | src/Bitmap.c | 636 |
4 files changed, 571 insertions, 191 deletions
diff --git a/doc/Manual/en/BH_Bitmap.pod b/doc/Manual/en/BH_Bitmap.pod index 1dd603b..08441a8 100644 --- a/doc/Manual/en/BH_Bitmap.pod +++ b/doc/Manual/en/BH_Bitmap.pod @@ -25,6 +25,18 @@ Currently, the following pixel formats are supported: =over +=item B<BH_BITMAP_INDEX1> + +1-bit indexed/paletted + +=item B<BH_BITMAP_INDEX2> + +2-bit indexed/paletted + +=item B<BH_BITMAP_INDEX4> + +4-bit indexed/paletted + =item B<BH_BITMAP_INDEX8> 8-bit indexed/paletted @@ -74,11 +86,17 @@ Currently, the following pixel formats are supported: All pixel formats use the current machine endianness. -The flag I<BH_BITMAP_BGR> can be used to change the order of the color channels +The flag I<BH_BITMAP_BGR> can be used to change the order of the color channels (RGB -> BGR). The flag has no effect on the following pixel formats: +I<BH_BITMAP_INDEX1>, I<BH_BITMAP_INDEX2>, I<BH_BITMAP_INDEX4>, I<BH_BITMAP_INDEX8>, I<BH_BITMAP_GRAY8>, I<BH_BITMAP_GRAY16>, I<BH_BITMAP_RGBA32> and I<BH_BITMAP_RGBA64>. +The flag I<BH_BITMAP_LSB> can be used to change the start of the bit order for +indexed images. This flag only affects the following pixel formats: +I<BH_BITMAP_INDEX1>, I<BH_BITMAP_INDEX2>, I<BH_BITMAP_INDEX4> and +I<BH_BITMAP_INDEX8>. + The flag I<BH_BITMAP_NOALPHA> can be used to indicate that the alpha channel is not used and should always be set to the maximum value (255 for 8-bit and 65535 for 16-bit). @@ -152,6 +170,29 @@ Writes color value of the pixel at specified position. The I<x> and I<y> parameters specify a position on the bitmap. +=head2 BH_BitmapIndex + + uint8_t BH_BitmapIndex(const BH_Bitmap *bitmap, + int x, + int y); + +Returns the index value at the specified position. + +The I<x> and I<y> parameters specify a position on the bitmap. + + +=head2 BH_BitmapSetIndex + + void BH_BitmapSetIndex(BH_Bitmap *bitmap, + int x, + int y, + uint8_t index); + +Sets the index value at the specified position. + +The I<x> and I<y> parameters specify a position on the bitmap. + + =head2 BH_BitmapCopy BH_Bitmap *BH_BitmapCopy(BH_Bitmap *bitmap, diff --git a/doc/Manual/ru/BH_Bitmap.pod b/doc/Manual/ru/BH_Bitmap.pod index 566f14f..4771770 100644 --- a/doc/Manual/ru/BH_Bitmap.pod +++ b/doc/Manual/ru/BH_Bitmap.pod @@ -25,6 +25,18 @@ BH_Bitmap - доступ к растровому изображению/карт =over +=item B<BH_BITMAP_INDEX1> + +1-разрядный индексированный/палитрированный + +=item B<BH_BITMAP_INDEX2> + +2-разрядный индексированный/палитрированный + +=item B<BH_BITMAP_INDEX4> + +4-разрядный индексированный/палитрированный + =item B<BH_BITMAP_INDEX8> 8-разрядный индексированный/палитрированный @@ -77,9 +89,15 @@ BH_Bitmap - доступ к растровому изображению/карт Флаг I<BH_BITMAP_BGR> может использоваться для изменения порядка цветовых каналов (RGB -> BGR). Этот флаг не влияет на следующие пиксельные форматы: +I<BH_BITMAP_INDEX1>, I<BH_BITMAP_INDEX2>, I<BH_BITMAP_INDEX4>, I<BH_BITMAP_INDEX8>, I<BH_BITMAP_GRAY8>, I<BH_BITMAP_GRAY16>, I<BH_BITMAP_RGBA32> и I<BH_BITMAP_RGBA64>. +Флаг I<BH_BITMAP_LSB> может использоваться для изменения начала отсчета порядка +бит для индексированных изображений. Этот флаг влияет только на следующие +пиксельные форматы: I<BH_BITMAP_INDEX1>, I<BH_BITMAP_INDEX2>, +I<BH_BITMAP_INDEX4> и I<BH_BITMAP_INDEX8>. + Флаг I<BH_BITMAP_NOALPHA> может использоваться для указания того, что альфа-канал не используется и всегда должен быть установлен в максимальное значение (255 для 8-разрядных и 65535 для 16-разрядных). @@ -155,7 +173,30 @@ I<BH_BITMAP_RGBA32> и I<BH_BITMAP_RGBA64>. Записывает значение цвета пикселя в указанной позиции. -Параметры I<x> и I<y> определяют положение на растровой карте. +Параметры I<x> и I<y> определяют положение на растровом изображении. + + +=head2 BH_BitmapIndex + + uint8_t BH_BitmapIndex(const BH_Bitmap *bitmap, + int x, + int y); + +Возвращает значение индекса в указанной позиции. + +Параметры I<x> и I<y> определяют положение на растровом изображении. + + +=head2 BH_BitmapSetIndex + +void BH_BitmapSetIndex(BH_Bitmap *bitmap, + int x, + int y, + uint8_t index); + +Устанавливает значение индекса в указанной позиции. + +Параметры I<x> и I<y> определяют положение на растровом изображении. =head2 BH_BitmapCopy diff --git a/include/BH/Bitmap.h b/include/BH/Bitmap.h index b1ec661..8098714 100644 --- a/include/BH/Bitmap.h +++ b/include/BH/Bitmap.h @@ -12,19 +12,22 @@ typedef struct BH_Bitmap BH_Bitmap; #define BH_BITMAP_PREMULT 0x1000 #define BH_BITMAP_NOALPHA 0x2000 #define BH_BITMAP_BGR 0x4000 - - -#define BH_BITMAP_INDEX8 0x0000 -#define BH_BITMAP_GRAY8 0x0001 -#define BH_BITMAP_GRAY16 0x0002 -#define BH_BITMAP_RGBA32 0x0003 -#define BH_BITMAP_RGBA64 0x0004 -#define BH_BITMAP_RGB565 0x8000 -#define BH_BITMAP_RGB888 0x8001 -#define BH_BITMAP_RGBA8888 0x8002 -#define BH_BITMAP_RGB161616 0x8003 -#define BH_BITMAP_RGBA16161616 0x8004 -#define BH_BITMAP_RGBA1010102 0x8005 +#define BH_BITMAP_LSB 0x8000 + +#define BH_BITMAP_INDEX1 0x0000 +#define BH_BITMAP_INDEX2 0x0001 +#define BH_BITMAP_INDEX4 0x0002 +#define BH_BITMAP_INDEX8 0x0003 +#define BH_BITMAP_GRAY8 0x0004 +#define BH_BITMAP_GRAY16 0x0005 +#define BH_BITMAP_RGBA32 0x0006 +#define BH_BITMAP_RGBA64 0x0007 +#define BH_BITMAP_RGB565 0x0008 +#define BH_BITMAP_RGB888 0x0009 +#define BH_BITMAP_RGBA8888 0x000A +#define BH_BITMAP_RGB161616 0x000B +#define BH_BITMAP_RGBA16161616 0x000C +#define BH_BITMAP_RGBA1010102 0x000D #define BH_BITMAP_FLAG_ALIGN32 0x0001 @@ -55,6 +58,17 @@ void BH_BitmapSetColor(BH_Bitmap *bitmap, const BH_Color *value); +uint8_t BH_BitmapIndex(const BH_Bitmap *bitmap, + int x, + int y); + + +void BH_BitmapSetIndex(BH_Bitmap *bitmap, + int x, + int y, + uint8_t index); + + BH_Bitmap *BH_BitmapCopy(BH_Bitmap *bitmap, int x, int y, diff --git a/src/Bitmap.c b/src/Bitmap.c index 2b908ad..85d6b99 100644 --- a/src/Bitmap.c +++ b/src/Bitmap.c @@ -20,10 +20,87 @@ struct BH_Bitmap }; -static size_t stepFromFormat(int format) +/* Bit and unit order arrays for working with RGB/BGR and MSB/LSB */ +static const size_t bitOrder1[][8] = { - switch (format & 0x8FFF) + {7, 6, 5, 4, 3, 2, 1, 0}, + {0, 1, 2, 3, 4, 5, 6, 7}, +}; + + +static const size_t bitMask1[][8] = +{ + {0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01}, + {0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80}, +}; + + +static const size_t bitOrder2[][4] = +{ + {6, 4, 2, 0}, + {0, 2, 4, 6}, +}; + + +static const size_t bitMask2[][4] = +{ + {0xC0, 0x30, 0x0C, 0x03}, + {0x03, 0x0C, 0x30, 0xC0}, +}; + + +static const size_t bitOrder4[][2] = +{ + {4, 0}, + {0, 4}, +}; + + +static const size_t bitMask4[][2] = +{ + {0xF0, 0x0F}, + {0x0F, 0xF0}, +}; + + +static const size_t bitOrder565[][3] = +{ + {11, 5, 0}, + {0, 5, 11}, +}; + + +static const size_t bitOrder1010102[][4] = +{ + {0, 10, 20, 30}, + {20, 10, 0, 30}, +}; + + +static const size_t unitOrderRGB[][3] = +{ + {0, 1, 2}, + {2, 1, 0}, +}; + + +static const size_t unitOrderRGBA[][4] = +{ + {0, 1, 2, 3}, + {2, 1, 0, 3}, +}; + + +/* Private functions */ +static size_t calculateStep(int format) +{ + switch (format & 0x0FFF) { + case BH_BITMAP_INDEX1: + case BH_BITMAP_INDEX2: + case BH_BITMAP_INDEX4: + return 0; + case BH_BITMAP_INDEX8: case BH_BITMAP_GRAY8: return 1; @@ -52,117 +129,115 @@ static size_t stepFromFormat(int format) } -BH_Bitmap *BH_BitmapNew(int width, - int height, - int format, - int flags, - void *data, - void *palette) +static uint8_t bitmapIndex(void *data, + int format, + int x) { - BH_Bitmap *result; - int needPalette; - size_t header, body, trailer, stride, step; + int isLSB; + uint8_t octet; - /* Unset internal flags */ - flags &= ~BH_BITMAP_FLAG_EXT_DATA; - flags &= ~BH_BITMAP_FLAG_EXT_PALETTE; + isLSB = (format & BH_BITMAP_LSB) > 0; + switch (format & 0x0FFF) + { + case BH_BITMAP_INDEX1: + octet = (*(uint8_t *)data) & bitMask1[isLSB][x & 7]; + return octet >> bitOrder1[isLSB][x & 7]; - /* Calculate size of the bitmap with headers */ - needPalette = (format & 0x8FFF) == BH_BITMAP_INDEX8; - step = stepFromFormat(format); - stride = step * width; - if (flags & BH_BITMAP_FLAG_ALIGN32) - stride = (stride + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1); + case BH_BITMAP_INDEX2: + octet = (*(uint8_t *)data) & bitMask2[isLSB][x & 3]; + return octet >> bitOrder2[isLSB][x & 3]; - header = sizeof(*result); - header = (header + (sizeof(uint64_t) - 1)) & ~(sizeof(uint64_t) - 1); - body = (stride * height + (sizeof(uint32_t) - 1)) & ~(sizeof(uint32_t) - 1); - trailer = sizeof(uint32_t) * 256; - - /* Adjust body and trailer size if ext data or palette is provided */ - if (!needPalette) - trailer = 0; + case BH_BITMAP_INDEX4: + octet = (*(uint8_t *)data) & bitMask4[isLSB][x & 1]; + return octet >> bitOrder4[isLSB][x & 1]; - if (palette) - { - flags |= BH_BITMAP_FLAG_EXT_PALETTE; - trailer = 0; - } - - if (data) - { - flags |= BH_BITMAP_FLAG_EXT_DATA; - body = 0; + case BH_BITMAP_INDEX8: + return *(uint8_t *)data; } - /* Allocate and setup bitmap data */ - result = malloc(header + body + trailer); - if (!result) - return NULL; + return 0; +} - if (!data) - data = (uint8_t *)result + header; - if (!palette && needPalette) - palette = (uint8_t *)result + header + body; +static void setBitmapIndex(void *data, + int format, + int x, + uint8_t index) +{ + int isLSB; + uint8_t octet; - result->width = width; - result->height = height; - result->format = format; - result->flags = flags; - result->step = step; - result->stride = stride; - result->data = data; - result->palette = palette; + isLSB = (format & BH_BITMAP_LSB) > 0; + switch (format & 0x0FFF) + { + case BH_BITMAP_INDEX1: + octet = (*(uint8_t *)data) & ~bitMask1[isLSB][x & 7]; + octet |= (index & 0x1) << bitOrder1[isLSB][x & 7]; + *(uint8_t *)data = octet; + break; - return result; -} + case BH_BITMAP_INDEX2: + octet = (*(uint8_t *)data) & ~bitMask2[isLSB][x & 3]; + octet |= (index & 0x3) << bitOrder2[isLSB][x & 3]; + *(uint8_t *)data = octet; + break; + case BH_BITMAP_INDEX4: + octet = (*(uint8_t *)data) & ~bitMask4[isLSB][x & 1]; + octet |= (index & 0xF) << bitOrder4[isLSB][x & 1]; + *(uint8_t *)data = octet; + break; -void BH_BitmapFree(BH_Bitmap *bitmap) -{ - free(bitmap); + case BH_BITMAP_INDEX8: + *(uint8_t *)data = index; + break; + } } -static const size_t bitOrder565[][3] = -{ - {11, 5, 0}, - {0, 5, 11}, -}; - - -static const size_t bitOrder1010102[][4] = +static void bitmapColor(void *data, + void *palette, + int format, + BH_Color *value, + int x) { - {0, 10, 20, 30}, - {20, 10, 0, 30}, -}; + switch (format & 0x0FFF) + { + case BH_BITMAP_INDEX1: + { + uint32_t color; + color = ((uint32_t *)palette)[bitmapIndex(data, format, x)]; + BH_ColorSetRGBA8(value, color >> 16 & 0xFF, color >> 8 & 0xFF, + color & 0xFF, color >> 24 & 0xFF); + } + break; -static const size_t unitOrderRGB[][3] = -{ - {0, 1, 2}, - {2, 1, 0}, -}; + case BH_BITMAP_INDEX2: + { + uint32_t color; + color = ((uint32_t *)palette)[bitmapIndex(data, format, x)]; + BH_ColorSetRGBA8(value, color >> 16 & 0xFF, color >> 8 & 0xFF, + color & 0xFF, color >> 24 & 0xFF); + } + break; -static const size_t unitOrderRGBA[][4] = -{ - {0, 1, 2, 3}, - {2, 1, 0, 3}, -}; + case BH_BITMAP_INDEX4: + { + uint32_t color; + color = ((uint32_t *)palette)[bitmapIndex(data, format, x)]; + BH_ColorSetRGBA8(value, color >> 16 & 0xFF, color >> 8 & 0xFF, + color & 0xFF, color >> 24 & 0xFF); + } + break; -static void color(void *data, - void *palette, - int format, - BH_Color *value) -{ - switch (format & 0x8FFF) - { case BH_BITMAP_INDEX8: { - uint32_t color = ((uint32_t *)palette)[*(uint8_t *)data]; + uint32_t color; + color = ((uint32_t *)palette)[bitmapIndex(data, format, x)]; + BH_ColorSetRGBA8(value, color >> 16 & 0xFF, color >> 8 & 0xFF, color & 0xFF, color >> 24 & 0xFF); } @@ -170,21 +245,27 @@ static void color(void *data, case BH_BITMAP_GRAY8: { - uint8_t color = *(uint8_t *)data; + uint8_t color; + + color = *(uint8_t *)data; BH_ColorSetRGBA8(value, color, color, color, 0xFF); } break; case BH_BITMAP_GRAY16: { - uint16_t color = *(uint16_t *)data; + uint16_t color; + + color = *(uint16_t *)data; BH_ColorSetRGBA16(value, color, color, color, 0xFFFF); } break; case BH_BITMAP_RGBA32: { - uint32_t color = *(uint32_t *)data; + uint32_t color; + + color = *(uint32_t *)data; BH_ColorSetRGBA8(value, color >> 16 & 0xFF, color >> 8 & 0xFF, color & 0xFF, color >> 24 & 0xFF); } @@ -192,7 +273,9 @@ static void color(void *data, case BH_BITMAP_RGBA64: { - uint64_t color = *(uint64_t *)data; + uint64_t color; + + color = *(uint64_t *)data; BH_ColorSetRGBA16(value, color >> 32 & 0xFFFF, color >> 16 & 0xFFFF, color & 0xFFFF, color >> 48 & 0xFFFF); } @@ -201,16 +284,18 @@ static void color(void *data, case BH_BITMAP_RGB565: { uint8_t r, g, b; - uint16_t color = *(uint16_t *)data; - int orderSelector = (format & BH_BITMAP_BGR) > 0; - - r = color >> bitOrder565[orderSelector][0] & 0x1F; - g = color >> bitOrder565[orderSelector][1] & 0x3F; - b = color >> bitOrder565[orderSelector][2] & 0x1F; + uint16_t color; + int isBGR; + color = *(uint16_t *)data; + isBGR = (format & BH_BITMAP_BGR) > 0; + r = color >> bitOrder565[isBGR][0] & 0x1F; + g = color >> bitOrder565[isBGR][1] & 0x3F; + b = color >> bitOrder565[isBGR][2] & 0x1F; r = r << 3 | r >> 2; g = g << 2 | g >> 4; b = b << 3 | b >> 2; + BH_ColorSetRGBA8(value, r, g, b, 0xFF); } break; @@ -218,11 +303,13 @@ static void color(void *data, case BH_BITMAP_RGB888: { uint8_t r, g, b; - int orderSelector = (format & BH_BITMAP_BGR) > 0; + int isBGR; + + isBGR = (format & BH_BITMAP_BGR) > 0; + r = ((uint8_t *)data)[unitOrderRGB[isBGR][0]]; + g = ((uint8_t *)data)[unitOrderRGB[isBGR][1]]; + b = ((uint8_t *)data)[unitOrderRGB[isBGR][2]]; - r = ((uint8_t *)data)[unitOrderRGB[orderSelector][0]]; - g = ((uint8_t *)data)[unitOrderRGB[orderSelector][1]]; - b = ((uint8_t *)data)[unitOrderRGB[orderSelector][2]]; BH_ColorSetRGBA8(value, r, g, b, 0xFF); } break; @@ -230,12 +317,14 @@ static void color(void *data, case BH_BITMAP_RGBA8888: { uint8_t r, g, b, a; - int orderSelector = (format & BH_BITMAP_BGR) > 0; + int isBGR; + + isBGR = (format & BH_BITMAP_BGR) > 0; + r = ((uint8_t *)data)[unitOrderRGBA[isBGR][0]]; + g = ((uint8_t *)data)[unitOrderRGBA[isBGR][1]]; + b = ((uint8_t *)data)[unitOrderRGBA[isBGR][2]]; + a = ((uint8_t *)data)[unitOrderRGBA[isBGR][3]]; - r = ((uint8_t *)data)[unitOrderRGBA[orderSelector][0]]; - g = ((uint8_t *)data)[unitOrderRGBA[orderSelector][1]]; - b = ((uint8_t *)data)[unitOrderRGBA[orderSelector][2]]; - a = ((uint8_t *)data)[unitOrderRGBA[orderSelector][3]]; BH_ColorSetRGBA8(value, r, g, b, a); } break; @@ -243,11 +332,13 @@ static void color(void *data, case BH_BITMAP_RGB161616: { uint16_t r, g, b; - int orderSelector = (format & BH_BITMAP_BGR) > 0; + int isBGR; + + isBGR = (format & BH_BITMAP_BGR) > 0; + r = ((uint16_t *)data)[unitOrderRGB[isBGR][0]]; + g = ((uint16_t *)data)[unitOrderRGB[isBGR][1]]; + b = ((uint16_t *)data)[unitOrderRGB[isBGR][2]]; - r = ((uint16_t *)data)[unitOrderRGB[orderSelector][0]]; - g = ((uint16_t *)data)[unitOrderRGB[orderSelector][1]]; - b = ((uint16_t *)data)[unitOrderRGB[orderSelector][2]]; BH_ColorSetRGBA16(value, r, g, b, 0xFFFF); } break; @@ -255,12 +346,14 @@ static void color(void *data, case BH_BITMAP_RGBA16161616: { uint16_t r, g, b, a; - int orderSelector = (format & BH_BITMAP_BGR) > 0; + int isBGR; + + isBGR = (format & BH_BITMAP_BGR) > 0; + r = ((uint16_t *)data)[unitOrderRGBA[isBGR][0]]; + g = ((uint16_t *)data)[unitOrderRGBA[isBGR][1]]; + b = ((uint16_t *)data)[unitOrderRGBA[isBGR][2]]; + a = ((uint16_t *)data)[unitOrderRGBA[isBGR][3]]; - r = ((uint16_t *)data)[unitOrderRGBA[orderSelector][0]]; - g = ((uint16_t *)data)[unitOrderRGBA[orderSelector][1]]; - b = ((uint16_t *)data)[unitOrderRGBA[orderSelector][2]]; - a = ((uint16_t *)data)[unitOrderRGBA[orderSelector][3]]; BH_ColorSetRGBA16(value, r, g, b, a); } break; @@ -268,20 +361,22 @@ static void color(void *data, case BH_BITMAP_RGBA1010102: { uint16_t r, g, b, a; - uint32_t color = *(uint32_t *)data; - int orderSelector = (format & BH_BITMAP_BGR) > 0; - - r = color >> bitOrder1010102[orderSelector][0] & 0x3FF; - g = color >> bitOrder1010102[orderSelector][1] & 0x3FF; - b = color >> bitOrder1010102[orderSelector][2] & 0x3FF; - a = color >> bitOrder1010102[orderSelector][3] & 0x3; - + uint32_t color; + int isBGR; + + color = *(uint32_t *)data; + isBGR = (format & BH_BITMAP_BGR) > 0; + r = color >> bitOrder1010102[isBGR][0] & 0x3FF; + g = color >> bitOrder1010102[isBGR][1] & 0x3FF; + b = color >> bitOrder1010102[isBGR][2] & 0x3FF; + a = color >> bitOrder1010102[isBGR][3] & 0x3; r = r << 6 | r >> 4; g = g << 6 | g >> 4; b = b << 6 | b >> 4; a = a << 2 | a; a = a << 4 | a; a = a << 8 | a; + BH_ColorSetRGBA16(value, r, g, b, a); } break; @@ -293,16 +388,17 @@ static void color(void *data, } -static size_t bestIndex(uint8_t r, - uint8_t g, - uint8_t b, - uint8_t a, - const uint32_t *palette) +static size_t bestPaletteIndex(uint8_t r, + uint8_t g, + uint8_t b, + uint8_t a, + const uint32_t *palette, + size_t paletteSize) { uint32_t bestError = -1; size_t i, bestIndex = 0; - for (i = 0; i < 256; ++i) { + for (i = 0; i < paletteSize; ++i) { int32_t dr, dg, db, da; uint32_t currentError; @@ -323,19 +419,47 @@ static size_t bestIndex(uint8_t r, } -static void setColor(void *data, - void *palette, - int format, - const BH_Color *value) +static void setBitmapColor(void *data, + void *palette, + int format, + const BH_Color *value, + int x) { - switch (format & 0x8FFF) + switch (format & 0x0FFF) { + case BH_BITMAP_INDEX1: + { + uint8_t r, g, b, a; + + BH_ColorRGBA8(value, &r, &g, &b, &a); + setBitmapIndex(data, format, x, bestPaletteIndex(r, g, b, a, palette, 1)); + } + break; + + case BH_BITMAP_INDEX2: + { + uint8_t r, g, b, a; + + BH_ColorRGBA8(value, &r, &g, &b, &a); + setBitmapIndex(data, format, x, bestPaletteIndex(r, g, b, a, palette, 4)); + } + break; + + case BH_BITMAP_INDEX4: + { + uint8_t r, g, b, a; + + BH_ColorRGBA8(value, &r, &g, &b, &a); + setBitmapIndex(data, format, x, bestPaletteIndex(r, g, b, a, palette, 16)); + } + break; + case BH_BITMAP_INDEX8: { uint8_t r, g, b, a; BH_ColorRGBA8(value, &r, &g, &b, &a); - *(uint8_t *)data = bestIndex(r, g, b, a, palette); + setBitmapIndex(data, format, x, bestPaletteIndex(r, g, b, a, palette, 256)); } break; @@ -386,14 +510,15 @@ static void setColor(void *data, case BH_BITMAP_RGB565: { uint8_t r, g, b, a; - int orderSelector = (format & BH_BITMAP_BGR) > 0; uint16_t color; + int isBGR; - color = 0; + isBGR = (format & BH_BITMAP_BGR) > 0; BH_ColorRGBA8(value, &r, &g, &b, &a); - color |= (r >> 3) << bitOrder565[orderSelector][0]; - color |= (g >> 2) << bitOrder565[orderSelector][1]; - color |= (b >> 3) << bitOrder565[orderSelector][2]; + color = 0; + color |= (r >> 3) << bitOrder565[isBGR][0]; + color |= (g >> 2) << bitOrder565[isBGR][1]; + color |= (b >> 3) << bitOrder565[isBGR][2]; *(uint16_t *)(data) = color; } @@ -402,74 +527,79 @@ static void setColor(void *data, case BH_BITMAP_RGB888: { uint8_t r, g, b, a; - int orderSelector = (format & BH_BITMAP_BGR) > 0; + int isBGR; + isBGR = (format & BH_BITMAP_BGR) > 0; BH_ColorRGBA8(value, &r, &g, &b, &a); - ((uint8_t *)data)[unitOrderRGB[orderSelector][0]] = r; - ((uint8_t *)data)[unitOrderRGB[orderSelector][1]] = g; - ((uint8_t *)data)[unitOrderRGB[orderSelector][2]] = b; + ((uint8_t *)data)[unitOrderRGB[isBGR][0]] = r; + ((uint8_t *)data)[unitOrderRGB[isBGR][1]] = g; + ((uint8_t *)data)[unitOrderRGB[isBGR][2]] = b; } break; case BH_BITMAP_RGBA8888: { uint8_t r, g, b, a; - int orderSelector = (format & BH_BITMAP_BGR) > 0; + int isBGR; + isBGR = (format & BH_BITMAP_BGR) > 0; BH_ColorRGBA8(value, &r, &g, &b, &a); if (format & BH_BITMAP_NOALPHA) a = 0xFF; - ((uint8_t *)data)[unitOrderRGBA[orderSelector][0]] = r; - ((uint8_t *)data)[unitOrderRGBA[orderSelector][1]] = g; - ((uint8_t *)data)[unitOrderRGBA[orderSelector][2]] = b; - ((uint8_t *)data)[unitOrderRGBA[orderSelector][3]] = a; + ((uint8_t *)data)[unitOrderRGBA[isBGR][0]] = r; + ((uint8_t *)data)[unitOrderRGBA[isBGR][1]] = g; + ((uint8_t *)data)[unitOrderRGBA[isBGR][2]] = b; + ((uint8_t *)data)[unitOrderRGBA[isBGR][3]] = a; } break; case BH_BITMAP_RGB161616: { uint16_t r, g, b, a; - int orderSelector = (format & BH_BITMAP_BGR) > 0; + int isBGR; + isBGR = (format & BH_BITMAP_BGR) > 0; BH_ColorRGBA16(value, &r, &g, &b, &a); - ((uint16_t *)data)[unitOrderRGB[orderSelector][0]] = r; - ((uint16_t *)data)[unitOrderRGB[orderSelector][1]] = g; - ((uint16_t *)data)[unitOrderRGB[orderSelector][2]] = b; + ((uint16_t *)data)[unitOrderRGB[isBGR][0]] = r; + ((uint16_t *)data)[unitOrderRGB[isBGR][1]] = g; + ((uint16_t *)data)[unitOrderRGB[isBGR][2]] = b; } break; case BH_BITMAP_RGBA16161616: { uint16_t r, g, b, a; - int orderSelector = (format & BH_BITMAP_BGR) > 0; + int isBGR; + isBGR = (format & BH_BITMAP_BGR) > 0; BH_ColorRGBA16(value, &r, &g, &b, &a); if (format & BH_BITMAP_NOALPHA) a = 0xFFFF; - ((uint16_t *)data)[unitOrderRGBA[orderSelector][0]] = r; - ((uint16_t *)data)[unitOrderRGBA[orderSelector][1]] = g; - ((uint16_t *)data)[unitOrderRGBA[orderSelector][2]] = b; - ((uint16_t *)data)[unitOrderRGBA[orderSelector][3]] = a; + ((uint16_t *)data)[unitOrderRGBA[isBGR][0]] = r; + ((uint16_t *)data)[unitOrderRGBA[isBGR][1]] = g; + ((uint16_t *)data)[unitOrderRGBA[isBGR][2]] = b; + ((uint16_t *)data)[unitOrderRGBA[isBGR][3]] = a; } break; case BH_BITMAP_RGBA1010102: { uint16_t r, g, b, a; - int orderSelector = (format & BH_BITMAP_BGR) > 0; uint32_t color; + int isBGR; + isBGR = (format & BH_BITMAP_BGR) > 0; BH_ColorRGBA16(value, &r, &g, &b, &a); if (format & BH_BITMAP_NOALPHA) a = 0xFFFF; color = 0; - color |= (r >> 6) << bitOrder1010102[orderSelector][0]; - color |= (g >> 6) << bitOrder1010102[orderSelector][1]; - color |= (b >> 6) << bitOrder1010102[orderSelector][2]; - color |= (a >> 10) << bitOrder1010102[orderSelector][3]; + color |= (r >> 6) << bitOrder1010102[isBGR][0]; + color |= (g >> 6) << bitOrder1010102[isBGR][1]; + color |= (b >> 6) << bitOrder1010102[isBGR][2]; + color |= (a >> 10) << bitOrder1010102[isBGR][3]; *(uint32_t *)data = color; } @@ -478,12 +608,148 @@ static void setColor(void *data, } +static void *rowAt(void *data, + int format, + int step, + int x) +{ + switch (format & 0x0FFF) + { + case BH_BITMAP_INDEX1: + return (uint8_t *)data + x / 8; + + case BH_BITMAP_INDEX2: + return (uint8_t *)data + x / 4; + + case BH_BITMAP_INDEX4: + return (uint8_t *)data + x / 2; + + default: + return (uint8_t *)data + step * x; + } +} + + +static size_t calculateStride(int format, + int width) +{ + switch (format & 0x0FFF) + { + case BH_BITMAP_INDEX1: return (width + 7) / 8; + case BH_BITMAP_INDEX2: return (width + 3) / 4; + case BH_BITMAP_INDEX4: return (width + 1) / 2; + case BH_BITMAP_INDEX8: return width * calculateStep(format); + } + return width * calculateStep(format); +} + + +static int isPaletteNeeded(int format) +{ + switch (format) + { + case BH_BITMAP_INDEX1: + case BH_BITMAP_INDEX2: + case BH_BITMAP_INDEX4: + case BH_BITMAP_INDEX8: + return 1; + } + + return 0; +} + + +static size_t calculateTrailer(int format) +{ + switch (format & 0x0FFF) + { + case BH_BITMAP_INDEX1: return sizeof(uint32_t) * 2; + case BH_BITMAP_INDEX2: return sizeof(uint32_t) * 4; + case BH_BITMAP_INDEX4: return sizeof(uint32_t) * 16; + case BH_BITMAP_INDEX8: return sizeof(uint32_t) * 256; + } + return 0; +} + + +/* Public functions */ +BH_Bitmap *BH_BitmapNew(int width, + int height, + int format, + int flags, + void *data, + void *palette) +{ + BH_Bitmap *result; + int needPalette; + size_t header, body, trailer, stride, step; + + /* Unset internal flags */ + flags &= ~BH_BITMAP_FLAG_EXT_DATA; + flags &= ~BH_BITMAP_FLAG_EXT_PALETTE; + + /* Calculate size of the bitmap with headers */ + step = calculateStep(format); + stride = calculateStride(format, width); + needPalette = isPaletteNeeded(format); + + if (flags & BH_BITMAP_FLAG_ALIGN32) + stride = (stride + sizeof(uint32_t) - 1) & ~(sizeof(uint32_t) - 1); + + header = sizeof(*result); + header = (header + (sizeof(uint64_t) - 1)) & ~(sizeof(uint64_t) - 1); + body = (stride * height + (sizeof(uint32_t) - 1)) & ~(sizeof(uint32_t) - 1); + trailer = calculateTrailer(format); + + /* Adjust body and trailer size if ext data or palette is provided */ + if (palette) + { + flags |= BH_BITMAP_FLAG_EXT_PALETTE; + trailer = 0; + } + + if (data) + { + flags |= BH_BITMAP_FLAG_EXT_DATA; + body = 0; + } + + /* Allocate and setup bitmap data */ + result = malloc(header + body + trailer); + if (!result) + return NULL; + + if (!data) + data = (uint8_t *)result + header; + + if (!palette && needPalette) + palette = (uint8_t *)result + header + body; + + result->width = width; + result->height = height; + result->format = format; + result->flags = flags; + result->step = step; + result->stride = stride; + result->data = data; + result->palette = palette; + + return result; +} + + +void BH_BitmapFree(BH_Bitmap *bitmap) +{ + free(bitmap); +} + + void BH_BitmapColor(const BH_Bitmap *bitmap, int x, int y, BH_Color *value) { - color(BH_BitmapAt(bitmap, x, y), bitmap->palette, bitmap->format, value); + bitmapColor(BH_BitmapAt(bitmap, x, y), bitmap->palette, bitmap->format, value, x); } void BH_BitmapSetColor(BH_Bitmap *bitmap, @@ -491,9 +757,10 @@ void BH_BitmapSetColor(BH_Bitmap *bitmap, int y, const BH_Color *value) { - setColor(BH_BitmapAt(bitmap, x, y), bitmap->palette, bitmap->format, value); + setBitmapColor(BH_BitmapAt(bitmap, x, y), bitmap->palette, bitmap->format, value, x); } + BH_Bitmap *BH_BitmapCopy(BH_Bitmap *bitmap, int x, int y, @@ -554,6 +821,23 @@ BH_Bitmap *BH_BitmapCopy(BH_Bitmap *bitmap, } +uint8_t BH_BitmapIndex(const BH_Bitmap *bitmap, + int x, + int y) +{ + return bitmapIndex(BH_BitmapAt(bitmap, x, y), bitmap->format, x); +} + + +void BH_BitmapSetIndex(BH_Bitmap *bitmap, + int x, + int y, + uint8_t index) +{ + setBitmapIndex(BH_BitmapAt(bitmap, x, y), bitmap->format, x, index); +} + + void *BH_BitmapScanline(const BH_Bitmap *bitmap, int y) { @@ -565,7 +849,7 @@ void *BH_BitmapAt(const BH_Bitmap *bitmap, int x, int y) { - return BH_BitmapScanline(bitmap, y) + bitmap->step * x; + return rowAt(BH_BitmapScanline(bitmap, y), bitmap->format, bitmap->step, x); } @@ -619,18 +903,18 @@ void BH_BitmapConvertRow(void *src, void *destPalette, size_t count) { - size_t srcStep, destStep; - - srcStep = stepFromFormat(srcFormat); - destStep = stepFromFormat(destFormat); + size_t srcStep, destStep, x; + srcStep = calculateStep(srcFormat); + destStep = calculateStep(destFormat); - for (; count; --count) + for (x = 0; count; --count, ++x) { + void *srcAt, *destAt; BH_Color data; - color(src, srcPalette, srcFormat, &data); - setColor(dest, destPalette, destFormat, &data); - src = (uint8_t*)src + srcStep; - dest = (uint8_t*)dest + destStep; + srcAt = rowAt(src, srcFormat, srcStep, x); + destAt = rowAt(dest, destFormat, destStep, x); + bitmapColor(srcAt, srcPalette, srcFormat, &data, x); + setBitmapColor(destAt, destPalette, destFormat, &data, x); } } |
