Panda3D
Loading...
Searching...
No Matches
staticTextFont.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 staticTextFont.cxx
10 * @author drose
11 * @date 2001-05-03
12 */
13
14#include "staticTextFont.h"
15#include "config_text.h"
16
17#include "geom.h"
18#include "geomNode.h"
19#include "geomVertexReader.h"
20#include "geomPoints.h"
21#include "renderState.h"
22#include "dcast.h"
23
24// Temporary
25#include "textureCollection.h"
26#include "nodePath.h"
27
28TypeHandle StaticTextFont::_type_handle;
29
30/**
31 * The constructor expects the root node to a model generated via egg-mkfont,
32 * which consists of a set of models, one per each character in the font.
33 *
34 * If a CoordinateSystem value is specified, it informs the font of the
35 * coordinate system in which this model was generated. "up" in this
36 * coordinate system will be the direction of the top of the letters.
37 */
39StaticTextFont(PandaNode *font_def, CoordinateSystem cs) {
40 nassertv(font_def != nullptr);
41 _font = font_def;
42 _cs = cs;
43 _glyphs.clear();
44
45 if (_cs == CS_default) {
46 _cs = get_default_coordinate_system();
47 }
48
49 NodePath np(font_def);
50 if (_cs != CS_zup_right) {
51 // We have to convert the entire font to CS_zup_right before we can use
52 // it, because the text subsystem assumes the glyphs are stored in
53 // CS_zup_right.
54 NodePath temp_root("root");
55 NodePath temp_child = temp_root.attach_new_node("child");
56 np = np.copy_to(temp_child);
57 LMatrix4 mat = LMatrix4::convert_mat(_cs, CS_zup_right);
58 temp_child.set_mat(mat);
59 temp_root.clear_model_nodes();
60 temp_root.flatten_light();
61 np = temp_root.get_child(0).get_child(0);
62 _font = np.node();
63 _cs = CS_zup_right;
64 }
65
66 // If there is no explicit quality level or filter settings on the textures
67 // in the static font, set the appropriate defaults for text.
69 int num_textures = tc.get_num_textures();
70 for (int i = 0; i < num_textures; ++i) {
71 Texture *tex = tc.get_texture(i);
72
73 // Don't compress font textures. Though there's a relatively high bang-
74 // for-the-buck in compressing them, there's an increased risk that broken
75 // graphics drivers will fail to render the text properly, causing
76 // troubles for a user who then won't be able to navigate the options
77 // menus to disable texture compression.
78 tex->set_compression(Texture::CM_off);
79
80 if (tex->get_quality_level() == Texture::QL_default) {
81 tex->set_quality_level(text_quality_level);
82 }
83 if (tex->get_minfilter() == SamplerState::FT_default) {
84 tex->set_minfilter(text_minfilter);
85 }
86 if (tex->get_magfilter() == SamplerState::FT_default) {
87 tex->set_magfilter(text_magfilter);
88 }
89 }
90
91 find_characters(_font, RenderState::make_empty());
92 _is_valid = !_glyphs.empty();
93
94 // Check for an explicit space width.
95 int character = 32;
96 Glyphs::iterator gi = _glyphs.find(character);
97 if (gi != _glyphs.end()) {
98 TextGlyph *glyph = (*gi).second;
99 _space_advance = glyph->get_advance();
100 }
101
102 set_name(font_def->get_name());
103}
104
105/**
106 * Returns a new copy of the same font.
107 */
108PT(TextFont) StaticTextFont::
109make_copy() const {
110 return new StaticTextFont(_font);
111}
112
113/**
114 *
115 */
116void StaticTextFont::
117write(std::ostream &out, int indent_level) const {
118 indent(out, indent_level)
119 << "StaticTextFont " << get_name() << "; "
120 << _glyphs.size() << " characters available in font:\n";
121 Glyphs::const_iterator gi;
122
123 // Figure out which symbols we have. We collect lowercase letters,
124 // uppercase letters, and digits together for the user's convenience.
125 static const int num_letters = 26;
126 static const int num_digits = 10;
127 bool lowercase[num_letters];
128 bool uppercase[num_letters];
129 bool digits[num_digits];
130
131 memset(lowercase, 0, sizeof(bool) * num_letters);
132 memset(uppercase, 0, sizeof(bool) * num_letters);
133 memset(digits, 0, sizeof(bool) * num_digits);
134
135 int count_lowercase = 0;
136 int count_uppercase = 0;
137 int count_digits = 0;
138
139 for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
140 int ch = (*gi).first;
141 if (ch < 128) {
142 if (islower(ch)) {
143 count_lowercase++;
144 lowercase[ch - 'a'] = true;
145
146 } else if (isupper(ch)) {
147 count_uppercase++;
148 uppercase[ch - 'A'] = true;
149
150 } else if (isdigit(ch)) {
151 count_digits++;
152 digits[ch - '0'] = true;
153 }
154 }
155 }
156
157 if (count_lowercase == num_letters) {
158 indent(out, indent_level + 2)
159 << "All lowercase letters\n";
160
161 } else if (count_lowercase > 0) {
162 indent(out, indent_level + 2)
163 << "Some lowercase letters: ";
164 for (int i = 0; i < num_letters; i++) {
165 if (lowercase[i]) {
166 out << (char)(i + 'a');
167 }
168 }
169 out << "\n";
170 }
171
172 if (count_uppercase == num_letters) {
173 indent(out, indent_level + 2)
174 << "All uppercase letters\n";
175
176 } else if (count_uppercase > 0) {
177 indent(out, indent_level + 2)
178 << "Some uppercase letters: ";
179 for (int i = 0; i < num_letters; i++) {
180 if (uppercase[i]) {
181 out << (char)(i + 'A');
182 }
183 }
184 out << "\n";
185 }
186
187 if (count_digits == num_digits) {
188 indent(out, indent_level + 2)
189 << "All digits\n";
190
191 } else if (count_digits > 0) {
192 indent(out, indent_level + 2)
193 << "Some digits: ";
194 for (int i = 0; i < num_digits; i++) {
195 if (digits[i]) {
196 out << (char)(i + '0');
197 }
198 }
199 out << "\n";
200 }
201
202 for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
203 int ch = (*gi).first;
204 if (ch >= 128 || !isalnum(ch)) {
205 indent(out, indent_level + 2)
206 << ch;
207 if (ch < isprint(ch)) {
208 out << " = '" << (char)ch << "'\n";
209 }
210 }
211 }
212}
213
214/**
215 * Gets the glyph associated with the given character code, as well as an
216 * optional scaling parameter that should be applied to the glyph's geometry
217 * and advance parameters. Returns true if the glyph exists, false if it does
218 * not. Even if the return value is false, the value for glyph might be
219 * filled in with a printable glyph.
220 */
221bool StaticTextFont::
222get_glyph(int character, CPT(TextGlyph) &glyph) {
223 Glyphs::const_iterator gi = _glyphs.find(character);
224 if (gi == _glyphs.end()) {
225 // No definition for this character.
226 glyph = get_invalid_glyph();
227 return false;
228 }
229
230 glyph = (*gi).second;
231 return true;
232}
233
234/**
235 * Given that 'root' is a PandaNode containing at least a polygon and a point
236 * which define the character's appearance and kern position, respectively,
237 * recursively walk the hierarchy and root and locate those two Geoms.
238 */
239void StaticTextFont::
240find_character_gsets(PandaNode *root, CPT(Geom) &ch, CPT(Geom) &dot,
241 const RenderState *&state, const RenderState *net_state) {
242 CPT(RenderState) next_net_state = net_state->compose(root->get_state());
243
244 if (root->is_geom_node()) {
245 GeomNode *geode = DCAST(GeomNode, root);
246
247 for (int i = 0; i < geode->get_num_geoms(); i++) {
248 const Geom *geom = geode->get_geom(i);
249
250 bool found_points = false;
251 for (size_t j = 0; j < geom->get_num_primitives() && !found_points; ++j) {
252 const GeomPrimitive *primitive = geom->get_primitive(j);
253 if (primitive->is_of_type(GeomPoints::get_class_type())) {
254 dot = geom;
255 found_points = true;
256 }
257 }
258 if (!found_points) {
259 // If it doesn't have any points, it must be the regular letter.
260 ch = geom;
261 state = next_net_state->compose(geode->get_geom_state(i));
262 }
263 }
264
265 } else {
267 int num_children = cr.get_num_children();
268 for (int i = 0; i < num_children; i++) {
269 find_character_gsets(cr.get_child(i), ch, dot, state,
270 next_net_state);
271 }
272 }
273}
274
275/**
276 * Walk the hierarchy beginning at the indicated root and locate any nodes
277 * whose names are just integers. These are taken to be characters, and their
278 * definitions and kern informations are retrieved.
279 */
280void StaticTextFont::
281find_characters(PandaNode *root, const RenderState *net_state) {
282 CPT(RenderState) next_net_state = net_state->compose(root->get_state());
283 std::string name = root->get_name();
284
285 bool all_digits = !name.empty();
286 const char *p = name.c_str();
287 while (all_digits && *p != '\0') {
288 // VC++ complains if we treat an int as a bool, so we have to do this != 0
289 // comparison on the int isdigit() function to shut it up.
290 all_digits = (isdigit(*p) != 0);
291 p++;
292 }
293
294 if (all_digits) {
295 int character = atoi(name.c_str());
296 CPT(Geom) ch;
297 CPT(Geom) dot;
298 const RenderState *state = nullptr;
299 find_character_gsets(root, ch, dot, state, next_net_state);
300 PN_stdfloat width = 0.0;
301 if (dot != nullptr) {
302 // Get the first vertex from the "dot" geoset. This will be the origin
303 // of the next character.
304 GeomVertexReader reader(dot->get_vertex_data(), InternalName::get_vertex());
305 width = reader.get_data1f();
306 }
307
308 _glyphs[character] = new TextGlyph(character, ch, state, width);
309
310 } else if (name == "ds") {
311 // The group "ds" is a special node that indicates the font's design size,
312 // or line height.
313
314 CPT(Geom) ch;
315 CPT(Geom) dot;
316 const RenderState *state = nullptr;
317 find_character_gsets(root, ch, dot, state, next_net_state);
318 if (dot != nullptr) {
319 // Get the first vertex from the "dot" geoset. This will be the design
320 // size indicator.
321 GeomVertexReader reader(dot->get_vertex_data(), InternalName::get_vertex());
322 LVecBase3 data = reader.get_data3();
323 _line_height = data[2];
324 _total_poly_margin = data[0];
325 _space_advance = 0.25f * _line_height;
326 }
327
328 } else {
330 int num_children = cr.get_num_children();
331 for (int i = 0; i < num_children; i++) {
332 find_characters(cr.get_child(i), next_net_state);
333 }
334 }
335}
A node that holds Geom objects, renderable pieces of geometry.
Definition geomNode.h:34
get_num_geoms
Returns the number of geoms in the node.
Definition geomNode.h:71
get_geom_state
Returns the RenderState associated with the nth geom of the node.
Definition geomNode.h:75
This is an abstract base class for a family of classes that represent the fundamental geometry primit...
This object provides a high-level interface for quickly reading a sequence of numeric values from a v...
A container for geometry primitives.
Definition geom.h:54
NodePath is the fundamental system for disambiguating instances, and also provides a higher-level int...
Definition nodePath.h:159
NodePath copy_to(const NodePath &other, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Functions like instance_to(), except a deep copy is made of the referenced node and all of its descen...
Definition nodePath.cxx:538
int flatten_light()
Analyzes the geometry below this node and reports the number of vertices, triangles,...
void set_mat(const LMatrix4 &mat)
Directly sets an arbitrary 4x4 transform matrix.
int clear_model_nodes()
Recursively walks through the scene graph at this level and below, looking for ModelNodes,...
Definition nodePath.I:1984
PandaNode * node() const
Returns the referenced node of the path.
Definition nodePath.I:227
NodePath get_child(int n, Thread *current_thread=Thread::get_current_thread()) const
Returns a NodePath representing the nth child of the referenced node.
Definition nodePath.I:337
TextureCollection find_all_textures() const
Returns a list of a textures applied to geometry at this node and below.
NodePath attach_new_node(PandaNode *node, int sort=0, Thread *current_thread=Thread::get_current_thread()) const
Attaches a new node, with or without existing parents, to the scene graph below the referenced node o...
Definition nodePath.cxx:599
PandaNode * get_child(size_t n) const
Returns the nth child of the node.
Definition pandaNode.I:962
size_t get_num_children() const
Returns the number of children of the node.
Definition pandaNode.I:953
A basic node of the scene graph or data graph.
Definition pandaNode.h:65
virtual bool is_geom_node() const
A simple downcast check.
get_children
Returns an object that can be used to walk through the list of children of the node.
Definition pandaNode.h:782
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
Definition renderState.h:47
StaticTextFont(PandaNode *font_def, CoordinateSystem cs=CS_default)
The constructor expects the root node to a model generated via egg-mkfont, which consists of a set of...
An encapsulation of a font; i.e.
Definition textFont.h:32
TextGlyph * get_invalid_glyph()
Returns a special glyph that can be used as a placeholder for any character not in the font.
Definition textFont.cxx:92
A representation of a single glyph (character) from a font.
Definition textGlyph.h:28
get_advance
Returns the distance by which the character pointer should be advanced after placing this character; ...
Definition textGlyph.h:46
Manages a list of Texture objects, as returned by TexturePool::find_all_textures().
get_num_textures
Returns the number of Textures in the collection.
get_texture
Returns the nth Texture in the collection.
Represents a texture object, which is typically a single 2-d image but may also represent a 1-d or 3-...
Definition texture.h:72
set_compression
Requests that this particular Texture be compressed when it is loaded into texture memory.
Definition texture.h:414
get_minfilter
Returns the filter mode of the texture for minification.
Definition texture.h:392
set_quality_level
Sets a hint to the renderer about the desired performance / quality tradeoff for this particular text...
Definition texture.h:428
get_magfilter
Returns the filter mode of the texture for magnification.
Definition texture.h:398
get_quality_level
Returns the current quality_level hint.
Definition texture.h:428
set_minfilter
Sets the filtering method that should be used when viewing the texture from a distance.
Definition texture.h:392
set_magfilter
Sets the filtering method that should be used when viewing the texture up close.
Definition texture.h:398
TypeHandle is the identifier used to differentiate C++ class types.
Definition typeHandle.h:81
bool is_of_type(TypeHandle handle) const
Returns true if the current object is or derives from the indicated type.
Definition typedObject.I:28
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.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
Definition indent.cxx:20
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.