Mercurial > vba-clojure
view src/win32/MapView.cpp @ 7:c0a590a394c3
ignore generated files
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:50:33 -0600 |
parents | f9f4f1b99eed |
children |
line wrap: on
line source
1 // MapView.cpp : implementation file2 //4 #include "stdafx.h"5 #include "resource.h"6 #include "MapView.h"7 #include "FileDlg.h"8 #include "Reg.h"9 #include "WinResUtil.h"10 #include "VBA.h"12 #include "../gba/GBAGlobals.h"13 #include "../NLS.h"14 #include "../common/Util.h"16 extern "C" {17 #include <png.h>18 }20 /////////////////////////////////////////////////////////////////////////////21 // MapView dialog23 MapView::MapView(CWnd*pParent /*=NULL*/)24 : ResizeDlg(MapView::IDD, pParent)25 {26 //{{AFX_DATA_INIT(MapView)27 //}}AFX_DATA_INIT28 autoUpdate = false;30 memset(&bmpInfo.bmiHeader, 0, sizeof(bmpInfo.bmiHeader));32 bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);33 bmpInfo.bmiHeader.biWidth = 1024;34 bmpInfo.bmiHeader.biHeight = -1024;35 bmpInfo.bmiHeader.biPlanes = 1;36 bmpInfo.bmiHeader.biBitCount = 24;37 bmpInfo.bmiHeader.biCompression = BI_RGB;38 data = (u8 *)calloc(1, 3 * 1024 * 1024);40 mapView.setData(data);41 mapView.setBmpInfo(&bmpInfo);43 control = BG0CNT;45 bg = 0;46 frame = 0;47 }49 MapView::~MapView()50 {51 free(data);52 data = NULL;53 }55 void MapView::DoDataExchange(CDataExchange*pDX)56 {57 CDialog::DoDataExchange(pDX);58 //{{AFX_DATA_MAP(MapView)59 DDX_Control(pDX, IDC_NUMCOLORS, m_numcolors);60 DDX_Control(pDX, IDC_MODE, m_mode);61 DDX_Control(pDX, IDC_OVERFLOW, m_overflow);62 DDX_Control(pDX, IDC_MOSAIC, m_mosaic);63 DDX_Control(pDX, IDC_PRIORITY, m_priority);64 DDX_Control(pDX, IDC_DIM, m_dim);65 DDX_Control(pDX, IDC_CHARBASE, m_charbase);66 DDX_Control(pDX, IDC_MAPBASE, m_mapbase);67 //}}AFX_DATA_MAP68 DDX_Control(pDX, IDC_MAP_VIEW, mapView);69 DDX_Control(pDX, IDC_MAP_VIEW_ZOOM, mapViewZoom);70 DDX_Control(pDX, IDC_COLOR, color);71 }73 BEGIN_MESSAGE_MAP(MapView, CDialog)74 //{{AFX_MSG_MAP(MapView)75 ON_BN_CLICKED(IDC_REFRESH, OnRefresh)76 ON_BN_CLICKED(IDC_FRAME_0, OnFrame0)77 ON_BN_CLICKED(IDC_FRAME_1, OnFrame1)78 ON_BN_CLICKED(IDC_BG0, OnBg0)79 ON_BN_CLICKED(IDC_BG1, OnBg1)80 ON_BN_CLICKED(IDC_BG2, OnBg2)81 ON_BN_CLICKED(IDC_BG3, OnBg3)82 ON_BN_CLICKED(IDC_STRETCH, OnStretch)83 ON_BN_CLICKED(IDC_AUTO_UPDATE, OnAutoUpdate)84 ON_BN_CLICKED(IDC_CLOSE, OnClose)85 ON_BN_CLICKED(IDC_SAVE, OnSave)86 //}}AFX_MSG_MAP87 ON_MESSAGE(WM_MAPINFO, OnMapInfo)88 ON_MESSAGE(WM_COLINFO, OnColInfo)89 END_MESSAGE_MAP()91 /////////////////////////////////////////////////////////////////////////////92 // MapView message handlers94 void MapView::renderTextScreen(u16 control)95 {96 u16 *palette = (u16 *)paletteRAM;97 u8 * charBase = &vram[((control >> 2) & 0x03) * 0x4000];98 u16 *screenBase = (u16 *)&vram[((control >> 8) & 0x1f) * 0x800];99 u8 * bmp = data;101 int sizeX = 256;102 int sizeY = 256;103 switch ((control >> 14) & 3)104 {105 case 0:106 break;107 case 1:108 sizeX = 512;109 break;110 case 2:111 sizeY = 512;112 break;113 case 3:114 sizeX = 512;115 sizeY = 512;116 break;117 }119 w = sizeX;120 h = sizeY;122 if (control & 0x80)123 {124 for (int y = 0; y < sizeY; y++)125 {126 int yy = y & 255;128 if (y == 256 && sizeY > 256)129 {130 screenBase += 0x400;131 if (sizeX > 256)132 screenBase += 0x400;133 }134 u16 *screenSource = screenBase + ((yy>>3)*32);136 for (int x = 0; x < sizeX; x++)137 {138 u16 data = *screenSource;140 int tile = data & 0x3FF;141 int tileX = (x & 7);142 int tileY = y & 7;144 if (data & 0x0400)145 tileX = 7 - tileX;146 if (data & 0x0800)147 tileY = 7 - tileY;149 u8 c = charBase[tile * 64 + tileY * 8 + tileX];151 u16 color = palette[c];153 *bmp++ = ((color >> 10) & 0x1f) << 3;154 *bmp++ = ((color >> 5) & 0x1f) << 3;155 *bmp++ = (color & 0x1f) << 3;157 if (data & 0x0400)158 {159 if (tileX == 0)160 screenSource++;161 }162 else if (tileX == 7)163 screenSource++;164 if (x == 255 && sizeX > 256)165 {166 screenSource = screenBase + 0x400 + ((yy>>3)*32);167 }168 }169 }170 }171 else172 {173 for (int y = 0; y < sizeY; y++)174 {175 int yy = y & 255;177 if (y == 256 && sizeY > 256)178 {179 screenBase += 0x400;180 if (sizeX > 256)181 screenBase += 0x400;182 }183 u16 *screenSource = screenBase + ((yy>>3)*32);185 for (int x = 0; x < sizeX; x++)186 {187 u16 data = *screenSource;189 int tile = data & 0x3FF;190 int tileX = (x & 7);191 int tileY = y & 7;193 if (data & 0x0400)194 tileX = 7 - tileX;195 if (data & 0x0800)196 tileY = 7 - tileY;198 u8 color = charBase[tile * 32 + tileY * 4 + (tileX>>1)];200 if (tileX & 1)201 {202 color = (color >> 4);203 }204 else205 {206 color &= 0x0F;207 }209 int pal = (*screenSource>>8) & 0xF0;210 u16 color2 = palette[pal + color];212 *bmp++ = ((color2 >> 10) & 0x1f) << 3;213 *bmp++ = ((color2 >> 5) & 0x1f) << 3;214 *bmp++ = (color2 & 0x1f) << 3;216 if (data & 0x0400)217 {218 if (tileX == 0)219 screenSource++;220 }221 else if (tileX == 7)222 screenSource++;224 if (x == 255 && sizeX > 256)225 {226 screenSource = screenBase + 0x400 + ((yy>>3)*32);227 }228 }229 }230 }231 /*232 switch(bg) {233 case 0:234 renderView(BG0HOFS<<8, BG0VOFS<<8,235 0x100, 0x000,236 0x000, 0x100,237 (sizeX -1) <<8,238 (sizeY -1) << 8,239 true);240 break;241 case 1:242 renderView(BG1HOFS<<8, BG1VOFS<<8,243 0x100, 0x000,244 0x000, 0x100,245 (sizeX -1) <<8,246 (sizeY -1) << 8,247 true);248 break;249 case 2:250 renderView(BG2HOFS<<8, BG2VOFS<<8,251 0x100, 0x000,252 0x000, 0x100,253 (sizeX -1) <<8,254 (sizeY -1) << 8,255 true);256 break;257 case 3:258 renderView(BG3HOFS<<8, BG3VOFS<<8,259 0x100, 0x000,260 0x000, 0x100,261 (sizeX -1) <<8,262 (sizeY -1) << 8,263 true);264 break;265 }266 */267 }269 void MapView::renderRotScreen(u16 control)270 {271 u16 *palette = (u16 *)paletteRAM;272 u8 * charBase = &vram[((control >> 2) & 0x03) * 0x4000];273 u8 * screenBase = (u8 *)&vram[((control >> 8) & 0x1f) * 0x800];274 u8 * bmp = data;276 int sizeX = 128;277 int sizeY = 128;278 switch ((control >> 14) & 3)279 {280 case 0:281 break;282 case 1:283 sizeX = sizeY = 256;284 break;285 case 2:286 sizeX = sizeY = 512;287 break;288 case 3:289 sizeX = sizeY = 1024;290 break;291 }293 w = sizeX;294 h = sizeY;296 if (control & 0x80)297 {298 for (int y = 0; y < sizeY; y++)299 {300 for (int x = 0; x < sizeX; x++)301 {302 int tile = screenBase[(x>>3) + (y>>3)*(w>>3)];304 int tileX = (x & 7);305 int tileY = y & 7;307 u8 color = charBase[tile * 64 + tileY * 8 + tileX];308 u16 color2 = palette[color];310 *bmp++ = ((color2 >> 10) & 0x1f) << 3;311 *bmp++ = ((color2 >> 5) & 0x1f) << 3;312 *bmp++ = (color2 & 0x1f) << 3;313 }314 }315 }316 else317 {318 for (int y = 0; y < sizeY; y++)319 {320 for (int x = 0; x < sizeX; x++)321 {322 int tile = screenBase[(x>>3) + (y>>3)*(w>>3)];324 int tileX = (x & 7);325 int tileY = y & 7;327 u8 color = charBase[tile * 64 + tileY * 8 + tileX];328 u16 color2 = palette[color];330 *bmp++ = ((color2 >> 10) & 0x1f) << 3;331 *bmp++ = ((color2 >> 5) & 0x1f) << 3;332 *bmp++ = (color2 & 0x1f) << 3;333 }334 }335 }337 u32 xx;338 u32 yy;340 switch (bg)341 {342 case 2:343 xx = BG2X_L | BG2X_H << 16;344 yy = BG2Y_L | BG2Y_H << 16;346 /*347 renderView(xx, yy,348 BG2PA, BG2PC,349 BG2PB, BG2PD,350 (sizeX -1) <<8,351 (sizeY -1) << 8,352 (control & 0x2000) != 0);353 */354 break;355 case 3:356 xx = BG3X_L | BG3X_H << 16;357 yy = BG3Y_L | BG3Y_H << 16;358 /*359 renderView(xx, yy,360 BG3PA, BG3PC,361 BG3PB, BG3PD,362 (sizeX -1) <<8,363 (sizeY -1) << 8,364 (control & 0x2000) != 0);365 */366 break;367 }368 }370 void MapView::renderMode0()371 {372 renderTextScreen(control);373 }375 void MapView::renderMode1()376 {377 switch (bg)378 {379 case 0:380 case 1:381 renderTextScreen(control);382 break;383 case 2:384 renderRotScreen(control);385 break;386 default:387 bg = 0;388 control = BG0CNT;389 renderTextScreen(control);390 break;391 }392 }394 void MapView::renderMode2()395 {396 switch (bg)397 {398 case 2:399 case 3:400 renderRotScreen(control);401 break;402 default:403 bg = 2;404 control = BG2CNT;405 renderRotScreen(control);406 break;407 }408 }410 void MapView::renderMode3()411 {412 u8 * bmp = data;413 u16 *src = (u16 *)&vram[0];415 w = 240;416 h = 160;418 for (int y = 0; y < 160; y++)419 {420 for (int x = 0; x < 240; x++)421 {422 u16 data = *src++;423 *bmp++ = ((data >> 10) & 0x1f) << 3;424 *bmp++ = ((data >> 5) & 0x1f) << 3;425 *bmp++ = (data & 0x1f) << 3;426 }427 }428 bg = 2;429 }431 void MapView::renderMode4()432 {433 u8 * bmp = data;434 u8 * src = frame ? &vram[0xa000] : &vram[0];435 u16 *pal = (u16 *)&paletteRAM[0];437 w = 240;438 h = 160;440 for (int y = 0; y < 160; y++)441 {442 for (int x = 0; x < 240; x++)443 {444 u8 c = *src++;445 u16 data = pal[c];446 *bmp++ = ((data >> 10) & 0x1f) << 3;447 *bmp++ = ((data >> 5) & 0x1f) << 3;448 *bmp++ = (data & 0x1f) << 3;449 }450 }451 bg = 2;452 }454 void MapView::renderMode5()455 {456 u8 * bmp = data;457 u16 *src = (u16 *)(frame ? &vram[0xa000] : &vram[0]);459 w = 160;460 h = 128;462 for (int y = 0; y < 128; y++)463 {464 for (int x = 0; x < 160; x++)465 {466 u16 data = *src++;467 *bmp++ = ((data >> 10) & 0x1f) << 3;468 *bmp++ = ((data >> 5) & 0x1f) << 3;469 *bmp++ = (data & 0x1f) << 3;470 }471 }472 bg = 2;473 }475 void MapView::OnRefresh()476 {477 paint();478 }480 void MapView::paint()481 {482 if (vram == NULL)483 return;484 int mode = DISPCNT & 7;486 switch (bg)487 {488 default:489 case 0:490 control = BG0CNT;491 break;492 case 1:493 control = BG1CNT;494 break;495 case 2:496 control = BG2CNT;497 break;498 case 3:499 control = BG3CNT;500 break;501 }503 switch (mode)504 {505 case 0:506 renderMode0();507 break;508 case 1:509 renderMode1();510 break;511 case 2:512 renderMode2();513 break;514 case 3:515 renderMode3();516 break;517 case 4:518 renderMode4();519 break;520 case 5:521 renderMode5();522 break;523 }524 enableButtons(mode);525 SIZE s;527 if (mapView.getStretch())528 {529 mapView.setSize(w, h);530 s.cx = s.cy = 1;531 mapView.SetScrollSizes(MM_TEXT, s);532 }533 else534 {535 mapView.setSize(w, h);536 s.cx = w;537 s.cy = h;538 mapView.SetScrollSizes(MM_TEXT, s);539 }541 mapView.refresh();543 CString buffer;545 u32 charBase = ((control >> 2) & 0x03) * 0x4000 + 0x6000000;546 u32 screenBase = ((control >> 8) & 0x1f) * 0x800 + 0x6000000;548 buffer.Format("%d", mode);549 m_mode.SetWindowText(buffer);551 if (mode >= 3)552 {553 m_mapbase.SetWindowText("");554 m_charbase.SetWindowText("");555 }556 else557 {558 buffer.Format("0x%08X", screenBase);559 m_mapbase.SetWindowText(buffer);561 buffer.Format("0x%08X", charBase);562 m_charbase.SetWindowText(buffer);563 }565 buffer.Format("%dx%d", w, h);566 m_dim.SetWindowText(buffer);568 m_numcolors.SetWindowText(control & 0x80 ? "256" : "16");570 buffer.Format("%d", control & 3);571 m_priority.SetWindowText(buffer);573 m_mosaic.SetWindowText(control & 0x40 ? "1" : "0");575 m_overflow.SetWindowText(bg <= 1 ? "" :576 control & 0x2000 ? "1" : "0");577 }579 BOOL MapView::OnInitDialog()580 {581 CDialog::OnInitDialog();583 DIALOG_SIZER_START(sz)584 DIALOG_SIZER_ENTRY(IDC_MAP_VIEW, DS_SizeX | DS_SizeY)585 DIALOG_SIZER_ENTRY(IDC_REFRESH, DS_MoveY)586 DIALOG_SIZER_ENTRY(IDC_CLOSE, DS_MoveY)587 DIALOG_SIZER_ENTRY(IDC_SAVE, DS_MoveY)588 DIALOG_SIZER_ENTRY(IDC_COLOR, DS_MoveY)589 DIALOG_SIZER_ENTRY(IDC_R, DS_MoveY)590 DIALOG_SIZER_ENTRY(IDC_G, DS_MoveY)591 DIALOG_SIZER_ENTRY(IDC_B, DS_MoveY)592 DIALOG_SIZER_END()593 SetData(sz,594 TRUE,595 HKEY_CURRENT_USER,596 "Software\\Emulators\\VisualBoyAdvance\\Viewer\\MapView",597 NULL);599 SIZE size;600 size.cx = 1;601 size.cy = 1;602 mapView.SetScrollSizes(MM_TEXT, size);603 int s = regQueryDwordValue("mapViewStretch", 0);604 if (s)605 mapView.setStretch(true);606 ((CButton *)GetDlgItem(IDC_STRETCH))->SetCheck(s);607 paint();609 return TRUE; // return TRUE unless you set the focus to a control610 // EXCEPTION: OCX Property Pages should return FALSE611 }613 void MapView::PostNcDestroy()614 {615 delete this;616 }618 void MapView::enableButtons(int mode)619 {620 bool enable[6] = { true, true, true, true, true, true };622 switch (mode)623 {624 case 0:625 enable[4] = false;626 enable[5] = false;627 break;628 case 1:629 enable[3] = false;630 enable[4] = false;631 enable[5] = false;632 break;633 case 2:634 enable[0] = false;635 enable[1] = false;636 enable[4] = false;637 enable[5] = false;638 break;639 case 3:640 enable[0] = false;641 enable[1] = false;642 enable[2] = false;643 enable[3] = false;644 enable[4] = false;645 enable[5] = false;646 break;647 case 4:648 enable[0] = false;649 enable[1] = false;650 enable[2] = false;651 enable[3] = false;652 break;653 case 5:654 enable[0] = false;655 enable[1] = false;656 enable[2] = false;657 enable[3] = false;658 break;659 }660 GetDlgItem(IDC_BG0)->EnableWindow(enable[0]);661 GetDlgItem(IDC_BG1)->EnableWindow(enable[1]);662 GetDlgItem(IDC_BG2)->EnableWindow(enable[2]);663 GetDlgItem(IDC_BG3)->EnableWindow(enable[3]);664 GetDlgItem(IDC_FRAME_0)->EnableWindow(enable[4]);665 GetDlgItem(IDC_FRAME_1)->EnableWindow(enable[5]);666 int id = IDC_BG0;667 switch (bg)668 {669 case 1:670 id = IDC_BG1;671 break;672 case 2:673 id = IDC_BG2;674 break;675 case 3:676 id = IDC_BG3;677 break;678 }679 CheckRadioButton(IDC_BG0, IDC_BG3, id);680 id = IDC_FRAME_0;681 if (frame != 0)682 id = IDC_FRAME_1;683 CheckRadioButton(IDC_FRAME_0, IDC_FRAME_1, id);684 }686 void MapView::OnFrame0()687 {688 frame = 0;689 paint();690 }692 void MapView::OnFrame1()693 {694 frame = 1;695 paint();696 }698 void MapView::OnBg0()699 {700 bg = 0;701 control = BG0CNT;702 paint();703 }705 void MapView::OnBg1()706 {707 bg = 1;708 control = BG1CNT;709 paint();710 }712 void MapView::OnBg2()713 {714 bg = 2;715 control = BG2CNT;716 paint();717 }719 void MapView::OnBg3()720 {721 bg = 3;722 control = BG3CNT;723 paint();724 }726 void MapView::OnStretch()727 {728 mapView.setStretch(!mapView.getStretch());729 paint();730 regSetDwordValue("mapViewStretch", mapView.getStretch());731 }733 void MapView::OnAutoUpdate()734 {735 autoUpdate = !autoUpdate;736 if (autoUpdate)737 {738 theApp.winAddUpdateListener(this);739 }740 else741 {742 theApp.winRemoveUpdateListener(this);743 }744 }746 void MapView::update()747 {748 paint();749 }751 void MapView::OnClose()752 {753 theApp.winRemoveUpdateListener(this);755 DestroyWindow();756 }758 u32 MapView::GetTextClickAddress(u32 base, int x, int y)759 {760 if (y > 255 && h > 256)761 {762 base += 0x800;763 if (w > 256)764 base += 0x800;765 }766 if (x >= 256)767 base += 0x800;768 x &= 255;769 y &= 255;770 base += (x>>3)*2 + 64*(y>>3);772 return base;773 }775 u32 MapView::GetClickAddress(int x, int y)776 {777 int mode = DISPCNT & 7;779 u32 base = ((control >> 8) & 0x1f) * 0x800 + 0x6000000;781 // all text bgs (16 bits)782 if (mode == 0 || (mode < 3 && bg < 2))783 {784 return GetTextClickAddress(base, x, y);785 }786 // rot bgs (8 bits)787 if (mode < 3)788 {789 return base + (x>>3) + (w>>3)*(y>>3);790 }791 // mode 3/5 (16 bits)792 if (mode != 4)793 {794 return 0x6000000 + 0xa000*frame + 2*x + w*y*2;795 }796 // mode 4 (8 bits)797 return 0x6000000 + 0xa000*frame + x + w*y;798 }800 LRESULT MapView::OnMapInfo(WPARAM wParam, LPARAM lParam)801 {802 u8 *colors = (u8 *)lParam;803 mapViewZoom.setColors(colors);805 int x = wParam & 0xffff;806 int y = (wParam >> 16);808 CString buffer;809 buffer.Format("(%d,%d)", x, y);810 GetDlgItem(IDC_XY)->SetWindowText(buffer);812 u32 address = GetClickAddress(x, y);813 buffer.Format("0x%08X", address);814 GetDlgItem(IDC_ADDRESS)->SetWindowText(buffer);816 int mode = DISPCNT & 7;817 if (mode >= 3)818 {819 // bitmap modes820 GetDlgItem(IDC_TILE_NUM)->SetWindowText("---");821 GetDlgItem(IDC_FLIP)->SetWindowText("--");822 GetDlgItem(IDC_PALETTE_NUM)->SetWindowText("---");823 }824 else if (mode == 0 || bg < 2)825 {826 // text bgs827 u16 value = *((u16 *)&vram[address - 0x6000000]);829 int tile = value & 1023;830 buffer.Format("%d", tile);831 GetDlgItem(IDC_TILE_NUM)->SetWindowText(buffer);832 buffer.Empty();833 buffer += value & 1024 ? 'H' : '-';834 buffer += value & 2048 ? 'V' : '-';835 GetDlgItem(IDC_FLIP)->SetWindowText(buffer);837 if (!(control & 0x80))838 {839 buffer.Format("%d", (value >> 12) & 15);840 }841 else842 buffer = "---";843 GetDlgItem(IDC_PALETTE_NUM)->SetWindowText(buffer);844 }845 else846 {847 // rot bgs848 GetDlgItem(IDC_TILE_NUM)->SetWindowText("---");849 GetDlgItem(IDC_FLIP)->SetWindowText("--");850 GetDlgItem(IDC_PALETTE_NUM)->SetWindowText("---");851 }853 return TRUE;854 }856 LRESULT MapView::OnColInfo(WPARAM wParam, LPARAM lParam)857 {858 u16 c = (u16)wParam;860 color.setColor(c);862 int r = (c & 0x1f);863 int g = (c & 0x3e0) >> 5;864 int b = (c & 0x7c00) >> 10;866 CString buffer;867 buffer.Format("R: %d", r);868 GetDlgItem(IDC_R)->SetWindowText(buffer);870 buffer.Format("G: %d", g);871 GetDlgItem(IDC_G)->SetWindowText(buffer);873 buffer.Format("B: %d", b);874 GetDlgItem(IDC_B)->SetWindowText(buffer);876 return TRUE;877 }879 void MapView::saveBMP(const char *name)880 {881 u8 writeBuffer[1024 * 3];883 FILE *fp = fopen(name, "wb");885 if (!fp)886 {887 systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name);888 return;889 }891 struct892 {893 u8 ident[2];894 u8 filesize[4];895 u8 reserved[4];896 u8 dataoffset[4];897 u8 headersize[4];898 u8 width[4];899 u8 height[4];900 u8 planes[2];901 u8 bitsperpixel[2];902 u8 compression[4];903 u8 datasize[4];904 u8 hres[4];905 u8 vres[4];906 u8 colors[4];907 u8 importantcolors[4];908 u8 pad[2];909 } bmpheader;910 memset(&bmpheader, 0, sizeof(bmpheader));912 bmpheader.ident[0] = 'B';913 bmpheader.ident[1] = 'M';915 u32 fsz = sizeof(bmpheader) + w*h*3;916 utilPutDword(bmpheader.filesize, fsz);917 utilPutDword(bmpheader.dataoffset, 0x38);918 utilPutDword(bmpheader.headersize, 0x28);919 utilPutDword(bmpheader.width, w);920 utilPutDword(bmpheader.height, h);921 utilPutDword(bmpheader.planes, 1);922 utilPutDword(bmpheader.bitsperpixel, 24);923 utilPutDword(bmpheader.datasize, 3*w*h);925 fwrite(&bmpheader, 1, sizeof(bmpheader), fp);927 u8 *b = writeBuffer;929 int sizeX = w;930 int sizeY = h;932 u8 *pixU8 = (u8 *)data+3*w*(h-1);933 for (int y = 0; y < sizeY; y++)934 {935 for (int x = 0; x < sizeX; x++)936 {937 *b++ = *pixU8++; // B938 *b++ = *pixU8++; // G939 *b++ = *pixU8++; // R940 }941 pixU8 -= 2*3*w;942 fwrite(writeBuffer, 1, 3*w, fp);944 b = writeBuffer;945 }947 fclose(fp);948 }950 void MapView::savePNG(const char *name)951 {952 u8 writeBuffer[1024 * 3];954 FILE *fp = fopen(name, "wb");956 if (!fp)957 {958 systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name);959 return;960 }962 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,963 NULL,964 NULL,965 NULL);966 if (!png_ptr)967 {968 fclose(fp);969 return;970 }972 png_infop info_ptr = png_create_info_struct(png_ptr);974 if (!info_ptr)975 {976 png_destroy_write_struct(&png_ptr, NULL);977 fclose(fp);978 return;979 }981 if (setjmp(png_ptr->jmpbuf))982 {983 png_destroy_write_struct(&png_ptr, NULL);984 fclose(fp);985 return;986 }988 png_init_io(png_ptr, fp);990 png_set_IHDR(png_ptr,991 info_ptr,992 w,993 h,994 8,995 PNG_COLOR_TYPE_RGB,996 PNG_INTERLACE_NONE,997 PNG_COMPRESSION_TYPE_DEFAULT,998 PNG_FILTER_TYPE_DEFAULT);1000 png_write_info(png_ptr, info_ptr);1002 u8 *b = writeBuffer;1004 int sizeX = w;1005 int sizeY = h;1007 u8 *pixU8 = (u8 *)data;1008 for (int y = 0; y < sizeY; y++)1009 {1010 for (int x = 0; x < sizeX; x++)1011 {1012 int blue = *pixU8++;1013 int green = *pixU8++;1014 int red = *pixU8++;1016 *b++ = red;1017 *b++ = green;1018 *b++ = blue;1019 }1020 png_write_row(png_ptr, writeBuffer);1022 b = writeBuffer;1023 }1025 png_write_end(png_ptr, info_ptr);1027 png_destroy_write_struct(&png_ptr, &info_ptr);1029 fclose(fp);1030 }1032 void MapView::OnSave()1033 {1034 CString filename;1036 if (theApp.captureFormat == 0)1037 filename = "map.png";1038 else1039 filename = "map.bmp";1041 LPCTSTR exts[] = {".png", ".bmp", NULL };1043 CString filter = winResLoadFilter(IDS_FILTER_PNG);1044 CString title = winResLoadString(IDS_SELECT_CAPTURE_NAME);1046 FileDlg dlg(this,1047 filename,1048 filter,1049 theApp.captureFormat ? 2 : 1,1050 theApp.captureFormat ? "BMP" : "PNG",1051 exts,1052 "",1053 title,1054 true);1056 if (dlg.DoModal() == IDCANCEL)1057 {1058 return;1059 }1061 if (dlg.getFilterIndex() == 2)1062 saveBMP(dlg.GetPathName());1063 else1064 savePNG(dlg.GetPathName());1065 }