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