Mercurial > vba-linux
comparison src/win32/TileView.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 // TileView.cpp : implementation file | |
2 // | |
3 | |
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 | |
11 | |
12 #include "../gba/GBAGlobals.h" | |
13 #include "../NLS.h" | |
14 #include "../common/Util.h" | |
15 | |
16 extern "C" { | |
17 #include <png.h> | |
18 } | |
19 | |
20 ///////////////////////////////////////////////////////////////////////////// | |
21 // TileView dialog | |
22 | |
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; | |
32 | |
33 memset(&bmpInfo, 0, sizeof(bmpInfo)); | |
34 | |
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); | |
42 | |
43 tileView.setData(data); | |
44 tileView.setBmpInfo(&bmpInfo); | |
45 | |
46 charBase = 0; | |
47 is256Colors = 0; | |
48 palette = 0; | |
49 w = h = 0; | |
50 } | |
51 | |
52 TileView::~TileView() | |
53 { | |
54 free(data); | |
55 data = NULL; | |
56 } | |
57 | |
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 } | |
71 | |
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() | |
90 | |
91 ///////////////////////////////////////////////////////////////////////////// | |
92 // TileView message handlers | |
93 | |
94 void TileView::saveBMP(const char *name) | |
95 { | |
96 u8 writeBuffer[1024 * 3]; | |
97 | |
98 FILE *fp = fopen(name, "wb"); | |
99 | |
100 if (!fp) | |
101 { | |
102 systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name); | |
103 return; | |
104 } | |
105 | |
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)); | |
126 | |
127 bmpheader.ident[0] = 'B'; | |
128 bmpheader.ident[1] = 'M'; | |
129 | |
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); | |
139 | |
140 fwrite(&bmpheader, 1, sizeof(bmpheader), fp); | |
141 | |
142 u8 *b = writeBuffer; | |
143 | |
144 int sizeX = w; | |
145 int sizeY = h; | |
146 | |
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); | |
158 | |
159 b = writeBuffer; | |
160 } | |
161 | |
162 fclose(fp); | |
163 } | |
164 | |
165 void TileView::savePNG(const char *name) | |
166 { | |
167 u8 writeBuffer[1024 * 3]; | |
168 | |
169 FILE *fp = fopen(name, "wb"); | |
170 | |
171 if (!fp) | |
172 { | |
173 systemMessage(MSG_ERROR_CREATING_FILE, "Error creating file %s", name); | |
174 return; | |
175 } | |
176 | |
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 } | |
186 | |
187 png_infop info_ptr = png_create_info_struct(png_ptr); | |
188 | |
189 if (!info_ptr) | |
190 { | |
191 png_destroy_write_struct(&png_ptr, NULL); | |
192 fclose(fp); | |
193 return; | |
194 } | |
195 | |
196 if (setjmp(png_ptr->jmpbuf)) | |
197 { | |
198 png_destroy_write_struct(&png_ptr, NULL); | |
199 fclose(fp); | |
200 return; | |
201 } | |
202 | |
203 png_init_io(png_ptr, fp); | |
204 | |
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); | |
214 | |
215 png_write_info(png_ptr, info_ptr); | |
216 | |
217 u8 *b = writeBuffer; | |
218 | |
219 int sizeX = w; | |
220 int sizeY = h; | |
221 | |
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++; | |
230 | |
231 *b++ = red; | |
232 *b++ = green; | |
233 *b++ = blue; | |
234 } | |
235 png_write_row(png_ptr, writeBuffer); | |
236 | |
237 b = writeBuffer; | |
238 } | |
239 | |
240 png_write_end(png_ptr, info_ptr); | |
241 | |
242 png_destroy_write_struct(&png_ptr, &info_ptr); | |
243 | |
244 fclose(fp); | |
245 } | |
246 | |
247 void TileView::OnSave() | |
248 { | |
249 CString captureBuffer; | |
250 | |
251 if (theApp.captureFormat == 0) | |
252 captureBuffer = "tiles.png"; | |
253 else | |
254 captureBuffer = "tiles.bmp"; | |
255 | |
256 LPCTSTR exts[] = {".png", ".bmp", NULL }; | |
257 | |
258 CString filter = winResLoadFilter(IDS_FILTER_PNG); | |
259 CString title = winResLoadString(IDS_SELECT_CAPTURE_NAME); | |
260 | |
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); | |
270 | |
271 if (dlg.DoModal() == IDCANCEL) | |
272 { | |
273 return; | |
274 } | |
275 | |
276 captureBuffer = dlg.GetPathName(); | |
277 | |
278 if (dlg.getFilterIndex() == 2) | |
279 saveBMP(captureBuffer); | |
280 else | |
281 savePNG(captureBuffer); | |
282 } | |
283 | |
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]; | |
287 | |
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]; | |
293 | |
294 u16 color = palette[c]; | |
295 | |
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 } | |
303 | |
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]; | |
307 | |
308 int pal = this->palette; | |
309 | |
310 if (this->charBase == 4) | |
311 pal += 16; | |
312 | |
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)]; | |
318 | |
319 if (i & 1) | |
320 c = c>>4; | |
321 else | |
322 c = c & 15; | |
323 | |
324 u16 color = palette[pal*16+c]; | |
325 | |
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 } | |
333 | |
334 void TileView::render() | |
335 { | |
336 u16 *palette = (u16 *)paletteRAM; | |
337 u8 * charBase = &vram[this->charBase * 0x4000]; | |
338 | |
339 int maxY; | |
340 | |
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 } | |
395 | |
396 void TileView::update() | |
397 { | |
398 paint(); | |
399 } | |
400 | |
401 BOOL TileView::OnInitDialog() | |
402 { | |
403 CDialog::OnInitDialog(); | |
404 | |
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); | |
420 | |
421 m_colors = is256Colors; | |
422 m_charBase = charBase; | |
423 | |
424 m_slider.SetRange(0, 15); | |
425 m_slider.SetPageSize(4); | |
426 m_slider.SetTicFreq(1); | |
427 | |
428 paint(); | |
429 | |
430 m_stretch = regQueryDwordValue("tileViewStretch", 0); | |
431 if (m_stretch) | |
432 tileView.setStretch(true); | |
433 UpdateData(FALSE); | |
434 | |
435 return TRUE; // return TRUE unless you set the focus to a control | |
436 // EXCEPTION: OCX Property Pages should return FALSE | |
437 } | |
438 | |
439 void TileView::OnClose() | |
440 { | |
441 theApp.winRemoveUpdateListener(this); | |
442 | |
443 DestroyWindow(); | |
444 } | |
445 | |
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 } | |
458 | |
459 void TileView::paint() | |
460 { | |
461 if (vram != NULL && paletteRAM != NULL) | |
462 { | |
463 render(); | |
464 tileView.refresh(); | |
465 } | |
466 } | |
467 | |
468 void TileView::On16Colors() | |
469 { | |
470 is256Colors = 0; | |
471 paint(); | |
472 } | |
473 | |
474 void TileView::On256Colors() | |
475 { | |
476 is256Colors = 1; | |
477 paint(); | |
478 } | |
479 | |
480 void TileView::OnCharbase0() | |
481 { | |
482 charBase = 0; | |
483 paint(); | |
484 } | |
485 | |
486 void TileView::OnCharbase1() | |
487 { | |
488 charBase = 1; | |
489 paint(); | |
490 } | |
491 | |
492 void TileView::OnCharbase2() | |
493 { | |
494 charBase = 2; | |
495 paint(); | |
496 } | |
497 | |
498 void TileView::OnCharbase3() | |
499 { | |
500 charBase = 3; | |
501 paint(); | |
502 } | |
503 | |
504 void TileView::OnCharbase4() | |
505 { | |
506 charBase = 4; | |
507 paint(); | |
508 } | |
509 | |
510 void TileView::OnStretch() | |
511 { | |
512 tileView.setStretch(!tileView.getStretch()); | |
513 paint(); | |
514 regSetDwordValue("tileViewStretch", tileView.getStretch()); | |
515 } | |
516 | |
517 LRESULT TileView::OnMapInfo(WPARAM wParam, LPARAM lParam) | |
518 { | |
519 u8 *colors = (u8 *)lParam; | |
520 zoom.setColors(colors); | |
521 | |
522 int x = (wParam & 0xFFFF)/8; | |
523 int y = ((wParam >> 16) & 0xFFFF)/8; | |
524 | |
525 u32 address = 0x6000000 + 0x4000 * charBase; | |
526 int tile = 32 * y + x; | |
527 if (is256Colors) | |
528 tile *= 2; | |
529 address += 32 * tile; | |
530 | |
531 CString buffer; | |
532 buffer.Format("%d", tile); | |
533 GetDlgItem(IDC_TILE_NUMBER)->SetWindowText(buffer); | |
534 | |
535 buffer.Format("%08x", address); | |
536 GetDlgItem(IDC_ADDRESS)->SetWindowText(buffer); | |
537 | |
538 return TRUE; | |
539 } | |
540 | |
541 LRESULT TileView::OnColInfo(WPARAM wParam, LPARAM) | |
542 { | |
543 u16 c = (u16)wParam; | |
544 | |
545 color.setColor(c); | |
546 | |
547 int r = (c & 0x1f); | |
548 int g = (c & 0x3e0) >> 5; | |
549 int b = (c & 0x7c00) >> 10; | |
550 | |
551 CString buffer; | |
552 buffer.Format("R: %d", r); | |
553 GetDlgItem(IDC_R)->SetWindowText(buffer); | |
554 | |
555 buffer.Format("G: %d", g); | |
556 GetDlgItem(IDC_G)->SetWindowText(buffer); | |
557 | |
558 buffer.Format("B: %d", b); | |
559 GetDlgItem(IDC_B)->SetWindowText(buffer); | |
560 | |
561 return TRUE; | |
562 } | |
563 | |
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 } | |
577 | |
578 void TileView::PostNcDestroy() | |
579 { | |
580 delete this; | |
581 } | |
582 |