home *** CD-ROM | disk | FTP | other *** search
/ Chip 2004 July / CMCD0704.ISO / Software / Freeware / Utilitare / VisualBoyAdvance-1.7.2 / src / win32 / OamView.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2004-05-13  |  14.0 KB  |  670 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. // OamView.cpp : implementation file
  20. //
  21.  
  22. #include "stdafx.h"
  23. #include "vba.h"
  24. #include "FileDlg.h"
  25. #include "OamView.h"
  26. #include "Reg.h"
  27. #include "WinResUtil.h"
  28.  
  29. #include "../System.h"
  30. #include "../GBA.h"
  31. #include "../Globals.h"
  32. #include "../NLS.h"
  33. #include "../Util.h"
  34.  
  35. extern "C" {
  36. #include <png.h>
  37. }
  38.  
  39. #ifdef _DEBUG
  40. #define new DEBUG_NEW
  41. #undef THIS_FILE
  42. static char THIS_FILE[] = __FILE__;
  43. #endif
  44.  
  45. /////////////////////////////////////////////////////////////////////////////
  46. // OamView dialog
  47.  
  48.  
  49. OamView::OamView(CWnd* pParent /*=NULL*/)
  50.   : ResizeDlg(OamView::IDD, pParent)
  51. {
  52.   //{{AFX_DATA_INIT(OamView)
  53.   m_stretch = FALSE;
  54.   //}}AFX_DATA_INIT
  55.   autoUpdate = false;
  56.   
  57.   memset(&bmpInfo.bmiHeader, 0, sizeof(bmpInfo.bmiHeader));
  58.   
  59.   bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);
  60.   bmpInfo.bmiHeader.biWidth = 32;
  61.   bmpInfo.bmiHeader.biHeight = 32;
  62.   bmpInfo.bmiHeader.biPlanes = 1;
  63.   bmpInfo.bmiHeader.biBitCount = 24;
  64.   bmpInfo.bmiHeader.biCompression = BI_RGB;
  65.   data = (u8 *)calloc(1, 3 * 64 * 64);
  66.  
  67.   oamView.setData(data);
  68.   oamView.setBmpInfo(&bmpInfo);
  69.  
  70.   number = 0;
  71. }
  72.  
  73.  
  74. void OamView::DoDataExchange(CDataExchange* pDX)
  75. {
  76.   CDialog::DoDataExchange(pDX);
  77.   //{{AFX_DATA_MAP(OamView)
  78.   DDX_Control(pDX, IDC_SPRITE, m_sprite);
  79.   DDX_Check(pDX, IDC_STRETCH, m_stretch);
  80.   //}}AFX_DATA_MAP
  81.   DDX_Control(pDX, IDC_COLOR, color);
  82.   DDX_Control(pDX, IDC_OAM_VIEW, oamView);
  83.   DDX_Control(pDX, IDC_OAM_VIEW_ZOOM, oamZoom);
  84. }
  85.  
  86.  
  87. BEGIN_MESSAGE_MAP(OamView, CDialog)
  88.   //{{AFX_MSG_MAP(OamView)
  89.   ON_BN_CLICKED(IDC_SAVE, OnSave)
  90.   ON_BN_CLICKED(IDC_STRETCH, OnStretch)
  91.   ON_BN_CLICKED(IDC_AUTO_UPDATE, OnAutoUpdate)
  92.   ON_EN_CHANGE(IDC_SPRITE, OnChangeSprite)
  93.   ON_BN_CLICKED(IDC_CLOSE, OnClose)
  94.   ON_WM_HSCROLL()
  95.   //}}AFX_MSG_MAP
  96.   ON_MESSAGE(WM_MAPINFO, OnMapInfo)
  97.   ON_MESSAGE(WM_COLINFO, OnColInfo)
  98.   END_MESSAGE_MAP()
  99.  
  100.   /////////////////////////////////////////////////////////////////////////////
  101. // OamView message handlers
  102.  
  103. OamView::~OamView()
  104. {
  105.   free(data);
  106.   data = NULL;
  107. }
  108.  
  109. void OamView::paint()
  110. {
  111.   if(oam == NULL || paletteRAM == NULL || vram == NULL)
  112.     return;
  113.   
  114.   render();
  115.   oamView.setSize(w,h);
  116.   oamView.refresh();
  117. }
  118.  
  119. void OamView::update()
  120. {
  121.   paint();
  122. }
  123.  
  124.  
  125.  
  126. void OamView::setAttributes(u16 a0, u16 a1, u16 a2)
  127. {
  128.   CString buffer;
  129.   
  130.   int y = a0 & 255;
  131.   int rot = a0 & 512;
  132.   int mode = (a0 >> 10) & 3;
  133.   int mosaic = a0 & 4096;
  134.   int color = a0 & 8192;
  135.   int duple = a0 & 1024;
  136.   int shape = (a0 >> 14) & 3;
  137.   int x = a1 & 511;
  138.   int rotParam = (a1 >> 9) & 31;
  139.   int flipH = a1 & 4096;
  140.   int flipV = a1 & 8192;
  141.   int size = (a1 >> 14) & 3;
  142.   int tile = a2 & 1023;
  143.   int prio = (a2 >> 10) & 3;
  144.   int pal = (a2 >> 12) & 15;
  145.  
  146.   buffer.Format("%d,%d", x,y);
  147.   GetDlgItem(IDC_POS)->SetWindowText(buffer);
  148.  
  149.   buffer.Format("%d", mode);
  150.   GetDlgItem(IDC_MODE)->SetWindowText(buffer);
  151.  
  152.   GetDlgItem(IDC_COLORS)->SetWindowText(color ? "256" : "16");
  153.  
  154.   buffer.Format("%d", pal);
  155.   GetDlgItem(IDC_PALETTE)->SetWindowText(buffer);
  156.  
  157.   buffer.Format("%d", tile);
  158.   GetDlgItem(IDC_TILE)->SetWindowText(buffer);
  159.  
  160.   buffer.Format("%d", prio);
  161.   GetDlgItem(IDC_PRIO)->SetWindowText(buffer);
  162.  
  163.   buffer.Format("%d,%d", w,h);
  164.   GetDlgItem(IDC_SIZE2)->SetWindowText(buffer);
  165.  
  166.   if(rot) {
  167.     buffer.Format("%d", rotParam);
  168.   } else
  169.     buffer.Empty();
  170.   GetDlgItem(IDC_ROT)->SetWindowText(buffer);
  171.  
  172.   buffer.Empty();
  173.  
  174.   if(rot)
  175.     buffer += 'R';
  176.   else buffer += ' ';
  177.   if(!rot) {
  178.     if(flipH)
  179.       buffer += 'H';
  180.     else
  181.       buffer += ' ';
  182.     if(flipV)
  183.       buffer += 'V';
  184.     else
  185.       buffer += ' ';
  186.   } else {
  187.     buffer += ' ';
  188.     buffer += ' ';
  189.   }
  190.   if(mosaic)
  191.     buffer += 'M';
  192.   else
  193.     buffer += ' ';
  194.   if(duple)
  195.     buffer += 'D';
  196.   else
  197.     buffer += ' ';
  198.   
  199.   GetDlgItem(IDC_FLAGS)->SetWindowText(buffer);
  200. }
  201.  
  202. void OamView::render()
  203. {
  204.   int m=0;
  205.   if(oam == NULL || paletteRAM == NULL || vram == NULL)
  206.     return;
  207.   
  208.   u16 *sprites = &((u16 *)oam)[4*number];
  209.   u16 *spritePalette = &((u16 *)paletteRAM)[0x100];
  210.   u8 *bmp = data;
  211.   
  212.   u16 a0 = *sprites++;
  213.   u16 a1 = *sprites++;
  214.   u16 a2 = *sprites++;
  215.   
  216.   int sizeY = 8;
  217.   int sizeX = 8;
  218.   
  219.   switch(((a0 >>12) & 0x0c)|(a1>>14)) {
  220.   case 0:
  221.     break;
  222.   case 1:
  223.     sizeX = sizeY = 16;
  224.     break;
  225.   case 2:
  226.     sizeX = sizeY = 32;
  227.     break;
  228.   case 3:
  229.     sizeX = sizeY = 64;
  230.     break;
  231.   case 4:
  232.     sizeX = 16;
  233.     break;
  234.   case 5:
  235.     sizeX = 32;
  236.     break;
  237.   case 6:
  238.     sizeX = 32;
  239.     sizeY = 16;
  240.     break;
  241.   case 7:
  242.     sizeX = 64;
  243.     sizeY = 32;
  244.     break;
  245.   case 8:
  246.     sizeY = 16;
  247.     break;
  248.   case 9:
  249.     sizeY = 32;
  250.     break;
  251.   case 10:
  252.     sizeX = 16;
  253.     sizeY = 32;
  254.     break;
  255.   case 11:
  256.     sizeX = 32;
  257.     sizeY = 64;
  258.     break;
  259.   default:
  260.     return;
  261.   }
  262.  
  263.   w = sizeX;
  264.   h = sizeY;
  265.  
  266.   setAttributes(a0,a1,a2);
  267.   
  268.   int sy = (a0 & 255);
  269.   
  270.   if(a0 & 0x2000) {
  271.     int c = (a2 & 0x3FF);
  272.     //          if((DISPCNT & 7) > 2 && (c < 512))
  273.     //            return;
  274.     int inc = 32;
  275.     if(DISPCNT & 0x40)
  276.       inc = sizeX >> 2;
  277.     else
  278.       c &= 0x3FE;
  279.     
  280.     for(int y = 0; y < sizeY; y++) {
  281.       for(int x = 0; x < sizeX; x++) {
  282.         u32 color = vram[0x10000 + (((c + (y>>3) * inc)*
  283.                                      32 + (y & 7) * 8 + (x >> 3) * 64 +
  284.                                      (x & 7))&0x7FFF)];
  285.         color = spritePalette[color];
  286.         *bmp++ = ((color >> 10) & 0x1f) << 3;
  287.         *bmp++ = ((color >> 5) & 0x1f) << 3;
  288.         *bmp++ = (color & 0x1f) << 3;
  289.       }
  290.     }
  291.   } else {
  292.     int c = (a2 & 0x3FF);
  293.     //      if((DISPCNT & 7) > 2 && (c < 512))
  294.     //          continue;
  295.     
  296.     int inc = 32;
  297.     if(DISPCNT & 0x40)
  298.       inc = sizeX >> 3;
  299.     int palette = (a2 >> 8) & 0xF0;
  300.     for(int y = 0; y < sizeY; y++) {
  301.       for(int x = 0; x < sizeX; x++) {
  302.         u32 color = vram[0x10000 + (((c + (y>>3) * inc)*
  303.                                      32 + (y & 7) * 4 + (x >> 3) * 32 +
  304.                                      ((x & 7)>>1))&0x7FFF)];
  305.         if(x & 1)
  306.           color >>= 4;
  307.         else
  308.           color &= 0x0F;
  309.         
  310.         color = spritePalette[palette+color];
  311.         *bmp++ = ((color >> 10) & 0x1f) << 3;
  312.         *bmp++ = ((color >> 5) & 0x1f) << 3;
  313.         *bmp++ = (color & 0x1f) << 3;            
  314.       }
  315.     }
  316.   }
  317. }
  318.  
  319. void OamView::saveBMP(const char *name)
  320. {
  321.   u8 writeBuffer[1024 * 3];
  322.   
  323.   FILE *fp = fopen(name,"wb");
  324.  
  325.   if(!fp) {
  326.     systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name);
  327.     return;
  328.   }
  329.  
  330.   struct {
  331.     u8 ident[2];
  332.     u8 filesize[4];
  333.     u8 reserved[4];
  334.     u8 dataoffset[4];
  335.     u8 headersize[4];
  336.     u8 width[4];
  337.     u8 height[4];
  338.     u8 planes[2];
  339.     u8 bitsperpixel[2];
  340.     u8 compression[4];
  341.     u8 datasize[4];
  342.     u8 hres[4];
  343.     u8 vres[4];
  344.     u8 colors[4];
  345.     u8 importantcolors[4];
  346.     u8 pad[2];
  347.   } bmpheader;
  348.   memset(&bmpheader, 0, sizeof(bmpheader));
  349.  
  350.   bmpheader.ident[0] = 'B';
  351.   bmpheader.ident[1] = 'M';
  352.  
  353.   u32 fsz = sizeof(bmpheader) + w*h*3;
  354.   utilPutDword(bmpheader.filesize, fsz);
  355.   utilPutDword(bmpheader.dataoffset, 0x38);
  356.   utilPutDword(bmpheader.headersize, 0x28);
  357.   utilPutDword(bmpheader.width, w);
  358.   utilPutDword(bmpheader.height, h);
  359.   utilPutDword(bmpheader.planes, 1);
  360.   utilPutDword(bmpheader.bitsperpixel, 24);
  361.   utilPutDword(bmpheader.datasize, 3*w*h);
  362.  
  363.   fwrite(&bmpheader, 1, sizeof(bmpheader), fp);
  364.  
  365.   u8 *b = writeBuffer;
  366.  
  367.   int sizeX = w;
  368.   int sizeY = h;
  369.  
  370.   u8 *pixU8 = (u8 *)data+3*w*(h-1);
  371.   for(int y = 0; y < sizeY; y++) {
  372.     for(int x = 0; x < sizeX; x++) {
  373.       *b++ = *pixU8++; // B
  374.       *b++ = *pixU8++; // G
  375.       *b++ = *pixU8++; // R
  376.     }
  377.     pixU8 -= 2*3*w;
  378.     fwrite(writeBuffer, 1, 3*w, fp);
  379.     
  380.     b = writeBuffer;
  381.   }
  382.  
  383.   fclose(fp);
  384. }
  385.  
  386.  
  387.  
  388. void OamView::savePNG(const char *name)
  389. {
  390.   u8 writeBuffer[1024 * 3];
  391.   
  392.   FILE *fp = fopen(name,"wb");
  393.  
  394.   if(!fp) {
  395.     systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name);
  396.     return;
  397.   }
  398.   
  399.   png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
  400.                                                 NULL,
  401.                                                 NULL,
  402.                                                 NULL);
  403.   if(!png_ptr) {
  404.     fclose(fp);
  405.     return;
  406.   }
  407.  
  408.   png_infop info_ptr = png_create_info_struct(png_ptr);
  409.  
  410.   if(!info_ptr) {
  411.     png_destroy_write_struct(&png_ptr,NULL);
  412.     fclose(fp);
  413.     return;
  414.   }
  415.  
  416.   if(setjmp(png_ptr->jmpbuf)) {
  417.     png_destroy_write_struct(&png_ptr,NULL);
  418.     fclose(fp);
  419.     return;
  420.   }
  421.  
  422.   png_init_io(png_ptr,fp);
  423.  
  424.   png_set_IHDR(png_ptr,
  425.                info_ptr,
  426.                w,
  427.                h,
  428.                8,
  429.                PNG_COLOR_TYPE_RGB,
  430.                PNG_INTERLACE_NONE,
  431.                PNG_COMPRESSION_TYPE_DEFAULT,
  432.                PNG_FILTER_TYPE_DEFAULT);
  433.  
  434.   png_write_info(png_ptr,info_ptr);
  435.  
  436.   u8 *b = writeBuffer;
  437.  
  438.   int sizeX = w;
  439.   int sizeY = h;
  440.  
  441.   u8 *pixU8 = (u8 *)data;
  442.   for(int y = 0; y < sizeY; y++) {
  443.     for(int x = 0; x < sizeX; x++) {
  444.       int blue = *pixU8++;
  445.       int green = *pixU8++;
  446.       int red = *pixU8++;
  447.       
  448.       *b++ = red;
  449.       *b++ = green;
  450.       *b++ = blue;
  451.     }
  452.     png_write_row(png_ptr,writeBuffer);
  453.     
  454.     b = writeBuffer;
  455.   }
  456.   
  457.   png_write_end(png_ptr, info_ptr);
  458.  
  459.   png_destroy_write_struct(&png_ptr, &info_ptr);
  460.  
  461.   fclose(fp);
  462. }
  463.  
  464. void OamView::OnSave() 
  465. {
  466.   CString captureBuffer;
  467.  
  468.   if(theApp.captureFormat == 0)
  469.     captureBuffer = "oam.png";
  470.   else
  471.     captureBuffer = "oam.bmp";
  472.  
  473.   LPCTSTR exts[] = {".png", ".bmp" };
  474.  
  475.   CString filter = theApp.winLoadFilter(IDS_FILTER_PNG);
  476.   CString title = winResLoadString(IDS_SELECT_CAPTURE_NAME);
  477.  
  478.   FileDlg dlg(this,
  479.               captureBuffer,
  480.               filter,
  481.               theApp.captureFormat ? 2 : 1,
  482.               theApp.captureFormat ? "BMP" : "PNG",
  483.               exts,
  484.               "",
  485.               title,
  486.               true);
  487.  
  488.   if(dlg.DoModal() == IDCANCEL) {
  489.     return;
  490.   }
  491.   captureBuffer = dlg.GetPathName();
  492.  
  493.   if(dlg.getFilterIndex() == 2)
  494.     saveBMP(captureBuffer);
  495.   else
  496.     savePNG(captureBuffer);  
  497. }
  498.  
  499. BOOL OamView::OnInitDialog() 
  500. {
  501.   CDialog::OnInitDialog();
  502.   
  503.   DIALOG_SIZER_START( sz )
  504.     DIALOG_SIZER_ENTRY( IDC_OAM_VIEW, DS_SizeX | DS_SizeY )
  505.     DIALOG_SIZER_ENTRY( IDC_OAM_VIEW_ZOOM, DS_MoveX)
  506.     DIALOG_SIZER_ENTRY( IDC_REFRESH, DS_MoveY)
  507.     DIALOG_SIZER_ENTRY( IDC_SAVE,  DS_MoveY)
  508.     DIALOG_SIZER_ENTRY( IDC_CLOSE, DS_MoveY)
  509.     DIALOG_SIZER_ENTRY( IDC_COLOR, DS_MoveY)
  510.     DIALOG_SIZER_ENTRY( IDC_R, DS_MoveY)
  511.     DIALOG_SIZER_ENTRY( IDC_G, DS_MoveY)
  512.     DIALOG_SIZER_ENTRY( IDC_B, DS_MoveY)    
  513.     DIALOG_SIZER_END()
  514.     SetData(sz,
  515.             TRUE,
  516.             HKEY_CURRENT_USER,
  517.             "Software\\Emulators\\VisualBoyAdvance\\Viewer\\OamView",
  518.             NULL);
  519.   m_sprite.SetWindowText("0");
  520.  
  521.   updateScrollInfo();
  522.  
  523.   m_stretch = regQueryDwordValue("oamViewStretch", 0);
  524.   if(m_stretch)
  525.     oamView.setStretch(true);
  526.   UpdateData(FALSE);
  527.   
  528.   paint();
  529.   
  530.   return TRUE;  // return TRUE unless you set the focus to a control
  531.                 // EXCEPTION: OCX Property Pages should return FALSE
  532. }
  533.  
  534. void OamView::OnStretch() 
  535. {
  536.   oamView.setStretch(!oamView.getStretch());
  537.   paint();
  538.   regSetDwordValue("oamViewStretch", oamView.getStretch());  
  539. }
  540.  
  541.  
  542. void OamView::OnAutoUpdate() 
  543. {
  544.   autoUpdate = !autoUpdate;
  545.   if(autoUpdate) {
  546.     theApp.winAddUpdateListener(this);
  547.   } else {
  548.     theApp.winRemoveUpdateListener(this);    
  549.   }  
  550. }
  551.  
  552. void OamView::OnChangeSprite() 
  553. {
  554.   CString buffer;
  555.   m_sprite.GetWindowText(buffer);
  556.   int n = atoi(buffer);
  557.   if(n < 0 || n > 127) {
  558.     buffer.Format("%d", number);
  559.     m_sprite.SetWindowText(buffer);
  560.     return;
  561.   }
  562.   number = n;
  563.   paint();
  564.   updateScrollInfo();
  565. }
  566.  
  567. void OamView::OnClose() 
  568. {
  569.   theApp.winRemoveUpdateListener(this);
  570.   
  571.   DestroyWindow();
  572. }
  573.  
  574. LRESULT OamView::OnMapInfo(WPARAM wParam, LPARAM lParam)
  575. {
  576.   u8 *colors = (u8 *)lParam;
  577.   oamZoom.setColors(colors);
  578.   
  579.   return TRUE;
  580. }
  581.  
  582. LRESULT OamView::OnColInfo(WPARAM wParam, LPARAM lParam)
  583. {
  584.   u16 c = (u16)wParam;
  585.  
  586.   color.setColor(c);  
  587.  
  588.   int r = (c & 0x1f);
  589.   int g = (c & 0x3e0) >> 5;
  590.   int b = (c & 0x7c00) >> 10;
  591.  
  592.   CString buffer;
  593.   buffer.Format("R: %d", r);
  594.   GetDlgItem(IDC_R)->SetWindowText(buffer);
  595.  
  596.   buffer.Format("G: %d", g);
  597.   GetDlgItem(IDC_G)->SetWindowText(buffer);
  598.  
  599.   buffer.Format("B: %d", b);
  600.   GetDlgItem(IDC_B)->SetWindowText(buffer);
  601.  
  602.   return TRUE;
  603. }
  604.  
  605. void OamView::updateScrollInfo()
  606. {
  607.   SCROLLINFO si;
  608.   ZeroMemory(&si, sizeof(si));
  609.   si.cbSize = sizeof(si);
  610.   si.fMask = SIF_PAGE | SIF_RANGE | SIF_DISABLENOSCROLL | SIF_POS;
  611.   si.nMin = 0;
  612.   si.nMax = 127;
  613.   si.nPage = 1;
  614.   si.nPos = number;
  615.   GetDlgItem(IDC_SCROLLBAR)->SetScrollInfo(SB_CTL,
  616.                                            &si,
  617.                                            TRUE);    
  618. }
  619.  
  620. void OamView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar) 
  621. {
  622.   switch(nSBCode) {
  623.   case SB_BOTTOM:
  624.     number = 127;
  625.     break;
  626.   case SB_LINEDOWN:
  627.     number++;
  628.     if(number > 127)
  629.       number = 127;
  630.     break;
  631.   case SB_LINEUP:
  632.     number--;
  633.     if(number < 0)
  634.       number = 0;
  635.     break;
  636.   case SB_PAGEDOWN:
  637.     number += 16;
  638.     if(number > 127)
  639.       number = 127;
  640.     break;
  641.   case SB_PAGEUP:
  642.     number -= 16;
  643.     if(number < 0)
  644.       number = 0;
  645.     break;
  646.   case SB_TOP:
  647.     number = 0;
  648.     break;
  649.   case SB_THUMBTRACK:
  650.     number = nPos;
  651.     if(number < 0)
  652.       number = 0;
  653.     if(number > 127)
  654.       number = 127;
  655.     break;
  656.   }
  657.  
  658.   updateScrollInfo();
  659.   
  660.   CString buffer;
  661.   buffer.Format("%d", number);
  662.   m_sprite.SetWindowText(buffer);
  663.   paint();
  664. }
  665.  
  666. void OamView::PostNcDestroy() 
  667. {
  668.   delete this;
  669. }
  670.