Created
July 25, 2018 17:36
-
-
Save mmozeiko/22cd5a20f173bc6caa6af732729727f0 to your computer and use it in GitHub Desktop.
DirectWrite without D2D
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#define WIN32_LEAN_AND_MEAN | |
#include <windows.h> | |
#include <dwrite.h> | |
#include <intrin.h> | |
#pragma comment (lib, "gdi32.lib") | |
#pragma comment (lib, "user32.lib") | |
#pragma comment (lib, "dwrite.lib") | |
#define CHECK(x) do { if (!(x)) __debugbreak(); } while (0) | |
#define HR_CHECK(x) do { if (FAILED(x)) __debugbreak(); } while (0) | |
struct MyRender : IDWriteTextRenderer | |
{ | |
IDWriteBitmapRenderTarget* target; | |
IDWriteRenderingParams* params; | |
COLORREF color; | |
STDMETHOD(QueryInterface) (REFIID riid, void** ppvObject) | |
{ | |
// not called | |
*ppvObject = NULL; | |
return E_NOTIMPL; | |
} | |
STDMETHOD_(ULONG,AddRef) () | |
{ | |
// not called | |
return 0; | |
} | |
STDMETHOD_(ULONG,Release) () | |
{ | |
// not called | |
return 0; | |
} | |
STDMETHOD(IsPixelSnappingDisabled) (void* ctx, BOOL* isDisabled) | |
{ | |
*isDisabled = FALSE; | |
return S_OK; | |
} | |
STDMETHOD(GetCurrentTransform) (void* ctx, DWRITE_MATRIX* transform) | |
{ | |
DWRITE_MATRIX identity = { | |
1, 0, | |
0, 1, | |
0, 0 | |
}; | |
*transform = identity; | |
return S_OK; | |
} | |
STDMETHOD(GetPixelsPerDip) (void* ctx, FLOAT* pixelsPerDip) | |
{ | |
// TODO: get from current monitor or smth? | |
*pixelsPerDip = 96.0f; | |
return S_OK; | |
} | |
STDMETHOD(DrawGlyphRun) (void* ctx, FLOAT baselineOriginX, FLOAT baselineOriginY, DWRITE_MEASURING_MODE measuringMode, const DWRITE_GLYPH_RUN* glyphRun, const DWRITE_GLYPH_RUN_DESCRIPTION* glyphRunDescription, IUnknown* clientDrawingEffect) | |
{ | |
return target->DrawGlyphRun(baselineOriginX, baselineOriginY, measuringMode, glyphRun, this->params, this->color); | |
} | |
STDMETHOD(DrawUnderline) (void* ctx, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_UNDERLINE* underline, IUnknown* clientDrawingEffect) | |
{ | |
// not supported | |
CHECK(0); | |
return E_NOTIMPL; | |
} | |
STDMETHOD(DrawStrikethrough) (void* ctx, FLOAT baselineOriginX, FLOAT baselineOriginY, const DWRITE_STRIKETHROUGH* strikethrough, IUnknown* clientDrawingEffect) | |
{ | |
// not supported | |
CHECK(0); | |
return E_NOTIMPL; | |
} | |
STDMETHOD(DrawInlineObject) (void* ctx, FLOAT originX, FLOAT originY, IDWriteInlineObject* inlineObject, BOOL isSideways, BOOL isRightToLeft, IUnknown* clientDrawingEffect) | |
{ | |
// not supported | |
CHECK(0); | |
return E_NOTIMPL; | |
} | |
}; | |
int main() | |
{ | |
HRESULT hr; | |
IDWriteFactory* factory; | |
IDWriteTextFormat* format; | |
IDWriteRenderingParams* params; | |
IDWriteGdiInterop* gdi; | |
IDWriteBitmapRenderTarget* target; | |
const DWORD width = 256; | |
const DWORD height = 256; | |
HR_CHECK(hr = DWriteCreateFactory(DWRITE_FACTORY_TYPE_SHARED, __uuidof(IDWriteFactory), (IUnknown**)&factory)); | |
HR_CHECK(hr = factory->CreateTextFormat(L"Comics Sans", NULL, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, 24.f, L"en-US", &format)); | |
HR_CHECK(hr = factory->CreateRenderingParams(¶ms)); | |
HR_CHECK(hr = factory->GetGdiInterop(&gdi)); | |
HR_CHECK(hr = gdi->CreateBitmapRenderTarget(NULL, width, height, &target)); | |
MyRender renderer; | |
renderer.target = target; | |
renderer.params = params; | |
renderer.color = RGB(0, 255, 0); | |
const WCHAR text[] = L"Hello World!"; | |
IDWriteTextLayout* layout; | |
HR_CHECK(hr = factory->CreateTextLayout(text, _countof(text) - 1, format, width, 0, &layout)); | |
HR_CHECK(hr = layout->Draw(NULL, &renderer, 0.f, 0.f)); | |
layout->Release(); | |
{ | |
// the memory bitmap is always 32-bit top-down | |
HDC dc = target->GetMemoryDC(); | |
HBITMAP bitmap = (HBITMAP)GetCurrentObject(dc, OBJ_BITMAP); | |
DIBSECTION dib; | |
GetObject(bitmap, sizeof(dib), &dib); | |
HANDLE f = CreateFileA("test.bmp", GENERIC_WRITE, 0, NULL, CREATE_ALWAYS, FILE_ATTRIBUTE_NORMAL, NULL); | |
CHECK(f != INVALID_HANDLE_VALUE); | |
BITMAPINFOHEADER header = {}; | |
header.biSize = sizeof(header); | |
header.biWidth = width; | |
header.biHeight = -height; // vertical flip | |
header.biPlanes = 1; | |
header.biBitCount = 32; | |
header.biCompression = BI_RGB; | |
BITMAPFILEHEADER bmp; | |
bmp.bfType = 'B' + ('M' << 8); | |
bmp.bfSize = sizeof(bmp) + sizeof(header) + height * dib.dsBm.bmWidthBytes; | |
bmp.bfOffBits = sizeof(bmp) + sizeof(header); | |
DWORD written; | |
WriteFile(f, &bmp, sizeof(bmp), &written, NULL); | |
WriteFile(f, &header, sizeof(header), &written, NULL); | |
WriteFile(f, dib.dsBm.bmBits, height * dib.dsBm.bmWidthBytes, &written, NULL); | |
CloseHandle(f); | |
} | |
target->Release(); | |
gdi->Release(); | |
params->Release(); | |
format->Release(); | |
factory->Release(); | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment