Panda3D
textGlyph.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file textGlyph.cxx
10  * @author drose
11  * @date 2002-02-08
12  */
13 
14 #include "textGlyph.h"
15 #include "geomTextGlyph.h"
16 #include "geomTriangles.h"
17 #include "geomVertexReader.h"
18 #include "geomVertexWriter.h"
19 
20 using std::max;
21 using std::min;
22 
23 TypeHandle TextGlyph::_type_handle;
24 
25 /**
26  *
27  */
28 TextGlyph::
29 ~TextGlyph() {
30 }
31 
32 /**
33  * Returns true if this glyph represents invisible whitespace, or false if it
34  * corresponds to some visible character.
35  */
36 bool TextGlyph::
37 is_whitespace() const {
38  // In a static font, there is no explicit glyph for whitespace, so all
39  // glyphs are non-whitespace.
40  return false;
41 }
42 
43 /**
44  * Returns a Geom that renders the particular glyph. It will be generated if
45  * necessary.
46  *
47  * This method will always return a copy of the Geom, so the caller is free to
48  * modify it.
49  */
50 PT(Geom) TextGlyph::
51 get_geom(Geom::UsageHint usage_hint) const {
52  if (_geom.is_null()) {
53  // Maybe we have yet to generate a suitable Geom.
54  if (_has_quad) {
55  ((TextGlyph *)this)->make_quad_geom();
56  if (_geom.is_null()) {
57  return nullptr;
58  }
59  } else {
60  // Nope.
61  return nullptr;
62  }
63  }
64 
65  // We always return a copy of the geom. That will allow the caller to
66  // modify its vertices without fear of stomping on other copies. It is also
67  // important that we store a reference to this glyph on the Geom, since the
68  // DynamicTextFont relies on counting references to determine whether a
69  // glyph is no longer used.
70  PT(Geom) new_geom = new GeomTextGlyph(*_geom, this);
71  new_geom->set_usage_hint(usage_hint);
72  const GeomVertexData *vdata = new_geom->get_vertex_data();
73  nassertr(vdata != nullptr, new_geom);
74  if (vdata->get_usage_hint() != usage_hint) {
75  new_geom->modify_vertex_data()->set_usage_hint(usage_hint);
76  }
77  return new_geom;
78 }
79 
80 /**
81  * Expands min_point and max_point to include all of the vertices in the
82  * glyph, if any. found_any is set true if any points are found. It is the
83  * caller's responsibility to initialize min_point, max_point, and found_any
84  * before calling this function.
85  */
86 void TextGlyph::
87 calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
88  bool &found_any, Thread *current_thread) const {
89  if (_has_quad) {
90  found_any = true;
91  min_point.set(_quad_dimensions[0], 0, _quad_dimensions[1]);
92  max_point.set(_quad_dimensions[2], 0, _quad_dimensions[3]);
93 
94  } else if (!_geom.is_null()) {
95  _geom->calc_tight_bounds(min_point, max_point, found_any, current_thread);
96  }
97 }
98 
99 /**
100  * Sets the glyph using the given quad parameters. Any Geom assigned will be
101  * cleared. The order of the components is left, bottom, right, top.
102  */
103 void TextGlyph::
104 set_quad(const LVecBase4 &dimensions, const LVecBase4 &texcoords,
105  const RenderState *state) {
106  _geom.clear();
107 
108  _quad_dimensions = dimensions;
109  _quad_texcoords = texcoords;
110  _has_quad = true;
111  _state = state;
112 }
113 
114 /**
115  * Sets the geom from a pre-built Geom object. Any quad parameters assigned
116  * will be cleared.
117  */
118 void TextGlyph::
120  const RenderState *state) {
121  PT(Geom) geom = new GeomTextGlyph(this, vdata);
122  geom->add_primitive(prim);
123  _geom = geom;
124 
125  _has_quad = false;
126  _state = state;
127 }
128 
129 /**
130  * Checks if the geom that was passed in is actually a quad, and if so, sets
131  * the appropriate quad parameters.
132  *
133  * This is useful when loading static text fonts, so that they can still
134  * benefit from the fast text assembly that is done for quads.
135  */
136 void TextGlyph::
137 check_quad_geom() {
138  // Currently it looks for rather specific signs that this glyph has been
139  // generated using egg-mkfont. For now, this is fine.
140  CPT(GeomVertexData) vdata = _geom->get_vertex_data();
141  if (vdata->get_num_rows() != 4) {
142  return;
143  }
144 
145  // Does it appear to have a single primitive with two triangles?
146  if (_geom->get_num_primitives() != 1) {
147  return;
148  }
149  CPT(GeomPrimitive) prim = _geom->get_primitive(0);
150  if (!prim->is_indexed() ||
151  prim->get_primitive_type() != GeomPrimitive::PT_polygons) {
152  return;
153  }
154  if (!prim->is_of_type(GeomTriangles::get_class_type())) {
155  prim = prim->decompose();
156  }
157  if (prim->get_num_vertices() != 6) {
158  return;
159  }
160 
161  // Check that it has a vertex column and optionally a texcoord column.
162  CPT(GeomVertexFormat) format = vdata->get_format();
163  if (format->get_num_columns() > 2 ||
164  !format->has_column(InternalName::get_vertex())) {
165  return;
166  }
167  if (format->has_column(InternalName::get_texcoord()) != (format->get_num_columns() == 2)) {
168  // The second column, if there is one, is not a texcoord.
169  return;
170  }
171 
172  // Check that the vertices are arranged in a square.
173  GeomVertexReader vertex(vdata, InternalName::get_vertex());
174  LVecBase3 v = vertex.get_data3();
175  if (!IS_NEARLY_ZERO(v[1])) {
176  return;
177  }
178  PN_stdfloat minx = v[0];
179  PN_stdfloat maxx = v[0];
180  PN_stdfloat miny = v[2];
181  PN_stdfloat maxy = v[2];
182 
183  for (int i = 0; i < 3; ++i) {
184  v = vertex.get_data3();
185  if (!IS_NEARLY_ZERO(v[1])) {
186  return;
187  }
188  if (!IS_NEARLY_EQUAL(v[0], minx) && !IS_NEARLY_EQUAL(v[0], maxx)) {
189  if (!IS_NEARLY_EQUAL(minx, maxx)) {
190  return;
191  }
192  minx = min(v[0], minx);
193  maxx = max(v[0], maxx);
194  }
195  if (!IS_NEARLY_EQUAL(v[2], miny) && !IS_NEARLY_EQUAL(v[2], maxy)) {
196  if (!IS_NEARLY_EQUAL(miny, maxy)) {
197  return;
198  }
199  miny = min(v[2], miny);
200  maxy = max(v[2], maxy);
201  }
202  }
203 
204  PN_stdfloat minu = 0;
205  PN_stdfloat maxu = 0;
206  PN_stdfloat minv = 0;
207  PN_stdfloat maxv = 0;
208 
209  // Same for the texcoord data.
210  if (format->has_column(InternalName::get_texcoord())) {
211  GeomVertexReader texcoord(vdata, InternalName::get_texcoord());
212  LVecBase2 tc = texcoord.get_data2();
213  minu = tc[0];
214  maxu = tc[0];
215  minv = tc[1];
216  maxv = tc[1];
217 
218  for (int i = 0; i < 3; ++i) {
219  tc = texcoord.get_data2();
220  if (!IS_NEARLY_EQUAL(tc[0], minu) && !IS_NEARLY_EQUAL(tc[0], maxu)) {
221  if (!IS_NEARLY_EQUAL(minu, maxu)) {
222  return;
223  }
224  minu = min(tc[0], minu);
225  maxu = max(tc[0], maxu);
226  }
227  if (!IS_NEARLY_EQUAL(tc[1], minv) && !IS_NEARLY_EQUAL(tc[1], maxv)) {
228  if (!IS_NEARLY_EQUAL(minv, maxv)) {
229  return;
230  }
231  minv = min(tc[1], minv);
232  maxv = max(tc[1], maxv);
233  }
234  }
235  }
236 
237  _quad_dimensions.set(minx, miny, maxx, maxy);
238  _quad_texcoords.set(minu, minv, maxu, maxv);
239  _has_quad = true;
240 }
241 
242 /**
243  * Generates a Geom representing this text glyph, if at all possible.
244  */
245 void TextGlyph::
246 make_quad_geom() {
247  // The default implementation is to generate a Geom based on the get_quad()
248  // implementation, if any.
249  LVecBase4 dimensions, uvs;
250  if (!get_quad(dimensions, uvs)) {
251  return;
252  }
253 
254  // Create a corresponding triangle pair. We use a pair of indexed triangles
255  // rather than a single triangle strip, to avoid the bad vertex duplication
256  // behavior with lots of two-triangle strips.
257  PT(GeomVertexData) vdata = new GeomVertexData
258  (std::string(), GeomVertexFormat::get_v3t2(), Geom::UH_static);
259  vdata->unclean_set_num_rows(4);
260 
261  PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
262 
263  {
264  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
265  GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
266 
267  PT(GeomVertexArrayData) indices = tris->modify_vertices();
268  indices->unclean_set_num_rows(6);
269 
270  GeomVertexWriter index(indices, 0);
271 
272  vertex.set_data3(dimensions[0], 0, dimensions[3]);
273  vertex.set_data3(dimensions[0], 0, dimensions[1]);
274  vertex.set_data3(dimensions[2], 0, dimensions[3]);
275  vertex.set_data3(dimensions[2], 0, dimensions[1]);
276 
277  texcoord.set_data2(uvs[0], uvs[3]);
278  texcoord.set_data2(uvs[0], uvs[1]);
279  texcoord.set_data2(uvs[2], uvs[3]);
280  texcoord.set_data2(uvs[2], uvs[1]);
281 
282  index.set_data1i(0);
283  index.set_data1i(1);
284  index.set_data1i(2);
285  index.set_data1i(2);
286  index.set_data1i(1);
287  index.set_data1i(3);
288  }
289 
290  // We create a regular Geom here, not a GeomTextGlyph, since doing so would
291  // create a circular reference. When the get_geom method makes a copy, it
292  // will add in a pointer to this text glyph.
293  PT(Geom) geom = new Geom(vdata);
294  geom->add_primitive(tris);
295  _geom = geom;
296 }
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
void set_geom(GeomVertexData *vdata, GeomPrimitive *prim, const RenderState *state)
Sets the geom from a pre-built Geom object.
Definition: textGlyph.cxx:119
virtual bool is_whitespace() const
Returns true if this glyph represents invisible whitespace, or false if it corresponds to some visibl...
Definition: textGlyph.cxx:37
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
A container for geometry primitives.
Definition: geom.h:54
A representation of a single glyph (character) from a font.
Definition: textGlyph.h:28
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
This class defines the physical layout of the vertex data stored within a Geom.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PT(Geom) TextGlyph
Returns a Geom that renders the particular glyph.
Definition: textGlyph.cxx:50
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A thread; that is, a lightweight process.
Definition: thread.h:46
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
Defines a series of disconnected triangles.
Definition: geomTriangles.h:23
get_usage_hint
Returns the usage hint that was passed to the constructor, and which will be passed to each array dat...
static const GeomVertexFormat * get_v3t2()
Returns a standard vertex format with a 2-component texture coordinate pair and a 3-component vertex ...
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
This is a specialization on Geom for containing a primitive intended to represent a TextGlyph.
Definition: geomTextGlyph.h:27
bool get_quad(LVecBase4 &dimensions, LVecBase4 &texcoords) const
Assuming that this glyph is representable as a textured quad, returns its dimensions and UV range.
Definition: textGlyph.I:104
This is the data for one array of a GeomVertexData structure.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.