mirror of
https://github.com/overte-org/overte.git
synced 2025-04-09 21:23:49 +02:00
Merge pull request #1395 from HifiExperiments/tofu
show tofu character on missing character
This commit is contained in:
commit
22122acab5
6 changed files with 45 additions and 14 deletions
|
@ -48,7 +48,9 @@ layout(location=RENDER_UTILS_ATTR_NORMAL_WS) in vec3 _normalWS;
|
|||
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) in vec4 _texCoord01;
|
||||
#define _texCoord0 _texCoord01.xy
|
||||
#define _texCoord1 _texCoord01.zw
|
||||
layout(location=RENDER_UTILS_ATTR_FADE1) flat in vec4 _glyphBounds; // we're reusing the fade texcoord locations here
|
||||
// we're reusing the fade texcoord locations here:
|
||||
layout(location=RENDER_UTILS_ATTR_FADE1) flat in vec4 _glyphBounds;
|
||||
layout(location=RENDER_UTILS_ATTR_FADE2) flat in float _isTofu;
|
||||
|
||||
<@if HIFI_USE_MIRROR@>
|
||||
<@include graphics/ShaderConstants.h@>
|
||||
|
@ -57,7 +59,7 @@ layout(location=RENDER_UTILS_ATTR_FADE1) flat in vec4 _glyphBounds; // we're reu
|
|||
<@endif@>
|
||||
|
||||
void main() {
|
||||
vec4 color = evalSDFSuperSampled(_texCoord0, _positionMS, _glyphBounds);
|
||||
vec4 color = evalSDFSuperSampled(_texCoord0, _positionMS, _glyphBounds, _isTofu);
|
||||
|
||||
<@if HIFI_USE_TRANSLUCENT or HIFI_USE_FORWARD@>
|
||||
color.a *= params.color.a;
|
||||
|
|
|
@ -60,8 +60,14 @@ vec2 evalSDF(vec2 texCoord) {
|
|||
return vec2(opacity, msdf.a);
|
||||
}
|
||||
|
||||
vec4 evalSDFColor(vec2 texCoord, vec4 glyphBounds) {
|
||||
vec4 evalSDFColor(vec2 texCoord, vec4 glyphBounds, float isTofu) {
|
||||
vec3 color = params.color.rgb;
|
||||
|
||||
if (isTofu > 0.0f) {
|
||||
const float OUTLINE_WIDTH = 0.1;
|
||||
return vec4(color, any(greaterThan(abs(texCoord - vec2(0.5)), vec2(0.5 - OUTLINE_WIDTH, 0.5 - (glyphBounds.z / glyphBounds.w) * OUTLINE_WIDTH))));
|
||||
}
|
||||
|
||||
vec2 sdf = evalSDF(texCoord);
|
||||
|
||||
// Outline
|
||||
|
@ -95,14 +101,14 @@ vec4 evalSDFColor(vec2 texCoord, vec4 glyphBounds) {
|
|||
return vec4(color, sdf.x);
|
||||
}
|
||||
|
||||
vec4 evalSDFSuperSampled(vec2 texCoord, vec2 positionMS, vec4 glyphBounds) {
|
||||
vec4 evalSDFSuperSampled(vec2 texCoord, vec2 positionMS, vec4 glyphBounds, float isTofu) {
|
||||
// Clip to edges. Note: We don't need to check the top edge.
|
||||
if ((params.bounds.z > 0.0 && (positionMS.x < params.bounds.x || positionMS.x > (params.bounds.x + params.bounds.z))) ||
|
||||
(params.bounds.w > 0.0 && (positionMS.y < params.bounds.y - params.bounds.w))) {
|
||||
return vec4(0.0);
|
||||
}
|
||||
|
||||
vec4 color = evalSDFColor(texCoord, glyphBounds);
|
||||
vec4 color = evalSDFColor(texCoord, glyphBounds, isTofu);
|
||||
|
||||
// Rely on TAA for anti-aliasing but smooth transition when minification
|
||||
// to help filtering
|
||||
|
|
|
@ -30,12 +30,15 @@ layout(location=RENDER_UTILS_ATTR_POSITION_MS) out vec2 _positionMS;
|
|||
<@endif@>
|
||||
layout(location=RENDER_UTILS_ATTR_NORMAL_WS) out vec3 _normalWS;
|
||||
layout(location=RENDER_UTILS_ATTR_TEXCOORD01) out vec4 _texCoord01;
|
||||
layout(location=RENDER_UTILS_ATTR_FADE1) flat out vec4 _glyphBounds; // we're reusing the fade texcoord locations here
|
||||
// we're reusing the fade texcoord locations here:
|
||||
layout(location=RENDER_UTILS_ATTR_FADE1) flat out vec4 _glyphBounds;
|
||||
layout(location=RENDER_UTILS_ATTR_FADE2) flat out float _isTofu;
|
||||
|
||||
void main() {
|
||||
_positionMS = inPosition.xy;
|
||||
_texCoord01 = vec4(inTexCoord0.st, 0.0, 0.0);
|
||||
_glyphBounds = inTexCoord1;
|
||||
_isTofu = inTexCoord2.x;
|
||||
|
||||
vec4 position = inPosition;
|
||||
// if we're in shadow mode, we need to move each subsequent quad slightly forward so it doesn't z-fight
|
||||
|
|
|
@ -40,8 +40,9 @@ struct TextureVertex {
|
|||
glm::vec2 pos;
|
||||
glm::vec2 tex;
|
||||
glm::vec4 bounds;
|
||||
float isTofu;
|
||||
TextureVertex() {}
|
||||
TextureVertex(const glm::vec2& pos, const glm::vec2& tex, const glm::vec4& bounds) : pos(pos), tex(tex), bounds(bounds) {}
|
||||
TextureVertex(const glm::vec2& pos, const glm::vec2& tex, const glm::vec4& bounds, bool isTofu) : pos(pos), tex(tex), bounds(bounds), isTofu(isTofu ? 1.0f : 0.0f) {}
|
||||
};
|
||||
|
||||
static const int NUMBER_OF_INDICES_PER_QUAD = 6; // 1 quad = 2 triangles
|
||||
|
@ -71,13 +72,13 @@ struct QuadBuilder {
|
|||
|
||||
// min = bottomLeft
|
||||
vertices[0] = TextureVertex(min,
|
||||
texMin + glm::vec2(0.0f, texSize.y), bounds);
|
||||
texMin + glm::vec2(0.0f, texSize.y), bounds, glyph.isTofu);
|
||||
vertices[1] = TextureVertex(min + glm::vec2(size.x, 0.0f),
|
||||
texMin + texSize, bounds);
|
||||
texMin + texSize, bounds, glyph.isTofu);
|
||||
vertices[2] = TextureVertex(min + glm::vec2(0.0f, size.y),
|
||||
texMin, bounds);
|
||||
texMin, bounds, glyph.isTofu);
|
||||
vertices[3] = TextureVertex(min + size,
|
||||
texMin + glm::vec2(texSize.x, 0.0f), bounds);
|
||||
texMin + glm::vec2(texSize.x, 0.0f), bounds, glyph.isTofu);
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -129,7 +130,8 @@ void Font::read(QIODevice& in) {
|
|||
}
|
||||
|
||||
_distanceRange = glm::vec2(arteryFont.variants[0].metrics.distanceRange);
|
||||
_fontHeight = arteryFont.variants[0].metrics.ascender + fabs(arteryFont.variants[0].metrics.descender);
|
||||
const float ascent = arteryFont.variants[0].metrics.ascender;
|
||||
_fontHeight = ascent + fabs(arteryFont.variants[0].metrics.descender);
|
||||
_leading = arteryFont.variants[0].metrics.lineHeight;
|
||||
_spaceWidth = 0.5f * arteryFont.variants[0].metrics.emSize; // We use half the emSize as a first guess for _spaceWidth
|
||||
|
||||
|
@ -193,6 +195,7 @@ void Font::read(QIODevice& in) {
|
|||
_glyphs.clear();
|
||||
glm::vec2 imageSize = toGlm(image.size());
|
||||
_distanceRange /= imageSize;
|
||||
bool hasTofu = false;
|
||||
foreach(Glyph g, glyphs) {
|
||||
// Adjust the pixel texture coordinates into UV coordinates,
|
||||
g.texSize /= imageSize;
|
||||
|
@ -202,8 +205,21 @@ void Font::read(QIODevice& in) {
|
|||
g.offset.y = -(1.0f - (g.offset.y + g.size.y));
|
||||
// store in the character to glyph hash
|
||||
_glyphs[g.c] = g;
|
||||
if (g.c == '?') {
|
||||
_tofuGlyph = g;
|
||||
hasTofu = true;
|
||||
}
|
||||
};
|
||||
|
||||
_tofuGlyph.texSize = glm::vec2(1.0f);
|
||||
_tofuGlyph.texOffset = glm::vec2(0.0f);
|
||||
if (!hasTofu) {
|
||||
_tofuGlyph.size = glm::vec2(2.0f * _spaceWidth, ascent);
|
||||
_tofuGlyph.offset = glm::vec2(0.0f, -(1.0f - ascent));
|
||||
_tofuGlyph.d = 2.0f * _spaceWidth;
|
||||
}
|
||||
_tofuGlyph.isTofu = true;
|
||||
|
||||
image = image.convertToFormat(QImage::Format_RGBA8888);
|
||||
|
||||
gpu::Element formatGPU = gpu::Element(gpu::VEC3, gpu::NUINT8, gpu::RGB);
|
||||
|
@ -283,7 +299,7 @@ Font::Font(const QString& family) : _family(family) {
|
|||
// 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 _tofuGlyph;
|
||||
}
|
||||
return _glyphs[c];
|
||||
}
|
||||
|
@ -360,6 +376,7 @@ void Font::setupGPU() {
|
|||
// Sanity checks
|
||||
static const int TEX_COORD_OFFSET = offsetof(TextureVertex, tex);
|
||||
static const int TEX_BOUNDS_OFFSET = offsetof(TextureVertex, bounds);
|
||||
static const int TOFU_OFFSET = offsetof(TextureVertex, isTofu);
|
||||
assert(TEX_COORD_OFFSET == sizeof(glm::vec2));
|
||||
assert(sizeof(TextureVertex) == 2 * sizeof(glm::vec2) + sizeof(glm::vec4));
|
||||
assert(sizeof(QuadBuilder) == 4 * sizeof(TextureVertex));
|
||||
|
@ -369,6 +386,7 @@ void Font::setupGPU() {
|
|||
_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), TEX_COORD_OFFSET);
|
||||
_format->setAttribute(gpu::Stream::TEXCOORD1, 0, gpu::Element(gpu::VEC4, gpu::FLOAT, gpu::XYZW), TEX_BOUNDS_OFFSET);
|
||||
_format->setAttribute(gpu::Stream::TEXCOORD2, 0, gpu::Element(gpu::SCALAR, gpu::FLOAT, gpu::RED), TOFU_OFFSET);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -441,7 +459,7 @@ void Font::buildVertices(Font::DrawInfo& drawInfo, const QString& str, const glm
|
|||
if (bounds.x != -1 && advance.x > rightEdge) {
|
||||
break;
|
||||
}
|
||||
const Glyph& glyph = _glyphs[c];
|
||||
const Glyph& glyph = getGlyph(c);
|
||||
|
||||
glyphsAndCorners.emplace_back(glyph, advance);
|
||||
|
||||
|
|
|
@ -117,6 +117,7 @@ private:
|
|||
// we declare the hash as mutable in order to avoid such
|
||||
// copies
|
||||
mutable QHash<QChar, Glyph> _glyphs;
|
||||
Glyph _tofuGlyph;
|
||||
|
||||
// Font characteristics
|
||||
QString _family;
|
||||
|
|
|
@ -26,6 +26,7 @@ struct Glyph {
|
|||
vec2 size;
|
||||
vec2 offset;
|
||||
float d; // xadvance - adjusts character positioning
|
||||
bool isTofu { false };
|
||||
|
||||
// We adjust bounds because offset is the bottom left corner of the font but the top left corner of a QRect
|
||||
QRectF bounds() const;
|
||||
|
|
Loading…
Reference in a new issue