1
2 // these are all the viewer dialogs with graphical panel areas
3 // they can be instantiated multiple times
4
5 #include "wxvbam.h"
6 #include "viewsupt.h"
7 #include <wx/colordlg.h>
8 #include <wx/ffile.h>
9
10 // FIXME: many of these read e.g. palette data directly without regard to
11 // byte order. Need to determine where things are stored in emulated machine
12 // order and where in native order, and swap the latter on big-endian
13
14 // most of these have label fields that need to be sized and later filled
15 // mv is a string to initialize with for sizing
16 #define getlab(v, n, mv) do { \
17 v = XRCCTRL(*this, n, wxControl); \
18 if(!v) \
19 baddialog(); \
20 v->SetLabel(wxT(mv)); \
21 } while(0)
22
23 // FIXME: this should be in a header
24 extern u8 gbInvertTab[256];
25
26 // avoid exporting classes
27 namespace Viewers
28 {
29 class MapViewer : public GfxViewer
30 {
31 public:
MapViewer()32 MapViewer() : GfxViewer(wxT("MapViewer"), 1024, 1024)
33 {
34 frame = bg = 0;
35 getradio(fr0 = , "Frame0", frame, 0);
36 getradio(fr1 = , "Frame1", frame, 0xa000);
37 getradio(bg0 = , "BG0", bg, 0);
38 getradio(bg1 = , "BG1", bg, 1);
39 getradio(bg2 = , "BG2", bg, 2);
40 getradio(bg3 = , "BG3", bg, 3);
41 getlab(modelab, "Mode", "8");
42 getlab(mapbase, "MapBase", "0xWWWWWWWW");
43 getlab(charbase, "CharBase", "0xWWWWWWWW");
44 getlab(size, "Size", "1024x1024");
45 getlab(colors, "Colors", "2WW");
46 getlab(prio, "Priority", "3");
47 getlab(mosaic, "Mosaic", "0");
48 getlab(overflow, "Overflow", "0");
49 getlab(coords, "Coords", "(1023,1023)");
50 getlab(addr, "Address", "0xWWWWWWWW");
51 getlab(tile, "Tile", "1023");
52 getlab(flip, "Flip", "HV");
53 getlab(palette, "Palette", "---");
54 Fit();
55 selx = sely = -1;
56 Update();
57 }
Update()58 void Update()
59 {
60 mode = DISPCNT & 7;
61
62 switch (bg)
63 {
64 case 0:
65 control = BG0CNT;
66 break;
67
68 case 1:
69 control = BG1CNT;
70 break;
71
72 case 2:
73 control = BG2CNT;
74 break;
75
76 case 3:
77 control = BG3CNT;
78 break;
79 }
80
81 bool fr0en = true, fr1en = true, bg0en = true, bg1en = true,
82 bg2en = true, bg3en = true;
83
84 switch (mode)
85 {
86 case 0:
87 fr0en = fr1en = false;
88 renderTextScreen();
89 break;
90
91 case 1:
92 fr0en = fr1en = false;
93 bg3en = false;
94
95 if (bg == 3)
96 {
97 bg = 0;
98 control = BG0CNT;
99 bg0->SetValue(true);
100 }
101
102 if (bg < 2)
103 renderTextScreen();
104 else
105 renderRotScreen();
106
107 break;
108
109 case 2:
110 fr0en = fr1en = false;
111 bg0en = bg1en = false;
112
113 if (bg < 2)
114 {
115 bg = 2;
116 control = BG2CNT;
117 bg2->SetValue(true);
118 }
119
120 renderRotScreen();
121 break;
122
123 case 3:
124 fr0en = fr1en = false;
125 bg0en = bg1en = bg2en = bg3en = false;
126 bg = 2;
127 bg2->SetValue(true);
128 renderMode3();
129 break;
130
131 case 4:
132 bg0en = bg1en = bg2en = bg3en = false;
133 bg = 2;
134 bg2->SetValue(true);
135 renderMode4();
136 break;
137
138 case 5:
139 case 6:
140 case 7:
141 bg = 2;
142 bg2->SetValue(true);
143 renderMode5();
144 break;
145 }
146
147 ChangeBMP();
148 fr0->Enable(fr0en);
149 fr1->Enable(fr1en);
150 bg0->Enable(bg0en);
151 bg1->Enable(bg1en);
152 bg2->Enable(bg2en);
153 bg3->Enable(bg3en);
154 wxString s;
155 s.Printf(wxT("%d"), (int)mode);
156 modelab->SetLabel(s);
157
158 if (mode >= 3)
159 {
160 mapbase->SetLabel(wxEmptyString);
161 charbase->SetLabel(wxEmptyString);
162 }
163 else
164 {
165 s.Printf(wxT("0x%08X"), ((control >> 8) & 0x1f) * 0x800 + 0x6000000);
166 mapbase->SetLabel(s);
167 s.Printf(wxT("0x%08X"), ((control >> 2) & 0x03) * 0x4000 + 0x6000000);
168 charbase->SetLabel(s);
169 }
170
171 s.Printf(wxT("%dx%d"), gv->bmw, gv->bmh);
172 size->SetLabel(s);
173 colors->SetLabel(control & 0x80 ? wxT("256") : wxT("16"));
174 s.Printf(wxT("%d"), control & 3);
175 prio->SetLabel(s);
176 mosaic->SetLabel(control & 0x40 ? wxT("1") : wxT("0"));
177 overflow->SetLabel(bg <= 1 ? wxEmptyString :
178 control & 0x2000 ? wxT("1") : wxT("0"));
179 UpdateMouseInfo();
180 }
181
UpdateMouseInfoEv(wxMouseEvent & ev)182 void UpdateMouseInfoEv(wxMouseEvent &ev)
183 {
184 selx = ev.GetX();
185 sely = ev.GetY();
186 UpdateMouseInfo(); // note that this will be inaccurate if game
187 // not paused since last refresh
188 }
189
AddressFromSel()190 u32 AddressFromSel()
191 {
192 u32 base = ((control >> 8) & 0x1f) * 0x800 + 0x6000000;
193
194 // all text bgs (16 bits)
195 if (mode == 0 || (mode < 3 && bg < 2) || mode == 6 || mode == 7)
196 {
197 if (sely > 255)
198 {
199 base += 0x800;
200
201 if (gv->bmw > 256)
202 base += 0x800;
203 }
204
205 if (selx >= 256)
206 base += 0x800;
207
208 return base + ((selx & 0xff) >> 3) * 2 + 64 * ((sely & 0xff) >> 3);
209 }
210
211 // rot bgs (8 bits)
212 if (mode < 3)
213 return base + (selx >> 3) + (gv->bmw >> 3) * (sely >> 3);
214
215 // mode 3/5 (16 bits)
216 if (mode != 4)
217 return 0x6000000 + 0xa000 * frame + (selx + gv->bmw * sely) * 2;
218
219 // mode 4 (8 bits)
220 return 0x6000000 + 0xa000 * frame + selx + gv->bmw * sely;
221 }
222
UpdateMouseInfo()223 void UpdateMouseInfo()
224 {
225 if (selx > gv->bmw || sely > gv->bmh)
226 selx = sely = -1;
227
228 if (selx < 0)
229 {
230 coords->SetLabel(wxEmptyString);
231 addr->SetLabel(wxEmptyString);
232 tile->SetLabel(wxEmptyString);
233 flip->SetLabel(wxEmptyString);
234 palette->SetLabel(wxEmptyString);
235 }
236 else
237 {
238 wxString s;
239 s.Printf(wxT("(%d,%d)"), selx, sely);
240 coords->SetLabel(s);
241 u32 address = AddressFromSel();
242 s.Printf(wxT("0x%08X"), address);
243 addr->SetLabel(s);
244
245 if (!mode || (mode < 3 || mode > 5) && bg < 2)
246 {
247 u16 value = *((u16*)&vram[address - 0x6000000]);
248 s.Printf(wxT("%d"), value & 1023);
249 tile->SetLabel(s);
250 s = value & 1024 ? wxT('H') : wxT('-');
251 s += value & 2048 ? wxT('V') : wxT('-');
252 flip->SetLabel(s);
253
254 if (control & 0x80)
255 palette->SetLabel(wxT("---"));
256 else
257 {
258 s.Printf(wxT("%d"), (value >> 12) & 15);
259 palette->SetLabel(s);
260 }
261 }
262 else
263 {
264 tile->SetLabel(wxT("---"));
265 flip->SetLabel(wxT("--"));
266 palette->SetLabel(wxT("---"));
267 }
268 }
269 }
270 protected:
271 u16 control, mode;
272 int frame, bg;
273 wxRadioButton* fr0, *fr1, *bg0, *bg1, *bg2, *bg3;
274 wxControl* modelab, *mapbase, *charbase, *size, *colors, *prio, *mosaic,
275 *overflow;
276 wxControl* coords, *addr, *tile, *flip, *palette;
277 int selx, sely;
278
279 // following routines were copied from win32/MapView.cpp with little
280 // attempt to read & validate, except:
281 // stride = 1024, rgb instead of bgr
282 // FIXME: probably needs changing for big-endian
283
renderTextScreen()284 void renderTextScreen()
285 {
286 u16* palette = (u16*)paletteRAM;
287 u8* charBase = &vram[((control >> 2) & 0x03) * 0x4000];
288 u16* screenBase = (u16*)&vram[((control >> 8) & 0x1f) * 0x800];
289 u8* bmp = image.GetData();
290 int sizeX = 256;
291 int sizeY = 256;
292
293 switch ((control >> 14) & 3)
294 {
295 case 0:
296 break;
297
298 case 1:
299 sizeX = 512;
300 break;
301
302 case 2:
303 sizeY = 512;
304 break;
305
306 case 3:
307 sizeX = 512;
308 sizeY = 512;
309 break;
310 }
311
312 BMPSize(sizeX, sizeY);
313
314 if (control & 0x80)
315 {
316 for (int y = 0; y < sizeY; y++)
317 {
318 int yy = y & 255;
319
320 if (y == 256 && sizeY > 256)
321 {
322 screenBase += 0x400;
323
324 if (sizeX > 256)
325 screenBase += 0x400;
326 }
327
328 u16* screenSource = screenBase + ((yy >> 3) * 32);
329
330 for (int x = 0; x < sizeX; x++)
331 {
332 u16 data = *screenSource;
333 int tile = data & 0x3FF;
334 int tileX = (x & 7);
335 int tileY = y & 7;
336
337 if (data & 0x0400)
338 tileX = 7 - tileX;
339
340 if (data & 0x0800)
341 tileY = 7 - tileY;
342
343 u8 c = charBase[tile * 64 + tileY * 8 + tileX];
344 u16 color = palette[c];
345 *bmp++ = (color & 0x1f) << 3;
346 *bmp++ = ((color >> 5) & 0x1f) << 3;
347 *bmp++ = ((color >> 10) & 0x1f) << 3;
348
349 if (data & 0x0400)
350 {
351 if (tileX == 0)
352 screenSource++;
353 }
354 else if (tileX == 7)
355 screenSource++;
356
357 if (x == 255 && sizeX > 256)
358 {
359 screenSource = screenBase + 0x400 + ((yy >> 3) * 32);
360 }
361 }
362
363 bmp += 3 * (1024 - sizeX);
364 }
365 }
366 else
367 {
368 for (int y = 0; y < sizeY; y++)
369 {
370 int yy = y & 255;
371
372 if (y == 256 && sizeY > 256)
373 {
374 screenBase += 0x400;
375
376 if (sizeX > 256)
377 screenBase += 0x400;
378 }
379
380 u16* screenSource = screenBase + ((yy >> 3) * 32);
381
382 for (int x = 0; x < sizeX; x++)
383 {
384 u16 data = *screenSource;
385 int tile = data & 0x3FF;
386 int tileX = (x & 7);
387 int tileY = y & 7;
388
389 if (data & 0x0400)
390 tileX = 7 - tileX;
391
392 if (data & 0x0800)
393 tileY = 7 - tileY;
394
395 u8 color = charBase[tile * 32 + tileY * 4 + (tileX >> 1)];
396
397 if (tileX & 1)
398 {
399 color = (color >> 4);
400 }
401 else
402 {
403 color &= 0x0F;
404 }
405
406 int pal = (*screenSource >> 8) & 0xF0;
407 u16 color2 = palette[pal + color];
408 *bmp++ = (color2 & 0x1f) << 3;
409 *bmp++ = ((color2 >> 5) & 0x1f) << 3;
410 *bmp++ = ((color2 >> 10) & 0x1f) << 3;
411
412 if (data & 0x0400)
413 {
414 if (tileX == 0)
415 screenSource++;
416 }
417 else if (tileX == 7)
418 screenSource++;
419
420 if (x == 255 && sizeX > 256)
421 {
422 screenSource = screenBase + 0x400 + ((yy >> 3) * 32);
423 }
424 }
425
426 bmp += 3 * (1024 - sizeX);
427 }
428 }
429
430 #if 0
431
432 switch (bg)
433 {
434 case 0:
435 renderView(BG0HOFS << 8, BG0VOFS << 8,
436 0x100, 0x000,
437 0x000, 0x100,
438 (sizeX - 1) << 8,
439 (sizeY - 1) << 8,
440 true);
441 break;
442
443 case 1:
444 renderView(BG1HOFS << 8, BG1VOFS << 8,
445 0x100, 0x000,
446 0x000, 0x100,
447 (sizeX - 1) << 8,
448 (sizeY - 1) << 8,
449 true);
450 break;
451
452 case 2:
453 renderView(BG2HOFS << 8, BG2VOFS << 8,
454 0x100, 0x000,
455 0x000, 0x100,
456 (sizeX - 1) << 8,
457 (sizeY - 1) << 8,
458 true);
459 break;
460
461 case 3:
462 renderView(BG3HOFS << 8, BG3VOFS << 8,
463 0x100, 0x000,
464 0x000, 0x100,
465 (sizeX - 1) << 8,
466 (sizeY - 1) << 8,
467 true);
468 break;
469 }
470
471 #endif
472 }
473
renderRotScreen()474 void renderRotScreen()
475 {
476 u16* palette = (u16*)paletteRAM;
477 u8* charBase = &vram[((control >> 2) & 0x03) * 0x4000];
478 u8* screenBase = (u8*)&vram[((control >> 8) & 0x1f) * 0x800];
479 u8* bmp = image.GetData();
480 int sizeX = 128;
481 int sizeY = 128;
482
483 switch ((control >> 14) & 3)
484 {
485 case 0:
486 break;
487
488 case 1:
489 sizeX = sizeY = 256;
490 break;
491
492 case 2:
493 sizeX = sizeY = 512;
494 break;
495
496 case 3:
497 sizeX = sizeY = 1024;
498 break;
499 }
500
501 BMPSize(sizeX, sizeY);
502
503 if (control & 0x80)
504 {
505 for (int y = 0; y < sizeY; y++)
506 {
507 for (int x = 0; x < sizeX; x++)
508 {
509 int tile = screenBase[(x >> 3) + (y >> 3) * (sizeX >> 3)];
510 int tileX = (x & 7);
511 int tileY = y & 7;
512 u8 color = charBase[tile * 64 + tileY * 8 + tileX];
513 u16 color2 = palette[color];
514 *bmp++ = (color2 & 0x1f) << 3;
515 *bmp++ = ((color2 >> 5) & 0x1f) << 3;
516 *bmp++ = ((color2 >> 10) & 0x1f) << 3;
517 }
518 }
519
520 bmp += 3 * (1024 - sizeX);
521 }
522 else
523 {
524 for (int y = 0; y < sizeY; y++)
525 {
526 for (int x = 0; x < sizeX; x++)
527 {
528 int tile = screenBase[(x >> 3) + (y >> 3) * (sizeX >> 3)];
529 int tileX = (x & 7);
530 int tileY = y & 7;
531 u8 color = charBase[tile * 64 + tileY * 8 + tileX];
532 u16 color2 = palette[color];
533 *bmp++ = (color2 & 0x1f) << 3;
534 *bmp++ = ((color2 >> 5) & 0x1f) << 3;
535 *bmp++ = ((color2 >> 10) & 0x1f) << 3;
536 }
537 }
538
539 bmp += 3 * (1024 - sizeX);
540 }
541
542 u32 xx;
543 u32 yy;
544
545 switch (bg)
546 {
547 case 2:
548 xx = BG2X_L | BG2X_H << 16;
549 yy = BG2Y_L | BG2Y_H << 16;
550 #if 0
551 renderView(xx, yy,
552 BG2PA, BG2PC,
553 BG2PB, BG2PD,
554 (sizeX - 1) << 8,
555 (sizeY - 1) << 8,
556 (control & 0x2000) != 0);
557 #endif
558 break;
559
560 case 3:
561 xx = BG3X_L | BG3X_H << 16;
562 yy = BG3Y_L | BG3Y_H << 16;
563 #if 0
564 renderView(xx, yy,
565 BG3PA, BG3PC,
566 BG3PB, BG3PD,
567 (sizeX - 1) << 8,
568 (sizeY - 1) << 8,
569 (control & 0x2000) != 0);
570 #endif
571 break;
572 }
573 }
574
renderMode3()575 void renderMode3()
576 {
577 u8* bmp = image.GetData();
578 u16* src = (u16*)&vram[0];
579 BMPSize(240, 160);
580
581 for (int y = 0; y < 160; y++)
582 {
583 for (int x = 0; x < 240; x++)
584 {
585 u16 data = *src++;
586 *bmp++ = (data & 0x1f) << 3;
587 *bmp++ = ((data >> 5) & 0x1f) << 3;
588 *bmp++ = ((data >> 10) & 0x1f) << 3;
589 }
590
591 bmp += 3 * (1024 - 240);
592 }
593 }
594
595
renderMode4()596 void renderMode4()
597 {
598 u8* bmp = image.GetData();
599 u8* src = frame ? &vram[0xa000] : &vram[0];
600 u16* pal = (u16*)&paletteRAM[0];
601 BMPSize(240, 160);
602
603 for (int y = 0; y < 160; y++)
604 {
605 for (int x = 0; x < 240; x++)
606 {
607 u8 c = *src++;
608 u16 data = pal[c];
609 *bmp++ = (data & 0x1f) << 3;
610 *bmp++ = ((data >> 5) & 0x1f) << 3;
611 *bmp++ = ((data >> 10) & 0x1f) << 3;
612 }
613
614 bmp += 3 * (1024 - 240);
615 }
616 }
617
618
renderMode5()619 void renderMode5()
620 {
621 u8* bmp = image.GetData();
622 u16* src = (u16*)(frame ? &vram[0xa000] : &vram[0]);
623 BMPSize(160, 128);
624
625 for (int y = 0; y < 128; y++)
626 {
627 for (int x = 0; x < 160; x++)
628 {
629 u16 data = *src++;
630 *bmp++ = (data & 0x1f) << 3;
631 *bmp++ = ((data >> 5) & 0x1f) << 3;
632 *bmp++ = ((data >> 10) & 0x1f) << 3;
633 }
634
635 bmp += 3 * (1024 - 160);
636 }
637 }
638
639 DECLARE_EVENT_TABLE()
640 };
641
642 BEGIN_EVENT_TABLE(MapViewer, GfxViewer)
643 EVT_GFX_CLICK(wxID_ANY, MapViewer::UpdateMouseInfoEv)
644 END_EVENT_TABLE()
645
646 class GBMapViewer : public GfxViewer
647 {
648 public:
GBMapViewer()649 GBMapViewer() : GfxViewer(wxT("GBMapViewer"), 256, 256)
650 {
651 getradio(, "CharBase0", charbase, 0x0000);
652 getradio(, "CharBase1", charbase, 0x0800);
653 getradio(, "MapBase0", mapbase, 0x1800);
654 getradio(, "MapBase1", mapbase, 0x1c00);
655 getlab(coords, "Coords", "(2WW,2WW)");
656 getlab(addr, "Address", "0xWWWW");
657 getlab(tile, "Tile", "2WW");
658 getlab(flip, "Flip", "HV");
659 getlab(palette, "Palette", "---");
660 getlab(prio, "Priority", "P");
661 Fit();
662 selx = sely = -1;
663 Update();
664 }
Update()665 void Update()
666 {
667 u8* bank0, *bank1;
668
669 if (gbCgbMode)
670 {
671 bank0 = &gbVram[0x0000];
672 bank1 = &gbVram[0x2000];
673 }
674 else
675 {
676 bank0 = &gbMemory[0x8000];
677 bank1 = NULL;
678 }
679
680 int tile_map_address = mapbase;
681 // following copied almost verbatim from win32/GBMapView.cpp
682 int tile = 0;
683
684 for (int y = 0; y < 32; y++)
685 {
686 for (int x = 0; x < 32; x++)
687 {
688 u8* bmp = &image.GetData()[y * 8 * 32 * 24 + x * 24];
689 u8 attrs = 0;
690
691 if (bank1 != NULL)
692 attrs = bank1[tile_map_address];
693
694 u8 tile = bank0[tile_map_address];
695 tile_map_address++;
696
697 if (charbase)
698 {
699 if (tile < 128) tile += 128;
700 else tile -= 128;
701 }
702
703 for (int j = 0; j < 8; j++)
704 {
705 int charbase_address = attrs & 0x40 ?
706 charbase + tile * 16 + (7 - j) * 2 :
707 charbase + tile * 16 + j * 2;
708 u8 tile_a = 0;
709 u8 tile_b = 0;
710
711 if (attrs & 0x08)
712 {
713 tile_a = bank1[charbase_address++];
714 tile_b = bank1[charbase_address];
715 }
716 else
717 {
718 tile_a = bank0[charbase_address++];
719 tile_b = bank0[charbase_address];
720 }
721
722 if (attrs & 0x20)
723 {
724 tile_a = gbInvertTab[tile_a];
725 tile_b = gbInvertTab[tile_b];
726 }
727
728 u8 mask = 0x80;
729
730 while (mask > 0)
731 {
732 u8 c = (tile_a & mask) ? 1 : 0;
733 c += (tile_b & mask) ? 2 : 0;
734
735 if (gbCgbMode)
736 c = c + (attrs & 7) * 4;
737
738 u16 color = gbPalette[c];
739 *bmp++ = (color & 0x1f) << 3;
740 *bmp++ = ((color >> 5) & 0x1f) << 3;
741 *bmp++ = ((color >> 10) & 0x1f) << 3;
742 mask >>= 1;
743 }
744
745 bmp += 31 * 24;
746 }
747 }
748 }
749
750 ChangeBMP();
751 UpdateMouseInfo();
752 }
753
UpdateMouseInfoEv(wxMouseEvent & ev)754 void UpdateMouseInfoEv(wxMouseEvent &ev)
755 {
756 selx = ev.GetX();
757 sely = ev.GetY();
758 UpdateMouseInfo(); // note that this will be inaccurate if game
759 // not paused since last refresh
760 }
761
UpdateMouseInfo()762 void UpdateMouseInfo()
763 {
764 if (selx > gv->bmw || sely > gv->bmh)
765 selx = sely = -1;
766
767 if (selx < 0)
768 {
769 coords->SetLabel(wxEmptyString);
770 addr->SetLabel(wxEmptyString);
771 tile->SetLabel(wxEmptyString);
772 flip->SetLabel(wxEmptyString);
773 palette->SetLabel(wxEmptyString);
774 prio->SetLabel(wxEmptyString);
775 }
776 else
777 {
778 wxString s;
779 s.Printf(wxT("(%d,%d)"), selx, sely);
780 coords->SetLabel(s);
781 u16 address = mapbase + 0x8000 + (sely >> 3) * 32 + (selx >> 3);
782 s.Printf(wxT("0x%04X"), address);
783 addr->SetLabel(s);
784 u8 attrs = 0;
785 u8 tilev = gbMemoryMap[9][address & 0xfff];
786
787 if (gbCgbMode)
788 {
789 attrs = gbVram[0x2000 + address - 0x8000];
790 tilev = gbVram[address & 0x1fff];
791 }
792
793 if (charbase)
794 {
795 if (tilev >= 128)
796 tilev -= 128;
797 else
798 tilev += 128;
799 }
800
801 s.Printf(wxT("%d"), (int)tilev);
802 tile->SetLabel(s);
803 s = attrs & 0x20 ? wxT('H') : wxT('-');
804 s += attrs & 0x40 ? wxT('V') : wxT('-');
805 flip->SetLabel(s);
806
807 if (gbCgbMode)
808 {
809 s.Printf(wxT("%d"), attrs & 7);
810 palette->SetLabel(s);
811 }
812 else
813 palette->SetLabel(wxT("---"));
814
815 prio->SetLabel(wxString(attrs & 0x80 ? wxT('P') : wxT('-')));
816 }
817 }
818 protected:
819 int charbase, mapbase;
820 wxControl* coords, *addr, *tile, *flip, *palette, *prio;
821 int selx, sely;
822
823 DECLARE_EVENT_TABLE()
824 };
825
826 BEGIN_EVENT_TABLE(GBMapViewer, GfxViewer)
827 EVT_GFX_CLICK(wxID_ANY, GBMapViewer::UpdateMouseInfoEv)
828 END_EVENT_TABLE()
829 }
830
MapViewer()831 void MainFrame::MapViewer()
832 {
833 switch (panel->game_type())
834 {
835 case IMAGE_GBA:
836 LoadXRCViewer(Map);
837 break;
838
839 case IMAGE_GB:
840 LoadXRCViewer(GBMap);
841 break;
842 }
843 }
844
845 namespace Viewers
846 {
847 class OAMViewer : public GfxViewer
848 {
849 public:
OAMViewer()850 OAMViewer() : GfxViewer(wxT("OAMViewer"), 544, 496)
851 {
852 sprite = 0;
853 getspin(, "Sprite", sprite);
854 getlab(pos, "Pos", "5WW,2WW");
855 getlab(mode, "Mode", "3");
856 getlab(colors, "Colors", "256");
857 getlab(pallab, "Palette", "1W");
858 getlab(tile, "Tile", "1WWW");
859 getlab(prio, "Priority", "3");
860 getlab(size, "Size", "64x64");
861 getlab(rot, "Rotation", "3W");
862 getlab(flg, "Flags", "RHVMD");
863 Fit();
864 Update();
865 }
Update()866 void Update()
867 {
868 BMPSize(544, 496);
869 wxImage screen(240, 160);
870 systemRedShift = 19;
871 systemGreenShift = 11;
872 systemBlueShift = 3;
873 utilReadScreenPixels(screen.GetData(), 240, 160);
874 systemRedShift = 3;
875 systemGreenShift = 11;
876 systemBlueShift = 19;
877
878 for (int sprite_no = 0; sprite_no < 128; sprite_no++)
879 {
880 u16* sparms = &((u16*)oam)[4 * sprite_no];
881 u16 a0 = sparms[0], a1 = sparms[1], a2 = sparms[2];
882 u16* pal = &((u16*)paletteRAM)[0x100];
883 int sizeX = 8, sizeY = 8;
884
885 // following is almost verbatim from OamView.cpp
886 // shape = (a0 >> 14) & 3;
887 // size = (a1 >> 14) & 3;
888 switch (((a0 >> 12) & 0xc) | (a1 >> 14))
889 {
890 case 0:
891 break;
892
893 case 1:
894 sizeX = sizeY = 16;
895 break;
896
897 case 2:
898 sizeX = sizeY = 32;
899 break;
900
901 case 3:
902 sizeX = sizeY = 64;
903 break;
904
905 case 4:
906 sizeX = 16;
907 break;
908
909 case 5:
910 sizeX = 32;
911 break;
912
913 case 6:
914 sizeX = 32;
915 sizeY = 16;
916 break;
917
918 case 7:
919 sizeX = 64;
920 sizeY = 32;
921 break;
922
923 case 8:
924 sizeY = 16;
925 break;
926
927 case 9:
928 sizeY = 32;
929 break;
930
931 case 10:
932 sizeX = 16;
933 sizeY = 32;
934 break;
935
936 case 11:
937 sizeX = 32;
938 sizeY = 64;
939 break;
940
941 default:
942 pos->SetLabel(wxEmptyString);
943 mode->SetLabel(wxEmptyString);
944 colors->SetLabel(wxEmptyString);
945 pallab->SetLabel(wxEmptyString);
946 tile->SetLabel(wxEmptyString);
947 prio->SetLabel(wxEmptyString);
948 size->SetLabel(wxEmptyString);
949 rot->SetLabel(wxEmptyString);
950 flg->SetLabel(wxEmptyString);
951 continue;
952 }
953
954 wxImage spriteData(64, 64);
955 u8* bmp = spriteData.GetData();
956 int sy = (a0 & 255);
957
958 if (a0 & 0x2000)
959 {
960 int c = (a2 & 0x3FF);
961 //if((DISPCNT & 7) > 2 && (c < 512))
962 // return;
963 int inc = 32;
964
965 if (DISPCNT & 0x40)
966 inc = sizeX >> 2;
967 else
968 c &= 0x3FE;
969
970 for (int y = 0; y < sizeY; y++)
971 {
972 for (int x = 0; x < sizeX; x++)
973 {
974 u32 color = vram[0x10000 + (((c + (y >> 3) * inc) *
975 32 + (y & 7) * 8 + (x >> 3) * 64 +
976 (x & 7)) & 0x7FFF)];
977 color = pal[color];
978 *bmp++ = (color & 0x1f) << 3;
979 *bmp++ = ((color >> 5) & 0x1f) << 3;
980 *bmp++ = ((color >> 10) & 0x1f) << 3;
981 }
982
983 bmp += (64 - sizeX) * 3;
984 }
985 }
986 else
987 {
988 int c = (a2 & 0x3FF);
989 //if((DISPCNT & 7) > 2 && (c < 512))
990 // return;
991 int inc = 32;
992
993 if (DISPCNT & 0x40)
994 inc = sizeX >> 3;
995
996 int palette = (a2 >> 8) & 0xF0;
997
998 for (int y = 0; y < sizeY; y++)
999 {
1000 for (int x = 0; x < sizeX; x++)
1001 {
1002 u32 color = vram[0x10000 + (((c + (y >> 3) * inc) *
1003 32 + (y & 7) * 4 + (x >> 3) * 32 +
1004 ((x & 7) >> 1)) & 0x7FFF)];
1005
1006 if (x & 1)
1007 color >>= 4;
1008 else
1009 color &= 0x0F;
1010
1011 color = pal[palette + color];
1012 *bmp++ = (color & 0x1f) << 3;
1013 *bmp++ = ((color >> 5) & 0x1f) << 3;
1014 *bmp++ = ((color >> 10) & 0x1f) << 3;
1015 }
1016
1017 bmp += (64 - sizeX) * 3;
1018 }
1019 }
1020
1021 if (sprite == sprite_no)
1022 {
1023 wxString s;
1024 s.Printf(wxT("%d,%d"), a1 & 511, a0 & 255);
1025 pos->SetLabel(s);
1026 s.Printf(wxT("%d"), (a0 >> 10) & 3);
1027 mode->SetLabel(s);
1028 colors->SetLabel(a0 & 8192 ? wxT("256") : wxT("16"));
1029 s.Printf(wxT("%d"), (a2 >> 12) & 15);
1030 pallab->SetLabel(s);
1031 s.Printf(wxT("%d"), a2 & 1023);
1032 tile->SetLabel(s);
1033 s.Printf(wxT("%d"), (a2 >> 10) & 3);
1034 prio->SetLabel(s);
1035 s.Printf(wxT("%dx%d"), sizeX, sizeY);
1036 s.Printf(wxT("%dx%d"), 0, 0);
1037 size->SetLabel(s);
1038
1039 if (a0 & 512)
1040 {
1041 s.Printf(wxT("%d"), (a1 >> 9) & 31);
1042 rot->SetLabel(s);
1043 }
1044 else
1045 rot->SetLabel(wxEmptyString);
1046
1047 s = wxEmptyString;
1048
1049 if (a0 & 512)
1050 s.append(wxT("R--"));
1051 else
1052 {
1053 s.append(wxT('-'));
1054 s.append(a1 & 4096 ? wxT('H') : wxT('-'));
1055 s.append(a1 & 8192 ? wxT('V') : wxT('-'));
1056 }
1057
1058 s.append(a0 & 4096 ? wxT('M') : wxT('-'));
1059 s.append(a0 & 1024 ? wxT('D') : wxT('-'));
1060 flg->SetLabel(s);
1061 u8* box = spriteData.GetData();
1062 int sprite_posx = a1 & 511;
1063 int sprite_posy = a0 & 255;
1064 u8* screen_box = screen.GetData();
1065
1066 if (sprite_posx >= 0 && sprite_posx <= (239 - sizeY) && sprite_posy >= 0 && sprite_posy <= (159 - sizeX))
1067 screen_box += (sprite_posx * 3) + (sprite_posy * screen.GetWidth() * 3);
1068
1069 for (int y = 0; y < sizeY; y++)
1070 {
1071 for (int x = 0; x < sizeX; x++)
1072 {
1073 u32 color = 0;
1074
1075 if (y == 0 || y == sizeY - 1 || x == 0 || x == sizeX - 1)
1076 {
1077 color = 255;
1078 *box++ = (color & 0x1f) << 3;
1079 *box++ = ((color >> 5) & 0x1f) << 3;
1080 *box++ = ((color >> 10) & 0x1f) << 3;
1081
1082 if (sprite_posx >= 0 && sprite_posx <= (239 - sizeY) && sprite_posy >= 0 && sprite_posy <= (159 - sizeX))
1083 {
1084 *screen_box++ = (color & 0x1f) << 3;
1085 *screen_box++ = ((color >> 5) & 0x1f) << 3;
1086 *screen_box++ = ((color >> 10) & 0x1f) << 3;
1087 }
1088 }
1089 else
1090 {
1091 box += 3;
1092
1093 if (sprite_posx >= 0 && sprite_posx <= (239 - sizeY) && sprite_posy >= 0 && sprite_posy <= (159 - sizeX))
1094 screen_box += 3;
1095 }
1096 }
1097
1098 box += (spriteData.GetWidth() - sizeX) * 3;
1099
1100 if (sprite_posx >= 0 && sprite_posx <= (239 - sizeY) && sprite_posy >= 0 && sprite_posy <= (159 - sizeX))
1101 screen_box += (screen.GetWidth() - sizeX) * 3;
1102 }
1103 }
1104
1105 image.Paste(spriteData, (sprite_no % 16) * 34, (sprite_no / 16) * 34);
1106 }
1107
1108 image.Paste(screen, 0, 304);
1109 ChangeBMP();
1110 }
1111 protected:
1112 int sprite;
1113 wxControl* pos, *mode, *colors, *pallab, *tile, *prio, *size, *rot, *flg;
1114 };
1115
1116 class GBOAMViewer : public GfxViewer
1117 {
1118 public:
GBOAMViewer()1119 GBOAMViewer() : GfxViewer(wxT("GBOAMViewer"), 8, 16)
1120 {
1121 sprite = 0;
1122 getspin(, "Sprite", sprite);
1123 getlab(pos, "Pos", "2WW,2WW");
1124 getlab(tilelab, "Tile", "2WW");
1125 getlab(prio, "Priority", "W");
1126 getlab(oap, "OAP", "W");
1127 getlab(pallab, "Palette", "W");
1128 getlab(flg, "Flags", "HV");
1129 getlab(banklab, "Bank", "W");
1130 Fit();
1131 Update();
1132 }
Update()1133 void Update()
1134 {
1135 u8* bmp = image.GetData();
1136 // following is almost verbatim from GBOamView.cpp
1137 u16 addr = sprite * 4 + 0xfe00;
1138 int size = register_LCDC & 4;
1139 u8 y = gbMemory[addr++];
1140 u8 x = gbMemory[addr++];
1141 u8 tile = gbMemory[addr++];
1142
1143 if (size)
1144 tile &= 254;
1145
1146 u8 flags = gbMemory[addr++];
1147 int w = 8;
1148 int h = size ? 16 : 8;
1149 BMPSize(w, h);
1150 u8* bank0;
1151 u8* bank1;
1152
1153 if (gbCgbMode)
1154 {
1155 if (register_VBK & 1)
1156 {
1157 bank0 = &gbVram[0x0000];
1158 bank1 = &gbVram[0x2000];
1159 }
1160 else
1161 {
1162 bank0 = &gbVram[0x0000];
1163 bank1 = &gbVram[0x2000];
1164 }
1165 }
1166 else
1167 {
1168 bank0 = &gbMemory[0x8000];
1169 bank1 = NULL;
1170 }
1171
1172 int init = 0x0000;
1173 u8* pal = gbObp0;
1174
1175 if ((flags & 0x10))
1176 pal = gbObp1;
1177
1178 for (int yy = 0; yy < h; yy++)
1179 {
1180 int address = init + tile * 16 + 2 * yy;
1181 int a = 0;
1182 int b = 0;
1183
1184 if (gbCgbMode && flags & 0x08)
1185 {
1186 a = bank1[address++];
1187 b = bank1[address++];
1188 }
1189 else
1190 {
1191 a = bank0[address++];
1192 b = bank0[address++];
1193 }
1194
1195 for (int xx = 0; xx < 8; xx++)
1196 {
1197 u8 mask = 1 << (7 - xx);
1198 u8 c = 0;
1199
1200 if ((a & mask))
1201 c++;
1202
1203 if ((b & mask))
1204 c += 2;
1205
1206 // make sure that sprites will work even in CGB mode
1207 if (gbCgbMode)
1208 {
1209 c = c + (flags & 0x07) * 4 + 32;
1210 }
1211 else
1212 {
1213 c = pal[c];
1214 }
1215
1216 u16 color = gbPalette[c];
1217 *bmp++ = (color & 0x1f) << 3;
1218 *bmp++ = ((color >> 5) & 0x1f) << 3;
1219 *bmp++ = ((color >> 10) & 0x1f) << 3;
1220 }
1221 }
1222
1223 ChangeBMP();
1224 wxString s;
1225 s.Printf(wxT("%d,%d"), x, y);
1226 pos->SetLabel(s);
1227 s.Printf(wxT("%d"), tile);
1228 tilelab->SetLabel(s);
1229 prio->SetLabel(flags & 0x80 ? wxT("1") : wxT("0"));
1230 oap->SetLabel(flags & 0x08 ? wxT("1") : wxT("0"));
1231 s.Printf(wxT("%d"), flags & 7);
1232 pallab->SetLabel(s);
1233 s = flags & 0x20 ? wxT('H') : wxT('-');
1234 s.append(flags & 0x40 ? wxT('V') : wxT('-'));
1235 flg->SetLabel(s);
1236 banklab->SetLabel(flags & 0x10 ? wxT("1") : wxT("0"));
1237 }
1238 protected:
1239 int sprite;
1240 wxControl* pos, *tilelab, *prio, *oap, *pallab, *flg, *banklab;
1241 };
1242 }
1243
OAMViewer()1244 void MainFrame::OAMViewer()
1245 {
1246 switch (panel->game_type())
1247 {
1248 case IMAGE_GBA:
1249 LoadXRCViewer(OAM);
1250 break;
1251
1252 case IMAGE_GB:
1253 LoadXRCViewer(GBOAM);
1254 break;
1255 }
1256 }
1257
1258 namespace Viewers
1259 {
1260 static int ptype = 0;
1261 static wxString pdir;
savepal(wxWindow * parent,const u8 * data,int ncols,const wxChar * type)1262 void savepal(wxWindow* parent, const u8* data, int ncols, const wxChar* type)
1263 {
1264 // no attempt is made here to translate the palette type name
1265 // it's just a suggested name, anyway
1266 wxString def_name = wxGetApp().frame->GetPanel()->game_name() +
1267 wxT('-') + type;
1268
1269 if (ptype == 2)
1270 def_name += wxT(".act");
1271 else
1272 def_name += wxT(".pal");
1273
1274 wxFileDialog dlg(parent, _("Select output file and type"), pdir, def_name,
1275 _("Windows Palette (*.pal)|*.pal|PaintShop Palette (*.pal)|*.pal|Adobe Color Table (*.act)|*.act"),
1276 wxFD_SAVE | wxFD_OVERWRITE_PROMPT);
1277 dlg.SetFilterIndex(ptype);
1278 int ret = dlg.ShowModal();
1279 ptype = dlg.GetFilterIndex();
1280 pdir = dlg.GetDirectory();
1281
1282 if (ret != wxID_OK)
1283 return;
1284
1285 wxFFile f(dlg.GetPath(), wxT("wb"));
1286
1287 // FIXME: check for errors
1288 switch (ptype)
1289 {
1290 case 0: // Windows palette
1291 {
1292 f.Write("RIFF", 4);
1293 u32 d = wxUINT32_SWAP_ON_BE(256 * 4 + 16);
1294 f.Write(&d, 4);
1295 f.Write("PAL data", 8);
1296 d = wxUINT32_SWAP_ON_BE(256 * 4 + 4);
1297 f.Write(&d, 4);
1298 u16 w = wxUINT16_SWAP_ON_BE(0x0300);
1299 f.Write(&w, 2);
1300 w = wxUINT16_SWAP_ON_BE(256); // cuases problems if not 16 or 256
1301 f.Write(&w, 2);
1302
1303 for (int i = 0; i < ncols; i++, data += 3)
1304 {
1305 f.Write(data, 3);
1306 u8 z = 0;
1307 f.Write(&z, 1);
1308 }
1309
1310 for (int i = ncols; i < 256; i++)
1311 {
1312 d = 0;
1313 f.Write(&d, 4);
1314 }
1315 }
1316 break;
1317
1318 case 1: // PaintShop palette
1319 {
1320 #define jasc_head "JASC-PAL\r\n0100\r\n256\r\n"
1321 f.Write(jasc_head, sizeof(jasc_head) - 1);
1322
1323 for (int i = 0; i < ncols; i++, data += 3)
1324 {
1325 char buf[14];
1326 int l = sprintf(buf, "%d %d %d\r\n", data[0], data[1], data[2]);
1327 f.Write(buf, l);
1328 }
1329
1330 for (int i = ncols; i < 256; i++)
1331 f.Write("0 0 0\r\n", 7);
1332
1333 break;
1334 }
1335
1336 case 2: // Adobe color table
1337 {
1338 f.Write(data, ncols * 3);
1339 u32 d = 0;
1340
1341 for (int i = ncols; i < 256; i++)
1342 f.Write(&d, 3);
1343 }
1344 break;
1345 }
1346
1347 f.Close(); // FIXME: check for errors
1348 }
1349
1350 class PaletteViewer : public Viewer
1351 {
1352 public:
PaletteViewer()1353 PaletteViewer() : Viewer(wxT("PaletteViewer"))
1354 {
1355 colorctrl(cv, "Color");
1356 pixview(bpv, "Background", 16, 16, cv);
1357 pixview(spv, "Sprite", 16, 16, cv);
1358 getlab(addr, "Address", "0x5000WWW");
1359 getlab(val, "Value", "0xWWWW");
1360 Fit();
1361 Update();
1362 }
Update()1363 void Update()
1364 {
1365 if (paletteRAM)
1366 {
1367 u16* pp = (u16*)paletteRAM;
1368 u8* bmp = colbmp;
1369
1370 for (int i = 0; i < 512; i++, pp++)
1371 {
1372 *bmp++ = (*pp & 0x1f) << 3;
1373 *bmp++ = (*pp & 0x3e0) >> 2;
1374 *bmp++ = (*pp & 0x7c00) >> 7;
1375 }
1376 }
1377 else
1378 memset(colbmp, 0, sizeof(colbmp));
1379
1380 bpv->SetData(colbmp, 16, 0, 0);
1381 spv->SetData(colbmp + 16 * 16 * 3, 16, 0, 0);
1382 ShowSel();
1383 }
SelBG(wxMouseEvent & ev)1384 void SelBG(wxMouseEvent &ev)
1385 {
1386 spv->SetSel(-1, -1, false);
1387 ShowSel();
1388 }
SelSprite(wxMouseEvent & ev)1389 void SelSprite(wxMouseEvent &ev)
1390 {
1391 bpv->SetSel(-1, -1, false);
1392 ShowSel();
1393 }
ShowSel()1394 void ShowSel()
1395 {
1396 int x, y;
1397 bool isbg = true;
1398 bpv->GetSel(x, y);
1399
1400 if (x < 0)
1401 {
1402 isbg = false;
1403 spv->GetSel(x, y);
1404
1405 if (x < 0)
1406 {
1407 addr->SetLabel(wxEmptyString);
1408 val->SetLabel(wxEmptyString);
1409 return;
1410 }
1411 }
1412
1413 int off = x + y * 16;
1414
1415 if (!isbg)
1416 off += 16 * 16;
1417
1418 u8* pix = &colbmp[off * 3];
1419 u16 v = (pix[0] >> 3) + ((pix[1] >> 3) << 5) + ((pix[2] >> 3) << 10);
1420 wxString s;
1421 s.Printf(wxT("0x%04X"), (int)v);
1422 val->SetLabel(s);
1423 s.Printf(wxT("0x%08X"), 0x5000000 + 2 * off);
1424 addr->SetLabel(s);
1425 }
SaveBG(wxCommandEvent & ev)1426 void SaveBG(wxCommandEvent &ev)
1427 {
1428 savepal(this, colbmp, 16 * 16, wxT("bg"));
1429 }
SaveOBJ(wxCommandEvent & ev)1430 void SaveOBJ(wxCommandEvent &ev)
1431 {
1432 savepal(this, colbmp + 16 * 16 * 3, 16 * 16, wxT("obj"));
1433 }
ChangeBackdrop(wxCommandEvent & ev)1434 void ChangeBackdrop(wxCommandEvent &ev)
1435 {
1436 // FIXME: this should really be a preference
1437 // should also have some way of indicating selection
1438 // perhaps replace w/ checkbox + colorpickerctrl
1439 static wxColourData* cd = NULL;
1440 wxColourDialog dlg(this, cd);
1441
1442 if (dlg.ShowModal() == wxID_OK)
1443 {
1444 if (!cd)
1445 cd = new wxColourData();
1446
1447 *cd = dlg.GetColourData();
1448 wxColour c = cd->GetColour();
1449 //Binary or the upper 5 bits of each color choice
1450 customBackdropColor =
1451 (c.Red() >> 3) ||
1452 ((c.Green() >> 3) << 5) ||
1453 ((c.Blue() >> 3) << 10);
1454 }
1455 else
1456 // kind of an unintuitive way to turn it off...
1457 customBackdropColor = -1;
1458 }
1459 protected:
1460 ColorView* cv;
1461 PixView* bpv, *spv;
1462 u8 colbmp[16 * 16 * 3 * 2];
1463 wxControl* addr, *val;
1464
1465 DECLARE_EVENT_TABLE()
1466 };
1467
1468 BEGIN_EVENT_TABLE(PaletteViewer, Viewer)
1469 EVT_BUTTON(XRCID("SaveBG"), PaletteViewer::SaveBG)
1470 EVT_BUTTON(XRCID("SaveOBJ"), PaletteViewer::SaveOBJ)
1471 EVT_BUTTON(XRCID("ChangeBackdrop"), PaletteViewer::ChangeBackdrop)
1472 EVT_GFX_CLICK(XRCID("Background"), PaletteViewer::SelBG)
1473 EVT_GFX_CLICK(XRCID("Sprite"), PaletteViewer::SelSprite)
1474 END_EVENT_TABLE()
1475
1476 class GBPaletteViewer : public Viewer
1477 {
1478 public:
GBPaletteViewer()1479 GBPaletteViewer() : Viewer(wxT("GBPaletteViewer"))
1480 {
1481 colorctrl(cv, "Color");
1482 pixview(bpv, "Background", 4, 8, cv);
1483 pixview(spv, "Sprite", 4, 8, cv);
1484 getlab(idx, "Index", "3W");
1485 getlab(val, "Value", "0xWWWW");
1486 Fit();
1487 Update();
1488 }
Update()1489 void Update()
1490 {
1491 u16* pp = gbPalette;
1492 u8* bmp = colbmp;
1493
1494 for (int i = 0; i < 64; i++, pp++)
1495 {
1496 *bmp++ = (*pp & 0x1f) << 3;
1497 *bmp++ = (*pp & 0x3e0) >> 2;
1498 *bmp++ = (*pp & 0x7c00) >> 7;
1499 }
1500
1501 bpv->SetData(colbmp, 4, 0, 0);
1502 spv->SetData(colbmp + 4 * 8 * 3, 4, 0, 0);
1503 ShowSel();
1504 }
SelBG(wxMouseEvent & ev)1505 void SelBG(wxMouseEvent &ev)
1506 {
1507 spv->SetSel(-1, -1, false);
1508 ShowSel();
1509 }
SelSprite(wxMouseEvent & ev)1510 void SelSprite(wxMouseEvent &ev)
1511 {
1512 bpv->SetSel(-1, -1, false);
1513 ShowSel();
1514 }
ShowSel()1515 void ShowSel()
1516 {
1517 int x, y;
1518 bool isbg = true;
1519 bpv->GetSel(x, y);
1520
1521 if (x < 0)
1522 {
1523 isbg = false;
1524 spv->GetSel(x, y);
1525
1526 if (x < 0)
1527 {
1528 idx->SetLabel(wxEmptyString);
1529 val->SetLabel(wxEmptyString);
1530 return;
1531 }
1532 }
1533
1534 u8* pix = &colbmp[(x + y * 4) * 3];
1535
1536 if (isbg)
1537 pix += 4 * 8 * 3;
1538
1539 u16 v = (pix[0] >> 3) + ((pix[1] >> 3) << 5) + ((pix[2] >> 3) << 10);
1540 wxString s;
1541 s.Printf(wxT("0x%04X"), (int)v);
1542 val->SetLabel(s);
1543 s.Printf(wxT("%d"), x + y * 4);
1544 idx->SetLabel(s);
1545 }
SaveBG(wxCommandEvent & ev)1546 void SaveBG(wxCommandEvent &ev)
1547 {
1548 savepal(this, colbmp, 4 * 8, wxT("bg"));
1549 }
SaveOBJ(wxCommandEvent & ev)1550 void SaveOBJ(wxCommandEvent &ev)
1551 {
1552 savepal(this, colbmp + 4 * 8 * 3, 4 * 8, wxT("obj"));
1553 }
1554 protected:
1555 ColorView* cv;
1556 PixView* bpv, *spv;
1557 u8 colbmp[4 * 8 * 3 * 2];
1558 wxControl* idx, *val;
1559 DECLARE_EVENT_TABLE()
1560 };
1561
1562 BEGIN_EVENT_TABLE(GBPaletteViewer, Viewer)
1563 EVT_BUTTON(XRCID("SaveBG"), GBPaletteViewer::SaveBG)
1564 EVT_BUTTON(XRCID("SaveOBJ"), GBPaletteViewer::SaveOBJ)
1565 EVT_GFX_CLICK(XRCID("Background"), GBPaletteViewer::SelBG)
1566 EVT_GFX_CLICK(XRCID("Sprite"), GBPaletteViewer::SelSprite)
1567 END_EVENT_TABLE()
1568 }
1569
PaletteViewer()1570 void MainFrame::PaletteViewer()
1571 {
1572 switch (panel->game_type())
1573 {
1574 case IMAGE_GBA:
1575 LoadXRCViewer(Palette);
1576 break;
1577
1578 case IMAGE_GB:
1579 LoadXRCViewer(GBPalette);
1580 break;
1581 }
1582 }
1583
1584 namespace Viewers
1585 {
1586 class TileViewer : public GfxViewer
1587 {
1588 public:
TileViewer()1589 TileViewer() : GfxViewer(wxT("TileViewer"), 32 * 8, 32 * 8)
1590 {
1591 is256 = charbase = 0;
1592 getradio(, "Color16", is256, 0);
1593 getradio(, "Color256", is256, 1);
1594 getradio(, "CharBase0", charbase, 0);
1595 getradio(, "CharBase1", charbase, 0x4000);
1596 getradio(, "CharBase2", charbase, 0x8000);
1597 getradio(, "CharBase3", charbase, 0xc000);
1598 getradio(, "CharBase4", charbase, 0x10000);
1599 getslider(, "Palette", palette);
1600 getlab(tileno, "Tile", "1WWW");
1601 getlab(addr, "Address", "06WWWWWW");
1602 selx = sely = -1;
1603 Fit();
1604 Update();
1605 }
Update()1606 void Update()
1607 {
1608 // Following copied almost verbatim from TileView.cpp
1609 u16* palette = (u16*)paletteRAM;
1610 u8* charBase = &vram[charbase];
1611 int maxY;
1612
1613 if (is256)
1614 {
1615 int tile = 0;
1616 maxY = 16;
1617
1618 for (int y = 0; y < maxY; y++)
1619 {
1620 for (int x = 0; x < 32; x++)
1621 {
1622 if (charbase == 4 * 0x4000)
1623 render256(tile, x, y, charBase, &palette[256]);
1624 else
1625 render256(tile, x, y, charBase, palette);
1626
1627 tile++;
1628 }
1629 }
1630
1631 BMPSize(32 * 8, maxY * 8);
1632 }
1633 else
1634 {
1635 int tile = 0;
1636 maxY = 32;
1637
1638 if (charbase == 3 * 0x4000)
1639 maxY = 16;
1640
1641 for (int y = 0; y < maxY; y++)
1642 {
1643 for (int x = 0; x < 32; x++)
1644 {
1645 render16(tile, x, y, charBase, palette);
1646 tile++;
1647 }
1648 }
1649
1650 BMPSize(32 * 8, maxY * 8);
1651 }
1652
1653 ChangeBMP();
1654 UpdateMouseInfo();
1655 }
UpdateMouseInfoEv(wxMouseEvent & ev)1656 void UpdateMouseInfoEv(wxMouseEvent &ev)
1657 {
1658 selx = ev.GetX();
1659 sely = ev.GetY();
1660 UpdateMouseInfo();
1661 }
1662
UpdateMouseInfo()1663 void UpdateMouseInfo()
1664 {
1665 if (selx > gv->bmw || sely > gv->bmh)
1666 selx = sely = -1;
1667
1668 if (selx < 0)
1669 {
1670 addr->SetLabel(wxEmptyString);
1671 tileno->SetLabel(wxEmptyString);
1672 }
1673 else
1674 {
1675 int x = selx / 8;
1676 int y = sely / 8;
1677 int t = 32 * y + x;
1678
1679 if (is256)
1680 t *= 2;
1681
1682 wxString s;
1683 s.Printf(wxT("%d"), t);
1684 tileno->SetLabel(s);
1685 s.Printf(wxT("%08X"), 0x6000000 + charbase + 32 * t);
1686 addr->SetLabel(s);
1687 }
1688 }
1689 // following 2 functions copied almost verbatim from TileView.cpp
render256(int tile,int x,int y,u8 * charBase,u16 * palette)1690 void render256(int tile, int x, int y, u8* charBase, u16* palette)
1691 {
1692 u8* bmp = &image.GetData()[24 * x + 8 * 32 * 24 * y];
1693
1694 for (int j = 0; j < 8; j++)
1695 {
1696 for (int i = 0; i < 8; i++)
1697 {
1698 u8 c = charBase[tile * 64 + j * 8 + i];
1699 u16 color = palette[c];
1700 *bmp++ = (color & 0x1f) << 3;
1701 *bmp++ = ((color >> 5) & 0x1f) << 3;
1702 *bmp++ = ((color >> 10) & 0x1f) << 3;
1703 }
1704
1705 bmp += 31 * 24; // advance line
1706 }
1707 }
1708
render16(int tile,int x,int y,u8 * charBase,u16 * palette)1709 void render16(int tile, int x, int y, u8* charBase, u16* palette)
1710 {
1711 u8* bmp = &image.GetData()[24 * x + 8 * 32 * 24 * y];
1712 int pal = this->palette;
1713
1714 if (this->charbase == 4 * 0x4000)
1715 pal += 16;
1716
1717 for (int j = 0; j < 8; j++)
1718 {
1719 for (int i = 0; i < 8; i++)
1720 {
1721 u8 c = charBase[tile * 32 + j * 4 + (i >> 1)];
1722
1723 if (i & 1)
1724 c = c >> 4;
1725 else
1726 c = c & 15;
1727
1728 u16 color = palette[pal * 16 + c];
1729 *bmp++ = (color & 0x1f) << 3;
1730 *bmp++ = ((color >> 5) & 0x1f) << 3;
1731 *bmp++ = ((color >> 10) & 0x1f) << 3;
1732 }
1733
1734 bmp += 31 * 24; // advance line
1735 }
1736 }
1737
1738 protected:
1739 int charbase, is256, palette;
1740 wxControl* tileno, *addr;
1741 int selx, sely;
1742
1743 DECLARE_EVENT_TABLE()
1744 };
1745
1746 BEGIN_EVENT_TABLE(TileViewer, GfxViewer)
1747 EVT_GFX_CLICK(wxID_ANY, TileViewer::UpdateMouseInfoEv)
1748 END_EVENT_TABLE()
1749
1750 class GBTileViewer : public GfxViewer
1751 {
1752 public:
GBTileViewer()1753 GBTileViewer() : GfxViewer(wxT("GBTileViewer"), 16 * 8, 16 * 8)
1754 {
1755 bank = charbase = 0;
1756 getradio(, "Bank0", bank, 0);
1757 getradio(, "Bank1", bank, 0x2000);
1758 getradio(, "CharBase0", charbase, 0);
1759 getradio(, "CharBase1", charbase, 0x800);
1760 getslider(, "Palette", palette);
1761 getlab(tileno, "Tile", "2WW");
1762 getlab(addr, "Address", "WWWW");
1763 selx = sely = -1;
1764 Fit();
1765 Update();
1766 }
Update()1767 void Update()
1768 {
1769 // following copied almost verbatim from GBTileView.cpp
1770 u8* charBase = (gbVram != NULL) ?
1771 &gbVram[bank + charbase] :
1772 &gbMemory[0x8000 + charbase];
1773 int tile = 0;
1774
1775 for (int y = 0; y < 16; y++)
1776 {
1777 for (int x = 0; x < 16; x++)
1778 {
1779 render(tile, x, y, charBase);
1780 tile++;
1781 }
1782 }
1783
1784 ChangeBMP();
1785 UpdateMouseInfo();
1786 }
UpdateMouseInfoEv(wxMouseEvent & ev)1787 void UpdateMouseInfoEv(wxMouseEvent &ev)
1788 {
1789 selx = ev.GetX();
1790 sely = ev.GetY();
1791 UpdateMouseInfo();
1792 }
1793
UpdateMouseInfo()1794 void UpdateMouseInfo()
1795 {
1796 if (selx > gv->bmw || sely > gv->bmh)
1797 selx = sely = -1;
1798
1799 if (selx < 0)
1800 {
1801 addr->SetLabel(wxEmptyString);
1802 tileno->SetLabel(wxEmptyString);
1803 }
1804 else
1805 {
1806 int x = selx / 8;
1807 int y = sely / 8;
1808 int t = 16 * y + x;
1809 wxString s;
1810 s.Printf(wxT("%d"), t);
1811 tileno->SetLabel(s);
1812 s.Printf(wxT("%04X"), 0x8000 + charbase + 16 * t);
1813 addr->SetLabel(s);
1814 }
1815 }
1816
1817 // following function copied almost verbatim from GBTileView.cpp
render(int tile,int x,int y,u8 * charBase)1818 void render(int tile, int x, int y, u8* charBase)
1819 {
1820 u8* bmp = &image.GetData()[24 * x + 8 * 16 * 24 * y];
1821
1822 for (int j = 0; j < 8; j++)
1823 {
1824 u8 mask = 0x80;
1825 u8 tile_a = charBase[tile * 16 + j * 2];
1826 u8 tile_b = charBase[tile * 16 + j * 2 + 1];
1827
1828 for (int i = 0; i < 8; i++)
1829 {
1830 u8 c = (tile_a & mask) ? 1 : 0;
1831 c += ((tile_b & mask) ? 2 : 0);
1832
1833 if (gbCgbMode)
1834 {
1835 c = c + palette * 4;
1836 }
1837 else
1838 {
1839 c = gbBgp[c];
1840 }
1841
1842 u16 color = gbPalette[c];
1843 *bmp++ = (color & 0x1f) << 3;
1844 *bmp++ = ((color >> 5) & 0x1f) << 3;
1845 *bmp++ = ((color >> 10) & 0x1f) << 3;
1846 mask >>= 1;
1847 }
1848
1849 bmp += 15 * 24; // advance line
1850 }
1851 }
1852 protected:
1853 int bank, charbase, palette;
1854 wxControl* addr, *tileno;
1855 int selx, sely;
1856
1857 DECLARE_EVENT_TABLE()
1858 };
1859
1860 BEGIN_EVENT_TABLE(GBTileViewer, GfxViewer)
1861 EVT_GFX_CLICK(wxID_ANY, GBTileViewer::UpdateMouseInfoEv)
1862 END_EVENT_TABLE()
1863 }
1864
TileViewer()1865 void MainFrame::TileViewer()
1866 {
1867 switch (panel->game_type())
1868 {
1869 case IMAGE_GBA:
1870 LoadXRCViewer(Tile);
1871 break;
1872
1873 case IMAGE_GB:
1874 LoadXRCViewer(GBTile);
1875 break;
1876 }
1877 }
1878