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  */
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  */
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  GeomVertexReader texcoord(vdata, InternalName::get_texcoord());
175  LVecBase3 v = vertex.get_data3();
176  if (!IS_NEARLY_ZERO(v[1])) {
177  return;
178  }
179  LTexCoord uv(0);
180  if (texcoord.has_column()) {
181  uv = texcoord.get_data2();
182  }
183  PN_stdfloat minx = v[0];
184  PN_stdfloat maxx = v[0];
185  PN_stdfloat miny = v[2];
186  PN_stdfloat maxy = v[2];
187  PN_stdfloat minu = uv[0];
188  PN_stdfloat maxu = uv[0];
189  PN_stdfloat minv = uv[1];
190  PN_stdfloat maxv = uv[1];
191 
192  for (int i = 1; i < 4; ++i) {
193  v = vertex.get_data3();
194  if (!IS_NEARLY_ZERO(v[1])) {
195  return;
196  }
197  if (texcoord.has_column()) {
198  uv = texcoord.get_data2();
199  }
200  if (!IS_NEARLY_EQUAL(v[0], minx) && !IS_NEARLY_EQUAL(v[0], maxx)) {
201  if (!IS_NEARLY_EQUAL(minx, maxx)) {
202  return;
203  }
204  if (v[0] < minx) {
205  minx = v[0];
206  minu = uv[0];
207  }
208  if (v[0] > maxx) {
209  maxx = v[0];
210  maxu = uv[0];
211  }
212  }
213  if (!IS_NEARLY_EQUAL(v[2], miny) && !IS_NEARLY_EQUAL(v[2], maxy)) {
214  if (!IS_NEARLY_EQUAL(miny, maxy)) {
215  return;
216  }
217  if (v[2] < miny) {
218  miny = v[2];
219  minv = uv[1];
220  }
221  if (v[2] > maxy) {
222  maxy = v[2];
223  maxv = uv[1];
224  }
225  }
226  if (!IS_NEARLY_EQUAL(uv[0], minu) && !IS_NEARLY_EQUAL(uv[0], maxu)) {
227  return;
228  }
229  if (!IS_NEARLY_EQUAL(uv[1], minv) && !IS_NEARLY_EQUAL(uv[1], maxv)) {
230  return;
231  }
232  }
233 
234  _quad_dimensions.set(minx, miny, maxx, maxy);
235  _quad_texcoords.set(minu, minv, maxu, maxv);
236  _has_quad = true;
237 }
238 
239 /**
240  * Generates a Geom representing this text glyph, if at all possible.
241  */
242 void TextGlyph::
243 make_quad_geom() {
244  // The default implementation is to generate a Geom based on the get_quad()
245  // implementation, if any.
246  LVecBase4 dimensions, uvs;
247  if (!get_quad(dimensions, uvs)) {
248  return;
249  }
250 
251  // Create a corresponding triangle pair. We use a pair of indexed triangles
252  // rather than a single triangle strip, to avoid the bad vertex duplication
253  // behavior with lots of two-triangle strips.
254  PT(GeomVertexData) vdata = new GeomVertexData
255  (std::string(), GeomVertexFormat::get_v3t2(), Geom::UH_static);
256  vdata->unclean_set_num_rows(4);
257 
258  PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
259 
260  {
261  GeomVertexWriter vertex(vdata, InternalName::get_vertex());
262  GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
263 
264  PT(GeomVertexArrayData) indices = tris->modify_vertices();
265  indices->unclean_set_num_rows(6);
266 
267  GeomVertexWriter index(indices, 0);
268 
269  vertex.set_data3(dimensions[0], 0, dimensions[3]);
270  vertex.set_data3(dimensions[0], 0, dimensions[1]);
271  vertex.set_data3(dimensions[2], 0, dimensions[3]);
272  vertex.set_data3(dimensions[2], 0, dimensions[1]);
273 
274  texcoord.set_data2(uvs[0], uvs[3]);
275  texcoord.set_data2(uvs[0], uvs[1]);
276  texcoord.set_data2(uvs[2], uvs[3]);
277  texcoord.set_data2(uvs[2], uvs[1]);
278 
279  index.set_data1i(0);
280  index.set_data1i(1);
281  index.set_data1i(2);
282  index.set_data1i(2);
283  index.set_data1i(1);
284  index.set_data1i(3);
285  }
286 
287  // We create a regular Geom here, not a GeomTextGlyph, since doing so would
288  // create a circular reference. When the get_geom method makes a copy, it
289  // will add in a pointer to this text glyph.
290  PT(Geom) geom = new Geom(vdata);
291  geom->add_primitive(tris);
292  _geom = geom;
293 }
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
Definition: geomPrimitive.h:56
This is a specialization on Geom for containing a primitive intended to represent a TextGlyph.
Definition: geomTextGlyph.h:27
Defines a series of disconnected triangles.
Definition: geomTriangles.h:23
This is the data for one array of a GeomVertexData structure.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
get_usage_hint
Returns the usage hint that was passed to the constructor, and which will be passed to each array dat...
This class defines the physical layout of the vertex data stored within a Geom.
static const GeomVertexFormat * get_v3t2()
Returns a standard vertex format with a 2-component texture coordinate pair and a 3-component vertex ...
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
A container for geometry primitives.
Definition: geom.h:54
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition: renderState.h:47
A representation of a single glyph (character) from a font.
Definition: textGlyph.h:28
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
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
A thread; that is, a lightweight process.
Definition: thread.h:46
TypeHandle is the identifier used to differentiate C++ class types.
Definition: typeHandle.h:81
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
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.