Add DirectWrite font support module

This commit is contained in:
Brad Hughes 2016-03-02 14:13:53 -05:00
parent 8a84dd2232
commit 8803de248e
5 changed files with 907 additions and 0 deletions

View File

@ -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",

View File

@ -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 <windows.h>
#include <tchar.h>
#include <memory>
// Windows Imaging Components
#include <wincodec.h>
// Load InitGuid after WIC to work around missing format problem
#include <initguid.h>
// Direct2D
#include <dxgi1_2.h>
#include <d2d1_1.h>
#include <dwrite_1.h>
// 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 <wrl\client.h>
#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<HRESULT, D2D1_FACTORY_TYPE, REFIID, const D2D1_FACTORY_OPTIONS*, void**> d2d_create_factory_fn;
typedef lazy_loaded_function_p3<HRESULT, DWRITE_FACTORY_TYPE, REFIID, IUnknown**> 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<IWICStream> stream;
ComPtr<ID2D1Factory1> d2dfactory;
ComPtr<IDWriteFactory> dwriteFactory;
ComPtr<IWICImagingFactory> 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<void**>(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<IUnknown **>(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<IWICBitmapEncoder> encoder;
HR_RET(wicFactory->CreateEncoder(GUID_ContainerFormatBmp, NULL, &encoder));
HR_RET(encoder->Initialize(stream.Get(), WICBitmapEncoderNoCache));
ComPtr<IWICBitmapFrameEncode> 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<UINT32> 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<IWICImagingFactory> wicFactory;
HR_RET(CoCreateInstance(
CLSID_WICImagingFactory,
NULL,
CLSCTX_INPROC_SERVER,
__uuidof(IWICImagingFactory),
(void**)&wicFactory));
// Save bitmap
ComPtr<IWICBitmap> 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<ID2D1Factory> m_d2dfactory;
ComPtr<IDWriteFactory> m_dwriteFactory;
ComPtr<IWICImagingFactory> m_wicFactory;
ComPtr<IDWriteFont> m_font;
float m_fontEmHeightInDips;
public:
osd_font_dwrite(ComPtr<ID2D1Factory> d2dfactory, ComPtr<IDWriteFactory> dwriteFactory, ComPtr<IWICImagingFactory> 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<WCHAR, void(*)(void *)>(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<ID2D1BitmapRenderTarget> target;
ComPtr<ID2D1SolidColorBrush> pWhiteBrush;
ComPtr<IWICBitmap> wicBitmap;
ComPtr<IWICBitmapLock> lock;
ComPtr<IDWriteFontFace> 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<ID2D1RenderTarget**>(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<IDWriteFontCollection> 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<IDWriteFontFamily> family;
HR_RETHR(fonts->GetFontFamily(family_index, family.GetAddressOf()));
ComPtr<IDWriteFont> 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<ID2D1Factory> m_d2dfactory;
ComPtr<IDWriteFactory> m_dwriteFactory;
ComPtr<IWICImagingFactory> 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<void**>(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<IUnknown **>(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)

View File

@ -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);

View File

@ -11,6 +11,9 @@
#include <windows.h>
#include <direct.h>
// 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());
}

View File

@ -10,6 +10,8 @@
#define __WINUTIL__
#include "osdcore.h"
#include <string>
#include <vector>
// 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<std::wstring> 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 TRet>
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 TRet, class P1>
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 TRet, class P1, class P2>
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 TRet, class P1, class P2, class P3>
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 TRet, class P1, class P2, class P3, class P4>
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__