rlm@1: // GBMapView.cpp : implementation file rlm@1: // rlm@1: rlm@1: #include "stdafx.h" rlm@1: #include "resource.h" rlm@1: #include "GBMapView.h" rlm@1: #include "FileDlg.h" rlm@1: #include "Reg.h" rlm@1: #include "WinResUtil.h" rlm@1: #include "VBA.h" rlm@1: rlm@1: //#include "../common/System.h" rlm@1: #include "../gb/gbGlobals.h" rlm@1: #include "../NLS.h" rlm@1: #include "../common/Util.h" rlm@1: rlm@1: extern "C" { rlm@1: #include rlm@1: } rlm@1: rlm@1: extern u8 gbInvertTab[256]; rlm@1: rlm@1: ///////////////////////////////////////////////////////////////////////////// rlm@1: // GBMapView dialog rlm@1: rlm@1: GBMapView::GBMapView(CWnd*pParent /*=NULL*/) rlm@1: : ResizeDlg(GBMapView::IDD, pParent) rlm@1: { rlm@1: //{{AFX_DATA_INIT(GBMapView) rlm@1: // NOTE: the ClassWizard will add member initialization here rlm@1: //}}AFX_DATA_INIT rlm@1: autoUpdate = false; rlm@1: rlm@1: memset(&bmpInfo.bmiHeader, 0, sizeof(bmpInfo.bmiHeader)); rlm@1: rlm@1: bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader); rlm@1: bmpInfo.bmiHeader.biWidth = 1024; rlm@1: bmpInfo.bmiHeader.biHeight = -1024; rlm@1: bmpInfo.bmiHeader.biPlanes = 1; rlm@1: bmpInfo.bmiHeader.biBitCount = 24; rlm@1: bmpInfo.bmiHeader.biCompression = BI_RGB; rlm@1: data = (u8 *)calloc(1, 3 * 1024 * 1024); rlm@1: rlm@1: mapView.setData(data); rlm@1: mapView.setBmpInfo(&bmpInfo); rlm@1: rlm@1: bg = 0; rlm@1: bank = 0; rlm@1: } rlm@1: rlm@1: void GBMapView::DoDataExchange(CDataExchange*pDX) rlm@1: { rlm@1: CDialog::DoDataExchange(pDX); rlm@1: //{{AFX_DATA_MAP(GBMapView) rlm@1: // NOTE: the ClassWizard will add DDX and DDV calls here rlm@1: //}}AFX_DATA_MAP rlm@1: DDX_Control(pDX, IDC_MAP_VIEW, mapView); rlm@1: DDX_Control(pDX, IDC_MAP_VIEW_ZOOM, mapViewZoom); rlm@1: DDX_Control(pDX, IDC_COLOR, color); rlm@1: } rlm@1: rlm@1: BEGIN_MESSAGE_MAP(GBMapView, CDialog) rlm@1: //{{AFX_MSG_MAP(GBMapView) rlm@1: ON_BN_CLICKED(IDC_SAVE, OnSave) rlm@1: ON_BN_CLICKED(IDC_REFRESH, OnRefresh) rlm@1: ON_BN_CLICKED(IDC_BG0, OnBg0) rlm@1: ON_BN_CLICKED(IDC_BG1, OnBg1) rlm@1: ON_BN_CLICKED(IDC_BANK_0, OnBank0) rlm@1: ON_BN_CLICKED(IDC_BANK_1, OnBank1) rlm@1: ON_BN_CLICKED(IDC_STRETCH, OnStretch) rlm@1: ON_BN_CLICKED(IDC_AUTO_UPDATE, OnAutoUpdate) rlm@1: ON_BN_CLICKED(IDC_CLOSE, OnClose) rlm@1: //}}AFX_MSG_MAP rlm@1: ON_MESSAGE(WM_MAPINFO, OnMapInfo) rlm@1: ON_MESSAGE(WM_COLINFO, OnColInfo) rlm@1: END_MESSAGE_MAP() rlm@1: rlm@1: ///////////////////////////////////////////////////////////////////////////// rlm@1: // GBMapView message handlers rlm@1: rlm@1: GBMapView::~GBMapView() rlm@1: { rlm@1: free(data); rlm@1: data = NULL; rlm@1: } rlm@1: rlm@1: void GBMapView::saveBMP(const char *name) rlm@1: { rlm@1: u8 writeBuffer[1024 * 3]; rlm@1: rlm@1: FILE *fp = fopen(name, "wb"); rlm@1: rlm@1: if (!fp) rlm@1: { rlm@1: systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name); rlm@1: return; rlm@1: } rlm@1: rlm@1: struct rlm@1: { rlm@1: u8 ident[2]; rlm@1: u8 filesize[4]; rlm@1: u8 reserved[4]; rlm@1: u8 dataoffset[4]; rlm@1: u8 headersize[4]; rlm@1: u8 width[4]; rlm@1: u8 height[4]; rlm@1: u8 planes[2]; rlm@1: u8 bitsperpixel[2]; rlm@1: u8 compression[4]; rlm@1: u8 datasize[4]; rlm@1: u8 hres[4]; rlm@1: u8 vres[4]; rlm@1: u8 colors[4]; rlm@1: u8 importantcolors[4]; rlm@1: u8 pad[2]; rlm@1: } bmpheader; rlm@1: memset(&bmpheader, 0, sizeof(bmpheader)); rlm@1: rlm@1: bmpheader.ident[0] = 'B'; rlm@1: bmpheader.ident[1] = 'M'; rlm@1: rlm@1: u32 fsz = sizeof(bmpheader) + w*h*3; rlm@1: utilPutDword(bmpheader.filesize, fsz); rlm@1: utilPutDword(bmpheader.dataoffset, 0x38); rlm@1: utilPutDword(bmpheader.headersize, 0x28); rlm@1: utilPutDword(bmpheader.width, w); rlm@1: utilPutDword(bmpheader.height, h); rlm@1: utilPutDword(bmpheader.planes, 1); rlm@1: utilPutDword(bmpheader.bitsperpixel, 24); rlm@1: utilPutDword(bmpheader.datasize, 3*w*h); rlm@1: rlm@1: fwrite(&bmpheader, 1, sizeof(bmpheader), fp); rlm@1: rlm@1: u8 *b = writeBuffer; rlm@1: rlm@1: int sizeX = w; rlm@1: int sizeY = h; rlm@1: rlm@1: u8 *pixU8 = (u8 *)data+3*w*(h-1); rlm@1: for (int y = 0; y < sizeY; y++) rlm@1: { rlm@1: for (int x = 0; x < sizeX; x++) rlm@1: { rlm@1: *b++ = *pixU8++; // B rlm@1: *b++ = *pixU8++; // G rlm@1: *b++ = *pixU8++; // R rlm@1: } rlm@1: pixU8 -= 2*3*w; rlm@1: fwrite(writeBuffer, 1, 3*w, fp); rlm@1: rlm@1: b = writeBuffer; rlm@1: } rlm@1: rlm@1: fclose(fp); rlm@1: } rlm@1: rlm@1: void GBMapView::savePNG(const char *name) rlm@1: { rlm@1: u8 writeBuffer[1024 * 3]; rlm@1: rlm@1: FILE *fp = fopen(name, "wb"); rlm@1: rlm@1: if (!fp) rlm@1: { rlm@1: systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name); rlm@1: return; rlm@1: } rlm@1: rlm@1: png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, rlm@1: NULL, rlm@1: NULL, rlm@1: NULL); rlm@1: if (!png_ptr) rlm@1: { rlm@1: fclose(fp); rlm@1: return; rlm@1: } rlm@1: rlm@1: png_infop info_ptr = png_create_info_struct(png_ptr); rlm@1: rlm@1: if (!info_ptr) rlm@1: { rlm@1: png_destroy_write_struct(&png_ptr, NULL); rlm@1: fclose(fp); rlm@1: return; rlm@1: } rlm@1: rlm@1: if (setjmp(png_ptr->jmpbuf)) rlm@1: { rlm@1: png_destroy_write_struct(&png_ptr, NULL); rlm@1: fclose(fp); rlm@1: return; rlm@1: } rlm@1: rlm@1: png_init_io(png_ptr, fp); rlm@1: rlm@1: png_set_IHDR(png_ptr, rlm@1: info_ptr, rlm@1: w, rlm@1: h, rlm@1: 8, rlm@1: PNG_COLOR_TYPE_RGB, rlm@1: PNG_INTERLACE_NONE, rlm@1: PNG_COMPRESSION_TYPE_DEFAULT, rlm@1: PNG_FILTER_TYPE_DEFAULT); rlm@1: rlm@1: png_write_info(png_ptr, info_ptr); rlm@1: rlm@1: u8 *b = writeBuffer; rlm@1: rlm@1: int sizeX = w; rlm@1: int sizeY = h; rlm@1: rlm@1: u8 *pixU8 = (u8 *)data; rlm@1: for (int y = 0; y < sizeY; y++) rlm@1: { rlm@1: for (int x = 0; x < sizeX; x++) rlm@1: { rlm@1: int blue = *pixU8++; rlm@1: int green = *pixU8++; rlm@1: int red = *pixU8++; rlm@1: rlm@1: *b++ = red; rlm@1: *b++ = green; rlm@1: *b++ = blue; rlm@1: } rlm@1: png_write_row(png_ptr, writeBuffer); rlm@1: rlm@1: b = writeBuffer; rlm@1: } rlm@1: rlm@1: png_write_end(png_ptr, info_ptr); rlm@1: rlm@1: png_destroy_write_struct(&png_ptr, &info_ptr); rlm@1: rlm@1: fclose(fp); rlm@1: } rlm@1: rlm@1: void GBMapView::OnSave() rlm@1: { rlm@1: CString filename; rlm@1: rlm@1: if (theApp.captureFormat == 0) rlm@1: filename = "map.png"; rlm@1: else rlm@1: filename = "map.bmp"; rlm@1: rlm@1: LPCTSTR exts[] = {".png", ".bmp", NULL }; rlm@1: CString filter = winResLoadFilter(IDS_FILTER_PNG); rlm@1: CString title = winResLoadString(IDS_SELECT_CAPTURE_NAME); rlm@1: rlm@1: FileDlg dlg(this, rlm@1: filename, rlm@1: filter, rlm@1: theApp.captureFormat ? 2 : 1, rlm@1: theApp.captureFormat ? "BMP" : "PNG", rlm@1: exts, rlm@1: "", rlm@1: title, rlm@1: true); rlm@1: rlm@1: if (dlg.DoModal() == IDCANCEL) rlm@1: { rlm@1: return; rlm@1: } rlm@1: rlm@1: if (dlg.getFilterIndex() == 2) rlm@1: saveBMP(dlg.GetPathName()); rlm@1: else rlm@1: savePNG(dlg.GetPathName()); rlm@1: } rlm@1: rlm@1: void GBMapView::render() rlm@1: { rlm@1: u8 *bank0; rlm@1: u8 *bank1; rlm@1: if (gbCgbMode) rlm@1: { rlm@1: bank0 = &gbVram[0x0000]; rlm@1: bank1 = &gbVram[0x2000]; rlm@1: } rlm@1: else rlm@1: { rlm@1: bank0 = &gbMemory[0x8000]; rlm@1: bank1 = NULL; rlm@1: } rlm@1: rlm@1: int tile_map_address = 0x1800; rlm@1: if (bg == 1) rlm@1: tile_map_address = 0x1c00; rlm@1: rlm@1: int tile_pattern = 0x0000; rlm@1: if (bank == 1) rlm@1: tile_pattern = 0x0800; rlm@1: rlm@1: w = 256; rlm@1: h = 256; rlm@1: rlm@1: int tile = 0; rlm@1: for (int y = 0; y < 32; y++) rlm@1: { rlm@1: for (int x = 0; x < 32; x++) rlm@1: { rlm@1: u8 *bmp = &data[y * 8 * 32 * 24 + x*24]; rlm@1: u8 attrs = 0; rlm@1: if (bank1 != NULL) rlm@1: attrs = bank1[tile_map_address]; rlm@1: u8 tile = bank0[tile_map_address]; rlm@1: tile_map_address++; rlm@1: rlm@1: if (bank == 1) rlm@1: { rlm@1: if (tile < 128) rlm@1: tile += 128; rlm@1: else rlm@1: tile -= 128; rlm@1: } rlm@1: for (int j = 0; j < 8; j++) rlm@1: { rlm@1: int tile_pattern_address = attrs & 0x40 ? rlm@1: tile_pattern + tile*16 + (7-j)*2 : rlm@1: tile_pattern + tile*16+j*2; rlm@1: rlm@1: u8 tile_a = 0; rlm@1: u8 tile_b = 0; rlm@1: rlm@1: if (attrs & 0x08) rlm@1: { rlm@1: tile_a = bank1[tile_pattern_address++]; rlm@1: tile_b = bank1[tile_pattern_address]; rlm@1: } rlm@1: else rlm@1: { rlm@1: tile_a = bank0[tile_pattern_address++]; rlm@1: tile_b = bank0[tile_pattern_address]; rlm@1: } rlm@1: rlm@1: if (attrs & 0x20) rlm@1: { rlm@1: tile_a = gbInvertTab[tile_a]; rlm@1: tile_b = gbInvertTab[tile_b]; rlm@1: } rlm@1: rlm@1: u8 mask = 0x80; rlm@1: rlm@1: while (mask > 0) rlm@1: { rlm@1: u8 c = (tile_a & mask) ? 1 : 0; rlm@1: c += (tile_b & mask) ? 2 : 0; rlm@1: rlm@1: if (gbCgbMode) rlm@1: c = c + (attrs & 7)*4; rlm@1: rlm@1: u16 color = gbPalette[c]; rlm@1: rlm@1: *bmp++ = ((color >> 10) & 0x1f) << 3; rlm@1: *bmp++ = ((color >> 5) & 0x1f) << 3; rlm@1: *bmp++ = (color & 0x1f) << 3; rlm@1: rlm@1: mask >>= 1; rlm@1: } rlm@1: bmp += 31*24; rlm@1: } rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void GBMapView::paint() rlm@1: { rlm@1: if (gbRom == NULL) rlm@1: return; rlm@1: render(); rlm@1: rlm@1: SIZE s; rlm@1: if (mapView.getStretch()) rlm@1: { rlm@1: mapView.setSize(w, h); rlm@1: s.cx = s.cy = 1; rlm@1: mapView.SetScrollSizes(MM_TEXT, s); rlm@1: } rlm@1: else rlm@1: { rlm@1: mapView.setSize(w, h); rlm@1: s.cx = w; rlm@1: s.cy = h; rlm@1: mapView.SetScrollSizes(MM_TEXT, s); rlm@1: } rlm@1: rlm@1: mapView.refresh(); rlm@1: } rlm@1: rlm@1: void GBMapView::OnRefresh() rlm@1: { rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void GBMapView::update() rlm@1: { rlm@1: paint(); rlm@1: } rlm@1: rlm@1: BOOL GBMapView::OnInitDialog() rlm@1: { rlm@1: CDialog::OnInitDialog(); rlm@1: rlm@1: DIALOG_SIZER_START(sz) rlm@1: DIALOG_SIZER_ENTRY(IDC_MAP_VIEW, DS_SizeX | DS_SizeY) rlm@1: DIALOG_SIZER_ENTRY(IDC_REFRESH, DS_MoveY) rlm@1: DIALOG_SIZER_ENTRY(IDC_CLOSE, DS_MoveY) rlm@1: DIALOG_SIZER_ENTRY(IDC_SAVE, DS_MoveY) rlm@1: DIALOG_SIZER_ENTRY(IDC_COLOR, DS_MoveY) rlm@1: DIALOG_SIZER_ENTRY(IDC_R, DS_MoveY) rlm@1: DIALOG_SIZER_ENTRY(IDC_G, DS_MoveY) rlm@1: DIALOG_SIZER_ENTRY(IDC_B, DS_MoveY) rlm@1: DIALOG_SIZER_END() rlm@1: SetData(sz, rlm@1: TRUE, rlm@1: HKEY_CURRENT_USER, rlm@1: "Software\\Emulators\\VisualBoyAdvance\\Viewer\\GBMapView", rlm@1: NULL); rlm@1: rlm@1: int s = regQueryDwordValue("mapViewStretch", 0); rlm@1: if (s) rlm@1: mapView.setStretch(true); rlm@1: ((CButton *)GetDlgItem(IDC_STRETCH))->SetCheck(s); rlm@1: rlm@1: UINT id = IDC_BANK_0; rlm@1: if (bank == 1) rlm@1: id = IDC_BANK_1; rlm@1: CheckRadioButton(IDC_BANK_0, IDC_BANK_1, id); rlm@1: id = IDC_BG0; rlm@1: if (bg == 1) rlm@1: id = IDC_BG1; rlm@1: CheckRadioButton(IDC_BG0, IDC_BG1, id); rlm@1: paint(); rlm@1: rlm@1: return TRUE; // return TRUE unless you set the focus to a control rlm@1: // EXCEPTION: OCX Property Pages should return FALSE rlm@1: } rlm@1: rlm@1: void GBMapView::OnBg0() rlm@1: { rlm@1: bg = 0; rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void GBMapView::OnBg1() rlm@1: { rlm@1: bg = 1; rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void GBMapView::OnBank0() rlm@1: { rlm@1: bank = 0; rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void GBMapView::OnBank1() rlm@1: { rlm@1: bank = 1; rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void GBMapView::OnStretch() rlm@1: { rlm@1: mapView.setStretch(!mapView.getStretch()); rlm@1: paint(); rlm@1: regSetDwordValue("mapViewStretch", mapView.getStretch()); rlm@1: } rlm@1: rlm@1: void GBMapView::OnAutoUpdate() rlm@1: { rlm@1: autoUpdate = !autoUpdate; rlm@1: if (autoUpdate) rlm@1: { rlm@1: theApp.winAddUpdateListener(this); rlm@1: } rlm@1: else rlm@1: { rlm@1: theApp.winRemoveUpdateListener(this); rlm@1: } rlm@1: } rlm@1: rlm@1: void GBMapView::OnClose() rlm@1: { rlm@1: theApp.winRemoveUpdateListener(this); rlm@1: rlm@1: DestroyWindow(); rlm@1: } rlm@1: rlm@1: u32 GBMapView::GetClickAddress(int x, int y) rlm@1: { rlm@1: u32 base = 0x9800; rlm@1: if (bg == 1) rlm@1: base = 0x9c00; rlm@1: rlm@1: return base + (y >> 3)*32 + (x >> 3); rlm@1: } rlm@1: rlm@1: LRESULT GBMapView::OnMapInfo(WPARAM wParam, LPARAM lParam) rlm@1: { rlm@1: u8 *colors = (u8 *)lParam; rlm@1: mapViewZoom.setColors(colors); rlm@1: rlm@1: int x = wParam & 0xffff; rlm@1: int y = (wParam >> 16); rlm@1: rlm@1: CString buffer; rlm@1: buffer.Format("(%d,%d)", x, y); rlm@1: GetDlgItem(IDC_XY)->SetWindowText(buffer); rlm@1: rlm@1: u32 address = GetClickAddress(x, y); rlm@1: buffer.Format("0x%08X", address); rlm@1: GetDlgItem(IDC_ADDRESS)->SetWindowText(buffer); rlm@1: rlm@1: u8 attrs = 0; rlm@1: rlm@1: u8 tile = gbReadMemoryQuick(0x9000 | (address & 0xfff)); rlm@1: if (gbCgbMode) rlm@1: { rlm@1: attrs = gbVram[0x2000 + address - 0x8000]; rlm@1: tile = gbVram[address & 0x1fff]; rlm@1: } rlm@1: rlm@1: if (bank == 1) rlm@1: { rlm@1: if (tile > 128) rlm@1: tile -= 128; rlm@1: else rlm@1: tile += 128; rlm@1: } rlm@1: rlm@1: buffer.Format("%d", tile); rlm@1: GetDlgItem(IDC_TILE_NUM)->SetWindowText(buffer); rlm@1: rlm@1: buffer.Empty(); rlm@1: buffer += attrs & 0x20 ? 'H' : '-'; rlm@1: buffer += attrs & 0x40 ? 'V' : '-'; rlm@1: GetDlgItem(IDC_FLIP)->SetWindowText(buffer); rlm@1: rlm@1: if (gbCgbMode) rlm@1: { rlm@1: buffer.Format("%d", (attrs & 7)); rlm@1: } rlm@1: else rlm@1: buffer = "---"; rlm@1: GetDlgItem(IDC_PALETTE_NUM)->SetWindowText(buffer); rlm@1: rlm@1: buffer.Empty(); rlm@1: if (gbCgbMode) rlm@1: buffer += attrs & 0x80 ? 'P' : '-'; rlm@1: else rlm@1: buffer += '-'; rlm@1: GetDlgItem(IDC_PRIORITY)->SetWindowText(buffer); rlm@1: rlm@1: return TRUE; rlm@1: } rlm@1: rlm@1: LRESULT GBMapView::OnColInfo(WPARAM wParam, LPARAM) rlm@1: { rlm@1: u16 c = (u16)wParam; rlm@1: rlm@1: color.setColor(c); rlm@1: rlm@1: int r = (c & 0x1f); rlm@1: int g = (c & 0x3e0) >> 5; rlm@1: int b = (c & 0x7c00) >> 10; rlm@1: rlm@1: CString buffer; rlm@1: buffer.Format("R: %d", r); rlm@1: GetDlgItem(IDC_R)->SetWindowText(buffer); rlm@1: rlm@1: buffer.Format("G: %d", g); rlm@1: GetDlgItem(IDC_G)->SetWindowText(buffer); rlm@1: rlm@1: buffer.Format("B: %d", b); rlm@1: GetDlgItem(IDC_B)->SetWindowText(buffer); rlm@1: rlm@1: return TRUE; rlm@1: } rlm@1: rlm@1: void GBMapView::PostNcDestroy() rlm@1: { rlm@1: delete this; rlm@1: CDialog::PostNcDestroy(); rlm@1: } rlm@1: