view src/win32/GBOamView.cpp @ 1:f9f4f1b99eed

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