summaryrefslogtreecommitdiffstats
path: root/src/runtimerender/Qt3DSOnscreenTextRenderer.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/runtimerender/Qt3DSOnscreenTextRenderer.cpp')
-rw-r--r--src/runtimerender/Qt3DSOnscreenTextRenderer.cpp421
1 files changed, 421 insertions, 0 deletions
diff --git a/src/runtimerender/Qt3DSOnscreenTextRenderer.cpp b/src/runtimerender/Qt3DSOnscreenTextRenderer.cpp
new file mode 100644
index 0000000..4b74c51
--- /dev/null
+++ b/src/runtimerender/Qt3DSOnscreenTextRenderer.cpp
@@ -0,0 +1,421 @@
+/****************************************************************************
+**
+** Copyright (C) 2008-2012 NVIDIA Corporation.
+** Copyright (C) 2017 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt 3D Studio.
+**
+** $QT_BEGIN_LICENSE:GPL$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 or (at your option) any later version
+** approved by the KDE Free Qt Foundation. The licenses are as published by
+** the Free Software Foundation and appearing in the file LICENSE.GPL3
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+#define QT3DS_RENDER_ONSCREEN_TEXT
+#ifdef QT3DS_RENDER_ONSCREEN_TEXT
+
+#include "Qt3DSTextRenderer.h"
+#include "Qt3DSRenderTextureAtlas.h"
+
+#include "EASTL/string.h"
+#include "EASTL/hash_set.h"
+
+#include "foundation/Qt3DSContainers.h"
+#include "foundation/Qt3DSFoundation.h"
+#include "foundation/StrConvertUTF.h"
+
+#include "render/Qt3DSRenderContext.h"
+
+#include <QtGui/qpainter.h>
+#include <QtGui/qimage.h>
+#include <QtGui/qrawfont.h>
+#include <QtCore/qfile.h>
+
+using namespace qt3ds::render;
+
+namespace {
+
+struct STextureAtlasFontEntry
+{
+ STextureAtlasFontEntry()
+ : m_x(0)
+ , m_y(0)
+ , m_width(0)
+ , m_height(0)
+ , m_xOffset(0)
+ , m_yOffset(0)
+ , m_advance(0)
+ , m_s(0)
+ , m_t(0)
+ , m_s1(0)
+ , m_t1(0)
+ {
+ }
+
+ STextureAtlasFontEntry(float x, float y, float width, float height, float xoffset,
+ float yoffset, float advance, float s, float t, float s1, float t1)
+ : m_x(x)
+ , m_y(y)
+ , m_width(width)
+ , m_height(height)
+ , m_xOffset(xoffset)
+ , m_yOffset(yoffset)
+ , m_advance(advance)
+ , m_s(s)
+ , m_t(t)
+ , m_s1(s1)
+ , m_t1(t1)
+ {
+ }
+
+ QT3DSF32 m_x;
+ QT3DSF32 m_y;
+ QT3DSF32 m_width;
+ QT3DSF32 m_height;
+ QT3DSF32 m_xOffset;
+ QT3DSF32 m_yOffset;
+ QT3DSF32 m_advance;
+
+ QT3DSF32 m_s;
+ QT3DSF32 m_t;
+ QT3DSF32 m_s1;
+ QT3DSF32 m_t1;
+};
+
+typedef eastl::basic_string<char8_t, ForwardingAllocator> TStrType;
+typedef nvhash_map<wchar_t, STextureAtlasFontEntry> TTextureAtlasMap;
+
+struct STextAtlasFont
+{
+ NVFoundationBase &m_Foundation;
+ volatile QT3DSI32 mRefCount;
+ QT3DSU32 m_FontSize;
+ TTextureAtlasMap m_AtlasEntries; ///< our entries in the atlas
+
+ STextAtlasFont(NVFoundationBase &inFoundation, QT3DSU32 fontSize)
+ : m_Foundation(inFoundation)
+ , mRefCount(0)
+ , m_FontSize(fontSize)
+ , m_AtlasEntries(inFoundation.getAllocator(),
+ "Qt3DSOnscreenRenderer::STextAtlasFont::m_AtlasEntrys")
+ {
+ }
+
+ ~STextAtlasFont() { m_AtlasEntries.clear(); }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE(m_Foundation.getAllocator())
+
+ static STextAtlasFont &CreateTextureAtlasFont(NVFoundationBase &inFnd, QT3DSU32 fontSize)
+ {
+ return *QT3DS_NEW(inFnd.getAllocator(), STextAtlasFont)(inFnd, fontSize);
+ }
+};
+
+// This class is only for rendering 2D screen aligned text
+// it uses a predefined true type font and character set with various sizes
+struct Qt3DSOnscreenTextRenderer : public ITextRenderer
+{
+
+ static const QT3DSI32 TEXTURE_ATLAS_DIM =
+ 256; // if you change this you need to adjust STextTextureAtlas size as well
+
+private:
+ NVFoundationBase &m_Foundation;
+ NVScopedRefCounted<NVRenderContext> m_RenderContext;
+ volatile QT3DSI32 mRefCount;
+ bool m_TextureAtlasInitialized; ///< true if atlas is setup
+ NVScopedRefCounted<ITextureAtlas> m_TextTextureAtlas;
+ NVScopedRefCounted<STextAtlasFont> m_TextFont;
+ QRawFont *m_font;
+public:
+ Qt3DSOnscreenTextRenderer(NVFoundationBase &inFoundation)
+ : m_Foundation(inFoundation)
+ , mRefCount(0)
+ , m_TextureAtlasInitialized(false)
+ , m_font(nullptr)
+ {
+ }
+
+ virtual ~Qt3DSOnscreenTextRenderer()
+ {
+ }
+
+ QT3DS_IMPLEMENT_REF_COUNT_ADDREF_RELEASE_OVERRIDE(m_Foundation.getAllocator())
+
+ void AddSystemFontDirectory(const char8_t *) override {}
+
+ virtual void AddProjectFontDirectory(CRegisteredString)
+ {
+ // We always render using the default font with on-screen renderer,
+ // so no need to care about font directories
+ }
+
+ void AddProjectFontDirectory(const char8_t *inProjectDirectory) override
+ {
+ if (m_RenderContext)
+ AddProjectFontDirectory(
+ m_RenderContext->GetStringTable().RegisterStr(inProjectDirectory));
+ }
+
+ void loadFont()
+ {
+ // Ensure font. We can only render text of single size at the moment.
+ // Add a size map of fonts if it ever becomes necessary to render multiple font sizes.
+ if (!m_font)
+ m_font = new QRawFont(QStringLiteral(":res/Font/TitilliumWeb-Regular.ttf"), 20.0);
+
+ // setup texture atlas
+ m_TextTextureAtlas =
+ ITextureAtlas::CreateTextureAtlas(m_RenderContext->GetFoundation(), *m_RenderContext,
+ TEXTURE_ATLAS_DIM, TEXTURE_ATLAS_DIM);
+
+ // our list of predefined cached characters
+ QString cache = QStringLiteral(" !\"#$%&'()*+,-./0123456789:;<=>?"
+ "@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_"
+ "`abcdefghijklmnopqrstuvwxyz{|}~");
+
+ m_TextFont = STextAtlasFont::CreateTextureAtlasFont(m_Foundation, 20);
+ CreateTextureAtlasEntries(m_font, *m_TextFont, cache);
+ m_TextureAtlasInitialized = true;
+ }
+
+ void CreateTextureAtlasEntries(QRawFont *rawFont, STextAtlasFont &font, const QString &cache)
+ {
+ if (m_TextureAtlasInitialized || !m_TextTextureAtlas || !rawFont)
+ return;
+
+ STextureAtlasRect theAtlasRect;
+
+ QVector<quint32> glyphIndices = rawFont->glyphIndexesForString(cache);
+ QVector<QPointF> glyphAdvances = rawFont->advancesForGlyphIndexes(glyphIndices);
+
+ for (int i = 0; i < glyphIndices.size(); i++) {
+ quint32 index = glyphIndices[i];
+ QImage glyphImage;
+
+ // blank char is not contained in a true type font
+ if (cache.at(i) != QChar(' '))
+ glyphImage = rawFont->alphaMapForGlyph(index, QRawFont::PixelAntialiasing);
+
+ QRectF rect = rawFont->boundingRect(index);
+ NVConstDataRef<QT3DSU8> bufferData(static_cast<const QT3DSU8 *>(glyphImage.bits()),
+ glyphImage.byteCount());
+
+ theAtlasRect = m_TextTextureAtlas->AddAtlasEntry(
+ glyphImage.width(), glyphImage.height(),
+ glyphImage.bytesPerLine(), glyphImage.width(), bufferData);
+
+ if (theAtlasRect.m_Width != 0) {
+ font.m_AtlasEntries.insert(
+ eastl::make_pair(
+ cache.at(i).unicode(), STextureAtlasFontEntry(
+ (QT3DSF32)theAtlasRect.m_X, (QT3DSF32)theAtlasRect.m_Y,
+ (QT3DSF32)theAtlasRect.m_Width, (QT3DSF32)theAtlasRect.m_Height,
+ (QT3DSF32)rect.x(), (QT3DSF32)(0.0 - rect.height() - rect.y()),
+ glyphAdvances[i].x(),
+ theAtlasRect.m_NormX, theAtlasRect.m_NormY,
+ theAtlasRect.m_NormX + theAtlasRect.m_NormWidth,
+ theAtlasRect.m_NormY + theAtlasRect.m_NormHeight)));
+ }
+ }
+ }
+
+ void ClearProjectFontDirectories() override {}
+
+ ITextRenderer &GetTextRenderer(NVRenderContext &inRenderContext) override
+ {
+ m_RenderContext = inRenderContext;
+ return *this;
+ }
+
+ void PreloadFonts() override {}
+ void ReloadFonts() override {}
+
+ // unused
+ NVConstDataRef<SRendererFontEntry> GetProjectFontList() override
+ {
+ Q_ASSERT(false);
+ return NVConstDataRef<SRendererFontEntry>();
+ }
+
+ // unused
+ Option<CRegisteredString> GetFontNameForFont(CRegisteredString) override
+ {
+ Q_ASSERT(false);
+ return Empty();
+ }
+
+ // unused
+ Option<CRegisteredString> GetFontNameForFont(const char8_t *) override
+ {
+ Q_ASSERT(false);
+ return Empty();
+ }
+
+ // unused
+ STextDimensions MeasureText(const STextRenderInfo &, QT3DSF32, const char8_t *) override
+ {
+ Q_ASSERT(false);
+ return STextDimensions(0, 0);
+ }
+
+ // unused
+ STextTextureDetails RenderText(const STextRenderInfo &, NVRenderTexture2D &) override
+ {
+ QT3DS_ASSERT(false);
+ return STextTextureDetails();
+ }
+
+ // unused
+ STextTextureDetails RenderText(const STextRenderInfo &, NVRenderPathFontItem &,
+ NVRenderPathFontSpecification &) override
+ {
+ QT3DS_ASSERT(false);
+ return STextTextureDetails();
+ }
+
+ SRenderTextureAtlasDetails RenderText(const STextRenderInfo &inText) override
+ {
+ qt3ds::foundation::IStringTable &theStringTable(m_RenderContext->GetStringTable());
+
+ const wchar_t *wText = theStringTable.GetWideStr(inText.m_Text);
+ QT3DSU32 length = (QT3DSU32)wcslen(wText);
+
+ if (length) {
+ STextAtlasFont *pFont = m_TextFont;
+ const STextureAtlasFontEntry *pEntry;
+ QT3DSF32 x1, y1, x2, y2;
+ QT3DSF32 s, t, s1, t1;
+ QT3DSF32 advance = 0.0;
+ // allocate buffer for all the vertex data we need
+ // we construct triangles here
+ // which means character count x 6 vertices x 5 floats
+ QT3DSF32 *vertexData =
+ (QT3DSF32 *)QT3DS_ALLOC(m_Foundation.getAllocator(),
+ length * 6 * 5 * sizeof(QT3DSF32),
+ "Qt3DSOnscreenTextRenderer");
+ QT3DSF32 *bufPtr = vertexData;
+ if (vertexData) {
+ for (size_t i = 0; i < length; ++i) {
+ pEntry = &pFont->m_AtlasEntries.find(wText[i])->second;
+
+ if (pEntry) {
+ x1 = advance + pEntry->m_xOffset;
+ x2 = x1 + pEntry->m_width * inText.m_ScaleX;
+ y1 = pEntry->m_yOffset;
+ y2 = y1 + pEntry->m_height * inText.m_ScaleY;
+
+ s = pEntry->m_s;
+ s1 = pEntry->m_s1;
+ t = pEntry->m_t;
+ t1 = pEntry->m_t1;
+ // store vertex data
+ bufPtr[0] = x1;
+ bufPtr[1] = y1;
+ bufPtr[2] = 0.0;
+ bufPtr[3] = s;
+ bufPtr[4] = t;
+ bufPtr[5] = x2;
+ bufPtr[6] = y1;
+ bufPtr[7] = 0.0;
+ bufPtr[8] = s1;
+ bufPtr[9] = t;
+ bufPtr[10] = x2;
+ bufPtr[11] = y2;
+ bufPtr[12] = 0.0;
+ bufPtr[13] = s1;
+ bufPtr[14] = t1;
+
+ bufPtr[15] = x1;
+ bufPtr[16] = y1;
+ bufPtr[17] = 0.0;
+ bufPtr[18] = s;
+ bufPtr[19] = t;
+ bufPtr[20] = x2;
+ bufPtr[21] = y2;
+ bufPtr[22] = 0.0;
+ bufPtr[23] = s1;
+ bufPtr[24] = t1;
+ bufPtr[25] = x1;
+ bufPtr[26] = y2;
+ bufPtr[27] = 0.0;
+ bufPtr[28] = s;
+ bufPtr[29] = t1;
+
+ advance += pEntry->m_advance * inText.m_ScaleX;
+
+ bufPtr += 30;
+ }
+ }
+
+ m_TextTextureAtlas->RelaseEntries();
+
+ return SRenderTextureAtlasDetails(length * 6,
+ toU8DataRef(vertexData, length * 6 * 5));
+ }
+ }
+
+ return SRenderTextureAtlasDetails();
+ }
+
+ STextTextureAtlasEntryDetails RenderAtlasEntry(QT3DSU32 index,
+ NVRenderTexture2D &inTexture) override
+ {
+ if (m_TextTextureAtlas) {
+ TTextureAtlasEntryAndBuffer theEntry = m_TextTextureAtlas->GetAtlasEntryByIndex(index);
+ if (theEntry.first.m_Width) {
+ inTexture.SetTextureData(theEntry.second, 0, theEntry.first.m_Width,
+ theEntry.first.m_Height, NVRenderTextureFormats::Alpha8);
+ inTexture.SetMagFilter(qt3ds::render::NVRenderTextureMagnifyingOp::Linear);
+ inTexture.SetMinFilter(qt3ds::render::NVRenderTextureMinifyingOp::Linear);
+ inTexture.SetTextureWrapS(qt3ds::render::NVRenderTextureCoordOp::ClampToEdge);
+ inTexture.SetTextureWrapT(qt3ds::render::NVRenderTextureCoordOp::ClampToEdge);
+ STextureDetails theTextureDetails = inTexture.GetTextureDetails();
+ return STextTextureAtlasEntryDetails(theTextureDetails.m_Width,
+ theTextureDetails.m_Height, theEntry.first.m_X,
+ theEntry.first.m_Y);
+ }
+ }
+
+ return STextTextureAtlasEntryDetails();
+ }
+ QT3DSI32 CreateTextureAtlas() override
+ {
+ loadFont();
+
+ QT3DSI32 count = 0;
+ if (m_TextTextureAtlas)
+ count = m_TextTextureAtlas->GetAtlasEntryCount();
+
+ return count;
+ }
+
+ void BeginFrame() override {}
+ void EndFrame() override {}
+ void BeginPreloadFonts(IThreadPool &, IPerfTimer &) override {}
+ void EndPreloadFonts() override {}
+};
+}
+
+ITextRendererCore &ITextRendererCore::CreateOnscreenTextRenderer(NVFoundationBase &inFnd)
+{
+ return *QT3DS_NEW(inFnd.getAllocator(), Qt3DSOnscreenTextRenderer)(inFnd);
+}
+
+#endif // QT3DS_RENDER_ONSCREEN_TEXT