Beispiel #1
0
void FontRendererImpl::DrawText(fwWString text, const CRect& rect, const CRGBA& color, float fontSize, float fontScale, fwString fontRef)
{
	// wait for a swap to complete
	FrpSeqAllocatorWaitForSwap();

	m_mutex.lock();

	// create or find a text format
	ComPtr<IDWriteTextFormat> textFormat;

	auto formatKey = std::make_pair(fontRef, fontSize);
	auto formatIter = m_textFormatCache.find(formatKey);

	if (formatIter != m_textFormatCache.end())
	{
		textFormat = formatIter->second;
	}
	else
	{
		wchar_t fontRefWide[128];
		mbstowcs(fontRefWide, fontRef.c_str(), _countof(fontRefWide));

		m_dwFactory->CreateTextFormat(fontRefWide, nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, fontSize, L"en-us", textFormat.GetAddressOf());

		m_textFormatCache[formatKey] = textFormat;
	}

	// create or find a cached text layout
	ComPtr<IDWriteTextLayout> textLayout;

	auto layoutKey = std::make_pair(textFormat.Get(), std::make_pair(color.AsARGB(), text));
	auto layoutIter = m_textLayoutCache.find(layoutKey);

	if (layoutIter != m_textLayoutCache.end())
	{
		textLayout = layoutIter->second;
	}
	else
	{
		m_dwFactory->CreateTextLayout(text.c_str(), text.length(), textFormat.Get(), rect.Width(), rect.Height(), textLayout.GetAddressOf());

		m_textLayoutCache[layoutKey] = textLayout;

		// set effect
		DWRITE_TEXT_RANGE effectRange = { 0, UINT32_MAX };
		ComPtr<CitizenDrawingEffect> effect = Make<CitizenDrawingEffect>();

		effect->SetColor(color);

		textLayout->SetDrawingEffect((IUnknown*)effect.Get(), effectRange);
	}

	// draw
	auto drawingContext = new CitizenDrawingContext();
	textLayout->Draw(drawingContext, m_textRenderer.Get(), rect.Left(), rect.Top());

	auto numRuns = drawingContext->glyphRuns.size();

	if (numRuns)
	{
		for (auto& run : drawingContext->glyphRuns)
		{
			m_queuedGlyphRuns.push_back(run);
		}
	}

	delete drawingContext;

	m_mutex.unlock();
}
void FontRendererImpl::DrawText(const std::string& text, const Rect& rect, const RGBA& color, float fontSize, float fontScale, const std::string& fontRef)
{
	// wait for a swap to complete
	FrpSeqAllocatorWaitForSwap();

	m_mutex.lock();

	// create or find a text format
	ComPtr<IDWriteTextFormat> textFormat;

	auto formatKey = std::make_pair(fontRef, fontSize);
	auto formatIter = m_textFormatCache.find(formatKey);

	if (formatIter != m_textFormatCache.end())
	{
		textFormat = formatIter->second;
	}
	else
	{
		m_dwFactory->CreateTextFormat(ToWide(fontRef).c_str(), nullptr, DWRITE_FONT_WEIGHT_NORMAL, DWRITE_FONT_STYLE_NORMAL, DWRITE_FONT_STRETCH_NORMAL, fontSize, L"en-us", textFormat.GetAddressOf());

		m_textFormatCache[formatKey] = textFormat;
	}

	// create or find a cached text layout
	ComPtr<IDWriteTextLayout> textLayout;

	auto layoutKey = std::make_pair(textFormat.Get(), std::make_pair(color.AsARGB(), text));
	auto layoutIter = m_textLayoutCache.find(layoutKey);

	if (layoutIter != m_textLayoutCache.end())
	{
		textLayout = layoutIter->second;
	}
	else
	{
		std::wstring wideText = ToWide(text);
		
		// parse colors and the lot
		std::wstring noColorTextString;

		std::vector<DWRITE_TEXT_RANGE> textRanges;
		std::vector<RGBA> textColors;

		{
			std::wstringstream noColorText;
			int count = 0;

			static const RGBA colors[] = {
				RGBA(0, 0, 0),
				RGBA(255, 0, 0),
				RGBA(0, 255, 0),
				RGBA(255, 255, 0),
				RGBA(0, 0, 255),
				RGBA(0, 255, 255),
				RGBA(255, 0, 255),
				RGBA(255, 255, 255),
				RGBA(100, 0, 0),
				RGBA(0, 0, 100)
			};

			textRanges.reserve(50);
			textColors.reserve(50);

			textRanges.push_back({ 0, UINT32_MAX });
			textColors.push_back(color);

			for (int i = 0; i < wideText.length(); i++)
			{
				if (wideText[i] == '^' && (i + 1) < wideText.length() && isdigit(wideText[i + 1]))
				{
					textRanges.back().length = count - textRanges.back().startPosition;
					textRanges.push_back({ (UINT32)count, UINT32_MAX });

					textColors.push_back(colors[wideText[i + 1] - '0']);

					++i;
					continue;
				}

				noColorText << wideText[i];
				++count;
			}

			textRanges.back().length = count - textRanges.back().startPosition;

			noColorTextString = noColorText.str();
		}

		m_dwFactory->CreateTextLayout(noColorTextString.c_str(), static_cast<UINT32>(noColorTextString.length()), textFormat.Get(), rect.Width(), rect.Height(), textLayout.GetAddressOf());

		m_textLayoutCache[layoutKey] = textLayout;

		// set effect
		for (size_t i : irange(textRanges.size()))
		{
			DWRITE_TEXT_RANGE effectRange = textRanges[i];
			RGBA color = textColors[i];

			static thread_local std::map<uint32_t, ComPtr<FrDrawingEffect>> effects;
			auto it = effects.find(color.AsARGB());

			if (it == effects.end())
			{
				ComPtr<FrDrawingEffect> effect = Make<FrDrawingEffect>();

				effect->SetColor(textColors[i]);

				it = effects.insert({ color.AsARGB(), effect }).first;
			}

			check(SUCCEEDED(textLayout->SetDrawingEffect((IUnknown*)it->second.Get(), effectRange)));
		}
	}

	// draw
	auto drawingContext = new FrDrawingContext();
	textLayout->Draw(drawingContext, m_textRenderer.Get(), rect.Left(), rect.Top());

	auto numRuns = drawingContext->glyphRuns.size();

	if (numRuns)
	{
		for (auto& run : drawingContext->glyphRuns)
		{
			m_queuedRenderables.push_back(std::make_unique<FrGlyphRunRenderable>(run));
			//m_queuedGlyphRuns.push_back(run);
		}
	}

	delete drawingContext;

	m_mutex.unlock();
}