rlm@1: // TileView.cpp : implementation file rlm@1: // rlm@1: rlm@1: #include "stdafx.h" rlm@1: #include "resource.h" rlm@1: #include "FileDlg.h" rlm@1: #include "Reg.h" rlm@1: #include "TileView.h" rlm@1: #include "WinResUtil.h" rlm@1: #include "VBA.h" // for theApp rlm@1: rlm@1: #include "../gba/GBAGlobals.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: ///////////////////////////////////////////////////////////////////////////// rlm@1: // TileView dialog rlm@1: rlm@1: TileView::TileView(CWnd*pParent /*=NULL*/) rlm@1: : ResizeDlg(TileView::IDD, pParent) rlm@1: { rlm@1: //{{AFX_DATA_INIT(TileView) rlm@1: m_colors = -1; rlm@1: m_charBase = -1; rlm@1: m_stretch = FALSE; rlm@1: //}}AFX_DATA_INIT rlm@1: autoUpdate = false; rlm@1: rlm@1: memset(&bmpInfo, 0, sizeof(bmpInfo)); rlm@1: rlm@1: bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader); rlm@1: bmpInfo.bmiHeader.biWidth = 32*8; rlm@1: bmpInfo.bmiHeader.biHeight = 32*8; 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 * 32*32 * 64); rlm@1: rlm@1: tileView.setData(data); rlm@1: tileView.setBmpInfo(&bmpInfo); rlm@1: rlm@1: charBase = 0; rlm@1: is256Colors = 0; rlm@1: palette = 0; rlm@1: w = h = 0; rlm@1: } rlm@1: rlm@1: TileView::~TileView() rlm@1: { rlm@1: free(data); rlm@1: data = NULL; rlm@1: } rlm@1: rlm@1: void TileView::DoDataExchange(CDataExchange*pDX) rlm@1: { rlm@1: CDialog::DoDataExchange(pDX); rlm@1: //{{AFX_DATA_MAP(TileView) rlm@1: DDX_Control(pDX, IDC_PALETTE_SLIDER, m_slider); rlm@1: DDX_Radio(pDX, IDC_16_COLORS, m_colors); rlm@1: DDX_Radio(pDX, IDC_CHARBASE_0, m_charBase); rlm@1: DDX_Check(pDX, IDC_STRETCH, m_stretch); rlm@1: //}}AFX_DATA_MAP rlm@1: DDX_Control(pDX, IDC_TILE_VIEW, tileView); rlm@1: DDX_Control(pDX, IDC_MAP_VIEW_ZOOM, zoom); rlm@1: DDX_Control(pDX, IDC_COLOR, color); rlm@1: } rlm@1: rlm@1: BEGIN_MESSAGE_MAP(TileView, CDialog) rlm@1: //{{AFX_MSG_MAP(TileView) rlm@1: ON_BN_CLICKED(IDC_SAVE, OnSave) rlm@1: ON_BN_CLICKED(IDC_CLOSE, OnClose) rlm@1: ON_BN_CLICKED(IDC_AUTO_UPDATE, OnAutoUpdate) rlm@1: ON_BN_CLICKED(IDC_16_COLORS, On16Colors) rlm@1: ON_BN_CLICKED(IDC_256_COLORS, On256Colors) rlm@1: ON_BN_CLICKED(IDC_CHARBASE_0, OnCharbase0) rlm@1: ON_BN_CLICKED(IDC_CHARBASE_1, OnCharbase1) rlm@1: ON_BN_CLICKED(IDC_CHARBASE_2, OnCharbase2) rlm@1: ON_BN_CLICKED(IDC_CHARBASE_3, OnCharbase3) rlm@1: ON_BN_CLICKED(IDC_CHARBASE_4, OnCharbase4) rlm@1: ON_BN_CLICKED(IDC_STRETCH, OnStretch) rlm@1: ON_WM_HSCROLL() 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: // TileView message handlers rlm@1: rlm@1: void TileView::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 TileView::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 TileView::OnSave() rlm@1: { rlm@1: CString captureBuffer; rlm@1: rlm@1: if (theApp.captureFormat == 0) rlm@1: captureBuffer = "tiles.png"; rlm@1: else rlm@1: captureBuffer = "tiles.bmp"; rlm@1: rlm@1: LPCTSTR exts[] = {".png", ".bmp", NULL }; rlm@1: 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: captureBuffer, 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: captureBuffer = dlg.GetPathName(); rlm@1: rlm@1: if (dlg.getFilterIndex() == 2) rlm@1: saveBMP(captureBuffer); rlm@1: else rlm@1: savePNG(captureBuffer); rlm@1: } rlm@1: rlm@1: void TileView::renderTile256(int tile, int x, int y, u8 *charBase, u16 *palette) rlm@1: { rlm@1: u8 *bmp = &data[24*x + 8*32*24*y]; rlm@1: rlm@1: for (int j = 0; j < 8; j++) rlm@1: { rlm@1: for (int i = 0; i < 8; i++) rlm@1: { rlm@1: u8 c = charBase[tile*64 + j * 8 + i]; rlm@1: rlm@1: u16 color = palette[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: bmp += 31*24; // advance line rlm@1: } rlm@1: } rlm@1: rlm@1: void TileView::renderTile16(int tile, int x, int y, u8 *charBase, u16 *palette) rlm@1: { rlm@1: u8 *bmp = &data[24*x + 8*32*24*y]; rlm@1: rlm@1: int pal = this->palette; rlm@1: rlm@1: if (this->charBase == 4) rlm@1: pal += 16; rlm@1: rlm@1: for (int j = 0; j < 8; j++) rlm@1: { rlm@1: for (int i = 0; i < 8; i++) rlm@1: { rlm@1: u8 c = charBase[tile*32 + j * 4 + (i>>1)]; rlm@1: rlm@1: if (i & 1) rlm@1: c = c>>4; rlm@1: else rlm@1: c = c & 15; rlm@1: rlm@1: u16 color = palette[pal*16+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: bmp += 31*24; // advance line rlm@1: } rlm@1: } rlm@1: rlm@1: void TileView::render() rlm@1: { rlm@1: u16 *palette = (u16 *)paletteRAM; rlm@1: u8 * charBase = &vram[this->charBase * 0x4000]; rlm@1: rlm@1: int maxY; rlm@1: rlm@1: if (is256Colors) rlm@1: { rlm@1: int tile = 0; rlm@1: maxY = 16; rlm@1: for (int y = 0; y < maxY; y++) rlm@1: { rlm@1: for (int x = 0; x < 32; x++) rlm@1: { rlm@1: if (this->charBase == 4) rlm@1: renderTile256(tile, x, y, charBase, &palette[256]); rlm@1: else rlm@1: renderTile256(tile, x, y, charBase, palette); rlm@1: tile++; rlm@1: } rlm@1: } rlm@1: tileView.setSize(32*8, maxY*8); rlm@1: w = 32*8; rlm@1: h = maxY*8; rlm@1: SIZE s; rlm@1: s.cx = 32*8; rlm@1: s.cy = maxY*8; rlm@1: if (tileView.getStretch()) rlm@1: { rlm@1: s.cx = s.cy = 1; rlm@1: } rlm@1: tileView.SetScrollSizes(MM_TEXT, s); rlm@1: } rlm@1: else rlm@1: { rlm@1: int tile = 0; rlm@1: maxY = 32; rlm@1: if (this->charBase == 3) rlm@1: maxY = 16; rlm@1: for (int y = 0; y < maxY; y++) rlm@1: { rlm@1: for (int x = 0; x < 32; x++) rlm@1: { rlm@1: renderTile16(tile, x, y, charBase, palette); rlm@1: tile++; rlm@1: } rlm@1: } rlm@1: tileView.setSize(32*8, maxY*8); rlm@1: w = 32*8; rlm@1: h = maxY*8; rlm@1: SIZE s; rlm@1: s.cx = 32*8; rlm@1: s.cy = maxY*8; rlm@1: if (tileView.getStretch()) rlm@1: { rlm@1: s.cx = s.cy = 1; rlm@1: } rlm@1: tileView.SetScrollSizes(MM_TEXT, s); rlm@1: } rlm@1: } rlm@1: rlm@1: void TileView::update() rlm@1: { rlm@1: paint(); rlm@1: } rlm@1: rlm@1: BOOL TileView::OnInitDialog() rlm@1: { rlm@1: CDialog::OnInitDialog(); rlm@1: rlm@1: DIALOG_SIZER_START(sz) rlm@1: DIALOG_SIZER_ENTRY(IDC_TILE_VIEW, DS_SizeX | DS_SizeY) 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_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_END() rlm@1: SetData(sz, rlm@1: TRUE, rlm@1: HKEY_CURRENT_USER, rlm@1: "Software\\Emulators\\VisualBoyAdvance\\Viewer\\TileView", rlm@1: NULL); rlm@1: rlm@1: m_colors = is256Colors; rlm@1: m_charBase = charBase; rlm@1: rlm@1: m_slider.SetRange(0, 15); rlm@1: m_slider.SetPageSize(4); rlm@1: m_slider.SetTicFreq(1); rlm@1: rlm@1: paint(); rlm@1: rlm@1: m_stretch = regQueryDwordValue("tileViewStretch", 0); rlm@1: if (m_stretch) rlm@1: tileView.setStretch(true); rlm@1: UpdateData(FALSE); 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 TileView::OnClose() rlm@1: { rlm@1: theApp.winRemoveUpdateListener(this); rlm@1: rlm@1: DestroyWindow(); rlm@1: } rlm@1: rlm@1: void TileView::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 TileView::paint() rlm@1: { rlm@1: if (vram != NULL && paletteRAM != NULL) rlm@1: { rlm@1: render(); rlm@1: tileView.refresh(); rlm@1: } rlm@1: } rlm@1: rlm@1: void TileView::On16Colors() rlm@1: { rlm@1: is256Colors = 0; rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void TileView::On256Colors() rlm@1: { rlm@1: is256Colors = 1; rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void TileView::OnCharbase0() rlm@1: { rlm@1: charBase = 0; rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void TileView::OnCharbase1() rlm@1: { rlm@1: charBase = 1; rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void TileView::OnCharbase2() rlm@1: { rlm@1: charBase = 2; rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void TileView::OnCharbase3() rlm@1: { rlm@1: charBase = 3; rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void TileView::OnCharbase4() rlm@1: { rlm@1: charBase = 4; rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void TileView::OnStretch() rlm@1: { rlm@1: tileView.setStretch(!tileView.getStretch()); rlm@1: paint(); rlm@1: regSetDwordValue("tileViewStretch", tileView.getStretch()); rlm@1: } rlm@1: rlm@1: LRESULT TileView::OnMapInfo(WPARAM wParam, LPARAM lParam) rlm@1: { rlm@1: u8 *colors = (u8 *)lParam; rlm@1: zoom.setColors(colors); rlm@1: rlm@1: int x = (wParam & 0xFFFF)/8; rlm@1: int y = ((wParam >> 16) & 0xFFFF)/8; rlm@1: rlm@1: u32 address = 0x6000000 + 0x4000 * charBase; rlm@1: int tile = 32 * y + x; rlm@1: if (is256Colors) rlm@1: tile *= 2; rlm@1: address += 32 * tile; rlm@1: rlm@1: CString buffer; rlm@1: buffer.Format("%d", tile); rlm@1: GetDlgItem(IDC_TILE_NUMBER)->SetWindowText(buffer); rlm@1: rlm@1: buffer.Format("%08x", address); rlm@1: GetDlgItem(IDC_ADDRESS)->SetWindowText(buffer); rlm@1: rlm@1: return TRUE; rlm@1: } rlm@1: rlm@1: LRESULT TileView::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 TileView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar*pScrollBar) rlm@1: { rlm@1: switch (nSBCode) rlm@1: { rlm@1: case TB_THUMBPOSITION: rlm@1: palette = nPos; rlm@1: break; rlm@1: default: rlm@1: palette = m_slider.GetPos(); rlm@1: break; rlm@1: } rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void TileView::PostNcDestroy() rlm@1: { rlm@1: delete this; rlm@1: } rlm@1: