splash_bmp.c revision 42623
142506Syokota/*- 242506Syokota * Copyright (c) 1999 Michael Smith <msmith@freebsd.org> 342506Syokota * Copyright (c) 1999 Kazutaka YOKOTA <yokota@freebsd.org> 442506Syokota * All rights reserved. 542506Syokota * 642506Syokota * Redistribution and use in source and binary forms, with or without 742506Syokota * modification, are permitted provided that the following conditions 842506Syokota * are met: 942506Syokota * 1. Redistributions of source code must retain the above copyright 1042506Syokota * notice, this list of conditions and the following disclaimer. 1142506Syokota * 2. Redistributions in binary form must reproduce the above copyright 1242506Syokota * notice, this list of conditions and the following disclaimer in the 1342506Syokota * documentation and/or other materials provided with the distribution. 1442506Syokota * 1542506Syokota * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1642506Syokota * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1742506Syokota * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1842506Syokota * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 1942506Syokota * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2042506Syokota * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2142506Syokota * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2242506Syokota * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2342506Syokota * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2442506Syokota * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2542506Syokota * SUCH DAMAGE. 2642506Syokota * 2742623Syokota * $Id: splash_bmp.c,v 1.2 1999/01/11 17:32:22 yokota Exp $ 2842506Syokota */ 2942506Syokota 3042506Syokota#include <sys/param.h> 3142506Syokota#include <sys/systm.h> 3242506Syokota#include <sys/kernel.h> 3342506Syokota#include <sys/linker.h> 3442506Syokota 3542506Syokota#include <machine/console.h> 3642506Syokota 3742506Syokota#include <dev/fb/fbreg.h> 3842506Syokota#include <dev/fb/splashreg.h> 3942506Syokota 4042506Syokota#define FADE_TIMEOUT 300 /* sec */ 4142506Syokota 4242506Syokotastatic int splash_mode = -1; 4342506Syokotastatic int splash_on = FALSE; 4442506Syokota 4542506Syokotastatic int bmp_start(video_adapter_t *adp); 4642506Syokotastatic int bmp_end(video_adapter_t *adp); 4742506Syokotastatic int bmp_splash(video_adapter_t *adp, int on); 4842506Syokotastatic int bmp_Init(const char *data, int swidth, int sheight, int sdepth); 4942506Syokotastatic int bmp_Draw(video_adapter_t *adp); 5042506Syokota 5142506Syokotastatic splash_decoder_t bmp_decoder = { 5242506Syokota "splash_bmp", bmp_start, bmp_end, bmp_splash, SPLASH_IMAGE, 5342506Syokota}; 5442506Syokota 5542506SyokotaSPLASH_DECODER(splash_bmp, bmp_decoder); 5642506Syokota 5742506Syokotastatic int 5842506Syokotabmp_start(video_adapter_t *adp) 5942506Syokota{ 6042506Syokota static int modes[] = { 6142506Syokota M_VGA_CG320, 6242506Syokota -1, 6342506Syokota }; 6442506Syokota video_info_t info; 6542506Syokota int i; 6642506Syokota 6742506Syokota if ((bmp_decoder.data == NULL) || (bmp_decoder.data_size <= 0)) 6842506Syokota return ENODEV; 6942506Syokota for (i = 0; modes[i] >= 0; ++i) { 7042506Syokota if (((*vidsw[adp->va_index]->get_info)(adp, modes[i], &info) == 0) 7142506Syokota && (bmp_Init((u_char *)bmp_decoder.data, 7242506Syokota info.vi_width, info.vi_height, info.vi_depth) == 0)) 7342506Syokota break; 7442506Syokota } 7542506Syokota splash_mode = modes[i]; 7642506Syokota if (bootverbose) 7742506Syokota printf("bmp_start(): splash_mode:%d\n", splash_mode); 7842506Syokota return ((splash_mode < 0) ? ENODEV : 0); 7942506Syokota} 8042506Syokota 8142506Syokotastatic int 8242506Syokotabmp_end(video_adapter_t *adp) 8342506Syokota{ 8442506Syokota /* nothing to do */ 8542506Syokota return 0; 8642506Syokota} 8742506Syokota 8842506Syokotastatic int 8942506Syokotabmp_splash(video_adapter_t *adp, int on) 9042506Syokota{ 9142506Syokota static u_char pal[256*3]; 9242506Syokota static long time_stamp; 9342506Syokota struct timeval tv; 9442506Syokota int i; 9542506Syokota 9642506Syokota if (on) { 9742506Syokota if (!splash_on) { 9842506Syokota /* set up the video mode and draw something */ 9942506Syokota if ((*vidsw[adp->va_index]->set_mode)(adp, splash_mode)) 10042506Syokota return 1; 10142506Syokota if (bmp_Draw(adp)) 10242506Syokota return 1; 10342506Syokota (*vidsw[adp->va_index]->save_palette)(adp, pal); 10442506Syokota time_stamp = 0; 10542506Syokota splash_on = TRUE; 10642506Syokota } 10742506Syokota /* 10842506Syokota * This is a kludge to fade the image away. This section of the 10942506Syokota * code takes effect only after the system is completely up. 11042506Syokota */ 11142506Syokota if (!cold) { 11242506Syokota getmicrotime(&tv); 11342506Syokota if (time_stamp == 0) 11442506Syokota time_stamp = tv.tv_sec; 11542506Syokota if (tv.tv_sec > time_stamp + FADE_TIMEOUT) { 11642506Syokota for (i = 0; i < sizeof(pal); ++i) { 11742506Syokota if (pal[i] > 40) 11842506Syokota pal[i] -= 4; 11942506Syokota } 12042506Syokota (*vidsw[adp->va_index]->load_palette)(adp, pal); 12142506Syokota } 12242506Syokota } 12342506Syokota return 0; 12442506Syokota } else { 12542506Syokota /* the video mode will be restored by the caller */ 12642506Syokota splash_on = FALSE; 12742506Syokota return 0; 12842506Syokota } 12942506Syokota} 13042506Syokota 13142506Syokota/* 13242506Syokota** Code to handle Microsoft DIB (".BMP") format images. 13342506Syokota** 13442506Syokota** Blame me (msmith@freebsd.org) if this is broken, not Soren. 13542506Syokota*/ 13642506Syokota 13742506Syokotatypedef struct tagBITMAPFILEHEADER { /* bmfh */ 13842506Syokota u_short bfType __attribute__ ((packed)); 13942506Syokota int bfSize __attribute__ ((packed)); 14042506Syokota u_short bfReserved1 __attribute__ ((packed)); 14142506Syokota u_short bfReserved2 __attribute__ ((packed)); 14242506Syokota int bfOffBits __attribute__ ((packed)); 14342506Syokota} BITMAPFILEHEADER; 14442506Syokota 14542506Syokotatypedef struct tagBITMAPINFOHEADER { /* bmih */ 14642506Syokota int biSize __attribute__ ((packed)); 14742506Syokota int biWidth __attribute__ ((packed)); 14842506Syokota int biHeight __attribute__ ((packed)); 14942506Syokota short biPlanes __attribute__ ((packed)); 15042506Syokota short biBitCount __attribute__ ((packed)); 15142506Syokota int biCompression __attribute__ ((packed)); 15242506Syokota int biSizeImage __attribute__ ((packed)); 15342506Syokota int biXPelsPerMeter __attribute__ ((packed)); 15442506Syokota int biYPelsPerMeter __attribute__ ((packed)); 15542506Syokota int biClrUsed __attribute__ ((packed)); 15642506Syokota int biClrImportant __attribute__ ((packed)); 15742506Syokota} BITMAPINFOHEADER; 15842506Syokota 15942506Syokotatypedef struct tagRGBQUAD { /* rgbq */ 16042506Syokota u_char rgbBlue __attribute__ ((packed)); 16142506Syokota u_char rgbGreen __attribute__ ((packed)); 16242506Syokota u_char rgbRed __attribute__ ((packed)); 16342506Syokota u_char rgbReserved __attribute__ ((packed)); 16442506Syokota} RGBQUAD; 16542506Syokota 16642506Syokotatypedef struct tagBITMAPINFO { /* bmi */ 16742506Syokota BITMAPINFOHEADER bmiHeader __attribute__ ((packed)); 16842506Syokota RGBQUAD bmiColors[256] __attribute__ ((packed)); 16942506Syokota} BITMAPINFO; 17042506Syokota 17142506Syokotatypedef struct tagBITMAPF 17242506Syokota{ 17342506Syokota BITMAPFILEHEADER bmfh __attribute__ ((packed)); 17442506Syokota BITMAPINFO bmfi __attribute__ ((packed)); 17542506Syokota} BITMAPF; 17642506Syokota 17742506Syokota#define BI_RGB 0 17842506Syokota#define BI_RLE8 1 17942506Syokota#define BI_RLE4 2 18042506Syokota 18142506Syokota/* 18242506Syokota** all we actually care about the image 18342506Syokota*/ 18442506Syokotatypedef struct 18542506Syokota{ 18642506Syokota int width,height; /* image dimensions */ 18742506Syokota int swidth,sheight; /* screen dimensions for the current mode */ 18842506Syokota u_char sdepth; /* screen depth (1, 4, 8 bpp) */ 18942506Syokota int ncols; /* number of colours */ 19042506Syokota u_char palette[256][3]; /* raw palette data */ 19142506Syokota u_char format; /* one of the BI_* constants above */ 19242506Syokota u_char *data; /* pointer to the raw data */ 19342506Syokota u_char *index; /* running pointer to the data while drawing */ 19442506Syokota u_char *vidmem; /* video memory allocated for drawing */ 19542506Syokota} BMP_INFO; 19642506Syokota 19742506Syokotastatic BMP_INFO bmp_info; 19842506Syokota 19942506Syokota/* 20042506Syokota** bmp_SetPix 20142506Syokota** 20242506Syokota** Given (info), set the pixel at (x),(y) to (val) 20342506Syokota** 20442506Syokota*/ 20542506Syokotastatic void 20642506Syokotabmp_SetPix(BMP_INFO *info, int x, int y, u_char val) 20742506Syokota{ 20842506Syokota int sofs, bofs; 20942506Syokota u_char tpv, mask; 21042506Syokota 21142506Syokota /* 21242506Syokota * range check to avoid explosions 21342506Syokota */ 21442506Syokota if ((x < 0) || (x >= info->swidth) || (y < 0) || (y >= info->sheight)) 21542506Syokota return; 21642506Syokota 21742506Syokota /* 21842506Syokota * calculate offset into video memory; 21942506Syokota * because 0,0 is bottom-left for DIB, we have to convert. 22042506Syokota */ 22142506Syokota sofs = ((info->height - (y+1) + (info->sheight - info->height) / 2) 22242506Syokota * info->swidth) + x + (info->swidth - info->width) / 2; 22342506Syokota 22442506Syokota switch(info->sdepth) { 22542506Syokota case 1: 22642506Syokota sofs = sofs >> 3; /* correct for depth */ 22742506Syokota bofs = x & 0x7; /* offset within byte */ 22842506Syokota 22942506Syokota val &= 1; /* mask pixel value */ 23042506Syokota mask = ~(0x80 >> bofs); /* calculate bit mask */ 23142506Syokota tpv = *(info->vidmem+sofs) & mask; /* get screen contents, excluding masked bit */ 23242506Syokota *(info->vidmem+sofs) = tpv | (val << (8-bofs)); /* write new bit */ 23342506Syokota break; 23442506Syokota 23542506Syokota /* XXX only correct for non-interleaved modes */ 23642506Syokota case 4: 23742506Syokota sofs = sofs >> 1; /* correct for depth */ 23842506Syokota bofs = x & 0x1; /* offset within byte */ 23942506Syokota 24042506Syokota val &= 0xf; /* mask pixel value */ 24142506Syokota mask = bofs ? 0x0f : 0xf0; /* calculate bit mask */ 24242506Syokota tpv = *(info->vidmem+sofs) & mask; /* get screen contents, excluding masked bits */ 24342506Syokota *(info->vidmem+sofs) = tpv | (val << (bofs ? 0 : 4)); /* write new bits */ 24442506Syokota break; 24542506Syokota 24642506Syokota case 8: 24742506Syokota *(info->vidmem+sofs) = val; 24842506Syokota break; 24942506Syokota } 25042506Syokota} 25142506Syokota 25242506Syokota/* 25342506Syokota** bmp_DecodeRLE4 25442506Syokota** 25542506Syokota** Given (data) pointing to a line of RLE4-format data and (line) being the starting 25642506Syokota** line onscreen, decode the line. 25742506Syokota*/ 25842506Syokotastatic void 25942506Syokotabmp_DecodeRLE4(BMP_INFO *info, int line) 26042506Syokota{ 26142506Syokota int count; /* run count */ 26242506Syokota u_char val; 26342506Syokota int x,y; /* screen position */ 26442506Syokota 26542506Syokota x = 0; /* starting position */ 26642506Syokota y = line; 26742506Syokota 26842506Syokota /* loop reading data */ 26942506Syokota for (;;) { 27042506Syokota /* 27142506Syokota * encoded mode starts with a run length, and then a byte with 27242506Syokota * two colour indexes to alternate between for the run 27342506Syokota */ 27442506Syokota if (*info->index) { 27542506Syokota for (count = 0; count < *info->index; count++, x++) { 27642506Syokota if (count & 1) { /* odd count, low nybble */ 27742506Syokota bmp_SetPix(info, x, y, *(info->index+1) & 0x0f); 27842506Syokota } else { /* even count, high nybble */ 27942506Syokota bmp_SetPix(info, x, y, (*(info->index+1) >>4) & 0x0f); 28042506Syokota } 28142506Syokota } 28242506Syokota info->index += 2; 28342506Syokota /* 28442506Syokota * A leading zero is an escape; it may signal the end of the 28542506Syokota * bitmap, a cursor move, or some absolute data. 28642506Syokota */ 28742506Syokota } else { /* zero tag may be absolute mode or an escape */ 28842506Syokota switch (*(info->index+1)) { 28942506Syokota case 0: /* end of line */ 29042506Syokota info->index += 2; 29142506Syokota return; 29242506Syokota case 1: /* end of bitmap */ 29342506Syokota info->index = NULL; 29442506Syokota return; 29542506Syokota case 2: /* move */ 29642506Syokota x += *(info->index + 2); /* new coords */ 29742506Syokota y += *(info->index + 3); 29842506Syokota info->index += 4; 29942506Syokota break; 30042506Syokota default: /* literal bitmap data */ 30142506Syokota for (count = 0; count < *(info->index + 1); count++, x++) { 30242506Syokota val = *(info->index + 2 + (count / 2)); /* byte with nybbles */ 30342506Syokota if (count & 1) { 30442506Syokota val &= 0xf; /* get low nybble */ 30542506Syokota } else { 30642506Syokota val = (val >> 4); /* get high nybble */ 30742506Syokota } 30842506Syokota bmp_SetPix(info, x, y, val); 30942506Syokota } 31042506Syokota /* warning, this depends on integer truncation, do not hand-optimise! */ 31142506Syokota info->index += 2 + ((count + 3) / 4) * 2; 31242506Syokota break; 31342506Syokota } 31442506Syokota } 31542506Syokota } 31642506Syokota} 31742506Syokota 31842506Syokota/* 31942506Syokota** bmp_DecodeRLE8 32042506Syokota** Given (data) pointing to a line of RLE4-format data and (line) being the starting 32142506Syokota** line onscreen, decode the line. 32242506Syokota*/ 32342506Syokotastatic void 32442506Syokotabmp_DecodeRLE8(BMP_INFO *info, int line) 32542506Syokota{ 32642506Syokota int count; /* run count */ 32742506Syokota int x,y; /* screen position */ 32842506Syokota 32942506Syokota x = 0; /* starting position */ 33042506Syokota y = line; 33142506Syokota 33242506Syokota /* loop reading data */ 33342506Syokota for(;;) { 33442506Syokota /* 33542506Syokota * encoded mode starts with a run length, and then a byte with 33642506Syokota * two colour indexes to alternate between for the run 33742506Syokota */ 33842506Syokota if (*info->index) { 33942506Syokota for (count = 0; count < *info->index; count++, x++) 34042506Syokota bmp_SetPix(info, x, y, *(info->index+1)); 34142506Syokota info->index += 2; 34242506Syokota /* 34342506Syokota * A leading zero is an escape; it may signal the end of the 34442506Syokota * bitmap, a cursor move, or some absolute data. 34542506Syokota */ 34642506Syokota } else { /* zero tag may be absolute mode or an escape */ 34742506Syokota switch(*(info->index+1)) { 34842506Syokota case 0: /* end of line */ 34942506Syokota info->index += 2; 35042506Syokota return; 35142506Syokota case 1: /* end of bitmap */ 35242506Syokota info->index = NULL; 35342506Syokota return; 35442506Syokota case 2: /* move */ 35542506Syokota x += *(info->index + 2); /* new coords */ 35642506Syokota y += *(info->index + 3); 35742506Syokota info->index += 4; 35842506Syokota break; 35942506Syokota default: /* literal bitmap data */ 36042506Syokota for (count = 0; count < *(info->index + 1); count++, x++) 36142506Syokota bmp_SetPix(info, x, y, *(info->index + 2 + count)); 36242506Syokota /* must be an even count */ 36342506Syokota info->index += 2 + count + (count & 1); 36442506Syokota break; 36542506Syokota } 36642506Syokota } 36742506Syokota } 36842506Syokota} 36942506Syokota 37042506Syokota/* 37142506Syokota** bmp_DecodeLine 37242506Syokota** 37342506Syokota** Given (info) pointing to an image being decoded, (line) being the line currently 37442506Syokota** being displayed, decode a line of data. 37542506Syokota*/ 37642506Syokotastatic void 37742506Syokotabmp_DecodeLine(BMP_INFO *info, int line) 37842506Syokota{ 37942506Syokota int x; 38042506Syokota 38142506Syokota switch(info->format) { 38242506Syokota case BI_RGB: 38342506Syokota for (x = 0; x < info->width; x++, info->index++) 38442506Syokota bmp_SetPix(info, x, line, *info->index); 38542529Syokota info->index += 3 - (--x % 4); 38642506Syokota break; 38742506Syokota case BI_RLE4: 38842506Syokota bmp_DecodeRLE4(info, line); 38942506Syokota break; 39042506Syokota case BI_RLE8: 39142506Syokota bmp_DecodeRLE8(info, line); 39242506Syokota break; 39342506Syokota } 39442506Syokota} 39542506Syokota 39642506Syokota/* 39742506Syokota** bmp_Init 39842506Syokota** 39942506Syokota** Given a pointer (data) to the image of a BMP file, fill in bmp_info with what 40042506Syokota** can be learnt from it. Return nonzero if the file isn't usable. 40142506Syokota** 40242506Syokota** Take screen dimensions (swidth), (sheight) and (sdepth) and make sure we 40342506Syokota** can work with these. 40442506Syokota*/ 40542506Syokotastatic int 40642506Syokotabmp_Init(const char *data, int swidth, int sheight, int sdepth) 40742506Syokota{ 40842506Syokota BITMAPF *bmf = (BITMAPF *)data; 40942506Syokota int pind; 41042506Syokota 41142506Syokota bmp_info.data = NULL; /* assume setup failed */ 41242506Syokota#if 0 41342506Syokota bmp_info.vidmem = vidmem; /* remember where */ 41442506Syokota#endif 41542506Syokota 41642506Syokota /* check file ID */ 41742506Syokota if (bmf->bmfh.bfType != 0x4d42) { 41842506Syokota return(1); /* XXX check word ordering for big-endian ports? */ 41942506Syokota } 42042506Syokota 42142506Syokota /* save what we know about the screen */ 42242506Syokota bmp_info.swidth = swidth; 42342506Syokota bmp_info.sheight = sheight; 42442506Syokota bmp_info.sdepth = sdepth; 42542506Syokota 42642506Syokota /* where's the data? */ 42742506Syokota bmp_info.data = (u_char *)data + bmf->bmfh.bfOffBits; 42842506Syokota 42942506Syokota /* image parameters */ 43042506Syokota bmp_info.width = bmf->bmfi.bmiHeader.biWidth; 43142506Syokota bmp_info.height = bmf->bmfi.bmiHeader.biHeight; 43242506Syokota bmp_info.format = bmf->bmfi.bmiHeader.biCompression; 43342506Syokota 43442506Syokota switch(bmp_info.format) { /* check compression format */ 43542506Syokota case BI_RGB: 43642506Syokota case BI_RLE4: 43742506Syokota case BI_RLE8: 43842506Syokota break; 43942506Syokota default: 44042506Syokota return(1); /* unsupported compression format */ 44142506Syokota } 44242506Syokota 44342506Syokota /* palette details */ 44442506Syokota bmp_info.ncols = (bmf->bmfi.bmiHeader.biClrUsed); 44542506Syokota bzero(bmp_info.palette,sizeof(bmp_info.palette)); 44642506Syokota if (bmp_info.ncols == 0) { /* uses all of them */ 44742623Syokota bmp_info.ncols = 1 << bmf->bmfi.bmiHeader.biBitCount; 44842506Syokota } 44942506Syokota if ((bmp_info.height > bmp_info.sheight) || 45042506Syokota (bmp_info.width > bmp_info.swidth) || 45142506Syokota (bmp_info.ncols > (1 << sdepth))) { 45242506Syokota return(1); /* beyond screen capacity */ 45342506Syokota } 45442506Syokota 45542506Syokota /* read palette */ 45642506Syokota for (pind = 0; pind < bmp_info.ncols; pind++) { 45742506Syokota bmp_info.palette[pind][0] = bmf->bmfi.bmiColors[pind].rgbRed; 45842506Syokota bmp_info.palette[pind][1] = bmf->bmfi.bmiColors[pind].rgbGreen; 45942506Syokota bmp_info.palette[pind][2] = bmf->bmfi.bmiColors[pind].rgbBlue; 46042506Syokota } 46142506Syokota return(0); 46242506Syokota} 46342506Syokota 46442506Syokota/* 46542506Syokota** bmp_Draw 46642506Syokota** 46742506Syokota** Render the image. Return nonzero if that's not possible. 46842506Syokota** 46942506Syokota*/ 47042506Syokotastatic int 47142506Syokotabmp_Draw(video_adapter_t *adp) 47242506Syokota{ 47342506Syokota int line; 47442506Syokota 47542506Syokota if (bmp_info.data == NULL) { /* init failed, do nothing */ 47642506Syokota return(1); 47742506Syokota } 47842506Syokota 47942506Syokota /* clear the screen */ 48042506Syokota bmp_info.vidmem = (u_char *)adp->va_window; 48142506Syokota /* XXX; the following line is correct only for 8bpp modes */ 48242506Syokota bzero(bmp_info.vidmem, bmp_info.swidth * bmp_info.sheight); 48342506Syokota 48442506Syokota /* initialise the info structure for drawing */ 48542506Syokota bmp_info.index = bmp_info.data; 48642506Syokota 48742506Syokota /* set the palette for our image */ 48842506Syokota (*vidsw[adp->va_index]->load_palette)(adp, (u_char *)&bmp_info.palette); 48942506Syokota 49042506Syokota for (line = 0; (line < bmp_info.height) && bmp_info.index; line++) { 49142506Syokota bmp_DecodeLine(&bmp_info, line); 49242506Syokota } 49342506Syokota return(0); 49442506Syokota} 495