Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/text/staticTextFont.cxx

Go to the documentation of this file.
00001 // Filename: staticTextFont.cxx
00002 // Created by:  drose (03May01)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "staticTextFont.h"
00020 #include "config_text.h"
00021 
00022 #include "geom.h"
00023 #include "geomPoint.h"
00024 #include "geomNode.h"
00025 #include "renderState.h"
00026 #include "dcast.h"
00027 
00028 TypeHandle StaticTextFont::_type_handle;
00029 
00030 ////////////////////////////////////////////////////////////////////
00031 //     Function: StaticTextFont::Constructor
00032 //       Access: Published
00033 //  Description: The constructor expects the root node to a model
00034 //               generated via egg-mkfont, which consists of a set of
00035 //               models, one per each character in the font.
00036 ////////////////////////////////////////////////////////////////////
00037 StaticTextFont::
00038 StaticTextFont(PandaNode *font_def) {
00039   nassertv(font_def != (PandaNode *)NULL);
00040   _font = font_def;
00041   _glyphs.clear();
00042 
00043   find_characters(font_def, RenderState::make_empty());
00044   _is_valid = !_glyphs.empty();
00045 
00046   set_name(font_def->get_name());
00047 }
00048 
00049 ////////////////////////////////////////////////////////////////////
00050 //     Function: StaticTextFont::write
00051 //       Access: Published, Virtual
00052 //  Description:
00053 ////////////////////////////////////////////////////////////////////
00054 void StaticTextFont::
00055 write(ostream &out, int indent_level) const {
00056   indent(out, indent_level)
00057     << "StaticTextFont " << get_name() << "; "
00058     << _glyphs.size() << " characters available in font:\n";
00059   Glyphs::const_iterator gi;
00060   
00061   // Figure out which symbols we have.  We collect lowercase letters,
00062   // uppercase letters, and digits together for the user's
00063   // convenience.
00064   static const int num_letters = 26;
00065   static const int num_digits = 10;
00066   bool lowercase[num_letters];
00067   bool uppercase[num_letters];
00068   bool digits[num_digits];
00069 
00070   memset(lowercase, 0, sizeof(bool) * num_letters);
00071   memset(uppercase, 0, sizeof(bool) * num_letters);
00072   memset(digits, 0, sizeof(bool) * num_digits);
00073 
00074   int count_lowercase = 0;
00075   int count_uppercase = 0;
00076   int count_digits = 0;
00077 
00078   for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
00079     int ch = (*gi).first;
00080     if (ch < 128) {
00081       if (islower(ch)) {
00082         count_lowercase++;
00083         lowercase[ch - 'a'] = true;
00084         
00085       } else if (isupper(ch)) {
00086         count_uppercase++;
00087         uppercase[ch - 'A'] = true;
00088         
00089       } else if (isdigit(ch)) {
00090         count_digits++;
00091         digits[ch - '0'] = true;
00092       }
00093     }
00094   }
00095 
00096   if (count_lowercase == num_letters) {
00097     indent(out, indent_level + 2)
00098       << "All lowercase letters\n";
00099 
00100   } else if (count_lowercase > 0) {
00101     indent(out, indent_level + 2)
00102       << "Some lowercase letters: ";
00103     for (int i = 0; i < num_letters; i++) {
00104       if (lowercase[i]) {
00105         out << (char)(i + 'a');
00106       }
00107     }
00108     out << "\n";
00109   }
00110 
00111   if (count_uppercase == num_letters) {
00112     indent(out, indent_level + 2)
00113       << "All uppercase letters\n";
00114 
00115   } else if (count_uppercase > 0) {
00116     indent(out, indent_level + 2)
00117       << "Some uppercase letters: ";
00118     for (int i = 0; i < num_letters; i++) {
00119       if (uppercase[i]) {
00120         out << (char)(i + 'A');
00121       }
00122     }
00123     out << "\n";
00124   }
00125 
00126   if (count_digits == num_digits) {
00127     indent(out, indent_level + 2)
00128       << "All digits\n";
00129 
00130   } else if (count_digits > 0) {
00131     indent(out, indent_level + 2)
00132       << "Some digits: ";
00133     for (int i = 0; i < num_digits; i++) {
00134       if (digits[i]) {
00135         out << (char)(i + '0');
00136       }
00137     }
00138     out << "\n";
00139   }
00140 
00141   for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
00142     int ch = (*gi).first;
00143     if (ch >= 128 || !isalnum(ch)) {
00144       indent(out, indent_level + 2)
00145         << ch;
00146       if (ch < isprint(ch)) {
00147         out << " = '" << (char)ch << "'\n";
00148       }
00149     }
00150   }
00151 }
00152 
00153 ////////////////////////////////////////////////////////////////////
00154 //     Function: StaticTextFont::get_glyph
00155 //       Access: Public, Virtual
00156 //  Description: Gets the glyph associated with the given character
00157 //               code, as well as an optional scaling parameter that
00158 //               should be applied to the glyph's geometry and advance
00159 //               parameters.  Returns true if the glyph exists, false
00160 //               if it does not.  Even if the return value is false,
00161 //               the value for glyph might be filled in with a
00162 //               printable glyph.
00163 ////////////////////////////////////////////////////////////////////
00164 bool StaticTextFont::
00165 get_glyph(int character, const TextGlyph *&glyph) {
00166   Glyphs::const_iterator gi = _glyphs.find(character);
00167   if (gi == _glyphs.end()) {
00168     // No definition for this character.
00169     glyph = (TextGlyph *)NULL;
00170     return false;
00171   }
00172 
00173   glyph = (*gi).second;
00174   return true;
00175 }
00176 
00177 ////////////////////////////////////////////////////////////////////
00178 //     Function: StaticTextFont::find_character_gsets
00179 //       Access: Private
00180 //  Description: Given that 'root' is a PandaNode containing at least
00181 //               a polygon and a point which define the character's
00182 //               appearance and kern position, respectively,
00183 //               recursively walk the hierarchy and root and locate
00184 //               those two Geoms.
00185 ////////////////////////////////////////////////////////////////////
00186 void StaticTextFont::
00187 find_character_gsets(PandaNode *root, Geom *&ch, GeomPoint *&dot,
00188                      const RenderState *&state, const RenderState *net_state) {
00189   CPT(RenderState) next_net_state = net_state->compose(root->get_state());
00190 
00191   if (root->is_geom_node()) {
00192     GeomNode *geode = DCAST(GeomNode, root);
00193 
00194     for (int i = 0; i < geode->get_num_geoms(); i++) {
00195       dDrawable *geom = geode->get_geom(i);
00196       if (geom->is_of_type(GeomPoint::get_class_type())) {
00197         dot = DCAST(GeomPoint, geom);
00198 
00199       } else if (geom->is_of_type(Geom::get_class_type())) {
00200         ch = DCAST(Geom, geom);
00201         state = next_net_state->compose(geode->get_geom_state(i));
00202       }
00203     }
00204 
00205   } else {
00206     PandaNode::Children cr = root->get_children();
00207     int num_children = cr.get_num_children();
00208     for (int i = 0; i < num_children; i++) {
00209       find_character_gsets(cr.get_child(i), ch, dot, state, next_net_state);
00210     }
00211   }
00212 }
00213 
00214 ////////////////////////////////////////////////////////////////////
00215 //     Function: StaticTextFont::find_characters
00216 //       Access: Private
00217 //  Description: Walk the hierarchy beginning at the indicated root
00218 //               and locate any nodes whose names are just integers.
00219 //               These are taken to be characters, and their
00220 //               definitions and kern informations are retrieved.
00221 ////////////////////////////////////////////////////////////////////
00222 void StaticTextFont::
00223 find_characters(PandaNode *root, const RenderState *net_state) {
00224   CPT(RenderState) next_net_state = net_state->compose(root->get_state());
00225   string name = root->get_name();
00226 
00227   bool all_digits = !name.empty();
00228   const char *p = name.c_str();
00229   while (all_digits && *p != '\0') {
00230     // VC++ complains if we treat an int as a bool, so we have to do
00231     // this != 0 comparison on the int isdigit() function to shut it
00232     // up.
00233     all_digits = (isdigit(*p) != 0);
00234     p++;
00235   }
00236 
00237   if (all_digits) {
00238     int character = atoi(name.c_str());
00239     Geom *ch = NULL;
00240     GeomPoint *dot = NULL;
00241     const RenderState *state = NULL;
00242     find_character_gsets(root, ch, dot, state, next_net_state);
00243     if (dot != NULL) {
00244       // Get the first vertex from the "dot" geoset.  This will be the
00245       // origin of the next character.
00246       PTA_Vertexf alist;
00247       PTA_ushort ilist;
00248       float width;
00249       dot->get_coords(alist, ilist);
00250       if (ilist.empty()) {
00251         width = alist[0][0];
00252       } else {
00253         width = alist[ilist[0]][0];
00254       }
00255 
00256       _glyphs[character] = new TextGlyph(ch, state, width);
00257     }
00258 
00259   } else if (name == "ds") {
00260     // The group "ds" is a special node that indicate's the font's
00261     // design size, or line height.
00262 
00263     Geom *ch = NULL;
00264     GeomPoint *dot = NULL;
00265     const RenderState *state = NULL;
00266     find_character_gsets(root, ch, dot, state, next_net_state);
00267     if (dot != NULL) {
00268       // Get the first vertex from the "dot" geoset.  This will be the
00269       // design size indicator.
00270       PTA_Vertexf alist;
00271       PTA_ushort ilist;
00272       dot->get_coords(alist, ilist);
00273       if (ilist.empty()) {
00274         _line_height = alist[0][2];
00275       } else {
00276         _line_height = alist[ilist[0]][2];
00277       }
00278       _space_advance = 0.25f * _line_height;
00279     }
00280 
00281   } else {
00282     PandaNode::Children cr = root->get_children();
00283     int num_children = cr.get_num_children();
00284     for (int i = 0; i < num_children; i++) {
00285       find_characters(cr.get_child(i), next_net_state);
00286     }
00287   }
00288 }

Generated on Fri May 2 00:44:17 2003 for Panda by doxygen1.3