/* 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