Skip to content

Instantly share code, notes, and snippets.

@mmozeiko
Created July 25, 2018 17:36
Show Gist options
  • Star 6 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mmozeiko/22cd5a20f173bc6caa6af732729727f0 to your computer and use it in GitHub Desktop.
Save mmozeiko/22cd5a20f173bc6caa6af732729727f0 to your computer and use it in GitHub Desktop.
DirectWrite without D2D
#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(&params));
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