home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Freeware / Utilitare / VisualBoyAdvance-1.7.2 / src / win32 / GBMapView.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-05-13  |  12.4 KB  |  578 lines

  1. // VisualBoyAdvance - Nintendo Gameboy/GameboyAdvance (TM) emulator.
  2. // Copyright (C) 1999-2003 Forgotten
  3. // Copyright (C) 2004 Forgotten and the VBA development team
  4.  
  5. // This program is free software; you can redistribute it and/or modify
  6. // it under the terms of the GNU General Public License as published by
  7. // the Free Software Foundation; either version 2, or(at your option)
  8. // any later version.
  9. //
  10. // This program is distributed in the hope that it will be useful,
  11. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13. // GNU General Public License for more details.
  14. //
  15. // You should have received a copy of the GNU General Public License
  16. // along with this program; if not, write to the Free Software Foundation,
  17. // Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
  18.  
  19. // GBMapView.cpp : implementation file
  20. //
  21.  
  22. #include "stdafx.h"
  23. #include "vba.h"
  24. #include "FileDlg.h"
  25. #include "GBMapView.h"
  26. #include "Reg.h"
  27. #include "WinResUtil.h"
  28.  
  29. #include "../System.h"
  30. #include "../NLS.h"
  31. #include "../Util.h"
  32. #include "../gb/gbGlobals.h"
  33.  
  34. extern "C" {
  35. #include <png.h>
  36. }
  37.  
  38. extern u8 gbInvertTab[256];
  39.  
  40. #ifdef _DEBUG
  41. #define new DEBUG_NEW
  42. #undef THIS_FILE
  43. static char THIS_FILE[] = __FILE__;
  44. #endif
  45.  
  46. /////////////////////////////////////////////////////////////////////////////
  47. // GBMapView dialog
  48.  
  49.  
  50. GBMapView::GBMapView(CWnd* pParent /*=NULL*/)
  51.   : ResizeDlg(GBMapView::IDD, pParent)
  52. {
  53.   //{{AFX_DATA_INIT(GBMapView)
  54.   // NOTE: the ClassWizard will add member initialization here
  55.   //}}AFX_DATA_INIT
  56.   autoUpdate = false;
  57.   
  58.   memset(&bmpInfo.bmiHeader, 0, sizeof(bmpInfo.bmiHeader));
  59.   
  60.   bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);
  61.   bmpInfo.bmiHeader.biWidth = 1024;
  62.   bmpInfo.bmiHeader.biHeight = -1024;
  63.   bmpInfo.bmiHeader.biPlanes = 1;
  64.   bmpInfo.bmiHeader.biBitCount = 24;
  65.   bmpInfo.bmiHeader.biCompression = BI_RGB;
  66.   data = (u8 *)calloc(1, 3 * 1024 * 1024);
  67.  
  68.   mapView.setData(data);
  69.   mapView.setBmpInfo(&bmpInfo);
  70.   
  71.   bg = 0;
  72.   bank = 0;
  73. }
  74.  
  75.  
  76. void GBMapView::DoDataExchange(CDataExchange* pDX)
  77. {
  78.   CDialog::DoDataExchange(pDX);
  79.   //{{AFX_DATA_MAP(GBMapView)
  80.   // NOTE: the ClassWizard will add DDX and DDV calls here
  81.   //}}AFX_DATA_MAP
  82.   DDX_Control(pDX, IDC_MAP_VIEW, mapView);
  83.   DDX_Control(pDX, IDC_MAP_VIEW_ZOOM, mapViewZoom);
  84.   DDX_Control(pDX, IDC_COLOR, color);
  85. }
  86.  
  87.  
  88. BEGIN_MESSAGE_MAP(GBMapView, CDialog)
  89.   //{{AFX_MSG_MAP(GBMapView)
  90.   ON_BN_CLICKED(IDC_SAVE, OnSave)
  91.   ON_BN_CLICKED(IDC_REFRESH, OnRefresh)
  92.   ON_BN_CLICKED(IDC_BG0, OnBg0)
  93.   ON_BN_CLICKED(IDC_BG1, OnBg1)
  94.   ON_BN_CLICKED(IDC_BANK_0, OnBank0)
  95.   ON_BN_CLICKED(IDC_BANK_1, OnBank1)
  96.   ON_BN_CLICKED(IDC_STRETCH, OnStretch)
  97.   ON_BN_CLICKED(IDC_AUTO_UPDATE, OnAutoUpdate)
  98.   ON_BN_CLICKED(IDC_CLOSE, OnClose)
  99.   //}}AFX_MSG_MAP
  100.   ON_MESSAGE(WM_MAPINFO, OnMapInfo)
  101.   ON_MESSAGE(WM_COLINFO, OnColInfo)
  102.   END_MESSAGE_MAP()
  103.  
  104.   /////////////////////////////////////////////////////////////////////////////
  105. // GBMapView message handlers
  106.  
  107. GBMapView::~GBMapView()
  108. {
  109.   free(data);
  110.   data = NULL;
  111. }
  112.  
  113. void GBMapView::saveBMP(const char *name)
  114. {
  115.   u8 writeBuffer[1024 * 3];
  116.   
  117.   FILE *fp = fopen(name,"wb");
  118.  
  119.   if(!fp) {
  120.     systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name);
  121.     return;
  122.   }
  123.  
  124.   struct {
  125.     u8 ident[2];
  126.     u8 filesize[4];
  127.     u8 reserved[4];
  128.     u8 dataoffset[4];
  129.     u8 headersize[4];
  130.     u8 width[4];
  131.     u8 height[4];
  132.     u8 planes[2];
  133.     u8 bitsperpixel[2];
  134.     u8 compression[4];
  135.     u8 datasize[4];
  136.     u8 hres[4];
  137.     u8 vres[4];
  138.     u8 colors[4];
  139.     u8 importantcolors[4];
  140.     u8 pad[2];
  141.   } bmpheader;
  142.   memset(&bmpheader, 0, sizeof(bmpheader));
  143.  
  144.   bmpheader.ident[0] = 'B';
  145.   bmpheader.ident[1] = 'M';
  146.  
  147.   u32 fsz = sizeof(bmpheader) + w*h*3;
  148.   utilPutDword(bmpheader.filesize, fsz);
  149.   utilPutDword(bmpheader.dataoffset, 0x38);
  150.   utilPutDword(bmpheader.headersize, 0x28);
  151.   utilPutDword(bmpheader.width, w);
  152.   utilPutDword(bmpheader.height, h);
  153.   utilPutDword(bmpheader.planes, 1);
  154.   utilPutDword(bmpheader.bitsperpixel, 24);
  155.   utilPutDword(bmpheader.datasize, 3*w*h);
  156.  
  157.   fwrite(&bmpheader, 1, sizeof(bmpheader), fp);
  158.  
  159.   u8 *b = writeBuffer;
  160.  
  161.   int sizeX = w;
  162.   int sizeY = h;
  163.  
  164.   u8 *pixU8 = (u8 *)data+3*w*(h-1);
  165.   for(int y = 0; y < sizeY; y++) {
  166.     for(int x = 0; x < sizeX; x++) {
  167.       *b++ = *pixU8++; // B
  168.       *b++ = *pixU8++; // G
  169.       *b++ = *pixU8++; // R
  170.     }
  171.     pixU8 -= 2*3*w;
  172.     fwrite(writeBuffer, 1, 3*w, fp);
  173.     
  174.     b = writeBuffer;
  175.   }
  176.  
  177.   fclose(fp);
  178. }
  179.  
  180. void GBMapView::savePNG(const char *name)
  181. {
  182.   u8 writeBuffer[1024 * 3];
  183.   
  184.   FILE *fp = fopen(name,"wb");
  185.  
  186.   if(!fp) {
  187.     systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name);
  188.     return;
  189.   }
  190.   
  191.   png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
  192.                                                 NULL,
  193.                                                 NULL,
  194.                                                 NULL);
  195.   if(!png_ptr) {
  196.     fclose(fp);
  197.     return;
  198.   }
  199.  
  200.   png_infop info_ptr = png_create_info_struct(png_ptr);
  201.  
  202.   if(!info_ptr) {
  203.     png_destroy_write_struct(&png_ptr,NULL);
  204.     fclose(fp);
  205.     return;
  206.   }
  207.  
  208.   if(setjmp(png_ptr->jmpbuf)) {
  209.     png_destroy_write_struct(&png_ptr,NULL);
  210.     fclose(fp);
  211.     return;
  212.   }
  213.  
  214.   png_init_io(png_ptr,fp);
  215.  
  216.   png_set_IHDR(png_ptr,
  217.                info_ptr,
  218.                w,
  219.                h,
  220.                8,
  221.                PNG_COLOR_TYPE_RGB,
  222.                PNG_INTERLACE_NONE,
  223.                PNG_COMPRESSION_TYPE_DEFAULT,
  224.                PNG_FILTER_TYPE_DEFAULT);
  225.  
  226.   png_write_info(png_ptr,info_ptr);
  227.  
  228.   u8 *b = writeBuffer;
  229.  
  230.   int sizeX = w;
  231.   int sizeY = h;
  232.  
  233.   u8 *pixU8 = (u8 *)data;
  234.   for(int y = 0; y < sizeY; y++) {
  235.     for(int x = 0; x < sizeX; x++) {
  236.       int blue = *pixU8++;
  237.       int green = *pixU8++;
  238.       int red = *pixU8++;
  239.       
  240.       *b++ = red;
  241.       *b++ = green;
  242.       *b++ = blue;
  243.     }
  244.     png_write_row(png_ptr,writeBuffer);
  245.     
  246.     b = writeBuffer;
  247.   }
  248.   
  249.   png_write_end(png_ptr, info_ptr);
  250.  
  251.   png_destroy_write_struct(&png_ptr, &info_ptr);
  252.  
  253.   fclose(fp);
  254. }
  255.  
  256. void GBMapView::OnSave() 
  257. {
  258.   CString filename;
  259.  
  260.   if(theApp.captureFormat == 0)
  261.     filename = "map.png";
  262.   else
  263.     filename = "map.bmp";
  264.  
  265.   LPCTSTR exts[] = {".png", ".bmp" };
  266.   CString title = winResLoadString(IDS_SELECT_CAPTURE_NAME);
  267.   CString filter = theApp.winLoadFilter(IDS_FILTER_PNG);
  268.  
  269.   FileDlg dlg(this,
  270.               filename,
  271.               filter,
  272.               theApp.captureFormat ? 2 : 1,
  273.               theApp.captureFormat ? "BMP" : "PNG",
  274.               exts,
  275.               "",
  276.               title, 
  277.               true);
  278.  
  279.   if(dlg.DoModal() == IDCANCEL) {
  280.     return;
  281.   }
  282.  
  283.   if(dlg.getFilterIndex() == 2)
  284.     saveBMP(dlg.GetPathName());
  285.   else
  286.     savePNG(dlg.GetPathName());
  287. }
  288.  
  289. void GBMapView::render()
  290. {
  291.   u8 * bank0;
  292.   u8 * bank1;
  293.   if(gbCgbMode) {
  294.     bank0 = &gbVram[0x0000];
  295.     bank1 = &gbVram[0x2000];
  296.   } else {
  297.     bank0 = &gbMemory[0x8000];
  298.     bank1 = NULL;
  299.   }
  300.  
  301.   int tile_map_address = 0x1800;
  302.   if(bg == 1)
  303.     tile_map_address = 0x1c00;
  304.  
  305.   int tile_pattern = 0x0000;
  306.   if(bank == 1)
  307.     tile_pattern = 0x0800;
  308.   
  309.   w = 256;
  310.   h = 256;
  311.   
  312.   int tile = 0;
  313.   for(int y = 0; y < 32; y++) {
  314.     for(int x = 0; x < 32; x++) {
  315.       u8 *bmp = &data[y * 8 * 32 * 24 + x*24];      
  316.       u8 attrs = 0;
  317.       if(bank1 != NULL)
  318.         attrs = bank1[tile_map_address];
  319.       u8 tile = bank0[tile_map_address];
  320.       tile_map_address++;
  321.  
  322.       if(bank == 1) {
  323.         if(tile < 128) tile += 128;
  324.         else tile -= 128;
  325.       }
  326.       for(int j = 0; j < 8; j++) {
  327.         int tile_pattern_address = attrs & 0x40 ?
  328.           tile_pattern + tile*16 + (7-j)*2:
  329.           tile_pattern + tile*16+j*2;
  330.         
  331.         u8 tile_a = 0;
  332.         u8 tile_b = 0;
  333.         
  334.         if(attrs & 0x08) {
  335.           tile_a = bank1[tile_pattern_address++];
  336.           tile_b = bank1[tile_pattern_address];
  337.         } else {
  338.           tile_a = bank0[tile_pattern_address++];
  339.           tile_b = bank0[tile_pattern_address];
  340.         }
  341.         
  342.         if(attrs & 0x20) {
  343.           tile_a = gbInvertTab[tile_a];
  344.           tile_b = gbInvertTab[tile_b];
  345.         }
  346.         
  347.         u8 mask = 0x80;
  348.         
  349.         while(mask > 0) {
  350.           u8 c = (tile_a & mask) ? 1 : 0;
  351.           c += (tile_b & mask) ? 2 : 0;
  352.           
  353.           if(gbCgbMode)
  354.             c = c + (attrs & 7)*4;
  355.           
  356.           u16 color = gbPalette[c];
  357.           
  358.           *bmp++ = ((color >> 10) & 0x1f) << 3;
  359.           *bmp++ = ((color >> 5) & 0x1f) << 3;
  360.           *bmp++ = (color & 0x1f) << 3;
  361.           
  362.           mask >>= 1;
  363.         }
  364.         bmp += 31*24;
  365.       }
  366.     }
  367.   }
  368. }
  369.  
  370. void GBMapView::paint()
  371. {
  372.   if(gbRom == NULL)
  373.     return;
  374.   render();
  375.   
  376.   SIZE s;
  377.   if(mapView.getStretch()) {
  378.     mapView.setSize(w, h);
  379.     s.cx = s.cy = 1;
  380.     mapView.SetScrollSizes(MM_TEXT, s);
  381.   } else {
  382.     mapView.setSize(w, h);
  383.     s.cx = w;
  384.     s.cy = h;
  385.     mapView.SetScrollSizes(MM_TEXT, s);
  386.   }
  387.  
  388.   mapView.refresh();
  389. }
  390.  
  391. void GBMapView::OnRefresh() 
  392. {
  393.   paint();
  394. }
  395.  
  396. void GBMapView::update()
  397. {
  398.   paint();
  399. }
  400.  
  401. BOOL GBMapView::OnInitDialog() 
  402. {
  403.   CDialog::OnInitDialog();
  404.   
  405.   DIALOG_SIZER_START( sz )
  406.     DIALOG_SIZER_ENTRY( IDC_MAP_VIEW, DS_SizeX | DS_SizeY )
  407.     DIALOG_SIZER_ENTRY( IDC_REFRESH, DS_MoveY)
  408.     DIALOG_SIZER_ENTRY( IDC_CLOSE, DS_MoveY)
  409.     DIALOG_SIZER_ENTRY( IDC_SAVE,  DS_MoveY)
  410.     DIALOG_SIZER_ENTRY( IDC_COLOR, DS_MoveY)
  411.     DIALOG_SIZER_ENTRY( IDC_R, DS_MoveY)
  412.     DIALOG_SIZER_ENTRY( IDC_G, DS_MoveY)
  413.     DIALOG_SIZER_ENTRY( IDC_B, DS_MoveY)    
  414.     DIALOG_SIZER_END()
  415.     SetData(sz,
  416.             TRUE,
  417.             HKEY_CURRENT_USER,
  418.             "Software\\Emulators\\VisualBoyAdvance\\Viewer\\GBMapView",
  419.             NULL);
  420.  
  421.   int s = regQueryDwordValue("mapViewStretch", 0);
  422.   if(s)
  423.     mapView.setStretch(true);
  424.   ((CButton *)GetDlgItem(IDC_STRETCH))->SetCheck(s);
  425.  
  426.   UINT id = IDC_BANK_0;
  427.   if(bank == 1)
  428.     id = IDC_BANK_1;
  429.   CheckRadioButton(IDC_BANK_0, IDC_BANK_1, id);
  430.   id = IDC_BG0;
  431.   if(bg == 1)
  432.     id = IDC_BG1;
  433.   CheckRadioButton(IDC_BG0, IDC_BG1, id);
  434.   paint();
  435.  
  436.   return TRUE;  // return TRUE unless you set the focus to a control
  437.                 // EXCEPTION: OCX Property Pages should return FALSE
  438. }
  439.  
  440. void GBMapView::OnBg0() 
  441. {
  442.   bg = 0;
  443.   paint();
  444. }
  445.  
  446. void GBMapView::OnBg1() 
  447. {
  448.   bg = 1;
  449.   paint();
  450. }
  451.  
  452. void GBMapView::OnBank0() 
  453. {
  454.   bank = 0;
  455.   paint();
  456. }
  457.  
  458. void GBMapView::OnBank1() 
  459. {
  460.   bank = 1;
  461.   paint();
  462. }
  463.  
  464. void GBMapView::OnStretch() 
  465. {
  466.   mapView.setStretch(!mapView.getStretch());
  467.   paint();
  468.   regSetDwordValue("mapViewStretch", mapView.getStretch());  
  469. }
  470.  
  471. void GBMapView::OnAutoUpdate() 
  472. {
  473.   autoUpdate = !autoUpdate;
  474.   if(autoUpdate) {
  475.     theApp.winAddUpdateListener(this);
  476.   } else {
  477.     theApp.winRemoveUpdateListener(this);    
  478.   }
  479. }
  480.  
  481. void GBMapView::OnClose() 
  482. {
  483.   theApp.winRemoveUpdateListener(this);
  484.   
  485.   DestroyWindow();
  486. }
  487.  
  488. u32 GBMapView::GetClickAddress(int x, int y)
  489. {
  490.   u32 base = 0x9800;
  491.   if(bg == 1)
  492.     base = 0x9c00;
  493.  
  494.   return base + (y >> 3)*32 + (x >> 3);
  495. }
  496.  
  497. LRESULT GBMapView::OnMapInfo(WPARAM wParam, LPARAM lParam)
  498. {
  499.   u8 *colors = (u8 *)lParam;
  500.   mapViewZoom.setColors(colors);
  501.  
  502.   int x = wParam & 0xffff;
  503.   int y = (wParam >> 16);
  504.   
  505.   CString buffer;
  506.   buffer.Format("(%d,%d)", x, y);
  507.   GetDlgItem(IDC_XY)->SetWindowText(buffer);
  508.  
  509.   u32 address = GetClickAddress(x,y);
  510.   buffer.Format("0x%08X", address);
  511.   GetDlgItem(IDC_ADDRESS)->SetWindowText(buffer);
  512.  
  513.   u8 attrs = 0;
  514.  
  515.   u8 tile = gbMemoryMap[9][address & 0xfff];
  516.   if(gbCgbMode) {
  517.     attrs = gbVram[0x2000 + address - 0x8000];
  518.     tile = gbVram[address & 0x1fff];
  519.   }
  520.  
  521.   if(bank == 1) {
  522.     if(tile > 128) tile -= 128;
  523.     else tile += 128;
  524.   }
  525.   
  526.   buffer.Format("%d", tile);
  527.   GetDlgItem(IDC_TILE_NUM)->SetWindowText(buffer);
  528.   
  529.   buffer.Empty();
  530.   buffer += attrs & 0x20 ? 'H' : '-';
  531.   buffer += attrs & 0x40 ? 'V' : '-';
  532.   GetDlgItem(IDC_FLIP)->SetWindowText(buffer);
  533.   
  534.   if(gbCgbMode) {
  535.     buffer.Format("%d", (attrs & 7));
  536.   } else
  537.     buffer = "---";
  538.   GetDlgItem(IDC_PALETTE_NUM)->SetWindowText(buffer);
  539.   
  540.   buffer.Empty();
  541.   if(gbCgbMode)
  542.     buffer += attrs & 0x80 ? 'P' : '-';
  543.   else
  544.     buffer += '-';
  545.   GetDlgItem(IDC_PRIORITY)->SetWindowText(buffer);
  546.  
  547.   return TRUE;
  548. }
  549.  
  550. LRESULT GBMapView::OnColInfo(WPARAM wParam, LPARAM)
  551. {
  552.   u16 c = (u16)wParam;
  553.  
  554.   color.setColor(c);  
  555.  
  556.   int r = (c & 0x1f);
  557.   int g = (c & 0x3e0) >> 5;
  558.   int b = (c & 0x7c00) >> 10;
  559.  
  560.   CString buffer;
  561.   buffer.Format("R: %d", r);
  562.   GetDlgItem(IDC_R)->SetWindowText(buffer);
  563.  
  564.   buffer.Format("G: %d", g);
  565.   GetDlgItem(IDC_G)->SetWindowText(buffer);
  566.  
  567.   buffer.Format("B: %d", b);
  568.   GetDlgItem(IDC_B)->SetWindowText(buffer);
  569.  
  570.   return TRUE;
  571. }
  572.  
  573. void GBMapView::PostNcDestroy() 
  574. {
  575.   delete this;
  576.   CDialog::PostNcDestroy();
  577. }
  578.