rlm@1: // GBOamView.cpp : implementation file rlm@1: // rlm@1: rlm@1: #include "stdafx.h" rlm@1: #include "resource.h" rlm@1: #include "GBOamView.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: ///////////////////////////////////////////////////////////////////////////// rlm@1: // GBOamView dialog rlm@1: rlm@1: GBOamView::GBOamView(CWnd*pParent /*=NULL*/) rlm@1: : ResizeDlg(GBOamView::IDD, pParent) rlm@1: { rlm@1: //{{AFX_DATA_INIT(GBOamView) rlm@1: m_stretch = FALSE; 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 = 8; rlm@1: bmpInfo.bmiHeader.biHeight = 16; 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 * 8 * 16); rlm@1: rlm@1: oamView.setData(data); rlm@1: oamView.setBmpInfo(&bmpInfo); rlm@1: rlm@1: number = 0; rlm@1: } rlm@1: rlm@1: void GBOamView::DoDataExchange(CDataExchange*pDX) rlm@1: { rlm@1: CDialog::DoDataExchange(pDX); rlm@1: //{{AFX_DATA_MAP(GBOamView) rlm@1: DDX_Control(pDX, IDC_SPRITE, m_sprite); rlm@1: DDX_Check(pDX, IDC_STRETCH, m_stretch); rlm@1: //}}AFX_DATA_MAP rlm@1: DDX_Control(pDX, IDC_COLOR, color); rlm@1: DDX_Control(pDX, IDC_OAM_VIEW, oamView); rlm@1: DDX_Control(pDX, IDC_OAM_VIEW_ZOOM, oamZoom); rlm@1: } rlm@1: rlm@1: BEGIN_MESSAGE_MAP(GBOamView, CDialog) rlm@1: //{{AFX_MSG_MAP(GBOamView) rlm@1: ON_BN_CLICKED(IDC_STRETCH, OnStretch) rlm@1: ON_BN_CLICKED(IDC_AUTO_UPDATE, OnAutoUpdate) rlm@1: ON_EN_CHANGE(IDC_SPRITE, OnChangeSprite) rlm@1: ON_BN_CLICKED(IDC_CLOSE, OnClose) 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: // GBOamView message handlers rlm@1: rlm@1: GBOamView::~GBOamView() rlm@1: { rlm@1: free(data); rlm@1: data = NULL; rlm@1: } rlm@1: rlm@1: void GBOamView::paint() rlm@1: { rlm@1: if (gbRom == NULL) rlm@1: return; rlm@1: rlm@1: render(); rlm@1: oamView.setSize(w, h); rlm@1: oamView.refresh(); rlm@1: } rlm@1: rlm@1: void GBOamView::update() rlm@1: { rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void GBOamView::setAttributes(int y, int x, int tile, int flags) rlm@1: { rlm@1: CString buffer; rlm@1: rlm@1: int flipH = flags & 0x20; rlm@1: int flipV = flags & 0x40; rlm@1: int prio = (flags & 0x80) >> 7; rlm@1: int pal = flags & 0x7; rlm@1: int oap = (flags & 0x08) >> 3; rlm@1: int bank = (flags & 0x10) >> 4; rlm@1: rlm@1: buffer.Format("%d,%d", x, y); rlm@1: GetDlgItem(IDC_POS)->SetWindowText(buffer); rlm@1: rlm@1: buffer.Format("%d", pal); rlm@1: GetDlgItem(IDC_PALETTE)->SetWindowText(buffer); rlm@1: rlm@1: buffer.Format("%d", tile); rlm@1: GetDlgItem(IDC_TILE)->SetWindowText(buffer); rlm@1: rlm@1: buffer.Format("%d", prio); rlm@1: GetDlgItem(IDC_PRIO)->SetWindowText(buffer); rlm@1: rlm@1: buffer.Format("%d", bank); rlm@1: GetDlgItem(IDC_BANK)->SetWindowText(buffer); rlm@1: rlm@1: buffer.Empty(); rlm@1: if (flipH) rlm@1: buffer += 'H'; rlm@1: else rlm@1: buffer += ' '; rlm@1: if (flipV) rlm@1: buffer += 'V'; rlm@1: else rlm@1: buffer += ' '; rlm@1: GetDlgItem(IDC_FLAGS)->SetWindowText(buffer); rlm@1: rlm@1: buffer.Format("%d", oap); rlm@1: GetDlgItem(IDC_OAP)->SetWindowText(buffer); rlm@1: } rlm@1: rlm@1: void GBOamView::render() rlm@1: { rlm@1: int m = 0; rlm@1: if (gbRom == NULL) rlm@1: return; rlm@1: rlm@1: u16 addr = number * 4 + 0xfe00; rlm@1: rlm@1: int size = register_LCDC & 4; rlm@1: rlm@1: u8 y = gbReadMemoryQuick(addr++); rlm@1: u8 x = gbReadMemoryQuick(addr++); rlm@1: u8 tile = gbReadMemoryQuick(addr++); rlm@1: if (size) rlm@1: tile &= 254; rlm@1: u8 flags = gbReadMemoryQuick(addr++); rlm@1: rlm@1: u8 *bmp = data; rlm@1: rlm@1: w = 8; rlm@1: h = size ? 16 : 8; rlm@1: rlm@1: setAttributes(y, x, tile, flags); rlm@1: rlm@1: u8 *bank0; rlm@1: u8 *bank1; rlm@1: if (gbCgbMode) rlm@1: { rlm@1: if (register_VBK & 1) rlm@1: { rlm@1: bank0 = &gbVram[0x0000]; rlm@1: bank1 = &gbVram[0x2000]; rlm@1: } rlm@1: else rlm@1: { rlm@1: bank0 = &gbVram[0x0000]; rlm@1: bank1 = &gbVram[0x2000]; rlm@1: } rlm@1: } rlm@1: else rlm@1: { rlm@1: bank0 = &gbMemory[0x8000]; rlm@1: bank1 = NULL; rlm@1: } rlm@1: rlm@1: int init = 0x0000; rlm@1: rlm@1: u8 *pal = gbObp0; rlm@1: rlm@1: if ((flags & 0x10)) rlm@1: pal = gbObp1; rlm@1: rlm@1: for (int yy = 0; yy < h; yy++) rlm@1: { rlm@1: int address = init + tile * 16 + 2*yy; rlm@1: int a = 0; rlm@1: int b = 0; rlm@1: rlm@1: if (gbCgbMode && flags & 0x08) rlm@1: { rlm@1: a = bank1[address++]; rlm@1: b = bank1[address++]; rlm@1: } rlm@1: else rlm@1: { rlm@1: a = bank0[address++]; rlm@1: b = bank0[address++]; rlm@1: } rlm@1: rlm@1: for (int xx = 0; xx < 8; xx++) rlm@1: { rlm@1: u8 mask = 1 << (7-xx); rlm@1: u8 c = 0; rlm@1: if ((a & mask)) rlm@1: c++; rlm@1: if ((b & mask)) rlm@1: c += 2; rlm@1: rlm@1: // make sure that sprites will work even in CGB mode rlm@1: if (gbCgbMode) rlm@1: { rlm@1: c = c + (flags & 0x07)*4 + 32; rlm@1: } rlm@1: else rlm@1: { rlm@1: c = pal[c]; rlm@1: } rlm@1: rlm@1: u16 color = gbPalette[c]; rlm@1: *bmp++ = ((color >> 10) & 0x1f) << 3; rlm@1: *bmp++ = ((color >> 5) & 0x1f) << 3; rlm@1: *bmp++ = (color & 0x1f) << 3; rlm@1: } rlm@1: } rlm@1: } rlm@1: rlm@1: void GBOamView::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 GBOamView::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 GBOamView::save() rlm@1: { rlm@1: CString captureBuffer; rlm@1: rlm@1: if (theApp.captureFormat == 0) rlm@1: captureBuffer = "oam.png"; rlm@1: else rlm@1: captureBuffer = "oam.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: 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: BOOL GBOamView::OnInitDialog() rlm@1: { rlm@1: CDialog::OnInitDialog(); rlm@1: rlm@1: DIALOG_SIZER_START(sz) rlm@1: DIALOG_SIZER_ENTRY(IDC_OAM_VIEW, DS_SizeX | DS_SizeY) rlm@1: DIALOG_SIZER_ENTRY(IDC_OAM_VIEW_ZOOM, DS_MoveX) rlm@1: DIALOG_SIZER_ENTRY(IDC_REFRESH, DS_MoveY) rlm@1: DIALOG_SIZER_ENTRY(IDC_SAVE, DS_MoveY) rlm@1: DIALOG_SIZER_ENTRY(IDC_CLOSE, 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\\GBOamView", rlm@1: NULL); rlm@1: rlm@1: m_sprite.SetWindowText("0"); rlm@1: rlm@1: updateScrollInfo(); rlm@1: rlm@1: m_stretch = regQueryDwordValue("GBOamViewStretch", 0); rlm@1: if (m_stretch) rlm@1: oamView.setStretch(true); rlm@1: UpdateData(FALSE); rlm@1: 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 GBOamView::OnStretch() rlm@1: { rlm@1: oamView.setStretch(!oamView.getStretch()); rlm@1: paint(); rlm@1: regSetDwordValue("GBOamViewStretch", oamView.getStretch()); rlm@1: } rlm@1: rlm@1: void GBOamView::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 GBOamView::OnChangeSprite() rlm@1: { rlm@1: CString buffer; rlm@1: m_sprite.GetWindowText(buffer); rlm@1: int n = atoi(buffer); rlm@1: if (n < 0 || n > 39) rlm@1: { rlm@1: buffer.Format("%d", number); rlm@1: m_sprite.SetWindowText(buffer); rlm@1: return; rlm@1: } rlm@1: number = n; rlm@1: paint(); rlm@1: updateScrollInfo(); rlm@1: } rlm@1: rlm@1: void GBOamView::OnClose() rlm@1: { rlm@1: theApp.winRemoveUpdateListener(this); rlm@1: rlm@1: DestroyWindow(); rlm@1: } rlm@1: rlm@1: LRESULT GBOamView::OnMapInfo(WPARAM, LPARAM lParam) rlm@1: { rlm@1: u8 *colors = (u8 *)lParam; rlm@1: oamZoom.setColors(colors); rlm@1: rlm@1: return TRUE; rlm@1: } rlm@1: rlm@1: LRESULT GBOamView::OnColInfo(WPARAM wParam, LPARAM 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 GBOamView::updateScrollInfo() rlm@1: { rlm@1: SCROLLINFO si; rlm@1: ZeroMemory(&si, sizeof(si)); rlm@1: si.cbSize = sizeof(si); rlm@1: si.fMask = SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL | SIF_POS; rlm@1: si.nMin = 0; rlm@1: si.nMax = 39; rlm@1: si.nPage = 1; rlm@1: si.nPos = number; rlm@1: GetDlgItem(IDC_SCROLLBAR)->SetScrollInfo(SB_CTL, rlm@1: &si, rlm@1: TRUE); rlm@1: } rlm@1: rlm@1: void GBOamView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar*pScrollBar) rlm@1: { rlm@1: switch (nSBCode) rlm@1: { rlm@1: case SB_BOTTOM: rlm@1: number = 39; rlm@1: break; rlm@1: case SB_LINEDOWN: rlm@1: number++; rlm@1: if (number > 39) rlm@1: number = 39; rlm@1: break; rlm@1: case SB_LINEUP: rlm@1: number--; rlm@1: if (number < 0) rlm@1: number = 0; rlm@1: break; rlm@1: case SB_PAGEDOWN: rlm@1: number += 16; rlm@1: if (number > 39) rlm@1: number = 39; rlm@1: break; rlm@1: case SB_PAGEUP: rlm@1: number -= 16; rlm@1: if (number < 0) rlm@1: number = 0; rlm@1: break; rlm@1: case SB_TOP: rlm@1: number = 0; rlm@1: break; rlm@1: case SB_THUMBTRACK: rlm@1: number = nPos; rlm@1: if (number < 0) rlm@1: number = 0; rlm@1: if (number > 39) rlm@1: number = 39; rlm@1: break; rlm@1: } rlm@1: rlm@1: updateScrollInfo(); rlm@1: rlm@1: CString buffer; rlm@1: buffer.Format("%d", number); rlm@1: m_sprite.SetWindowText(buffer); rlm@1: paint(); rlm@1: } rlm@1: rlm@1: void GBOamView::PostNcDestroy() rlm@1: { rlm@1: delete this; rlm@1: } rlm@1: