aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--doc/Manual/en/BH_Bitmap.pod43
-rw-r--r--doc/Manual/ru/BH_Bitmap.pod43
-rw-r--r--include/BH/Bitmap.h40
-rw-r--r--src/Bitmap.c636
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);
}
}