Hi guys, I'm having a problem rendering with DWrite, and I don't understand why, can you help me figure it out?
As you can see in the image below, if you look carefully you'll notice that the top of R8 is cut (missing 1 row of pixels), the bottom of R11 is cut again, the 4 in R14 is rendered weird compared to the 4 in R4 and so on, if you look closely you'll spot more yourself.
I can't figure out why ?
Under the image I'll also leave the code, in case I'm doing something wrong like with type conversion or stuff. Any help is much appreciated
#include "GBAEmulator_PCH.h"
#include "Disassembler.h"
#include "GBAEmulator.h"
Disassembler::Disassembler(LONG width, LONG height, HINSTANCE hInstance, GBAEmulator* emuInstance) :
D2DWindowBase(width, height, hInstance, emuInstance),
m_background(0.156f, 0.087f, 0.16f, 1.f),
m_textFormat{ nullptr }
{
//Init Window
std::string className = "Disassembler";
std::string windowName = "Disassembler";
WNDCLASSEX clientClass{};
clientClass.cbSize = sizeof(WNDCLASSEX);
clientClass.style = CS_HREDRAW | CS_VREDRAW;
clientClass.lpfnWndProc = GBAEmulator::DisassemblerWinProc;
clientClass.hInstance = m_hInstance;
//clientClass.hIcon =; TODO: Add Icon
clientClass.hCursor = LoadCursor(m_hInstance, IDC_ARROW);
clientClass.hbrBackground = (HBRUSH)(COLOR_BACKGROUND + 1);
clientClass.lpszClassName = className.c_str();
//clientClass.hIconSm =; TODO: Add Icon
DWORD windowStyle = WS_VISIBLE | WS_CAPTION | WS_MINIMIZEBOX | WS_TABSTOP | WS_SYSMENU;
m_isValid = InitWindow(windowName, clientClass, windowStyle, false);
//Init DWrite
if (m_isValid)
m_isValid = InitDWrite();
std::vector<std::wstring> tempEntries{
L"PC: ", L"R0: ", L"R1: ", L"R2: ", L"R3: ", L"R4: ",
L"R5: ", L"R6: ", L"R7: ", L"R8: ", L"R9: ", L"R10: ",
L"R11: ", L"R12: ", L"R13: ", L"R14: ", L"R15: ", L"R16: "
};
std::wstring value = L"-UNDEFINED-";
FLOAT left{}, top{}, right{ 300.f }, bottom{ 50.f };
for (auto& s : tempEntries)
{
m_entries.emplace_back(TextEntry{ s, value, D2D1_RECT_F{ left, top, right, bottom} });
top += 30.f;
bottom += 30.f;
}
}
bool Disassembler::InitDWrite()
{
//Set Text Format
HRESULT hr;
hr = m_DWriteFactory->CreateTextFormat(
L"consolas",
NULL,
DWRITE_FONT_WEIGHT_NORMAL,
DWRITE_FONT_STYLE_NORMAL,
DWRITE_FONT_STRETCH_NORMAL,
22.f,
L"en-US",
&m_textFormat
);
if (FAILED(hr))
{
MessageBox(NULL, "Failed to create TextFormat", "Error", MB_OK);
return false;
}
//Set Colors
m_renderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::SkyBlue),
&m_fillBrush1
);
m_renderTarget->CreateSolidColorBrush(
D2D1::ColorF(D2D1::ColorF::Crimson),
&m_fillBrush2
);
return true;
}
Disassembler::~Disassembler()
{
DestroyWindow(m_hwnd);
if (m_textFormat) m_textFormat->Release();
if (m_fillBrush1) m_fillBrush1->Release();
if (m_fillBrush2) m_fillBrush2->Release();
}
void Disassembler::Updade(float deltaTime)
{
}
void Disassembler::Draw()
{
m_renderTarget->BeginDraw();
m_renderTarget->Clear(m_background);
for (auto& entry : m_entries)
{
DrawEntryWithShadow(entry);
}
m_renderTarget->EndDraw();
}
void Disassembler::DrawEntryWithShadow(const TextEntry& entry)
{
//shadow offset
D2D1_RECT_F shadowPos = entry.position;
shadowPos.top += 1.05f;
shadowPos.left -= 0.95f;
//draw text
DrawEntry(entry.text, shadowPos, m_fillBrush2);
DrawEntry(entry.text, entry.position, m_fillBrush1);
D2D1_RECT_F valuePos = entry.position;
FLOAT valueOffset = 50.f;
valuePos.left += valueOffset;
valuePos.right += valueOffset;
shadowPos.left += valueOffset;
shadowPos.right += valueOffset;
//draw value
DrawEntry(entry.value, shadowPos, m_fillBrush2);
DrawEntry(entry.value, valuePos, m_fillBrush1);
}
void Disassembler::DrawEntry(const std::wstring& text, const D2D1_RECT_F& pos, ID2D1SolidColorBrush* brush)
{
m_renderTarget->DrawTextA(
text.c_str(),
static_cast<UINT>(text.size()),
m_textFormat,
pos,
brush,
D2D1_DRAW_TEXT_OPTIONS_NONE
);
}