/*
gdi.cpp
Copyright (C) 2007 Acekard, www.acekard.com
Copyright (C) 2007-2009 somebody
Copyright (C) 2009 yellow wood goblin
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see .
*/
#include
#include
#include "dbgtool.h"
#include "gdi.h"
#include "sprite.h"
#include "../../share/memtool.h"
#include "userinput.h"
#include "globalsettings.h"
#include "fontfactory.h"
static inline void dmaCopyWordsGdi(uint8 channel,const void* src,void* dest,uint32 size)
{
DC_FlushRange(src,size);
dmaCopyWords(channel,src,dest,size);
DC_InvalidateRange(dest,size);
}
#ifdef DEBUG
PrintConsole custom_console;
static void MyInitConsole(u16* aBufferSub1,u16* aBufferSub2)
{
custom_console=*consoleGetDefault();
custom_console.loadGraphics=false;
consoleInit(&custom_console, custom_console.bgLayer, BgType_Text4bpp, BgSize_T_256x256, custom_console.mapBase, custom_console.gfxBase, false, false);
custom_console.fontBgMap=aBufferSub1;
custom_console.fontBgGfx=aBufferSub2;
dmaCopy(custom_console.font.gfx, custom_console.fontBgGfx, custom_console.font.numChars * 64 / 2);
custom_console.fontCurPal = 15 << 12;
u16* palette = BG_PALETTE_SUB;
palette[1 * 16 - 15] = RGB15(0,0,0); //30 normal black
palette[2 * 16 - 15] = RGB15(15,0,0); //31 normal red
palette[3 * 16 - 15] = RGB15(0,15,0); //32 normal green
palette[4 * 16 - 15] = RGB15(15,15,0); //33 normal yellow
palette[5 * 16 - 15] = RGB15(0,0,15); //34 normal blue
palette[6 * 16 - 15] = RGB15(15,0,15); //35 normal magenta
palette[7 * 16 - 15] = RGB15(0,15,15); //36 normal cyan
palette[8 * 16 - 15] = RGB15(24,24,24); //37 normal white
palette[9 * 16 - 15] = RGB15(15,15,15); //40 bright black
palette[10 * 16 - 15] = RGB15(31,0,0); //41 bright red
palette[11 * 16 - 15] = RGB15(0,31,0); //42 bright green
palette[12 * 16 - 15] = RGB15(31,31,0); //43 bright yellow
palette[13 * 16 - 15] = RGB15(0,0,31); //44 bright blue
palette[14 * 16 - 15] = RGB15(31,0,31); //45 bright magenta
palette[15 * 16 - 15] = RGB15(0,31,31); //46 bright cyan
palette[16 * 16 - 15] = RGB15(31,31,31); //47 & 39 bright white
}
#endif
cGdi::cGdi()
{
_transColor=0;
_mainEngineLayer=MEL_UP;
_subEngineMode=SEM_TEXT;
_bufferMain2=NULL;
_bufferSub2=NULL;
#ifdef DEBUG
_bufferSub3=NULL;
#endif
_sprites=NULL;
}
cGdi::~cGdi()
{
if( NULL != _bufferMain2 )
delete[] _bufferMain2;
if( NULL != _bufferSub2 )
delete[] _bufferSub2;
#ifdef DEBUG
if( NULL != _bufferSub3 )
delete[] _bufferSub3;
#endif
if( NULL != _sprites )
delete[] _sprites;
}
void cGdi::init()
{
swapLCD();
activeFbMain();
activeFbSub();
cSprite::sysinit();
}
void cGdi::initBg(const std::string& aFileName)
{
_sprites=new cSprite[12];
_background=createBMP15FromFile(aFileName);
if(_background.width()>1;
for(size_t ii=0;ii<3;++ii)
{
for(size_t jj=0;jj<4;++jj)
{
size_t index=ii*4+jj;
_sprites[index].init(2+index);
_sprites[index].setSize(SS_SIZE_64);
_sprites[index].setPriority(3);
_sprites[index].setBufferOffset(32+index*64);
_sprites[index].setPosition(jj*64,ii*64);
for(size_t kk=0;kk<64;++kk)
{
for(size_t ll=0;ll<64;++ll)
{
((u16*)_sprites[index].buffer())[kk*64+ll]=((u16*)_background.buffer())[(kk+ii*64)*pitch+(ll+jj*64)];
}
}
_sprites[index].show();
}
}
oamUpdate(&oamMain);
}
void cGdi::swapLCD(void)
{
lcdSwap();
}
void cGdi::activeFbMain(void)
{
vramSetBankB( VRAM_B_MAIN_BG_0x06000000 );
vramSetBankD( VRAM_D_MAIN_BG_0x06020000 );
vramSetBankA( VRAM_A_MAIN_SPRITE_0x06400000 );
REG_BG2CNT = BG_BMP16_256x256 | BG_BMP_BASE(0) | BG_PRIORITY_1;
REG_BG2PA = 1 << 8; // 2 =放大倍数
REG_BG2PD = 1 << 8; // 2 =放大倍数
REG_BG2PB = 0;
REG_BG2PC = 0;
REG_BG2Y = 0;
REG_BG2X = 0;
REG_BG3CNT = BG_BMP16_256x256 | BG_BMP_BASE(8) | BG_PRIORITY_2;
REG_BG3PA = 1 << 8; // 2 =放大倍数
REG_BG3PD = 1 << 8; // 2 =放大倍数
REG_BG3PB = 0;
REG_BG3PC = 0;
REG_BG3Y = 0;
REG_BG3X = 0;
_bufferMain1 = (u16 *)0x06000000;
_bufferMain2 = (u16 *)new u32[256*192];
_bufferMain3 = (u16 *)0x06020000;
setMainEngineLayer( MEL_UP );
zeroMemory( _bufferMain1, 0x20000 );
fillMemory( _bufferMain3, 0x20000, 0xffffffff );
REG_BLDCNT = BLEND_ALPHA | BLEND_DST_BG2 | BLEND_DST_BG3;
REG_BLDALPHA = (4 << 8) | 7;
swiWaitForVBlank(); //remove tearing at bottop screen
videoSetMode( MODE_5_2D
| DISPLAY_BG2_ACTIVE
| DISPLAY_BG3_ACTIVE
| DISPLAY_SPR_ACTIVE
| DISPLAY_SPR_1D_BMP_SIZE_128
| DISPLAY_SPR_1D_BMP );
}
void cGdi::activeFbSub(void)
{
#ifdef DEBUG
_bufferSub3 = (u16 *)new u32[0x1200];
MyInitConsole(_bufferSub3+0x2000,_bufferSub3);
#endif
// 分配显存存, 128k
vramSetBankC( VRAM_C_SUB_BG_0x06200000 ); // 128k
// 初始化为文字模式
_subEngineMode = SEM_GRAPHICS;
// BMP bg 的参数设置,从 VRAM地址 0x06200000 开始,优先级3
REG_BG2CNT_SUB = BG_BMP16_256x256 | BG_BMP_BASE(0) | BG_PRIORITY_1;
REG_BG2PA_SUB = 1<<8;
REG_BG2PD_SUB = 1<<8;
REG_BG2PB_SUB = 0;
REG_BG2PC_SUB = 0;
REG_BG2Y_SUB = 0;
REG_BG2X_SUB = 0;
_bufferSub1 = (u16 *)0x06200000;
_bufferSub2 = (u16 *)new u32[256*192/2];
fillMemory( _bufferSub2, 0x18000, 0xffffffff );
fillMemory( _bufferSub1, 0x18000, 0xffffffff );
// text BG
// text bg 的字模占用 32(字节/字模) * 256(个ascii字) = 8192 字节显存,
// 文字显示占用 32 x 32 * 2 = 2048 字节显存
// 字模从 block 8 开始 = 0x06200000 + 8 * 0x4000 = 0x06220000
// 文字信息从 block 72 开始 = 0x06200000 + 72 * 0x800 = 0x06224000
// 优先级 2
#ifdef DEBUG
BG_PALETTE_SUB[255] = RGB15(31,31,31); //by default font will be rendered with color 255
REG_BG0CNT_SUB = BG_TILE_BASE(0) | BG_MAP_BASE(8) | BG_PRIORITY_2;
#endif
swiWaitForVBlank(); //remove tearing at top screen
// 模式5,开两层BG,一层BMP,一层文字(用于调试),bmp层现在默认关闭
videoSetModeSub( MODE_5_2D | DISPLAY_BG2_ACTIVE );
}
void cGdi::drawLine( s16 x1, s16 y1, s16 x2, s16 y2, GRAPHICS_ENGINE engine )
{
if((x1==x2)&&(y1==y2)) return;
if(x1==x2) {
int ys,ye;
if(y1abs(y2-y1)) {
int px=0;
float py=0;
int xe=x2-x1;
float ye=y2-y1;
int xv;
float yv;
if(0> 1;
u16 remain = w & 1;
if( destAligned )
for( u32 i = 0; i < h; ++i ) {
swiFastCopy( pSrc, pDest, COPY_MODE_WORD | COPY_MODE_FILL | halfWidth );
pDest += halfWidth << 1;
if( remain )
*pDest++ = *pSrc;
pDest += destInc;
}
else
for( u32 i = 0; i < h; ++i ) {
for( u32 j = 0; j < w; ++j ) {
*pDest++ = pSrc[j&1];
}
pDest += destInc;
}
}
void cGdi::fillRectBlend( u16 color1, u16 color2, s16 x, s16 y, u16 w, u16 h, GRAPHICS_ENGINE engine, u16 opacity)
{
if(opacity==0) return;
if(opacity==100)
{
fillRect(color1,color2,x,y,w,h,engine);
return;
}
u16* pSrc=((GE_MAIN==engine)?(u16*)_background.buffer():_bufferSub2)+(y<<8)+x;
u16* pDest=((GE_MAIN==engine)?(_bufferMain2+_layerPitch):_bufferSub2)+(y<<8)+x;
u32 alpha=(opacity*32)/100;
u32 destInc=256-w;
for(u32 ii=0;ii>5)|BIT(15);
}
pDest+=destInc;
pSrc+=destInc;
}
}
void cGdi::bitBlt( const void * src, s16 srcW, s16 srcH, s16 destX, s16 destY, u16 destW, u16 destH, GRAPHICS_ENGINE engine )
{
if( destW <= 0 )
return;
u16 * pSrc = (u16 *)src;
u16 * pDest = NULL;
if( GE_MAIN == engine )
pDest = _bufferMain2 + (destY) * 256 + destX + _layerPitch;
else
pDest = _bufferSub2 + (destY) * 256 + destX;
bool destAligned = !(destX & 1);
if( destW > srcW )
destW = srcW;
if( destH > srcH )
destH = srcH;
u16 srcInc = srcW - destW;
u16 destInc = 256 - destW;
u16 destHalfWidth = destW >> 1;
u16 lineSize = destW << 1;
u16 remain = destW & 1;
if( destAligned ) {
for( u32 i = 0; i < destH; ++i ) {
dmaCopyWordsGdi( 3, pSrc, pDest, lineSize );
pDest += destHalfWidth << 1;
pSrc += destHalfWidth << 1;
if( remain )
*pDest++ = *pSrc++;
pDest += destInc;
pSrc += srcInc;
}
}
}
void cGdi::bitBlt( const void * src, s16 destX, s16 destY, u16 destW, u16 destH, GRAPHICS_ENGINE engine )
{
u16 * pSrc = (u16 *)src;
u16 * pDest = NULL;
if( GE_MAIN == engine )
pDest = _bufferMain2 + (destY) * 256 + destX + _layerPitch;
else
pDest = _bufferSub2 + (destY) * 256 + destX;
u16 pitchPixel = (destW + (destW & 1));
u16 destInc = 256 - pitchPixel;
u16 halfPitch = pitchPixel >> 1;
u16 remain = pitchPixel & 1;
for( u16 i = 0; i < destH; ++i ) {
swiFastCopy( pSrc, pDest, COPY_MODE_WORD | COPY_MODE_COPY | halfPitch );
pDest += halfPitch << 1;
pSrc += halfPitch << 1;
if( remain )
*pDest++ = *pSrc++;
pDest += destInc;
}
}
// maskBlt 要destW是偶数,速度可以快一倍
// 不是偶数也可以,但要求在内存中 src 的 pitch 凑成偶数
void cGdi::maskBlt( const void * src, s16 destX, s16 destY, u16 destW, u16 destH, GRAPHICS_ENGINE engine )
{
u16 * pSrc = (u16 *)src;
u16 * pDest = NULL;
bool destAligned = !(destX & 1);
if( GE_MAIN == engine )
pDest = _bufferMain2 + (destY) * 256 + destX + _layerPitch;
else
pDest = _bufferSub2 + (destY) * 256 + destX;
u16 pitch = (destW + (destW & 1));
u16 destInc = 256 - pitch;
u16 halfPitch = pitch >> 1;
if( destAligned )
for( u32 i = 0; i < destH; ++i ) {
for( u32 j = 0; j < halfPitch; ++j ) {
if( ((*(u32 *)pSrc) & 0x80008000) == 0x80008000 ) {
*(u32 *)pDest = *(u32 *)pSrc;
pSrc += 2; pDest += 2;
}
else {
if( *pSrc & 0x8000 )
*pDest = *pSrc;
pSrc++; pDest++;
if( *pSrc & 0x8000 )
*pDest = *pSrc;
pSrc++; pDest++;
}
}
pDest += destInc;
}
else
for( u16 i = 0; i < destH; ++i ) {
for( u16 j = 0; j < pitch; ++j ) {
if( *pSrc & 0x8000 )
*pDest = *pSrc;
pDest++; pSrc++;
}
pDest += destInc;
}
}
void cGdi::maskBlt( const void * src, s16 srcW, s16 srcH, s16 destX, s16 destY, u16 destW, u16 destH, GRAPHICS_ENGINE engine )
{
if( destW <= 0 )
return;
u16 * pSrc = (u16 *)src;
u16 * pDest = NULL;
if( GE_MAIN == engine )
pDest = _bufferMain2 + (destY) * 256 + destX + _layerPitch;
else
pDest = _bufferSub2 + (destY) * 256 + destX;
bool destAligned = !(destX & 1);
if( destW > srcW )
destW = srcW;
if( destH > srcH )
destH = srcH;
u16 srcInc = srcW - destW;
u16 destInc = 256 - destW;
u16 destHalfWidth = destW >> 1;
u16 pitch = (destW + (destW & 1));
u16 remain = destW & 1;
if( destAligned ) {
for( u32 i = 0; i < destH; ++i ) {
for( u32 j = 0; j < destHalfWidth; ++j ) {
if( ((*(u32 *)pSrc) & 0x80008000) == 0x80008000 ) {
*(u32 *)pDest = *(u32 *)pSrc;
pSrc += 2; pDest += 2;
}
else {
if( *pSrc & 0x8000 )
*pDest = *pSrc;
pSrc++; pDest++;
if( *pSrc & 0x8000 )
*pDest = *pSrc;
pSrc++; pDest++;
}
}
if( remain )
*pDest++ = *pSrc++;
pDest += destInc;
pSrc += srcInc;
}
}
else
for( u16 i = 0; i < destH; ++i ) {
for( u16 j = 0; j < pitch; ++j ) {
if( *pSrc & 0x8000 )
*pDest = *pSrc;
pDest++; pSrc++;
}
pDest += destInc;
pSrc += srcInc;
}
}
void cGdi::textOutRect( s16 x, s16 y, u16 w, u16 h, const char * text, GRAPHICS_ENGINE engine )
{
const s16 originX=x,limitY=y+h-gs().fontHeight;
while(*text)
{
if('\r'==*text||'\n'==*text)
{
y+=gs().fontHeight; //FIXME
x=originX;
++text;
if(y>limitY) break;
}
else
{
u32 ww,add;
font().Info(text,&ww,&add);
if(x+(s16)ww