STLL  0.0
Simple Text Layouting Library
output_OpenGL.h
Go to the documentation of this file.
1 /*
2  * STLL Simple Text Layouting Library
3  *
4  * STLL is the legal property of its developers, whose
5  * names are listed in the COPYRIGHT file, which is included
6  * within the source distribution.
7  *
8  * This program is free software; you can redistribute it and/or
9  * modify it under the terms of the GNU Lesser General Public License
10  * as published by the Free Software Foundation; either version 2.1
11  * of the License, or (at your option) any later version.
12  *
13  * This program is distributed in the hope that it will be useful,
14  * but WITHOUT ANY WARRANTY; without even the implied warranty of
15  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16  * GNU General Public License for more details.
17  *
18  * You should have received a copy of the GNU General Public License
19  * along with this program; if not, write to the Free Software
20  * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
21  */
22 #ifndef STLL_LAYOUTER_OPEN_GL
23 #define STLL_LAYOUTER_OPEN_GL
24 
29 #include "layouterFont.h"
30 #include "color.h"
31 
32 #include "internal/glyphAtlas.h"
33 #include "internal/gamma.h"
34 #include "internal/openGL_internal.h"
35 
36 namespace STLL {
37 
66 template <int V, class G = internal::Gamma_c<>>
67 class showOpenGL : internal::openGL_internals<V>
68 {
69  private:
70  internal::GlyphAtlas_c cache;
71  G g;
72 
73  GLuint glTextureId = 0; // OpenGL texture id
74  uint32_t uploadVersion = 0; // a counter changed each time the texture changes to know when to update
75  uint32_t atlasId = 1;
76  uint32_t cacheMax;
77 
78  public:
79 
84  using DrawCache_c = typename internal::openGL_internals<V>::DrawCacheInternal_c;
85 
94  showOpenGL(uint32_t cStart = 256, uint32_t cMax = 1024) : cache(cStart, cStart), cacheMax(cMax)
95  {
96  glActiveTexture(GL_TEXTURE0);
97  glGenTextures(1, &glTextureId);
98  glBindTexture(GL_TEXTURE_2D, glTextureId);
99  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
100  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
101  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
102  glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
103  glTexEnvi(GL_TEXTURE_2D, GL_TEXTURE_ENV_MODE, GL_REPLACE);
104  g.setGamma(22);
105 
106  internal::openGL_internals<V>::setup();
107  }
108 
110  {
111  glDeleteTextures(1, &glTextureId);
112  internal::openGL_internals<V>::cleanup();
113  }
114 
117  {
118  public:
119  virtual void draw(int32_t x, int32_t y, uint32_t w, uint32_t h, const std::string & url) = 0;
120  };
121 
122 
137  void showLayout(const TextLayout_c & l, int sx, int sy, SubPixelArrangement sp,
138  imageDrawer_c * images = nullptr, DrawCache_c * dc = nullptr)
139  {
140  glActiveTexture(GL_TEXTURE0);
141  glBindTexture( GL_TEXTURE_2D, glTextureId );
142  glEnable(GL_BLEND);
143 
144  if (dc && dc->atlasId == atlasId)
145  {
146  internal::openGL_internals<V>::drawCache(*dc, sp, sx, sy, cache.width());
147  return;
148  }
149 
150  const auto & dat = l.getData();
151  size_t i = 0;
152  bool cleared = false;
153 
154  while (i < dat.size())
155  {
156  size_t j = i;
157 
158  // make sure that there is a small completely filled rectangle
159  // used for drawing filled rectangles
160  cache.getRect(640, 640, SUBP_NONE, 0);
161 
162  while (j < dat.size())
163  {
164  auto & ii = dat[j];
165 
166  bool found = true;
167 
168  switch (ii.command)
169  {
171  // when subpixel placement is on we always create all 3 required images
172  found &= (bool)cache.getGlyph(ii.font, ii.glyphIndex, sp, ii.blurr);
173  break;
175  if (ii.blurr > 0)
176  found &= (bool)cache.getRect(ii.w, ii.h, sp, ii.blurr);
177  break;
178 
179  default:
180  break;
181  }
182 
183  if (!found)
184  {
185  // glyph not found means there was no space to include it inside
186  // the current cache, so try to double its size, if the cache
187  // is already at least cacheMax size, we'll have to split the layout
188  if (cache.width() < cacheMax)
189  {
190  cache.doubleSize();
191  }
192  else
193  {
194  break;
195  }
196  }
197  else
198  {
199  j++;
200  }
201  }
202 
203  // check, if the texture cache has been changed to include
204  // glyphs from this layout, if so re-upload it to the graphics memory
205  if (cache.getVersion() != uploadVersion)
206  {
207  uploadVersion = cache.getVersion();
208  internal::openGL_internals<V>::updateTexture(cache.getData(), cache.width());
209  }
210 
211  typename internal::openGL_internals<V>::CreateInternal_c vb(dat.size());
212 
213  size_t k = i;
214 
215  // check if the user wants caching and if we are able to provide it
216  // we can only use caching, if all the layout completely fits into
217  // one drawing batch
218  if (dc && !cleared && j == dat.size())
219  {
220  internal::openGL_internals<V>::startCachePreparation(*dc);
221  }
222  else
223  {
224  internal::openGL_internals<V>::startPreparation(sx, sy);
225  }
226 
227  while (k < j)
228  {
229  auto & ii = dat[k];
230 
231  switch (ii.command)
232  {
234  {
235  auto pos = cache.getGlyph(ii.font, ii.glyphIndex, sp, ii.blurr).value();
236  Color_c c = g.forward(ii.c);
237 
238  if ((sp == SUBP_RGB || sp == SUBP_BGR) && (ii.blurr <= cache.blurrmax))
239  {
240  internal::openGL_internals<V>::drawSubpGlyph(vb, sp, ii, pos, c, cache.width());
241  }
242  else
243  {
244  internal::openGL_internals<V>::drawNormalGlyph(vb, ii, pos, c, cache.width());
245  }
246  }
247  break;
248 
250  {
251  Color_c c = g.forward(ii.c);
252 
253  if (ii.blurr == 0)
254  {
255  auto pos = cache.getRect(640, 640, SUBP_NONE, 0).value();
256  internal::openGL_internals<V>::drawRectangle(vb, ii, pos, c, cache.width());
257  }
258  else
259  {
260  auto pos = cache.getRect(ii.w, ii.h, sp, ii.blurr).value();
261  internal::openGL_internals<V>::drawSmoothRectangle(vb, ii, pos, c, cache.width());
262  }
263  }
264  break;
265 
267  if (images)
268  images->draw(ii.x+sx, ii.y+sy, ii.w, ii.h, ii.imageURL);
269  break;
270  }
271  k++;
272  }
273 
274  // depending on the drawing options finish the drawing either
275  // by finishing the cache, drawing and leaving the function
276  // or by just completing the drawing batch without cache
277  if (dc && !cleared && j == dat.size())
278  {
279  internal::openGL_internals<V>::endCachePreparation(*dc, vb, sp, sx, sy, atlasId, cache.width());
280  }
281  else
282  {
283  internal::openGL_internals<V>::endPreparation(vb, sp, sx, sy, cache.width());
284 
285  if (j < dat.size())
286  {
287  // atlas is not big enough, it needs to be cleared
288  // and will be repopulated for the next batch of the layout
289  cache.clear();
290  atlasId++;
291  cleared = true;
292  }
293  }
294 
295  i = j;
296  }
297 
298  return;
299  }
300 
305  void setupMatrixes(int width, int height)
306  {
307  internal::openGL_internals<V>::setupProjection(width, height);
308  }
309 
314  const uint8_t * getData(void) const { return cache.getData(); }
315 
316  uint32_t cacheWidth(void) const { return cache.width(); }
317  uint32_t cacheHeight(void) const { return cache.height(); }
318 
326  void setGamma(uint8_t gamma = 22)
327  {
328  g.setGamma(gamma);
329  }
330 
335  void clear(void)
336  {
337  cache.clear();
338  atlasId++;
339  }
340 };
341 
342 }
343 
344 #endif
showOpenGL(uint32_t cStart=256, uint32_t cMax=1024)
constructor
Definition: output_OpenGL.h:94
a little class representing an RGBA colour value, an a value of 255 is assumed to be opaque ...
Definition: color.h:36
const std::vector< CommandData_c > getData(void) const
get the command vector
Definition: layouter.h:121
void setGamma(uint8_t gamma=22)
update the gamma value used for output
Definition: output_OpenGL.h:326
helper class used to draw images
Definition: output_OpenGL.h:116
use horizontal RGB
Definition: layouterFont.h:62
typename internal::openGL_internals< V >::DrawCacheInternal_c DrawCache_c
type to keep the caching information for redrawing layouts extra fast. You dont't need to know anythi...
Definition: output_OpenGL.h:84
SubPixelArrangement
define, which sub-pixel arrangement you want to use for sub-pixel output
Definition: layouterFont.h:59
use horizontal BGR
Definition: layouterFont.h:63
const uint8_t * getData(void) const
get a pointer to the texture atlas with all the glyphs
Definition: output_OpenGL.h:314
draw a rectangle
Definition: layouter.h:55
The namespace for the library. Every function and class is within this namespace. ...
Definition: color.h:31
encapsulates a finished layout.
Definition: layouter.h:105
this file contains just a little helper class for a 4-value colour
uint32_t cacheWidth(void) const
Definition: output_OpenGL.h:316
a FreeType wrapper
void setupMatrixes(int width, int height)
helper function to setup the projection matrices for the showLayout function. It will change the view...
Definition: output_OpenGL.h:305
don't use sub-pixel output (e.g. non LCD)
Definition: layouterFont.h:61
~showOpenGL(void)
Definition: output_OpenGL.h:109
virtual void draw(int32_t x, int32_t y, uint32_t w, uint32_t h, const std::string &url)=0
uint32_t cacheHeight(void) const
Definition: output_OpenGL.h:317
draw an image
Definition: layouter.h:56
draw a glyph from a font
Definition: layouter.h:54
void clear(void)
clear the glyph cache. This might be useful when you change the fonts that you use for output...
Definition: output_OpenGL.h:335
a class to output layouts using OpenGL
Definition: output_OpenGL.h:67
void showLayout(const TextLayout_c &l, int sx, int sy, SubPixelArrangement sp, imageDrawer_c *images=nullptr, DrawCache_c *dc=nullptr)
paint the layout
Definition: output_OpenGL.h:137