mirror of
https://github.com/dborth/vbagx.git
synced 2024-11-29 22:14:17 +01:00
1015 lines
23 KiB
C++
1015 lines
23 KiB
C++
|
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
||
|
// Copyright (C) 1999-2003 Forgotten
|
||
|
// Copyright (C) 2004 Forgotten and the VBA development team
|
||
|
|
||
|
// 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 2, 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, write to the Free Software Foundation,
|
||
|
// Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
||
|
|
||
|
#include <stdlib.h>
|
||
|
#include <string.h>
|
||
|
|
||
|
#include "../System.h"
|
||
|
#include "../Port.h"
|
||
|
#include "../Util.h"
|
||
|
#include "GB.h"
|
||
|
#include "gbGlobals.h"
|
||
|
|
||
|
extern u8 *pix;
|
||
|
extern bool speedup;
|
||
|
|
||
|
#define GBSGB_NONE 0
|
||
|
#define GBSGB_RESET 1
|
||
|
#define GBSGB_PACKET_TRANSMIT 2
|
||
|
|
||
|
u8 *gbSgbBorderChar = NULL;
|
||
|
u8 *gbSgbBorder = NULL;
|
||
|
|
||
|
int gbSgbCGBSupport = 0;
|
||
|
int gbSgbMask = 0;
|
||
|
int gbSgbMode = 0;
|
||
|
int gbSgbPacketState = GBSGB_NONE;
|
||
|
int gbSgbBit = 0;
|
||
|
int gbSgbPacketTimeout = 0;
|
||
|
int GBSGB_PACKET_TIMEOUT = 66666;
|
||
|
u8 gbSgbPacket[16*7];
|
||
|
int gbSgbPacketNBits = 0;
|
||
|
int gbSgbPacketByte = 0;
|
||
|
int gbSgbPacketNumber = 0;
|
||
|
int gbSgbMultiplayer = 0;
|
||
|
int gbSgbFourPlayers = 0;
|
||
|
u8 gbSgbNextController = 0x0f;
|
||
|
u8 gbSgbReadingController = 0;
|
||
|
u16 gbSgbSCPPalette[4*512];
|
||
|
u8 gbSgbATF[20 * 18];
|
||
|
u8 gbSgbATFList[45 * 20 * 18];
|
||
|
u8 gbSgbScreenBuffer[4160];
|
||
|
|
||
|
inline void gbSgbDraw24Bit(u8 *p, u16 v)
|
||
|
{
|
||
|
*((u32*) p) = systemColorMap32[v];
|
||
|
}
|
||
|
|
||
|
inline void gbSgbDraw32Bit(u32 *p, u16 v)
|
||
|
{
|
||
|
*p = systemColorMap32[v];
|
||
|
}
|
||
|
|
||
|
inline void gbSgbDraw16Bit(u16 *p, u16 v)
|
||
|
{
|
||
|
*p = systemColorMap16[v];
|
||
|
}
|
||
|
|
||
|
void gbSgbReset()
|
||
|
{
|
||
|
gbSgbPacketTimeout = 0;
|
||
|
gbSgbCGBSupport = 0;
|
||
|
gbSgbMask = 0;
|
||
|
gbSgbPacketState = GBSGB_NONE;
|
||
|
gbSgbBit = 0;
|
||
|
gbSgbPacketNBits = 0;
|
||
|
gbSgbPacketNumber = 0;
|
||
|
gbSgbMultiplayer = 0;
|
||
|
gbSgbFourPlayers = 0;
|
||
|
gbSgbNextController = 0x0f;
|
||
|
gbSgbReadingController = 0;
|
||
|
|
||
|
memset(gbSgbSCPPalette, 0, 512*4);
|
||
|
memset(gbSgbATF, 0, 20*18);
|
||
|
memset(gbSgbATFList, 0, 45 * 20 * 18);
|
||
|
memset(gbSgbPacket, 0, 16 * 7);
|
||
|
memset(gbSgbBorderChar, 0, 32*256);
|
||
|
memset(gbSgbBorder, 0, 2048);
|
||
|
|
||
|
int i;
|
||
|
for(i = 1; i < 2048; i+=2)
|
||
|
{
|
||
|
gbSgbBorder[i] = 1 << 2;
|
||
|
}
|
||
|
|
||
|
for(i = 0; i < 4; i++)
|
||
|
{
|
||
|
gbPalette[i*4] = (0x1f) | (0x1f << 5) | (0x1f << 10);
|
||
|
gbPalette[i*4+1] = (0x15) | (0x15 << 5) | (0x15 << 10);
|
||
|
gbPalette[i*4+2] = (0x0c) | (0x0c << 5) | (0x0c << 10);
|
||
|
gbPalette[i*4+3] = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbInit()
|
||
|
{
|
||
|
gbSgbBorderChar = (u8 *)malloc(32 * 256);
|
||
|
gbSgbBorder = (u8 *)malloc(2048);
|
||
|
|
||
|
gbSgbReset();
|
||
|
}
|
||
|
|
||
|
void gbSgbShutdown()
|
||
|
{
|
||
|
if(gbSgbBorderChar != NULL)
|
||
|
{
|
||
|
free(gbSgbBorderChar);
|
||
|
gbSgbBorderChar = NULL;
|
||
|
}
|
||
|
|
||
|
if(gbSgbBorder != NULL)
|
||
|
{
|
||
|
free(gbSgbBorder);
|
||
|
gbSgbBorder = NULL;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbFillScreen(u16 color)
|
||
|
{
|
||
|
switch(systemColorDepth)
|
||
|
{
|
||
|
case 16:
|
||
|
{
|
||
|
for(int y = 0; y < 144; y++)
|
||
|
{
|
||
|
int yLine = (y+gbBorderRowSkip+1)*(gbBorderLineSkip+2) +
|
||
|
gbBorderColumnSkip;
|
||
|
u16 *dest = (u16*)pix + yLine;
|
||
|
for(register int x = 0; x < 160; x++)
|
||
|
gbSgbDraw16Bit(dest++, color);
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 24:
|
||
|
{
|
||
|
for(int y = 0; y < 144; y++)
|
||
|
{
|
||
|
int yLine = (y+gbBorderRowSkip)*gbBorderLineSkip + gbBorderColumnSkip;
|
||
|
u8 *dest = (u8 *)pix + yLine*3;
|
||
|
for(register int x = 0; x < 160; x++)
|
||
|
{
|
||
|
gbSgbDraw24Bit(dest, color);
|
||
|
dest += 3;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
case 32:
|
||
|
{
|
||
|
for(int y = 0; y < 144; y++)
|
||
|
{
|
||
|
int yLine = (y+gbBorderRowSkip+1)*(gbBorderLineSkip+1) + gbBorderColumnSkip;
|
||
|
u32 *dest = (u32 *)pix + yLine;
|
||
|
for(register int x = 0; x < 160; x++)
|
||
|
{
|
||
|
gbSgbDraw32Bit(dest++, color);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
#define getmem(x) gbMemoryMap[(x) >> 12][(x) & 0xfff]
|
||
|
|
||
|
void gbSgbRenderScreenToBuffer()
|
||
|
{
|
||
|
u16 mapAddress = 0x9800;
|
||
|
|
||
|
if(register_LCDC & 0x08)
|
||
|
mapAddress = 0x9c00;
|
||
|
|
||
|
u16 patternAddress = 0x8800;
|
||
|
|
||
|
int flag = 1;
|
||
|
|
||
|
if(register_LCDC & 0x10)
|
||
|
{
|
||
|
patternAddress = 0x8000;
|
||
|
flag = 0;
|
||
|
}
|
||
|
|
||
|
u8 *toAddress = gbSgbScreenBuffer;
|
||
|
|
||
|
for(int i = 0; i < 13; i++)
|
||
|
{
|
||
|
for(int j = 0; j < 20; j++)
|
||
|
{
|
||
|
int tile = getmem(mapAddress);
|
||
|
mapAddress++;
|
||
|
|
||
|
if(flag)
|
||
|
{
|
||
|
if(tile > 127)
|
||
|
tile -= 128;
|
||
|
else
|
||
|
tile += 128;
|
||
|
}
|
||
|
for(int k = 0; k < 16; k++)
|
||
|
*toAddress++ = getmem(patternAddress + tile*16 + k);
|
||
|
}
|
||
|
mapAddress += 12;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbDrawBorderTile(int x, int y, int tile, int attr)
|
||
|
{
|
||
|
u16 *dest = (u16*)pix + ((y+1) * (256+2)) + x;
|
||
|
u8 *dest8 = (u8*)pix + ((y*256)+x)*3;
|
||
|
u32 *dest32 = (u32*)pix + ((y+1)*257) + x;
|
||
|
|
||
|
u8 *tileAddress = &gbSgbBorderChar[tile * 32];
|
||
|
u8 *tileAddress2 = &gbSgbBorderChar[tile * 32 + 16];
|
||
|
|
||
|
u8 l = 8;
|
||
|
|
||
|
u8 palette = ((attr >> 2 ) & 7);
|
||
|
|
||
|
if(palette < 4)
|
||
|
palette += 4;
|
||
|
|
||
|
palette *= 16;
|
||
|
|
||
|
u8 xx = 0;
|
||
|
u8 yy = 0;
|
||
|
|
||
|
int flipX = attr & 0x40;
|
||
|
int flipY = attr & 0x80;
|
||
|
|
||
|
while(l > 0)
|
||
|
{
|
||
|
u8 mask = 0x80;
|
||
|
u8 a = *tileAddress++;
|
||
|
u8 b = *tileAddress++;
|
||
|
u8 c = *tileAddress2++;
|
||
|
u8 d = *tileAddress2++;
|
||
|
|
||
|
while(mask > 0)
|
||
|
{
|
||
|
|
||
|
u8 color = 0;
|
||
|
if(a & mask)
|
||
|
color++;
|
||
|
if(b & mask)
|
||
|
color+=2;
|
||
|
if(c & mask)
|
||
|
color+=4;
|
||
|
if(d & mask)
|
||
|
color+=8;
|
||
|
|
||
|
u8 xxx = xx;
|
||
|
u8 yyy = yy;
|
||
|
|
||
|
if(flipX)
|
||
|
xxx = 7 - xx;
|
||
|
if(flipY)
|
||
|
yyy = 7 - yy;
|
||
|
|
||
|
u16 c = gbPalette[palette + color];
|
||
|
if(!color)
|
||
|
c = gbPalette[0];
|
||
|
if((yy < 40 || yy >= 184) || (xx < 48 || xx >= 208))
|
||
|
{
|
||
|
switch(systemColorDepth)
|
||
|
{
|
||
|
case 16:
|
||
|
gbSgbDraw16Bit(dest + yyy*(256+2) + xxx, c);
|
||
|
break;
|
||
|
case 24:
|
||
|
gbSgbDraw24Bit(dest8 + (yyy*256+xxx)*3, c);
|
||
|
break;
|
||
|
case 32:
|
||
|
gbSgbDraw32Bit(dest32 + yyy*(256+1)+xxx, c);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
mask >>= 1;
|
||
|
|
||
|
xx++;
|
||
|
}
|
||
|
yy++;
|
||
|
xx = 0;
|
||
|
l--;
|
||
|
mask = 0x80;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbRenderBorder()
|
||
|
{
|
||
|
if(gbBorderOn)
|
||
|
{
|
||
|
u8 *fromAddress = gbSgbBorder;
|
||
|
|
||
|
for(u8 y = 0; y < 28; y++)
|
||
|
{
|
||
|
for(u8 x = 0; x< 32; x++)
|
||
|
{
|
||
|
u8 tile = *fromAddress++;
|
||
|
u8 attr = *fromAddress++;
|
||
|
|
||
|
gbSgbDrawBorderTile(x*8,y*8,tile,attr);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbPicture()
|
||
|
{
|
||
|
gbSgbRenderScreenToBuffer();
|
||
|
|
||
|
memcpy(gbSgbBorder, gbSgbScreenBuffer, 2048);
|
||
|
|
||
|
u16 *paletteAddr = (u16 *)&gbSgbScreenBuffer[2048];
|
||
|
|
||
|
for(int i = 64; i < 128; i++)
|
||
|
{
|
||
|
gbPalette[i] = READ16LE(paletteAddr++);
|
||
|
}
|
||
|
|
||
|
gbSgbCGBSupport |= 4;
|
||
|
|
||
|
if(gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4)
|
||
|
{
|
||
|
gbBorderOn = 1;
|
||
|
systemGbBorderOn();
|
||
|
}
|
||
|
|
||
|
if(gbBorderOn && !gbSgbMask)
|
||
|
gbSgbRenderBorder();
|
||
|
|
||
|
if(gbSgbMode && gbCgbMode && gbSgbCGBSupport > 4)
|
||
|
{
|
||
|
gbSgbCGBSupport = 0;
|
||
|
gbSgbMode = 0;
|
||
|
gbSgbMask = 0;
|
||
|
gbSgbRenderBorder();
|
||
|
gbReset();
|
||
|
}
|
||
|
|
||
|
if(gbSgbCGBSupport > 4)
|
||
|
gbSgbCGBSupport = 0;
|
||
|
}
|
||
|
|
||
|
void gbSgbSetPalette(int a,int b,u16 *p)
|
||
|
{
|
||
|
u16 bit00 = READ16LE(p++);
|
||
|
int i;
|
||
|
|
||
|
for(i = 1; i < 4; i++)
|
||
|
{
|
||
|
gbPalette[a*4+i] = READ16LE(p++);
|
||
|
}
|
||
|
|
||
|
for(i = 1; i < 4; i++)
|
||
|
{
|
||
|
gbPalette[b*4+i] = READ16LE(p++);
|
||
|
}
|
||
|
|
||
|
gbPalette[0] = gbPalette[4] = gbPalette[8] = gbPalette[12] = bit00;
|
||
|
if(gbBorderOn && !gbSgbMask)
|
||
|
gbSgbRenderBorder();
|
||
|
}
|
||
|
|
||
|
void gbSgbScpPalette()
|
||
|
{
|
||
|
gbSgbRenderScreenToBuffer();
|
||
|
|
||
|
u16 *fromAddress = (u16 *)gbSgbScreenBuffer;
|
||
|
|
||
|
for(int i = 0; i < 512*4; i++)
|
||
|
{
|
||
|
gbSgbSCPPalette[i] = READ16LE(fromAddress++);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbSetATF(int n)
|
||
|
{
|
||
|
if(n < 0)
|
||
|
n = 0;
|
||
|
if(n > 44)
|
||
|
n = 44;
|
||
|
memcpy(gbSgbATF,&gbSgbATFList[n * 20 * 18], 20 * 18);
|
||
|
|
||
|
if(gbSgbPacket[1] & 0x40)
|
||
|
{
|
||
|
gbSgbMask = 0;
|
||
|
if(gbBorderOn)
|
||
|
gbSgbRenderBorder();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbSetPalette()
|
||
|
{
|
||
|
u16 pal = READ16LE((((u16 *)&gbSgbPacket[1])))&511;
|
||
|
memcpy(&gbPalette[0], &gbSgbSCPPalette[pal*4], 4 * sizeof(u16));
|
||
|
|
||
|
pal = READ16LE((((u16 *)&gbSgbPacket[3])))&511;
|
||
|
memcpy(&gbPalette[4], &gbSgbSCPPalette[pal*4], 4 * sizeof(u16));
|
||
|
|
||
|
pal = READ16LE((((u16 *)&gbSgbPacket[5])))&511;
|
||
|
memcpy(&gbPalette[8], &gbSgbSCPPalette[pal*4], 4 * sizeof(u16));
|
||
|
|
||
|
pal = READ16LE((((u16 *)&gbSgbPacket[7])))&511;
|
||
|
memcpy(&gbPalette[12], &gbSgbSCPPalette[pal*4], 4 * sizeof(u16));
|
||
|
|
||
|
u8 atf = gbSgbPacket[9];
|
||
|
|
||
|
if(atf & 0x80)
|
||
|
{
|
||
|
gbSgbSetATF(atf & 0x3f);
|
||
|
}
|
||
|
|
||
|
if(atf & 0x40)
|
||
|
{
|
||
|
gbSgbMask = 0;
|
||
|
if(gbBorderOn)
|
||
|
gbSgbRenderBorder();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbAttributeBlock()
|
||
|
{
|
||
|
u8 *fromAddress = &gbSgbPacket[1];
|
||
|
|
||
|
u8 nDataSet = *fromAddress++;
|
||
|
if(nDataSet > 12)
|
||
|
nDataSet = 12;
|
||
|
if(nDataSet == 0)
|
||
|
nDataSet = 1;
|
||
|
|
||
|
while(nDataSet)
|
||
|
{
|
||
|
u8 controlCode = (*fromAddress++) & 7;
|
||
|
u8 paletteDesignation = (*fromAddress++) & 0x3f;
|
||
|
u8 startH = (*fromAddress++) & 0x1f;
|
||
|
u8 startV = (*fromAddress++) & 0x1f;
|
||
|
u8 endH = (*fromAddress++) & 0x1f;
|
||
|
u8 endV = (*fromAddress++) & 0x1f;
|
||
|
|
||
|
u8 * toAddress = gbSgbATF;
|
||
|
|
||
|
for(u8 y = 0; y < 18; y++)
|
||
|
{
|
||
|
for(u8 x = 0; x < 20; x++)
|
||
|
{
|
||
|
if(x < startH || y < startV ||
|
||
|
x > endH || y > endV)
|
||
|
{
|
||
|
// outside
|
||
|
if(controlCode & 0x04)
|
||
|
*toAddress = (paletteDesignation >> 4) & 0x03;
|
||
|
}
|
||
|
else if(x > startH && x < endH &&
|
||
|
y > startV && y < endV)
|
||
|
{
|
||
|
// inside
|
||
|
if(controlCode & 0x01)
|
||
|
*toAddress = paletteDesignation & 0x03;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
// surrounding line
|
||
|
if(controlCode & 0x02)
|
||
|
*toAddress = (paletteDesignation>>2) & 0x03;
|
||
|
else if(controlCode == 0x01)
|
||
|
*toAddress = paletteDesignation & 0x03;
|
||
|
}
|
||
|
toAddress++;
|
||
|
}
|
||
|
}
|
||
|
nDataSet--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbSetColumnPalette(u8 col, u8 p)
|
||
|
{
|
||
|
// if(col < 0)
|
||
|
// col = 0;
|
||
|
if(col > 19)
|
||
|
col = 19;
|
||
|
|
||
|
p &= 3;
|
||
|
|
||
|
u8 *toAddress = &gbSgbATF[col];
|
||
|
|
||
|
for(u8 y = 0; y < 18; y++)
|
||
|
{
|
||
|
*toAddress = p;
|
||
|
toAddress += 20;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbSetRowPalette(u8 row, u8 p)
|
||
|
{
|
||
|
// if(row < 0)
|
||
|
// row = 0;
|
||
|
if(row > 17)
|
||
|
row = 17;
|
||
|
|
||
|
p &= 3;
|
||
|
|
||
|
u8 *toAddress = &gbSgbATF[row*20];
|
||
|
|
||
|
for(u8 x = 0; x < 20; x++)
|
||
|
{
|
||
|
*toAddress++ = p;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbAttributeDivide()
|
||
|
{
|
||
|
u8 control = gbSgbPacket[1];
|
||
|
u8 coord = gbSgbPacket[2];
|
||
|
u8 colorBR = control & 3;
|
||
|
u8 colorAL = (control >> 2) & 3;
|
||
|
u8 colorOL = (control >> 4) & 3;
|
||
|
|
||
|
if(control & 0x40)
|
||
|
{
|
||
|
if(coord > 17)
|
||
|
coord = 17;
|
||
|
|
||
|
for(u8 i = 0; i < 18; i++)
|
||
|
{
|
||
|
if(i < coord)
|
||
|
gbSgbSetRowPalette(i, colorAL);
|
||
|
else if ( i > coord)
|
||
|
gbSgbSetRowPalette(i, colorBR);
|
||
|
else
|
||
|
gbSgbSetRowPalette(i, colorOL);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(coord > 19)
|
||
|
coord = 19;
|
||
|
|
||
|
for(u8 i = 0; i < 20; i++)
|
||
|
{
|
||
|
if(i < coord)
|
||
|
gbSgbSetColumnPalette(i, colorAL);
|
||
|
else if ( i > coord)
|
||
|
gbSgbSetColumnPalette(i, colorBR);
|
||
|
else
|
||
|
gbSgbSetColumnPalette(i, colorOL);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbAttributeLine()
|
||
|
{
|
||
|
u8 *fromAddress = &gbSgbPacket[1];
|
||
|
|
||
|
u8 nDataSet = *fromAddress++;
|
||
|
|
||
|
if(nDataSet > 0x6e)
|
||
|
nDataSet = 0x6e;
|
||
|
|
||
|
while(nDataSet)
|
||
|
{
|
||
|
u8 line = *fromAddress++;
|
||
|
u8 num = line & 0x1f;
|
||
|
u8 pal = (line >> 5) & 0x03;
|
||
|
if(line & 0x80)
|
||
|
{
|
||
|
if(num > 17)
|
||
|
num = 17;
|
||
|
gbSgbSetRowPalette(num,pal);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(num > 19)
|
||
|
num = 19;
|
||
|
gbSgbSetColumnPalette(num,pal);
|
||
|
}
|
||
|
nDataSet--;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbAttributeCharacter()
|
||
|
{
|
||
|
u8 startH = gbSgbPacket[1] & 0x1f;
|
||
|
u8 startV = gbSgbPacket[2] & 0x1f;
|
||
|
int nDataSet = READ16LE(((u16 *)&gbSgbPacket[3]));
|
||
|
int style = gbSgbPacket[5] & 1;
|
||
|
if(startH > 19)
|
||
|
startH = 19;
|
||
|
if(startV > 17)
|
||
|
startV = 17;
|
||
|
|
||
|
u8 s = 6;
|
||
|
u8 *fromAddress = &gbSgbPacket[6];
|
||
|
u8 v = *fromAddress++;
|
||
|
|
||
|
if(style)
|
||
|
{
|
||
|
while(nDataSet)
|
||
|
{
|
||
|
u8 p = (v >> s) & 3;
|
||
|
gbSgbATF[startV * 20 + startH] = p;
|
||
|
startV++;
|
||
|
if(startV == 18)
|
||
|
{
|
||
|
startV = 0;
|
||
|
startH++;
|
||
|
if(startH == 20)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(s)
|
||
|
s -= 2;
|
||
|
else
|
||
|
{
|
||
|
s = 6;
|
||
|
v = *fromAddress++;
|
||
|
nDataSet--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
while(nDataSet)
|
||
|
{
|
||
|
u8 p = (v >> s) & 3;
|
||
|
gbSgbATF[startV * 20 + startH] = p;
|
||
|
startH++;
|
||
|
if(startH == 20)
|
||
|
{
|
||
|
startH = 0;
|
||
|
startV++;
|
||
|
if(startV == 18)
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
if(s)
|
||
|
s -= 2;
|
||
|
else
|
||
|
{
|
||
|
s = 6;
|
||
|
v = *fromAddress++;
|
||
|
nDataSet--;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbSetATFList()
|
||
|
{
|
||
|
gbSgbRenderScreenToBuffer();
|
||
|
|
||
|
u8 *fromAddress = gbSgbScreenBuffer;
|
||
|
u8 *toAddress = gbSgbATFList;
|
||
|
|
||
|
for(int i = 0; i < 45; i++)
|
||
|
{
|
||
|
for(int j = 0; j < 90; j++)
|
||
|
{
|
||
|
u8 v = *fromAddress++;
|
||
|
u8 s = 6;
|
||
|
if(i == 2)
|
||
|
s = 6;
|
||
|
for(int k = 0; k < 4; k++)
|
||
|
{
|
||
|
*toAddress++ = (v >> s) & 0x03;
|
||
|
s -= 2;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbMaskEnable()
|
||
|
{
|
||
|
int gbSgbMaskFlag = gbSgbPacket[1] & 3;
|
||
|
|
||
|
gbSgbMask = gbSgbMaskFlag;
|
||
|
|
||
|
switch(gbSgbMaskFlag)
|
||
|
{
|
||
|
case 1:
|
||
|
break;
|
||
|
case 2:
|
||
|
gbSgbFillScreen(0x0000);
|
||
|
// memset(&gbPalette[0], 0, 128*sizeof(u16));
|
||
|
break;
|
||
|
case 3:
|
||
|
gbSgbFillScreen(gbPalette[0]);
|
||
|
break;
|
||
|
}
|
||
|
if(!gbSgbMask)
|
||
|
{
|
||
|
if(gbBorderOn)
|
||
|
gbSgbRenderBorder();
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbChrTransfer()
|
||
|
{
|
||
|
gbSgbRenderScreenToBuffer();
|
||
|
|
||
|
int address = (gbSgbPacket[1] & 1) * (128*32);
|
||
|
|
||
|
if(gbSgbPacket[1] & 1)
|
||
|
gbSgbCGBSupport |= 2;
|
||
|
else
|
||
|
gbSgbCGBSupport |= 1;
|
||
|
|
||
|
memcpy(&gbSgbBorderChar[address], gbSgbScreenBuffer, 128 * 32);
|
||
|
|
||
|
if(gbBorderAutomatic && !gbBorderOn && gbSgbCGBSupport > 4)
|
||
|
{
|
||
|
gbBorderOn = 1;
|
||
|
systemGbBorderOn();
|
||
|
}
|
||
|
|
||
|
if(gbBorderOn && !gbSgbMask)
|
||
|
gbSgbRenderBorder();
|
||
|
|
||
|
if(gbSgbMode && gbCgbMode && gbSgbCGBSupport == 7)
|
||
|
{
|
||
|
gbSgbCGBSupport = 0;
|
||
|
gbSgbMode = 0;
|
||
|
gbSgbMask = 0;
|
||
|
gbSgbRenderBorder();
|
||
|
gbReset();
|
||
|
}
|
||
|
|
||
|
if(gbSgbCGBSupport > 4)
|
||
|
gbSgbCGBSupport = 0;
|
||
|
}
|
||
|
|
||
|
void gbSgbMultiRequest()
|
||
|
{
|
||
|
if(gbSgbPacket[1] & 1)
|
||
|
{
|
||
|
gbSgbMultiplayer = 1;
|
||
|
if(gbSgbPacket[1] & 2)
|
||
|
gbSgbFourPlayers = 1;
|
||
|
else
|
||
|
gbSgbFourPlayers = 0;
|
||
|
gbSgbNextController = 0x0e;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gbSgbFourPlayers = 0;
|
||
|
gbSgbMultiplayer = 0;
|
||
|
gbSgbNextController = 0x0f;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbCommand()
|
||
|
{
|
||
|
int command = gbSgbPacket[0] >> 3;
|
||
|
// int nPacket = gbSgbPacket[0] & 7;
|
||
|
|
||
|
switch(command)
|
||
|
{
|
||
|
case 0x00:
|
||
|
gbSgbSetPalette(0,1,(u16 *)&gbSgbPacket[1]);
|
||
|
break;
|
||
|
case 0x01:
|
||
|
gbSgbSetPalette(2,3,(u16 *)&gbSgbPacket[1]);
|
||
|
break;
|
||
|
case 0x02:
|
||
|
gbSgbSetPalette(0,3,(u16 *)&gbSgbPacket[1]);
|
||
|
break;
|
||
|
case 0x03:
|
||
|
gbSgbSetPalette(1,2,(u16 *)&gbSgbPacket[1]);
|
||
|
break;
|
||
|
case 0x04:
|
||
|
gbSgbAttributeBlock();
|
||
|
break;
|
||
|
case 0x05:
|
||
|
gbSgbAttributeLine();
|
||
|
break;
|
||
|
case 0x06:
|
||
|
gbSgbAttributeDivide();
|
||
|
break;
|
||
|
case 0x07:
|
||
|
gbSgbAttributeCharacter();
|
||
|
break;
|
||
|
case 0x0a:
|
||
|
gbSgbSetPalette();
|
||
|
break;
|
||
|
case 0x0b:
|
||
|
gbSgbScpPalette();
|
||
|
break;
|
||
|
case 0x11:
|
||
|
gbSgbMultiRequest();
|
||
|
break;
|
||
|
case 0x13:
|
||
|
gbSgbChrTransfer();
|
||
|
break;
|
||
|
case 0x14:
|
||
|
gbSgbPicture();
|
||
|
break;
|
||
|
case 0x15:
|
||
|
gbSgbSetATFList();
|
||
|
break;
|
||
|
case 0x16:
|
||
|
gbSgbSetATF(gbSgbPacket[1] & 0x3f);
|
||
|
break;
|
||
|
case 0x17:
|
||
|
gbSgbMaskEnable();
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void gbSgbResetPacketState()
|
||
|
{
|
||
|
gbSgbPacketState = GBSGB_NONE;
|
||
|
gbSgbPacketTimeout = 0;
|
||
|
}
|
||
|
|
||
|
void gbSgbDoBitTransfer(u8 value)
|
||
|
{
|
||
|
value = value & 0x30;
|
||
|
switch(gbSgbPacketState)
|
||
|
{
|
||
|
case GBSGB_NONE:
|
||
|
if(value == 0)
|
||
|
{
|
||
|
gbSgbPacketState = GBSGB_RESET;
|
||
|
gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT;
|
||
|
}
|
||
|
else if (value == 0x30)
|
||
|
{
|
||
|
if(gbSgbMultiplayer)
|
||
|
{
|
||
|
if((gbSgbReadingController & 7) == 7)
|
||
|
{
|
||
|
gbSgbReadingController = 0;
|
||
|
if(gbSgbMultiplayer)
|
||
|
{
|
||
|
gbSgbNextController--;
|
||
|
if(gbSgbFourPlayers)
|
||
|
{
|
||
|
if(gbSgbNextController == 0x0b)
|
||
|
gbSgbNextController = 0x0f;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(gbSgbNextController == 0x0d)
|
||
|
gbSgbNextController = 0x0f;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gbSgbReadingController &= 3;
|
||
|
}
|
||
|
}
|
||
|
gbSgbPacketTimeout = 0;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(value == 0x10)
|
||
|
gbSgbReadingController |= 0x2;
|
||
|
else if(value == 0x20)
|
||
|
gbSgbReadingController |= 0x01;
|
||
|
gbSgbPacketTimeout = 0;
|
||
|
}
|
||
|
gbSgbPacketTimeout = 0;
|
||
|
break;
|
||
|
case GBSGB_RESET:
|
||
|
if(value == 0x30)
|
||
|
{
|
||
|
gbSgbPacketState = GBSGB_PACKET_TRANSMIT;
|
||
|
gbSgbPacketByte = 0;
|
||
|
gbSgbPacketNBits = 0;
|
||
|
gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT;
|
||
|
}
|
||
|
else if(value == 0x00)
|
||
|
{
|
||
|
gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT;
|
||
|
gbSgbPacketState = GBSGB_RESET;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
gbSgbPacketState = GBSGB_NONE;
|
||
|
gbSgbPacketTimeout = 0;
|
||
|
}
|
||
|
break;
|
||
|
case GBSGB_PACKET_TRANSMIT:
|
||
|
if(value == 0)
|
||
|
{
|
||
|
gbSgbPacketState = GBSGB_RESET;
|
||
|
gbSgbPacketTimeout = 0;
|
||
|
}
|
||
|
else if (value == 0x30)
|
||
|
{
|
||
|
if(gbSgbPacketNBits == 128)
|
||
|
{
|
||
|
gbSgbPacketNBits = 0;
|
||
|
gbSgbPacketByte = 0;
|
||
|
gbSgbPacketNumber++;
|
||
|
gbSgbPacketTimeout = 0;
|
||
|
if(gbSgbPacketNumber == (gbSgbPacket[0] & 7))
|
||
|
{
|
||
|
gbSgbCommand();
|
||
|
gbSgbPacketNumber = 0;
|
||
|
gbSgbPacketState = GBSGB_NONE;
|
||
|
gbSgbPacketTimeout = 0;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(gbSgbPacketNBits < 128)
|
||
|
{
|
||
|
gbSgbPacket[gbSgbPacketNumber * 16 + gbSgbPacketByte] >>= 1;
|
||
|
gbSgbPacket[gbSgbPacketNumber * 16 + gbSgbPacketByte] |= gbSgbBit;
|
||
|
gbSgbPacketNBits++;
|
||
|
if(!(gbSgbPacketNBits & 7))
|
||
|
{
|
||
|
gbSgbPacketByte++;
|
||
|
}
|
||
|
gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(value == 0x20)
|
||
|
gbSgbBit = 0x00;
|
||
|
else
|
||
|
gbSgbBit = 0x80;
|
||
|
gbSgbPacketTimeout = GBSGB_PACKET_TIMEOUT;
|
||
|
}
|
||
|
gbSgbReadingController = 0;
|
||
|
break;
|
||
|
default:
|
||
|
gbSgbPacketState = GBSGB_NONE;
|
||
|
gbSgbPacketTimeout = 0;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
variable_desc gbSgbSaveStruct[] = {
|
||
|
{ &gbSgbMask, sizeof(int) },
|
||
|
{ &gbSgbPacketState, sizeof(int) },
|
||
|
{ &gbSgbBit, sizeof(int) },
|
||
|
{ &gbSgbPacketNBits, sizeof(int) },
|
||
|
{ &gbSgbPacketByte, sizeof(int) },
|
||
|
{ &gbSgbPacketNumber, sizeof(int) },
|
||
|
{ &gbSgbMultiplayer, sizeof(int) },
|
||
|
{ &gbSgbNextController, sizeof(u8) },
|
||
|
{ &gbSgbReadingController, sizeof(u8) },
|
||
|
{ NULL, 0 }
|
||
|
};
|
||
|
|
||
|
variable_desc gbSgbSaveStructV3[] = {
|
||
|
{ &gbSgbMask, sizeof(int) },
|
||
|
{ &gbSgbPacketState, sizeof(int) },
|
||
|
{ &gbSgbBit, sizeof(int) },
|
||
|
{ &gbSgbPacketNBits, sizeof(int) },
|
||
|
{ &gbSgbPacketByte, sizeof(int) },
|
||
|
{ &gbSgbPacketNumber, sizeof(int) },
|
||
|
{ &gbSgbMultiplayer, sizeof(int) },
|
||
|
{ &gbSgbNextController, sizeof(u8) },
|
||
|
{ &gbSgbReadingController, sizeof(u8) },
|
||
|
{ &gbSgbFourPlayers, sizeof(int) },
|
||
|
{ NULL, 0 }
|
||
|
};
|
||
|
|
||
|
void gbSgbSaveGame(gzFile gzFile)
|
||
|
{
|
||
|
utilWriteData(gzFile, gbSgbSaveStructV3);
|
||
|
|
||
|
utilGzWrite(gzFile, gbSgbBorder, 2048);
|
||
|
utilGzWrite(gzFile, gbSgbBorderChar, 32*256);
|
||
|
|
||
|
utilGzWrite(gzFile, gbSgbPacket, 16*7);
|
||
|
|
||
|
utilGzWrite(gzFile, gbSgbSCPPalette, 4 * 512 * sizeof(u16));
|
||
|
utilGzWrite(gzFile, gbSgbATF, 20 * 18);
|
||
|
utilGzWrite(gzFile, gbSgbATFList, 45 * 20 * 18);
|
||
|
}
|
||
|
|
||
|
void gbSgbReadGame(gzFile gzFile, int version)
|
||
|
{
|
||
|
if(version >= 3)
|
||
|
utilReadData(gzFile, gbSgbSaveStructV3);
|
||
|
else
|
||
|
{
|
||
|
utilReadData(gzFile, gbSgbSaveStruct);
|
||
|
gbSgbFourPlayers = 0;
|
||
|
}
|
||
|
|
||
|
if(version >= 8)
|
||
|
{
|
||
|
utilGzRead(gzFile, gbSgbBorder, 2048);
|
||
|
utilGzRead(gzFile, gbSgbBorderChar, 32*256);
|
||
|
}
|
||
|
|
||
|
utilGzRead(gzFile, gbSgbPacket, 16*7);
|
||
|
|
||
|
utilGzRead(gzFile, gbSgbSCPPalette, 4 * 512 * sizeof(u16));
|
||
|
utilGzRead(gzFile, gbSgbATF, 20 * 18);
|
||
|
utilGzRead(gzFile, gbSgbATFList, 45 * 20 * 18);
|
||
|
}
|