5 #include "../../pico/pico.h"
\r
6 #include "../common/readpng.h"
\r
7 #include "../common/config.h"
\r
8 #include "../common/lprintf.h"
\r
9 #include "../common/emu.h"
\r
10 #include "../common/menu.h"
\r
11 #include "../common/input.h"
\r
12 #include "../common/plat.h"
\r
13 #include "version.h"
\r
20 RECT EmuScreenRect = { 0, 0, 320, 224 };
\r
21 int lock_to_1_1 = 1;
\r
22 static HWND PicoSwWnd=NULL, PicoPadWnd=NULL;
\r
24 static HMENU mmain = 0, mdisplay = 0, mpicohw = 0;
\r
25 static HBITMAP ppad_bmp = 0;
\r
26 static HBITMAP ppage_bmps[7] = { 0, };
\r
27 static char rom_name[0x20*3+1];
\r
28 static int main_wnd_as_pad = 0;
\r
30 static HANDLE loop_enter_event, loop_end_event;
\r
32 void error(char *text)
\r
34 MessageBox(FrameWnd, text, "Error", 0);
\r
37 static void UpdateRect(void)
\r
40 memset(&wi, 0, sizeof(wi));
\r
41 wi.cbSize = sizeof(wi);
\r
42 GetWindowInfo(FrameWnd, &wi);
\r
43 FrameRectMy = wi.rcClient;
\r
46 static int extract_rom_name(char *dest, const unsigned char *src, int len)
\r
48 char *p = dest, s_old = 0x20;
\r
51 for (i = len - 1; i >= 0; i--)
\r
53 if (src[i^1] != ' ') break;
\r
57 for (i = 0; i < len; i++)
\r
59 unsigned char s = src[i^1];
\r
60 if (s == 0x20 && s_old == 0x20) continue;
\r
61 else if (s >= 0x20 && s < 0x7f && s != '%')
\r
67 sprintf(p, "%%%02x", s);
\r
77 static void check_name_alias(const char *afname)
\r
79 char buff[256], *var, *val;
\r
83 f = fopen(afname, "r");
\r
84 if (f == NULL) return;
\r
88 ret = config_get_var_val(f, buff, sizeof(buff), &var, &val);
\r
89 if (ret == 0) break;
\r
90 if (ret == -1) continue;
\r
92 if (strcmp(rom_name, var) == 0) {
\r
93 lprintf("rom aliased: \"%s\" -> \"%s\"\n", rom_name, val);
\r
94 strncpy(rom_name, val, sizeof(rom_name));
\r
101 static HBITMAP png2hb(const char *fname, int is_480)
\r
103 BITMAPINFOHEADER bih;
\r
108 bmem = calloc(1, is_480 ? 480*240*3 : 320*240*3);
\r
109 if (bmem == NULL) return NULL;
\r
110 ret = readpng(bmem, fname, is_480 ? READPNG_480_24 : READPNG_320_24);
\r
116 memset(&bih, 0, sizeof(bih));
\r
117 bih.biSize = sizeof(bih);
\r
118 bih.biWidth = is_480 ? 480 : 320;
\r
119 bih.biHeight = -240;
\r
121 bih.biBitCount = 24;
\r
122 bih.biCompression = BI_RGB;
\r
123 bmp = CreateDIBitmap(GetDC(FrameWnd), &bih, CBM_INIT, bmem, (BITMAPINFO *)&bih, 0);
\r
125 lprintf("CreateDIBitmap failed with %i", GetLastError());
\r
131 static void PrepareForROM(void)
\r
133 unsigned char *rom_data = NULL;
\r
134 int i, ret, show = PicoAHW & PAHW_PICO;
\r
136 PicoGetInternal(PI_ROM, (pint_ret_t *) &rom_data);
\r
137 EnableMenuItem(mmain, 2, MF_BYPOSITION|(show ? MF_ENABLED : MF_GRAYED));
\r
138 ShowWindow(PicoPadWnd, show ? SW_SHOWNA : SW_HIDE);
\r
139 ShowWindow(PicoSwWnd, show ? SW_SHOWNA : SW_HIDE);
\r
140 CheckMenuItem(mpicohw, 1210, show ? MF_CHECKED : MF_UNCHECKED);
\r
141 CheckMenuItem(mpicohw, 1211, show ? MF_CHECKED : MF_UNCHECKED);
\r
142 PostMessage(FrameWnd, WM_COMMAND, 1220 + PicoPicohw.page, 0);
\r
143 DrawMenuBar(FrameWnd);
\r
144 InvalidateRect(PicoSwWnd, NULL, 1);
\r
146 PicoPicohw.pen_pos[0] =
\r
147 PicoPicohw.pen_pos[1] = 0x8000;
\r
148 in_vk_add_pl12 = 0;
\r
150 ret = extract_rom_name(rom_name, rom_data + 0x150, 0x20);
\r
152 extract_rom_name(rom_name, rom_data + 0x130, 0x20);
\r
156 char path[MAX_PATH], *p;
\r
157 GetModuleFileName(NULL, path, sizeof(path) - 32);
\r
158 p = strrchr(path, '\\');
\r
159 if (p == NULL) p = path;
\r
161 if (ppad_bmp == NULL) {
\r
162 strcpy(p, "pico\\pad.png");
\r
163 ppad_bmp = png2hb(path, 0);
\r
166 strcpy(p, "pico\\alias.txt");
\r
167 check_name_alias(path);
\r
169 for (i = 0; i < 7; i++) {
\r
170 if (ppage_bmps[i] != NULL) DeleteObject(ppage_bmps[i]);
\r
171 sprintf(p, "pico\\%s_%i.png", rom_name, i);
\r
172 ppage_bmps[i] = png2hb(path, 1);
\r
174 // games usually don't have page 6, so just duplicate page 5.
\r
175 if (ppage_bmps[6] == NULL && ppage_bmps[5] != NULL) {
\r
176 sprintf(p, "pico\\%s_5.png", rom_name);
\r
177 ppage_bmps[6] = png2hb(path, 1);
\r
182 static void LoadROM(const char *cmdpath)
\r
184 char rompath[MAX_PATH];
\r
187 if (cmdpath != NULL && strlen(cmdpath)) {
\r
188 strcpy(rompath, cmdpath + (cmdpath[0] == '\"' ? 1 : 0));
\r
189 if (rompath[strlen(rompath)-1] == '\"')
\r
190 rompath[strlen(rompath)-1] = 0;
\r
193 OPENFILENAME of; ZeroMemory(&of, sizeof(of));
\r
194 rompath[sizeof(rompath) - 1] = 0;
\r
195 strncpy(rompath, rom_fname_loaded, sizeof(rompath) - 1);
\r
196 of.lStructSize = sizeof(of);
\r
197 of.lpstrFilter = "ROMs, CD images\0*.smd;*.bin;*.gen;*.zip;*.32x;*.sms;*.iso;*.cso;*.cue\0"
\r
199 of.lpstrFile = rompath;
\r
200 of.nMaxFile = MAX_PATH;
\r
201 of.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY;
\r
202 of.hwndOwner = FrameWnd;
\r
203 if (!GetOpenFileName(&of))
\r
207 if (engineState == PGS_Running) {
\r
208 engineState = PGS_Paused;
\r
209 WaitForSingleObject(loop_end_event, 5000);
\r
212 ret = emu_reload_rom(rompath);
\r
214 extern char menu_error_msg[]; // HACK..
\r
215 error(menu_error_msg);
\r
220 engineState = PGS_Running;
\r
221 SetEvent(loop_enter_event);
\r
224 static const int rect_widths[4] = { 320, 256, 640, 512 };
\r
225 static const int rect_heights[4] = { 224, 224, 448, 448 };
\r
227 // Window proc for the frame window:
\r
228 static LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
\r
236 PostQuitMessage(0);
\r
239 FrameWnd = NULL; // Blank the handle
\r
245 if (lock_to_1_1 && FrameRectMy.right - FrameRectMy.left != 0 &&
\r
246 (FrameRectMy.right - FrameRectMy.left != EmuScreenRect.right - EmuScreenRect.left ||
\r
247 FrameRectMy.bottom - FrameRectMy.top != EmuScreenRect.bottom - EmuScreenRect.top)) {
\r
249 CheckMenuItem(mdisplay, 1104, MF_UNCHECKED);
\r
253 switch (LOWORD(wparam))
\r
262 PostQuitMessage(0);
\r
268 // LoopWait=1; // another sync hack
\r
269 // for (i = 0; !LoopWaiting && i < 10; i++) Sleep(10);
\r
270 FrameRectMy.right = FrameRectMy.left + rect_widths[wparam&3];
\r
271 FrameRectMy.bottom = FrameRectMy.top + rect_heights[wparam&3];
\r
272 AdjustWindowRect(&FrameRectMy, WS_OVERLAPPEDWINDOW, 1);
\r
273 MoveWindow(hwnd, FrameRectMy.left, FrameRectMy.top,
\r
274 FrameRectMy.right-FrameRectMy.left, FrameRectMy.bottom-FrameRectMy.top, 1);
\r
277 CheckMenuItem(mdisplay, 1104, MF_UNCHECKED);
\r
278 // if (rom_loaded) LoopWait=0;
\r
281 lock_to_1_1 = !lock_to_1_1;
\r
282 CheckMenuItem(mdisplay, 1104, lock_to_1_1 ? MF_CHECKED : MF_UNCHECKED);
\r
284 case 2000: // EmuScreenRect/FrameRectMy sync request
\r
287 FrameRectMy.right = FrameRectMy.left + (EmuScreenRect.right - EmuScreenRect.left);
\r
288 FrameRectMy.bottom = FrameRectMy.top + (EmuScreenRect.bottom - EmuScreenRect.top);
\r
289 AdjustWindowRect(&FrameRectMy, WS_OVERLAPPEDWINDOW, 1);
\r
290 MoveWindow(hwnd, FrameRectMy.left, FrameRectMy.top,
\r
291 FrameRectMy.right-FrameRectMy.left, FrameRectMy.bottom-FrameRectMy.top, 1);
\r
296 i = IsWindowVisible((LOWORD(wparam)&1) ? PicoPadWnd : PicoSwWnd);
\r
298 ShowWindow((LOWORD(wparam)&1) ? PicoPadWnd : PicoSwWnd, i ? SW_SHOWNA : SW_HIDE);
\r
299 CheckMenuItem(mpicohw, LOWORD(wparam), i ? MF_CHECKED : MF_UNCHECKED);
\r
302 main_wnd_as_pad = !main_wnd_as_pad;
\r
303 CheckMenuItem(mpicohw, 1212, main_wnd_as_pad ? MF_CHECKED : MF_UNCHECKED);
\r
312 PicoPicohw.page = LOWORD(wparam) % 10;
\r
313 for (i = 0; i < 7; i++)
\r
314 CheckMenuItem(mpicohw, 1220 + i, MF_UNCHECKED);
\r
315 CheckMenuItem(mpicohw, 1220 + PicoPicohw.page, MF_CHECKED);
\r
316 InvalidateRect(PicoSwWnd, NULL, 1);
\r
319 MessageBox(FrameWnd, plat_get_credits(), "About", 0);
\r
325 GetWindowRect(PicoSwWnd, &rc);
\r
326 if (PtInRect(&rc, pt)) break;
\r
327 GetWindowRect(PicoPadWnd, &rc);
\r
328 if (PtInRect(&rc, pt)) break;
\r
329 PicoPicohw.pen_pos[0] |= 0x8000;
\r
330 PicoPicohw.pen_pos[1] |= 0x8000;
\r
331 in_vk_add_pl12 = 0;
\r
333 case WM_LBUTTONDOWN: in_vk_add_pl12 |= 0x20; return 0;
\r
334 case WM_LBUTTONUP: in_vk_add_pl12 &= ~0x20; return 0;
\r
336 if (!main_wnd_as_pad) break;
\r
337 PicoPicohw.pen_pos[0] = 0x03c + (320 * LOWORD(lparam) / (FrameRectMy.right - FrameRectMy.left));
\r
338 PicoPicohw.pen_pos[1] = 0x1fc + (232 * HIWORD(lparam) / (FrameRectMy.bottom - FrameRectMy.top));
\r
339 SetTimer(FrameWnd, 100, 1000, NULL);
\r
342 if (wparam == VK_TAB) {
\r
346 if (wparam == VK_ESCAPE) {
\r
350 in_vk_keydown(wparam);
\r
353 in_vk_keyup(wparam);
\r
357 return DefWindowProc(hwnd,msg,wparam,lparam);
\r
360 static LRESULT CALLBACK PicoSwWndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
\r
367 case WM_DESTROY: PicoSwWnd=NULL; break;
\r
368 case WM_LBUTTONDOWN: in_vk_add_pl12 |= 0x20; return 0;
\r
369 case WM_LBUTTONUP: in_vk_add_pl12 &= ~0x20; return 0;
\r
371 if (HIWORD(lparam) < 0x20) break;
\r
372 PicoPicohw.pen_pos[0] = 0x03c + LOWORD(lparam) * 2/3;
\r
373 PicoPicohw.pen_pos[1] = 0x2f8 + HIWORD(lparam) - 0x20;
\r
374 SetTimer(FrameWnd, 100, 1000, NULL);
\r
376 case WM_KEYDOWN: in_vk_keydown(wparam); break;
\r
377 case WM_KEYUP: in_vk_keyup(wparam); break;
\r
379 hdc = BeginPaint(hwnd, &ps);
\r
380 if (ppage_bmps[PicoPicohw.page] == NULL)
\r
382 SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT));
\r
383 SetTextColor(hdc, RGB(255, 255, 255));
\r
384 SetBkColor(hdc, RGB(0, 0, 0));
\r
385 TextOut(hdc, 2, 2, "missing PNGs for", 16);
\r
386 TextOut(hdc, 2, 18, rom_name, strlen(rom_name));
\r
390 hdc2 = CreateCompatibleDC(GetDC(FrameWnd));
\r
391 SelectObject(hdc2, ppage_bmps[PicoPicohw.page]);
\r
392 BitBlt(hdc, 0, 0, 480, 240, hdc2, 0, 0, SRCCOPY);
\r
395 EndPaint(hwnd, &ps);
\r
398 ShowWindow(hwnd, SW_HIDE);
\r
399 CheckMenuItem(mpicohw, 1210, MF_UNCHECKED);
\r
403 return DefWindowProc(hwnd,msg,wparam,lparam);
\r
406 static LRESULT CALLBACK PicoPadWndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam)
\r
413 case WM_DESTROY: PicoPadWnd=NULL; break;
\r
414 case WM_LBUTTONDOWN: in_vk_add_pl12 |= 0x20; return 0;
\r
415 case WM_LBUTTONUP: in_vk_add_pl12 &= ~0x20; return 0;
\r
417 PicoPicohw.pen_pos[0] = 0x03c + LOWORD(lparam);
\r
418 PicoPicohw.pen_pos[1] = 0x1fc + HIWORD(lparam);
\r
419 SetTimer(FrameWnd, 100, 1000, NULL);
\r
421 case WM_KEYDOWN: in_vk_keydown(wparam); break;
\r
422 case WM_KEYUP: in_vk_keyup(wparam); break;
\r
424 if (ppad_bmp == NULL) break;
\r
425 hdc = BeginPaint(hwnd, &ps);
\r
426 hdc2 = CreateCompatibleDC(GetDC(FrameWnd));
\r
427 SelectObject(hdc2, ppad_bmp);
\r
428 BitBlt(hdc, 0, 0, 320, 240, hdc2, 0, 0, SRCCOPY);
\r
429 EndPaint(hwnd, &ps);
\r
433 ShowWindow(hwnd, SW_HIDE);
\r
434 CheckMenuItem(mpicohw, 1211, MF_UNCHECKED);
\r
438 return DefWindowProc(hwnd,msg,wparam,lparam);
\r
442 static int FrameInit()
\r
445 RECT rect={0,0,0,0};
\r
448 int left=0,top=0,width=0,height=0;
\r
450 memset(&wc,0,sizeof(wc));
\r
452 // Register the window class:
\r
453 wc.lpfnWndProc=WndProc;
\r
454 wc.hInstance=GetModuleHandle(NULL);
\r
455 wc.hCursor=LoadCursor(NULL,IDC_ARROW);
\r
456 wc.hbrBackground=CreateSolidBrush(0);
\r
457 wc.lpszClassName="PicoMainFrame";
\r
458 RegisterClass(&wc);
\r
460 wc.lpszClassName="PicoSwWnd";
\r
461 wc.lpfnWndProc=PicoSwWndProc;
\r
462 RegisterClass(&wc);
\r
464 wc.lpszClassName="PicoPadWnd";
\r
465 wc.lpfnWndProc=PicoPadWndProc;
\r
466 RegisterClass(&wc);
\r
471 // Adjust size of windows based on borders:
\r
472 style=WS_OVERLAPPEDWINDOW;
\r
473 AdjustWindowRect(&rect,style,1);
\r
474 width =rect.right-rect.left;
\r
475 height=rect.bottom-rect.top;
\r
477 // Place window in the centre of the screen:
\r
478 SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0);
\r
479 left=rect.left+rect.right;
\r
480 top=rect.top+rect.bottom;
\r
482 left-=width; left>>=1;
\r
483 top-=height; top>>=1;
\r
486 mfile = CreateMenu();
\r
487 InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1000, "&Load ROM");
\r
488 InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1001, "&Reset");
\r
489 InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1002, "E&xit");
\r
490 mdisplay = CreateMenu();
\r
491 InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1100, "320x224");
\r
492 InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1101, "256x224");
\r
493 InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1102, "640x448");
\r
494 InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1103, "512x448");
\r
495 InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1104, "Lock to 1:1");
\r
496 mpicohw = CreateMenu();
\r
497 InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1210, "Show &Storyware");
\r
498 InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1211, "Show &Drawing pad");
\r
499 InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1212, "&Main window as pad");
\r
500 InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL);
\r
501 InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1220, "Title page (&0)");
\r
502 InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1221, "Page &1");
\r
503 InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1222, "Page &2");
\r
504 InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1223, "Page &3");
\r
505 InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1224, "Page &4");
\r
506 InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1225, "Page &5");
\r
507 InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1226, "Page &6");
\r
508 mmain = CreateMenu();
\r
509 InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mfile, "&File");
\r
510 InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mdisplay, "&Display");
\r
511 InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mpicohw, "&Pico");
\r
512 EnableMenuItem(mmain, 2, MF_BYPOSITION|MF_GRAYED);
\r
513 // InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, 1200, "&Config");
\r
514 InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING, 1300, "&About");
\r
516 // Create the window:
\r
517 FrameWnd=CreateWindow("PicoMainFrame","PicoDrive " VERSION,style|WS_VISIBLE,
\r
518 left,top,width,height,NULL,mmain,NULL,NULL);
\r
520 CheckMenuItem(mdisplay, 1104, lock_to_1_1 ? MF_CHECKED : MF_UNCHECKED);
\r
521 ShowWindow(FrameWnd, SW_NORMAL);
\r
522 UpdateWindow(FrameWnd);
\r
525 // create Pico windows
\r
526 style = WS_OVERLAPPED|WS_CAPTION|WS_BORDER|WS_SYSMENU;
\r
527 rect.left=rect.top=0;
\r
531 AdjustWindowRect(&rect,style,1);
\r
532 width =rect.right-rect.left;
\r
533 height=rect.bottom-rect.top;
\r
536 PicoSwWnd=CreateWindow("PicoSwWnd","Storyware",style,
\r
537 left,top,width+160,height,FrameWnd,NULL,NULL,NULL);
\r
540 PicoPadWnd=CreateWindow("PicoPadWnd","Drawing Pad",style,
\r
541 left,top,width,height,FrameWnd,NULL,NULL,NULL);
\r
546 // --------------------
\r
548 static DWORD WINAPI work_thread(void *x)
\r
550 while (engineState != PGS_Quit) {
\r
551 WaitForSingleObject(loop_enter_event, INFINITE);
\r
552 if (engineState != PGS_Running)
\r
555 printf("loop..\n");
\r
557 SetEvent(loop_end_event);
\r
566 /* in_init() must go before config, config accesses in_ fwk */
\r
568 pemu_prep_defconfig();
\r
569 emu_read_config(0, 0);
\r
570 config_readlrom(PicoConfigFile);
\r
580 int WINAPI WinMain(HINSTANCE p1, HINSTANCE p2, LPSTR cmdline, int p4)
\r
589 ret = DirectInit();
\r
593 loop_enter_event = CreateEvent(NULL, 0, 0, NULL);
\r
594 if (loop_enter_event == NULL)
\r
597 loop_end_event = CreateEvent(NULL, 0, 0, NULL);
\r
598 if (loop_end_event == NULL)
\r
601 thread = CreateThread(NULL, 0, work_thread, NULL, 0, &tid);
\r
602 if (thread == NULL)
\r
607 // Main window loop:
\r
610 GetMessage(&msg,NULL,0,0);
\r
611 if (msg.message==WM_QUIT) break;
\r
613 TranslateMessage(&msg);
\r
614 DispatchMessage(&msg);
\r
617 // Signal thread to quit and wait for it to exit:
\r
618 if (engineState == PGS_Running) {
\r
619 engineState = PGS_Quit;
\r
620 WaitForSingleObject(loop_end_event, 5000);
\r
622 CloseHandle(thread); thread=NULL;
\r
624 emu_write_config(0);
\r
630 DestroyWindow(FrameWnd);
\r
632 // _CrtDumpMemoryLeaks();
\r