Panda3D
Loading...
Searching...
No Matches
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
20using std::max;
21using std::min;
22
23TypeHandle TextGlyph::_type_handle;
24
25/**
26 *
27 */
28TextGlyph::
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 */
37is_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 */
50PT(Geom) TextGlyph::
51get_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 */
86void TextGlyph::
87calc_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 */
103void TextGlyph::
104set_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 */
136void TextGlyph::
137check_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 */
242void TextGlyph::
243make_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...
This is a specialization on Geom for containing a primitive intended to represent a TextGlyph.
Defines a series of disconnected triangles.
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.
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.