Ion
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Pages
outlinebuilder.cc
Go to the documentation of this file.
1 
19 
20 #include "ion/base/datacontainer.h"
21 #include "ion/base/invalid.h"
22 #include "ion/base/logging.h"
24 #include "ion/gfx/attribute.h"
25 #include "ion/gfx/attributearray.h"
26 #include "ion/gfx/bufferobject.h"
28 #include "ion/gfx/texture.h"
29 #include "ion/gfx/uniform.h"
31 #include "ion/math/vector.h"
32 #include "ion/text/font.h"
33 #include "ion/text/fontimage.h"
34 #include "ion/text/layout.h"
35 
36 
37 namespace ion {
38 namespace text {
39 
40 namespace {
41 
43 
66 
67 
68 static const char* kVertexShaderSource =
69  "uniform ivec2 uViewportSize;\n"
70  "uniform mat4 uProjectionMatrix;\n"
71  "uniform mat4 uModelviewMatrix;\n"
72  "attribute vec3 aVertex;\n"
73  "attribute vec3 aFontPixelVec;\n"
74  "attribute vec2 aTexCoords;\n"
75  "varying vec2 vTexCoords;\n"
76  "varying vec2 vFontPixelSize;\n"
77  "\n"
78  "void main(void) {\n"
79  " vTexCoords = aTexCoords;\n"
80  " mat4 pmv = uProjectionMatrix * uModelviewMatrix;\n"
81  " vec4 v0 = pmv * vec4(aVertex, 1.0);\n"
82  " vec4 v1 = pmv * vec4(aVertex + aFontPixelVec, 1.0);\n"
83  " gl_Position = v0;\n"
84  " // Compute the size of a font pixel in screen pixels in X and Y.\n"
85  " vec4 v = (v1 / v1.w) - (v0 / v0.w);\n"
86  " vFontPixelSize = vec2(abs(v.x * float(uViewportSize.x)),\n"
87  " abs(v.y * float(uViewportSize.y)));\n"
88  "}\n";
89 
90 static const char* kFragmentShaderSource =
91  "#ifdef GL_ES\n"
92  "#ifdef GL_FRAGMENT_PRECISION_HIGH\n"
93  "precision highp float;\n"
94  "#else\n"
95  "precision mediump float;\n"
96  "#endif\n"
97  "#endif\n"
98  "uniform sampler2D uSdfSampler;\n"
99  "uniform float uSdfPadding;\n"
100  "uniform vec4 uTextColor;\n"
101  "uniform vec4 uOutlineColor;\n"
102  "uniform float uHalfSmoothWidth;\n"
103  "uniform float uOutlineWidth;\n"
104  "varying vec2 vTexCoords;\n"
105  "varying vec2 vFontPixelSize;\n"
106  "\n"
107  "void main(void) {\n"
108  " float half_smooth_width = uHalfSmoothWidth;\n"
109  " float outline_width = uOutlineWidth;\n"
110  "\n"
111  " // Get the signed distance from the edge in font pixels, centered at\n"
112  " // 0, then convert to screen pixels.\n"
113  " float sdf = texture2D(uSdfSampler, vTexCoords).r;\n"
114  " float dist = uSdfPadding * 2.0 * (sdf - 0.5);\n"
115  " float pixel_scale = mix(vFontPixelSize.x, vFontPixelSize.y, 0.5);\n"
116  " dist *= pixel_scale;\n"
117  "\n"
118  " // Ensure the outline blending does not exceed the maximum distance.\n"
119  " float max_dist = uSdfPadding * pixel_scale;\n"
120  " outline_width = min(outline_width, max_dist - half_smooth_width);\n"
121  "\n"
122  " // Discard fragments completely outside the smoothed outline.\n"
123  " if (dist >= outline_width + half_smooth_width) {\n"
124  " discard;\n"
125  " } else {\n"
126  " vec4 color;\n"
127  " // Set to blended outline color.\n"
128  " float outline_min = outline_width - half_smooth_width;\n"
129  " float outline_max = outline_width + half_smooth_width;\n"
130  " float d1 = smoothstep(outline_min, outline_max, dist);\n"
131  " color = (1.0 - smoothstep(outline_min, outline_max, dist)) *\n"
132  " uOutlineColor;\n"
133  "\n"
134  " // Blend in text color.\n"
135  " float interior_bias = 0.2;\n"
136  " float interior_min = -half_smooth_width + interior_bias;\n"
137  " float interior_max = half_smooth_width + interior_bias;\n"
138  " float d2 = smoothstep(interior_min, interior_max, dist);\n"
139  " color = mix(uTextColor, color,\n"
140  " smoothstep(interior_min, interior_max, dist));\n"
141  " gl_FragColor = vec4(color.rgb * color.a, color.a);\n"
142  " }\n"
143  "}\n";
144 
146 
151 
152 
157 static const math::Vector3f ComputeFontPixelVec(
158  const Font& font, const Layout& layout, size_t glyph_index) {
159  const Layout::Glyph& glyph = layout.GetGlyph(glyph_index);
160  const Font::GlyphGrid& grid = font.GetGlyphGrid(glyph.glyph_index);
161  math::Vector3f vec(math::Vector3f::Zero());
162  if (!base::IsInvalidReference(grid)) {
163  const size_t width = grid.pixels.GetWidth();
164  const size_t height = grid.pixels.GetHeight();
165  if (width && height) {
166  const float inv_width = 1.0f / static_cast<float>(width);
167  const float inv_height = 1.0f / static_cast<float>(height);
168  const math::Point3f& lower_left = glyph.quad.points[0];
169  const math::Point3f& lower_right = glyph.quad.points[1];
170  const math::Point3f& upper_left = glyph.quad.points[3];
171  const math::Vector3f v_right = (lower_right - lower_left) * inv_width;
172  const math::Vector3f v_up = (upper_left - lower_left) * inv_height;
173  vec = v_right + v_up;
174  }
175  }
176  return vec;
177 }
178 
179 } // anonymous namespace
180 
182 
187 
188 
190  const gfxutils::ShaderManagerPtr& shader_manager,
191  const base::AllocatorPtr& allocator)
192  : Builder(font_image, shader_manager, allocator) {}
193 
195 
196 bool OutlineBuilder::SetSdfPadding(float padding) {
197  return GetNode().Get() && GetNode()->SetUniformByName("uSdfPadding", padding);
198 }
199 
200 bool OutlineBuilder::SetTextColor(const math::VectorBase4f& color) {
201  return GetNode().Get() && GetNode()->SetUniformByName("uTextColor", color);
202 }
203 
204 bool OutlineBuilder::SetOutlineColor(const math::VectorBase4f& color) {
205  return GetNode().Get() && GetNode()->SetUniformByName("uOutlineColor", color);
206 }
207 
209  return GetNode().Get() && GetNode()->SetUniformByName("uOutlineWidth", width);
210 }
211 
213  return GetNode().Get() && GetNode()->SetUniformByName("uHalfSmoothWidth",
214  width);
215 }
216 
219  reg->IncludeGlobalRegistry();
221  "uSdfPadding", gfx::kFloatUniform, "SDF padding amount"));
223  "uSdfSampler", gfx::kTextureUniform, "SDF font texture sampler"));
225  "uTextColor", gfx::kFloatVector4Uniform, "Text foreground color"));
227  "uOutlineColor", gfx::kFloatVector4Uniform, "Text outline color"));
229  "uOutlineWidth", gfx::kFloatUniform, "Text outline width in pixels"));
231  "uHalfSmoothWidth", gfx::kFloatUniform,
232  "Half of edge smoothing width in pixels"));
233  return reg;
234 }
235 
236 void OutlineBuilder::GetShaderStrings(std::string* id_string,
237  std::string* vertex_source,
238  std::string* fragment_source) {
239  *id_string = "Outline Text Shader";
240  *vertex_source = kVertexShaderSource;
241  *fragment_source = kFragmentShaderSource;
242 }
243 
245  gfx::Node* node) {
247  DCHECK(GetFontImage().Get());
248  const Font* font = GetFontImage()->GetFont().Get();
249  DCHECK(font);
250  const float sdf_padding =
251  font ? static_cast<float>(font->GetSdfPadding()) : 0.f;
252  if (node->GetUniforms().size() < 6U)
253  node->ClearUniforms();
254  if (node->GetUniforms().empty()) {
255  node->AddUniform(registry->Create<gfx::Uniform>(
256  "uSdfPadding", sdf_padding));
257  node->AddUniform(registry->Create<gfx::Uniform>(
258  "uSdfSampler", GetFontImageTexture()));
259  node->AddUniform(registry->Create<gfx::Uniform>(
260  "uTextColor", math::Point4f(1.f, 1.f, 1.f, 1.f)));
261  node->AddUniform(registry->Create<gfx::Uniform>(
262  "uOutlineColor", math::Point4f(0.f, 0.f, 0.f, 0.f)));
263  node->AddUniform(registry->Create<gfx::Uniform>("uOutlineWidth", 2.f));
264  node->AddUniform(registry->Create<gfx::Uniform>("uHalfSmoothWidth", 3.f));
265  } else {
268  DCHECK_GE(node->GetUniforms().size(), 6U);
269  node->SetUniformValue<float>(0U, sdf_padding);
271  }
272 }
273 
275  const gfx::BufferObjectPtr& buffer_object) {
276  Vertex v;
278  .Bind(v.position, "aVertex")
279  .Bind(v.texture_coords, "aTexCoords")
280  .Bind(v.font_pixel_vec, "aFontPixelVec")
282  buffer_object);
283 }
284 
286  size_t* vertex_size,
287  size_t* num_vertices) {
289  const size_t num_glyphs = layout.GetGlyphCount();
290  *vertex_size = sizeof(Vertex);
291  *num_vertices = 4 * num_glyphs;
292  base::AllocVector<char> vertex_data(
294  vertex_data.resize(sizeof(Vertex) * (*num_vertices));
295  Vertex* vertices = reinterpret_cast<Vertex*>(&vertex_data[0]);
296  math::Point3f positions[4];
297  math::Point2f texture_coords[4];
298  DCHECK(GetFont().Get());
299  const Font& font = *GetFont();
300  for (size_t i = 0; i < num_glyphs; ++i) {
301  StoreGlyphVertices(layout, i, positions, texture_coords);
302  const math::Vector3f font_pixel_vec = ComputeFontPixelVec(font, layout, i);
303  for (int j = 0; j < 4; ++j)
304  vertices[4 * i + j] =
305  Vertex(positions[j], texture_coords[j], font_pixel_vec);
306  }
307  return vertex_data;
308 }
309 
310 } // namespace text
311 } // namespace ion
bool IsInvalidReference(const T &value)
IsInvalidReference() returns true if a passed const reference of type T has an address of InvalidRefe...
Definition: invalid.h:41
kShortTerm is used for objects that are very transient in nature, such as scratch memory used to comp...
Definition: allocator.h:36
void StoreGlyphVertices(const Layout &layout, size_t glyph_index, math::Point3f positions[4], math::Point2f texture_coords[4])
Fills in the position and texture_coords for the 4 vertices of the indexed Layout glyph quad...
Definition: builder.cc:246
size_t GetSdfPadding() const
Returns the padding value used when generating SDF glyphs from the font.
Definition: font.h:84
const FontPtr GetFont() const
Returns the Font from the FontImage. This may be a NULL pointer.
Definition: builder.h:57
This struct is stored for each registered ShaderInput.
bool UpdateFontImageTextureUniform(size_t index, gfx::Node *node)
Modifies the indexed Texture uniform in the node if necessary to contain the current FontImage image...
Definition: builder.cc:232
size_t AddUniform(const Uniform &uniform)
Adds a uniform to this and returns an index that can be used to refer to the uniform.
Definition: uniformholder.h:46
static const ShaderInputRegistryPtr & GetGlobalRegistry()
Returns the ShaderInputRegistry instance representing all supported global uniforms and attributes...
bool SetTextColor(const math::VectorBase4f &color)
std::string text
#define DCHECK(expr)
Definition: logging.h:331
Point2f texture_coords
Definition: shapeutils.cc:74
const base::AllocatorPtr & GetAllocator()
Returns the Allocator passed to the constructor.
Definition: builder.h:97
void UpdateUniforms(const gfx::ShaderInputRegistryPtr &registry, gfx::Node *node) override
Adds or updates uniforms for the shaders in the node.
A Uniform instance represents a uniform shader argument.
Definition: uniform.h:76
const base::AllocVector< Uniform > & GetUniforms() const
Gets the vector of uniforms.
Definition: uniformholder.h:81
bool SetOutlineWidth(float width)
Scalar types.
Definition: uniform.h:39
const AllocatorPtr & GetAllocatorForLifetime(AllocationLifetime lifetime) const
Convenience function that returns the Allocator to use to allocate an object with a specific lifetime...
Definition: allocatable.h:78
T * Get() const
Returns a raw pointer to the instance, which may be NULL.
Definition: sharedptr.h:89
OutlineBuilder(const FontImagePtr &font_image, const gfxutils::ShaderManagerPtr &shader_manager, const base::AllocatorPtr &allocator)
OutlineBuilder functions.
A ShaderInputRegistry is used to manage a collection of shader inputs to a specific ShaderProgram (bo...
const gfx::ShaderInputRegistryPtr GetShaderInputRegistry() override
Required Builder functions.
~OutlineBuilder() override
The destructor is protected because all base::Referent classes must have protected or private destruc...
void GetShaderStrings(std::string *id_string, std::string *vertex_source, std::string *fragment_source) override
Returns the strings needed for shader definition.
bool SetOutlineColor(const math::VectorBase4f &color)
const gfx::NodePtr & GetNode() const
Returns the Node set up by the last successful call to Build().
Definition: builder.h:76
void ClearUniforms()
Clears the vector of uniforms in this.
Definition: uniformholder.h:78
#define DCHECK_GE(val1, val2)
Definition: logging.h:336
size_t GetGlyphCount() const
Returns the number of glyphs added to the layout.
Definition: layout.cc:31
BufferToAttributeBinder is a simple interface to insert a set of Attributes containing BufferObjectEl...
Copyright 2016 Google Inc.
A Layout instance specifies how glyphs are arranged to form text.
Definition: layout.h:127
BufferToAttributeBinder & Bind(const FieldType &field, const std::string &attribute_name)
int width
base::AllocVector< char > BuildVertexData(const Layout &layout, size_t *vertex_size, size_t *num_vertices) override
Returns a vector of data that represents vertex data, the size of a vertex, the number of vertices...
bool SetHalfSmoothWidth(float width)
void BindAttributes(const gfx::AttributeArrayPtr &attr_array, const gfx::BufferObjectPtr &buffer_object) override
Binds attributes for the Builder's shader program.
bool SetUniformValue(size_t index, const T &value)
Sets the value of the uniform at an index if the index is valid.
Definition: uniformholder.h:86
const gfx::TexturePtr GetFontImageTexture()
Returns a Texture that contains the FontImage image.
Definition: builder.cc:223
Builder is an abstract base class for building graphics objects used to render text.
Definition: builder.h:45
A Node instance represents a node in a scene graph.
Definition: node.h:45
A SharedPtr is a smart shared pointer to an instance of some class that implements reference counting...
Definition: sharedptr.h:60
Font is a base class for implementation-specific representations of fonts.
Definition: font.h:43
void Apply(const gfx::ShaderInputRegistryPtr &reg, const gfx::AttributeArrayPtr &aa, const gfx::BufferObjectPtr &bo)
This class can be used in place of std::vector to allow an Ion Allocator to be used for memory alloca...
Definition: allocvector.h:50
bool SetSdfPadding(float padding)
These convenience functions can be used to modify uniform values in the built Node returned by GetNod...
const FontImagePtr & GetFontImage() const
Returns the FontImage passed to the constructor.
Definition: builder.h:48