00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "staticTextFont.h"
00016 #include "config_text.h"
00017
00018 #include "geom.h"
00019 #include "geomNode.h"
00020 #include "geomVertexReader.h"
00021 #include "geomPoints.h"
00022 #include "renderState.h"
00023 #include "dcast.h"
00024
00025
00026 #include "textureCollection.h"
00027 #include "nodePath.h"
00028
00029 TypeHandle StaticTextFont::_type_handle;
00030
00031
00032
00033
00034
00035
00036
00037
00038 StaticTextFont::
00039 StaticTextFont(PandaNode *font_def) {
00040 nassertv(font_def != (PandaNode *)NULL);
00041 _font = font_def;
00042 _glyphs.clear();
00043
00044
00045
00046
00047 NodePath np(font_def);
00048 TextureCollection tc = np.find_all_textures();
00049 int num_textures = tc.get_num_textures();
00050 for (int i = 0; i < num_textures; ++i) {
00051 Texture *tex = tc.get_texture(i);
00052
00053
00054
00055
00056
00057
00058 tex->set_compression(Texture::CM_off);
00059
00060 if (tex->get_quality_level() == Texture::QL_default) {
00061 tex->set_quality_level(text_quality_level);
00062 }
00063 if (tex->get_minfilter() == Texture::FT_default) {
00064 tex->set_minfilter(text_minfilter);
00065 }
00066 if (tex->get_magfilter() == Texture::FT_default) {
00067 tex->set_magfilter(text_magfilter);
00068 }
00069 }
00070
00071 find_characters(font_def, RenderState::make_empty());
00072 _is_valid = !_glyphs.empty();
00073
00074
00075 int character = 32;
00076 Glyphs::iterator gi = _glyphs.find(character);
00077 if (gi != _glyphs.end()) {
00078 TextGlyph *glyph = (*gi).second;
00079 _space_advance = glyph->get_advance();
00080 }
00081
00082 set_name(font_def->get_name());
00083 }
00084
00085
00086
00087
00088
00089
00090 PT(TextFont) StaticTextFont::
00091 make_copy() const {
00092 return new StaticTextFont(_font);
00093 }
00094
00095
00096
00097
00098
00099
00100 void StaticTextFont::
00101 write(ostream &out, int indent_level) const {
00102 indent(out, indent_level)
00103 << "StaticTextFont " << get_name() << "; "
00104 << _glyphs.size() << " characters available in font:\n";
00105 Glyphs::const_iterator gi;
00106
00107
00108
00109
00110 static const int num_letters = 26;
00111 static const int num_digits = 10;
00112 bool lowercase[num_letters];
00113 bool uppercase[num_letters];
00114 bool digits[num_digits];
00115
00116 memset(lowercase, 0, sizeof(bool) * num_letters);
00117 memset(uppercase, 0, sizeof(bool) * num_letters);
00118 memset(digits, 0, sizeof(bool) * num_digits);
00119
00120 int count_lowercase = 0;
00121 int count_uppercase = 0;
00122 int count_digits = 0;
00123
00124 for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
00125 int ch = (*gi).first;
00126 if (ch < 128) {
00127 if (islower(ch)) {
00128 count_lowercase++;
00129 lowercase[ch - 'a'] = true;
00130
00131 } else if (isupper(ch)) {
00132 count_uppercase++;
00133 uppercase[ch - 'A'] = true;
00134
00135 } else if (isdigit(ch)) {
00136 count_digits++;
00137 digits[ch - '0'] = true;
00138 }
00139 }
00140 }
00141
00142 if (count_lowercase == num_letters) {
00143 indent(out, indent_level + 2)
00144 << "All lowercase letters\n";
00145
00146 } else if (count_lowercase > 0) {
00147 indent(out, indent_level + 2)
00148 << "Some lowercase letters: ";
00149 for (int i = 0; i < num_letters; i++) {
00150 if (lowercase[i]) {
00151 out << (char)(i + 'a');
00152 }
00153 }
00154 out << "\n";
00155 }
00156
00157 if (count_uppercase == num_letters) {
00158 indent(out, indent_level + 2)
00159 << "All uppercase letters\n";
00160
00161 } else if (count_uppercase > 0) {
00162 indent(out, indent_level + 2)
00163 << "Some uppercase letters: ";
00164 for (int i = 0; i < num_letters; i++) {
00165 if (uppercase[i]) {
00166 out << (char)(i + 'A');
00167 }
00168 }
00169 out << "\n";
00170 }
00171
00172 if (count_digits == num_digits) {
00173 indent(out, indent_level + 2)
00174 << "All digits\n";
00175
00176 } else if (count_digits > 0) {
00177 indent(out, indent_level + 2)
00178 << "Some digits: ";
00179 for (int i = 0; i < num_digits; i++) {
00180 if (digits[i]) {
00181 out << (char)(i + '0');
00182 }
00183 }
00184 out << "\n";
00185 }
00186
00187 for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
00188 int ch = (*gi).first;
00189 if (ch >= 128 || !isalnum(ch)) {
00190 indent(out, indent_level + 2)
00191 << ch;
00192 if (ch < isprint(ch)) {
00193 out << " = '" << (char)ch << "'\n";
00194 }
00195 }
00196 }
00197 }
00198
00199
00200
00201
00202
00203
00204
00205
00206
00207
00208
00209
00210 bool StaticTextFont::
00211 get_glyph(int character, const TextGlyph *&glyph) {
00212 Glyphs::const_iterator gi = _glyphs.find(character);
00213 if (gi == _glyphs.end()) {
00214
00215 glyph = get_invalid_glyph();
00216 return false;
00217 }
00218
00219 glyph = (*gi).second;
00220 return true;
00221 }
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 void StaticTextFont::
00233 find_character_gsets(PandaNode *root, CPT(Geom) &ch, CPT(Geom) &dot,
00234 const RenderState *&state, const RenderState *net_state) {
00235 CPT(RenderState) next_net_state = net_state->compose(root->get_state());
00236
00237 if (root->is_geom_node()) {
00238 GeomNode *geode = DCAST(GeomNode, root);
00239
00240 for (int i = 0; i < geode->get_num_geoms(); i++) {
00241 const Geom *geom = geode->get_geom(i);
00242
00243 bool found_points = false;
00244 for (int j = 0; j < geom->get_num_primitives() && !found_points; j++) {
00245 const GeomPrimitive *primitive = geom->get_primitive(j);
00246 if (primitive->is_of_type(GeomPoints::get_class_type())) {
00247 dot = geom;
00248 found_points = true;
00249 }
00250 }
00251 if (!found_points) {
00252
00253
00254 ch = geom;
00255 state = next_net_state->compose(geode->get_geom_state(i));
00256 }
00257 }
00258
00259 } else {
00260 PandaNode::Children cr = root->get_children();
00261 int num_children = cr.get_num_children();
00262 for (int i = 0; i < num_children; i++) {
00263 find_character_gsets(cr.get_child(i), ch, dot, state,
00264 next_net_state);
00265 }
00266 }
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00276
00277 void StaticTextFont::
00278 find_characters(PandaNode *root, const RenderState *net_state) {
00279 CPT(RenderState) next_net_state = net_state->compose(root->get_state());
00280 string name = root->get_name();
00281
00282 bool all_digits = !name.empty();
00283 const char *p = name.c_str();
00284 while (all_digits && *p != '\0') {
00285
00286
00287
00288 all_digits = (isdigit(*p) != 0);
00289 p++;
00290 }
00291
00292 if (all_digits) {
00293 int character = atoi(name.c_str());
00294 CPT(Geom) ch;
00295 CPT(Geom) dot;
00296 const RenderState *state = NULL;
00297 find_character_gsets(root, ch, dot, state, next_net_state);
00298 PN_stdfloat width = 0.0;
00299 if (dot != (Geom *)NULL) {
00300
00301
00302 GeomVertexReader reader(dot->get_vertex_data(), InternalName::get_vertex());
00303 width = reader.get_data1f();
00304 }
00305
00306 _glyphs[character] = new TextGlyph(character, ch, state, width);
00307
00308 } else if (name == "ds") {
00309
00310
00311
00312 CPT(Geom) ch;
00313 CPT(Geom) dot;
00314 const RenderState *state = NULL;
00315 find_character_gsets(root, ch, dot, state, next_net_state);
00316 if (dot != (Geom *)NULL) {
00317
00318
00319 GeomVertexReader reader(dot->get_vertex_data(), InternalName::get_vertex());
00320 _line_height = reader.get_data3()[2];
00321 _space_advance = 0.25f * _line_height;
00322 }
00323
00324 } else {
00325 PandaNode::Children cr = root->get_children();
00326 int num_children = cr.get_num_children();
00327 for (int i = 0; i < num_children; i++) {
00328 find_characters(cr.get_child(i), next_net_state);
00329 }
00330 }
00331 }