Mercurial > vba-clojure
comparison src/win32/GBMapView.cpp @ 1:f9f4f1b99eed
importing src directory
author | Robert McIntyre <rlm@mit.edu> |
---|---|
date | Sat, 03 Mar 2012 10:31:27 -0600 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
0:8ced16adf2e1 | 1:f9f4f1b99eed |
---|---|
1 // GBMapView.cpp : implementation file | |
2 // | |
3 | |
4 #include "stdafx.h" | |
5 #include "resource.h" | |
6 #include "GBMapView.h" | |
7 #include "FileDlg.h" | |
8 #include "Reg.h" | |
9 #include "WinResUtil.h" | |
10 #include "VBA.h" | |
11 | |
12 //#include "../common/System.h" | |
13 #include "../gb/gbGlobals.h" | |
14 #include "../NLS.h" | |
15 #include "../common/Util.h" | |
16 | |
17 extern "C" { | |
18 #include <png.h> | |
19 } | |
20 | |
21 extern u8 gbInvertTab[256]; | |
22 | |
23 ///////////////////////////////////////////////////////////////////////////// | |
24 // GBMapView dialog | |
25 | |
26 GBMapView::GBMapView(CWnd*pParent /*=NULL*/) | |
27 : ResizeDlg(GBMapView::IDD, pParent) | |
28 { | |
29 //{{AFX_DATA_INIT(GBMapView) | |
30 // NOTE: the ClassWizard will add member initialization here | |
31 //}}AFX_DATA_INIT | |
32 autoUpdate = false; | |
33 | |
34 memset(&bmpInfo.bmiHeader, 0, sizeof(bmpInfo.bmiHeader)); | |
35 | |
36 bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader); | |
37 bmpInfo.bmiHeader.biWidth = 1024; | |
38 bmpInfo.bmiHeader.biHeight = -1024; | |
39 bmpInfo.bmiHeader.biPlanes = 1; | |
40 bmpInfo.bmiHeader.biBitCount = 24; | |
41 bmpInfo.bmiHeader.biCompression = BI_RGB; | |
42 data = (u8 *)calloc(1, 3 * 1024 * 1024); | |
43 | |
44 mapView.setData(data); | |
45 mapView.setBmpInfo(&bmpInfo); | |
46 | |
47 bg = 0; | |
48 bank = 0; | |
49 } | |
50 | |
51 void GBMapView::DoDataExchange(CDataExchange*pDX) | |
52 { | |
53 CDialog::DoDataExchange(pDX); | |
54 //{{AFX_DATA_MAP(GBMapView) | |
55 // NOTE: the ClassWizard will add DDX and DDV calls here | |
56 //}}AFX_DATA_MAP | |
57 DDX_Control(pDX, IDC_MAP_VIEW, mapView); | |
58 DDX_Control(pDX, IDC_MAP_VIEW_ZOOM, mapViewZoom); | |
59 DDX_Control(pDX, IDC_COLOR, color); | |
60 } | |
61 | |
62 BEGIN_MESSAGE_MAP(GBMapView, CDialog) | |
63 //{{AFX_MSG_MAP(GBMapView) | |
64 ON_BN_CLICKED(IDC_SAVE, OnSave) | |
65 ON_BN_CLICKED(IDC_REFRESH, OnRefresh) | |
66 ON_BN_CLICKED(IDC_BG0, OnBg0) | |
67 ON_BN_CLICKED(IDC_BG1, OnBg1) | |
68 ON_BN_CLICKED(IDC_BANK_0, OnBank0) | |
69 ON_BN_CLICKED(IDC_BANK_1, OnBank1) | |
70 ON_BN_CLICKED(IDC_STRETCH, OnStretch) | |
71 ON_BN_CLICKED(IDC_AUTO_UPDATE, OnAutoUpdate) | |
72 ON_BN_CLICKED(IDC_CLOSE, OnClose) | |
73 //}}AFX_MSG_MAP | |
74 ON_MESSAGE(WM_MAPINFO, OnMapInfo) | |
75 ON_MESSAGE(WM_COLINFO, OnColInfo) | |
76 END_MESSAGE_MAP() | |
77 | |
78 ///////////////////////////////////////////////////////////////////////////// | |
79 // GBMapView message handlers | |
80 | |
81 GBMapView::~GBMapView() | |
82 { | |
83 free(data); | |
84 data = NULL; | |
85 } | |
86 | |
87 void GBMapView::saveBMP(const char *name) | |
88 { | |
89 u8 writeBuffer[1024 * 3]; | |
90 | |
91 FILE *fp = fopen(name, "wb"); | |
92 | |
93 if (!fp) | |
94 { | |
95 systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name); | |
96 return; | |
97 } | |
98 | |
99 struct | |
100 { | |
101 u8 ident[2]; | |
102 u8 filesize[4]; | |
103 u8 reserved[4]; | |
104 u8 dataoffset[4]; | |
105 u8 headersize[4]; | |
106 u8 width[4]; | |
107 u8 height[4]; | |
108 u8 planes[2]; | |
109 u8 bitsperpixel[2]; | |
110 u8 compression[4]; | |
111 u8 datasize[4]; | |
112 u8 hres[4]; | |
113 u8 vres[4]; | |
114 u8 colors[4]; | |
115 u8 importantcolors[4]; | |
116 u8 pad[2]; | |
117 } bmpheader; | |
118 memset(&bmpheader, 0, sizeof(bmpheader)); | |
119 | |
120 bmpheader.ident[0] = 'B'; | |
121 bmpheader.ident[1] = 'M'; | |
122 | |
123 u32 fsz = sizeof(bmpheader) + w*h*3; | |
124 utilPutDword(bmpheader.filesize, fsz); | |
125 utilPutDword(bmpheader.dataoffset, 0x38); | |
126 utilPutDword(bmpheader.headersize, 0x28); | |
127 utilPutDword(bmpheader.width, w); | |
128 utilPutDword(bmpheader.height, h); | |
129 utilPutDword(bmpheader.planes, 1); | |
130 utilPutDword(bmpheader.bitsperpixel, 24); | |
131 utilPutDword(bmpheader.datasize, 3*w*h); | |
132 | |
133 fwrite(&bmpheader, 1, sizeof(bmpheader), fp); | |
134 | |
135 u8 *b = writeBuffer; | |
136 | |
137 int sizeX = w; | |
138 int sizeY = h; | |
139 | |
140 u8 *pixU8 = (u8 *)data+3*w*(h-1); | |
141 for (int y = 0; y < sizeY; y++) | |
142 { | |
143 for (int x = 0; x < sizeX; x++) | |
144 { | |
145 *b++ = *pixU8++; // B | |
146 *b++ = *pixU8++; // G | |
147 *b++ = *pixU8++; // R | |
148 } | |
149 pixU8 -= 2*3*w; | |
150 fwrite(writeBuffer, 1, 3*w, fp); | |
151 | |
152 b = writeBuffer; | |
153 } | |
154 | |
155 fclose(fp); | |
156 } | |
157 | |
158 void GBMapView::savePNG(const char *name) | |
159 { | |
160 u8 writeBuffer[1024 * 3]; | |
161 | |
162 FILE *fp = fopen(name, "wb"); | |
163 | |
164 if (!fp) | |
165 { | |
166 systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name); | |
167 return; | |
168 } | |
169 | |
170 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, | |
171 NULL, | |
172 NULL, | |
173 NULL); | |
174 if (!png_ptr) | |
175 { | |
176 fclose(fp); | |
177 return; | |
178 } | |
179 | |
180 png_infop info_ptr = png_create_info_struct(png_ptr); | |
181 | |
182 if (!info_ptr) | |
183 { | |
184 png_destroy_write_struct(&png_ptr, NULL); | |
185 fclose(fp); | |
186 return; | |
187 } | |
188 | |
189 if (setjmp(png_ptr->jmpbuf)) | |
190 { | |
191 png_destroy_write_struct(&png_ptr, NULL); | |
192 fclose(fp); | |
193 return; | |
194 } | |
195 | |
196 png_init_io(png_ptr, fp); | |
197 | |
198 png_set_IHDR(png_ptr, | |
199 info_ptr, | |
200 w, | |
201 h, | |
202 8, | |
203 PNG_COLOR_TYPE_RGB, | |
204 PNG_INTERLACE_NONE, | |
205 PNG_COMPRESSION_TYPE_DEFAULT, | |
206 PNG_FILTER_TYPE_DEFAULT); | |
207 | |
208 png_write_info(png_ptr, info_ptr); | |
209 | |
210 u8 *b = writeBuffer; | |
211 | |
212 int sizeX = w; | |
213 int sizeY = h; | |
214 | |
215 u8 *pixU8 = (u8 *)data; | |
216 for (int y = 0; y < sizeY; y++) | |
217 { | |
218 for (int x = 0; x < sizeX; x++) | |
219 { | |
220 int blue = *pixU8++; | |
221 int green = *pixU8++; | |
222 int red = *pixU8++; | |
223 | |
224 *b++ = red; | |
225 *b++ = green; | |
226 *b++ = blue; | |
227 } | |
228 png_write_row(png_ptr, writeBuffer); | |
229 | |
230 b = writeBuffer; | |
231 } | |
232 | |
233 png_write_end(png_ptr, info_ptr); | |
234 | |
235 png_destroy_write_struct(&png_ptr, &info_ptr); | |
236 | |
237 fclose(fp); | |
238 } | |
239 | |
240 void GBMapView::OnSave() | |
241 { | |
242 CString filename; | |
243 | |
244 if (theApp.captureFormat == 0) | |
245 filename = "map.png"; | |
246 else | |
247 filename = "map.bmp"; | |
248 | |
249 LPCTSTR exts[] = {".png", ".bmp", NULL }; | |
250 CString filter = winResLoadFilter(IDS_FILTER_PNG); | |
251 CString title = winResLoadString(IDS_SELECT_CAPTURE_NAME); | |
252 | |
253 FileDlg dlg(this, | |
254 filename, | |
255 filter, | |
256 theApp.captureFormat ? 2 : 1, | |
257 theApp.captureFormat ? "BMP" : "PNG", | |
258 exts, | |
259 "", | |
260 title, | |
261 true); | |
262 | |
263 if (dlg.DoModal() == IDCANCEL) | |
264 { | |
265 return; | |
266 } | |
267 | |
268 if (dlg.getFilterIndex() == 2) | |
269 saveBMP(dlg.GetPathName()); | |
270 else | |
271 savePNG(dlg.GetPathName()); | |
272 } | |
273 | |
274 void GBMapView::render() | |
275 { | |
276 u8 *bank0; | |
277 u8 *bank1; | |
278 if (gbCgbMode) | |
279 { | |
280 bank0 = &gbVram[0x0000]; | |
281 bank1 = &gbVram[0x2000]; | |
282 } | |
283 else | |
284 { | |
285 bank0 = &gbMemory[0x8000]; | |
286 bank1 = NULL; | |
287 } | |
288 | |
289 int tile_map_address = 0x1800; | |
290 if (bg == 1) | |
291 tile_map_address = 0x1c00; | |
292 | |
293 int tile_pattern = 0x0000; | |
294 if (bank == 1) | |
295 tile_pattern = 0x0800; | |
296 | |
297 w = 256; | |
298 h = 256; | |
299 | |
300 int tile = 0; | |
301 for (int y = 0; y < 32; y++) | |
302 { | |
303 for (int x = 0; x < 32; x++) | |
304 { | |
305 u8 *bmp = &data[y * 8 * 32 * 24 + x*24]; | |
306 u8 attrs = 0; | |
307 if (bank1 != NULL) | |
308 attrs = bank1[tile_map_address]; | |
309 u8 tile = bank0[tile_map_address]; | |
310 tile_map_address++; | |
311 | |
312 if (bank == 1) | |
313 { | |
314 if (tile < 128) | |
315 tile += 128; | |
316 else | |
317 tile -= 128; | |
318 } | |
319 for (int j = 0; j < 8; j++) | |
320 { | |
321 int tile_pattern_address = attrs & 0x40 ? | |
322 tile_pattern + tile*16 + (7-j)*2 : | |
323 tile_pattern + tile*16+j*2; | |
324 | |
325 u8 tile_a = 0; | |
326 u8 tile_b = 0; | |
327 | |
328 if (attrs & 0x08) | |
329 { | |
330 tile_a = bank1[tile_pattern_address++]; | |
331 tile_b = bank1[tile_pattern_address]; | |
332 } | |
333 else | |
334 { | |
335 tile_a = bank0[tile_pattern_address++]; | |
336 tile_b = bank0[tile_pattern_address]; | |
337 } | |
338 | |
339 if (attrs & 0x20) | |
340 { | |
341 tile_a = gbInvertTab[tile_a]; | |
342 tile_b = gbInvertTab[tile_b]; | |
343 } | |
344 | |
345 u8 mask = 0x80; | |
346 | |
347 while (mask > 0) | |
348 { | |
349 u8 c = (tile_a & mask) ? 1 : 0; | |
350 c += (tile_b & mask) ? 2 : 0; | |
351 | |
352 if (gbCgbMode) | |
353 c = c + (attrs & 7)*4; | |
354 | |
355 u16 color = gbPalette[c]; | |
356 | |
357 *bmp++ = ((color >> 10) & 0x1f) << 3; | |
358 *bmp++ = ((color >> 5) & 0x1f) << 3; | |
359 *bmp++ = (color & 0x1f) << 3; | |
360 | |
361 mask >>= 1; | |
362 } | |
363 bmp += 31*24; | |
364 } | |
365 } | |
366 } | |
367 } | |
368 | |
369 void GBMapView::paint() | |
370 { | |
371 if (gbRom == NULL) | |
372 return; | |
373 render(); | |
374 | |
375 SIZE s; | |
376 if (mapView.getStretch()) | |
377 { | |
378 mapView.setSize(w, h); | |
379 s.cx = s.cy = 1; | |
380 mapView.SetScrollSizes(MM_TEXT, s); | |
381 } | |
382 else | |
383 { | |
384 mapView.setSize(w, h); | |
385 s.cx = w; | |
386 s.cy = h; | |
387 mapView.SetScrollSizes(MM_TEXT, s); | |
388 } | |
389 | |
390 mapView.refresh(); | |
391 } | |
392 | |
393 void GBMapView::OnRefresh() | |
394 { | |
395 paint(); | |
396 } | |
397 | |
398 void GBMapView::update() | |
399 { | |
400 paint(); | |
401 } | |
402 | |
403 BOOL GBMapView::OnInitDialog() | |
404 { | |
405 CDialog::OnInitDialog(); | |
406 | |
407 DIALOG_SIZER_START(sz) | |
408 DIALOG_SIZER_ENTRY(IDC_MAP_VIEW, DS_SizeX | DS_SizeY) | |
409 DIALOG_SIZER_ENTRY(IDC_REFRESH, DS_MoveY) | |
410 DIALOG_SIZER_ENTRY(IDC_CLOSE, DS_MoveY) | |
411 DIALOG_SIZER_ENTRY(IDC_SAVE, DS_MoveY) | |
412 DIALOG_SIZER_ENTRY(IDC_COLOR, DS_MoveY) | |
413 DIALOG_SIZER_ENTRY(IDC_R, DS_MoveY) | |
414 DIALOG_SIZER_ENTRY(IDC_G, DS_MoveY) | |
415 DIALOG_SIZER_ENTRY(IDC_B, DS_MoveY) | |
416 DIALOG_SIZER_END() | |
417 SetData(sz, | |
418 TRUE, | |
419 HKEY_CURRENT_USER, | |
420 "Software\\Emulators\\VisualBoyAdvance\\Viewer\\GBMapView", | |
421 NULL); | |
422 | |
423 int s = regQueryDwordValue("mapViewStretch", 0); | |
424 if (s) | |
425 mapView.setStretch(true); | |
426 ((CButton *)GetDlgItem(IDC_STRETCH))->SetCheck(s); | |
427 | |
428 UINT id = IDC_BANK_0; | |
429 if (bank == 1) | |
430 id = IDC_BANK_1; | |
431 CheckRadioButton(IDC_BANK_0, IDC_BANK_1, id); | |
432 id = IDC_BG0; | |
433 if (bg == 1) | |
434 id = IDC_BG1; | |
435 CheckRadioButton(IDC_BG0, IDC_BG1, id); | |
436 paint(); | |
437 | |
438 return TRUE; // return TRUE unless you set the focus to a control | |
439 // EXCEPTION: OCX Property Pages should return FALSE | |
440 } | |
441 | |
442 void GBMapView::OnBg0() | |
443 { | |
444 bg = 0; | |
445 paint(); | |
446 } | |
447 | |
448 void GBMapView::OnBg1() | |
449 { | |
450 bg = 1; | |
451 paint(); | |
452 } | |
453 | |
454 void GBMapView::OnBank0() | |
455 { | |
456 bank = 0; | |
457 paint(); | |
458 } | |
459 | |
460 void GBMapView::OnBank1() | |
461 { | |
462 bank = 1; | |
463 paint(); | |
464 } | |
465 | |
466 void GBMapView::OnStretch() | |
467 { | |
468 mapView.setStretch(!mapView.getStretch()); | |
469 paint(); | |
470 regSetDwordValue("mapViewStretch", mapView.getStretch()); | |
471 } | |
472 | |
473 void GBMapView::OnAutoUpdate() | |
474 { | |
475 autoUpdate = !autoUpdate; | |
476 if (autoUpdate) | |
477 { | |
478 theApp.winAddUpdateListener(this); | |
479 } | |
480 else | |
481 { | |
482 theApp.winRemoveUpdateListener(this); | |
483 } | |
484 } | |
485 | |
486 void GBMapView::OnClose() | |
487 { | |
488 theApp.winRemoveUpdateListener(this); | |
489 | |
490 DestroyWindow(); | |
491 } | |
492 | |
493 u32 GBMapView::GetClickAddress(int x, int y) | |
494 { | |
495 u32 base = 0x9800; | |
496 if (bg == 1) | |
497 base = 0x9c00; | |
498 | |
499 return base + (y >> 3)*32 + (x >> 3); | |
500 } | |
501 | |
502 LRESULT GBMapView::OnMapInfo(WPARAM wParam, LPARAM lParam) | |
503 { | |
504 u8 *colors = (u8 *)lParam; | |
505 mapViewZoom.setColors(colors); | |
506 | |
507 int x = wParam & 0xffff; | |
508 int y = (wParam >> 16); | |
509 | |
510 CString buffer; | |
511 buffer.Format("(%d,%d)", x, y); | |
512 GetDlgItem(IDC_XY)->SetWindowText(buffer); | |
513 | |
514 u32 address = GetClickAddress(x, y); | |
515 buffer.Format("0x%08X", address); | |
516 GetDlgItem(IDC_ADDRESS)->SetWindowText(buffer); | |
517 | |
518 u8 attrs = 0; | |
519 | |
520 u8 tile = gbReadMemoryQuick(0x9000 | (address & 0xfff)); | |
521 if (gbCgbMode) | |
522 { | |
523 attrs = gbVram[0x2000 + address - 0x8000]; | |
524 tile = gbVram[address & 0x1fff]; | |
525 } | |
526 | |
527 if (bank == 1) | |
528 { | |
529 if (tile > 128) | |
530 tile -= 128; | |
531 else | |
532 tile += 128; | |
533 } | |
534 | |
535 buffer.Format("%d", tile); | |
536 GetDlgItem(IDC_TILE_NUM)->SetWindowText(buffer); | |
537 | |
538 buffer.Empty(); | |
539 buffer += attrs & 0x20 ? 'H' : '-'; | |
540 buffer += attrs & 0x40 ? 'V' : '-'; | |
541 GetDlgItem(IDC_FLIP)->SetWindowText(buffer); | |
542 | |
543 if (gbCgbMode) | |
544 { | |
545 buffer.Format("%d", (attrs & 7)); | |
546 } | |
547 else | |
548 buffer = "---"; | |
549 GetDlgItem(IDC_PALETTE_NUM)->SetWindowText(buffer); | |
550 | |
551 buffer.Empty(); | |
552 if (gbCgbMode) | |
553 buffer += attrs & 0x80 ? 'P' : '-'; | |
554 else | |
555 buffer += '-'; | |
556 GetDlgItem(IDC_PRIORITY)->SetWindowText(buffer); | |
557 | |
558 return TRUE; | |
559 } | |
560 | |
561 LRESULT GBMapView::OnColInfo(WPARAM wParam, LPARAM) | |
562 { | |
563 u16 c = (u16)wParam; | |
564 | |
565 color.setColor(c); | |
566 | |
567 int r = (c & 0x1f); | |
568 int g = (c & 0x3e0) >> 5; | |
569 int b = (c & 0x7c00) >> 10; | |
570 | |
571 CString buffer; | |
572 buffer.Format("R: %d", r); | |
573 GetDlgItem(IDC_R)->SetWindowText(buffer); | |
574 | |
575 buffer.Format("G: %d", g); | |
576 GetDlgItem(IDC_G)->SetWindowText(buffer); | |
577 | |
578 buffer.Format("B: %d", b); | |
579 GetDlgItem(IDC_B)->SetWindowText(buffer); | |
580 | |
581 return TRUE; | |
582 } | |
583 | |
584 void GBMapView::PostNcDestroy() | |
585 { | |
586 delete this; | |
587 CDialog::PostNcDestroy(); | |
588 } | |
589 |