Supermodel/win32/win_main.c
Ville Linde 83f2c2259c
2006-07-12 18:56:25 +00:00

478 lines
10 KiB
C

/*
* Sega Model 3 Emulator
* Copyright (C) 2003 Bart Trzynadlowski, Ville Linde, Stefano Teso
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License Version 2 as published
* by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
* for more details.
*
* You should have received a copy of the GNU General Public License along
* with this program (license.txt); if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/******************************************************************/
/* Windows Main */
/******************************************************************/
#include "model3.h"
#ifdef RENDERER_D3D
#include "dx_render.h"
#else // RENDERER_GL
#include "win_gl.h"
#endif
#define XRES (496)
#define YRES (384)
static CHAR app_title[] = "Supermodel";
static CHAR app_version[] = "1.0";
static CHAR class_name[] = "MODEL3";
static CHAR CONFIG_FILE[] = "config.xml";
HWND main_window;
// Window Procedure prototype
static LRESULT CALLBACK win_window_proc(HWND, UINT, WPARAM, LPARAM);
static BOOL win_register_class(void)
{
WNDCLASSEX wcex;
wcex.cbSize = sizeof(WNDCLASSEX);
wcex.style = CS_HREDRAW | CS_VREDRAW;
wcex.lpfnWndProc = (WNDPROC)win_window_proc;
wcex.cbClsExtra = 0;
wcex.cbWndExtra = 0;
wcex.hInstance = GetModuleHandle(NULL);
wcex.hIcon = NULL;
wcex.hIconSm = NULL;
wcex.hCursor = LoadCursor(NULL, IDC_ARROW);
wcex.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wcex.lpszMenuName = NULL;
wcex.lpszClassName = class_name;
if (FAILED(RegisterClassEx(&wcex))) // MinGW: "comparison is always false due to limited range of data"
return FALSE;
return TRUE;
}
static BOOL win_create_window(UINT xres, UINT yres)
{
DWORD frame_width, frame_height, caption_height;
int width, height, window_width, window_height;
window_width = xres;
window_height = yres;
frame_width = GetSystemMetrics(SM_CXSIZEFRAME);
frame_height = GetSystemMetrics(SM_CYSIZEFRAME);
caption_height = GetSystemMetrics(SM_CYCAPTION);
width = (window_width - 1) + (frame_width * 2);
height = (window_height - 1) + (frame_height * 2) + caption_height;
main_window = CreateWindow(class_name,
app_title,
WS_CLIPSIBLINGS | WS_CLIPCHILDREN | // required for OpenGL
WS_OVERLAPPED | WS_SYSMENU | WS_MINIMIZEBOX,
CW_USEDEFAULT, CW_USEDEFAULT, // Window X & Y coords
width - 1, height - 1, // Width & Height
NULL, NULL, // Parent Window & Menu
GetModuleHandle(NULL), NULL );
if (!main_window)
return FALSE;
return TRUE;
}
/*
* NOTE: This should actually return an error if something goes wrong, but
* it doesn't matter now. This stuff probably needs to be rewritten anyway ;)
*/
static void win_destroy(void)
{
#ifdef RENDERER_D3D
d3d_shutdown();
#else // RENDERER_GL
win_gl_shutdown();
#endif
DestroyWindow(main_window);
UnregisterClass(class_name, GetModuleHandle(NULL));
}
void *malloc_exec(int length)
{
void *ptr;
ptr = VirtualAlloc(NULL, length, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
if (ptr == NULL)
{
error("malloc_exec %d failed\n", length);
}
return ptr;
}
void free_exec(void *ptr)
{
if (VirtualFree(ptr, 0, MEM_RELEASE) == FALSE)
{
error("free_exec failed\n");
}
}
BOOL check_cpu_features(void)
{
BOOL features_ok = TRUE;
char cpuname[256];
UINT32 cpu_version;
UINT32 cpu_features;
memset(cpuname, 0, sizeof(cpuname));
__asm
{
// get cpu name string
mov eax, 0x80000002
cpuid
mov dword ptr [cpuname+0 ], eax
mov dword ptr [cpuname+4 ], ebx
mov dword ptr [cpuname+8 ], ecx
mov dword ptr [cpuname+12 ], edx
mov eax, 0x80000003
cpuid
mov dword ptr [cpuname+16 ], eax
mov dword ptr [cpuname+20 ], ebx
mov dword ptr [cpuname+24 ], ecx
mov dword ptr [cpuname+28 ], edx
mov eax, 0x80000004
cpuid
mov dword ptr [cpuname+32 ], eax
mov dword ptr [cpuname+36 ], ebx
mov dword ptr [cpuname+40 ], ecx
mov dword ptr [cpuname+44 ], edx
// get cpu version and features
mov eax, 1
cpuid
mov [cpu_version], eax
mov [cpu_features], edx
}
message(0, "CPU: %s", cpuname);
if ((cpu_features & (1 << 15)) == 0)
{
message(0, "CPU doesn't support Conditional Move/Compare instructions");
features_ok = FALSE;
}
if ((cpu_features & (1 << 23)) == 0)
{
message(0, "CPU doesn't support MMX instructions");
features_ok = FALSE;
}
if ((cpu_features & (1 << 25)) == 0)
{
message(0, "CPU doesn't support SSE instructions");
features_ok = FALSE;
}
if ((cpu_features & (1 << 26)) == 0)
{
message(0, "CPU doesn't support SSE2 instructions");
features_ok = FALSE;
}
if (features_ok == FALSE)
{
message(0, "The CPU doesn't meet the requirements, the program will not run further.");
}
return features_ok;
}
int main(int argc, char *argv[])
{
MSG msg;
BOOL quit = FALSE, do_fps;
INT64 freq, time_start, time_end;
char title[256];
double fps = 0.0;
int frame = 0;
if(argc < 2) {
// Show usage
printf("ERROR: not enough arguments.\n\n");
printf("Usage: m3.exe [romset]\n");
return 0;
}
message(0, "%s v%s\n", app_title, app_version);
if (check_cpu_features() == FALSE)
{
exit(1);
}
#if RENDERER_D3D
if (d3d_pre_init() == FALSE)
{
message(0, "The video card doesn't meet the requirements, the program will not run further.");
exit(1);
}
#endif
message(0, "");
// Load config
if (parse_config(CONFIG_FILE) == FALSE)
{
exit(1);
}
m3_config.layer_enable = 0xF;
// Parse command-line
strncpy(m3_config.game_id, argv[1], 8);
m3_config.game_id[8] = '\0'; // in case game name was 8 or more chars
if (stricmp(m3_config.game_id, "lostwsga") == 0)
{
m3_config.has_lightgun = TRUE;
}
// Some initialization
if (!win_register_class())
{
message(0, "win_register_class failed.");
exit(1);
}
if (!win_create_window(XRES, YRES))
{
message(0, "win_create_window failed.");
exit(1);
}
if (model3_load() == FALSE)
{
message(0, "ROM loading failed");
exit(1);
}
model3_init();
model3_reset();
#if RENDERER_D3D
if (!d3d_init(main_window))
{
message(0, "d3d_init failed.");
exit(1);
}
#else
win_gl_init(XRES, YRES);
#endif
if (osd_input_init() == FALSE)
{
exit(1);
}
// Set window title to show the game name
sprintf(title, "%s: %s", app_title, m3_config.game_name);
SetWindowText(main_window, title);
// Now that everything works, we can show the window
ShowWindow(main_window, SW_SHOWNORMAL);
SetForegroundWindow(main_window);
SetFocus(main_window);
UpdateWindow(main_window);
if (m3_config.fullscreen && !m3_config.has_lightgun)
{
ShowCursor(FALSE);
}
if(QueryPerformanceFrequency((LARGE_INTEGER *)&freq))
do_fps = TRUE;
else
do_fps = FALSE;
QueryPerformanceCounter((LARGE_INTEGER *)&time_start);
QueryPerformanceCounter((LARGE_INTEGER *)&time_end);
memset(&msg, 0, sizeof(MSG));
while (quit == FALSE)
{
//QueryPerformanceCounter((LARGE_INTEGER *)&time_start);
while (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
if (msg.message == WM_QUIT)
quit = TRUE;
else
{
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
model3_run_frame();
frame++;
// gather profiler stats
//QueryPerformanceCounter((LARGE_INTEGER *)&time_end);
if (frame >= 5)
{
frame = 0;
QueryPerformanceCounter((LARGE_INTEGER *)&time_end);
fps = 5.0 / ((double)(time_end - time_start) / freq);
time_start = time_end;
}
#if RENDERER_D3D
if (m3_config.show_fps)
{
//fps = 1.0 / ((double)(time_end - time_start) / freq);
sprintf(title, "FPS: %.3f", fps);
osd_renderer_draw_text(2, 2, title, 0xffff0000, TRUE);
}
#else
sprintf(title, "%s: %s, FPS: %.3f", app_title, m3_config.game_name, fps);
SetWindowText(main_window, title);
#endif
//osd_renderer_draw_text(2, 2, title, 0x00ff0000, TRUE);
osd_renderer_blit();
#ifdef _PROFILE_
profile_print(prof);
printf(prof);
#endif
}
//for (i = 0; i < 32; i += 4)
// printf("R%d=%08X\tR%d=%08X\tR%d=%08X\tR%d=%08X\n",
// i + 0, ppc_get_reg(PPC_REG_R0 + i + 0),
// i + 1, ppc_get_reg(PPC_REG_R0 + i + 1),
// i + 2, ppc_get_reg(PPC_REG_R0 + i + 2),
// i + 3, ppc_get_reg(PPC_REG_R0 + i + 3));
exit(0);
}
void osd_warning()
{
}
void osd_error(CHAR * string)
{
printf("ERROR: %s\n",string);
exit(0);
}
static LRESULT CALLBACK win_window_proc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
CHAR fname[13];
static UINT xres = 496, yres = 384;
switch(message)
{
case WM_DESTROY:
{
PostQuitMessage(0);
break;
}
case WM_KEYDOWN:
{
switch (wParam)
{
default:
break;
case '7':
m3_config.layer_enable ^= 1;
break;
case '8':
m3_config.layer_enable ^= 2;
break;
case '9':
m3_config.layer_enable ^= 4;
break;
case '0':
m3_config.layer_enable ^= 8;
break;
case 0x36:
m3_config.layer_enable = 0xF;
break;
case VK_ESCAPE:
DestroyWindow(hWnd);
break;
/*case VK_F7:
strncpy(fname, m3_config.game_id, 8);
fname[8] = '\0';
strcat(fname, ".sta");
model3_save_state(fname);
break;
case VK_F8:
strncpy(fname, m3_config.game_id, 8);
fname[8] = '\0';
strcat(fname, ".sta");
model3_load_state(fname);
break;*/
}
break;
}
case WM_KEYUP:
{
switch (wParam)
{
default:
break;
case VK_F11:
{
if (m3_config.fps_limit)
{
m3_config.fps_limit = FALSE;
}
else
{
m3_config.fps_limit = TRUE;
}
break;
}
case VK_F12:
{
if (m3_config.show_fps)
{
m3_config.show_fps = FALSE;
}
else
{
m3_config.show_fps = TRUE;
}
break;
}
break;
}
}
default:
return DefWindowProc(hWnd, message, wParam, lParam);
}
return 0;
}