最近有个朋友希望我帮忙给他的一块板子加一个启动画面。板子是用烂了的三星2410处理器。 不同之处就在于他的板子是640 x 480 VGA输出,而不是通常的240 x 320的LCD。
在Windows CE中,通常加入启动画面的方法很土,因为OS没有启动,所以没有什么BitBlt,StretchBlt等方法可以贴图,唯一的方法就是在启动的过程中,直接往显卡的Framebuffer里面写数据。这个工作一般在Boot Loader里面做,如果在OS启动的时候一般就太晚了,如果不加入人为的延时,启动画面刚一显示,就到了OS画面了。做法一般是这样,在Boot Loader里面:
BOOL OEMPlatformInit() { ………………………… // Init the Display InitDisplay();
………………………… }
然后是InitDisplay函数一般如下所示: static void InitDisplay() { int i = 0; int j = 0; volatile IOPreg *s2410IOP; volatile LCDreg *s2410LCD;
s2410IOP = (IOPreg *)IOP_BASE; s2410LCD = (LCDreg *)LCD_BASE;
// LCD port initialize. s2410IOP->rGPCUP = 0xFFFFFFFF; s2410IOP->rGPCCON = 0xAAAAAAAA; s2410IOP->rGPCCON = 0xAAAAAAAA;
s2410IOP->rGPDUP = 0xFFFFFFFF; s2410IOP->rGPDCON = 0xAAAAAAAA;
s2410IOP->rGPGCON &= ~(3 << 8); /* Set LCD_PWREN as output */ s2410IOP->rGPGCON |= (1 << 8);
s2410IOP->rGPGDAT |= (1 << 4); /* Backlight ON */
s2410LCD->rLCDCON1=(1<<8)|(MVAL_USED<<7)|(3<<5)|(12<<1)|0; // TFT LCD panel,16bpp TFT,ENVID=off s2410LCD->rLCDCON2=(VBPD<<24)|(LINEVAL_TFT<<14)|(VFPD<<6)|(VSPW); s2410LCD->rLCDCON3=(HBPD<<19)|(HOZVAL_TFT<<8)|(HFPD); s2410LCD->rLCDCON4=(MVAL<<8)|(HSPW); s2410LCD->rLCDCON5=(1<<11)|(1<<9)|(1<<8)|(1<<3)|(1<<0); //FRM5:6:5,HSYNC and VSYNC are inverted s2410LCD->rLCDSADDR1=((FRAMEBUF_DMA_BASE>>22)<<21)|M5D(FRAMEBUF_DMA_BASE>>1); s2410LCD->rLCDSADDR2=M5D( (FRAMEBUF_DMA_BASE+(LCD_XSIZE_TFT*LCD_YSIZE_TFT*2))>>1 ); s2410LCD->rLCDSADDR3=(((LCD_XSIZE_TFT-LCD_XSIZE_TFT)/1)<<11)|(LCD_XSIZE_TFT/1); //s2410LCD->rLCDINTMSK|=(3); // MASK LCD Sub Interrupt s2410LCD->rLPCSEL&=(~7); // Disable LPC3600 s2410LCD->rTPAL=0; // Disable Temp Palette s2410LCD->rLCDCON1 |= 1;
// Display a bitmap image on the LCD... //memcpy((void *)FRAMEBUF_BASE, ScreenBitmap, ARRAY_SIZE_TFT_16BIT);
// Jason : Interpolation
EdbgOutputDebugString("+Interpolation\r\n");
for(i = 0; i < 320 * 240; i++) { PWORD pWord = (PWORD)ScreenBitmap; PWORD pFrmBuf = (PWORD)FRAMEBUF_BASE;
pFrmBuf[4 * i - 2 * (i % 320)] = pWord; pFrmBuf[4 * i - 2 * (i % 320) + 1] = pWord; pFrmBuf[4 * i - 2 * (i % 320) + 320 * 2] = pWord; pFrmBuf[4 * i - 2 * (i % 320) + 1 + 320 * 2] = pWord;
}
前面初始化硬件的代码没什么好看的。 注意到memcpy((void *)FRAMEBUF_BASE, ScreenBitmap, ARRAY_SIZE_TFT_16BIT);这一句,这就是显示启动画面的关键了,直接调用memcpy函数,把一个大数组,复制到了FRAMEBUF_BASE这个地址。这个其实就是直接往显卡缓冲区里面填东西了。至于这个大数组,可以用Image2LCD等类似软件生成,也就是直接把一张位图转成C语言数组的软件,这东西在游戏开发中用的比较多。
一般情况下,这种方法都是OK的,但是现在遇到什么问题呢?
因为目标设备的显示分辨率是640 x 480 x 16位的,所以这个大数组需要多大的存储空间是可以算出来的:640 * 480 * 2 = 600KB。但是对于一般的boot loader而言,板子上不会划分这么大的空间给boot loader用,一般boot loader的空间只有256KB。(其实可以人为改,只不过这个板子用linux的loader 引导CE的loader,才产生这么多问题)。所以解决方法只能有下面两条:
1. 压缩,然后在运行时候解压缩,然后再memcpy。可以找一些最基本的通用开源压缩算法来完成。 2. 插值,弄一张小图片,把它插值到640 x 480。
两者权衡,偶还是决定采用插值的办法,这样的工作量还是小一些的。其实也就是自己把StretchBlt函数实现了。
哎,本科的时候没有开设图形学,所以也不知道插值有没有具体的公式,只能自己推导了。好在这个不是一个通用的算法,只是放大4倍的这样一个特例。一个点变四个点,还是很容易的。自己拿着纸笔比划了一阵子,终于得出个公式来,公式不好帖,直接帖代码就是下面这样:
for(i = 0; i < 320 * 240; i++) { PWORD pWord = (PWORD)ScreenBitmap; PWORD pFrmBuf = (PWORD)FRAMEBUF_BASE;
pFrmBuf[4 * i - 2 * (i % 320)] = pWord; pFrmBuf[4 * i - 2 * (i % 320) + 1] = pWord; pFrmBuf[4 * i - 2 * (i % 320) + 320 * 2] = pWord; pFrmBuf[4 * i - 2 * (i % 320) + 1 + 320 * 2] = pWord; }
只不过这次准备的是一张320 x 240的照片,然后采用一重的循环,把它写到framebuffer相应的位置去。
最终的效果还是不错的,不知道插值有没有更好的公式。如果有,也请告诉偶。呵呵。 |
文章评论(0条评论)
登录后参与讨论