//============================================================ // // video.c - Win32 video handling // //============================================================ // // Copyright Aaron Giles // All rights reserved. // // Redistribution and use in source and binary forms, with or // without modification, are permitted provided that the // following conditions are met: // // * Redistributions of source code must retain the above // copyright notice, this list of conditions and the // following disclaimer. // * Redistributions in binary form must reproduce the // above copyright notice, this list of conditions and // the following disclaimer in the documentation and/or // other materials provided with the distribution. // * Neither the name 'MAME' nor the names of its // contributors may be used to endorse or promote // products derived from this software without specific // prior written permission. // // THIS SOFTWARE IS PROVIDED BY AARON GILES ''AS IS'' AND // ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND // FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO // EVENT SHALL AARON GILES BE LIABLE FOR ANY DIRECT, // INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL // DAMAGE (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON // ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT // LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN // IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. // //============================================================ // standard windows headers #define WIN32_LEAN_AND_MEAN #include // Windows 95/NT4 multimonitor stubs #ifdef WIN95_MULTIMON #include "multidef.h" #endif // MAME headers #include "emu.h" #include "emuopts.h" #include "osdepend.h" #include "video/vector.h" #include "render.h" #include "rendutil.h" #include "ui.h" #include "uiinput.h" // MAMEOS headers #include "winmain.h" #include "video.h" #include "window.h" #include "input.h" #include "debugwin.h" #include "strconv.h" #include "config.h" //============================================================ // GLOBAL VARIABLES //============================================================ win_video_config video_config; //============================================================ // LOCAL VARIABLES //============================================================ // monitor info win_monitor_info *win_monitor_list; static win_monitor_info *primary_monitor; //============================================================ // PROTOTYPES //============================================================ static void winvideo_exit(running_machine &machine); static void init_monitors(void); static BOOL CALLBACK monitor_enum_callback(HMONITOR handle, HDC dc, LPRECT rect, LPARAM data); static win_monitor_info *pick_monitor(windows_options &options, int index); static void check_osd_inputs(running_machine &machine); static void extract_video_config(running_machine &machine); static float get_aspect(const char *defdata, const char *data, int report_error); static void get_resolution(const char *defdata, const char *data, win_window_config *config, int report_error); //============================================================ // winvideo_init //============================================================ void winvideo_init(running_machine &machine) { int index; // ensure we get called on the way out machine.add_notifier(MACHINE_NOTIFY_EXIT, machine_notify_delegate(FUNC(winvideo_exit), &machine)); // extract data from the options extract_video_config(machine); // set up monitors first init_monitors(); // initialize the window system so we can make windows winwindow_init(machine); // create the windows windows_options &options = downcast(machine.options()); for (index = 0; index < video_config.numscreens; index++) winwindow_video_window_create(machine, index, pick_monitor(options, index), &video_config.window[index]); if (video_config.mode != VIDEO_MODE_NONE) SetForegroundWindow(win_window_list->hwnd); // possibly create the debug window, but don't show it yet if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED) debugwin_init_windows(machine); } //============================================================ // winvideo_exit //============================================================ static void winvideo_exit(running_machine &machine) { // free all of our monitor information while (win_monitor_list != NULL) { win_monitor_info *temp = win_monitor_list; win_monitor_list = temp->next; global_free(temp); } } //============================================================ // winvideo_monitor_refresh //============================================================ void winvideo_monitor_refresh(win_monitor_info *monitor) { BOOL result; // fetch the latest info about the monitor monitor->info.cbSize = sizeof(monitor->info); result = GetMonitorInfo(monitor->handle, (LPMONITORINFO)&monitor->info); assert(result); (void)result; // to silence gcc 4.6 } //============================================================ // winvideo_monitor_get_aspect //============================================================ float winvideo_monitor_get_aspect(win_monitor_info *monitor) { // refresh the monitor information and compute the aspect if (video_config.keepaspect) { int width, height; winvideo_monitor_refresh(monitor); width = rect_width(&monitor->info.rcMonitor); height = rect_height(&monitor->info.rcMonitor); return monitor->aspect / ((float)width / (float)height); } return 0.0f; } //============================================================ // winvideo_monitor_from_handle //============================================================ win_monitor_info *winvideo_monitor_from_handle(HMONITOR hmonitor) { win_monitor_info *monitor; // find the matching monitor for (monitor = win_monitor_list; monitor != NULL; monitor = monitor->next) if (monitor->handle == hmonitor) return monitor; return NULL; } //============================================================ // update //============================================================ void windows_osd_interface::update(bool skip_redraw) { // ping the watchdog on each update winmain_watchdog_ping(); // if we're not skipping this redraw, update all windows if (!skip_redraw) for (win_window_info *window = win_window_list; window != NULL; window = window->next) winwindow_video_window_update(window); // poll the joystick values here winwindow_process_events(machine(), TRUE); wininput_poll(machine()); check_osd_inputs(machine()); } //============================================================ // init_monitors //============================================================ static void init_monitors(void) { win_monitor_info **tailptr; // make a list of monitors win_monitor_list = NULL; tailptr = &win_monitor_list; EnumDisplayMonitors(NULL, NULL, monitor_enum_callback, (LPARAM)&tailptr); // if we're verbose, print the list of monitors { win_monitor_info *monitor; for (monitor = win_monitor_list; monitor != NULL; monitor = monitor->next) { char *utf8_device = utf8_from_tstring(monitor->info.szDevice); if (utf8_device != NULL) { mame_printf_verbose("Video: Monitor %p = \"%s\" %s\n", monitor->handle, utf8_device, (monitor == primary_monitor) ? "(primary)" : ""); osd_free(utf8_device); } } } } //============================================================ // monitor_enum_callback //============================================================ static BOOL CALLBACK monitor_enum_callback(HMONITOR handle, HDC dc, LPRECT rect, LPARAM data) { win_monitor_info ***tailptr = (win_monitor_info ***)data; win_monitor_info *monitor; MONITORINFOEX info; BOOL result; // get the monitor info info.cbSize = sizeof(info); result = GetMonitorInfo(handle, (LPMONITORINFO)&info); assert(result); (void)result; // to silence gcc 4.6 // allocate a new monitor info monitor = global_alloc_clear(win_monitor_info); // copy in the data monitor->handle = handle; monitor->info = info; // guess the aspect ratio assuming square pixels monitor->aspect = (float)(info.rcMonitor.right - info.rcMonitor.left) / (float)(info.rcMonitor.bottom - info.rcMonitor.top); // save the primary monitor handle if (monitor->info.dwFlags & MONITORINFOF_PRIMARY) primary_monitor = monitor; // hook us into the list **tailptr = monitor; *tailptr = &monitor->next; // enumerate all the available monitors so to list their names in verbose mode return TRUE; } //============================================================ // pick_monitor //============================================================ static win_monitor_info *pick_monitor(windows_options &options, int index) { const char *scrname, *scrname2; win_monitor_info *monitor; int moncount = 0; float aspect; // get the screen option scrname = options.screen(); scrname2 = options.screen(index); // decide which one we want to use if (strcmp(scrname2, "auto") != 0) scrname = scrname2; // get the aspect ratio aspect = get_aspect(options.aspect(), options.aspect(index), TRUE); // look for a match in the name first if (scrname[0] != 0) for (monitor = win_monitor_list; monitor != NULL; monitor = monitor->next) { char *utf8_device; int rc = 1; moncount++; utf8_device = utf8_from_tstring(monitor->info.szDevice); if (utf8_device != NULL) { rc = strcmp(scrname, utf8_device); osd_free(utf8_device); } if (rc == 0) goto finishit; } // didn't find it; alternate monitors until we hit the jackpot index %= moncount; for (monitor = win_monitor_list; monitor != NULL; monitor = monitor->next) if (index-- == 0) goto finishit; // return the primary just in case all else fails monitor = primary_monitor; finishit: if (aspect != 0) monitor->aspect = aspect; return monitor; } //============================================================ // check_osd_inputs //============================================================ static void check_osd_inputs(running_machine &machine) { // check for toggling fullscreen mode if (ui_input_pressed(machine, IPT_OSD_1)) winwindow_toggle_full_screen(); // check for taking fullscreen snap if (ui_input_pressed(machine, IPT_OSD_2)) winwindow_take_snap(); // check for taking fullscreen video if (ui_input_pressed(machine, IPT_OSD_3)) winwindow_take_video(); // check for taking fullscreen video if (ui_input_pressed(machine, IPT_OSD_4)) winwindow_toggle_fsfx(); } //============================================================ // extract_video_config //============================================================ static void extract_video_config(running_machine &machine) { windows_options &options = downcast(machine.options()); const char *stemp; // global options: extract the data video_config.windowed = options.window(); video_config.prescale = options.prescale(); video_config.keepaspect = options.keep_aspect(); video_config.numscreens = options.numscreens(); // if we are in debug mode, never go full screen if (machine.debug_flags & DEBUG_FLAG_OSD_ENABLED) video_config.windowed = TRUE; // per-window options: extract the data const char *default_resolution = options.resolution(); get_resolution(default_resolution, options.resolution(0), &video_config.window[0], TRUE); get_resolution(default_resolution, options.resolution(1), &video_config.window[1], TRUE); get_resolution(default_resolution, options.resolution(2), &video_config.window[2], TRUE); get_resolution(default_resolution, options.resolution(3), &video_config.window[3], TRUE); // video options: extract the data stemp = options.video(); if (strcmp(stemp, "d3d") == 0) video_config.mode = VIDEO_MODE_D3D; else if (strcmp(stemp, "ddraw") == 0) video_config.mode = VIDEO_MODE_DDRAW; else if (strcmp(stemp, "gdi") == 0) video_config.mode = VIDEO_MODE_GDI; else if (strcmp(stemp, "none") == 0) { video_config.mode = VIDEO_MODE_NONE; if (options.seconds_to_run() == 0) mame_printf_warning("Warning: -video none doesn't make much sense without -seconds_to_run\n"); } else { mame_printf_warning("Invalid video value %s; reverting to gdi\n", stemp); video_config.mode = VIDEO_MODE_GDI; } video_config.waitvsync = options.wait_vsync(); video_config.syncrefresh = options.sync_refresh(); video_config.triplebuf = options.triple_buffer(); video_config.switchres = options.switch_res(); // ddraw options: extract the data video_config.hwstretch = options.hwstretch(); // d3d options: extract the data video_config.filter = options.filter(); if (video_config.prescale == 0) video_config.prescale = 1; } //============================================================ // get_aspect //============================================================ static float get_aspect(const char *defdata, const char *data, int report_error) { int num = 0, den = 1; if (strcmp(data, "auto") == 0) { if (strcmp(defdata, "auto") == 0) return 0; data = defdata; } if (sscanf(data, "%d:%d", &num, &den) != 2 && report_error) mame_printf_error("Illegal aspect ratio value = %s\n", data); return (float)num / (float)den; } //============================================================ // get_resolution //============================================================ static void get_resolution(const char *defdata, const char *data, win_window_config *config, int report_error) { config->width = config->height = config->refresh = 0; if (strcmp(data, "auto") == 0) { if (strcmp(defdata, "auto") == 0) return; data = defdata; } if (sscanf(data, "%dx%d@%d", &config->width, &config->height, &config->refresh) < 2 && report_error) mame_printf_error("Illegal resolution value = %s\n", data); }