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