X-Git-Url: https://notaz.gp2x.de/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=win32%2Fmain.c;fp=win32%2Fmain.c;h=17191e269deb2fed5c6b01dcfc02f5a5fe055aff;hb=8ced8d2b38431e23be1b26457110febbe10d14c7;hp=0000000000000000000000000000000000000000;hpb=6c026031a80434cda8499e2208538e0155466d6b;p=libpicofe.git diff --git a/win32/main.c b/win32/main.c new file mode 100644 index 0000000..17191e2 --- /dev/null +++ b/win32/main.c @@ -0,0 +1,635 @@ +#include +#include +#include + +#include "../../pico/pico.h" +#include "../common/readpng.h" +#include "../common/config.h" +#include "../common/lprintf.h" +#include "../common/emu.h" +#include "../common/menu.h" +#include "../common/input.h" +#include "../common/plat.h" +#include "version.h" +#include "direct.h" +#include "in_vk.h" + +char *romname=NULL; +HWND FrameWnd=NULL; +RECT FrameRectMy; +RECT EmuScreenRect = { 0, 0, 320, 224 }; +int lock_to_1_1 = 1; +static HWND PicoSwWnd=NULL, PicoPadWnd=NULL; + +static HMENU mmain = 0, mdisplay = 0, mpicohw = 0; +static HBITMAP ppad_bmp = 0; +static HBITMAP ppage_bmps[7] = { 0, }; +static char rom_name[0x20*3+1]; +static int main_wnd_as_pad = 0; + +static HANDLE loop_enter_event, loop_end_event; + +void error(char *text) +{ + MessageBox(FrameWnd, text, "Error", 0); +} + +static void UpdateRect(void) +{ + WINDOWINFO wi; + memset(&wi, 0, sizeof(wi)); + wi.cbSize = sizeof(wi); + GetWindowInfo(FrameWnd, &wi); + FrameRectMy = wi.rcClient; +} + +static int extract_rom_name(char *dest, const unsigned char *src, int len) +{ + char *p = dest, s_old = 0x20; + int i; + + for (i = len - 1; i >= 0; i--) + { + if (src[i^1] != ' ') break; + } + len = i + 1; + + for (i = 0; i < len; i++) + { + unsigned char s = src[i^1]; + if (s == 0x20 && s_old == 0x20) continue; + else if (s >= 0x20 && s < 0x7f && s != '%') + { + *p++ = s; + } + else + { + sprintf(p, "%%%02x", s); + p += 3; + } + s_old = s; + } + *p = 0; + + return p - dest; +} + +static void check_name_alias(const char *afname) +{ + char buff[256], *var, *val; + FILE *f; + int ret; + + f = fopen(afname, "r"); + if (f == NULL) return; + + while (1) + { + ret = config_get_var_val(f, buff, sizeof(buff), &var, &val); + if (ret == 0) break; + if (ret == -1) continue; + + if (strcmp(rom_name, var) == 0) { + lprintf("rom aliased: \"%s\" -> \"%s\"\n", rom_name, val); + strncpy(rom_name, val, sizeof(rom_name)); + break; + } + } + fclose(f); +} + +static HBITMAP png2hb(const char *fname, int is_480) +{ + BITMAPINFOHEADER bih; + HBITMAP bmp; + void *bmem; + int ret; + + bmem = calloc(1, is_480 ? 480*240*3 : 320*240*3); + if (bmem == NULL) return NULL; + ret = readpng(bmem, fname, is_480 ? READPNG_480_24 : READPNG_320_24); + if (ret != 0) { + free(bmem); + return NULL; + } + + memset(&bih, 0, sizeof(bih)); + bih.biSize = sizeof(bih); + bih.biWidth = is_480 ? 480 : 320; + bih.biHeight = -240; + bih.biPlanes = 1; + bih.biBitCount = 24; + bih.biCompression = BI_RGB; + bmp = CreateDIBitmap(GetDC(FrameWnd), &bih, CBM_INIT, bmem, (BITMAPINFO *)&bih, 0); + if (bmp == NULL) + lprintf("CreateDIBitmap failed with %i", GetLastError()); + + free(bmem); + return bmp; +} + +static void PrepareForROM(void) +{ + unsigned char *rom_data = NULL; + int i, ret, show = PicoAHW & PAHW_PICO; + + PicoGetInternal(PI_ROM, (pint_ret_t *) &rom_data); + EnableMenuItem(mmain, 2, MF_BYPOSITION|(show ? MF_ENABLED : MF_GRAYED)); + ShowWindow(PicoPadWnd, show ? SW_SHOWNA : SW_HIDE); + ShowWindow(PicoSwWnd, show ? SW_SHOWNA : SW_HIDE); + CheckMenuItem(mpicohw, 1210, show ? MF_CHECKED : MF_UNCHECKED); + CheckMenuItem(mpicohw, 1211, show ? MF_CHECKED : MF_UNCHECKED); + PostMessage(FrameWnd, WM_COMMAND, 1220 + PicoPicohw.page, 0); + DrawMenuBar(FrameWnd); + InvalidateRect(PicoSwWnd, NULL, 1); + + PicoPicohw.pen_pos[0] = + PicoPicohw.pen_pos[1] = 0x8000; + in_vk_add_pl12 = 0; + + ret = extract_rom_name(rom_name, rom_data + 0x150, 0x20); + if (ret == 0) + extract_rom_name(rom_name, rom_data + 0x130, 0x20); + + if (show) + { + char path[MAX_PATH], *p; + GetModuleFileName(NULL, path, sizeof(path) - 32); + p = strrchr(path, '\\'); + if (p == NULL) p = path; + else p++; + if (ppad_bmp == NULL) { + strcpy(p, "pico\\pad.png"); + ppad_bmp = png2hb(path, 0); + } + + strcpy(p, "pico\\alias.txt"); + check_name_alias(path); + + for (i = 0; i < 7; i++) { + if (ppage_bmps[i] != NULL) DeleteObject(ppage_bmps[i]); + sprintf(p, "pico\\%s_%i.png", rom_name, i); + ppage_bmps[i] = png2hb(path, 1); + } + // games usually don't have page 6, so just duplicate page 5. + if (ppage_bmps[6] == NULL && ppage_bmps[5] != NULL) { + sprintf(p, "pico\\%s_5.png", rom_name); + ppage_bmps[6] = png2hb(path, 1); + } + } +} + +static void LoadROM(const char *cmdpath) +{ + char rompath[MAX_PATH]; + int ret; + + if (cmdpath != NULL && strlen(cmdpath)) { + strcpy(rompath, cmdpath + (cmdpath[0] == '\"' ? 1 : 0)); + if (rompath[strlen(rompath)-1] == '\"') + rompath[strlen(rompath)-1] = 0; + } + else { + OPENFILENAME of; ZeroMemory(&of, sizeof(of)); + rompath[sizeof(rompath) - 1] = 0; + strncpy(rompath, rom_fname_loaded, sizeof(rompath) - 1); + of.lStructSize = sizeof(of); + of.lpstrFilter = "ROMs, CD images\0*.smd;*.bin;*.gen;*.zip;*.32x;*.sms;*.iso;*.cso;*.cue\0" + "whatever\0*.*\0"; + of.lpstrFile = rompath; + of.nMaxFile = MAX_PATH; + of.Flags = OFN_FILEMUSTEXIST|OFN_HIDEREADONLY; + of.hwndOwner = FrameWnd; + if (!GetOpenFileName(&of)) + return; + } + + if (engineState == PGS_Running) { + engineState = PGS_Paused; + WaitForSingleObject(loop_end_event, 5000); + } + + ret = emu_reload_rom(rompath); + if (ret == 0) { + extern char menu_error_msg[]; // HACK.. + error(menu_error_msg); + return; + } + + PrepareForROM(); + engineState = PGS_Running; + SetEvent(loop_enter_event); +} + +static const int rect_widths[4] = { 320, 256, 640, 512 }; +static const int rect_heights[4] = { 224, 224, 448, 448 }; + +// Window proc for the frame window: +static LRESULT CALLBACK WndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam) +{ + POINT pt; + RECT rc; + int i; + switch (msg) + { + case WM_CLOSE: + PostQuitMessage(0); + return 0; + case WM_DESTROY: + FrameWnd = NULL; // Blank the handle + break; + case WM_SIZE: + case WM_MOVE: + case WM_SIZING: + UpdateRect(); + if (lock_to_1_1 && FrameRectMy.right - FrameRectMy.left != 0 && + (FrameRectMy.right - FrameRectMy.left != EmuScreenRect.right - EmuScreenRect.left || + FrameRectMy.bottom - FrameRectMy.top != EmuScreenRect.bottom - EmuScreenRect.top)) { + lock_to_1_1 = 0; + CheckMenuItem(mdisplay, 1104, MF_UNCHECKED); + } + break; + case WM_COMMAND: + switch (LOWORD(wparam)) + { + case 1000: + LoadROM(NULL); + break; + case 1001: + emu_reset_game(); + return 0; + case 1002: + PostQuitMessage(0); + return 0; + case 1100: + case 1101: + case 1102: + case 1103: +// LoopWait=1; // another sync hack +// for (i = 0; !LoopWaiting && i < 10; i++) Sleep(10); + FrameRectMy.right = FrameRectMy.left + rect_widths[wparam&3]; + FrameRectMy.bottom = FrameRectMy.top + rect_heights[wparam&3]; + AdjustWindowRect(&FrameRectMy, WS_OVERLAPPEDWINDOW, 1); + MoveWindow(hwnd, FrameRectMy.left, FrameRectMy.top, + FrameRectMy.right-FrameRectMy.left, FrameRectMy.bottom-FrameRectMy.top, 1); + UpdateRect(); + lock_to_1_1 = 0; + CheckMenuItem(mdisplay, 1104, MF_UNCHECKED); +// if (rom_loaded) LoopWait=0; + return 0; + case 1104: + lock_to_1_1 = !lock_to_1_1; + CheckMenuItem(mdisplay, 1104, lock_to_1_1 ? MF_CHECKED : MF_UNCHECKED); + /* FALLTHROUGH */ + case 2000: // EmuScreenRect/FrameRectMy sync request + if (!lock_to_1_1) + return 0; + FrameRectMy.right = FrameRectMy.left + (EmuScreenRect.right - EmuScreenRect.left); + FrameRectMy.bottom = FrameRectMy.top + (EmuScreenRect.bottom - EmuScreenRect.top); + AdjustWindowRect(&FrameRectMy, WS_OVERLAPPEDWINDOW, 1); + MoveWindow(hwnd, FrameRectMy.left, FrameRectMy.top, + FrameRectMy.right-FrameRectMy.left, FrameRectMy.bottom-FrameRectMy.top, 1); + UpdateRect(); + return 0; + case 1210: + case 1211: + i = IsWindowVisible((LOWORD(wparam)&1) ? PicoPadWnd : PicoSwWnd); + i = !i; + ShowWindow((LOWORD(wparam)&1) ? PicoPadWnd : PicoSwWnd, i ? SW_SHOWNA : SW_HIDE); + CheckMenuItem(mpicohw, LOWORD(wparam), i ? MF_CHECKED : MF_UNCHECKED); + return 0; + case 1212: + main_wnd_as_pad = !main_wnd_as_pad; + CheckMenuItem(mpicohw, 1212, main_wnd_as_pad ? MF_CHECKED : MF_UNCHECKED); + return 0; + case 1220: + case 1221: + case 1222: + case 1223: + case 1224: + case 1225: + case 1226: + PicoPicohw.page = LOWORD(wparam) % 10; + for (i = 0; i < 7; i++) + CheckMenuItem(mpicohw, 1220 + i, MF_UNCHECKED); + CheckMenuItem(mpicohw, 1220 + PicoPicohw.page, MF_CHECKED); + InvalidateRect(PicoSwWnd, NULL, 1); + return 0; + case 1300: + MessageBox(FrameWnd, plat_get_credits(), "About", 0); + return 0; + } + break; + case WM_TIMER: + GetCursorPos(&pt); + GetWindowRect(PicoSwWnd, &rc); + if (PtInRect(&rc, pt)) break; + GetWindowRect(PicoPadWnd, &rc); + if (PtInRect(&rc, pt)) break; + PicoPicohw.pen_pos[0] |= 0x8000; + PicoPicohw.pen_pos[1] |= 0x8000; + in_vk_add_pl12 = 0; + break; + case WM_LBUTTONDOWN: in_vk_add_pl12 |= 0x20; return 0; + case WM_LBUTTONUP: in_vk_add_pl12 &= ~0x20; return 0; + case WM_MOUSEMOVE: + if (!main_wnd_as_pad) break; + PicoPicohw.pen_pos[0] = 0x03c + (320 * LOWORD(lparam) / (FrameRectMy.right - FrameRectMy.left)); + PicoPicohw.pen_pos[1] = 0x1fc + (232 * HIWORD(lparam) / (FrameRectMy.bottom - FrameRectMy.top)); + SetTimer(FrameWnd, 100, 1000, NULL); + break; + case WM_KEYDOWN: + if (wparam == VK_TAB) { + emu_reset_game(); + break; + } + if (wparam == VK_ESCAPE) { + LoadROM(NULL); + break; + } + in_vk_keydown(wparam); + break; + case WM_KEYUP: + in_vk_keyup(wparam); + break; + } + + return DefWindowProc(hwnd,msg,wparam,lparam); +} + +static LRESULT CALLBACK PicoSwWndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam) +{ + PAINTSTRUCT ps; + HDC hdc, hdc2; + + switch (msg) + { + case WM_DESTROY: PicoSwWnd=NULL; break; + case WM_LBUTTONDOWN: in_vk_add_pl12 |= 0x20; return 0; + case WM_LBUTTONUP: in_vk_add_pl12 &= ~0x20; return 0; + case WM_MOUSEMOVE: + if (HIWORD(lparam) < 0x20) break; + PicoPicohw.pen_pos[0] = 0x03c + LOWORD(lparam) * 2/3; + PicoPicohw.pen_pos[1] = 0x2f8 + HIWORD(lparam) - 0x20; + SetTimer(FrameWnd, 100, 1000, NULL); + break; + case WM_KEYDOWN: in_vk_keydown(wparam); break; + case WM_KEYUP: in_vk_keyup(wparam); break; + case WM_PAINT: + hdc = BeginPaint(hwnd, &ps); + if (ppage_bmps[PicoPicohw.page] == NULL) + { + SelectObject(hdc, GetStockObject(DEFAULT_GUI_FONT)); + SetTextColor(hdc, RGB(255, 255, 255)); + SetBkColor(hdc, RGB(0, 0, 0)); + TextOut(hdc, 2, 2, "missing PNGs for", 16); + TextOut(hdc, 2, 18, rom_name, strlen(rom_name)); + } + else + { + hdc2 = CreateCompatibleDC(GetDC(FrameWnd)); + SelectObject(hdc2, ppage_bmps[PicoPicohw.page]); + BitBlt(hdc, 0, 0, 480, 240, hdc2, 0, 0, SRCCOPY); + DeleteDC(hdc2); + } + EndPaint(hwnd, &ps); + return 0; + case WM_CLOSE: + ShowWindow(hwnd, SW_HIDE); + CheckMenuItem(mpicohw, 1210, MF_UNCHECKED); + return 0; + } + + return DefWindowProc(hwnd,msg,wparam,lparam); +} + +static LRESULT CALLBACK PicoPadWndProc(HWND hwnd,UINT msg,WPARAM wparam,LPARAM lparam) +{ + PAINTSTRUCT ps; + HDC hdc, hdc2; + + switch (msg) + { + case WM_DESTROY: PicoPadWnd=NULL; break; + case WM_LBUTTONDOWN: in_vk_add_pl12 |= 0x20; return 0; + case WM_LBUTTONUP: in_vk_add_pl12 &= ~0x20; return 0; + case WM_MOUSEMOVE: + PicoPicohw.pen_pos[0] = 0x03c + LOWORD(lparam); + PicoPicohw.pen_pos[1] = 0x1fc + HIWORD(lparam); + SetTimer(FrameWnd, 100, 1000, NULL); + break; + case WM_KEYDOWN: in_vk_keydown(wparam); break; + case WM_KEYUP: in_vk_keyup(wparam); break; + case WM_PAINT: + if (ppad_bmp == NULL) break; + hdc = BeginPaint(hwnd, &ps); + hdc2 = CreateCompatibleDC(GetDC(FrameWnd)); + SelectObject(hdc2, ppad_bmp); + BitBlt(hdc, 0, 0, 320, 240, hdc2, 0, 0, SRCCOPY); + EndPaint(hwnd, &ps); + DeleteDC(hdc2); + return 0; + case WM_CLOSE: + ShowWindow(hwnd, SW_HIDE); + CheckMenuItem(mpicohw, 1211, MF_UNCHECKED); + return 0; + } + + return DefWindowProc(hwnd,msg,wparam,lparam); +} + + +static int FrameInit() +{ + WNDCLASS wc; + RECT rect={0,0,0,0}; + HMENU mfile; + int style=0; + int left=0,top=0,width=0,height=0; + + memset(&wc,0,sizeof(wc)); + + // Register the window class: + wc.lpfnWndProc=WndProc; + wc.hInstance=GetModuleHandle(NULL); + wc.hCursor=LoadCursor(NULL,IDC_ARROW); + wc.hbrBackground=CreateSolidBrush(0); + wc.lpszClassName="PicoMainFrame"; + RegisterClass(&wc); + + wc.lpszClassName="PicoSwWnd"; + wc.lpfnWndProc=PicoSwWndProc; + RegisterClass(&wc); + + wc.lpszClassName="PicoPadWnd"; + wc.lpfnWndProc=PicoPadWndProc; + RegisterClass(&wc); + + rect.right =320; + rect.bottom=224; + + // Adjust size of windows based on borders: + style=WS_OVERLAPPEDWINDOW; + AdjustWindowRect(&rect,style,1); + width =rect.right-rect.left; + height=rect.bottom-rect.top; + + // Place window in the centre of the screen: + SystemParametersInfo(SPI_GETWORKAREA,0,&rect,0); + left=rect.left+rect.right; + top=rect.top+rect.bottom; + + left-=width; left>>=1; + top-=height; top>>=1; + + // Create menu: + mfile = CreateMenu(); + InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1000, "&Load ROM"); + InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1001, "&Reset"); + InsertMenu(mfile, -1, MF_BYPOSITION|MF_STRING, 1002, "E&xit"); + mdisplay = CreateMenu(); + InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1100, "320x224"); + InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1101, "256x224"); + InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1102, "640x448"); + InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1103, "512x448"); + InsertMenu(mdisplay, -1, MF_BYPOSITION|MF_STRING, 1104, "Lock to 1:1"); + mpicohw = CreateMenu(); + InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1210, "Show &Storyware"); + InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1211, "Show &Drawing pad"); + InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1212, "&Main window as pad"); + InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_SEPARATOR, 0, NULL); + InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1220, "Title page (&0)"); + InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1221, "Page &1"); + InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1222, "Page &2"); + InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1223, "Page &3"); + InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1224, "Page &4"); + InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1225, "Page &5"); + InsertMenu(mpicohw, -1, MF_BYPOSITION|MF_STRING, 1226, "Page &6"); + mmain = CreateMenu(); + InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mfile, "&File"); + InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mdisplay, "&Display"); + InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, (UINT_PTR) mpicohw, "&Pico"); + EnableMenuItem(mmain, 2, MF_BYPOSITION|MF_GRAYED); +// InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING|MF_POPUP, 1200, "&Config"); + InsertMenu(mmain, -1, MF_BYPOSITION|MF_STRING, 1300, "&About"); + + // Create the window: + FrameWnd=CreateWindow("PicoMainFrame","PicoDrive " VERSION,style|WS_VISIBLE, + left,top,width,height,NULL,mmain,NULL,NULL); + + CheckMenuItem(mdisplay, 1104, lock_to_1_1 ? MF_CHECKED : MF_UNCHECKED); + ShowWindow(FrameWnd, SW_NORMAL); + UpdateWindow(FrameWnd); + UpdateRect(); + + // create Pico windows + style = WS_OVERLAPPED|WS_CAPTION|WS_BORDER|WS_SYSMENU; + rect.left=rect.top=0; + rect.right =320; + rect.bottom=224; + + AdjustWindowRect(&rect,style,1); + width =rect.right-rect.left; + height=rect.bottom-rect.top; + + left += 326; + PicoSwWnd=CreateWindow("PicoSwWnd","Storyware",style, + left,top,width+160,height,FrameWnd,NULL,NULL,NULL); + + top += 266; + PicoPadWnd=CreateWindow("PicoPadWnd","Drawing Pad",style, + left,top,width,height,FrameWnd,NULL,NULL,NULL); + + return 0; +} + +// -------------------- + +static DWORD WINAPI work_thread(void *x) +{ + while (engineState != PGS_Quit) { + WaitForSingleObject(loop_enter_event, INFINITE); + if (engineState != PGS_Running) + continue; + + printf("loop..\n"); + emu_loop(); + SetEvent(loop_end_event); + } + + return 0; +} + +// XXX: use main.c +void xxinit(void) +{ + /* in_init() must go before config, config accesses in_ fwk */ + in_init(); + pemu_prep_defconfig(); + emu_read_config(0, 0); + config_readlrom(PicoConfigFile); + + plat_init(); + in_probe(); + + emu_init(); + menu_init(); +} + + +int WINAPI WinMain(HINSTANCE p1, HINSTANCE p2, LPSTR cmdline, int p4) +{ + MSG msg; + DWORD tid = 0; + HANDLE thread; + int ret; + + xxinit(); + FrameInit(); + ret = DirectInit(); + if (ret) + goto end0; + + loop_enter_event = CreateEvent(NULL, 0, 0, NULL); + if (loop_enter_event == NULL) + goto end0; + + loop_end_event = CreateEvent(NULL, 0, 0, NULL); + if (loop_end_event == NULL) + goto end0; + + thread = CreateThread(NULL, 0, work_thread, NULL, 0, &tid); + if (thread == NULL) + goto end0; + + LoadROM(cmdline); + + // Main window loop: + for (;;) + { + GetMessage(&msg,NULL,0,0); + if (msg.message==WM_QUIT) break; + + TranslateMessage(&msg); + DispatchMessage(&msg); + } + + // Signal thread to quit and wait for it to exit: + if (engineState == PGS_Running) { + engineState = PGS_Quit; + WaitForSingleObject(loop_end_event, 5000); + } + CloseHandle(thread); thread=NULL; + + emu_write_config(0); + emu_finish(); + //plat_finish(); + +end0: + DirectExit(); + DestroyWindow(FrameWnd); + +// _CrtDumpMemoryLeaks(); + return 0; +} +