view src/win32/TileView.cpp @ 4:5f6f2134e8ce

apu appears to not be used
author Robert McIntyre <rlm@mit.edu>
date Sat, 03 Mar 2012 10:35:58 -0600
parents f9f4f1b99eed
children
line wrap: on
line source
1 // TileView.cpp : implementation file
2 //
4 #include "stdafx.h"
5 #include "resource.h"
6 #include "FileDlg.h"
7 #include "Reg.h"
8 #include "TileView.h"
9 #include "WinResUtil.h"
10 #include "VBA.h" // for theApp
12 #include "../gba/GBAGlobals.h"
13 #include "../NLS.h"
14 #include "../common/Util.h"
16 extern "C" {
17 #include <png.h>
18 }
20 /////////////////////////////////////////////////////////////////////////////
21 // TileView dialog
23 TileView::TileView(CWnd*pParent /*=NULL*/)
24 : ResizeDlg(TileView::IDD, pParent)
25 {
26 //{{AFX_DATA_INIT(TileView)
27 m_colors = -1;
28 m_charBase = -1;
29 m_stretch = FALSE;
30 //}}AFX_DATA_INIT
31 autoUpdate = false;
33 memset(&bmpInfo, 0, sizeof(bmpInfo));
35 bmpInfo.bmiHeader.biSize = sizeof(bmpInfo.bmiHeader);
36 bmpInfo.bmiHeader.biWidth = 32*8;
37 bmpInfo.bmiHeader.biHeight = 32*8;
38 bmpInfo.bmiHeader.biPlanes = 1;
39 bmpInfo.bmiHeader.biBitCount = 24;
40 bmpInfo.bmiHeader.biCompression = BI_RGB;
41 data = (u8 *)calloc(1, 3 * 32*32 * 64);
43 tileView.setData(data);
44 tileView.setBmpInfo(&bmpInfo);
46 charBase = 0;
47 is256Colors = 0;
48 palette = 0;
49 w = h = 0;
50 }
52 TileView::~TileView()
53 {
54 free(data);
55 data = NULL;
56 }
58 void TileView::DoDataExchange(CDataExchange*pDX)
59 {
60 CDialog::DoDataExchange(pDX);
61 //{{AFX_DATA_MAP(TileView)
62 DDX_Control(pDX, IDC_PALETTE_SLIDER, m_slider);
63 DDX_Radio(pDX, IDC_16_COLORS, m_colors);
64 DDX_Radio(pDX, IDC_CHARBASE_0, m_charBase);
65 DDX_Check(pDX, IDC_STRETCH, m_stretch);
66 //}}AFX_DATA_MAP
67 DDX_Control(pDX, IDC_TILE_VIEW, tileView);
68 DDX_Control(pDX, IDC_MAP_VIEW_ZOOM, zoom);
69 DDX_Control(pDX, IDC_COLOR, color);
70 }
72 BEGIN_MESSAGE_MAP(TileView, CDialog)
73 //{{AFX_MSG_MAP(TileView)
74 ON_BN_CLICKED(IDC_SAVE, OnSave)
75 ON_BN_CLICKED(IDC_CLOSE, OnClose)
76 ON_BN_CLICKED(IDC_AUTO_UPDATE, OnAutoUpdate)
77 ON_BN_CLICKED(IDC_16_COLORS, On16Colors)
78 ON_BN_CLICKED(IDC_256_COLORS, On256Colors)
79 ON_BN_CLICKED(IDC_CHARBASE_0, OnCharbase0)
80 ON_BN_CLICKED(IDC_CHARBASE_1, OnCharbase1)
81 ON_BN_CLICKED(IDC_CHARBASE_2, OnCharbase2)
82 ON_BN_CLICKED(IDC_CHARBASE_3, OnCharbase3)
83 ON_BN_CLICKED(IDC_CHARBASE_4, OnCharbase4)
84 ON_BN_CLICKED(IDC_STRETCH, OnStretch)
85 ON_WM_HSCROLL()
86 //}}AFX_MSG_MAP
87 ON_MESSAGE(WM_MAPINFO, OnMapInfo)
88 ON_MESSAGE(WM_COLINFO, OnColInfo)
89 END_MESSAGE_MAP()
91 /////////////////////////////////////////////////////////////////////////////
92 // TileView message handlers
94 void TileView::saveBMP(const char *name)
95 {
96 u8 writeBuffer[1024 * 3];
98 FILE *fp = fopen(name, "wb");
100 if (!fp)
101 {
102 systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name);
103 return;
104 }
106 struct
107 {
108 u8 ident[2];
109 u8 filesize[4];
110 u8 reserved[4];
111 u8 dataoffset[4];
112 u8 headersize[4];
113 u8 width[4];
114 u8 height[4];
115 u8 planes[2];
116 u8 bitsperpixel[2];
117 u8 compression[4];
118 u8 datasize[4];
119 u8 hres[4];
120 u8 vres[4];
121 u8 colors[4];
122 u8 importantcolors[4];
123 u8 pad[2];
124 } bmpheader;
125 memset(&bmpheader, 0, sizeof(bmpheader));
127 bmpheader.ident[0] = 'B';
128 bmpheader.ident[1] = 'M';
130 u32 fsz = sizeof(bmpheader) + w*h*3;
131 utilPutDword(bmpheader.filesize, fsz);
132 utilPutDword(bmpheader.dataoffset, 0x38);
133 utilPutDword(bmpheader.headersize, 0x28);
134 utilPutDword(bmpheader.width, w);
135 utilPutDword(bmpheader.height, h);
136 utilPutDword(bmpheader.planes, 1);
137 utilPutDword(bmpheader.bitsperpixel, 24);
138 utilPutDword(bmpheader.datasize, 3*w*h);
140 fwrite(&bmpheader, 1, sizeof(bmpheader), fp);
142 u8 *b = writeBuffer;
144 int sizeX = w;
145 int sizeY = h;
147 u8 *pixU8 = (u8 *)data+3*w*(h-1);
148 for (int y = 0; y < sizeY; y++)
149 {
150 for (int x = 0; x < sizeX; x++)
151 {
152 *b++ = *pixU8++; // B
153 *b++ = *pixU8++; // G
154 *b++ = *pixU8++; // R
155 }
156 pixU8 -= 2*3*w;
157 fwrite(writeBuffer, 1, 3*w, fp);
159 b = writeBuffer;
160 }
162 fclose(fp);
163 }
165 void TileView::savePNG(const char *name)
166 {
167 u8 writeBuffer[1024 * 3];
169 FILE *fp = fopen(name, "wb");
171 if (!fp)
172 {
173 systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name);
174 return;
175 }
177 png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING,
178 NULL,
179 NULL,
180 NULL);
181 if (!png_ptr)
182 {
183 fclose(fp);
184 return;
185 }
187 png_infop info_ptr = png_create_info_struct(png_ptr);
189 if (!info_ptr)
190 {
191 png_destroy_write_struct(&png_ptr, NULL);
192 fclose(fp);
193 return;
194 }
196 if (setjmp(png_ptr->jmpbuf))
197 {
198 png_destroy_write_struct(&png_ptr, NULL);
199 fclose(fp);
200 return;
201 }
203 png_init_io(png_ptr, fp);
205 png_set_IHDR(png_ptr,
206 info_ptr,
207 w,
208 h,
209 8,
210 PNG_COLOR_TYPE_RGB,
211 PNG_INTERLACE_NONE,
212 PNG_COMPRESSION_TYPE_DEFAULT,
213 PNG_FILTER_TYPE_DEFAULT);
215 png_write_info(png_ptr, info_ptr);
217 u8 *b = writeBuffer;
219 int sizeX = w;
220 int sizeY = h;
222 u8 *pixU8 = (u8 *)data;
223 for (int y = 0; y < sizeY; y++)
224 {
225 for (int x = 0; x < sizeX; x++)
226 {
227 int blue = *pixU8++;
228 int green = *pixU8++;
229 int red = *pixU8++;
231 *b++ = red;
232 *b++ = green;
233 *b++ = blue;
234 }
235 png_write_row(png_ptr, writeBuffer);
237 b = writeBuffer;
238 }
240 png_write_end(png_ptr, info_ptr);
242 png_destroy_write_struct(&png_ptr, &info_ptr);
244 fclose(fp);
245 }
247 void TileView::OnSave()
248 {
249 CString captureBuffer;
251 if (theApp.captureFormat == 0)
252 captureBuffer = "tiles.png";
253 else
254 captureBuffer = "tiles.bmp";
256 LPCTSTR exts[] = {".png", ".bmp", NULL };
258 CString filter = winResLoadFilter(IDS_FILTER_PNG);
259 CString title = winResLoadString(IDS_SELECT_CAPTURE_NAME);
261 FileDlg dlg(this,
262 captureBuffer,
263 filter,
264 theApp.captureFormat ? 2 : 1,
265 theApp.captureFormat ? "BMP" : "PNG",
266 exts,
267 "",
268 title,
269 true);
271 if (dlg.DoModal() == IDCANCEL)
272 {
273 return;
274 }
276 captureBuffer = dlg.GetPathName();
278 if (dlg.getFilterIndex() == 2)
279 saveBMP(captureBuffer);
280 else
281 savePNG(captureBuffer);
282 }
284 void TileView::renderTile256(int tile, int x, int y, u8 *charBase, u16 *palette)
285 {
286 u8 *bmp = &data[24*x + 8*32*24*y];
288 for (int j = 0; j < 8; j++)
289 {
290 for (int i = 0; i < 8; i++)
291 {
292 u8 c = charBase[tile*64 + j * 8 + i];
294 u16 color = palette[c];
296 *bmp++ = ((color >> 10) & 0x1f) << 3;
297 *bmp++ = ((color >> 5) & 0x1f) << 3;
298 *bmp++ = (color & 0x1f) << 3;
299 }
300 bmp += 31*24; // advance line
301 }
302 }
304 void TileView::renderTile16(int tile, int x, int y, u8 *charBase, u16 *palette)
305 {
306 u8 *bmp = &data[24*x + 8*32*24*y];
308 int pal = this->palette;
310 if (this->charBase == 4)
311 pal += 16;
313 for (int j = 0; j < 8; j++)
314 {
315 for (int i = 0; i < 8; i++)
316 {
317 u8 c = charBase[tile*32 + j * 4 + (i>>1)];
319 if (i & 1)
320 c = c>>4;
321 else
322 c = c & 15;
324 u16 color = palette[pal*16+c];
326 *bmp++ = ((color >> 10) & 0x1f) << 3;
327 *bmp++ = ((color >> 5) & 0x1f) << 3;
328 *bmp++ = (color & 0x1f) << 3;
329 }
330 bmp += 31*24; // advance line
331 }
332 }
334 void TileView::render()
335 {
336 u16 *palette = (u16 *)paletteRAM;
337 u8 * charBase = &vram[this->charBase * 0x4000];
339 int maxY;
341 if (is256Colors)
342 {
343 int tile = 0;
344 maxY = 16;
345 for (int y = 0; y < maxY; y++)
346 {
347 for (int x = 0; x < 32; x++)
348 {
349 if (this->charBase == 4)
350 renderTile256(tile, x, y, charBase, &palette[256]);
351 else
352 renderTile256(tile, x, y, charBase, palette);
353 tile++;
354 }
355 }
356 tileView.setSize(32*8, maxY*8);
357 w = 32*8;
358 h = maxY*8;
359 SIZE s;
360 s.cx = 32*8;
361 s.cy = maxY*8;
362 if (tileView.getStretch())
363 {
364 s.cx = s.cy = 1;
365 }
366 tileView.SetScrollSizes(MM_TEXT, s);
367 }
368 else
369 {
370 int tile = 0;
371 maxY = 32;
372 if (this->charBase == 3)
373 maxY = 16;
374 for (int y = 0; y < maxY; y++)
375 {
376 for (int x = 0; x < 32; x++)
377 {
378 renderTile16(tile, x, y, charBase, palette);
379 tile++;
380 }
381 }
382 tileView.setSize(32*8, maxY*8);
383 w = 32*8;
384 h = maxY*8;
385 SIZE s;
386 s.cx = 32*8;
387 s.cy = maxY*8;
388 if (tileView.getStretch())
389 {
390 s.cx = s.cy = 1;
391 }
392 tileView.SetScrollSizes(MM_TEXT, s);
393 }
394 }
396 void TileView::update()
397 {
398 paint();
399 }
401 BOOL TileView::OnInitDialog()
402 {
403 CDialog::OnInitDialog();
405 DIALOG_SIZER_START(sz)
406 DIALOG_SIZER_ENTRY(IDC_TILE_VIEW, DS_SizeX | DS_SizeY)
407 DIALOG_SIZER_ENTRY(IDC_COLOR, DS_MoveY)
408 DIALOG_SIZER_ENTRY(IDC_R, DS_MoveY)
409 DIALOG_SIZER_ENTRY(IDC_G, DS_MoveY)
410 DIALOG_SIZER_ENTRY(IDC_B, DS_MoveY)
411 DIALOG_SIZER_ENTRY(IDC_REFRESH, DS_MoveY)
412 DIALOG_SIZER_ENTRY(IDC_CLOSE, DS_MoveY)
413 DIALOG_SIZER_ENTRY(IDC_SAVE, DS_MoveY)
414 DIALOG_SIZER_END()
415 SetData(sz,
416 TRUE,
417 HKEY_CURRENT_USER,
418 "Software\\Emulators\\VisualBoyAdvance\\Viewer\\TileView",
419 NULL);
421 m_colors = is256Colors;
422 m_charBase = charBase;
424 m_slider.SetRange(0, 15);
425 m_slider.SetPageSize(4);
426 m_slider.SetTicFreq(1);
428 paint();
430 m_stretch = regQueryDwordValue("tileViewStretch", 0);
431 if (m_stretch)
432 tileView.setStretch(true);
433 UpdateData(FALSE);
435 return TRUE; // return TRUE unless you set the focus to a control
436 // EXCEPTION: OCX Property Pages should return FALSE
437 }
439 void TileView::OnClose()
440 {
441 theApp.winRemoveUpdateListener(this);
443 DestroyWindow();
444 }
446 void TileView::OnAutoUpdate()
447 {
448 autoUpdate = !autoUpdate;
449 if (autoUpdate)
450 {
451 theApp.winAddUpdateListener(this);
452 }
453 else
454 {
455 theApp.winRemoveUpdateListener(this);
456 }
457 }
459 void TileView::paint()
460 {
461 if (vram != NULL && paletteRAM != NULL)
462 {
463 render();
464 tileView.refresh();
465 }
466 }
468 void TileView::On16Colors()
469 {
470 is256Colors = 0;
471 paint();
472 }
474 void TileView::On256Colors()
475 {
476 is256Colors = 1;
477 paint();
478 }
480 void TileView::OnCharbase0()
481 {
482 charBase = 0;
483 paint();
484 }
486 void TileView::OnCharbase1()
487 {
488 charBase = 1;
489 paint();
490 }
492 void TileView::OnCharbase2()
493 {
494 charBase = 2;
495 paint();
496 }
498 void TileView::OnCharbase3()
499 {
500 charBase = 3;
501 paint();
502 }
504 void TileView::OnCharbase4()
505 {
506 charBase = 4;
507 paint();
508 }
510 void TileView::OnStretch()
511 {
512 tileView.setStretch(!tileView.getStretch());
513 paint();
514 regSetDwordValue("tileViewStretch", tileView.getStretch());
515 }
517 LRESULT TileView::OnMapInfo(WPARAM wParam, LPARAM lParam)
518 {
519 u8 *colors = (u8 *)lParam;
520 zoom.setColors(colors);
522 int x = (wParam & 0xFFFF)/8;
523 int y = ((wParam >> 16) & 0xFFFF)/8;
525 u32 address = 0x6000000 + 0x4000 * charBase;
526 int tile = 32 * y + x;
527 if (is256Colors)
528 tile *= 2;
529 address += 32 * tile;
531 CString buffer;
532 buffer.Format("%d", tile);
533 GetDlgItem(IDC_TILE_NUMBER)->SetWindowText(buffer);
535 buffer.Format("%08x", address);
536 GetDlgItem(IDC_ADDRESS)->SetWindowText(buffer);
538 return TRUE;
539 }
541 LRESULT TileView::OnColInfo(WPARAM wParam, LPARAM)
542 {
543 u16 c = (u16)wParam;
545 color.setColor(c);
547 int r = (c & 0x1f);
548 int g = (c & 0x3e0) >> 5;
549 int b = (c & 0x7c00) >> 10;
551 CString buffer;
552 buffer.Format("R: %d", r);
553 GetDlgItem(IDC_R)->SetWindowText(buffer);
555 buffer.Format("G: %d", g);
556 GetDlgItem(IDC_G)->SetWindowText(buffer);
558 buffer.Format("B: %d", b);
559 GetDlgItem(IDC_B)->SetWindowText(buffer);
561 return TRUE;
562 }
564 void TileView::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar*pScrollBar)
565 {
566 switch (nSBCode)
567 {
568 case TB_THUMBPOSITION:
569 palette = nPos;
570 break;
571 default:
572 palette = m_slider.GetPos();
573 break;
574 }
575 paint();
576 }
578 void TileView::PostNcDestroy()
579 {
580 delete this;
581 }