From 89faf85ad9e1c0ab3fae240d9409077975a37f57 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 16 Jul 2015 15:56:01 -0700 Subject: [PATCH 01/27] Working on text rendering overlays --- .../resources/qml/TextOverlayElement.qml | 21 + interface/src/Application.cpp | 1 - interface/src/Util.cpp | 22 - interface/src/Util.h | 1 - interface/src/avatar/Avatar.cpp | 2 +- interface/src/avatar/MyAvatar.cpp | 3 +- interface/src/ui/overlays/ImageOverlay.cpp | 4 +- interface/src/ui/overlays/TextOverlay.cpp | 166 +++-- interface/src/ui/overlays/TextOverlay.h | 12 +- .../src/RenderableWebEntityItem.cpp | 1 - libraries/render-utils/src/TextRenderer.cpp | 576 ------------------ libraries/render-utils/src/TextRenderer.h | 89 --- libraries/render-utils/src/TextRenderer3D.cpp | 422 +------------ libraries/render-utils/src/TextRenderer3D.h | 33 +- libraries/render-utils/src/sdf_text.slf | 49 -- libraries/render-utils/src/sdf_text.slv | 24 - libraries/render-utils/src/text/EffectType.h | 15 + libraries/render-utils/src/text/Font.cpp | 366 +++++++++++ libraries/render-utils/src/text/Font.h | 88 +++ .../render-utils/src/text/FontFamilies.h | 31 + libraries/render-utils/src/text/Glyph.cpp | 22 + libraries/render-utils/src/text/Glyph.h | 38 ++ libraries/shared/src/StreamHelpers.h | 32 + 23 files changed, 772 insertions(+), 1246 deletions(-) create mode 100644 interface/resources/qml/TextOverlayElement.qml delete mode 100644 libraries/render-utils/src/TextRenderer.cpp delete mode 100644 libraries/render-utils/src/TextRenderer.h delete mode 100644 libraries/render-utils/src/sdf_text.slf delete mode 100644 libraries/render-utils/src/sdf_text.slv create mode 100644 libraries/render-utils/src/text/EffectType.h create mode 100644 libraries/render-utils/src/text/Font.cpp create mode 100644 libraries/render-utils/src/text/Font.h create mode 100644 libraries/render-utils/src/text/FontFamilies.h create mode 100644 libraries/render-utils/src/text/Glyph.cpp create mode 100644 libraries/render-utils/src/text/Glyph.h create mode 100644 libraries/shared/src/StreamHelpers.h diff --git a/interface/resources/qml/TextOverlayElement.qml b/interface/resources/qml/TextOverlayElement.qml new file mode 100644 index 0000000000..492a38ee0b --- /dev/null +++ b/interface/resources/qml/TextOverlayElement.qml @@ -0,0 +1,21 @@ +import Hifi 1.0 +import QtQuick 2.3 +import QtQuick.Controls 1.2 + +TextOverlayElement { + id: root + Rectangle { + color: root.backgroundColor + anchors.fill: parent + Text { + x: root.leftMargin + y: root.topMargin + id: text + objectName: "textElement" + text: root.text + color: root.textColor + font.family: root.fontFamily + font.pointSize: root.fontSize + } + } +} diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 027ad159d0..5ba02221e1 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -92,7 +92,6 @@ #include #include #include -#include #include #include #include diff --git a/interface/src/Util.cpp b/interface/src/Util.cpp index 9a013c8f6f..5d625ba3a3 100644 --- a/interface/src/Util.cpp +++ b/interface/src/Util.cpp @@ -23,7 +23,6 @@ #include #include -#include #include "InterfaceConfig.h" #include "world.h" @@ -79,27 +78,6 @@ const glm::vec3 randVector() { return glm::vec3(randFloat() - 0.5f, randFloat() - 0.5f, randFloat() - 0.5f) * 2.0f; } -static TextRenderer* textRenderer(int mono) { - static TextRenderer* monoRenderer = TextRenderer::getInstance(MONO_FONT_FAMILY); - static TextRenderer* proportionalRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, - -1, -1, false, TextRenderer::SHADOW_EFFECT); - static TextRenderer* inconsolataRenderer = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, -1, INCONSOLATA_FONT_WEIGHT, - false); - switch (mono) { - case 1: - return monoRenderer; - case 2: - return inconsolataRenderer; - case 0: - default: - return proportionalRenderer; - } -} - -int widthText(float scale, int mono, char const* string) { - return textRenderer(mono)->computeExtent(string).x; // computeWidth(string) * (scale / 0.10); -} - void renderCollisionOverlay(int width, int height, float magnitude, float red, float blue, float green) { const float MIN_VISIBLE_COLLISION = 0.01f; if (magnitude > MIN_VISIBLE_COLLISION) { diff --git a/interface/src/Util.h b/interface/src/Util.h index a422918d9a..2599847f7e 100644 --- a/interface/src/Util.h +++ b/interface/src/Util.h @@ -22,7 +22,6 @@ float randFloat(); const glm::vec3 randVector(); void renderWorldBox(gpu::Batch& batch); -int widthText(float scale, int mono, char const* string); void renderCollisionOverlay(int width, int height, float magnitude, float red = 0, float blue = 0, float green = 0); diff --git a/interface/src/avatar/Avatar.cpp b/interface/src/avatar/Avatar.cpp index 6374b6b10b..239359c1cf 100644 --- a/interface/src/avatar/Avatar.cpp +++ b/interface/src/avatar/Avatar.cpp @@ -281,7 +281,7 @@ enum TextRendererType { static TextRenderer3D* textRenderer(TextRendererType type) { static TextRenderer3D* chatRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY, -1, - false, TextRenderer3D::SHADOW_EFFECT); + false, SHADOW_EFFECT); static TextRenderer3D* displayNameRenderer = TextRenderer3D::getInstance(SANS_FONT_FAMILY); switch(type) { diff --git a/interface/src/avatar/MyAvatar.cpp b/interface/src/avatar/MyAvatar.cpp index 053ce7b3cc..93303c3536 100644 --- a/interface/src/avatar/MyAvatar.cpp +++ b/interface/src/avatar/MyAvatar.cpp @@ -19,6 +19,7 @@ #include +#include #include #include #include @@ -31,7 +32,7 @@ #include #include #include -#include +#include #include #include "devices/Faceshift.h" diff --git a/interface/src/ui/overlays/ImageOverlay.cpp b/interface/src/ui/overlays/ImageOverlay.cpp index ce6e12d73e..73a3f7e39c 100644 --- a/interface/src/ui/overlays/ImageOverlay.cpp +++ b/interface/src/ui/overlays/ImageOverlay.cpp @@ -55,15 +55,15 @@ void ImageOverlay::render(RenderArgs* args) { _isLoaded = true; _texture = DependencyManager::get()->getTexture(_imageURL); } - // If we are not visible or loaded, return. If we are trying to render an // image but the texture hasn't loaded, return. if (!_visible || !_isLoaded || (_renderImage && !_texture->isLoaded())) { return; } + auto geometryCache = DependencyManager::get(); gpu::Batch& batch = *args->_batch; - + geometryCache->useSimpleDrawPipeline(batch); if (_renderImage) { batch.setResourceTexture(0, _texture->getGPUTexture()); } else { diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 3f033d9266..466e536189 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -10,15 +10,70 @@ // include this before QGLWidget, which includes an earlier version of OpenGL #include "InterfaceConfig.h" - +#include "Application.h" #include "TextOverlay.h" - +#include "OffscreenUi.h" +#include "text/FontFamilies.h" +#include #include #include +#include +#include #include #include -#include +#include +#include +#define TEXT_OVERLAY_PROPERTY(type, name, initialValue) \ + Q_PROPERTY(type name READ name WRITE set##name NOTIFY name##Changed) \ +public: \ + type name() { return _##name; }; \ + void set##name(const type& name) { \ + if (name != _##name) { \ + _##name = name; \ + emit name##Changed(); \ + } \ + } \ +private: \ + type _##name{ initialValue }; + + +class TextOverlayElement : public QQuickItem { + Q_OBJECT + HIFI_QML_DECL +private: + TEXT_OVERLAY_PROPERTY(QString, text, "") + TEXT_OVERLAY_PROPERTY(QString, fontFamily, SANS_FONT_FAMILY) + TEXT_OVERLAY_PROPERTY(QString, textColor, "#ffffffff") + TEXT_OVERLAY_PROPERTY(QString, backgroundColor, "#B2000000") + TEXT_OVERLAY_PROPERTY(qreal, fontSize, 18) + TEXT_OVERLAY_PROPERTY(qreal, leftMargin, 0) + TEXT_OVERLAY_PROPERTY(qreal, topMargin, 0) + +public: + TextOverlayElement(QQuickItem* parent = nullptr) : QQuickItem(parent) { + } + +signals: + void textChanged(); + void fontFamilyChanged(); + void fontSizeChanged(); + void leftMarginChanged(); + void topMarginChanged(); + void textColorChanged(); + void backgroundColorChanged(); +}; + +HIFI_QML_DEF(TextOverlayElement) + +QString toQmlColor(const glm::vec4& v) { + QString templat("#%1%2%3%4"); + return templat. + arg((int)(v.a * 255), 2, 16, QChar('0')). + arg((int)(v.r * 255), 2, 16, QChar('0')). + arg((int)(v.g * 255), 2, 16, QChar('0')). + arg((int)(v.b * 255), 2, 16, QChar('0')); +} TextOverlay::TextOverlay() : _backgroundColor(DEFAULT_BACKGROUND_COLOR), @@ -27,7 +82,20 @@ TextOverlay::TextOverlay() : _topMargin(DEFAULT_MARGIN), _fontSize(DEFAULT_FONTSIZE) { - _textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT); + + qApp->postLambdaEvent([=] { + static std::once_flag once; + std::call_once(once, [] { + TextOverlayElement::registerType(); + }); + auto offscreenUi = DependencyManager::get(); + TextOverlayElement::show([=](QQmlContext* context, QObject* object) { + _qmlElement = static_cast(object); + }); + }); + while (!_qmlElement) { + QThread::msleep(1); + } } TextOverlay::TextOverlay(const TextOverlay* textOverlay) : @@ -39,11 +107,21 @@ TextOverlay::TextOverlay(const TextOverlay* textOverlay) : _topMargin(textOverlay->_topMargin), _fontSize(textOverlay->_fontSize) { - _textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT); + qApp->postLambdaEvent([=] { + auto offscreenUi = DependencyManager::get(); + TextOverlayElement::show([this](QQmlContext* context, QObject* object) { + _qmlElement = static_cast(object); + }); + }); + while (!_qmlElement) { + QThread::sleep(1); + } } TextOverlay::~TextOverlay() { - delete _textRenderer; + if (_qmlElement) { + _qmlElement->deleteLater(); + } } xColor TextOverlay::getBackgroundColor() { @@ -65,44 +143,29 @@ xColor TextOverlay::getBackgroundColor() { return result; } - void TextOverlay::render(RenderArgs* args) { - if (!_visible) { - return; // do nothing if we're not visible + if (_visible != _qmlElement->isVisible()) { + _qmlElement->setVisible(_visible); } + float pulseLevel = updatePulse(); + static float _oldPulseLevel = 0.0f; + if (pulseLevel != _oldPulseLevel) { - const float MAX_COLOR = 255.0f; - xColor backgroundColor = getBackgroundColor(); - glm::vec4 quadColor(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR, backgroundColor.blue / MAX_COLOR, - getBackgroundAlpha()); - - int left = _bounds.left(); - int right = _bounds.right() + 1; - int top = _bounds.top(); - int bottom = _bounds.bottom() + 1; - - glm::vec2 topLeft(left, top); - glm::vec2 bottomRight(right, bottom); - glBindTexture(GL_TEXTURE_2D, 0); - DependencyManager::get()->renderQuad(topLeft, bottomRight, quadColor); - - const int leftAdjust = -1; // required to make text render relative to left edge of bounds - const int topAdjust = -2; // required to make text render relative to top edge of bounds - int x = _bounds.left() + _leftMargin + leftAdjust; - int y = _bounds.top() + _topMargin + topAdjust; - - float alpha = getAlpha(); - glm::vec4 textColor = {_color.red / MAX_COLOR, _color.green / MAX_COLOR, _color.blue / MAX_COLOR, alpha }; - _textRenderer->draw(x, y, _text, textColor); + } } + void TextOverlay::setProperties(const QScriptValue& properties) { Overlay2D::setProperties(properties); - + _qmlElement->setX(_bounds.left()); + _qmlElement->setY(_bounds.top()); + _qmlElement->setWidth(_bounds.width()); + _qmlElement->setHeight(_bounds.height()); + _qmlElement->settextColor(toQmlColor(vec4(toGlm(_color), _alpha))); QScriptValue font = properties.property("font"); if (font.isObject()) { if (font.property("size").isValid()) { - setFontSize(font.property("size").toInt32()); + setFontSize(font.property("size").toInt32() / 1.2); } } @@ -126,6 +189,7 @@ void TextOverlay::setProperties(const QScriptValue& properties) { if (properties.property("backgroundAlpha").isValid()) { _backgroundAlpha = properties.property("backgroundAlpha").toVariant().toFloat(); } + _qmlElement->setbackgroundColor(toQmlColor(vec4(toGlm(_backgroundColor), _backgroundAlpha))); if (properties.property("leftMargin").isValid()) { setLeftMargin(properties.property("leftMargin").toVariant().toInt()); @@ -166,15 +230,35 @@ QScriptValue TextOverlay::getProperty(const QString& property) { } QSizeF TextOverlay::textSize(const QString& text) const { - auto extents = _textRenderer->computeExtent(text); - - return QSizeF(extents.x, extents.y); + int lines = 1; + foreach(QChar c, text) { + if (c == "\n") { + ++lines; + } + } + QFontMetrics fm(QFont(SANS_FONT_FAMILY, _fontSize)); + QSizeF result = QSizeF(fm.width(text), fm.lineSpacing() * lines); + return result; } void TextOverlay::setFontSize(int fontSize) { _fontSize = fontSize; - - auto oldTextRenderer = _textRenderer; - _textRenderer = TextRenderer::getInstance(SANS_FONT_FAMILY, _fontSize, DEFAULT_FONT_WEIGHT); - delete oldTextRenderer; + _qmlElement->setfontSize(fontSize); } + +void TextOverlay::setText(const QString& text) { + _text = text; + _qmlElement->settext(text); +} + +void TextOverlay::setLeftMargin(int margin) { + _leftMargin = margin; + _qmlElement->setleftMargin(margin); +} + +void TextOverlay::setTopMargin(int margin) { + _topMargin = margin; + _qmlElement->settopMargin(margin); +} + +#include "TextOverlay.moc" \ No newline at end of file diff --git a/interface/src/ui/overlays/TextOverlay.h b/interface/src/ui/overlays/TextOverlay.h index 32786c3220..7ada26f892 100644 --- a/interface/src/ui/overlays/TextOverlay.h +++ b/interface/src/ui/overlays/TextOverlay.h @@ -26,7 +26,7 @@ const int DEFAULT_MARGIN = 10; const int DEFAULT_FONTSIZE = 12; const int DEFAULT_FONT_WEIGHT = 50; -class TextRenderer; +class TextOverlayElement; class TextOverlay : public Overlay2D { Q_OBJECT @@ -45,9 +45,9 @@ public: float getBackgroundAlpha() const { return _backgroundAlpha; } // setters - void setText(const QString& text) { _text = text; } - void setLeftMargin(int margin) { _leftMargin = margin; } - void setTopMargin(int margin) { _topMargin = margin; } + void setText(const QString& text); + void setLeftMargin(int margin); + void setTopMargin(int margin); void setFontSize(int fontSize); virtual void setProperties(const QScriptValue& properties); @@ -57,9 +57,7 @@ public: QSizeF textSize(const QString& text) const; // Pixels private: - - TextRenderer* _textRenderer = nullptr; - + TextOverlayElement* _qmlElement{ nullptr }; QString _text; xColor _backgroundColor; float _backgroundAlpha; diff --git a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp index 95147ef2b1..219d066611 100644 --- a/libraries/entities-renderer/src/RenderableWebEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableWebEntityItem.cpp @@ -17,7 +17,6 @@ #include #include #include -#include #include #include #include diff --git a/libraries/render-utils/src/TextRenderer.cpp b/libraries/render-utils/src/TextRenderer.cpp deleted file mode 100644 index 61a7ce78cf..0000000000 --- a/libraries/render-utils/src/TextRenderer.cpp +++ /dev/null @@ -1,576 +0,0 @@ -// -// TextRenderer.cpp -// interface/src/ui -// -// Created by Andrzej Kapolka on 4/24/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - - -#include -#include -#include -#include -#include -#include -#include - -#ifdef __GNUC__ -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdouble-promotion" -#endif - -// FIXME, decouple from the GL headers -#include -#include -#include -#include - -#ifdef __GNUC__ -#pragma GCC diagnostic pop -#endif - -#include -#include - -#include "gpu/GLBackend.h" -#include "gpu/Stream.h" - -#include "GLMHelpers.h" -#include "MatrixStack.h" -#include "RenderUtilsLogging.h" -#include "TextRenderer.h" - -#include "sdf_text_vert.h" -#include "sdf_text_frag.h" - -// Helper functions for reading binary data from an IO device -template -void readStream(QIODevice & in, T & t) { - in.read((char*) &t, sizeof(t)); -} - -template -void readStream(QIODevice & in, T (&t)[N]) { - in.read((char*) t, N); -} - -template -void fillBuffer(QBuffer & buffer, T (&t)[N]) { - buffer.setData((const char*) t, N); -} - -// FIXME support the shadow effect, or remove it from the API -// FIXME figure out how to improve the anti-aliasing on the -// interior of the outline fonts - -// stores the font metrics for a single character -struct Glyph { - QChar c; - glm::vec2 texOffset; - glm::vec2 texSize; - glm::vec2 size; - glm::vec2 offset; - float d; // xadvance - adjusts character positioning - size_t indexOffset; - - QRectF bounds() const; - QRectF textureBounds(const glm::vec2 & textureSize) const; - - void read(QIODevice & in); -}; - -void Glyph::read(QIODevice & in) { - uint16_t charcode; - readStream(in, charcode); - c = charcode; - readStream(in, texOffset); - readStream(in, size); - readStream(in, offset); - readStream(in, d); - texSize = size; -} - -const float DEFAULT_POINT_SIZE = 12; - -class Font { -public: - - Font(); - - using TexturePtr = QSharedPointer < QOpenGLTexture >; - using VertexArrayPtr = QSharedPointer< QOpenGLVertexArrayObject >; - using ProgramPtr = QSharedPointer < QOpenGLShaderProgram >; - using BufferPtr = QSharedPointer < QOpenGLBuffer >; - - // maps characters to cached glyph info - // HACK... the operator[] const for QHash returns a - // copy of the value, not a const value reference, so - // we declare the hash as mutable in order to avoid such - // copies - mutable QHash _glyphs; - - // the id of the glyph texture to which we're currently writing - GLuint _currentTextureID; - - int _pointSize; - - // the height of the current row of characters - int _rowHeight; - - QString _family; - float _fontSize { 0 }; - float _leading { 0 }; - float _ascent { 0 }; - float _descent { 0 }; - float _spaceWidth { 0 }; - - BufferPtr _vertices; - BufferPtr _indices; - TexturePtr _texture; - VertexArrayPtr _vao; - QImage _image; - ProgramPtr _program; - - const Glyph & getGlyph(const QChar & c) const; - void read(QIODevice& path); - // Initialize the OpenGL structures - void setupGL(); - - glm::vec2 computeExtent(const QString & str) const; - - glm::vec2 computeTokenExtent(const QString & str) const; - - glm::vec2 drawString(float x, float y, const QString & str, - const glm::vec4& color, TextRenderer::EffectType effectType, - const glm::vec2& bound); - -private: - QStringList tokenizeForWrapping(const QString & str) const; - - bool _initialized; -}; - -static QHash LOADED_FONTS; - -Font* loadFont(QIODevice& fontFile) { - Font* result = new Font(); - result->read(fontFile); - return result; -} - -Font* loadFont(const QString& family) { - if (!LOADED_FONTS.contains(family)) { - - const QString SDFF_COURIER_PRIME_FILENAME = ":/CourierPrime.sdff"; - const QString SDFF_INCONSOLATA_MEDIUM_FILENAME = ":/InconsolataMedium.sdff"; - const QString SDFF_ROBOTO_FILENAME = ":/Roboto.sdff"; - const QString SDFF_TIMELESS_FILENAME = ":/Timeless.sdff"; - - QString loadFilename; - - if (family == MONO_FONT_FAMILY) { - loadFilename = SDFF_COURIER_PRIME_FILENAME; - } else if (family == INCONSOLATA_FONT_FAMILY) { - loadFilename = SDFF_INCONSOLATA_MEDIUM_FILENAME; - } else if (family == SANS_FONT_FAMILY) { - loadFilename = SDFF_ROBOTO_FILENAME; - } else { - if (!LOADED_FONTS.contains(SERIF_FONT_FAMILY)) { - loadFilename = SDFF_TIMELESS_FILENAME; - } else { - LOADED_FONTS[family] = LOADED_FONTS[SERIF_FONT_FAMILY]; - } - } - - if (!loadFilename.isEmpty()) { - QFile fontFile(loadFilename); - fontFile.open(QIODevice::ReadOnly); - - qCDebug(renderutils) << "Loaded font" << loadFilename << "from Qt Resource System."; - - LOADED_FONTS[family] = loadFont(fontFile); - } - } - return LOADED_FONTS[family]; -} - -Font::Font() : _initialized(false) { - static bool fontResourceInitComplete = false; - if (!fontResourceInitComplete) { - Q_INIT_RESOURCE(fonts); - fontResourceInitComplete = true; - } -} - -// NERD RAGE: why doesn't QHash have a 'const T & operator[] const' member -const Glyph & Font::getGlyph(const QChar & c) const { - if (!_glyphs.contains(c)) { - return _glyphs[QChar('?')]; - } - return _glyphs[c]; -} - -void Font::read(QIODevice& in) { - uint8_t header[4]; - readStream(in, header); - if (memcmp(header, "SDFF", 4)) { - qFatal("Bad SDFF file"); - } - - uint16_t version; - readStream(in, version); - - // read font name - _family = ""; - if (version > 0x0001) { - char c; - readStream(in, c); - while (c) { - _family += c; - readStream(in, c); - } - } - - // read font data - readStream(in, _leading); - readStream(in, _ascent); - readStream(in, _descent); - readStream(in, _spaceWidth); - _fontSize = _ascent + _descent; - _rowHeight = _fontSize + _descent; - - // Read character count - uint16_t count; - readStream(in, count); - // read metrics data for each character - QVector glyphs(count); - // std::for_each instead of Qt foreach because we need non-const references - std::for_each(glyphs.begin(), glyphs.end(), [&](Glyph & g) { - g.read(in); - }); - - // read image data - if (!_image.loadFromData(in.readAll(), "PNG")) { - qFatal("Failed to read SDFF image"); - } - - _glyphs.clear(); - foreach(Glyph g, glyphs) { - // Adjust the pixel texture coordinates into UV coordinates, - glm::vec2 imageSize = toGlm(_image.size()); - g.texSize /= imageSize; - g.texOffset /= imageSize; - // store in the character to glyph hash - _glyphs[g.c] = g; - }; -} - -struct TextureVertex { - glm::vec2 pos; - glm::vec2 tex; - TextureVertex() { - } - TextureVertex(const glm::vec2 & pos, const glm::vec2 & tex) : - pos(pos), tex(tex) { - } - TextureVertex(const QPointF & pos, const QPointF & tex) : - pos(pos.x(), pos.y()), tex(tex.x(), tex.y()) { - } -}; - -struct QuadBuilder { - TextureVertex vertices[4]; - QuadBuilder(const QRectF & r, const QRectF & tr) { - vertices[0] = TextureVertex(r.bottomLeft(), tr.topLeft()); - vertices[1] = TextureVertex(r.bottomRight(), tr.topRight()); - vertices[2] = TextureVertex(r.topRight(), tr.bottomRight()); - vertices[3] = TextureVertex(r.topLeft(), tr.bottomLeft()); - } -}; - -QRectF Glyph::bounds() const { - return glmToRect(offset, size); -} - -QRectF Glyph::textureBounds(const glm::vec2 & textureSize) const { - return glmToRect(texOffset, texSize); -} - -void Font::setupGL() { - if (_initialized) { - return; - } - _initialized = true; - - _texture = TexturePtr( - new QOpenGLTexture(_image, QOpenGLTexture::GenerateMipMaps)); - _program = ProgramPtr(new QOpenGLShaderProgram()); - if (!_program->create()) { - qFatal("Could not create text shader"); - } - if (!_program->addShaderFromSourceCode(QOpenGLShader::Vertex, sdf_text_vert) || // - !_program->addShaderFromSourceCode(QOpenGLShader::Fragment, sdf_text_frag) || // - !_program->link()) { - qFatal("%s", _program->log().toLocal8Bit().constData()); - } - - std::vector vertexData; - std::vector indexData; - vertexData.reserve(_glyphs.size() * 4); - std::for_each(_glyphs.begin(), _glyphs.end(), [&](Glyph & m) { - GLuint index = (GLuint)vertexData.size(); - - QRectF bounds = m.bounds(); - QRectF texBounds = m.textureBounds(toGlm(_image.size())); - QuadBuilder qb(bounds, texBounds); - for (int i = 0; i < 4; ++i) { - vertexData.push_back(qb.vertices[i]); - } - - m.indexOffset = indexData.size() * sizeof(GLuint); - // FIXME use triangle strips + primitive restart index - indexData.push_back(index + 0); - indexData.push_back(index + 1); - indexData.push_back(index + 2); - indexData.push_back(index + 0); - indexData.push_back(index + 2); - indexData.push_back(index + 3); - }); - - _vao = VertexArrayPtr(new QOpenGLVertexArrayObject()); - _vao->create(); - _vao->bind(); - - _vertices = BufferPtr(new QOpenGLBuffer(QOpenGLBuffer::VertexBuffer)); - _vertices->create(); - _vertices->bind(); - _vertices->allocate(&vertexData[0], - sizeof(TextureVertex) * vertexData.size()); - _indices = BufferPtr(new QOpenGLBuffer(QOpenGLBuffer::IndexBuffer)); - _indices->create(); - _indices->bind(); - _indices->allocate(&indexData[0], sizeof(GLuint) * indexData.size()); - - GLsizei stride = (GLsizei) sizeof(TextureVertex); - void* offset = (void*) offsetof(TextureVertex, tex); - int posLoc = _program->attributeLocation("Position"); - int texLoc = _program->attributeLocation("TexCoord"); - glEnableVertexAttribArray(posLoc); - glVertexAttribPointer(posLoc, 2, GL_FLOAT, false, stride, nullptr); - glEnableVertexAttribArray(texLoc); - glVertexAttribPointer(texLoc, 2, GL_FLOAT, false, stride, offset); - _vao->release(); -} - -// FIXME there has to be a cleaner way of doing this -QStringList Font::tokenizeForWrapping(const QString & str) const { - QStringList result; - foreach(const QString & token1, str.split(" ")) { - bool lineFeed = false; - if (token1.isEmpty()) { - result << token1; - continue; - } - foreach(const QString & token2, token1.split("\n")) { - if (lineFeed) { - result << "\n"; - } - if (token2.size()) { - result << token2; - } - lineFeed = true; - } - } - return result; -} - - -glm::vec2 Font::computeTokenExtent(const QString & token) const { - glm::vec2 advance(0, _rowHeight - _descent); - foreach(QChar c, token) { - assert(c != ' ' && c != '\n'); - const Glyph & m = getGlyph(c); - advance.x += m.d; - } - return advance; -} - - -glm::vec2 Font::computeExtent(const QString & str) const { - glm::vec2 extent(0, _rowHeight - _descent); - // FIXME, come up with a better method of splitting text - // that will allow wrapping but will preserve things like - // tabs or consecutive spaces - bool firstTokenOnLine = true; - float lineWidth = 0.0f; - QStringList tokens = tokenizeForWrapping(str); - foreach(const QString & token, tokens) { - if (token == "\n") { - extent.x = std::max(lineWidth, extent.x); - lineWidth = 0.0f; - extent.y += _rowHeight; - firstTokenOnLine = true; - continue; - } - if (!firstTokenOnLine) { - lineWidth += _spaceWidth; - } - lineWidth += computeTokenExtent(token).x; - firstTokenOnLine = false; - } - extent.x = std::max(lineWidth, extent.x); - return extent; -} - -// FIXME support the maxWidth parameter and allow the text to automatically wrap -// even without explicit line feeds. -glm::vec2 Font::drawString(float x, float y, const QString & str, - const glm::vec4& color, TextRenderer::EffectType effectType, - const glm::vec2& bounds) { - - setupGL(); - - // Stores how far we've moved from the start of the string, in DTP units - glm::vec2 advance(0, -_rowHeight - _descent); - - _program->bind(); - _program->setUniformValue("Color", color.r, color.g, color.b, color.a); - _program->setUniformValue("Projection", - fromGlm(MatrixStack::projection().top())); - if (effectType == TextRenderer::OUTLINE_EFFECT) { - _program->setUniformValue("Outline", true); - } - // Needed? - glEnable(GL_TEXTURE_2D); - _texture->bind(); - _vao->bind(); - - MatrixStack & mv = MatrixStack::modelview(); - // scale the modelview into font units - mv.translate(glm::vec3(0, _ascent, 0)); - foreach(const QString & token, tokenizeForWrapping(str)) { - if (token == "\n") { - advance.x = 0.0f; - advance.y -= _rowHeight; - // If we've wrapped right out of the bounds, then we're - // done with rendering the tokens - if (bounds.y > 0 && std::abs(advance.y) > bounds.y) { - break; - } - continue; - } - - glm::vec2 tokenExtent = computeTokenExtent(token); - if (bounds.x > 0 && advance.x > 0) { - // We check if we'll be out of bounds - if (advance.x + tokenExtent.x >= bounds.x) { - // We're out of bounds, so wrap to the next line - advance.x = 0.0f; - advance.y -= _rowHeight; - // If we've wrapped right out of the bounds, then we're - // done with rendering the tokens - if (bounds.y > 0 && std::abs(advance.y) > bounds.y) { - break; - } - } - } - - foreach(const QChar & c, token) { - // get metrics for this character to speed up measurements - const Glyph & m = getGlyph(c); - // We create an offset vec2 to hold the local offset of this character - // This includes compensating for the inverted Y axis of the font - // coordinates - glm::vec2 offset(advance); - offset.y -= m.size.y; - // Bind the new position - mv.withPush([&] { - mv.translate(offset); - // FIXME find a better (and GL ES 3.1 compatible) way of rendering the text - // that doesn't involve a single GL call per character. - // Most likely an 'indirect' call or an 'instanced' call. - _program->setUniformValue("ModelView", fromGlm(mv.top())); - glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, (void*)(m.indexOffset)); - }); - advance.x += m.d; - } - advance.x += _spaceWidth; - } - - _vao->release(); - _texture->release(); // TODO: Brad & Sam, let's discuss this. Without this non-textured quads get their colors borked. - _program->release(); - - return advance; -} - -TextRenderer* TextRenderer::getInstance(const char* family, float pointSize, - int weight, bool italic, EffectType effect, int effectThickness, - const QColor& color) { - if (pointSize < 0) { - pointSize = DEFAULT_POINT_SIZE; - } - return new TextRenderer(family, pointSize, weight, italic, effect, - effectThickness, color); -} - -TextRenderer::TextRenderer(const char* family, float pointSize, int weight, - bool italic, EffectType effect, int effectThickness, - const QColor& color) : - _effectType(effect), _effectThickness(effectThickness), _pointSize(pointSize), _color(color), _font(loadFont(family)) { - if (!_font) { - qWarning() << "Unable to load font with family " << family; - _font = loadFont("Courier"); - } - if (1 != _effectThickness) { - qWarning() << "Effect thickness not current supported"; - } - if (NO_EFFECT != _effectType && OUTLINE_EFFECT != _effectType) { - qWarning() << "Effect thickness not current supported"; - } -} - -TextRenderer::~TextRenderer() { -} - -glm::vec2 TextRenderer::computeExtent(const QString & str) const { - float scale = (_pointSize / DEFAULT_POINT_SIZE) * 0.25f; - if (_font) { - return _font->computeExtent(str) * scale; - } - return glm::vec2(0.1f,0.1f); -} - -float TextRenderer::draw(float x, float y, const QString & str, - const glm::vec4& color, const glm::vec2 & bounds) { - glm::vec4 actualColor(color); - if (actualColor.r < 0) { - actualColor = toGlm(_color); - } - - float scale = (_pointSize / DEFAULT_POINT_SIZE) * 0.25f; - glm::vec2 result; - - MatrixStack::withPushAll([&] { - MatrixStack & mv = MatrixStack::modelview(); - MatrixStack & pr = MatrixStack::projection(); - gpu::GLBackend::fetchMatrix(GL_MODELVIEW_MATRIX, mv.top()); - gpu::GLBackend::fetchMatrix(GL_PROJECTION_MATRIX, pr.top()); - - // scale the modelview into font units - // FIXME migrate the constant scale factor into the geometry of the - // fonts so we don't have to flip the Y axis here and don't have to - // scale at all. - mv.translate(glm::vec2(x, y)).scale(glm::vec3(scale, -scale, scale)); - // The font does all the OpenGL work - if (_font) { - result = _font->drawString(x, y, str, actualColor, _effectType, bounds / scale); - } - }); - return result.x; -} - diff --git a/libraries/render-utils/src/TextRenderer.h b/libraries/render-utils/src/TextRenderer.h deleted file mode 100644 index 85bb18cec9..0000000000 --- a/libraries/render-utils/src/TextRenderer.h +++ /dev/null @@ -1,89 +0,0 @@ -// -// TextRenderer.h -// interface/src/ui -// -// Created by Andrzej Kapolka on 4/26/13. -// Copyright 2013 High Fidelity, Inc. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -#ifndef hifi_TextRenderer_h -#define hifi_TextRenderer_h - -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include - -// a special "character" that renders as a solid block -const char SOLID_BLOCK_CHAR = 127; - -// the standard sans serif font family -#define SANS_FONT_FAMILY "Helvetica" - -// the standard sans serif font family -#define SERIF_FONT_FAMILY "Timeless" - -// the standard mono font family -#define MONO_FONT_FAMILY "Courier" - -// the Inconsolata font family -#ifdef Q_OS_WIN -#define INCONSOLATA_FONT_FAMILY "Fixedsys" -#define INCONSOLATA_FONT_WEIGHT QFont::Normal -#else -#define INCONSOLATA_FONT_FAMILY "Inconsolata" -#define INCONSOLATA_FONT_WEIGHT QFont::Bold -#endif - -class Font; - -// TextRenderer is actually a fairly thin wrapper around a Font class -// defined in the cpp file. -class TextRenderer { -public: - enum EffectType { NO_EFFECT, SHADOW_EFFECT, OUTLINE_EFFECT }; - - static TextRenderer* getInstance(const char* family, float pointSize = -1, int weight = -1, bool italic = false, - EffectType effect = NO_EFFECT, int effectThickness = 1, const QColor& color = QColor(255, 255, 255)); - - ~TextRenderer(); - - glm::vec2 computeExtent(const QString & str) const; - - float draw( - float x, float y, - const QString & str, - const glm::vec4& color = glm::vec4(-1.0f), - const glm::vec2& bounds = glm::vec2(-1.0f)); - -private: - TextRenderer(const char* family, float pointSize = -1, int weight = -1, bool italic = false, - EffectType effect = NO_EFFECT, int effectThickness = 1, const QColor& color = QColor(255, 255, 255)); - - // the type of effect to apply - const EffectType _effectType; - - // the thickness of the effect - const int _effectThickness; - - const float _pointSize; - - // text color - const QColor _color; - - Font * _font; -}; - - -#endif // hifi_TextRenderer_h diff --git a/libraries/render-utils/src/TextRenderer3D.cpp b/libraries/render-utils/src/TextRenderer3D.cpp index 973cddc4d7..a93ba1daec 100644 --- a/libraries/render-utils/src/TextRenderer3D.cpp +++ b/libraries/render-utils/src/TextRenderer3D.cpp @@ -10,6 +10,7 @@ // #include "TextRenderer3D.h" +#include #include #include @@ -20,6 +21,8 @@ #include #include +#include "text/Font.h" + #include "GLMHelpers.h" #include "MatrixStack.h" #include "RenderUtilsLogging.h" @@ -30,421 +33,22 @@ #include "GeometryCache.h" #include "DeferredLightingEffect.h" -// Helper functions for reading binary data from an IO device -template -void readStream(QIODevice& in, T& t) { - in.read((char*) &t, sizeof(t)); +const float TextRenderer3D::DEFAULT_POINT_SIZE = 12; + +TextRenderer3D* TextRenderer3D::getInstance(const char* family, float pointSize, + bool bold, bool italic, EffectType effect, int effectThickness) { + return new TextRenderer3D(family, pointSize, false, italic, effect, effectThickness); } -template -void readStream(QIODevice& in, T (&t)[N]) { - in.read((char*) t, N); -} - -template -void fillBuffer(QBuffer& buffer, T (&t)[N]) { - buffer.setData((const char*) t, N); -} - -// stores the font metrics for a single character -struct Glyph3D { - QChar c; - glm::vec2 texOffset; - glm::vec2 texSize; - glm::vec2 size; - glm::vec2 offset; - float d; // xadvance - adjusts character positioning - size_t indexOffset; - - // We adjust bounds because offset is the bottom left corner of the font but the top left corner of a QRect - QRectF bounds() const { return glmToRect(offset, size).translated(0.0f, -size.y); } - QRectF textureBounds() const { return glmToRect(texOffset, texSize); } - - void read(QIODevice& in); -}; - -void Glyph3D::read(QIODevice& in) { - uint16_t charcode; - readStream(in, charcode); - c = charcode; - readStream(in, texOffset); - readStream(in, size); - readStream(in, offset); - readStream(in, d); - texSize = size; -} - -struct TextureVertex { - glm::vec2 pos; - glm::vec2 tex; - TextureVertex() {} - TextureVertex(const glm::vec2& pos, const glm::vec2& tex) : pos(pos), tex(tex) {} -}; - -struct QuadBuilder { - TextureVertex vertices[4]; - QuadBuilder(const glm::vec2& min, const glm::vec2& size, - const glm::vec2& texMin, const glm::vec2& texSize) { - // min = bottomLeft - vertices[0] = TextureVertex(min, - texMin + glm::vec2(0.0f, texSize.y)); - vertices[1] = TextureVertex(min + glm::vec2(size.x, 0.0f), - texMin + texSize); - vertices[2] = TextureVertex(min + size, - texMin + glm::vec2(texSize.x, 0.0f)); - vertices[3] = TextureVertex(min + glm::vec2(0.0f, size.y), - texMin); - } - QuadBuilder(const Glyph3D& glyph, const glm::vec2& offset) : - QuadBuilder(offset + glm::vec2(glyph.offset.x, glyph.offset.y - glyph.size.y), glyph.size, - glyph.texOffset, glyph.texSize) {} - -}; - -class Font3D { -public: - Font3D(); - - void read(QIODevice& path); - - glm::vec2 computeExtent(const QString& str) const; - float getFontSize() const { return _fontSize; } - - // Render string to batch - void drawString(gpu::Batch& batch, float x, float y, const QString& str, - const glm::vec4* color, TextRenderer3D::EffectType effectType, - const glm::vec2& bound); - -private: - QStringList tokenizeForWrapping(const QString& str) const; - QStringList splitLines(const QString& str) const; - glm::vec2 computeTokenExtent(const QString& str) const; - - const Glyph3D& getGlyph(const QChar& c) const; - - void setupGPU(); - - // maps characters to cached glyph info - // HACK... the operator[] const for QHash returns a - // copy of the value, not a const value reference, so - // we declare the hash as mutable in order to avoid such - // copies - mutable QHash _glyphs; - - // Font characteristics - QString _family; - float _fontSize = 0.0f; - float _leading = 0.0f; - float _ascent = 0.0f; - float _descent = 0.0f; - float _spaceWidth = 0.0f; - - bool _initialized = false; - - // gpu structures - gpu::PipelinePointer _pipeline; - gpu::TexturePointer _texture; - gpu::Stream::FormatPointer _format; - gpu::BufferPointer _verticesBuffer; - gpu::BufferStreamPointer _stream; - unsigned int _numVertices = 0; - - int _fontLoc = -1; - int _outlineLoc = -1; - int _colorLoc = -1; - - // last string render characteristics - QString _lastStringRendered; - glm::vec2 _lastBounds; -}; - -static QHash LOADED_FONTS; - -Font3D* loadFont3D(QIODevice& fontFile) { - Font3D* result = new Font3D(); - result->read(fontFile); - return result; -} - -Font3D* loadFont3D(const QString& family) { - if (!LOADED_FONTS.contains(family)) { - - const QString SDFF_COURIER_PRIME_FILENAME = ":/CourierPrime.sdff"; - const QString SDFF_INCONSOLATA_MEDIUM_FILENAME = ":/InconsolataMedium.sdff"; - const QString SDFF_ROBOTO_FILENAME = ":/Roboto.sdff"; - const QString SDFF_TIMELESS_FILENAME = ":/Timeless.sdff"; - - QString loadFilename; - - if (family == MONO_FONT_FAMILY) { - loadFilename = SDFF_COURIER_PRIME_FILENAME; - } else if (family == INCONSOLATA_FONT_FAMILY) { - loadFilename = SDFF_INCONSOLATA_MEDIUM_FILENAME; - } else if (family == SANS_FONT_FAMILY) { - loadFilename = SDFF_ROBOTO_FILENAME; - } else { - if (!LOADED_FONTS.contains(SERIF_FONT_FAMILY)) { - loadFilename = SDFF_TIMELESS_FILENAME; - } else { - LOADED_FONTS[family] = LOADED_FONTS[SERIF_FONT_FAMILY]; - } - } - - if (!loadFilename.isEmpty()) { - QFile fontFile(loadFilename); - fontFile.open(QIODevice::ReadOnly); - - qCDebug(renderutils) << "Loaded font" << loadFilename << "from Qt Resource System."; - - LOADED_FONTS[family] = loadFont3D(fontFile); - } - } - return LOADED_FONTS[family]; -} - -Font3D::Font3D() { - static bool fontResourceInitComplete = false; - if (!fontResourceInitComplete) { - Q_INIT_RESOURCE(fonts); - fontResourceInitComplete = true; - } -} - -// NERD RAGE: why doesn't QHash have a 'const T & operator[] const' member -const Glyph3D& Font3D::getGlyph(const QChar& c) const { - if (!_glyphs.contains(c)) { - return _glyphs[QChar('?')]; - } - return _glyphs[c]; -} - -QStringList Font3D::splitLines(const QString& str) const { - return str.split('\n'); -} - -QStringList Font3D::tokenizeForWrapping(const QString& str) const { - QStringList tokens; - for(auto line : splitLines(str)) { - if (!tokens.empty()) { - tokens << QString('\n'); - } - tokens << line.split(' '); - } - return tokens; -} - -glm::vec2 Font3D::computeTokenExtent(const QString& token) const { - glm::vec2 advance(0, _fontSize); - foreach(QChar c, token) { - Q_ASSERT(c != '\n'); - advance.x += (c == ' ') ? _spaceWidth : getGlyph(c).d; - } - return advance; -} - -glm::vec2 Font3D::computeExtent(const QString& str) const { - glm::vec2 extent = glm::vec2(0.0f, 0.0f); - - QStringList lines{ splitLines(str) }; - if (!lines.empty()) { - for(const auto& line : lines) { - glm::vec2 tokenExtent = computeTokenExtent(line); - extent.x = std::max(tokenExtent.x, extent.x); - } - extent.y = lines.count() * _fontSize; - } - return extent; -} - -void Font3D::read(QIODevice& in) { - uint8_t header[4]; - readStream(in, header); - if (memcmp(header, "SDFF", 4)) { - qFatal("Bad SDFF file"); - } - - uint16_t version; - readStream(in, version); - - // read font name - _family = ""; - if (version > 0x0001) { - char c; - readStream(in, c); - while (c) { - _family += c; - readStream(in, c); - } - } - - // read font data - readStream(in, _leading); - readStream(in, _ascent); - readStream(in, _descent); - readStream(in, _spaceWidth); - _fontSize = _ascent + _descent; - - // Read character count - uint16_t count; - readStream(in, count); - // read metrics data for each character - QVector glyphs(count); - // std::for_each instead of Qt foreach because we need non-const references - std::for_each(glyphs.begin(), glyphs.end(), [&](Glyph3D& g) { - g.read(in); - }); - - // read image data - QImage image; - if (!image.loadFromData(in.readAll(), "PNG")) { - qFatal("Failed to read SDFF image"); - } - - _glyphs.clear(); - glm::vec2 imageSize = toGlm(image.size()); - foreach(Glyph3D g, glyphs) { - // Adjust the pixel texture coordinates into UV coordinates, - g.texSize /= imageSize; - g.texOffset /= imageSize; - // store in the character to glyph hash - _glyphs[g.c] = g; - }; - - image = image.convertToFormat(QImage::Format_RGBA8888); - - gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB); - gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB); - if (image.hasAlphaChannel()) { - formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA); - formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA); - } - _texture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(), - gpu::Sampler(gpu::Sampler::FILTER_MIN_POINT_MAG_LINEAR))); - _texture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); - _texture->autoGenerateMips(-1); -} - -void Font3D::setupGPU() { - if (!_initialized) { - _initialized = true; - - // Setup render pipeline - auto vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(sdf_text3D_vert))); - auto pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(sdf_text3D_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); - - gpu::Shader::BindingSet slotBindings; - gpu::Shader::makeProgram(*program, slotBindings); - - _fontLoc = program->getTextures().findLocation("Font"); - _outlineLoc = program->getUniforms().findLocation("Outline"); - _colorLoc = program->getUniforms().findLocation("Color"); - - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(true, true, gpu::LESS_EQUAL); - state->setBlendFunction(true, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); - - // Sanity checks - static const int OFFSET = offsetof(TextureVertex, tex); - assert(OFFSET == sizeof(glm::vec2)); - assert(sizeof(glm::vec2) == 2 * sizeof(float)); - assert(sizeof(TextureVertex) == 2 * sizeof(glm::vec2)); - assert(sizeof(QuadBuilder) == 4 * sizeof(TextureVertex)); - - // Setup rendering structures - _format.reset(new gpu::Stream::Format()); - _format->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0); - _format->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), OFFSET); - } -} - -void Font3D::drawString(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4* color, - TextRenderer3D::EffectType effectType, const glm::vec2& bounds) { - if (str == "") { - return; - } - - if (str != _lastStringRendered || bounds != _lastBounds) { - _verticesBuffer.reset(new gpu::Buffer()); - _numVertices = 0; - _lastStringRendered = str; - _lastBounds = bounds; - - // Top left of text - glm::vec2 advance = glm::vec2(x, y); - foreach(const QString& token, tokenizeForWrapping(str)) { - bool isNewLine = (token == QString('\n')); - bool forceNewLine = false; - - // Handle wrapping - if (!isNewLine && (bounds.x != -1) && (advance.x + computeExtent(token).x > x + bounds.x)) { - // We are out of the x bound, force new line - forceNewLine = true; - } - if (isNewLine || forceNewLine) { - // Character return, move the advance to a new line - advance = glm::vec2(x, advance.y - _leading); - - if (isNewLine) { - // No need to draw anything, go directly to next token - continue; - } else if (computeExtent(token).x > bounds.x) { - // token will never fit, stop drawing - break; - } - } - if ((bounds.y != -1) && (advance.y - _fontSize < -y - bounds.y)) { - // We are out of the y bound, stop drawing - break; - } - - // Draw the token - if (!isNewLine) { - for (auto c : token) { - auto glyph = _glyphs[c]; - - QuadBuilder qd(glyph, advance - glm::vec2(0.0f, _ascent)); - _verticesBuffer->append(sizeof(QuadBuilder), (const gpu::Byte*)&qd); - _numVertices += 4; - - // Advance by glyph size - advance.x += glyph.d; - } - - // Add space after all non return tokens - advance.x += _spaceWidth; - } - } - } - - setupGPU(); - batch.setPipeline(_pipeline); - batch.setResourceTexture(_fontLoc, _texture); - batch._glUniform1i(_outlineLoc, (effectType == TextRenderer3D::OUTLINE_EFFECT)); - batch._glUniform4fv(_colorLoc, 1, (const GLfloat*)color); - - batch.setInputFormat(_format); - batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); - batch.draw(gpu::QUADS, _numVertices, 0); -} - -TextRenderer3D* TextRenderer3D::getInstance(const char* family, - int weight, bool italic, EffectType effect, int effectThickness) { - return new TextRenderer3D(family, weight, italic, effect, effectThickness); -} - -TextRenderer3D::TextRenderer3D(const char* family, int weight, bool italic, - EffectType effect, int effectThickness) : +TextRenderer3D::TextRenderer3D(const char* family, float pointSize, int weight, bool italic, + EffectType effect, int effectThickness) : + _pointSize(pointSize), _effectType(effect), _effectThickness(effectThickness), - _font(loadFont3D(family)) { + _font(Font::load(family)) { if (!_font) { qWarning() << "Unable to load font with family " << family; - _font = loadFont3D("Courier"); + _font = Font::load("Courier"); } if (1 != _effectThickness) { qWarning() << "Effect thickness not currently supported"; diff --git a/libraries/render-utils/src/TextRenderer3D.h b/libraries/render-utils/src/TextRenderer3D.h index c4200a8d23..c5af61a252 100644 --- a/libraries/render-utils/src/TextRenderer3D.h +++ b/libraries/render-utils/src/TextRenderer3D.h @@ -15,37 +15,25 @@ #include #include -// the standard sans serif font family -#define SANS_FONT_FAMILY "Helvetica" -// the standard sans serif font family -#define SERIF_FONT_FAMILY "Timeless" - -// the standard mono font family -#define MONO_FONT_FAMILY "Courier" - -// the Inconsolata font family -#ifdef Q_OS_WIN -#define INCONSOLATA_FONT_FAMILY "Fixedsys" -#define INCONSOLATA_FONT_WEIGHT QFont::Normal -#else -#define INCONSOLATA_FONT_FAMILY "Inconsolata" -#define INCONSOLATA_FONT_WEIGHT QFont::Bold -#endif namespace gpu { class Batch; } -class Font3D; +class Font; + +#include "text/EffectType.h" +#include "text/FontFamilies.h" // TextRenderer3D is actually a fairly thin wrapper around a Font class // defined in the cpp file. class TextRenderer3D { public: - enum EffectType { NO_EFFECT, SHADOW_EFFECT, OUTLINE_EFFECT }; + static const float DEFAULT_POINT_SIZE; + + static TextRenderer3D* getInstance(const char* family, float pointSize = DEFAULT_POINT_SIZE, + bool bold = false, bool italic = false, EffectType effect = NO_EFFECT, int effectThickness = 1); - static TextRenderer3D* getInstance(const char* family, int weight = -1, bool italic = false, - EffectType effect = NO_EFFECT, int effectThickness = 1); ~TextRenderer3D(); glm::vec2 computeExtent(const QString& str) const; @@ -55,7 +43,7 @@ public: const glm::vec2& bounds = glm::vec2(-1.0f)); private: - TextRenderer3D(const char* family, int weight = -1, bool italic = false, + TextRenderer3D(const char* family, float pointSize, int weight = -1, bool italic = false, EffectType effect = NO_EFFECT, int effectThickness = 1); // the type of effect to apply @@ -66,8 +54,9 @@ private: // text color glm::vec4 _color; + float _pointSize{ DEFAULT_POINT_SIZE }; - Font3D* _font; + Font* _font; }; diff --git a/libraries/render-utils/src/sdf_text.slf b/libraries/render-utils/src/sdf_text.slf deleted file mode 100644 index 1affbe4c57..0000000000 --- a/libraries/render-utils/src/sdf_text.slf +++ /dev/null @@ -1,49 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// sdf_text.frag -// fragment shader -// -// Created by Bradley Austin Davis on 2015-02-04 -// Based on fragment shader code from -// https://github.com/paulhoux/Cinder-Samples/blob/master/TextRendering/include/text/Text.cpp -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html - -uniform sampler2D Font; -uniform vec4 Color; -uniform bool Outline; - -varying vec2 vTexCoord; - -const float gamma = 2.6; -const float smoothing = 100.0; -const float interiorCutoff = 0.8; -const float outlineExpansion = 0.2; - -void main() { - // retrieve signed distance - float sdf = texture2D(Font, vTexCoord).r; - if (Outline) { - if (sdf > interiorCutoff) { - sdf = 1.0 - sdf; - } else { - sdf += outlineExpansion; - } - } - // perform adaptive anti-aliasing of the edges - // The larger we're rendering, the less anti-aliasing we need - float s = smoothing * length(fwidth(vTexCoord)); - float w = clamp( s, 0.0, 0.5); - float a = smoothstep(0.5 - w, 0.5 + w, sdf); - - // gamma correction for linear attenuation - a = pow(a, 1.0 / gamma); - - if (a < 0.01) { - discard; - } - - // final color - gl_FragColor = vec4(Color.rgb, a); -} \ No newline at end of file diff --git a/libraries/render-utils/src/sdf_text.slv b/libraries/render-utils/src/sdf_text.slv deleted file mode 100644 index 27db1c4985..0000000000 --- a/libraries/render-utils/src/sdf_text.slv +++ /dev/null @@ -1,24 +0,0 @@ -<@include gpu/Config.slh@> -<$VERSION_HEADER$> -// Generated on <$_SCRIBE_DATE$> -// sdf_text.vert -// vertex shader -// -// Created by Brad Davis on 10/14/13. -// -// Distributed under the Apache License, Version 2.0. -// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html -// - -uniform mat4 Projection; -uniform mat4 ModelView; - -attribute vec2 Position; -attribute vec2 TexCoord; - -varying vec2 vTexCoord; - -void main() { - vTexCoord = TexCoord; - gl_Position = Projection * ModelView * vec4(Position, 0.0, 1.0); -} \ No newline at end of file diff --git a/libraries/render-utils/src/text/EffectType.h b/libraries/render-utils/src/text/EffectType.h new file mode 100644 index 0000000000..63ec820036 --- /dev/null +++ b/libraries/render-utils/src/text/EffectType.h @@ -0,0 +1,15 @@ +// +// Created by Bradley Austin Davis on 2015/07/16 +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_EffectType_h +#define hifi_EffectType_h + +enum EffectType { NO_EFFECT, SHADOW_EFFECT, OUTLINE_EFFECT }; + +#endif diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp new file mode 100644 index 0000000000..8e83c55fec --- /dev/null +++ b/libraries/render-utils/src/text/Font.cpp @@ -0,0 +1,366 @@ +#include "Font.h" + +#include +#include + +#include + +#include "sdf_text3D_vert.h" +#include "sdf_text3D_frag.h" +#include "sdf_text_vert.h" +#include "sdf_text_frag.h" + +#include "../RenderUtilsLogging.h" +#include "FontFamilies.h" + +struct TextureVertex { + glm::vec2 pos; + glm::vec2 tex; + TextureVertex() {} + TextureVertex(const glm::vec2& pos, const glm::vec2& tex) : pos(pos), tex(tex) {} +}; + +struct QuadBuilder { + TextureVertex vertices[4]; + QuadBuilder(const glm::vec2& min, const glm::vec2& size, + const glm::vec2& texMin, const glm::vec2& texSize) { + // min = bottomLeft + vertices[0] = TextureVertex(min, + texMin + glm::vec2(0.0f, texSize.y)); + vertices[1] = TextureVertex(min + glm::vec2(size.x, 0.0f), + texMin + texSize); + vertices[2] = TextureVertex(min + size, + texMin + glm::vec2(texSize.x, 0.0f)); + vertices[3] = TextureVertex(min + glm::vec2(0.0f, size.y), + texMin); + } + QuadBuilder(const Glyph& glyph, const glm::vec2& offset) : + QuadBuilder(offset + glm::vec2(glyph.offset.x, glyph.offset.y - glyph.size.y), glyph.size, + glyph.texOffset, glyph.texSize) {} + +}; + + + +static QHash LOADED_FONTS; + +Font* Font::load(QIODevice& fontFile) { + Font* result = new Font(); + result->read(fontFile); + return result; +} + +Font* Font::load(const QString& family) { + if (!LOADED_FONTS.contains(family)) { + + const QString SDFF_COURIER_PRIME_FILENAME = ":/CourierPrime.sdff"; + const QString SDFF_INCONSOLATA_MEDIUM_FILENAME = ":/InconsolataMedium.sdff"; + const QString SDFF_ROBOTO_FILENAME = ":/Roboto.sdff"; + const QString SDFF_TIMELESS_FILENAME = ":/Timeless.sdff"; + + QString loadFilename; + + if (family == MONO_FONT_FAMILY) { + loadFilename = SDFF_COURIER_PRIME_FILENAME; + } else if (family == INCONSOLATA_FONT_FAMILY) { + loadFilename = SDFF_INCONSOLATA_MEDIUM_FILENAME; + } else if (family == SANS_FONT_FAMILY) { + loadFilename = SDFF_ROBOTO_FILENAME; + } else { + if (!LOADED_FONTS.contains(SERIF_FONT_FAMILY)) { + loadFilename = SDFF_TIMELESS_FILENAME; + } else { + LOADED_FONTS[family] = LOADED_FONTS[SERIF_FONT_FAMILY]; + } + } + + if (!loadFilename.isEmpty()) { + QFile fontFile(loadFilename); + fontFile.open(QIODevice::ReadOnly); + + qCDebug(renderutils) << "Loaded font" << loadFilename << "from Qt Resource System."; + + LOADED_FONTS[family] = load(fontFile); + } + } + return LOADED_FONTS[family]; +} + +Font::Font() { + static bool fontResourceInitComplete = false; + if (!fontResourceInitComplete) { + Q_INIT_RESOURCE(fonts); + fontResourceInitComplete = true; + } +} + +// NERD RAGE: why doesn't QHash have a 'const T & operator[] const' member +const Glyph& Font::getGlyph(const QChar& c) const { + if (!_glyphs.contains(c)) { + return _glyphs[QChar('?')]; + } + return _glyphs[c]; +} + +QStringList Font::splitLines(const QString& str) const { + return str.split('\n'); +} + +QStringList Font::tokenizeForWrapping(const QString& str) const { + QStringList tokens; + for(auto line : splitLines(str)) { + if (!tokens.empty()) { + tokens << QString('\n'); + } + tokens << line.split(' '); + } + return tokens; +} + +glm::vec2 Font::computeTokenExtent(const QString& token) const { + glm::vec2 advance(0, _fontSize); + foreach(QChar c, token) { + Q_ASSERT(c != '\n'); + advance.x += (c == ' ') ? _spaceWidth : getGlyph(c).d; + } + return advance; +} + +glm::vec2 Font::computeExtent(const QString& str) const { + glm::vec2 extent = glm::vec2(0.0f, 0.0f); + + QStringList lines{ splitLines(str) }; + if (!lines.empty()) { + for(const auto& line : lines) { + glm::vec2 tokenExtent = computeTokenExtent(line); + extent.x = std::max(tokenExtent.x, extent.x); + } + extent.y = lines.count() * _fontSize; + } + return extent; +} + +void Font::read(QIODevice& in) { + uint8_t header[4]; + readStream(in, header); + if (memcmp(header, "SDFF", 4)) { + qFatal("Bad SDFF file"); + } + + uint16_t version; + readStream(in, version); + + // read font name + _family = ""; + if (version > 0x0001) { + char c; + readStream(in, c); + while (c) { + _family += c; + readStream(in, c); + } + } + + // read font data + readStream(in, _leading); + readStream(in, _ascent); + readStream(in, _descent); + readStream(in, _spaceWidth); + _fontSize = _ascent + _descent; + + // Read character count + uint16_t count; + readStream(in, count); + // read metrics data for each character + QVector glyphs(count); + // std::for_each instead of Qt foreach because we need non-const references + std::for_each(glyphs.begin(), glyphs.end(), [&](Glyph& g) { + g.read(in); + }); + + // read image data + QImage image; + if (!image.loadFromData(in.readAll(), "PNG")) { + qFatal("Failed to read SDFF image"); + } + + _glyphs.clear(); + glm::vec2 imageSize = toGlm(image.size()); + foreach(Glyph g, glyphs) { + // Adjust the pixel texture coordinates into UV coordinates, + g.texSize /= imageSize; + g.texOffset /= imageSize; + // store in the character to glyph hash + _glyphs[g.c] = g; + }; + + image = image.convertToFormat(QImage::Format_RGBA8888); + + gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB); + gpu::Element formatMip = gpu::Element(gpu::VEC3, gpu::UINT8, gpu::RGB); + if (image.hasAlphaChannel()) { + formatGPU = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::RGBA); + formatMip = gpu::Element(gpu::VEC4, gpu::UINT8, gpu::BGRA); + } + _texture = gpu::TexturePointer(gpu::Texture::create2D(formatGPU, image.width(), image.height(), + gpu::Sampler(gpu::Sampler::FILTER_MIN_POINT_MAG_LINEAR))); + _texture->assignStoredMip(0, formatMip, image.byteCount(), image.constBits()); + _texture->autoGenerateMips(-1); +} + +void Font::setupGPU() { + if (!_initialized) { + _initialized = true; + + // Setup render pipeline + { + auto vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(sdf_text3D_vert))); + auto pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(sdf_text3D_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + _fontLoc = program->getTextures().findLocation("Font"); + _outlineLoc = program->getUniforms().findLocation("Outline"); + _colorLoc = program->getUniforms().findLocation("Color"); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setCullMode(gpu::State::CULL_BACK); + state->setDepthTest(true, true, gpu::LESS_EQUAL); + state->setBlendFunction(true, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + } + + { + auto vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(sdf_text_vert))); + auto pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(sdf_text_frag))); + gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); + + gpu::Shader::BindingSet slotBindings; + gpu::Shader::makeProgram(*program, slotBindings); + + _fontLoc2D = program->getTextures().findLocation("Font"); + _outlineLoc2D = program->getUniforms().findLocation("Outline"); + _colorLoc2D = program->getUniforms().findLocation("Color"); + + gpu::StatePointer state = gpu::StatePointer(new gpu::State()); + state->setCullMode(gpu::State::CULL_BACK); + state->setDepthTest(false); + state->setBlendFunction(false, + gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, + gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); + _pipeline2D = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); + } + + // Sanity checks + static const int OFFSET = offsetof(TextureVertex, tex); + assert(OFFSET == sizeof(glm::vec2)); + assert(sizeof(glm::vec2) == 2 * sizeof(float)); + assert(sizeof(TextureVertex) == 2 * sizeof(glm::vec2)); + assert(sizeof(QuadBuilder) == 4 * sizeof(TextureVertex)); + + // Setup rendering structures + _format.reset(new gpu::Stream::Format()); + _format->setAttribute(gpu::Stream::POSITION, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::XYZ), 0); + _format->setAttribute(gpu::Stream::TEXCOORD, 0, gpu::Element(gpu::VEC2, gpu::FLOAT, gpu::UV), OFFSET); + } +} + +void Font::rebuildVertices(float x, float y, const QString& str, const glm::vec2& bounds) { + _verticesBuffer.reset(new gpu::Buffer()); + _numVertices = 0; + _lastStringRendered = str; + _lastBounds = bounds; + + // Top left of text + glm::vec2 advance = glm::vec2(x, y); + foreach(const QString& token, tokenizeForWrapping(str)) { + bool isNewLine = (token == QString('\n')); + bool forceNewLine = false; + + // Handle wrapping + if (!isNewLine && (bounds.x != -1) && (advance.x + computeExtent(token).x > x + bounds.x)) { + // We are out of the x bound, force new line + forceNewLine = true; + } + if (isNewLine || forceNewLine) { + // Character return, move the advance to a new line + advance = glm::vec2(x, advance.y - _leading); + + if (isNewLine) { + // No need to draw anything, go directly to next token + continue; + } else if (computeExtent(token).x > bounds.x) { + // token will never fit, stop drawing + break; + } + } + if ((bounds.y != -1) && (advance.y - _fontSize < -y - bounds.y)) { + // We are out of the y bound, stop drawing + break; + } + + // Draw the token + if (!isNewLine) { + for (auto c : token) { + auto glyph = _glyphs[c]; + + QuadBuilder qd(glyph, advance - glm::vec2(0.0f, _ascent)); + _verticesBuffer->append(sizeof(QuadBuilder), (const gpu::Byte*)&qd); + _numVertices += 4; + + // Advance by glyph size + advance.x += glyph.d; + } + + // Add space after all non return tokens + advance.x += _spaceWidth; + } + } +} + +void Font::drawString(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4* color, + EffectType effectType, const glm::vec2& bounds) { + if (str == "") { + return; + } + + if (str != _lastStringRendered || bounds != _lastBounds) { + rebuildVertices(x, y, str, bounds); + } + + setupGPU(); + + batch.setPipeline(_pipeline); + batch.setResourceTexture(_fontLoc, _texture); + batch._glUniform1i(_outlineLoc, (effectType == OUTLINE_EFFECT)); + batch._glUniform4fv(_colorLoc, 1, (const GLfloat*)color); + + batch.setInputFormat(_format); + batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); + batch.draw(gpu::QUADS, _numVertices, 0); +} + +void Font::drawString2D(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4* color, + EffectType effectType, const glm::vec2& bounds) { + if (str == "") { + return; + } + + if (str != _lastStringRendered || bounds != _lastBounds) { + rebuildVertices(x, y, str, bounds); + } + + setupGPU(); + + batch.setPipeline(_pipeline2D); + batch.setResourceTexture(_fontLoc2D, _texture); + batch._glUniform1i(_outlineLoc2D, (effectType == OUTLINE_EFFECT)); + batch._glUniform4fv(_colorLoc2D, 1, (const GLfloat*)color); + batch.setInputFormat(_format); + batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); + batch.draw(gpu::QUADS, _numVertices, 0); +} diff --git a/libraries/render-utils/src/text/Font.h b/libraries/render-utils/src/text/Font.h new file mode 100644 index 0000000000..98d0a31cf4 --- /dev/null +++ b/libraries/render-utils/src/text/Font.h @@ -0,0 +1,88 @@ +// +// Created by Bradley Austin Davis on 2015/07/16 +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_Font_h +#define hifi_Font_h + +#include "Glyph.h" +#include "EffectType.h" +#include +#include + +class Font { +public: + Font(); + + void read(QIODevice& path); + + glm::vec2 computeExtent(const QString& str) const; + float getFontSize() const { return _fontSize; } + + // Render string to batch + void drawString(gpu::Batch& batch, float x, float y, const QString& str, + const glm::vec4* color, EffectType effectType, + const glm::vec2& bound); + + void drawString2D(gpu::Batch& batch, float x, float y, const QString& str, + const glm::vec4* color, EffectType effectType, + const glm::vec2& bound); + + static Font* load(QIODevice& fontFile); + static Font* load(const QString& family); + +private: + QStringList tokenizeForWrapping(const QString& str) const; + QStringList splitLines(const QString& str) const; + glm::vec2 computeTokenExtent(const QString& str) const; + + const Glyph& getGlyph(const QChar& c) const; + void rebuildVertices(float x, float y, const QString& str, const glm::vec2& bounds); + + void setupGPU(); + + // maps characters to cached glyph info + // HACK... the operator[] const for QHash returns a + // copy of the value, not a const value reference, so + // we declare the hash as mutable in order to avoid such + // copies + mutable QHash _glyphs; + + // Font characteristics + QString _family; + float _fontSize = 0.0f; + float _leading = 0.0f; + float _ascent = 0.0f; + float _descent = 0.0f; + float _spaceWidth = 0.0f; + + bool _initialized = false; + + // gpu structures + gpu::PipelinePointer _pipeline; + gpu::PipelinePointer _pipeline2D; + gpu::TexturePointer _texture; + gpu::Stream::FormatPointer _format; + gpu::BufferPointer _verticesBuffer; + gpu::BufferStreamPointer _stream; + unsigned int _numVertices = 0; + + int _fontLoc = -1; + int _outlineLoc = -1; + int _colorLoc = -1; + int _fontLoc2D = -1; + int _outlineLoc2D = -1; + int _colorLoc2D = -1; + + // last string render characteristics + QString _lastStringRendered; + glm::vec2 _lastBounds; +}; + +#endif + diff --git a/libraries/render-utils/src/text/FontFamilies.h b/libraries/render-utils/src/text/FontFamilies.h new file mode 100644 index 0000000000..3c4186f5c4 --- /dev/null +++ b/libraries/render-utils/src/text/FontFamilies.h @@ -0,0 +1,31 @@ +// +// Created by Bradley Austin Davis on 2015/07/16 +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_FontFamilies_h +#define hifi_FontFamilies_h + +// the standard sans serif font family +#define SANS_FONT_FAMILY "Helvetica" + +// the standard sans serif font family +#define SERIF_FONT_FAMILY "Timeless" + +// the standard mono font family +#define MONO_FONT_FAMILY "Courier" + +// the Inconsolata font family +#ifdef Q_OS_WIN +#define INCONSOLATA_FONT_FAMILY "Fixedsys" +#define INCONSOLATA_FONT_WEIGHT QFont::Normal +#else +#define INCONSOLATA_FONT_FAMILY "Inconsolata" +#define INCONSOLATA_FONT_WEIGHT QFont::Bold +#endif + +#endif diff --git a/libraries/render-utils/src/text/Glyph.cpp b/libraries/render-utils/src/text/Glyph.cpp new file mode 100644 index 0000000000..0354b1057c --- /dev/null +++ b/libraries/render-utils/src/text/Glyph.cpp @@ -0,0 +1,22 @@ +#include "Glyph.h" +#include + +// We adjust bounds because offset is the bottom left corner of the font but the top left corner of a QRect +QRectF Glyph::bounds() const { + return glmToRect(offset, size).translated(0.0f, -size.y); +} + +QRectF Glyph::textureBounds() const { + return glmToRect(texOffset, texSize); +} + +void Glyph::read(QIODevice& in) { + uint16_t charcode; + readStream(in, charcode); + c = charcode; + readStream(in, texOffset); + readStream(in, size); + readStream(in, offset); + readStream(in, d); + texSize = size; +} diff --git a/libraries/render-utils/src/text/Glyph.h b/libraries/render-utils/src/text/Glyph.h new file mode 100644 index 0000000000..3cb08cc7e2 --- /dev/null +++ b/libraries/render-utils/src/text/Glyph.h @@ -0,0 +1,38 @@ +// +// Created by Bradley Austin Davis on 2015/07/16 +// Copyright 2013 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_Glyph_h +#define hifi_Glyph_h + +#include + +#include +#include +#include + +#include + +// stores the font metrics for a single character +struct Glyph { + QChar c; + vec2 texOffset; + vec2 texSize; + vec2 size; + vec2 offset; + float d; // xadvance - adjusts character positioning + size_t indexOffset; + + // We adjust bounds because offset is the bottom left corner of the font but the top left corner of a QRect + QRectF bounds() const; + QRectF textureBounds() const; + + void read(QIODevice& in); +}; + +#endif diff --git a/libraries/shared/src/StreamHelpers.h b/libraries/shared/src/StreamHelpers.h new file mode 100644 index 0000000000..f13c15e45f --- /dev/null +++ b/libraries/shared/src/StreamHelpers.h @@ -0,0 +1,32 @@ +// +// Created by Bradley Austin Davis 2015/07/16 +// Copyright 2014 High Fidelity, Inc. +// +// Distributed under the Apache License, Version 2.0. +// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html +// + +#pragma once +#ifndef hifi_StreamHelpers_h +#define hifi_StreamHelpers_h + +#include +#include + +// Helper functions for reading binary data from an IO device +template +inline void readStream(QIODevice& in, T& t) { + in.read((char*) &t, sizeof(t)); +} + +template +inline void readStream(QIODevice& in, T (&t)[N]) { + in.read((char*) t, N); +} + +template +inline void fillBuffer(QBuffer& buffer, T (&t)[N]) { + buffer.setData((const char*) t, N); +} + +#endif From 398075e45aa32775988e671857f012b518fa08da Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 16 Jul 2015 16:26:28 -0700 Subject: [PATCH 02/27] hacking on more naked GL --- interface/src/Application.cpp | 5 + interface/src/Application.h | 3 - interface/src/audio/AudioScope.cpp | 4 +- interface/src/audio/AudioScope.h | 1 + interface/src/ui/ApplicationCompositor.cpp | 31 ++-- interface/src/ui/ApplicationOverlay.cpp | 180 +++++++++++++------ interface/src/ui/ApplicationOverlay.h | 9 +- interface/src/ui/overlays/Overlays.cpp | 17 +- libraries/render-utils/src/GeometryCache.cpp | 2 + 9 files changed, 185 insertions(+), 67 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 056490806a..71eabd2d6d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -895,6 +895,11 @@ void Application::paintGL() { { PerformanceTimer perfTimer("renderOverlay"); + + // NOTE: the ApplicationOverlay class assumes it's viewport is setup to be the device size + // There is no batch associated with this renderArgs + QSize size = qApp->getDeviceSize(); + renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); _applicationOverlay.renderOverlay(&renderArgs); } diff --git a/interface/src/Application.h b/interface/src/Application.h index 44ead54563..d2a55fbf70 100644 --- a/interface/src/Application.h +++ b/interface/src/Application.h @@ -359,9 +359,6 @@ signals: /// Fired when we're rendering in-world interface elements; allows external parties to hook in. void renderingInWorldInterface(); - /// Fired when we're rendering the overlay. - void renderingOverlay(); - /// Fired when the import window is closed void importDone(); diff --git a/interface/src/audio/AudioScope.cpp b/interface/src/audio/AudioScope.cpp index 4b4e86e7f4..d9ceb82eef 100644 --- a/interface/src/audio/AudioScope.cpp +++ b/interface/src/audio/AudioScope.cpp @@ -38,6 +38,7 @@ AudioScope::AudioScope() : _scopeOutputLeft(NULL), _scopeOutputRight(NULL), _scopeLastFrame(), + _audioScopeBackground(DependencyManager::get()->allocateID()), _audioScopeGrid(DependencyManager::get()->allocateID()), _inputID(DependencyManager::get()->allocateID()), _outputLeftID(DependencyManager::get()->allocateID()), @@ -135,7 +136,8 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) { batch.setProjectionTransform(legacyProjection); batch.setModelTransform(Transform()); batch.setViewTransform(Transform()); - geometryCache->renderQuad(batch, x, y, w, h, backgroundColor); + batch._glLineWidth(1.0f); // default + geometryCache->renderQuad(batch, x, y, w, h, backgroundColor, _audioScopeBackground); geometryCache->renderGrid(batch, x, y, w, h, gridRows, gridCols, gridColor, _audioScopeGrid); renderLineStrip(batch, _inputID, inputColor, x, y, _samplesPerScope, _scopeInputOffset, _scopeInput); renderLineStrip(batch, _outputLeftID, outputLeftColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputLeft); diff --git a/interface/src/audio/AudioScope.h b/interface/src/audio/AudioScope.h index 4ff4b55c29..0b716d7666 100644 --- a/interface/src/audio/AudioScope.h +++ b/interface/src/audio/AudioScope.h @@ -69,6 +69,7 @@ private: QByteArray* _scopeOutputRight; QByteArray _scopeLastFrame; + int _audioScopeBackground; int _audioScopeGrid; int _inputID; int _outputLeftID; diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 4623109cdd..56735111c1 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -189,8 +189,9 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { return; } - GLuint texture = qApp->getApplicationOverlay().getOverlayTexture(); - if (!texture) { + //GLuint texture = 0; // FIXME -- qApp->getApplicationOverlay().getOverlayTexture(); + gpu::FramebufferPointer overlayFramebuffer = qApp->getApplicationOverlay().getOverlayFramebuffer(); + if (!overlayFramebuffer) { return; } @@ -209,9 +210,12 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { batch.setModelTransform(Transform()); batch.setViewTransform(Transform()); batch.setProjectionTransform(mat4()); - batch._glBindTexture(GL_TEXTURE_2D, texture); - batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + //batch._glBindTexture(GL_TEXTURE_2D, texture); + //batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + //batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + batch.setResourceTexture(0, overlayFramebuffer->getRenderBuffer(0)); + geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha)); // Doesn't actually render @@ -258,8 +262,12 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int return; } - GLuint texture = qApp->getApplicationOverlay().getOverlayTexture(); - if (!texture) { + //GLuint texture = 0; // FIXME -- qApp->getApplicationOverlay().getOverlayTexture(); + //if (!texture) { + // return; + //} + gpu::FramebufferPointer overlayFramebuffer = qApp->getApplicationOverlay().getOverlayFramebuffer(); + if (!overlayFramebuffer) { return; } @@ -275,9 +283,12 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int geometryCache->useSimpleDrawPipeline(batch); batch._glDisable(GL_DEPTH_TEST); batch._glDisable(GL_CULL_FACE); - batch._glBindTexture(GL_TEXTURE_2D, texture); - batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + //batch._glBindTexture(GL_TEXTURE_2D, texture); + //batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + //batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + batch.setResourceTexture(0, overlayFramebuffer->getRenderBuffer(0)); + batch.setViewTransform(Transform()); batch.setProjectionTransform(qApp->getEyeProjection(eye)); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 63dcba9d5d..f89867c70d 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -40,12 +40,6 @@ const float CONNECTION_STATUS_BORDER_LINE_WIDTH = 4.0f; static const float ORTHO_NEAR_CLIP = -10000; static const float ORTHO_FAR_CLIP = 10000; -// TODO move somewhere useful -static void fboViewport(QOpenGLFramebufferObject* fbo) { - auto size = fbo->size(); - glViewport(0, 0, size.width(), size.height()); -} - ApplicationOverlay::ApplicationOverlay() { auto geometryCache = DependencyManager::get(); @@ -84,16 +78,41 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { buildFramebufferObject(); // Execute the batch into our framebuffer - _overlayFramebuffer->bind(); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - fboViewport(_overlayFramebuffer); + + gpu::Batch batch; + + // 1) bind the framebuffer + //_overlayFramebuffer->bind(); + batch.setFramebuffer(_overlayFramebuffer); + + // 2) clear it... + //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + glm::vec4 color { 0.0f, 0.0f, 0.0f, 0.0f }; + float depth = 1.0f; + int stencil = 0; + //batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLORS | gpu::Framebuffer::BUFFER_DEPTH, color, depth, stencil); + batch.clearColorFramebuffer(_overlayFramebuffer->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); + + int width = _overlayFramebuffer ? _overlayFramebuffer->getWidth() : 0; + int height = _overlayFramebuffer ? _overlayFramebuffer->getHeight() : 0; + + glViewport(0, 0, width, height); + + qDebug() << "ApplicationOverlay::renderOverlay()... "; + qDebug() << " renderArgs->batch:" << (void*)renderArgs->_batch; + qDebug() << " renderArgs->_viewport:" << renderArgs->_viewport.z << "," << renderArgs->_viewport.w; + qDebug() << " getDeviceSize:" << qApp->getDeviceSize(); + qDebug() << " getCanvasSize:" << qApp->getCanvasSize(); + qDebug() << " _overlayFramebuffer size:" << width << "," << height; // Now render the overlay components together into a single texture - renderOverlays(renderArgs); - renderStatsAndLogs(renderArgs); - renderDomainConnectionStatusBorder(renderArgs); - renderQmlUi(renderArgs); - _overlayFramebuffer->release(); + renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope + renderStatsAndLogs(renderArgs); // currently renders nothing + renderDomainConnectionStatusBorder(renderArgs); // renders the connected domain line + renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture + + //_overlayFramebuffer->release(); // now we're done for later composition + batch.setFramebuffer(nullptr); CHECK_GL_ERROR(); } @@ -102,11 +121,15 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { if (_uiTexture) { gpu::Batch batch; auto geometryCache = DependencyManager::get(); + geometryCache->useSimpleDrawPipeline(batch); batch.setProjectionTransform(mat4()); - batch.setModelTransform(mat4()); + batch.setModelTransform(Transform()); + batch.setViewTransform(Transform()); batch._glBindTexture(GL_TEXTURE_2D, _uiTexture); + geometryCache->renderUnitQuad(batch, glm::vec4(1)); + renderArgs->_context->syncCache(); renderArgs->_context->render(batch); } @@ -114,31 +137,34 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { PROFILE_RANGE(__FUNCTION__); - glm::vec2 size = qApp->getCanvasSize(); - mat4 legacyProjection = glm::ortho(0, size.x, size.y, 0, ORTHO_NEAR_CLIP, ORTHO_FAR_CLIP); - glMatrixMode(GL_PROJECTION); - glPushMatrix(); - glLoadMatrixf(glm::value_ptr(legacyProjection)); - glMatrixMode(GL_MODELVIEW); - - glDisable(GL_DEPTH_TEST); - glDisable(GL_LIGHTING); - glEnable(GL_BLEND); - glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); - glUseProgram(0); - - // give external parties a change to hook in - emit qApp->renderingOverlay(); - qApp->getOverlays().renderHUD(renderArgs); - - DependencyManager::get()->render(renderArgs, _overlayFramebuffer->size().width(), _overlayFramebuffer->size().height()); - - glMatrixMode(GL_PROJECTION); - glPopMatrix(); - glMatrixMode(GL_MODELVIEW); - - fboViewport(_overlayFramebuffer); + gpu::Batch batch; + auto geometryCache = DependencyManager::get(); + geometryCache->useSimpleDrawPipeline(batch); + auto textureCache = DependencyManager::get(); + batch.setResourceTexture(0, textureCache->getWhiteTexture()); + int width = renderArgs->_viewport.z; + int height = renderArgs->_viewport.w; + mat4 legacyProjection = glm::ortho(0, width, height, 0, -1000, 1000); + batch.setProjectionTransform(legacyProjection); + batch.setModelTransform(Transform()); + batch.setViewTransform(Transform()); + batch._glLineWidth(1.0f); // default + + { + // Render all of the Script based "HUD" aka 2D overlays. + // note: we call them HUD, as opposed to 2D, only because there are some cases of 3D HUD overlays, like the + // cameral controls for the edit.js + qApp->getOverlays().renderHUD(renderArgs); + + // Render the audio scope + int width = _overlayFramebuffer ? _overlayFramebuffer->getWidth() : 0; + int height = _overlayFramebuffer ? _overlayFramebuffer->getHeight() : 0; + DependencyManager::get()->render(renderArgs, width, height); + } + + renderArgs->_context->syncCache(); + renderArgs->_context->render(batch); } void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) { @@ -202,32 +228,86 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderAr } } -GLuint ApplicationOverlay::getOverlayTexture() { - if (!_overlayFramebuffer) { - return 0; - } - return _overlayFramebuffer->texture(); -} - void ApplicationOverlay::buildFramebufferObject() { PROFILE_RANGE(__FUNCTION__); - QSize fboSize = qApp->getDeviceSize(); - if (_overlayFramebuffer && fboSize == _overlayFramebuffer->size()) { + + QSize desiredSize = qApp->getDeviceSize(); + int currentWidth = _overlayFramebuffer ? _overlayFramebuffer->getWidth() : 0; + int currentHeight = _overlayFramebuffer ? _overlayFramebuffer->getHeight() : 0; + QSize frameBufferCurrentSize(currentWidth, currentHeight); + + if (_overlayFramebuffer && desiredSize == frameBufferCurrentSize) { // Already built return; } if (_overlayFramebuffer) { - delete _overlayFramebuffer; + _overlayFramebuffer.reset(); + _overlayDepthTexture.reset(); + _overlayColorTexture.reset(); } + + _overlayFramebuffer = gpu::FramebufferPointer(gpu::Framebuffer::create()); + + auto colorFormat = gpu::Element(gpu::VEC4, gpu::NUINT8, gpu::RGBA); + auto width = desiredSize.width(); + auto height = desiredSize.height(); + + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + _overlayColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); + _overlayFramebuffer->setRenderBuffer(0, _overlayColorTexture); + + + auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); + _overlayDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler)); + + _overlayFramebuffer->setDepthStencilBuffer(_overlayDepthTexture, depthFormat); + + + /* + // This code essentially created a frame buffer, then sets a bunch of the parameters for that texture. _overlayFramebuffer = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth); + + GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; + + gpu::Batch batch; + batch._glBindTexture(GL_TEXTURE_2D, getOverlayTexture()); + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + batch._glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); + batch._glBindTexture(GL_TEXTURE_2D, 0); + */ + + /* glBindTexture(GL_TEXTURE_2D, getOverlayTexture()); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); glBindTexture(GL_TEXTURE_2D, 0); + */ + + + + /**** Example code... + batch._glBindTexture(GL_TEXTURE_2D, texture); + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + + + // this stuff is what would actually render from the texture + + geometryCache->useSimpleDrawPipeline(batch); + batch.setViewportTransform(glm::ivec4(0, 0, deviceSize.width(), deviceSize.height())); + batch.setModelTransform(Transform()); + batch.setViewTransform(Transform()); + batch.setProjectionTransform(mat4()); + batch._glBindTexture(GL_TEXTURE_2D, texture); + geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha)); + ****/ + } diff --git a/interface/src/ui/ApplicationOverlay.h b/interface/src/ui/ApplicationOverlay.h index 2f434ed7e1..0bbe4e3f77 100644 --- a/interface/src/ui/ApplicationOverlay.h +++ b/interface/src/ui/ApplicationOverlay.h @@ -25,7 +25,8 @@ public: ~ApplicationOverlay(); void renderOverlay(RenderArgs* renderArgs); - GLuint getOverlayTexture(); + + gpu::FramebufferPointer getOverlayFramebuffer() const { return _overlayFramebuffer; } private: void renderStatsAndLogs(RenderArgs* renderArgs); @@ -44,7 +45,11 @@ private: int _magnifierBorder; ivec2 _previousBorderSize{ -1 }; - QOpenGLFramebufferObject* _overlayFramebuffer{ nullptr }; + + gpu::TexturePointer _overlayDepthTexture; + gpu::TexturePointer _overlayColorTexture; + gpu::FramebufferPointer _overlayFramebuffer; + }; #endif // hifi_ApplicationOverlay_h diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index e4401b32ef..8a1aa1014e 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -100,9 +100,24 @@ void Overlays::renderHUD(RenderArgs* renderArgs) { QReadLocker lock(&_lock); gpu::Batch batch; renderArgs->_batch = &batch; - + + auto geometryCache = DependencyManager::get(); + auto textureCache = DependencyManager::get(); + int width = renderArgs->_viewport.z; + int height = renderArgs->_viewport.w; + mat4 legacyProjection = glm::ortho(0, width, height, 0, -1000, 1000); + foreach(Overlay::Pointer thisOverlay, _overlaysHUD) { + + // Reset all batch pipeline settings between overlay + geometryCache->useSimpleDrawPipeline(batch); + batch.setResourceTexture(0, textureCache->getWhiteTexture()); + batch.setProjectionTransform(legacyProjection); + batch.setModelTransform(Transform()); + batch.setViewTransform(Transform()); + batch._glLineWidth(1.0f); // default + thisOverlay->render(renderArgs); } diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 2bf41bc9b3..7cb882acc1 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -433,6 +433,8 @@ void GeometryCache::renderGrid(gpu::Batch& batch, int x, int y, int width, int h } // Draw vertical grid lines for (int i = cols + 1; --i >= 0; ) { + //glVertex2i(tx, y); + //glVertex2i(tx, y + height); *(vertex++) = tx; *(vertex++) = y; From 09430b6596107f9fbdf7dfd76ed6851dcc2411a7 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 16 Jul 2015 16:27:41 -0700 Subject: [PATCH 03/27] hacking on more naked GL --- interface/src/ui/ApplicationOverlay.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index f89867c70d..cfa0390e73 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -90,8 +90,8 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { glm::vec4 color { 0.0f, 0.0f, 0.0f, 0.0f }; float depth = 1.0f; int stencil = 0; - //batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLORS | gpu::Framebuffer::BUFFER_DEPTH, color, depth, stencil); - batch.clearColorFramebuffer(_overlayFramebuffer->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); + batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLORS | gpu::Framebuffer::BUFFER_DEPTH, color, depth, stencil); + //batch.clearColorFramebuffer(_overlayFramebuffer->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); int width = _overlayFramebuffer ? _overlayFramebuffer->getWidth() : 0; int height = _overlayFramebuffer ? _overlayFramebuffer->getHeight() : 0; From 069620b2d9cdfc7c840dbdae2a4df43b38fb2b8f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 16 Jul 2015 16:36:48 -0700 Subject: [PATCH 04/27] hacking on more naked GL --- interface/src/ui/ApplicationOverlay.cpp | 23 ++++++++++++++--------- interface/src/ui/overlays/Overlays.cpp | 7 +++---- 2 files changed, 17 insertions(+), 13 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index cfa0390e73..4fa6cbcb92 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -80,6 +80,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { // Execute the batch into our framebuffer gpu::Batch batch; + renderArgs->_batch = &batch; // 1) bind the framebuffer //_overlayFramebuffer->bind(); @@ -113,13 +114,17 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { //_overlayFramebuffer->release(); // now we're done for later composition batch.setFramebuffer(nullptr); + + renderArgs->_context->syncCache(); + renderArgs->_context->render(batch); + CHECK_GL_ERROR(); } void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { PROFILE_RANGE(__FUNCTION__); if (_uiTexture) { - gpu::Batch batch; + gpu::Batch& batch = *renderArgs->_batch; auto geometryCache = DependencyManager::get(); geometryCache->useSimpleDrawPipeline(batch); @@ -130,15 +135,15 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { geometryCache->renderUnitQuad(batch, glm::vec4(1)); - renderArgs->_context->syncCache(); - renderArgs->_context->render(batch); + //renderArgs->_context->syncCache(); + //renderArgs->_context->render(batch); } } void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { PROFILE_RANGE(__FUNCTION__); - gpu::Batch batch; + gpu::Batch& batch = *renderArgs->_batch; auto geometryCache = DependencyManager::get(); geometryCache->useSimpleDrawPipeline(batch); auto textureCache = DependencyManager::get(); @@ -163,8 +168,8 @@ void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { DependencyManager::get()->render(renderArgs, width, height); } - renderArgs->_context->syncCache(); - renderArgs->_context->render(batch); + //renderArgs->_context->syncCache(); + //renderArgs->_context->render(batch); } void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) { @@ -208,7 +213,7 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderAr }); auto nodeList = DependencyManager::get(); if (nodeList && !nodeList->getDomainHandler().isConnected()) { - gpu::Batch batch; + gpu::Batch& batch = *renderArgs->_batch; auto geometryCache = DependencyManager::get(); geometryCache->useSimpleDrawPipeline(batch); batch.setProjectionTransform(mat4()); @@ -223,8 +228,8 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderAr //batch.setModelTransform(glm::scale(mat4(), vec3(scaleAmount))); geometryCache->renderVertices(batch, gpu::LINE_STRIP, _domainStatusBorder); - renderArgs->_context->syncCache(); - renderArgs->_context->render(batch); + //renderArgs->_context->syncCache(); + //renderArgs->_context->render(batch); } } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 8a1aa1014e..343e571bfe 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -98,8 +98,7 @@ void Overlays::cleanupOverlaysToDelete() { void Overlays::renderHUD(RenderArgs* renderArgs) { PROFILE_RANGE(__FUNCTION__); QReadLocker lock(&_lock); - gpu::Batch batch; - renderArgs->_batch = &batch; + gpu::Batch& batch = *renderArgs->_batch; auto geometryCache = DependencyManager::get(); auto textureCache = DependencyManager::get(); @@ -121,8 +120,8 @@ void Overlays::renderHUD(RenderArgs* renderArgs) { thisOverlay->render(renderArgs); } - renderArgs->_context->syncCache(); - renderArgs->_context->render(batch); + //renderArgs->_context->syncCache(); + //renderArgs->_context->render(batch); } unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) { From ae10d5814211f2f62cdefbd35bee8a76e11fec47 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 16 Jul 2015 16:42:29 -0700 Subject: [PATCH 05/27] Fixing font class --- libraries/render-utils/src/text/Font.cpp | 52 ++---------------------- libraries/render-utils/src/text/Font.h | 8 ---- 2 files changed, 4 insertions(+), 56 deletions(-) diff --git a/libraries/render-utils/src/text/Font.cpp b/libraries/render-utils/src/text/Font.cpp index 8e83c55fec..6aae7ae81a 100644 --- a/libraries/render-utils/src/text/Font.cpp +++ b/libraries/render-utils/src/text/Font.cpp @@ -7,8 +7,6 @@ #include "sdf_text3D_vert.h" #include "sdf_text3D_frag.h" -#include "sdf_text_vert.h" -#include "sdf_text_frag.h" #include "../RenderUtilsLogging.h" #include "FontFamilies.h" @@ -53,10 +51,10 @@ Font* Font::load(QIODevice& fontFile) { Font* Font::load(const QString& family) { if (!LOADED_FONTS.contains(family)) { - const QString SDFF_COURIER_PRIME_FILENAME = ":/CourierPrime.sdff"; - const QString SDFF_INCONSOLATA_MEDIUM_FILENAME = ":/InconsolataMedium.sdff"; - const QString SDFF_ROBOTO_FILENAME = ":/Roboto.sdff"; - const QString SDFF_TIMELESS_FILENAME = ":/Timeless.sdff"; + static const QString SDFF_COURIER_PRIME_FILENAME{ ":/CourierPrime.sdff" }; + static const QString SDFF_INCONSOLATA_MEDIUM_FILENAME{ ":/InconsolataMedium.sdff" }; + static const QString SDFF_ROBOTO_FILENAME{ ":/Roboto.sdff" }; + static const QString SDFF_TIMELESS_FILENAME{ ":/Timeless.sdff" }; QString loadFilename; @@ -234,27 +232,6 @@ void Font::setupGPU() { _pipeline = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); } - { - auto vertexShader = gpu::ShaderPointer(gpu::Shader::createVertex(std::string(sdf_text_vert))); - auto pixelShader = gpu::ShaderPointer(gpu::Shader::createPixel(std::string(sdf_text_frag))); - gpu::ShaderPointer program = gpu::ShaderPointer(gpu::Shader::createProgram(vertexShader, pixelShader)); - - gpu::Shader::BindingSet slotBindings; - gpu::Shader::makeProgram(*program, slotBindings); - - _fontLoc2D = program->getTextures().findLocation("Font"); - _outlineLoc2D = program->getUniforms().findLocation("Outline"); - _colorLoc2D = program->getUniforms().findLocation("Color"); - - gpu::StatePointer state = gpu::StatePointer(new gpu::State()); - state->setCullMode(gpu::State::CULL_BACK); - state->setDepthTest(false); - state->setBlendFunction(false, - gpu::State::SRC_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::INV_SRC_ALPHA, - gpu::State::FACTOR_ALPHA, gpu::State::BLEND_OP_ADD, gpu::State::ONE); - _pipeline2D = gpu::PipelinePointer(gpu::Pipeline::create(program, state)); - } - // Sanity checks static const int OFFSET = offsetof(TextureVertex, tex); assert(OFFSET == sizeof(glm::vec2)); @@ -343,24 +320,3 @@ void Font::drawString(gpu::Batch& batch, float x, float y, const QString& str, c batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); batch.draw(gpu::QUADS, _numVertices, 0); } - -void Font::drawString2D(gpu::Batch& batch, float x, float y, const QString& str, const glm::vec4* color, - EffectType effectType, const glm::vec2& bounds) { - if (str == "") { - return; - } - - if (str != _lastStringRendered || bounds != _lastBounds) { - rebuildVertices(x, y, str, bounds); - } - - setupGPU(); - - batch.setPipeline(_pipeline2D); - batch.setResourceTexture(_fontLoc2D, _texture); - batch._glUniform1i(_outlineLoc2D, (effectType == OUTLINE_EFFECT)); - batch._glUniform4fv(_colorLoc2D, 1, (const GLfloat*)color); - batch.setInputFormat(_format); - batch.setInputBuffer(0, _verticesBuffer, 0, _format->getChannels().at(0)._stride); - batch.draw(gpu::QUADS, _numVertices, 0); -} diff --git a/libraries/render-utils/src/text/Font.h b/libraries/render-utils/src/text/Font.h index 98d0a31cf4..55801419f9 100644 --- a/libraries/render-utils/src/text/Font.h +++ b/libraries/render-utils/src/text/Font.h @@ -29,10 +29,6 @@ public: const glm::vec4* color, EffectType effectType, const glm::vec2& bound); - void drawString2D(gpu::Batch& batch, float x, float y, const QString& str, - const glm::vec4* color, EffectType effectType, - const glm::vec2& bound); - static Font* load(QIODevice& fontFile); static Font* load(const QString& family); @@ -65,7 +61,6 @@ private: // gpu structures gpu::PipelinePointer _pipeline; - gpu::PipelinePointer _pipeline2D; gpu::TexturePointer _texture; gpu::Stream::FormatPointer _format; gpu::BufferPointer _verticesBuffer; @@ -75,9 +70,6 @@ private: int _fontLoc = -1; int _outlineLoc = -1; int _colorLoc = -1; - int _fontLoc2D = -1; - int _outlineLoc2D = -1; - int _colorLoc2D = -1; // last string render characteristics QString _lastStringRendered; From 410e0a99ad58b8c2d26a8ac10432d42ab5038868 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Thu, 16 Jul 2015 16:45:58 -0700 Subject: [PATCH 06/27] hacking on more naked GL --- interface/src/ui/ApplicationOverlay.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 4fa6cbcb92..f2d00512ae 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -89,7 +89,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { // 2) clear it... //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glm::vec4 color { 0.0f, 0.0f, 0.0f, 0.0f }; - float depth = 1.0f; + float depth = 0.0f; int stencil = 0; batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLORS | gpu::Framebuffer::BUFFER_DEPTH, color, depth, stencil); //batch.clearColorFramebuffer(_overlayFramebuffer->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); @@ -97,14 +97,8 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { int width = _overlayFramebuffer ? _overlayFramebuffer->getWidth() : 0; int height = _overlayFramebuffer ? _overlayFramebuffer->getHeight() : 0; - glViewport(0, 0, width, height); - - qDebug() << "ApplicationOverlay::renderOverlay()... "; - qDebug() << " renderArgs->batch:" << (void*)renderArgs->_batch; - qDebug() << " renderArgs->_viewport:" << renderArgs->_viewport.z << "," << renderArgs->_viewport.w; - qDebug() << " getDeviceSize:" << qApp->getDeviceSize(); - qDebug() << " getCanvasSize:" << qApp->getCanvasSize(); - qDebug() << " _overlayFramebuffer size:" << width << "," << height; + //glViewport(0, 0, width, height); + batch.setViewportTransform(glm::ivec4(0, 0, width, height)); // Now render the overlay components together into a single texture renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope @@ -113,7 +107,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture //_overlayFramebuffer->release(); // now we're done for later composition - batch.setFramebuffer(nullptr); + //batch.setFramebuffer(nullptr); renderArgs->_context->syncCache(); renderArgs->_context->render(batch); From e6e9f017c0d848c4c0a244f29a3a1d07544579c1 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 16 Jul 2015 17:23:25 -0700 Subject: [PATCH 07/27] Fixing test code --- tests/render-utils/src/main.cpp | 61 +++++---------------------------- 1 file changed, 9 insertions(+), 52 deletions(-) diff --git a/tests/render-utils/src/main.cpp b/tests/render-utils/src/main.cpp index 87338e414b..350db8c879 100644 --- a/tests/render-utils/src/main.cpp +++ b/tests/render-utils/src/main.cpp @@ -8,7 +8,7 @@ // See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html // -#include "TextRenderer.h" +#include #include #include @@ -29,6 +29,7 @@ #include #include #include + #include #include @@ -86,7 +87,7 @@ class QTestWindow : public QWindow { QOpenGLContext* _context{ nullptr }; QSize _size; - TextRenderer* _textRenderer[4]; + //TextRenderer* _textRenderer[4]; RateCounter fps; protected: @@ -146,12 +147,12 @@ public: glGetError(); #endif - _textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false); - _textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false, - TextRenderer::SHADOW_EFFECT); - _textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1, - false, TextRenderer::OUTLINE_EFFECT); - _textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24); + //_textRenderer[0] = TextRenderer::getInstance(SANS_FONT_FAMILY, 12, false); + //_textRenderer[1] = TextRenderer::getInstance(SERIF_FONT_FAMILY, 12, false, + // TextRenderer::SHADOW_EFFECT); + //_textRenderer[2] = TextRenderer::getInstance(MONO_FONT_FAMILY, 48, -1, + // false, TextRenderer::OUTLINE_EFFECT); + //_textRenderer[3] = TextRenderer::getInstance(INCONSOLATA_FONT_FAMILY, 24); glEnable(GL_BLEND); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); @@ -190,48 +191,6 @@ static const glm::uvec2 QUAD_OFFSET(10, 10); static const glm::vec3 COLORS[4] = { { 1.0, 1.0, 1.0 }, { 0.5, 1.0, 0.5 }, { 1.0, 0.5, 0.5 }, { 0.5, 0.5, 1.0 } }; -void QTestWindow::renderText() { - glMatrixMode(GL_PROJECTION); - glLoadIdentity(); - glOrtho(0, _size.width(), _size.height(), 0, 1, -1); - glMatrixMode(GL_MODELVIEW); - glLoadIdentity(); - - const glm::uvec2 size = glm::uvec2(_size.width() / 2, _size.height() / 2); - - const glm::uvec2 offsets[4] = { - { QUAD_OFFSET.x, QUAD_OFFSET.y }, - { size.x + QUAD_OFFSET.x, QUAD_OFFSET.y }, - { size.x + QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, - { QUAD_OFFSET.x, size.y + QUAD_OFFSET.y }, - }; - - QString str = QString::fromWCharArray(EXAMPLE_TEXT); - for (int i = 0; i < 4; ++i) { - glm::vec2 bounds = _textRenderer[i]->computeExtent(str); - glPushMatrix(); - { - glTranslatef(offsets[i].x, offsets[i].y, 0); - glColor3f(0, 0, 0); - glBegin(GL_QUADS); - { - glVertex2f(0, 0); - glVertex2f(0, bounds.y); - glVertex2f(bounds.x, bounds.y); - glVertex2f(bounds.x, 0); - } - glEnd(); - } - glPopMatrix(); - const int testCount = 100; - for (int j = 0; j < testCount; ++j) { - // Draw backgrounds around where the text will appear - // Draw the text itself - _textRenderer[i]->draw(offsets[i].x, offsets[i].y, str.toLocal8Bit().constData(), - glm::vec4(COLORS[i], 1.0f)); - } - } -} void QTestWindow::draw() { if (!isVisible()) { @@ -242,8 +201,6 @@ void QTestWindow::draw() { glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glViewport(0, 0, _size.width() * devicePixelRatio(), _size.height() * devicePixelRatio()); - renderText(); - _context->swapBuffers(this); glFinish(); From 7e32bfb85e5a698ef2e83dbc8b773764d8664401 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Thu, 16 Jul 2015 17:35:05 -0700 Subject: [PATCH 08/27] Fixing mac/linux build --- interface/src/ui/overlays/TextOverlay.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 466e536189..32d94ec05b 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -232,7 +232,7 @@ QScriptValue TextOverlay::getProperty(const QString& property) { QSizeF TextOverlay::textSize(const QString& text) const { int lines = 1; foreach(QChar c, text) { - if (c == "\n") { + if (c == QChar('\n')) { ++lines; } } @@ -261,4 +261,4 @@ void TextOverlay::setTopMargin(int margin) { _qmlElement->settopMargin(margin); } -#include "TextOverlay.moc" \ No newline at end of file +#include "TextOverlay.moc" From 18d0cb5158f7d5ebd140060f25f6d82ffef1cec0 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 16 Jul 2015 17:48:28 -0700 Subject: [PATCH 09/27] cleanup of EntityItem ctors and friends --- libraries/entities/src/BoxEntityItem.cpp | 1 - libraries/entities/src/EntityItem.cpp | 8 ++------ libraries/entities/src/EntityItem.h | 1 - libraries/entities/src/LightEntityItem.cpp | 2 +- libraries/entities/src/LineEntityItem.cpp | 1 - libraries/entities/src/ModelEntityItem.cpp | 2 +- libraries/entities/src/ParticleEffectEntityItem.cpp | 2 +- libraries/entities/src/PolyVoxEntityItem.cpp | 1 - libraries/entities/src/SphereEntityItem.cpp | 2 +- libraries/entities/src/TextEntityItem.cpp | 1 - libraries/entities/src/WebEntityItem.cpp | 3 +-- libraries/entities/src/ZoneEntityItem.cpp | 1 - 12 files changed, 7 insertions(+), 18 deletions(-) diff --git a/libraries/entities/src/BoxEntityItem.cpp b/libraries/entities/src/BoxEntityItem.cpp index 291e350db0..ce05bd93f0 100644 --- a/libraries/entities/src/BoxEntityItem.cpp +++ b/libraries/entities/src/BoxEntityItem.cpp @@ -29,7 +29,6 @@ BoxEntityItem::BoxEntityItem(const EntityItemID& entityItemID, const EntityItemP EntityItem(entityItemID) { _type = EntityTypes::Box; - _created = properties.getCreated(); setProperties(properties); } diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 50b36ec6e2..935ca77376 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -85,11 +85,6 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _lastUpdated = now; } -EntityItem::EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : EntityItem(entityItemID) -{ - setProperties(properties); -} - EntityItem::~EntityItem() { // clear out any left-over actions EntityTree* entityTree = _element ? _element->getTree() : nullptr; @@ -1077,6 +1072,8 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c bool EntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = false; + // just in case _created must be properly set before the rest we do it first + SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); // these affect TerseUpdate properties SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner); @@ -1099,7 +1096,6 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions); SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); - SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); // non-simulation properties below diff --git a/libraries/entities/src/EntityItem.h b/libraries/entities/src/EntityItem.h index de431446e8..478c96a2f2 100644 --- a/libraries/entities/src/EntityItem.h +++ b/libraries/entities/src/EntityItem.h @@ -119,7 +119,6 @@ public: DONT_ALLOW_INSTANTIATION // This class can not be instantiated directly EntityItem(const EntityItemID& entityItemID); - EntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties); virtual ~EntityItem(); // ID and EntityItemID related methods diff --git a/libraries/entities/src/LightEntityItem.cpp b/libraries/entities/src/LightEntityItem.cpp index 5e765a0792..d67d09e4b1 100644 --- a/libraries/entities/src/LightEntityItem.cpp +++ b/libraries/entities/src/LightEntityItem.cpp @@ -29,7 +29,7 @@ EntityItemPointer LightEntityItem::factory(const EntityItemID& entityID, const E // our non-pure virtual subclass for now... LightEntityItem::LightEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID, properties) + EntityItem(entityItemID) { _type = EntityTypes::Light; diff --git a/libraries/entities/src/LineEntityItem.cpp b/libraries/entities/src/LineEntityItem.cpp index 067b1d8fee..222aee1a8f 100644 --- a/libraries/entities/src/LineEntityItem.cpp +++ b/libraries/entities/src/LineEntityItem.cpp @@ -38,7 +38,6 @@ LineEntityItem::LineEntityItem(const EntityItemID& entityItemID, const EntityIte _points(QVector(0)) { _type = EntityTypes::Line; - _created = properties.getCreated(); setProperties(properties); diff --git a/libraries/entities/src/ModelEntityItem.cpp b/libraries/entities/src/ModelEntityItem.cpp index b72dd5fab4..a5c52a32bf 100644 --- a/libraries/entities/src/ModelEntityItem.cpp +++ b/libraries/entities/src/ModelEntityItem.cpp @@ -33,7 +33,7 @@ EntityItemPointer ModelEntityItem::factory(const EntityItemID& entityID, const E } ModelEntityItem::ModelEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID, properties) + EntityItem(entityItemID) { _type = EntityTypes::Model; setProperties(properties); diff --git a/libraries/entities/src/ParticleEffectEntityItem.cpp b/libraries/entities/src/ParticleEffectEntityItem.cpp index 5c8a5b63a1..60c46b4cac 100644 --- a/libraries/entities/src/ParticleEffectEntityItem.cpp +++ b/libraries/entities/src/ParticleEffectEntityItem.cpp @@ -61,7 +61,7 @@ EntityItemPointer ParticleEffectEntityItem::factory(const EntityItemID& entityID // our non-pure virtual subclass for now... ParticleEffectEntityItem::ParticleEffectEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID, properties), + EntityItem(entityItemID), _maxParticles(DEFAULT_MAX_PARTICLES), _lifespan(DEFAULT_LIFESPAN), _emitRate(DEFAULT_EMIT_RATE), diff --git a/libraries/entities/src/PolyVoxEntityItem.cpp b/libraries/entities/src/PolyVoxEntityItem.cpp index 6f284caeaa..9657b1a8fe 100644 --- a/libraries/entities/src/PolyVoxEntityItem.cpp +++ b/libraries/entities/src/PolyVoxEntityItem.cpp @@ -57,7 +57,6 @@ PolyVoxEntityItem::PolyVoxEntityItem(const EntityItemID& entityItemID, const Ent _voxelSurfaceStyle(PolyVoxEntityItem::DEFAULT_VOXEL_SURFACE_STYLE) { _type = EntityTypes::PolyVox; - _created = properties.getCreated(); setProperties(properties); } diff --git a/libraries/entities/src/SphereEntityItem.cpp b/libraries/entities/src/SphereEntityItem.cpp index 2298035854..c77a513cfc 100644 --- a/libraries/entities/src/SphereEntityItem.cpp +++ b/libraries/entities/src/SphereEntityItem.cpp @@ -30,7 +30,7 @@ EntityItemPointer SphereEntityItem::factory(const EntityItemID& entityID, const // our non-pure virtual subclass for now... SphereEntityItem::SphereEntityItem(const EntityItemID& entityItemID, const EntityItemProperties& properties) : - EntityItem(entityItemID, properties) + EntityItem(entityItemID) { _type = EntityTypes::Sphere; setProperties(properties); diff --git a/libraries/entities/src/TextEntityItem.cpp b/libraries/entities/src/TextEntityItem.cpp index 31ee9e6676..f4472642e4 100644 --- a/libraries/entities/src/TextEntityItem.cpp +++ b/libraries/entities/src/TextEntityItem.cpp @@ -37,7 +37,6 @@ TextEntityItem::TextEntityItem(const EntityItemID& entityItemID, const EntityIte EntityItem(entityItemID) { _type = EntityTypes::Text; - _created = properties.getCreated(); setProperties(properties); } diff --git a/libraries/entities/src/WebEntityItem.cpp b/libraries/entities/src/WebEntityItem.cpp index 4c849f5270..915fd8c00c 100644 --- a/libraries/entities/src/WebEntityItem.cpp +++ b/libraries/entities/src/WebEntityItem.cpp @@ -30,7 +30,6 @@ WebEntityItem::WebEntityItem(const EntityItemID& entityItemID, const EntityItemP EntityItem(entityItemID) { _type = EntityTypes::Web; - _created = properties.getCreated(); setProperties(properties); } @@ -149,4 +148,4 @@ void WebEntityItem::setSourceUrl(const QString& value) { } } -const QString& WebEntityItem::getSourceUrl() const { return _sourceUrl; } \ No newline at end of file +const QString& WebEntityItem::getSourceUrl() const { return _sourceUrl; } diff --git a/libraries/entities/src/ZoneEntityItem.cpp b/libraries/entities/src/ZoneEntityItem.cpp index 6f44223892..871e9b8cdd 100644 --- a/libraries/entities/src/ZoneEntityItem.cpp +++ b/libraries/entities/src/ZoneEntityItem.cpp @@ -37,7 +37,6 @@ ZoneEntityItem::ZoneEntityItem(const EntityItemID& entityItemID, const EntityIte EntityItem(entityItemID) { _type = EntityTypes::Zone; - _created = properties.getCreated(); _keyLightColor[RED_INDEX] = DEFAULT_KEYLIGHT_COLOR.red; _keyLightColor[GREEN_INDEX] = DEFAULT_KEYLIGHT_COLOR.green; From 2441be21e29175518c41e056690cfad3131ec0aa Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Thu, 16 Jul 2015 20:58:34 -0700 Subject: [PATCH 10/27] restore order of setting properties --- libraries/entities/src/EntityItem.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 935ca77376..17dae38075 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -1072,8 +1072,6 @@ void EntityItem::getAllTerseUpdateProperties(EntityItemProperties& properties) c bool EntityItem::setProperties(const EntityItemProperties& properties) { bool somethingChanged = false; - // just in case _created must be properly set before the rest we do it first - SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); // these affect TerseUpdate properties SET_ENTITY_PROPERTY_FROM_PROPERTIES(simulationOwner, setSimulationOwner); @@ -1096,6 +1094,7 @@ bool EntityItem::setProperties(const EntityItemProperties& properties) { SET_ENTITY_PROPERTY_FROM_PROPERTIES(friction, updateFriction); SET_ENTITY_PROPERTY_FROM_PROPERTIES(ignoreForCollisions, updateIgnoreForCollisions); SET_ENTITY_PROPERTY_FROM_PROPERTIES(collisionsWillMove, updateCollisionsWillMove); + SET_ENTITY_PROPERTY_FROM_PROPERTIES(created, updateCreated); SET_ENTITY_PROPERTY_FROM_PROPERTIES(lifetime, updateLifetime); // non-simulation properties below From c46533d9a675613998346671f5b2a98507ec4190 Mon Sep 17 00:00:00 2001 From: David Rowe Date: Thu, 16 Jul 2015 21:05:14 -0700 Subject: [PATCH 11/27] Make renderGrid handle changing position and dimensions So that audio scope grid moves when Interface window is resized. --- libraries/render-utils/src/GeometryCache.cpp | 24 +++++++++++++------- libraries/render-utils/src/GeometryCache.h | 3 ++- 2 files changed, 18 insertions(+), 9 deletions(-) diff --git a/libraries/render-utils/src/GeometryCache.cpp b/libraries/render-utils/src/GeometryCache.cpp index 2bf41bc9b3..30ee7a2108 100644 --- a/libraries/render-utils/src/GeometryCache.cpp +++ b/libraries/render-utils/src/GeometryCache.cpp @@ -392,7 +392,6 @@ void GeometryCache::renderGrid(int x, int y, int width, int height, int rows, in gpu::GLBackend::renderBatch(batch); } -// TODO: properly handle the x,y,w,h changing for an ID // TODO: why do we seem to create extra BatchItemDetails when we resize the window?? what's that?? void GeometryCache::renderGrid(gpu::Batch& batch, int x, int y, int width, int height, int rows, int cols, const glm::vec4& color, int id) { #ifdef WANT_DEBUG @@ -410,8 +409,23 @@ void GeometryCache::renderGrid(gpu::Batch& batch, int x, int y, int width, int h Vec3Pair colorKey(glm::vec3(color.x, color.y, rows), glm::vec3(color.z, color.y, cols)); int vertices = (cols + 1 + rows + 1) * 2; - if ((registered && !_registeredAlternateGridBuffers.contains(id)) || (!registered && !_alternateGridBuffers.contains(key))) { + if ((registered && (!_registeredAlternateGridBuffers.contains(id) || _lastRegisteredAlternateGridBuffers[id] != key)) + || (!registered && !_alternateGridBuffers.contains(key))) { + + if (registered && _registeredAlternateGridBuffers.contains(id)) { + _registeredAlternateGridBuffers[id].reset(); + #ifdef WANT_DEBUG + qCDebug(renderutils) << "renderGrid()... RELEASING REGISTERED VERTICES BUFFER"; + #endif + } + gpu::BufferPointer verticesBuffer(new gpu::Buffer()); + if (registered) { + _registeredAlternateGridBuffers[id] = verticesBuffer; + _lastRegisteredAlternateGridBuffers[id] = key; + } else { + _alternateGridBuffers[key] = verticesBuffer; + } GLfloat* vertexData = new GLfloat[vertices * 2]; GLfloat* vertex = vertexData; @@ -443,12 +457,6 @@ void GeometryCache::renderGrid(gpu::Batch& batch, int x, int y, int width, int h verticesBuffer->append(sizeof(GLfloat) * vertices * 2, (gpu::Byte*) vertexData); delete[] vertexData; - - if (registered) { - _registeredAlternateGridBuffers[id] = verticesBuffer; - } else { - _alternateGridBuffers[key] = verticesBuffer; - } } if (!_gridColors.contains(colorKey)) { diff --git a/libraries/render-utils/src/GeometryCache.h b/libraries/render-utils/src/GeometryCache.h index 2e64489c3e..47490bca0d 100644 --- a/libraries/render-utils/src/GeometryCache.h +++ b/libraries/render-utils/src/GeometryCache.h @@ -337,8 +337,9 @@ private: QHash _registeredDashedLines; QHash _gridBuffers; - QHash _registeredAlternateGridBuffers; QHash _alternateGridBuffers; + QHash _registeredAlternateGridBuffers; + QHash _lastRegisteredAlternateGridBuffers; QHash _gridColors; QHash _sphereVertices; From 33464dfd6c5d27fdb22959da619c5c3caedadef3 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 17 Jul 2015 11:35:42 -0700 Subject: [PATCH 12/27] cleanup dead code --- interface/src/ui/ApplicationCompositor.cpp | 4 +- interface/src/ui/ApplicationOverlay.cpp | 81 +++++----------------- 2 files changed, 19 insertions(+), 66 deletions(-) diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index 56735111c1..d98ddf7d5a 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -210,10 +210,12 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { batch.setModelTransform(Transform()); batch.setViewTransform(Transform()); batch.setProjectionTransform(mat4()); + + // FIXME - Is this the proper technique for selecting the source 2D texture used by the renderUnitQuad??? + // And, how do we make sure we're getting the right blend/resampler? //batch._glBindTexture(GL_TEXTURE_2D, texture); //batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); //batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - batch.setResourceTexture(0, overlayFramebuffer->getRenderBuffer(0)); geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha)); diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index f2d00512ae..ea18867844 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -76,14 +76,16 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { AvatarInputs::getInstance()->update(); buildFramebufferObject(); + + if (!_overlayFramebuffer) { + return; // we can't do anything without our frame buffer. + } // Execute the batch into our framebuffer - gpu::Batch batch; renderArgs->_batch = &batch; // 1) bind the framebuffer - //_overlayFramebuffer->bind(); batch.setFramebuffer(_overlayFramebuffer); // 2) clear it... @@ -94,10 +96,9 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLORS | gpu::Framebuffer::BUFFER_DEPTH, color, depth, stencil); //batch.clearColorFramebuffer(_overlayFramebuffer->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); - int width = _overlayFramebuffer ? _overlayFramebuffer->getWidth() : 0; - int height = _overlayFramebuffer ? _overlayFramebuffer->getHeight() : 0; + int width = _overlayFramebuffer->getWidth(); + int height = _overlayFramebuffer->getHeight(); - //glViewport(0, 0, width, height); batch.setViewportTransform(glm::ivec4(0, 0, width, height)); // Now render the overlay components together into a single texture @@ -106,12 +107,11 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { renderDomainConnectionStatusBorder(renderArgs); // renders the connected domain line renderQmlUi(renderArgs); // renders a unit quad with the QML UI texture - //_overlayFramebuffer->release(); // now we're done for later composition - //batch.setFramebuffer(nullptr); - renderArgs->_context->syncCache(); renderArgs->_context->render(batch); + renderArgs->_batch = nullptr; // so future users of renderArgs don't try to use our batch + CHECK_GL_ERROR(); } @@ -128,9 +128,6 @@ void ApplicationOverlay::renderQmlUi(RenderArgs* renderArgs) { batch._glBindTexture(GL_TEXTURE_2D, _uiTexture); geometryCache->renderUnitQuad(batch, glm::vec4(1)); - - //renderArgs->_context->syncCache(); - //renderArgs->_context->render(batch); } } @@ -161,9 +158,6 @@ void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { int height = _overlayFramebuffer ? _overlayFramebuffer->getHeight() : 0; DependencyManager::get()->render(renderArgs, width, height); } - - //renderArgs->_context->syncCache(); - //renderArgs->_context->render(batch); } void ApplicationOverlay::renderRearViewToFbo(RenderArgs* renderArgs) { @@ -222,8 +216,6 @@ void ApplicationOverlay::renderDomainConnectionStatusBorder(RenderArgs* renderAr //batch.setModelTransform(glm::scale(mat4(), vec3(scaleAmount))); geometryCache->renderVertices(batch, gpu::LINE_STRIP, _domainStatusBorder); - //renderArgs->_context->syncCache(); - //renderArgs->_context->render(batch); } } @@ -252,61 +244,20 @@ void ApplicationOverlay::buildFramebufferObject() { auto width = desiredSize.width(); auto height = desiredSize.height(); + // NOTE: I need to make sure this gpu::Sampler is using these values... + // + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); + // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); + // glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); _overlayColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _overlayFramebuffer->setRenderBuffer(0, _overlayColorTexture); - auto depthFormat = gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::DEPTH); _overlayDepthTexture = gpu::TexturePointer(gpu::Texture::create2D(depthFormat, width, height, defaultSampler)); _overlayFramebuffer->setDepthStencilBuffer(_overlayDepthTexture, depthFormat); - - - /* - - // This code essentially created a frame buffer, then sets a bunch of the parameters for that texture. - _overlayFramebuffer = new QOpenGLFramebufferObject(fboSize, QOpenGLFramebufferObject::Depth); - - GLfloat borderColor[4] = { 0.0f, 0.0f, 0.0f, 0.0f }; - - gpu::Batch batch; - batch._glBindTexture(GL_TEXTURE_2D, getOverlayTexture()); - batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - batch._glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); - batch._glBindTexture(GL_TEXTURE_2D, 0); - */ - - /* - glBindTexture(GL_TEXTURE_2D, getOverlayTexture()); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); - glBindTexture(GL_TEXTURE_2D, 0); - */ - - - - /**** Example code... - batch._glBindTexture(GL_TEXTURE_2D, texture); - batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - - - // this stuff is what would actually render from the texture - - geometryCache->useSimpleDrawPipeline(batch); - batch.setViewportTransform(glm::ivec4(0, 0, deviceSize.width(), deviceSize.height())); - batch.setModelTransform(Transform()); - batch.setViewTransform(Transform()); - batch.setProjectionTransform(mat4()); - batch._glBindTexture(GL_TEXTURE_2D, texture); - geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha)); - ****/ - } From f09b3eb736243897dc6a07f9e7b2f077ca1d35b2 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 17 Jul 2015 12:14:07 -0700 Subject: [PATCH 13/27] set creation time when loading unknown timestamp --- libraries/entities/src/EntityTreeElement.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/libraries/entities/src/EntityTreeElement.cpp b/libraries/entities/src/EntityTreeElement.cpp index 41c0529b80..856550f297 100644 --- a/libraries/entities/src/EntityTreeElement.cpp +++ b/libraries/entities/src/EntityTreeElement.cpp @@ -772,6 +772,9 @@ int EntityTreeElement::readElementDataFromBuffer(const unsigned char* data, int entityItemID = entityItem->getEntityItemID(); _myTree->setContainingElement(entityItemID, this); _myTree->postAddEntity(entityItem); + if (entityItem->getCreated() == UNKNOWN_CREATED_TIME) { + entityItem->recordCreationTime(); + } } } // Move the buffer forward to read more entities From 1c7afbda04d2ff4032a6ffb73133c44c8be9bc5d Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 17 Jul 2015 12:14:53 -0700 Subject: [PATCH 14/27] workaround for bad sphere radius --- .../entities-renderer/src/RenderableSphereEntityItem.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp index 6d9cb525d6..ea25f748af 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp @@ -39,7 +39,15 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; +#define USE_MAGIC_WORKAROUND +#ifdef USE_MAGIC_WORKAROUND + // It's a mystery how this actually works! + Transform transform = getTransformToCenter(); + transform.setScale(transform.getScale()); + batch.setModelTransform(transform); // use a transform with scale, rotation, registration point and translation +#else // USE_MAGIC_WORKAROUND batch.setModelTransform(getTransformToCenter()); // use a transform with scale, rotation, registration point and translation +#endif // USE_MAGIC_WORKAROUND DependencyManager::get()->renderSolidSphere(batch, 0.5f, SLICES, STACKS, sphereColor); RenderableDebugableEntityItem::render(this, args); From c5e0298f8d07692fe940a5a75c4c4c5f8fc10658 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Fri, 17 Jul 2015 12:22:38 -0700 Subject: [PATCH 15/27] Working on mac sizing --- interface/resources/qml/TextOverlayElement.qml | 2 +- interface/src/ui/overlays/TextOverlay.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/resources/qml/TextOverlayElement.qml b/interface/resources/qml/TextOverlayElement.qml index 492a38ee0b..56309e5391 100644 --- a/interface/resources/qml/TextOverlayElement.qml +++ b/interface/resources/qml/TextOverlayElement.qml @@ -15,7 +15,7 @@ TextOverlayElement { text: root.text color: root.textColor font.family: root.fontFamily - font.pointSize: root.fontSize + font.pixelSize: root.fontSize } } } diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 32d94ec05b..e32b7804d9 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -165,7 +165,7 @@ void TextOverlay::setProperties(const QScriptValue& properties) { QScriptValue font = properties.property("font"); if (font.isObject()) { if (font.property("size").isValid()) { - setFontSize(font.property("size").toInt32() / 1.2); + setFontSize(font.property("size").toInt32()); } } From 4dadf60724c57bc60b411fcd23569da8edf55779 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 17 Jul 2015 12:50:20 -0700 Subject: [PATCH 16/27] some tweaks from Sam --- interface/src/ui/ApplicationOverlay.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index ea18867844..5d0e8cfa05 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -91,7 +91,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { // 2) clear it... //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glm::vec4 color { 0.0f, 0.0f, 0.0f, 0.0f }; - float depth = 0.0f; + float depth = 1.0f; int stencil = 0; batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLORS | gpu::Framebuffer::BUFFER_DEPTH, color, depth, stencil); //batch.clearColorFramebuffer(_overlayFramebuffer->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); @@ -252,7 +252,7 @@ void ApplicationOverlay::buildFramebufferObject() { // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); // glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_POINT); + auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); _overlayColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _overlayFramebuffer->setRenderBuffer(0, _overlayColorTexture); From 6f998e5d28a89f8dc6772e56b9063282a7290d8e Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 17 Jul 2015 13:32:31 -0700 Subject: [PATCH 17/27] Working on line spacing on mac --- interface/src/ui/overlays/TextOverlay.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index e32b7804d9..e33c18face 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -236,7 +236,11 @@ QSizeF TextOverlay::textSize(const QString& text) const { ++lines; } } +#ifdef Q_OS_MAC + QFontMetrics fm(QFont(SANS_FONT_FAMILY, _fontSize * 1.2)); +#else QFontMetrics fm(QFont(SANS_FONT_FAMILY, _fontSize)); +#endif QSizeF result = QSizeF(fm.width(text), fm.lineSpacing() * lines); return result; } From 24643ca282f2d4a9c88125b4d2a3c3fba1460cff Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Fri, 17 Jul 2015 14:19:39 -0700 Subject: [PATCH 18/27] Working on line spacing --- interface/resources/qml/TextOverlayElement.qml | 2 ++ interface/src/ui/overlays/TextOverlay.cpp | 6 ++---- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/TextOverlayElement.qml b/interface/resources/qml/TextOverlayElement.qml index 56309e5391..ac17468c07 100644 --- a/interface/resources/qml/TextOverlayElement.qml +++ b/interface/resources/qml/TextOverlayElement.qml @@ -16,6 +16,8 @@ TextOverlayElement { color: root.textColor font.family: root.fontFamily font.pixelSize: root.fontSize + lineHeightMode: Text.FixedHeight + lineHeight: root.fontSize * 1.2 } } } diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index e33c18face..5507ef38ac 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -236,12 +236,9 @@ QSizeF TextOverlay::textSize(const QString& text) const { ++lines; } } -#ifdef Q_OS_MAC - QFontMetrics fm(QFont(SANS_FONT_FAMILY, _fontSize * 1.2)); -#else QFontMetrics fm(QFont(SANS_FONT_FAMILY, _fontSize)); -#endif QSizeF result = QSizeF(fm.width(text), fm.lineSpacing() * lines); + result.rheight() *= 1.2; return result; } @@ -252,6 +249,7 @@ void TextOverlay::setFontSize(int fontSize) { void TextOverlay::setText(const QString& text) { _text = text; + qDebug() << text; _qmlElement->settext(text); } From 914b47069b34d2f116fa6df996fcb710f2110d74 Mon Sep 17 00:00:00 2001 From: Brad Davis Date: Fri, 17 Jul 2015 14:33:32 -0700 Subject: [PATCH 19/27] Working on line height --- interface/resources/qml/TextOverlayElement.qml | 2 +- interface/src/ui/overlays/TextOverlay.cpp | 13 ++++++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/interface/resources/qml/TextOverlayElement.qml b/interface/resources/qml/TextOverlayElement.qml index ac17468c07..0d9dd1eacc 100644 --- a/interface/resources/qml/TextOverlayElement.qml +++ b/interface/resources/qml/TextOverlayElement.qml @@ -17,7 +17,7 @@ TextOverlayElement { font.family: root.fontFamily font.pixelSize: root.fontSize lineHeightMode: Text.FixedHeight - lineHeight: root.fontSize * 1.2 + lineHeight: root.lineHeight } } } diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 5507ef38ac..4c8a0d36e4 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -47,6 +47,7 @@ private: TEXT_OVERLAY_PROPERTY(QString, textColor, "#ffffffff") TEXT_OVERLAY_PROPERTY(QString, backgroundColor, "#B2000000") TEXT_OVERLAY_PROPERTY(qreal, fontSize, 18) + TEXT_OVERLAY_PROPERTY(qreal, lineHeight, 18) TEXT_OVERLAY_PROPERTY(qreal, leftMargin, 0) TEXT_OVERLAY_PROPERTY(qreal, topMargin, 0) @@ -58,6 +59,7 @@ signals: void textChanged(); void fontFamilyChanged(); void fontSizeChanged(); + void lineHeightChanged(); void leftMarginChanged(); void topMarginChanged(); void textColorChanged(); @@ -167,6 +169,10 @@ void TextOverlay::setProperties(const QScriptValue& properties) { if (font.property("size").isValid()) { setFontSize(font.property("size").toInt32()); } + QFont font(_qmlElement->fontFamily()); + font.setPixelSize(_qmlElement->fontSize()); + QFontMetrics fm(font); + _qmlElement->setlineHeight(fm.lineSpacing() * 1.2); } QScriptValue text = properties.property("text"); @@ -236,9 +242,10 @@ QSizeF TextOverlay::textSize(const QString& text) const { ++lines; } } - QFontMetrics fm(QFont(SANS_FONT_FAMILY, _fontSize)); - QSizeF result = QSizeF(fm.width(text), fm.lineSpacing() * lines); - result.rheight() *= 1.2; + QFont font(_qmlElement->fontFamily()); + font.setPixelSize(_qmlElement->fontSize()); + QFontMetrics fm(font); + QSizeF result = QSizeF(fm.width(text), _qmlElement->lineHeight() * lines); return result; } From 3bfa8aae0baa8b3544f2f1ff8661e6b746285b06 Mon Sep 17 00:00:00 2001 From: Bradley Austin Davis Date: Fri, 17 Jul 2015 14:34:24 -0700 Subject: [PATCH 20/27] Removing debug output --- interface/src/ui/overlays/TextOverlay.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 4c8a0d36e4..597a630e3c 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -256,7 +256,6 @@ void TextOverlay::setFontSize(int fontSize) { void TextOverlay::setText(const QString& text) { _text = text; - qDebug() << text; _qmlElement->settext(text); } From 32b1fe0918f4755d5f5d6720d908f0bab0232029 Mon Sep 17 00:00:00 2001 From: Andrew Meadows Date: Fri, 17 Jul 2015 15:21:02 -0700 Subject: [PATCH 21/27] proper fix for incorrect render of scaled entities --- .../entities-renderer/src/RenderableSphereEntityItem.cpp | 8 -------- libraries/entities/src/EntityItem.cpp | 8 +++++--- 2 files changed, 5 insertions(+), 11 deletions(-) diff --git a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp index ea25f748af..6d9cb525d6 100644 --- a/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp +++ b/libraries/entities-renderer/src/RenderableSphereEntityItem.cpp @@ -39,15 +39,7 @@ void RenderableSphereEntityItem::render(RenderArgs* args) { Q_ASSERT(args->_batch); gpu::Batch& batch = *args->_batch; -#define USE_MAGIC_WORKAROUND -#ifdef USE_MAGIC_WORKAROUND - // It's a mystery how this actually works! - Transform transform = getTransformToCenter(); - transform.setScale(transform.getScale()); - batch.setModelTransform(transform); // use a transform with scale, rotation, registration point and translation -#else // USE_MAGIC_WORKAROUND batch.setModelTransform(getTransformToCenter()); // use a transform with scale, rotation, registration point and translation -#endif // USE_MAGIC_WORKAROUND DependencyManager::get()->renderSolidSphere(batch, 0.5f, SLICES, STACKS, sphereColor); RenderableDebugableEntityItem::render(this, args); diff --git a/libraries/entities/src/EntityItem.cpp b/libraries/entities/src/EntityItem.cpp index 17dae38075..9dec62b0c0 100644 --- a/libraries/entities/src/EntityItem.cpp +++ b/libraries/entities/src/EntityItem.cpp @@ -45,9 +45,7 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _lastEditedFromRemoteInRemoteTime(0), _created(UNKNOWN_CREATED_TIME), _changedOnServer(0), - _transform(ENTITY_ITEM_DEFAULT_ROTATION, - ENTITY_ITEM_DEFAULT_DIMENSIONS, - ENTITY_ITEM_DEFAULT_POSITION), + _transform(), _glowLevel(ENTITY_ITEM_DEFAULT_GLOW_LEVEL), _localRenderAlpha(ENTITY_ITEM_DEFAULT_LOCAL_RENDER_ALPHA), _density(ENTITY_ITEM_DEFAULT_DENSITY), @@ -80,6 +78,10 @@ EntityItem::EntityItem(const EntityItemID& entityItemID) : _physicsInfo(nullptr), _simulated(false) { + // explicitly set transform parts to set dirty flags used by batch rendering + _transform.setTranslation(ENTITY_ITEM_DEFAULT_POSITION); + _transform.setRotation(ENTITY_ITEM_DEFAULT_ROTATION); + _transform.setScale(ENTITY_ITEM_DEFAULT_DIMENSIONS); quint64 now = usecTimestampNow(); _lastSimulated = now; _lastUpdated = now; From ccd2f98a76db96ffd53e02786ad80e181efec0fa Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 17 Jul 2015 15:28:25 -0700 Subject: [PATCH 22/27] one more try --- interface/src/ui/ApplicationOverlay.cpp | 13 ++++++------- libraries/gpu/src/gpu/GLBackend.cpp | 2 +- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 5d0e8cfa05..2cf7c508ec 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -85,6 +85,11 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { gpu::Batch batch; renderArgs->_batch = &batch; + int width = _overlayFramebuffer->getWidth(); + int height = _overlayFramebuffer->getHeight(); + + batch.setViewportTransform(glm::ivec4(0, 0, width, height)); + // 1) bind the framebuffer batch.setFramebuffer(_overlayFramebuffer); @@ -93,13 +98,7 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { glm::vec4 color { 0.0f, 0.0f, 0.0f, 0.0f }; float depth = 1.0f; int stencil = 0; - batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLORS | gpu::Framebuffer::BUFFER_DEPTH, color, depth, stencil); - //batch.clearColorFramebuffer(_overlayFramebuffer->getBufferMask(), glm::vec4(0.0f, 0.0f, 0.0f, 0.0f)); - - int width = _overlayFramebuffer->getWidth(); - int height = _overlayFramebuffer->getHeight(); - - batch.setViewportTransform(glm::ivec4(0, 0, width, height)); + batch.clearFramebuffer(gpu::Framebuffer::BUFFER_COLOR0 | gpu::Framebuffer::BUFFER_DEPTH, color, depth, stencil); // Now render the overlay components together into a single texture renderOverlays(renderArgs); // renders Scripts Overlay and AudioScope diff --git a/libraries/gpu/src/gpu/GLBackend.cpp b/libraries/gpu/src/gpu/GLBackend.cpp index adbef7cb31..b14f9afc97 100644 --- a/libraries/gpu/src/gpu/GLBackend.cpp +++ b/libraries/gpu/src/gpu/GLBackend.cpp @@ -227,7 +227,7 @@ void GLBackend::do_clearFramebuffer(Batch& batch, uint32 paramOffset) { int stencil = batch._params[paramOffset + 0]._float; GLuint glmask = 0; - if (masks & Framebuffer::BUFFER_DEPTH) { + if (masks & Framebuffer::BUFFER_STENCIL) { glClearStencil(stencil); glmask |= GL_STENCIL_BUFFER_BIT; } From 03a44a1c80cf7e816201f02944d3a585dd3b295e Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 17 Jul 2015 15:45:42 -0700 Subject: [PATCH 23/27] fix retina --- interface/src/Application.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index d815329602..b3270332f4 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -898,8 +898,8 @@ void Application::paintGL() { // NOTE: the ApplicationOverlay class assumes it's viewport is setup to be the device size // There is no batch associated with this renderArgs - QSize size = qApp->getDeviceSize(); - renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); + glm::vec2 size = getCanvasSize(); + renderArgs._viewport = glm::ivec4(0, 0, size.x, size.y); _applicationOverlay.renderOverlay(&renderArgs); } From c20c6e4b90081b4b36310e830fcb3789678ce2af Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 17 Jul 2015 16:01:32 -0700 Subject: [PATCH 24/27] fix retina in an Austin approved manner --- interface/src/Application.cpp | 5 +---- interface/src/ui/overlays/Overlays.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index b3270332f4..002ba68a86 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -896,10 +896,7 @@ void Application::paintGL() { { PerformanceTimer perfTimer("renderOverlay"); - // NOTE: the ApplicationOverlay class assumes it's viewport is setup to be the device size - // There is no batch associated with this renderArgs - glm::vec2 size = getCanvasSize(); - renderArgs._viewport = glm::ivec4(0, 0, size.x, size.y); + // NOTE: There is no batch associated with this renderArgs _applicationOverlay.renderOverlay(&renderArgs); } diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 343e571bfe..0d40c60ca4 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -102,8 +102,10 @@ void Overlays::renderHUD(RenderArgs* renderArgs) { auto geometryCache = DependencyManager::get(); auto textureCache = DependencyManager::get(); - int width = renderArgs->_viewport.z; - int height = renderArgs->_viewport.w; + + auto size = qApp->getCanvasSize(); + int width = size.x; + int height = size.y; mat4 legacyProjection = glm::ortho(0, width, height, 0, -1000, 1000); From 8692f51399ca69cbb0302509c14c10359b4b4e82 Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 17 Jul 2015 16:15:02 -0700 Subject: [PATCH 25/27] dead code cleanup --- interface/src/Application.cpp | 3 +++ interface/src/ui/ApplicationCompositor.cpp | 12 ------------ interface/src/ui/ApplicationOverlay.cpp | 12 ------------ interface/src/ui/overlays/Overlays.cpp | 3 --- 4 files changed, 3 insertions(+), 27 deletions(-) diff --git a/interface/src/Application.cpp b/interface/src/Application.cpp index 002ba68a86..d36392d61d 100644 --- a/interface/src/Application.cpp +++ b/interface/src/Application.cpp @@ -897,6 +897,9 @@ void Application::paintGL() { PerformanceTimer perfTimer("renderOverlay"); // NOTE: There is no batch associated with this renderArgs + // the ApplicationOverlay class assumes it's viewport is setup to be the device size + QSize size = qApp->getDeviceSize(); + renderArgs._viewport = glm::ivec4(0, 0, size.width(), size.height()); _applicationOverlay.renderOverlay(&renderArgs); } diff --git a/interface/src/ui/ApplicationCompositor.cpp b/interface/src/ui/ApplicationCompositor.cpp index d98ddf7d5a..cd28ca0732 100644 --- a/interface/src/ui/ApplicationCompositor.cpp +++ b/interface/src/ui/ApplicationCompositor.cpp @@ -189,7 +189,6 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { return; } - //GLuint texture = 0; // FIXME -- qApp->getApplicationOverlay().getOverlayTexture(); gpu::FramebufferPointer overlayFramebuffer = qApp->getApplicationOverlay().getOverlayFramebuffer(); if (!overlayFramebuffer) { return; @@ -210,14 +209,7 @@ void ApplicationCompositor::displayOverlayTexture(RenderArgs* renderArgs) { batch.setModelTransform(Transform()); batch.setViewTransform(Transform()); batch.setProjectionTransform(mat4()); - - // FIXME - Is this the proper technique for selecting the source 2D texture used by the renderUnitQuad??? - // And, how do we make sure we're getting the right blend/resampler? - //batch._glBindTexture(GL_TEXTURE_2D, texture); - //batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - //batch._glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); batch.setResourceTexture(0, overlayFramebuffer->getRenderBuffer(0)); - geometryCache->renderUnitQuad(batch, vec4(vec3(1), _alpha)); // Doesn't actually render @@ -264,10 +256,6 @@ void ApplicationCompositor::displayOverlayTextureHmd(RenderArgs* renderArgs, int return; } - //GLuint texture = 0; // FIXME -- qApp->getApplicationOverlay().getOverlayTexture(); - //if (!texture) { - // return; - //} gpu::FramebufferPointer overlayFramebuffer = qApp->getApplicationOverlay().getOverlayFramebuffer(); if (!overlayFramebuffer) { return; diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index 2cf7c508ec..afcccc4776 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -89,12 +89,8 @@ void ApplicationOverlay::renderOverlay(RenderArgs* renderArgs) { int height = _overlayFramebuffer->getHeight(); batch.setViewportTransform(glm::ivec4(0, 0, width, height)); - - // 1) bind the framebuffer batch.setFramebuffer(_overlayFramebuffer); - // 2) clear it... - //glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glm::vec4 color { 0.0f, 0.0f, 0.0f, 0.0f }; float depth = 1.0f; int stencil = 0; @@ -243,14 +239,6 @@ void ApplicationOverlay::buildFramebufferObject() { auto width = desiredSize.width(); auto height = desiredSize.height(); - // NOTE: I need to make sure this gpu::Sampler is using these values... - // - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_BORDER); - // glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_BORDER); - // glTexParameterfv(GL_TEXTURE_2D, GL_TEXTURE_BORDER_COLOR, borderColor); - auto defaultSampler = gpu::Sampler(gpu::Sampler::FILTER_MIN_MAG_LINEAR); _overlayColorTexture = gpu::TexturePointer(gpu::Texture::create2D(colorFormat, width, height, defaultSampler)); _overlayFramebuffer->setRenderBuffer(0, _overlayColorTexture); diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index 0d40c60ca4..e801de4484 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -121,9 +121,6 @@ void Overlays::renderHUD(RenderArgs* renderArgs) { thisOverlay->render(renderArgs); } - - //renderArgs->_context->syncCache(); - //renderArgs->_context->render(batch); } unsigned int Overlays::addOverlay(const QString& type, const QScriptValue& properties) { From 695470b1c1bf7ba7a1ebd7ab0d7812841ab1fd5f Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 17 Jul 2015 16:30:10 -0700 Subject: [PATCH 26/27] fix audio scope --- interface/src/audio/AudioScope.cpp | 7 ++++--- interface/src/ui/ApplicationOverlay.cpp | 9 +++++---- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/interface/src/audio/AudioScope.cpp b/interface/src/audio/AudioScope.cpp index d9ceb82eef..75a5137ca4 100644 --- a/interface/src/audio/AudioScope.cpp +++ b/interface/src/audio/AudioScope.cpp @@ -127,11 +127,14 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) { int w = (int)SCOPE_WIDTH; int h = (int)SCOPE_HEIGHT; - gpu::Batch batch; + gpu::Batch& batch = *renderArgs->_batch; auto geometryCache = DependencyManager::get(); geometryCache->useSimpleDrawPipeline(batch); auto textureCache = DependencyManager::get(); batch.setResourceTexture(0, textureCache->getWhiteTexture()); + + // FIXME - do we really need to reset this here? we know that we're called inside of ApplicationOverlay::renderOverlays + // which already set up our batch for us to have these settings mat4 legacyProjection = glm::ortho(0, width, height, 0, -1000, 1000); batch.setProjectionTransform(legacyProjection); batch.setModelTransform(Transform()); @@ -142,8 +145,6 @@ void AudioScope::render(RenderArgs* renderArgs, int width, int height) { renderLineStrip(batch, _inputID, inputColor, x, y, _samplesPerScope, _scopeInputOffset, _scopeInput); renderLineStrip(batch, _outputLeftID, outputLeftColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputLeft); renderLineStrip(batch, _outputRightD, outputRightColor, x, y, _samplesPerScope, _scopeOutputOffset, _scopeOutputRight); - renderArgs->_context->syncCache(); - renderArgs->_context->render(batch); } void AudioScope::renderLineStrip(gpu::Batch& batch, int id, const glm::vec4& color, int x, int y, int n, int offset, const QByteArray* byteArray) { diff --git a/interface/src/ui/ApplicationOverlay.cpp b/interface/src/ui/ApplicationOverlay.cpp index afcccc4776..f455b1dc62 100644 --- a/interface/src/ui/ApplicationOverlay.cpp +++ b/interface/src/ui/ApplicationOverlay.cpp @@ -143,15 +143,16 @@ void ApplicationOverlay::renderOverlays(RenderArgs* renderArgs) { batch._glLineWidth(1.0f); // default { + // Render the audio scope + //int width = _overlayFramebuffer ? _overlayFramebuffer->getWidth() : 0; + //int height = _overlayFramebuffer ? _overlayFramebuffer->getHeight() : 0; + DependencyManager::get()->render(renderArgs, width, height); + // Render all of the Script based "HUD" aka 2D overlays. // note: we call them HUD, as opposed to 2D, only because there are some cases of 3D HUD overlays, like the // cameral controls for the edit.js qApp->getOverlays().renderHUD(renderArgs); - // Render the audio scope - int width = _overlayFramebuffer ? _overlayFramebuffer->getWidth() : 0; - int height = _overlayFramebuffer ? _overlayFramebuffer->getHeight() : 0; - DependencyManager::get()->render(renderArgs, width, height); } } From eb989fd7250d690f1c92c821416c230d4f6a696a Mon Sep 17 00:00:00 2001 From: ZappoMan Date: Fri, 17 Jul 2015 16:38:05 -0700 Subject: [PATCH 27/27] fix the backround colors for text overlays, pending austins PR to really fix them --- interface/src/ui/overlays/Overlays.cpp | 2 +- interface/src/ui/overlays/TextOverlay.cpp | 8 +++++++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/interface/src/ui/overlays/Overlays.cpp b/interface/src/ui/overlays/Overlays.cpp index e801de4484..63b87a30ae 100644 --- a/interface/src/ui/overlays/Overlays.cpp +++ b/interface/src/ui/overlays/Overlays.cpp @@ -113,7 +113,7 @@ void Overlays::renderHUD(RenderArgs* renderArgs) { // Reset all batch pipeline settings between overlay geometryCache->useSimpleDrawPipeline(batch); - batch.setResourceTexture(0, textureCache->getWhiteTexture()); + batch.setResourceTexture(0, textureCache->getWhiteTexture()); // FIXME - do we really need to do this?? batch.setProjectionTransform(legacyProjection); batch.setModelTransform(Transform()); batch.setViewTransform(Transform()); diff --git a/interface/src/ui/overlays/TextOverlay.cpp b/interface/src/ui/overlays/TextOverlay.cpp index 3f033d9266..a2f0f13e82 100644 --- a/interface/src/ui/overlays/TextOverlay.cpp +++ b/interface/src/ui/overlays/TextOverlay.cpp @@ -71,6 +71,12 @@ void TextOverlay::render(RenderArgs* args) { return; // do nothing if we're not visible } + if (!args->_batch) { + return; // do nothing if the batch is not valid + } + + gpu::Batch& batch = *args->_batch; + const float MAX_COLOR = 255.0f; xColor backgroundColor = getBackgroundColor(); glm::vec4 quadColor(backgroundColor.red / MAX_COLOR, backgroundColor.green / MAX_COLOR, backgroundColor.blue / MAX_COLOR, @@ -84,7 +90,7 @@ void TextOverlay::render(RenderArgs* args) { glm::vec2 topLeft(left, top); glm::vec2 bottomRight(right, bottom); glBindTexture(GL_TEXTURE_2D, 0); - DependencyManager::get()->renderQuad(topLeft, bottomRight, quadColor); + DependencyManager::get()->renderQuad(batch, topLeft, bottomRight, quadColor); const int leftAdjust = -1; // required to make text render relative to left edge of bounds const int topAdjust = -2; // required to make text render relative to top edge of bounds