Patch by David Powell:

* Implement color palette generation for the boot splash images in the
  generate_boot_screen build tool. Only 4-bit screen support is missing now.
* Adopted images.h with the new results from generate_boot_screen.

This should fix black boot screens for graphics cards that don't support
true color modes for the native resolution. I've tried to find the ticket,
#2177 almost looks like the one, but it looks more like the mode is out
of range if I understand the ticket right.

Thanks a lot, David, and sorry it took so very long to apply your patch!


git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27223 a95241bf-73f2-0310-859d-f6bbb57e9c96
This commit is contained in:
Stephan Aßmus 2008-08-28 16:59:34 +00:00
parent e2bc27448f
commit ec56835f51
5 changed files with 2468 additions and 65 deletions

File diff suppressed because it is too large Load Diff

View File

@ -781,16 +781,15 @@ blit4(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth,
static void
blit_image(const uint8 *data, const uint8* indexedData, uint16 width,
uint16 height, uint16 imageWidth, const uint8 *palette, uint16 left,
uint16 top)
blit_image(const uint8 *data, uint16 width, uint16 height, uint16 imageWidth,
const uint8 *palette, uint16 left, uint16 top)
{
switch (gKernelArgs.frame_buffer.depth) {
case 4:
return blit4(indexedData, width, height, imageWidth, palette,
return blit4(data, width, height, imageWidth, palette,
left, top);
case 8:
return blit8(indexedData, width, height, imageWidth, palette,
return blit8(data, width, height, imageWidth, palette,
left, top);
case 15:
return blit15(data, width, height, imageWidth, left, top);
@ -805,7 +804,7 @@ blit_image(const uint8 *data, const uint8* indexedData, uint16 width,
static void
uncompress_RLE(const uint8 compressed[], uint8 *uncompressed)
uncompress_24bit_RLE(const uint8 compressed[], uint8 *uncompressed)
{
uint32 cursorUncompressed = 0;
uint32 cursorCompressed = 0;
@ -842,6 +841,39 @@ uncompress_RLE(const uint8 compressed[], uint8 *uncompressed)
}
}
static void
uncompress_8Bit_RLE(const uint8 compressed[], uint8 *uncompressed)
{
uint32 cursorUncompressed = 0;
uint32 cursorCompressed = 0;
uint8 count = 0;
uint8 item = 0;
int i = 0;
while (compressed[cursorCompressed]) {
// at the end of the channel there is a terminating 0,
// so the loop will end... (ref: generate_boot_screen.cpp)
count = compressed[cursorCompressed++];
if (count < 128) {
// regular run, repeat "item" "count" times...
item = compressed[cursorCompressed++];
for (i = count - 1; i >= 0; --i) {
uncompressed[cursorUncompressed] = item;
cursorUncompressed++;
}
} else {
// enumeration, just write the next "count" items as is...
count = count - 128;
for (i = count - 1; i >= 0; --i) {
uncompressed[cursorUncompressed]
= compressed[cursorCompressed++];
cursorUncompressed++;
}
}
}
}
// #pragma mark -
extern "C" void
@ -916,13 +948,27 @@ fallback:
memset((void *)sFrameBuffer, 0,
gKernelArgs.frame_buffer.physical_buffer.size);
uint8 *uncompressedLogo = (uint8 *)kernel_args_malloc(kSplashLogoWidth
* kSplashLogoHeight * 3);
if (uncompressedLogo == NULL)
return;
uncompress_RLE(kSplashLogoCompressedImage, uncompressedLogo);
uint8 *uncompressedLogo = NULL;
switch (gKernelArgs.frame_buffer.depth) {
case 8:
uncompressedLogo = (uint8 *)kernel_args_malloc(kSplashLogoWidth
* kSplashLogoHeight);
if (uncompressedLogo == NULL)
return;
uncompress_8Bit_RLE(kSplashLogo8BitCompressedImage,
uncompressedLogo);
break;
default:
uncompressedLogo = (uint8 *)kernel_args_malloc(kSplashLogoWidth
* kSplashLogoHeight * 3);
if (uncompressedLogo == NULL)
return;
uncompress_24bit_RLE(kSplashLogo24BitCompressedImage,
uncompressedLogo);
break;
}
// TODO: support indexed versions of the images!
// TODO: support 4-bit indexed version of the images!
// render splash logo
uint16 iconsHalfHeight = kSplashIconsHeight / 2;
@ -937,16 +983,39 @@ fallback:
int y = (gKernelArgs.frame_buffer.height - height) * placementY / 100;
height = min_c(kSplashLogoHeight, gKernelArgs.frame_buffer.height);
blit_image(uncompressedLogo, NULL, width, height, kSplashLogoWidth,
NULL, x, y);
blit_image(uncompressedLogo, width, height, kSplashLogoWidth,
k8BitPalette, x, y);
kernel_args_free(uncompressedLogo);
gKernelArgs.boot_splash = (uint8 *)kernel_args_malloc(kSplashIconsWidth
* kSplashIconsHeight * 3);
if (gKernelArgs.boot_splash == NULL)
return;
uncompress_RLE(kSplashIconsCompressedImage, gKernelArgs.boot_splash );
const uint8* lowerHalfIconImage;
switch (gKernelArgs.frame_buffer.depth) {
case 8:
// pointer into the lower half of the icons image data
gKernelArgs.boot_splash
= (uint8 *)kernel_args_malloc(kSplashIconsWidth
* kSplashIconsHeight);
if (gKernelArgs.boot_splash == NULL)
return;
uncompress_8Bit_RLE(kSplashIcons8BitCompressedImage,
gKernelArgs.boot_splash );
lowerHalfIconImage = gKernelArgs.boot_splash
+ (kSplashIconsWidth * iconsHalfHeight);
break;
default:
// pointer into the lower half of the icons image data
gKernelArgs.boot_splash
= (uint8 *)kernel_args_malloc(kSplashIconsWidth
* kSplashIconsHeight * 3);
if (gKernelArgs.boot_splash == NULL)
return;
uncompress_24bit_RLE(kSplashIcons24BitCompressedImage,
gKernelArgs.boot_splash );
lowerHalfIconImage = gKernelArgs.boot_splash
+ (kSplashIconsWidth * iconsHalfHeight) * 3;
break;
}
// render initial (grayed out) icons
// the grayed out version is the lower half of the icons image
@ -961,12 +1030,9 @@ fallback:
y = kSplashLogoHeight + (gKernelArgs.frame_buffer.height - height)
* placementY / 100;
// pointer into the lower half of the icons image data
const uint8* lowerHalfIconImage = gKernelArgs.boot_splash
+ (kSplashIconsWidth * iconsHalfHeight) * 3;
height = min_c(iconsHalfHeight, gKernelArgs.frame_buffer.height);
blit_image(lowerHalfIconImage, NULL, width, height,
kSplashIconsWidth, NULL, x, y);
blit_image(lowerHalfIconImage, width, height, kSplashIconsWidth,
k8BitPalette, x, y);
}

View File

@ -36,10 +36,34 @@
static struct frame_buffer_boot_info *sInfo;
static uint8 *sUncompressedIcons;
static void
blit8_cropped(const uint8 *data, uint16 imageLeft, uint16 imageTop,
uint16 imageRight, uint16 imageBottom, uint16 imageWidth,
uint16 left, uint16 top)
{
data += (imageWidth * imageTop + imageLeft);
uint8* start = (uint8*)(sInfo->frame_buffer
+ sInfo->bytes_per_row * (top + imageTop) + 1 * (left + imageLeft));
for (int32 y = imageTop; y < imageBottom; y++) {
const uint8* src = data;
uint8* dst = start;
for (int32 x = imageLeft; x < imageRight; x++) {
dst[0] = src[0];
dst++;
src++;
}
data += imageWidth;
start = (uint8*)((addr_t)start + sInfo->bytes_per_row);
}
}
static void
blit15_cropped(const uint8 *data, uint16 imageLeft, uint16 imageTop,
uint16 imageRight, uint16 imageBottom, uint16 imageWidth,
const uint8 *palette, uint16 left, uint16 top)
uint16 left, uint16 top)
{
data += (imageWidth * imageTop + imageLeft) * 3;
uint16* start = (uint16*)(sInfo->frame_buffer
@ -67,7 +91,7 @@ blit15_cropped(const uint8 *data, uint16 imageLeft, uint16 imageTop,
static void
blit16_cropped(const uint8 *data, uint16 imageLeft, uint16 imageTop,
uint16 imageRight, uint16 imageBottom, uint16 imageWidth,
const uint8 *palette, uint16 left, uint16 top)
uint16 left, uint16 top)
{
data += (imageWidth * imageTop + imageLeft) * 3;
uint16* start = (uint16*)(sInfo->frame_buffer
@ -94,7 +118,7 @@ blit16_cropped(const uint8 *data, uint16 imageLeft, uint16 imageTop,
static void
blit24_cropped(const uint8 *data, uint16 imageLeft, uint16 imageTop,
uint16 imageRight, uint16 imageBottom, uint16 imageWidth,
const uint8 *palette, uint16 left, uint16 top)
uint16 left, uint16 top)
{
data += (imageWidth * imageTop + imageLeft) * 3;
uint8* start = (uint8*)(sInfo->frame_buffer
@ -120,7 +144,7 @@ blit24_cropped(const uint8 *data, uint16 imageLeft, uint16 imageTop,
static void
blit32_cropped(const uint8 *data, uint16 imageLeft, uint16 imageTop,
uint16 imageRight, uint16 imageBottom, uint16 imageWidth,
const uint8 *palette, uint16 left, uint16 top)
uint16 left, uint16 top)
{
data += (imageWidth * imageTop + imageLeft) * 3;
uint32* start = (uint32*)(sInfo->frame_buffer
@ -142,26 +166,30 @@ blit32_cropped(const uint8 *data, uint16 imageLeft, uint16 imageTop,
static void
blit_cropped(const uint8* data, const uint8* indexedData,
uint16 imageLeft, uint16 imageTop, uint16 imageRight, uint16 imageBottom,
uint16 imageWidth, const uint8 *palette, uint16 left, uint16 top)
blit_cropped(const uint8* data, uint16 imageLeft, uint16 imageTop,
uint16 imageRight, uint16 imageBottom, uint16 imageWidth,
uint16 left, uint16 top)
{
switch (sInfo->depth) {
case 8:
blit8_cropped(data, imageLeft, imageTop, imageRight, imageBottom,
imageWidth, left, top);
return;
case 15:
blit15_cropped(data, imageLeft, imageTop, imageRight, imageBottom,
imageWidth, palette, left, top);
imageWidth, left, top);
return;
case 16:
blit16_cropped(data, imageLeft, imageTop, imageRight, imageBottom,
imageWidth, palette, left, top);
imageWidth, left, top);
return;
case 24:
blit24_cropped(data, imageLeft, imageTop, imageRight, imageBottom,
imageWidth, palette, left, top);
imageWidth, left, top);
return;
case 32:
blit32_cropped(data, imageLeft, imageTop, imageRight, imageBottom,
imageWidth, palette, left, top);
imageWidth, left, top);
return;
}
}
@ -213,7 +241,7 @@ boot_splash_set_stage(int stage)
int stageRightEdge = width * (stage + 1) / BOOT_SPLASH_STAGE_MAX;
height = min_c(iconsHalfHeight, sInfo->height);
blit_cropped(sUncompressedIcons, NULL, stageLeftEdge, 0, stageRightEdge,
height, kSplashIconsWidth, NULL, x, y);
blit_cropped(sUncompressedIcons, stageLeftEdge, 0, stageRightEdge,
height, kSplashIconsWidth, x, y);
}

View File

@ -39,7 +39,11 @@ BuildPlatformMain <build>copyattr : copyattr.cpp
BuildPlatformMain <build>data_to_source : data_to_source.cpp
: $(HOST_LIBSUPC++) ;
BuildPlatformMain <build>generate_boot_screen : generate_boot_screen.cpp
UsePrivateObjectHeaders generate_boot_screen.cpp : shared : : true ;
UsePrivateObjectHeaders ColorQuantizer.cpp : shared : : true ;
BuildPlatformMain <build>generate_boot_screen :
generate_boot_screen.cpp
ColorQuantizer.cpp
: $(HOST_LIBSUPC++) $(HOST_LIBSTDC++) png z ;
BuildPlatformMain <build>listattr : listattr.cpp : $(HOST_LIBBE) ;
@ -88,6 +92,10 @@ SEARCH on [ FGristFiles
UpdateMimeInfoThread.cpp MimeUpdateThread.cpp database_support.cpp
] = [ FDirName $(HAIKU_TOP) src build libbe storage mime ] ;
SEARCH on [ FGristFiles
ColorQuantizer.cpp
] = [ FDirName $(HAIKU_TOP) src kits shared ] ;
SubInclude HAIKU_TOP src tools addattr ;
SubInclude HAIKU_TOP src tools bfs_shell ;
SubInclude HAIKU_TOP src tools copy_to_bfs_image ;

View File

@ -6,6 +6,7 @@
* Artur Wyszynski <harakash@gmail.com>
* Stephan Aßmus <superstippi@gmx.de>
* Philippe Saint-Pierre <stpere@gmail.com>
* David Powell <david@mad.scientist.com>
*/
//! Haiku boot splash image generator/converter
@ -16,10 +17,12 @@
#include <stdarg.h>
#include <stdint.h>
// TODO: Generate the single optimal palette for all three images,
// store palette versions of these images as well, so that they are
// ready to be used during boot in case we need to run in palette
// VGA mode.
#include <ColorQuantizer.h>
// TODO: Create 4 bit palette version of these
// images as well, so that they are ready to be
// used during boot in case we need to run in
// palette 4 bit VGA mode.
FILE* sOutput = NULL;
@ -131,7 +134,7 @@ new_line_if_required()
static void
write_image(const char* baseName, int width, int height, png_bytep* rowPtrs)
write_24bit_image(const char* baseName, int width, int height, png_bytep* rowPtrs)
{
fprintf(sOutput, "static const uint16 %sWidth = %d;\n", baseName, width);
fprintf(sOutput, "static const uint16 %sHeight = %d;\n", baseName, height);
@ -140,7 +143,7 @@ write_image(const char* baseName, int width, int height, png_bytep* rowPtrs)
int buffer[128];
// buffer[0] stores count, buffer[1..127] holds the actual values
fprintf(sOutput, "static uint8 %sCompressedImage[] = {\n\t",
fprintf(sOutput, "static uint8 %s24BitCompressedImage[] = {\n\t",
baseName);
for (int c = 0; c < 3; c++) {
@ -164,12 +167,12 @@ write_image(const char* baseName, int width, int height, png_bytep* rowPtrs)
bufferActive = false;
count = 2;
if (buffer[0] > 1) {
fprintf (sOutput, "%d, ",
fprintf(sOutput, "%d, ",
128 + buffer[0] - 1);
new_line_if_required();
for (int i = 1; i < buffer[0] ; i++) {
fprintf( sOutput, "%d, ",
buffer[i] );
fprintf(sOutput, "%d, ",
buffer[i]);
new_line_if_required();
}
}
@ -241,21 +244,222 @@ write_image(const char* baseName, int width, int height, png_bytep* rowPtrs)
static void
parse_image(const char* filename, const char* baseName)
{
int width;
int height;
png_bytep* rowPtrs = NULL;
png_structp pngPtr;
png_infop infoPtr;
read_png(filename, width, height, rowPtrs, pngPtr, infoPtr);
write_image(baseName, width, height, rowPtrs);
write_8bit_image(const char* baseName, int width, int height, unsigned char** rowPtrs)
{
int buffer[128];
// buffer[0] stores count, buffer[1..127] holds the actual values
fprintf(sOutput, "static uint8 %s8BitCompressedImage[] = {\n\t",
baseName);
// NOTE: I don't care much about performance at this step,
// decoding however...
unsigned char currentValue = rowPtrs[0][0];
int count = 0;
// When bufferActive == true, we store the number rather than writing
// them directly; we use this to store numbers until we find a pair..
bool bufferActive = false;
sOffset = 0;
for (int y = 0; y < height; y++) {
unsigned char* row = rowPtrs[y];
for (int x = 0; x < width; x++) {
if (row[x] == currentValue) {
if (bufferActive) {
bufferActive = false;
count = 2;
if (buffer[0] > 1) {
fprintf(sOutput, "%d, ",
128 + buffer[0] - 1);
new_line_if_required();
for (int i = 1; i < buffer[0] ; i++) {
fprintf(sOutput, "%d, ",
buffer[i]);
new_line_if_required();
}
}
} else {
count++;
if (count == 127) {
fprintf(sOutput, "127, ");
new_line_if_required();
fprintf(sOutput, "%d, ", currentValue);
new_line_if_required();
count = 0;
}
}
} else {
if (bufferActive) {
if (buffer[0] == 127) {
// we don't have enough room,
// flush the buffer
fprintf(sOutput, "%d, ",
128 + buffer[0] - 1);
new_line_if_required();
for (int i = 1; i < buffer[0]; i++) {
fprintf(sOutput, "%d, ", buffer[i]);
new_line_if_required();
}
buffer[0] = 0;
}
buffer[0]++;
buffer[buffer[0]] = row[x];
} else if (count > 0) {
buffer[0] = 1;
buffer[1] = row[x];
bufferActive = true;
if (count > 1) {
fprintf(sOutput, "%d, ", count);
new_line_if_required();
fprintf(sOutput, "%d, ", currentValue);
new_line_if_required();
}
}
currentValue = row[x];
}
}
}
if (bufferActive) {
// I could have written 127 + buffer[0],
// but I think this is more readable...
fprintf(sOutput, "%d, ", 128 + buffer[0] - 1);
new_line_if_required();
for (int i = 1; i < buffer[0] ; i++) {
fprintf(sOutput, "%d, ", buffer[i]);
new_line_if_required();
}
} else {
fprintf(sOutput, "%d, %d, ", count, currentValue);
new_line_if_required();
}
// we put a terminating zero for the next byte that indicates
// a "count", to indicate the end
fprintf(sOutput, "0");
fprintf(sOutput, "\n\t");
fprintf(sOutput, "};\n\n");
}
unsigned char
nearest_color(unsigned char* color, RGBA palette[256])
{
int i, dist, minDist, index = 0;
minDist = 255 * 255 + 255 * 255 + 255 * 255 + 1;
for (i = 0; i < 256; i++) {
int dr = ((int)color[2]) - palette[i].r;
int dg = ((int)color[1]) - palette[i].g;
int db = ((int)color[0]) - palette[i].b;
dist = dr * dr + dg * dg + db * db;
if (dist < minDist) {
minDist = dist;
index = i;
}
}
return index;
}
static void
create_8bit_images(const char* logoBaseName, int logoWidth, int logoHeight,
png_bytep* logoRowPtrs, const char* iconsBaseName, int iconsWidth,
int iconsHeight, png_bytep* iconsRowPtrs)
{
// Generate 8-bit palette
BColorQuantizer quantizer(256, 8);
quantizer.ProcessImage(logoRowPtrs, logoWidth, logoHeight);
quantizer.ProcessImage(iconsRowPtrs, iconsWidth, iconsHeight);
RGBA palette[256];
quantizer.GetColorTable(palette);
// convert 24-bit logo image to 8-bit indexed color
uint8* logoIndexedImageRows[logoHeight];
for (int y = 0; y < logoHeight; y++) {
logoIndexedImageRows[y] = new uint8[logoWidth];
for (int x = 0; x < logoWidth; x++) {
logoIndexedImageRows[y][x] = nearest_color(&logoRowPtrs[y][x*3],
palette);
}
}
// convert 24-bit icons image to 8-bit indexed color
uint8* iconsIndexedImageRows[iconsHeight];
for (int y = 0; y < iconsHeight; y++) {
iconsIndexedImageRows[y] = new uint8[iconsWidth];
for (int x = 0; x < iconsWidth; x++) {
iconsIndexedImageRows[y][x] = nearest_color(&iconsRowPtrs[y][x*3],
palette);
}
}
fprintf(sOutput, "#ifndef __BOOTSPLASH_KERNEL__\n");
// write the 8-bit color palette
fprintf(sOutput, "static const uint8 k8BitPalette[] = {\n");
for (int c = 0; c < 256; c++) {
fprintf(sOutput, "\t0x%x, 0x%x, 0x%x,\n",
palette[c].r, palette[c].g, palette[c].b);
}
fprintf(sOutput, "\t};\n\n");
// write the 8-bit images
write_8bit_image(logoBaseName, logoWidth, logoHeight, logoIndexedImageRows);
write_8bit_image(iconsBaseName, iconsWidth, iconsHeight,
iconsIndexedImageRows);
fprintf(sOutput, "#endif\n\n");
// free memory
for (int y = 0; y < logoHeight; y++)
delete[] logoIndexedImageRows[y];
for (int y = 0; y < iconsHeight; y++)
delete[] iconsIndexedImageRows[y];
}
static void
parse_images(const char* logoFilename, const char* logoBaseName,
const char* iconsFilename, const char* iconsBaseName)
{
int logoWidth;
int logoHeight;
png_bytep* logoRowPtrs = NULL;
png_structp logoPngPtr;
png_infop logoInfoPtr;
int iconsWidth;
int iconsHeight;
png_bytep* iconsRowPtrs = NULL;
png_structp iconsPngPtr;
png_infop iconsInfoPtr;
read_png(logoFilename, logoWidth, logoHeight, logoRowPtrs, logoPngPtr,
logoInfoPtr);
read_png(iconsFilename, iconsWidth, iconsHeight, iconsRowPtrs, iconsPngPtr,
iconsInfoPtr);
// write 24-bit images
write_24bit_image(logoBaseName, logoWidth, logoHeight, logoRowPtrs);
write_24bit_image(iconsBaseName, iconsWidth, iconsHeight, iconsRowPtrs);
// write 8-bit index color images
create_8bit_images(logoBaseName, logoWidth, logoHeight, logoRowPtrs,
iconsBaseName, iconsWidth, iconsHeight, iconsRowPtrs);
// free resources
png_destroy_read_struct(&pngPtr, &infoPtr, NULL);
for (int y = 0; y < height; y++)
free(rowPtrs[y]);
free(rowPtrs);
png_destroy_read_struct(&logoPngPtr, &logoInfoPtr, NULL);
for (int y = 0; y < logoHeight; y++)
free(logoRowPtrs[y]);
free(logoRowPtrs);
png_destroy_read_struct(&iconsPngPtr, &iconsInfoPtr, NULL);
for (int y = 0; y < iconsHeight; y++)
free(iconsRowPtrs[y]);
free(iconsRowPtrs);
}
@ -308,10 +512,8 @@ main(int argc, char* argv[])
fprintf(sOutput, "static const int32 kSplashIconsPlacementY = %d;\n\n",
iconPlacementY);
parse_image(argv[1], "kSplashLogo");
parse_image(argv[4], "kSplashIcons");
parse_images(argv[1], "kSplashLogo", argv[4], "kSplashIcons");
fclose(sOutput);
return 0;
}