1037 lines
21 KiB
C++
1037 lines
21 KiB
C++
// VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
|
|
// Copyright (C) 1999-2003 Forgotten
|
|
// Copyright (C) 2005 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.
|
|
|
|
// MapView.cpp : implementation file
|
|
//
|
|
|
|
#include "stdafx.h"
|
|
#include "vba.h"
|
|
#include "FileDlg.h"
|
|
#include "MapView.h"
|
|
#include "Reg.h"
|
|
#include "WinResUtil.h"
|
|
|
|
#include "../System.h"
|
|
#include "../GBA.h"
|
|
#include "../Globals.h"
|
|
#include "../NLS.h"
|
|
#include "../Util.h"
|
|
|
|
extern "C" {
|
|
#include <png.h>
|
|
}
|
|
|
|
#ifdef _DEBUG
|
|
#define new DEBUG_NEW
|
|
#undef THIS_FILE
|
|
static char THIS_FILE[] = __FILE__;
|
|
#endif
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// MapView dialog
|
|
|
|
|
|
MapView::MapView(CWnd* pParent /*=NULL*/)
|
|
: ResizeDlg(MapView::IDD, pParent)
|
|
{
|
|
//{{AFX_DATA_INIT(MapView)
|
|
//}}AFX_DATA_INIT
|
|
autoUpdate = false;
|
|
|
|
memset(&bmpInfo.bmiHeader, 0, sizeof(bmpInfo.bmiHeader));
|
|
|
|
bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);
|
|
bmpInfo.bmiHeader.biWidth = 1024;
|
|
bmpInfo.bmiHeader.biHeight = -1024;
|
|
bmpInfo.bmiHeader.biPlanes = 1;
|
|
bmpInfo.bmiHeader.biBitCount = 24;
|
|
bmpInfo.bmiHeader.biCompression = BI_RGB;
|
|
data = (u8 *)calloc(1, 3 * 1024 * 1024);
|
|
|
|
mapView.setData(data);
|
|
mapView.setBmpInfo(&bmpInfo);
|
|
|
|
control = BG0CNT;
|
|
|
|
bg = 0;
|
|
frame = 0;
|
|
}
|
|
|
|
MapView::~MapView()
|
|
{
|
|
free(data);
|
|
data = NULL;
|
|
}
|
|
|
|
void MapView::DoDataExchange(CDataExchange* pDX)
|
|
{
|
|
CDialog::DoDataExchange(pDX);
|
|
//{{AFX_DATA_MAP(MapView)
|
|
DDX_Control(pDX, IDC_NUMCOLORS, m_numcolors);
|
|
DDX_Control(pDX, IDC_MODE, m_mode);
|
|
DDX_Control(pDX, IDC_OVERFLOW, m_overflow);
|
|
DDX_Control(pDX, IDC_MOSAIC, m_mosaic);
|
|
DDX_Control(pDX, IDC_PRIORITY, m_priority);
|
|
DDX_Control(pDX, IDC_DIM, m_dim);
|
|
DDX_Control(pDX, IDC_CHARBASE, m_charbase);
|
|
DDX_Control(pDX, IDC_MAPBASE, m_mapbase);
|
|
//}}AFX_DATA_MAP
|
|
DDX_Control(pDX, IDC_MAP_VIEW, mapView);
|
|
DDX_Control(pDX, IDC_MAP_VIEW_ZOOM, mapViewZoom);
|
|
DDX_Control(pDX, IDC_COLOR, color);
|
|
}
|
|
|
|
|
|
BEGIN_MESSAGE_MAP(MapView, CDialog)
|
|
//{{AFX_MSG_MAP(MapView)
|
|
ON_BN_CLICKED(IDC_REFRESH, OnRefresh)
|
|
ON_BN_CLICKED(IDC_FRAME_0, OnFrame0)
|
|
ON_BN_CLICKED(IDC_FRAME_1, OnFrame1)
|
|
ON_BN_CLICKED(IDC_BG0, OnBg0)
|
|
ON_BN_CLICKED(IDC_BG1, OnBg1)
|
|
ON_BN_CLICKED(IDC_BG2, OnBg2)
|
|
ON_BN_CLICKED(IDC_BG3, OnBg3)
|
|
ON_BN_CLICKED(IDC_STRETCH, OnStretch)
|
|
ON_BN_CLICKED(IDC_AUTO_UPDATE, OnAutoUpdate)
|
|
ON_BN_CLICKED(IDC_CLOSE, OnClose)
|
|
ON_BN_CLICKED(IDC_SAVE, OnSave)
|
|
//}}AFX_MSG_MAP
|
|
ON_MESSAGE(WM_MAPINFO, OnMapInfo)
|
|
ON_MESSAGE(WM_COLINFO, OnColInfo)
|
|
END_MESSAGE_MAP()
|
|
|
|
/////////////////////////////////////////////////////////////////////////////
|
|
// MapView message handlers
|
|
|
|
void MapView::renderTextScreen(u16 control)
|
|
{
|
|
u16 *palette = (u16 *)paletteRAM;
|
|
u8 *charBase = &vram[((control >> 2) & 0x03) * 0x4000];
|
|
u16 *screenBase = (u16 *)&vram[((control >> 8) & 0x1f) * 0x800];
|
|
u8 *bmp = data;
|
|
|
|
int sizeX = 256;
|
|
int sizeY = 256;
|
|
switch((control >> 14) & 3) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
sizeX = 512;
|
|
break;
|
|
case 2:
|
|
sizeY = 512;
|
|
break;
|
|
case 3:
|
|
sizeX = 512;
|
|
sizeY = 512;
|
|
break;
|
|
}
|
|
|
|
w = sizeX;
|
|
h = sizeY;
|
|
|
|
if(control & 0x80) {
|
|
for(int y = 0; y < sizeY; y++) {
|
|
int yy = y & 255;
|
|
|
|
if(y == 256 && sizeY > 256) {
|
|
screenBase += 0x400;
|
|
if(sizeX > 256)
|
|
screenBase += 0x400;
|
|
}
|
|
u16 *screenSource = screenBase + ((yy>>3)*32);
|
|
|
|
for(int x = 0; x < sizeX; x++) {
|
|
u16 data = *screenSource;
|
|
|
|
int tile = data & 0x3FF;
|
|
int tileX = (x & 7);
|
|
int tileY = y & 7;
|
|
|
|
if(data & 0x0400)
|
|
tileX = 7 - tileX;
|
|
if(data & 0x0800)
|
|
tileY = 7 - tileY;
|
|
|
|
u8 c = charBase[tile * 64 + tileY * 8 + tileX];
|
|
|
|
u16 color = palette[c];
|
|
|
|
*bmp++ = ((color >> 10) & 0x1f) << 3;
|
|
*bmp++ = ((color >> 5) & 0x1f) << 3;
|
|
*bmp++ = (color & 0x1f) << 3;
|
|
|
|
if(data & 0x0400) {
|
|
if(tileX == 0)
|
|
screenSource++;
|
|
} else if(tileX == 7)
|
|
screenSource++;
|
|
if(x == 255 && sizeX > 256) {
|
|
screenSource = screenBase + 0x400 + ((yy>>3)*32);
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
for(int y = 0; y < sizeY; y++) {
|
|
int yy = y & 255;
|
|
|
|
if(y == 256 && sizeY > 256) {
|
|
screenBase += 0x400;
|
|
if(sizeX > 256)
|
|
screenBase += 0x400;
|
|
}
|
|
u16 *screenSource = screenBase + ((yy>>3)*32);
|
|
|
|
for(int x = 0; x < sizeX; x++) {
|
|
u16 data = *screenSource;
|
|
|
|
int tile = data & 0x3FF;
|
|
int tileX = (x & 7);
|
|
int tileY = y & 7;
|
|
|
|
if(data & 0x0400)
|
|
tileX = 7 - tileX;
|
|
if(data & 0x0800)
|
|
tileY = 7 - tileY;
|
|
|
|
u8 color = charBase[tile * 32 + tileY * 4 + (tileX>>1)];
|
|
|
|
if(tileX & 1) {
|
|
color = (color >> 4);
|
|
} else {
|
|
color &= 0x0F;
|
|
}
|
|
|
|
int pal = (*screenSource>>8) & 0xF0;
|
|
u16 color2 = palette[pal + color];
|
|
|
|
*bmp++ = ((color2 >> 10) & 0x1f) << 3;
|
|
*bmp++ = ((color2 >> 5) & 0x1f) << 3;
|
|
*bmp++ = (color2 & 0x1f) << 3;
|
|
|
|
if(data & 0x0400) {
|
|
if(tileX == 0)
|
|
screenSource++;
|
|
} else if(tileX == 7)
|
|
screenSource++;
|
|
|
|
if(x == 255 && sizeX > 256) {
|
|
screenSource = screenBase + 0x400 + ((yy>>3)*32);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
/*
|
|
switch(bg) {
|
|
case 0:
|
|
renderView(BG0HOFS<<8, BG0VOFS<<8,
|
|
0x100, 0x000,
|
|
0x000, 0x100,
|
|
(sizeX -1) <<8,
|
|
(sizeY -1) << 8,
|
|
true);
|
|
break;
|
|
case 1:
|
|
renderView(BG1HOFS<<8, BG1VOFS<<8,
|
|
0x100, 0x000,
|
|
0x000, 0x100,
|
|
(sizeX -1) <<8,
|
|
(sizeY -1) << 8,
|
|
true);
|
|
break;
|
|
case 2:
|
|
renderView(BG2HOFS<<8, BG2VOFS<<8,
|
|
0x100, 0x000,
|
|
0x000, 0x100,
|
|
(sizeX -1) <<8,
|
|
(sizeY -1) << 8,
|
|
true);
|
|
break;
|
|
case 3:
|
|
renderView(BG3HOFS<<8, BG3VOFS<<8,
|
|
0x100, 0x000,
|
|
0x000, 0x100,
|
|
(sizeX -1) <<8,
|
|
(sizeY -1) << 8,
|
|
true);
|
|
break;
|
|
}
|
|
*/
|
|
}
|
|
|
|
void MapView::renderRotScreen(u16 control)
|
|
{
|
|
u16 *palette = (u16 *)paletteRAM;
|
|
u8 *charBase = &vram[((control >> 2) & 0x03) * 0x4000];
|
|
u8 *screenBase = (u8 *)&vram[((control >> 8) & 0x1f) * 0x800];
|
|
u8 *bmp = data;
|
|
|
|
int sizeX = 128;
|
|
int sizeY = 128;
|
|
switch((control >> 14) & 3) {
|
|
case 0:
|
|
break;
|
|
case 1:
|
|
sizeX = sizeY = 256;
|
|
break;
|
|
case 2:
|
|
sizeX = sizeY = 512;
|
|
break;
|
|
case 3:
|
|
sizeX = sizeY = 1024;
|
|
break;
|
|
}
|
|
|
|
w = sizeX;
|
|
h = sizeY;
|
|
|
|
if(control & 0x80) {
|
|
for(int y = 0; y < sizeY; y++) {
|
|
for(int x = 0; x < sizeX; x++) {
|
|
int tile = screenBase[(x>>3) + (y>>3)*(w>>3)];
|
|
|
|
int tileX = (x & 7);
|
|
int tileY = y & 7;
|
|
|
|
u8 color = charBase[tile * 64 + tileY * 8 + tileX];
|
|
u16 color2 = palette[color];
|
|
|
|
*bmp++ = ((color2 >> 10) & 0x1f) << 3;
|
|
*bmp++ = ((color2 >> 5) & 0x1f) << 3;
|
|
*bmp++ = (color2 & 0x1f) << 3;
|
|
}
|
|
}
|
|
} else {
|
|
for(int y = 0; y < sizeY; y++) {
|
|
for(int x = 0; x < sizeX; x++) {
|
|
int tile = screenBase[(x>>3) + (y>>3)*(w>>3)];
|
|
|
|
int tileX = (x & 7);
|
|
int tileY = y & 7;
|
|
|
|
u8 color = charBase[tile * 64 + tileY * 8 + tileX];
|
|
u16 color2 = palette[color];
|
|
|
|
*bmp++ = ((color2 >> 10) & 0x1f) << 3;
|
|
*bmp++ = ((color2 >> 5) & 0x1f) << 3;
|
|
*bmp++ = (color2 & 0x1f) << 3;
|
|
}
|
|
}
|
|
}
|
|
|
|
u32 xx;
|
|
u32 yy;
|
|
|
|
switch(bg) {
|
|
case 2:
|
|
xx = BG2X_L | BG2X_H << 16;
|
|
yy = BG2Y_L | BG2Y_H << 16;
|
|
|
|
/*
|
|
renderView(xx, yy,
|
|
BG2PA, BG2PC,
|
|
BG2PB, BG2PD,
|
|
(sizeX -1) <<8,
|
|
(sizeY -1) << 8,
|
|
(control & 0x2000) != 0);
|
|
*/
|
|
break;
|
|
case 3:
|
|
xx = BG3X_L | BG3X_H << 16;
|
|
yy = BG3Y_L | BG3Y_H << 16;
|
|
/*
|
|
renderView(xx, yy,
|
|
BG3PA, BG3PC,
|
|
BG3PB, BG3PD,
|
|
(sizeX -1) <<8,
|
|
(sizeY -1) << 8,
|
|
(control & 0x2000) != 0);
|
|
*/
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MapView::renderMode0()
|
|
{
|
|
renderTextScreen(control);
|
|
}
|
|
|
|
void MapView::renderMode1()
|
|
{
|
|
switch(bg) {
|
|
case 0:
|
|
case 1:
|
|
renderTextScreen(control);
|
|
break;
|
|
case 2:
|
|
renderRotScreen(control);
|
|
break;
|
|
default:
|
|
bg = 0;
|
|
control = BG0CNT;
|
|
renderTextScreen(control);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MapView::renderMode2()
|
|
{
|
|
switch(bg) {
|
|
case 2:
|
|
case 3:
|
|
renderRotScreen(control);
|
|
break;
|
|
default:
|
|
bg = 2;
|
|
control = BG2CNT;
|
|
renderRotScreen(control);
|
|
break;
|
|
}
|
|
}
|
|
|
|
void MapView::renderMode3()
|
|
{
|
|
u8 *bmp = data;
|
|
u16 *src = (u16 *)&vram[0];
|
|
|
|
w = 240;
|
|
h = 160;
|
|
|
|
for(int y = 0; y < 160; y++) {
|
|
for(int x = 0; x < 240; x++) {
|
|
u16 data = *src++;
|
|
*bmp++ = ((data >> 10) & 0x1f) << 3;
|
|
*bmp++ = ((data >> 5) & 0x1f) << 3;
|
|
*bmp++ = (data & 0x1f) << 3;
|
|
}
|
|
}
|
|
bg = 2;
|
|
}
|
|
|
|
|
|
void MapView::renderMode4()
|
|
{
|
|
u8 *bmp = data;
|
|
u8 *src = frame ? &vram[0xa000] : &vram[0];
|
|
u16 *pal = (u16 *)&paletteRAM[0];
|
|
|
|
w = 240;
|
|
h = 160;
|
|
|
|
for(int y = 0; y < 160; y++) {
|
|
for(int x = 0; x < 240; x++) {
|
|
u8 c = *src++;
|
|
u16 data = pal[c];
|
|
*bmp++ = ((data >> 10) & 0x1f) << 3;
|
|
*bmp++ = ((data >> 5) & 0x1f) << 3;
|
|
*bmp++ = (data & 0x1f) << 3;
|
|
}
|
|
}
|
|
bg = 2;
|
|
}
|
|
|
|
|
|
void MapView::renderMode5()
|
|
{
|
|
u8 *bmp = data;
|
|
u16 *src = (u16 *)(frame ? &vram[0xa000] : &vram[0]);
|
|
|
|
w = 160;
|
|
h = 128;
|
|
|
|
for(int y = 0; y < 128; y++) {
|
|
for(int x = 0; x < 160; x++) {
|
|
u16 data = *src++;
|
|
*bmp++ = ((data >> 10) & 0x1f) << 3;
|
|
*bmp++ = ((data >> 5) & 0x1f) << 3;
|
|
*bmp++ = (data & 0x1f) << 3;
|
|
}
|
|
}
|
|
bg = 2;
|
|
}
|
|
|
|
|
|
void MapView::OnRefresh()
|
|
{
|
|
paint();
|
|
}
|
|
|
|
void MapView::paint()
|
|
{
|
|
if(vram == NULL)
|
|
return;
|
|
int mode = DISPCNT & 7;
|
|
|
|
switch(bg) {
|
|
default:
|
|
case 0:
|
|
control = BG0CNT;
|
|
break;
|
|
case 1:
|
|
control = BG1CNT;
|
|
break;
|
|
case 2:
|
|
control = BG2CNT;
|
|
break;
|
|
case 3:
|
|
control = BG3CNT;
|
|
break;
|
|
}
|
|
|
|
switch(mode) {
|
|
case 0:
|
|
renderMode0();
|
|
break;
|
|
case 1:
|
|
renderMode1();
|
|
break;
|
|
case 2:
|
|
renderMode2();
|
|
break;
|
|
case 3:
|
|
renderMode3();
|
|
break;
|
|
case 4:
|
|
renderMode4();
|
|
break;
|
|
case 5:
|
|
renderMode5();
|
|
break;
|
|
case 6:
|
|
renderMode5();
|
|
break;
|
|
case 7:
|
|
renderMode5();
|
|
break;
|
|
}
|
|
enableButtons(mode);
|
|
SIZE s;
|
|
|
|
if(mapView.getStretch()) {
|
|
mapView.setSize(w, h);
|
|
s.cx = s.cy = 1;
|
|
mapView.SetScrollSizes(MM_TEXT, s);
|
|
} else {
|
|
mapView.setSize(w, h);
|
|
s.cx = w;
|
|
s.cy = h;
|
|
mapView.SetScrollSizes(MM_TEXT, s);
|
|
}
|
|
|
|
mapView.refresh();
|
|
|
|
CString buffer;
|
|
|
|
u32 charBase = ((control >> 2) & 0x03) * 0x4000 + 0x6000000;
|
|
u32 screenBase = ((control >> 8) & 0x1f) * 0x800 + 0x6000000;
|
|
|
|
buffer.Format("%d", mode);
|
|
m_mode.SetWindowText(buffer);
|
|
|
|
if(mode >= 3) {
|
|
m_mapbase.SetWindowText("");
|
|
m_charbase.SetWindowText("");
|
|
} else {
|
|
buffer.Format("0x%08X", screenBase);
|
|
m_mapbase.SetWindowText(buffer);
|
|
|
|
buffer.Format("0x%08X", charBase);
|
|
m_charbase.SetWindowText(buffer);
|
|
}
|
|
|
|
buffer.Format("%dx%d", w, h);
|
|
m_dim.SetWindowText(buffer);
|
|
|
|
m_numcolors.SetWindowText(control & 0x80 ? "256" : "16");
|
|
|
|
buffer.Format("%d", control & 3);
|
|
m_priority.SetWindowText(buffer);
|
|
|
|
m_mosaic.SetWindowText(control & 0x40 ? "1" : "0");
|
|
|
|
m_overflow.SetWindowText(bg <= 1 ? "" :
|
|
control & 0x2000 ? "1" : "0");
|
|
}
|
|
|
|
BOOL MapView::OnInitDialog()
|
|
{
|
|
CDialog::OnInitDialog();
|
|
|
|
DIALOG_SIZER_START( sz )
|
|
DIALOG_SIZER_ENTRY( IDC_MAP_VIEW, DS_SizeX | DS_SizeY )
|
|
DIALOG_SIZER_ENTRY( IDC_REFRESH, DS_MoveY)
|
|
DIALOG_SIZER_ENTRY( IDC_CLOSE, DS_MoveY)
|
|
DIALOG_SIZER_ENTRY( IDC_SAVE, DS_MoveY)
|
|
DIALOG_SIZER_ENTRY( IDC_COLOR, DS_MoveY)
|
|
DIALOG_SIZER_ENTRY( IDC_R, DS_MoveY)
|
|
DIALOG_SIZER_ENTRY( IDC_G, DS_MoveY)
|
|
DIALOG_SIZER_ENTRY( IDC_B, DS_MoveY)
|
|
DIALOG_SIZER_END()
|
|
SetData(sz,
|
|
TRUE,
|
|
HKEY_CURRENT_USER,
|
|
"Software\\Emulators\\VisualBoyAdvance\\Viewer\\MapView",
|
|
NULL);
|
|
SIZE size;
|
|
size.cx = 1;
|
|
size.cy = 1;
|
|
mapView.SetScrollSizes(MM_TEXT,size);
|
|
int s = regQueryDwordValue("mapViewStretch", 0);
|
|
if(s)
|
|
mapView.setStretch(true);
|
|
((CButton *)GetDlgItem(IDC_STRETCH))->SetCheck(s);
|
|
paint();
|
|
|
|
return TRUE; // return TRUE unless you set the focus to a control
|
|
// EXCEPTION: OCX Property Pages should return FALSE
|
|
}
|
|
|
|
void MapView::PostNcDestroy()
|
|
{
|
|
delete this;
|
|
}
|
|
|
|
void MapView::enableButtons(int mode)
|
|
{
|
|
bool enable[6] = { true, true, true, true, true, true };
|
|
|
|
switch(mode) {
|
|
case 0:
|
|
enable[4] = false;
|
|
enable[5] = false;
|
|
break;
|
|
case 1:
|
|
enable[3] = false;
|
|
enable[4] = false;
|
|
enable[5] = false;
|
|
break;
|
|
case 2:
|
|
enable[0] = false;
|
|
enable[1] = false;
|
|
enable[4] = false;
|
|
enable[5] = false;
|
|
break;
|
|
case 3:
|
|
enable[0] = false;
|
|
enable[1] = false;
|
|
enable[2] = false;
|
|
enable[3] = false;
|
|
enable[4] = false;
|
|
enable[5] = false;
|
|
break;
|
|
case 4:
|
|
enable[0] = false;
|
|
enable[1] = false;
|
|
enable[2] = false;
|
|
enable[3] = false;
|
|
break;
|
|
case 5:
|
|
enable[0] = false;
|
|
enable[1] = false;
|
|
enable[2] = false;
|
|
enable[3] = false;
|
|
break;
|
|
}
|
|
GetDlgItem(IDC_BG0)->EnableWindow(enable[0]);
|
|
GetDlgItem(IDC_BG1)->EnableWindow(enable[1]);
|
|
GetDlgItem(IDC_BG2)->EnableWindow(enable[2]);
|
|
GetDlgItem(IDC_BG3)->EnableWindow(enable[3]);
|
|
GetDlgItem(IDC_FRAME_0)->EnableWindow(enable[4]);
|
|
GetDlgItem(IDC_FRAME_1)->EnableWindow(enable[5]);
|
|
int id = IDC_BG0;
|
|
switch(bg) {
|
|
case 1:
|
|
id = IDC_BG1;
|
|
break;
|
|
case 2:
|
|
id = IDC_BG2;
|
|
break;
|
|
case 3:
|
|
id = IDC_BG3;
|
|
break;
|
|
}
|
|
CheckRadioButton(IDC_BG0, IDC_BG3, id);
|
|
id = IDC_FRAME_0;
|
|
if(frame != 0)
|
|
id = IDC_FRAME_1;
|
|
CheckRadioButton(IDC_FRAME_0, IDC_FRAME_1, id);
|
|
}
|
|
|
|
void MapView::OnFrame0()
|
|
{
|
|
frame = 0;
|
|
paint();
|
|
}
|
|
|
|
void MapView::OnFrame1()
|
|
{
|
|
frame = 1;
|
|
paint();
|
|
}
|
|
|
|
void MapView::OnBg0()
|
|
{
|
|
bg = 0;
|
|
control = BG0CNT;
|
|
paint();
|
|
}
|
|
|
|
void MapView::OnBg1()
|
|
{
|
|
bg = 1;
|
|
control = BG1CNT;
|
|
paint();
|
|
}
|
|
|
|
void MapView::OnBg2()
|
|
{
|
|
bg = 2;
|
|
control = BG2CNT;
|
|
paint();
|
|
}
|
|
|
|
void MapView::OnBg3()
|
|
{
|
|
bg = 3;
|
|
control = BG3CNT;
|
|
paint();
|
|
}
|
|
|
|
void MapView::OnStretch()
|
|
{
|
|
mapView.setStretch(!mapView.getStretch());
|
|
paint();
|
|
regSetDwordValue("mapViewStretch", mapView.getStretch());
|
|
}
|
|
|
|
void MapView::OnAutoUpdate()
|
|
{
|
|
autoUpdate = !autoUpdate;
|
|
if(autoUpdate) {
|
|
theApp.winAddUpdateListener(this);
|
|
} else {
|
|
theApp.winRemoveUpdateListener(this);
|
|
}
|
|
}
|
|
|
|
void MapView::update()
|
|
{
|
|
paint();
|
|
}
|
|
|
|
void MapView::OnClose()
|
|
{
|
|
theApp.winRemoveUpdateListener(this);
|
|
|
|
DestroyWindow();
|
|
}
|
|
|
|
u32 MapView::GetTextClickAddress(u32 base, int x, int y)
|
|
{
|
|
if(y > 255 && h > 256) {
|
|
base += 0x800;
|
|
if(w > 256)
|
|
base += 0x800;
|
|
}
|
|
if(x >= 256)
|
|
base += 0x800;
|
|
x &= 255;
|
|
y &= 255;
|
|
base += (x>>3)*2 + 64*(y>>3);
|
|
|
|
return base;
|
|
}
|
|
|
|
|
|
|
|
u32 MapView::GetClickAddress(int x, int y)
|
|
{
|
|
int mode = DISPCNT & 7;
|
|
|
|
u32 base = ((control >> 8) & 0x1f) * 0x800 + 0x6000000;
|
|
|
|
// all text bgs (16 bits)
|
|
if(mode == 0 ||(mode < 3 && bg < 2) || mode == 6 || mode == 7) {
|
|
return GetTextClickAddress(base, x, y);
|
|
}
|
|
// rot bgs (8 bits)
|
|
if(mode < 3) {
|
|
return base + (x>>3) + (w>>3)*(y>>3);
|
|
}
|
|
// mode 3/5 (16 bits)
|
|
if(mode != 4) {
|
|
return 0x6000000 + 0xa000*frame + 2*x + w*y*2;
|
|
}
|
|
// mode 4 (8 bits)
|
|
return 0x6000000 + 0xa000*frame + x + w*y;
|
|
}
|
|
|
|
LRESULT MapView::OnMapInfo(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
u8 *colors = (u8 *)lParam;
|
|
mapViewZoom.setColors(colors);
|
|
|
|
int x = (int)(wParam & 0xffff);
|
|
int y = (int)(wParam >> 16);
|
|
|
|
CString buffer;
|
|
buffer.Format("(%d,%d)", x, y);
|
|
GetDlgItem(IDC_XY)->SetWindowText(buffer);
|
|
|
|
u32 address = GetClickAddress(x,y);
|
|
buffer.Format("0x%08X", address);
|
|
GetDlgItem(IDC_ADDRESS)->SetWindowText(buffer);
|
|
|
|
int mode = DISPCNT & 7;
|
|
if(mode >= 3 && mode <=5) {
|
|
// bitmap modes
|
|
GetDlgItem(IDC_TILE_NUM)->SetWindowText("---");
|
|
GetDlgItem(IDC_FLIP)->SetWindowText("--");
|
|
GetDlgItem(IDC_PALETTE_NUM)->SetWindowText("---");
|
|
} else if(mode == 0 || bg < 2) {
|
|
// text bgs
|
|
u16 value = *((u16 *)&vram[address - 0x6000000]);
|
|
|
|
int tile = value & 1023;
|
|
buffer.Format("%d", tile);
|
|
GetDlgItem(IDC_TILE_NUM)->SetWindowText(buffer);
|
|
buffer.Empty();
|
|
buffer += value & 1024 ? 'H' : '-';
|
|
buffer += value & 2048 ? 'V' : '-';
|
|
GetDlgItem(IDC_FLIP)->SetWindowText(buffer);
|
|
|
|
if(!(control & 0x80)) {
|
|
buffer.Format("%d", (value >> 12) & 15);
|
|
} else
|
|
buffer = "---";
|
|
GetDlgItem(IDC_PALETTE_NUM)->SetWindowText(buffer);
|
|
} else {
|
|
// rot bgs
|
|
GetDlgItem(IDC_TILE_NUM)->SetWindowText("---");
|
|
GetDlgItem(IDC_FLIP)->SetWindowText("--");
|
|
GetDlgItem(IDC_PALETTE_NUM)->SetWindowText("---");
|
|
}
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
LRESULT MapView::OnColInfo(WPARAM wParam, LPARAM lParam)
|
|
{
|
|
u16 c = (u16)wParam;
|
|
|
|
color.setColor(c);
|
|
|
|
int r = (c & 0x1f);
|
|
int g = (c & 0x3e0) >> 5;
|
|
int b = (c & 0x7c00) >> 10;
|
|
|
|
CString buffer;
|
|
buffer.Format("R: %d", r);
|
|
GetDlgItem(IDC_R)->SetWindowText(buffer);
|
|
|
|
buffer.Format("G: %d", g);
|
|
GetDlgItem(IDC_G)->SetWindowText(buffer);
|
|
|
|
buffer.Format("B: %d", b);
|
|
GetDlgItem(IDC_B)->SetWindowText(buffer);
|
|
|
|
return TRUE;
|
|
}
|
|
|
|
void MapView::saveBMP(const char *name)
|
|
{
|
|
u8 writeBuffer[1024 * 3];
|
|
|
|
FILE *fp = fopen(name,"wb");
|
|
|
|
if(!fp) {
|
|
systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name);
|
|
return;
|
|
}
|
|
|
|
struct {
|
|
u8 ident[2];
|
|
u8 filesize[4];
|
|
u8 reserved[4];
|
|
u8 dataoffset[4];
|
|
u8 headersize[4];
|
|
u8 width[4];
|
|
u8 height[4];
|
|
u8 planes[2];
|
|
u8 bitsperpixel[2];
|
|
u8 compression[4];
|
|
u8 datasize[4];
|
|
u8 hres[4];
|
|
u8 vres[4];
|
|
u8 colors[4];
|
|
u8 importantcolors[4];
|
|
u8 pad[2];
|
|
} bmpheader;
|
|
memset(&bmpheader, 0, sizeof(bmpheader));
|
|
|
|
bmpheader.ident[0] = 'B';
|
|
bmpheader.ident[1] = 'M';
|
|
|
|
u32 fsz = sizeof(bmpheader) + w*h*3;
|
|
utilPutDword(bmpheader.filesize, fsz);
|
|
utilPutDword(bmpheader.dataoffset, 0x38);
|
|
utilPutDword(bmpheader.headersize, 0x28);
|
|
utilPutDword(bmpheader.width, w);
|
|
utilPutDword(bmpheader.height, h);
|
|
utilPutDword(bmpheader.planes, 1);
|
|
utilPutDword(bmpheader.bitsperpixel, 24);
|
|
utilPutDword(bmpheader.datasize, 3*w*h);
|
|
|
|
fwrite(&bmpheader, 1, sizeof(bmpheader), fp);
|
|
|
|
u8 *b = writeBuffer;
|
|
|
|
int sizeX = w;
|
|
int sizeY = h;
|
|
|
|
u8 *pixU8 = (u8 *)data+3*w*(h-1);
|
|
for(int y = 0; y < sizeY; y++) {
|
|
for(int x = 0; x < sizeX; x++) {
|
|
*b++ = *pixU8++; // B
|
|
*b++ = *pixU8++; // G
|
|
*b++ = *pixU8++; // R
|
|
}
|
|
pixU8 -= 2*3*w;
|
|
fwrite(writeBuffer, 1, 3*w, fp);
|
|
|
|
b = writeBuffer;
|
|
}
|
|
|
|
fclose(fp);
|
|
}
|
|
|
|
|
|
|
|
void MapView::savePNG(const char *name)
|
|
{
|
|
u8 writeBuffer[1024 * 3];
|
|
|
|
FILE *fp = fopen(name,"wb");
|
|
|
|
if(!fp) {
|
|
systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name);
|
|
return;
|
|
}
|
|
|
|
png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
|
|
NULL,
|
|
NULL,
|
|
NULL);
|
|
if(!png_ptr) {
|
|
fclose(fp);
|
|
return;
|
|
}
|
|
|
|
png_infop info_ptr = png_create_info_struct(png_ptr);
|
|
|
|
if(!info_ptr) {
|
|
png_destroy_write_struct(&png_ptr,NULL);
|
|
fclose(fp);
|
|
return;
|
|
}
|
|
|
|
if(setjmp(png_ptr->jmpbuf)) {
|
|
png_destroy_write_struct(&png_ptr,NULL);
|
|
fclose(fp);
|
|
return;
|
|
}
|
|
|
|
png_init_io(png_ptr,fp);
|
|
|
|
png_set_IHDR(png_ptr,
|
|
info_ptr,
|
|
w,
|
|
h,
|
|
8,
|
|
PNG_COLOR_TYPE_RGB,
|
|
PNG_INTERLACE_NONE,
|
|
PNG_COMPRESSION_TYPE_DEFAULT,
|
|
PNG_FILTER_TYPE_DEFAULT);
|
|
|
|
png_write_info(png_ptr,info_ptr);
|
|
|
|
u8 *b = writeBuffer;
|
|
|
|
int sizeX = w;
|
|
int sizeY = h;
|
|
|
|
u8 *pixU8 = (u8 *)data;
|
|
for(int y = 0; y < sizeY; y++) {
|
|
for(int x = 0; x < sizeX; x++) {
|
|
int blue = *pixU8++;
|
|
int green = *pixU8++;
|
|
int red = *pixU8++;
|
|
|
|
*b++ = red;
|
|
*b++ = green;
|
|
*b++ = blue;
|
|
}
|
|
png_write_row(png_ptr,writeBuffer);
|
|
|
|
b = writeBuffer;
|
|
}
|
|
|
|
png_write_end(png_ptr, info_ptr);
|
|
|
|
png_destroy_write_struct(&png_ptr, &info_ptr);
|
|
|
|
fclose(fp);
|
|
}
|
|
|
|
void MapView::OnSave()
|
|
{
|
|
if(rom != NULL)
|
|
{
|
|
CString filename;
|
|
|
|
if(theApp.captureFormat == 0)
|
|
filename = "map.png";
|
|
else
|
|
filename = "map.bmp";
|
|
|
|
LPCTSTR exts[] = {".png", ".bmp" };
|
|
|
|
CString filter = theApp.winLoadFilter(IDS_FILTER_PNG);
|
|
CString title = winResLoadString(IDS_SELECT_CAPTURE_NAME);
|
|
|
|
FileDlg dlg(this,
|
|
filename,
|
|
filter,
|
|
theApp.captureFormat ? 2 : 1,
|
|
theApp.captureFormat ? "BMP" : "PNG",
|
|
exts,
|
|
"",
|
|
title,
|
|
true);
|
|
|
|
if(dlg.DoModal() == IDCANCEL) {
|
|
return;
|
|
}
|
|
|
|
if(dlg.getFilterIndex() == 2)
|
|
saveBMP(dlg.GetPathName());
|
|
else
|
|
savePNG(dlg.GetPathName());
|
|
}
|
|
}
|