From 7dfb5785594a359ce9886ef6eebf564ea73af729 Mon Sep 17 00:00:00 2001 From: Brad Hughes Date: Fri, 29 Jan 2016 15:02:27 -0500 Subject: Refactor OSD input into modules --- src/osd/modules/lib/osdobj_common.cpp | 87 ++++++++++++++++++++++++++++++++--- 1 file changed, 80 insertions(+), 7 deletions(-) (limited to 'src/osd/modules/lib/osdobj_common.cpp') diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp index b36bbf60df3..b3e0d428b49 100644 --- a/src/osd/modules/lib/osdobj_common.cpp +++ b/src/osd/modules/lib/osdobj_common.cpp @@ -25,6 +25,12 @@ const options_entry osd_options::s_option_entries[] = { NULL, NULL, OPTION_HEADER, "OSD FONT OPTIONS" }, { OSD_FONT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for ui font: " }, + { NULL, NULL, OPTION_HEADER, "OSD INPUT OPTIONS" }, + { OSD_KEYBOARDINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for keyboard input: " }, + { OSD_MOUSEINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for mouse input: " }, + { OSD_LIGHTGUNINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for lightgun input: " }, + { OSD_JOYSTICKINPUT_PROVIDER, OSDOPTVAL_AUTO, OPTION_STRING, "provider for joystick input: " }, + { NULL, NULL, OPTION_HEADER, "OSD CLI OPTIONS" }, { OSDCOMMAND_LIST_MIDI_DEVICES ";mlist", "0", OPTION_COMMAND, "list available MIDI I/O devices" }, { OSDCOMMAND_LIST_NETWORK_ADAPTERS ";nlist", "0", OPTION_COMMAND, "list available network adapters" }, @@ -155,7 +161,11 @@ osd_common_t::osd_common_t(osd_options &options) m_options(options), m_print_verbose(false), m_sound(NULL), - m_debugger(NULL) + m_debugger(NULL), + m_keyboard_input(NULL), + m_mouse_input(NULL), + m_lightgun_input(NULL), + m_joystick_input(NULL) { osd_output::push(this); } @@ -207,6 +217,26 @@ void osd_common_t::register_options() #endif REGISTER_MODULE(m_mod_man, MIDI_NONE); + REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_SDL); + REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_RAWINPUT); + REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_DINPUT); + REGISTER_MODULE(m_mod_man, KEYBOARDINPUT_WIN32); + REGISTER_MODULE(m_mod_man, KEYBOARD_NONE); + + REGISTER_MODULE(m_mod_man, MOUSEINPUT_SDL); + REGISTER_MODULE(m_mod_man, MOUSEINPUT_RAWINPUT); + REGISTER_MODULE(m_mod_man, MOUSEINPUT_DINPUT); + REGISTER_MODULE(m_mod_man, MOUSEINPUT_WIN32); + REGISTER_MODULE(m_mod_man, MOUSE_NONE); + + REGISTER_MODULE(m_mod_man, LIGHTGUN_X11); + REGISTER_MODULE(m_mod_man, LIGHTGUNINPUT_WIN32); + REGISTER_MODULE(m_mod_man, LIGHTGUN_NONE); + + REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_SDL); + REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_DINPUT); + REGISTER_MODULE(m_mod_man, JOYSTICK_NONE); + // after initialization we know which modules are supported const char *names[20]; @@ -217,6 +247,30 @@ void osd_common_t::register_options() dnames.push_back(names[i]); update_option(OSD_FONT_PROVIDER, dnames); + m_mod_man.get_module_names(OSD_KEYBOARDINPUT_PROVIDER, 20, &num, names); + dnames.clear(); + for (int i = 0; i < num; i++) + dnames.push_back(names[i]); + update_option(OSD_KEYBOARDINPUT_PROVIDER, dnames); + + m_mod_man.get_module_names(OSD_MOUSEINPUT_PROVIDER, 20, &num, names); + dnames.clear(); + for (int i = 0; i < num; i++) + dnames.push_back(names[i]); + update_option(OSD_MOUSEINPUT_PROVIDER, dnames); + + m_mod_man.get_module_names(OSD_LIGHTGUNINPUT_PROVIDER, 20, &num, names); + dnames.clear(); + for (int i = 0; i < num; i++) + dnames.push_back(names[i]); + update_option(OSD_LIGHTGUNINPUT_PROVIDER, dnames); + + m_mod_man.get_module_names(OSD_JOYSTICKINPUT_PROVIDER, 20, &num, names); + dnames.clear(); + for (int i = 0; i < num; i++) + dnames.push_back(names[i]); + update_option(OSD_JOYSTICKINPUT_PROVIDER, dnames); + m_mod_man.get_module_names(OSD_SOUND_PROVIDER, 20, &num, names); dnames.clear(); for (int i = 0; i < num; i++) @@ -544,15 +598,14 @@ void osd_common_t::init_subsystems() exit(-1); } - input_init(); - // we need pause callbacks - machine().add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(FUNC(osd_common_t::input_pause), this)); - machine().add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(FUNC(osd_common_t::input_resume), this)); - output_init(); - m_font_module = select_module_options(options(), OSD_FONT_PROVIDER); + m_keyboard_input = select_module_options(options(), OSD_KEYBOARDINPUT_PROVIDER); + m_mouse_input = select_module_options(options(), OSD_MOUSEINPUT_PROVIDER); + m_lightgun_input = select_module_options(options(), OSD_LIGHTGUNINPUT_PROVIDER); + m_joystick_input = select_module_options(options(), OSD_JOYSTICKINPUT_PROVIDER); + m_font_module = select_module_options(options(), OSD_FONT_PROVIDER); m_sound = select_module_options(options(), OSD_SOUND_PROVIDER); m_sound->m_sample_rate = options().sample_rate(); m_sound->m_audio_latency = options().audio_latency(); @@ -565,6 +618,10 @@ void osd_common_t::init_subsystems() m_mod_man.init(options()); + input_init(); + // we need pause callbacks + machine().add_notifier(MACHINE_NOTIFY_PAUSE, machine_notify_delegate(FUNC(osd_common_t::input_pause), this)); + machine().add_notifier(MACHINE_NOTIFY_RESUME, machine_notify_delegate(FUNC(osd_common_t::input_resume), this)); } bool osd_common_t::video_init() @@ -588,15 +645,27 @@ void osd_common_t::video_register() bool osd_common_t::input_init() { + m_keyboard_input->input_init(machine()); + m_mouse_input->input_init(machine()); + m_lightgun_input->input_init(machine()); + m_joystick_input->input_init(machine()); return true; } void osd_common_t::input_pause() { + m_keyboard_input->pause(); + m_mouse_input->pause(); + m_lightgun_input->pause(); + m_joystick_input->pause(); } void osd_common_t::input_resume() { + m_keyboard_input->resume(); + m_mouse_input->resume(); + m_lightgun_input->resume(); + m_joystick_input->resume(); } bool osd_common_t::output_init() @@ -621,6 +690,10 @@ void osd_common_t::window_exit() void osd_common_t::input_exit() { + m_keyboard_input->exit(); + m_mouse_input->exit(); + m_lightgun_input->exit(); + m_joystick_input->exit(); } void osd_common_t::output_exit() -- cgit v1.2.3-70-g09d2 From 5cc9973a0aec22600ba118eb60a1603c7d471ee4 Mon Sep 17 00:00:00 2001 From: Brad Hughes Date: Mon, 29 Feb 2016 11:47:29 -0500 Subject: Add XInput support for Windows OSD --- scripts/src/osd/modules.lua | 1 + scripts/src/osd/windows.lua | 1 + src/osd/modules/input/input_xinput.cpp | 290 +++++++++++++++++++++++++++++++++ src/osd/modules/lib/osdobj_common.cpp | 1 + 4 files changed, 293 insertions(+) create mode 100644 src/osd/modules/input/input_xinput.cpp (limited to 'src/osd/modules/lib/osdobj_common.cpp') diff --git a/scripts/src/osd/modules.lua b/scripts/src/osd/modules.lua index 6be181c46a8..18a709784f8 100644 --- a/scripts/src/osd/modules.lua +++ b/scripts/src/osd/modules.lua @@ -82,6 +82,7 @@ function osdmodulesbuild() MAME_DIR .. "src/osd/modules/input/input_x11.cpp", MAME_DIR .. "src/osd/modules/input/input_windows.cpp", MAME_DIR .. "src/osd/modules/input/input_windows.h", + MAME_DIR .. "src/osd/modules/input/input_xinput.cpp", } if _OPTIONS["targetos"]=="windows" then diff --git a/scripts/src/osd/windows.lua b/scripts/src/osd/windows.lua index 950e15d1e46..7ff677eb1ba 100644 --- a/scripts/src/osd/windows.lua +++ b/scripts/src/osd/windows.lua @@ -46,6 +46,7 @@ function maintargetosdoptions(_target,_subtarget) "comctl32", "comdlg32", "psapi", + "xinput", } end diff --git a/src/osd/modules/input/input_xinput.cpp b/src/osd/modules/input/input_xinput.cpp new file mode 100644 index 00000000000..292f9ee5d35 --- /dev/null +++ b/src/osd/modules/input/input_xinput.cpp @@ -0,0 +1,290 @@ +// license:BSD-3-Clause +// copyright-holders:Brad Hughes +//============================================================ +// +// input_xinput.cpp - XInput API input support for Windows +// +//============================================================ + +#include "input_module.h" +#include "modules/osdmodule.h" + +#if defined(OSD_WINDOWS) + +// standard windows headers +#define WIN32_LEAN_AND_MEAN +#include + +// XInput header +#include + +#undef interface + +// MAME headers +#include "emu.h" +#include "osdepend.h" +#include "ui/ui.h" + +// MAMEOS headers +#include "winmain.h" +#include "window.h" + +#include "input_common.h" +#include "input_windows.h" + +#define XINPUT_MAX_POV 4 +#define XINPUT_MAX_BUTTONS 10 +#define XINPUT_MAX_AXIS 4 + +#define XINPUT_AXIS_MINVALUE -32767 +#define XINPUT_AXIS_MAXVALUE 32767 + +// default axis names +static const char *const xinput_axis_name[] = +{ + "LSX", + "LSY", + "RSX", + "RSY" +}; + +static const input_item_id xinput_axis_ids[] = +{ + ITEM_ID_XAXIS, + ITEM_ID_YAXIS, + ITEM_ID_RXAXIS, + ITEM_ID_RYAXIS +}; + +static const USHORT xinput_pov_dir[] = { + XINPUT_GAMEPAD_DPAD_UP, + XINPUT_GAMEPAD_DPAD_DOWN, + XINPUT_GAMEPAD_DPAD_LEFT, + XINPUT_GAMEPAD_DPAD_RIGHT +}; + +static const char *const xinput_pov_names[] = { + "DPAD Up", + "DPAD Down", + "DPAD Left", + "DPAD Right" +}; + +static const USHORT xinput_buttons[] = { + XINPUT_GAMEPAD_A, + XINPUT_GAMEPAD_B, + XINPUT_GAMEPAD_X, + XINPUT_GAMEPAD_Y, + XINPUT_GAMEPAD_LEFT_SHOULDER, + XINPUT_GAMEPAD_RIGHT_SHOULDER, + XINPUT_GAMEPAD_START, + XINPUT_GAMEPAD_BACK, + XINPUT_GAMEPAD_LEFT_THUMB, + XINPUT_GAMEPAD_RIGHT_THUMB, +}; + +static const char *const xinput_button_names[] = { + "A", + "B", + "X", + "Y", + "Left Shoulder", + "Right Shoulder", + "Start", + "Back", + "Left Thumb", + "Right Thumb" +}; + +struct gamepad_state +{ + BYTE rgbButtons[XINPUT_MAX_BUTTONS]; + BYTE rgbPov[XINPUT_MAX_POV]; + BYTE bLeftTrigger; + BYTE bRightTrigger; + LONG sThumbLX; + LONG sThumbLY; + LONG sThumbRX; + LONG sThumbRY; +}; + +// state information for a gamepad; state must be first element +struct xinput_api_state +{ + UINT32 playerIndex; + XINPUT_STATE xstate; + XINPUT_CAPABILITIES caps; +}; + +//============================================================ +// xinput_joystick_device +//============================================================ + +class xinput_joystick_device : public device_info +{ +public: + gamepad_state gamepad; + xinput_api_state xinput_state; + + xinput_joystick_device(running_machine &machine, const char *name, input_module &module) + : device_info(machine, name, DEVICE_CLASS_JOYSTICK, module), + gamepad({0}), + xinput_state({0}) + { + } + + void poll() override + { + // poll the device first + HRESULT result = XInputGetState(xinput_state.playerIndex, &xinput_state.xstate); + + // If we can't poll the device, skip + if (FAILED(result)) + return; + + // Copy the XState into State + // Start with the POV (DPAD) + for (int povindex = 0; povindex < XINPUT_MAX_POV; povindex++) + { + int currentPov = xinput_pov_dir[povindex]; + gamepad.rgbPov[currentPov] = (xinput_state.xstate.Gamepad.wButtons & currentPov) ? 0xFF : 0; + } + + // Now do the buttons + for (int buttonindex = 0; buttonindex < XINPUT_MAX_BUTTONS; buttonindex++) + { + int currentButton = xinput_buttons[buttonindex]; + gamepad.rgbButtons[buttonindex] = (xinput_state.xstate.Gamepad.wButtons & currentButton) ? 0xFF : 0; + } + + // Now grab the axis values + // Each of the thumbstick axis members is a signed value between -32768 and 32767 describing the position of the thumbstick + // However, the Y axis values are inverted from what MAME expects, so multiply by -1 first + gamepad.sThumbLX = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbLX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE); + gamepad.sThumbLY = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbLY * -1, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE); + gamepad.sThumbRX = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbRX, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE); + gamepad.sThumbRY = normalize_absolute_axis(xinput_state.xstate.Gamepad.sThumbRY * -1, XINPUT_AXIS_MINVALUE, XINPUT_AXIS_MAXVALUE); + + // Now the triggers + gamepad.bLeftTrigger = xinput_state.xstate.Gamepad.bLeftTrigger; + gamepad.bRightTrigger = xinput_state.xstate.Gamepad.bRightTrigger; + } + + void reset() override + { + memset(&gamepad, 0, sizeof(gamepad)); + } +}; + +//============================================================ +// xinput_joystick_module +//============================================================ + +class xinput_joystick_module : public wininput_module +{ +public: + xinput_joystick_module() + : wininput_module(OSD_JOYSTICKINPUT_PROVIDER, "xinput") + { + } + +protected: + virtual void input_init(running_machine &machine) override + { + xinput_joystick_device *devinfo; + + // Loop through each gamepad to determine if they are connected + for (UINT i = 0; i < XUSER_MAX_COUNT; i++) + { + XINPUT_STATE state = {0}; + + if (XInputGetState(i, &state) == ERROR_SUCCESS) + { + // allocate and link in a new device + devinfo = create_xinput_device(machine, i); + if (devinfo == nullptr) + continue; + + // Add the axes + for (int i = 0; i < XINPUT_MAX_AXIS; i++) + { + devinfo->device()->add_item( + xinput_axis_name[i], + xinput_axis_ids[i], + generic_axis_get_state, + &devinfo->gamepad.sThumbLX + i); + } + + // Populate the POVs + // For XBOX, we treat the DPAD as a hat switch + for (int povnum = 0; povnum < XINPUT_MAX_POV; povnum++) + { + devinfo->device()->add_item( + xinput_pov_names[povnum], + ITEM_ID_OTHER_SWITCH, + generic_button_get_state, + &devinfo->gamepad.rgbPov[povnum]); + } + + // populate the buttons + for (int butnum = 0; butnum < XINPUT_MAX_BUTTONS; butnum++) + { + devinfo->device()->add_item( + xinput_button_names[butnum], + (input_item_id)(ITEM_ID_BUTTON1 + butnum), + generic_button_get_state, + &devinfo->gamepad.rgbButtons[butnum]); + } + + devinfo->device()->add_item( + "Left Trigger", + (input_item_id)(ITEM_ID_BUTTON1 + XINPUT_MAX_BUTTONS), + generic_button_get_state, + &devinfo->gamepad.bLeftTrigger); + + devinfo->device()->add_item( + "Right Trigger", + (input_item_id)(ITEM_ID_BUTTON1 + XINPUT_MAX_BUTTONS + 1), + generic_button_get_state, + &devinfo->gamepad.bRightTrigger); + } + } + } + + private: + //============================================================ + // create_xinput_device + //============================================================ + + xinput_joystick_device * create_xinput_device(running_machine &machine, UINT index) + { + xinput_joystick_device *devinfo; + + XINPUT_CAPABILITIES caps = {0}; + if (FAILED(XInputGetCapabilities(index, 0, &caps))) + { + // If we can't get the capabilities skip this device + return nullptr; + } + + char device_name[16]; + snprintf(device_name, sizeof(device_name), "XInput Player %u", index + 1); + + // allocate the device object + devinfo = devicelist()->create_device(machine, device_name, *this); + + // Set the player ID + devinfo->xinput_state.playerIndex = index; + + // Assign the caps we captured earlier + devinfo->xinput_state.caps = caps; + + return devinfo; + } +}; + +#else +MODULE_NOT_SUPPORTED(xinput_joystick_module, OSD_KEYBOARDINPUT_PROVIDER, "xinput") +#endif + +MODULE_DEFINITION(JOYSTICKINPUT_XINPUT, xinput_joystick_module) \ No newline at end of file diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp index 277dc4ef692..be9590087c9 100644 --- a/src/osd/modules/lib/osdobj_common.cpp +++ b/src/osd/modules/lib/osdobj_common.cpp @@ -235,6 +235,7 @@ void osd_common_t::register_options() REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_SDL); REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_DINPUT); + REGISTER_MODULE(m_mod_man, JOYSTICKINPUT_XINPUT); REGISTER_MODULE(m_mod_man, JOYSTICK_NONE); // after initialization we know which modules are supported -- cgit v1.2.3-70-g09d2 From 8803de248e2437ebde8981dc196447546914ae36 Mon Sep 17 00:00:00 2001 From: Brad Hughes Date: Wed, 2 Mar 2016 14:13:53 -0500 Subject: Add DirectWrite font support module --- scripts/src/osd/modules.lua | 1 + src/osd/modules/font/font_dwrite.cpp | 708 ++++++++++++++++++++++++++++++++++ src/osd/modules/lib/osdobj_common.cpp | 1 + src/osd/windows/winutil.cpp | 61 +++ src/osd/windows/winutil.h | 136 +++++++ 5 files changed, 907 insertions(+) create mode 100644 src/osd/modules/font/font_dwrite.cpp (limited to 'src/osd/modules/lib/osdobj_common.cpp') diff --git a/scripts/src/osd/modules.lua b/scripts/src/osd/modules.lua index 18a709784f8..54443d4f618 100644 --- a/scripts/src/osd/modules.lua +++ b/scripts/src/osd/modules.lua @@ -56,6 +56,7 @@ function osdmodulesbuild() MAME_DIR .. "src/osd/modules/debugger/debugwin.cpp", MAME_DIR .. "src/osd/modules/font/font_sdl.cpp", MAME_DIR .. "src/osd/modules/font/font_windows.cpp", + MAME_DIR .. "src/osd/modules/font/font_dwrite.cpp", MAME_DIR .. "src/osd/modules/font/font_osx.cpp", MAME_DIR .. "src/osd/modules/font/font_none.cpp", MAME_DIR .. "src/osd/modules/netdev/taptun.cpp", diff --git a/src/osd/modules/font/font_dwrite.cpp b/src/osd/modules/font/font_dwrite.cpp new file mode 100644 index 00000000000..8f78badda3b --- /dev/null +++ b/src/osd/modules/font/font_dwrite.cpp @@ -0,0 +1,708 @@ +// license:BSD-3-Clause +// copyright-holders:Aaron Giles, Brad Hughes +/* +* font_dwrite.c +* +*/ + +#include "font_module.h" +#include "modules/osdmodule.h" + +// We take dependencies on WRL client headers and +// we can only build with a high enough version +#if defined(OSD_WINDOWS) && (_WIN32_WINNT >= 0x0602) + +#define WIN32_LEAN_AND_MEAN +#include +#include + +#include + +// Windows Imaging Components +#include + +// Load InitGuid after WIC to work around missing format problem +#include + +// Direct2D +#include +#include +#include + +// WIC GUIDs +DEFINE_GUID(CLSID_WICImagingFactory, 0xcacaf262, 0x9370, 0x4615, 0xa1, 0x3b, 0x9f, 0x55, 0x39, 0xda, 0x4c, 0xa); +DEFINE_GUID(GUID_WICPixelFormat8bppAlpha, 0xe6cd0116, 0xeeba, 0x4161, 0xaa, 0x85, 0x27, 0xdd, 0x9f, 0xb3, 0xa8, 0x95); + +#include +#undef interface + +#include "emu.h" +#include "strconv.h" +#include "corestr.h" +#include "corealloc.h" +#include "fileio.h" +#include "winutil.h" + +using namespace Microsoft::WRL; + +//------------------------------------------------- +// Some formulas and constants +//------------------------------------------------- + +//#define DEFAULT_CELL_HEIGHT (200) +#define DEFAULT_EM_HEIGHT (166.5f) + +// 1DIP = 1/96in vs 1pt = 1/72in (or 4 / 3) +static const float DIPS_PER_POINT = (4.0f / 3.0f); +static const float POINTS_PER_DIP = (3.0f / 4.0f); + +//------------------------------------------------- +// Error handling macros +//------------------------------------------------- + +// Macro to check for a failed HRESULT and if failed, return 0 +#define HR_RET( CALL, ret ) do { \ + result = CALL; \ + if (FAILED(result)) { \ + osd_printf_error(#CALL " failed with error 0x%X\n", (unsigned int)result); \ + return ret; } \ +} while (0) + +#define HR_RETHR( CALL ) HR_RET(CALL, result) +#define HR_RET0( CALL ) HR_RET(CALL, 0) +#define HR_RET1( CALL ) HR_RET(CALL, 1) + +// Typedefs for dynamically loaded functions +typedef lazy_loaded_function_p4 d2d_create_factory_fn; +typedef lazy_loaded_function_p3 dwrite_create_factory_fn; + +// Debugging functions +#ifdef DWRITE_DEBUGGING + +//------------------------------------------------- +// Save image to file +//------------------------------------------------- + +void SaveBitmap(IWICBitmap* bitmap, GUID pixelFormat, const WCHAR *filename) +{ + HRESULT result = S_OK; + ComPtr stream; + ComPtr d2dfactory; + ComPtr dwriteFactory; + ComPtr wicFactory; + + d2d_create_factory_fn pfn_D2D1CreateFactory("D2D1CreateFactory", L"D2d1.dll"); + dwrite_create_factory_fn pfn_DWriteCreateFactory("DWriteCreateFactory", L"Dwrite.dll"); + HR_RET(pfn_D2D1CreateFactory.initialize()); + HR_RET(pfn_DWriteCreateFactory.initialize()); + + // Create a Direct2D factory + HR_RET(pfn_D2D1CreateFactory( + D2D1_FACTORY_TYPE_SINGLE_THREADED, + __uuidof(ID2D1Factory1), + nullptr, + reinterpret_cast(d2dfactory.GetAddressOf()))); + + // Initialize COM - ignore failure + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + // Create a DirectWrite factory. + HR_RET(pfn_DWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(dwriteFactory.GetAddressOf()))); + + HR_RET(CoCreateInstance( + CLSID_WICImagingFactory, + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IWICImagingFactory), + (void**)&wicFactory)); + + HR_RET(wicFactory->CreateStream(&stream)); + HR_RET(stream->InitializeFromFilename(filename, GENERIC_WRITE)); + + ComPtr encoder; + HR_RET(wicFactory->CreateEncoder(GUID_ContainerFormatBmp, NULL, &encoder)); + HR_RET(encoder->Initialize(stream.Get(), WICBitmapEncoderNoCache)); + + ComPtr frameEncode; + HR_RET(encoder->CreateNewFrame(&frameEncode, NULL)); + HR_RET(frameEncode->Initialize(NULL)); + + UINT width, height; + HR_RET(bitmap->GetSize(&width, &height)); + HR_RET(frameEncode->SetSize(width, height)); + HR_RET(frameEncode->SetPixelFormat(&pixelFormat)); + + HR_RET(frameEncode->WriteSource(bitmap, NULL)); + + HR_RET(frameEncode->Commit()); + HR_RET(encoder->Commit()); +} + +void SaveBitmap2(bitmap_argb32 &bitmap, const WCHAR *filename) +{ + HRESULT result; + + // Convert the bitmap into a form we understand and save it + std::unique_ptr pBitmap(new UINT32[bitmap.width() * bitmap.height()]); + for (int y = 0; y < bitmap.height(); y++) + { + UINT32* pRow = pBitmap.get() + (y * bitmap.width()); + for (int x = 0; x < bitmap.width(); x++) + { + UINT32 pixel = bitmap.pix32(y, x); + pRow[x] = (pixel == 0xFFFFFFFF) ? rgb_t(0xFF, 0x00, 0x00, 0x00) : pRow[x] = rgb_t(0xFF, 0xFF, 0xFF, 0xFF); + } + } + + ComPtr wicFactory; + HR_RET(CoCreateInstance( + CLSID_WICImagingFactory, + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IWICImagingFactory), + (void**)&wicFactory)); + + // Save bitmap + ComPtr bmp2 = nullptr; + wicFactory->CreateBitmapFromMemory( + bitmap.width(), + bitmap.height(), + GUID_WICPixelFormat32bppRGBA, + bitmap.width() * sizeof(UINT32), + bitmap.width() * bitmap.height() * sizeof(UINT32), + (BYTE*)pBitmap.get(), + &bmp2); + + SaveBitmap(bmp2.Get(), GUID_WICPixelFormat32bppRGBA, filename); +} + +#endif + +//------------------------------------------------- +// FontDimension class - holds a font dimension +// and makes it availabile in different formats +//------------------------------------------------- + +class FontDimension +{ +private: + UINT16 m_designUnitsPerEm; + float m_emSizeInDip; + float m_designUnits; + +public: + FontDimension(UINT16 designUnitsPerEm, float emSizeInDip, float designUnits) + { + m_designUnitsPerEm = designUnitsPerEm; + m_emSizeInDip = emSizeInDip; + m_designUnits = designUnits; + } + + UINT16 DesignUnitsPerEm() + { + return m_designUnitsPerEm; + } + + float EmSizeInDip() + { + return m_emSizeInDip; + } + + float DesignUnits() + { + return m_designUnits; + } + + int Dips() + { + return (int)floor((m_designUnits * m_emSizeInDip) / m_designUnitsPerEm); + } + + float Points() + { + return Dips() * POINTS_PER_DIP; + } + + FontDimension operator-(const FontDimension &other) + { + if (m_designUnitsPerEm != other.m_designUnitsPerEm || m_emSizeInDip != other.m_emSizeInDip) + { + throw emu_fatalerror("Attempted subtraction of FontDimension with different scale."); + } + + return FontDimension(m_designUnitsPerEm, m_emSizeInDip, m_designUnits - other.m_designUnits); + } + + FontDimension operator+(const FontDimension &other) + { + if (m_designUnitsPerEm != other.m_designUnitsPerEm || m_emSizeInDip != other.m_emSizeInDip) + { + throw emu_fatalerror("Attempted addition of FontDimension with different scale."); + } + + return FontDimension(m_designUnitsPerEm, m_emSizeInDip, m_designUnits + other.m_designUnits); + } +}; + +//------------------------------------------------- +// FontABCWidths class - hold width-related +// font dimensions for a glyph +//------------------------------------------------- + +class FontABCWidths +{ +private: + FontDimension m_advanceWidth; + FontDimension m_a; + FontDimension m_c; + +public: + FontABCWidths(const FontDimension &advanceWidth, const FontDimension &leftSideBearing, const FontDimension &rightsideBearing) : + m_advanceWidth(advanceWidth), + m_a(leftSideBearing), + m_c(rightsideBearing) + { + } + + FontDimension advanceWidth() { return m_advanceWidth; } + FontDimension abcA() { return m_a; } + + // Relationship between advanceWidth and B is ADV = A + B + C so B = ADV - A - C + FontDimension abcB() { return advanceWidth() - abcA() - abcC(); } + FontDimension abcC() { return m_c; } +}; + +//------------------------------------------------- +// FontDimensionFactory class - simple way of +// creating font dimensions +//------------------------------------------------- + +class FontDimensionFactory +{ +private: + UINT16 m_designUnitsPerEm; + float m_emSizeInDip; + +public: + float EmSizeInDip() + { + return m_emSizeInDip; + } + + FontDimensionFactory(UINT16 designUnitsPerEm, float emSizeInDip) + { + m_designUnitsPerEm = designUnitsPerEm; + m_emSizeInDip = emSizeInDip; + } + + FontDimension FromDip(float dip) + { + float sizeInDesignUnits = (dip / m_emSizeInDip) * m_designUnitsPerEm; + return FontDimension(m_designUnitsPerEm, m_emSizeInDip, sizeInDesignUnits); + } + + FontDimension FromDesignUnit(float designUnits) + { + return FontDimension(m_designUnitsPerEm, m_emSizeInDip, designUnits); + } + + FontDimension FromPoint(float pointSize) + { + float sizeInDip = pointSize * (4.0f / 3.0f); + float sizeInDesignUnits = (sizeInDip / m_emSizeInDip) * m_designUnitsPerEm; + return FontDimension(m_designUnitsPerEm, m_emSizeInDip, sizeInDesignUnits); + } + + FontABCWidths CreateAbcWidths(float advanceWidth, float leftSideBearing, float rightSideBearing) + { + return FontABCWidths( + FromDesignUnit(advanceWidth), + FromDesignUnit(leftSideBearing), + FromDesignUnit(rightSideBearing)); + } +}; + +//------------------------------------------------- +// font_open - attempt to "open" a handle to the +// font with the given name +//------------------------------------------------- + +class osd_font_dwrite : public osd_font +{ +private: + ComPtr m_d2dfactory; + ComPtr m_dwriteFactory; + ComPtr m_wicFactory; + ComPtr m_font; + float m_fontEmHeightInDips; + +public: + osd_font_dwrite(ComPtr d2dfactory, ComPtr dwriteFactory, ComPtr wicFactory) + : m_d2dfactory(d2dfactory), m_dwriteFactory(dwriteFactory), m_wicFactory(wicFactory) + { + } + + virtual bool open(const char *font_path, const char *_name, int &height) override + { + if (m_d2dfactory == nullptr || m_dwriteFactory == nullptr || m_wicFactory == nullptr) + return false; + + HRESULT result; + + // accept qualifiers from the name + std::string name(_name); + if (name.compare("default") == 0) name = "Tahoma"; + bool bold = (strreplace(name, "[B]", "") + strreplace(name, "[b]", "") > 0); + bool italic = (strreplace(name, "[I]", "") + strreplace(name, "[i]", "") > 0); + + // convert the face name + auto familyName = std::wstring(std::unique_ptr(wstring_from_utf8(name.c_str()), osd_free).get()); + + // find the font + HR_RET0(find_font( + familyName.c_str(), + bold ? DWRITE_FONT_WEIGHT_BOLD : DWRITE_FONT_WEIGHT_NORMAL, + DWRITE_FONT_STRETCH_NORMAL, + italic ? DWRITE_FONT_STYLE_ITALIC : DWRITE_FONT_STYLE_NORMAL, + m_font.GetAddressOf())); + + DWRITE_FONT_METRICS metrics; + m_font->GetMetrics(&metrics); + + m_fontEmHeightInDips = DEFAULT_EM_HEIGHT; + height = (int)round(m_fontEmHeightInDips * DIPS_PER_POINT); + + return true; + } + + //------------------------------------------------- + // font_close - release resources associated with + // a given OSD font + //------------------------------------------------- + + virtual void close() override + { + m_font = nullptr; + m_fontEmHeightInDips = 0; + } + + //------------------------------------------------- + // font_get_bitmap - allocate and populate a + // BITMAP_FORMAT_ARGB32 bitmap containing the + // pixel values rgb_t(0xff,0xff,0xff,0xff) + // or rgb_t(0x00,0xff,0xff,0xff) for each + // pixel of a black & white font + //------------------------------------------------- + + virtual bool get_bitmap(unicode_char chnum, bitmap_argb32 &bitmap, INT32 &width, INT32 &xoffs, INT32 &yoffs) override + { + const int MEM_ALIGN_CONST = 31; + const int BITMAP_PAD = 50; + + HRESULT result; + UINT cbData; + BYTE* pixels = nullptr; + + ComPtr target; + ComPtr pWhiteBrush; + ComPtr wicBitmap; + ComPtr lock; + + ComPtr face; + HR_RET0(m_font->CreateFontFace(face.GetAddressOf())); + + // get the GDI metrics + DWRITE_FONT_METRICS gdi_metrics; + HR_RET0(face->GetGdiCompatibleMetrics( + m_fontEmHeightInDips, + 1.0f, + nullptr, + &gdi_metrics)); + + FontDimensionFactory fdf(gdi_metrics.designUnitsPerEm, m_fontEmHeightInDips); + + UINT32 tempChar = chnum; + UINT16 glyphIndex; + HR_RET0(face->GetGlyphIndicesW(&tempChar, 1, &glyphIndex)); + + // get the width of this character + DWRITE_GLYPH_METRICS glyph_metrics = { 0 }; + HR_RET0(face->GetGdiCompatibleGlyphMetrics( + m_fontEmHeightInDips, + 1.0f, + nullptr, + FALSE, + &glyphIndex, + 1, + &glyph_metrics)); + + // The height is the ascent added to the descent + // By definition, the Em is equal to Cell Height minus Internal Leading (topSide bearing). + //auto cellheight = fdf.FromDesignUnit(gdi_metrics.ascent + gdi_metrics.descent + gdi_metrics.); + auto ascent = fdf.FromDesignUnit(gdi_metrics.ascent); + auto descent = fdf.FromDesignUnit(gdi_metrics.descent); + auto charHeight = ascent + descent; + + auto abc = fdf.CreateAbcWidths( + glyph_metrics.advanceWidth, + glyph_metrics.leftSideBearing, + glyph_metrics.rightSideBearing); + + width = abc.abcA().Dips() + abc.abcB().Dips() + abc.abcC().Dips(); + + // determine desired bitmap size + int bmwidth = (BITMAP_PAD + abc.abcA().Dips() + abc.abcB().Dips() + abc.abcC().Dips() + BITMAP_PAD + MEM_ALIGN_CONST) & ~MEM_ALIGN_CONST; + int bmheight = BITMAP_PAD + charHeight.Dips() + BITMAP_PAD; + + // GUID_WICPixelFormat8bppAlpha is 8 bits per pixel + const REFWICPixelFormatGUID source_bitmap_wic_format = GUID_WICPixelFormat8bppAlpha; + const DXGI_FORMAT source_bitmap_dxgi_format = DXGI_FORMAT_A8_UNORM; + const D2D1_ALPHA_MODE source_bitmap_d2d_alpha_mode = D2D1_ALPHA_MODE_STRAIGHT; + + // describe the bitmap we want + HR_RET0(m_wicFactory->CreateBitmap( + bmwidth, + bmheight, + source_bitmap_wic_format, + WICBitmapCacheOnLoad, + wicBitmap.GetAddressOf())); + + D2D1_RENDER_TARGET_PROPERTIES targetProps; + targetProps = D2D1::RenderTargetProperties(); + targetProps.pixelFormat = D2D1::PixelFormat(source_bitmap_dxgi_format, source_bitmap_d2d_alpha_mode); + + // create a DIB to render to + HR_RET0(this->m_d2dfactory->CreateWicBitmapRenderTarget( + wicBitmap.Get(), + &targetProps, + reinterpret_cast(target.GetAddressOf()))); + + target->SetTextAntialiasMode(D2D1_TEXT_ANTIALIAS_MODE_ALIASED); + + // Create our brush + HR_RET0(target->CreateSolidColorBrush(D2D1::ColorF(1.0f, 1.0f, 1.0f, 1.0f), pWhiteBrush.GetAddressOf())); + + // Signal the start of the frame + target->BeginDraw(); + + // clear the bitmap + // In the alpha mask, it will look like 0x00 per pixel + target->Clear(D2D1::ColorF(0.0f, 0.0f, 0.0f, 0.0f)); + + // now draw the character + DWRITE_GLYPH_RUN run = { 0 }; + DWRITE_GLYPH_OFFSET offsets; + offsets.advanceOffset = 0; + offsets.ascenderOffset = 0; + float advanceWidth = abc.advanceWidth().Dips(); + + run.fontEmSize = m_fontEmHeightInDips; + run.fontFace = face.Get(); + run.glyphCount = 1; + run.glyphIndices = &glyphIndex; + run.glyphAdvances = &advanceWidth; + run.glyphOffsets = &offsets; + + auto baseline_origin = D2D1::Point2F(BITMAP_PAD + abc.abcA().Dips() + 1, BITMAP_PAD + ascent.Dips()); + target->DrawGlyphRun( + baseline_origin, + &run, + pWhiteBrush.Get(), + DWRITE_MEASURING_MODE_GDI_CLASSIC); + + HR_RET0(target->EndDraw()); + +#ifdef DWRITE_DEBUGGING + // Save to file for debugging + SaveBitmap(wicBitmap.Get(), GUID_WICPixelFormatBlackWhite, L"C:\\temp\\ddraw_step1.bmp"); +#endif + + // characters are expected to be full-height + rectangle actbounds; + actbounds.min_y = BITMAP_PAD; + actbounds.max_y = BITMAP_PAD + charHeight.Dips() - 1; + + // Lock the bitmap and get the data pointer + WICRect rect = { 0, 0, bmwidth, bmheight }; + HR_RET0(wicBitmap->Lock(&rect, WICBitmapLockRead, lock.GetAddressOf())); + HR_RET0(lock->GetDataPointer(&cbData, (BYTE**)&pixels)); + + // determine the actual left of the character + for (actbounds.min_x = 0; actbounds.min_x < bmwidth; actbounds.min_x++) + { + BYTE *offs = pixels + actbounds.min_x; + UINT8 summary = 0; + for (int y = 0; y < bmheight; y++) + summary |= offs[y * bmwidth]; + if (summary != 0) + { + break; + } + } + + // determine the actual right of the character + // Start from the right edge, and move in until we find a pixel + for (actbounds.max_x = bmwidth - 1; actbounds.max_x >= 0; actbounds.max_x--) + { + BYTE *offs = pixels + actbounds.max_x; + UINT8 summary = 0; + + // Go through the entire column and build a summary + for (int y = 0; y < bmheight; y++) + summary |= offs[y * bmwidth]; + if (summary != 0) + { + break; + } + } + + // allocate a new bitmap + if (actbounds.max_x >= actbounds.min_x && actbounds.max_y >= actbounds.min_y) + { + bitmap.allocate(actbounds.max_x + 1 - actbounds.min_x, actbounds.max_y + 1 - actbounds.min_y); + + // copy the bits into it + for (int y = 0; y < bitmap.height(); y++) + { + UINT32 *dstrow = &bitmap.pix32(y); + UINT8 *srcrow = &pixels[(y + actbounds.min_y) * bmwidth]; + for (int x = 0; x < bitmap.width(); x++) + { + int effx = x + actbounds.min_x; + dstrow[x] = rgb_t(srcrow[effx], 0xff, 0xff, 0xff); + } + } + + // set the final offset values + xoffs = actbounds.min_x - (BITMAP_PAD + abc.abcA().Dips()); + yoffs = actbounds.max_y - (BITMAP_PAD + ascent.Dips()); + +#ifdef DWRITE_DEBUGGING + SaveBitmap2(bitmap, L"C:\\temp\\dwrite_final.bmp"); +#endif + } + + BOOL success = bitmap.valid(); + +#ifdef DWRITE_DEBUGGING + osd_printf_debug( + "dwr: %s, c'%S' w%i x%i y%i asc%i dsc%i a%ib%ic%i\n", + success ? "Success" : "Error", + (WCHAR*)&chnum, + width, + xoffs, + yoffs, + ascent.Dips(), + descent.Dips(), + abc.abcA().Dips(), + abc.abcB().Dips(), + abc.abcC().Dips()); +#endif + return success; + } + +private: + + //------------------------------------------------- + // find_font - finds a font, given attributes + //------------------------------------------------- + + HRESULT find_font(std::wstring familyName, DWRITE_FONT_WEIGHT weight, DWRITE_FONT_STRETCH stretch, DWRITE_FONT_STYLE style, IDWriteFont ** ppfont) + { + HRESULT result = S_OK; + + ComPtr fonts; + HR_RETHR(m_dwriteFactory->GetSystemFontCollection(fonts.GetAddressOf())); + + UINT family_index; BOOL exists; + HR_RETHR(fonts->FindFamilyName(familyName.c_str(), &family_index, &exists)); + if (!exists) + { + osd_printf_error("Font with family name %S does not exist", familyName.c_str()); + return E_FAIL; + } + + ComPtr family; + HR_RETHR(fonts->GetFontFamily(family_index, family.GetAddressOf())); + + ComPtr font; + HR_RETHR(family->GetFirstMatchingFont(weight, stretch, style, font.GetAddressOf())); + + *ppfont = font.Detach(); + return result; + } +}; + +//------------------------------------------------- +// font_dwrite - the DirectWrite font module +//------------------------------------------------- + +class font_dwrite : public osd_module, public font_module +{ +private: + d2d_create_factory_fn m_pfnD2D1CreateFactory; + dwrite_create_factory_fn m_pfnDWriteCreateFactory; + ComPtr m_d2dfactory; + ComPtr m_dwriteFactory; + ComPtr m_wicFactory; + +public: + font_dwrite() : + osd_module(OSD_FONT_PROVIDER, "dwrite"), + font_module(), + m_pfnD2D1CreateFactory("D2D1CreateFactory", L"D2d1.dll"), + m_pfnDWriteCreateFactory("DWriteCreateFactory", L"Dwrite.dll"), + m_d2dfactory(nullptr), + m_dwriteFactory(nullptr), + m_wicFactory(nullptr) + { + } + + virtual int init(const osd_options &options) override + { + HRESULT result; + + // Make sure we can initialize our api functions + HR_RET1(m_pfnD2D1CreateFactory.initialize()); + HR_RET1(m_pfnDWriteCreateFactory.initialize()); + + // Create a Direct2D factory. + HR_RET1(m_pfnD2D1CreateFactory( + D2D1_FACTORY_TYPE_SINGLE_THREADED, + __uuidof(ID2D1Factory), + nullptr, + reinterpret_cast(this->m_d2dfactory.GetAddressOf()))); + + // Initialize COM + CoInitializeEx(NULL, COINIT_APARTMENTTHREADED); + + // Create a DirectWrite factory. + HR_RET1(m_pfnDWriteCreateFactory( + DWRITE_FACTORY_TYPE_SHARED, + __uuidof(IDWriteFactory), + reinterpret_cast(m_dwriteFactory.GetAddressOf()))); + + HR_RET1(CoCreateInstance( + CLSID_WICImagingFactory, + NULL, + CLSCTX_INPROC_SERVER, + __uuidof(IWICImagingFactory), + (void**)&m_wicFactory)); + + return 0; + } + + virtual osd_font *font_alloc() override + { + return global_alloc(osd_font_dwrite(m_d2dfactory, m_dwriteFactory, m_wicFactory)); + } +}; + +#else +MODULE_NOT_SUPPORTED(font_dwrite, OSD_FONT_PROVIDER, "dwrite") +#endif + +MODULE_DEFINITION(FONT_DWRITE, font_dwrite) \ No newline at end of file diff --git a/src/osd/modules/lib/osdobj_common.cpp b/src/osd/modules/lib/osdobj_common.cpp index be9590087c9..5cb7cb85da4 100644 --- a/src/osd/modules/lib/osdobj_common.cpp +++ b/src/osd/modules/lib/osdobj_common.cpp @@ -188,6 +188,7 @@ void osd_common_t::register_options() { REGISTER_MODULE(m_mod_man, FONT_OSX); REGISTER_MODULE(m_mod_man, FONT_WINDOWS); + REGISTER_MODULE(m_mod_man, FONT_DWRITE); REGISTER_MODULE(m_mod_man, FONT_SDL); REGISTER_MODULE(m_mod_man, FONT_NONE); diff --git a/src/osd/windows/winutil.cpp b/src/osd/windows/winutil.cpp index f7d120e6ea2..fe835301907 100644 --- a/src/osd/windows/winutil.cpp +++ b/src/osd/windows/winutil.cpp @@ -11,6 +11,9 @@ #include #include +// MAME headers +#include "emu.h" + // MAMEOS headers #include "winutil.h" #include "strconv.h" @@ -146,3 +149,61 @@ HMODULE WINAPI GetModuleHandleUni() VirtualQuery((LPCVOID)GetModuleHandleUni, &mbi, sizeof(mbi)); return (HMODULE)mbi.AllocationBase; } + +//----------------------------------------------------------- +// Lazy loaded function using LoadLibrary / GetProcAddress +//----------------------------------------------------------- + +lazy_loaded_function::lazy_loaded_function(const char * name, const wchar_t* dll_name) + : lazy_loaded_function(name, &dll_name, 1) +{ +} + +lazy_loaded_function::lazy_loaded_function(const char * name, const wchar_t** dll_names, int dll_count) + : m_name(name), m_initialized(false), m_pfn(nullptr) +{ + for (int i = 0; i < dll_count; i++) + m_dll_names.push_back(std::wstring(dll_names[i])); +} + +lazy_loaded_function::~lazy_loaded_function() +{ + if (m_module != nullptr) + { + FreeLibrary(m_module); + m_module = nullptr; + } +} + +int lazy_loaded_function::initialize() +{ + if (m_module == nullptr) + { + for (int i = 0; i < m_dll_names.size(); i++) + { + m_module = LoadLibraryW(m_dll_names[i].c_str()); + if (m_module != NULL) + break; + } + + if (m_module == NULL) + return ERROR_DLL_NOT_FOUND; + } + + if (m_pfn == nullptr) + { + m_pfn = GetProcAddress(m_module, m_name.c_str()); + if (m_pfn == nullptr) + return ERROR_NOT_FOUND; + } + + m_initialized = true; + + return 0; +} + +void lazy_loaded_function::check_init() +{ + if (!m_initialized) + fatalerror("Attempt to use function pointer for function %s prior to init!", name()); +} diff --git a/src/osd/windows/winutil.h b/src/osd/windows/winutil.h index c8d1190b6a8..8f205e5a8ba 100644 --- a/src/osd/windows/winutil.h +++ b/src/osd/windows/winutil.h @@ -10,6 +10,8 @@ #define __WINUTIL__ #include "osdcore.h" +#include +#include // Shared code file_error win_error_to_file_error(DWORD error); @@ -17,4 +19,138 @@ osd_dir_entry_type win_attributes_to_entry_type(DWORD attributes); BOOL win_is_gui_application(void); HMODULE WINAPI GetModuleHandleUni(); +//----------------------------------------------------------- +// Lazy loaded function using LoadLibrary / GetProcAddress +//----------------------------------------------------------- + +class lazy_loaded_function +{ +private: + std::string m_name; + std::vector m_dll_names; + HMODULE m_module; + bool m_initialized; + +protected: + void check_init(); + FARPROC m_pfn; + +public: + lazy_loaded_function(const char * name, const wchar_t* dll_name); + lazy_loaded_function(const char * name, const wchar_t** dll_names, int dll_count); + ~lazy_loaded_function(); + int initialize(); + const char * name() { return m_name.c_str(); } +}; + +// No parameters +template +class lazy_loaded_function_ret : public lazy_loaded_function +{ +public: + lazy_loaded_function_ret(const char * name, const wchar_t* dll_name) + : lazy_loaded_function(name, &dll_name, 1) + { + } + + lazy_loaded_function_ret(const char * name, const wchar_t** dll_names, int dll_count) + : lazy_loaded_function(name, dll_names, dll_count) + { + } + + TRet operator ()() + { + check_init(); + return ((TRet(__stdcall *) ())m_pfn)(); + } +}; + +// One parameter +template +class lazy_loaded_function_p1 : public lazy_loaded_function +{ +public: + lazy_loaded_function_p1(const char * name, const wchar_t* dll_name) + : lazy_loaded_function(name, &dll_name, 1) + { + } + + lazy_loaded_function_p1(const char * name, const wchar_t** dll_names, int dll_count) + : lazy_loaded_function(name, dll_names, dll_count) + { + } + + TRet operator ()(P1 p1) + { + check_init(); + return ((TRet(__stdcall *) (P1))m_pfn)(p1); + } +}; + +// Two parameters +template +class lazy_loaded_function_p2 : public lazy_loaded_function +{ +public: + lazy_loaded_function_p2(const char * name, const wchar_t* dll_name) + : lazy_loaded_function(name, &dll_name, 1) + { + } + + lazy_loaded_function_p2(const char * name, const wchar_t** dll_names, int dll_count) + : lazy_loaded_function(name, dll_names, dll_count) + { + } + + TRet operator ()(P1 p1, P2 p2) + { + check_init(); + return ((TRet(__stdcall *) (P1, P2))m_pfn)(p1, p2); + } +}; + +// Three parameters +template +class lazy_loaded_function_p3 : public lazy_loaded_function +{ +public: + lazy_loaded_function_p3(const char * name, const wchar_t* dll_name) + : lazy_loaded_function(name, &dll_name, 1) + { + } + + lazy_loaded_function_p3(const char * name, const wchar_t** dll_names, int dll_count) + : lazy_loaded_function(name, dll_names, dll_count) + { + } + + TRet operator ()(P1 p1, P2 p2, P3 p3) + { + check_init(); + return ((TRet(__stdcall *) (P1, P2, P3))m_pfn)(p1, p2, p3); + } +}; + +// Four parameters +template +class lazy_loaded_function_p4 : public lazy_loaded_function +{ +public: + lazy_loaded_function_p4(const char * name, const wchar_t* dll_name) + : lazy_loaded_function(name, &dll_name, 1) + { + } + + lazy_loaded_function_p4(const char * name, const wchar_t** dll_names, int dll_count) + : lazy_loaded_function(name, dll_names, dll_count) + { + } + + TRet operator ()(P1 p1, P2 p2, P3 p3, P4 p4) + { + check_init(); + return ((TRet(__stdcall *) (P1, P2, P3, P4))m_pfn)(p1, p2, p3, p4); + } +}; + #endif // __WINUTIL__ -- cgit v1.2.3-70-g09d2