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