generate cheesy accents if font doesn't have them

This commit is contained in:
David Rose 2003-02-02 20:39:49 +00:00
parent 7421fe3e05
commit 5b7526d3a0
20 changed files with 2203 additions and 176 deletions

View File

@ -23,7 +23,8 @@
stringDecoder.I stringDecoder.h \
textFont.I textFont.h \
textGlyph.I textGlyph.h \
textNode.I textNode.h textNode.cxx
textNode.I textNode.h textNode.cxx \
unicodeLatinMap.h
#define INCLUDED_SOURCES \
config_text.cxx \
@ -35,7 +36,8 @@
geomTextGlyph.cxx \
stringDecoder.cxx \
staticTextFont.cxx \
textFont.cxx textGlyph.cxx
textFont.cxx textGlyph.cxx \
unicodeLatinMap.cxx
#define INSTALL_HEADERS \
config_text.h \
@ -48,9 +50,10 @@
stringDecoder.I stringDecoder.h \
textFont.I textFont.h \
textGlyph.I textGlyph.h \
textNode.I textNode.h
textNode.I textNode.h \
unicodeLatinMap.h
#define IGATESCAN all
#end lib_target

View File

@ -23,6 +23,7 @@
#include "dynamicTextFont.h"
#include "dynamicTextPage.h"
#include "geomTextGlyph.h"
#include "unicodeLatinMap.h"
#include "dconfig.h"

View File

@ -118,67 +118,6 @@ get_scale_factor() const {
return _scale_factor;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::set_small_caps
// Access: Published
// Description: Sets the small_caps flag. When this is set,
// lowercase letters are generated as scaled-down
// versions of their uppercase equivalents. This is
// particularly useful to set for fonts that do not have
// lowercase letters.
//
// It is also a good idea to set this for a font that
// has already implemented lowercase letters as
// scaled-down versions of their uppercase equivalents,
// since without this flag the texture memory may
// needlessly duplicate equivalent glyphs for upper and
// lowercase letters. Setting this flag causes the
// texture memory to share the mixed-case letters.
//
// The amount by which the lowercase letters are scaled
// is specified by set_small_caps_scale().
////////////////////////////////////////////////////////////////////
INLINE void DynamicTextFont::
set_small_caps(bool small_caps) {
_small_caps = small_caps;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_small_caps
// Access: Published
// Description: Returns the small_caps flag. See set_small_caps().
////////////////////////////////////////////////////////////////////
INLINE bool DynamicTextFont::
get_small_caps() const {
return _small_caps;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::set_small_caps_scale
// Access: Published
// Description: Sets the scale factor applied to lowercase letters
// from their uppercase equivalents, when the small_caps
// flag is in effect. See set_small_caps(). Normally,
// this will be a number less than one.
////////////////////////////////////////////////////////////////////
INLINE void DynamicTextFont::
set_small_caps_scale(float small_caps_scale) {
_small_caps_scale = small_caps_scale;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_small_caps_scale
// Access: Published
// Description: Returns the scale factor applied to lowercase letters
// from their uppercase equivalents, when the small_caps
// flag is in effect. See set_small_caps() and
// set_small_caps_scale().
////////////////////////////////////////////////////////////////////
INLINE float DynamicTextFont::
get_small_caps_scale() const {
return _small_caps_scale;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::set_texture_margin
// Access: Published

View File

@ -325,20 +325,12 @@ write(ostream &out, int indent_level) const {
// printable glyph.
////////////////////////////////////////////////////////////////////
bool DynamicTextFont::
get_glyph(int character, const TextGlyph *&glyph, float &glyph_scale) {
get_glyph(int character, const TextGlyph *&glyph) {
if (!_is_valid) {
glyph = (TextGlyph *)NULL;
return false;
}
glyph_scale = 1.0f;
if (character < 128 && islower(character) && get_small_caps()) {
// If we have small_caps on, we implement lowercase letters by
// applying a scale to the corresponding uppercase letter.
glyph_scale = get_small_caps_scale();
character = toupper(character);
}
int glyph_index = FT_Get_Char_Index(_face, character);
Cache::iterator ci = _cache.find(glyph_index);
@ -368,8 +360,6 @@ initialize() {
_point_size = text_point_size;
_tex_pixels_per_unit = text_pixels_per_unit;
_scale_factor = text_scale_factor;
_small_caps = text_small_caps;
_small_caps_scale = text_small_caps_scale;
// We don't necessarily want to use mipmaps, since we don't want to
// regenerate those every time the texture changes, but we probably

View File

@ -57,11 +57,6 @@ PUBLISHED:
INLINE bool set_scale_factor(float scale_factor);
INLINE float get_scale_factor() const;
INLINE void set_small_caps(bool small_caps);
INLINE bool get_small_caps() const;
INLINE void set_small_caps_scale(float small_caps_scale);
INLINE float get_small_caps_scale() const;
INLINE void set_texture_margin(int texture_margin);
INLINE int get_texture_margin() const;
INLINE void set_poly_margin(float poly_margin);
@ -91,8 +86,7 @@ PUBLISHED:
virtual void write(ostream &out, int indent_level) const;
public:
virtual bool get_glyph(int character, const TextGlyph *&glyph,
float &glyph_scale);
virtual bool get_glyph(int character, const TextGlyph *&glyph);
private:
void initialize();
@ -110,8 +104,6 @@ private:
float _tex_pixels_per_unit;
float _scale_factor;
float _font_pixels_per_unit;
bool _small_caps;
float _small_caps_scale;
int _texture_margin;
float _poly_margin;
int _page_x_size, _page_y_size;

View File

@ -35,22 +35,6 @@ DynamicTextGlyph::
~DynamicTextGlyph() {
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextGlyph::get_geom
// Access: Public, Virtual
// Description: Returns a Geom that renders the particular glyph.
////////////////////////////////////////////////////////////////////
PT(Geom) DynamicTextGlyph::
get_geom() const {
if (_geom == (Geom *)NULL) {
return _geom;
}
// A DynamicTextGlyph must make a copy of its GeomTextGlyph, so that
// it will increase the reference count properly.
return _geom->make_copy();
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextGlyph::get_row
// Access: Public

View File

@ -45,7 +45,6 @@ private:
public:
virtual ~DynamicTextGlyph();
virtual PT(Geom) get_geom() const;
INLINE bool intersects(int x, int y, int x_size, int y_size) const;
unsigned char *get_row(int y);

View File

@ -162,9 +162,7 @@ write(ostream &out, int indent_level) const {
// printable glyph.
////////////////////////////////////////////////////////////////////
bool StaticTextFont::
get_glyph(int character, const TextGlyph *&glyph, float &glyph_scale) {
glyph_scale = 1.0f;
get_glyph(int character, const TextGlyph *&glyph) {
Glyphs::const_iterator gi = _glyphs.find(character);
if (gi == _glyphs.end()) {
// No definition for this character.

View File

@ -47,8 +47,7 @@ PUBLISHED:
virtual void write(ostream &out, int indent_level) const;
public:
virtual bool get_glyph(int character, const TextGlyph *&glyph,
float &glyph_scale);
virtual bool get_glyph(int character, const TextGlyph *&glyph);
private:
void find_character_gsets(PandaNode *root, Geom *&ch, GeomPoint *&dot,

View File

@ -78,14 +78,13 @@ calc_width(int character) {
}
const TextGlyph *glyph;
float glyph_scale;
get_glyph(character, glyph, glyph_scale);
get_glyph(character, glyph);
if (glyph == (TextGlyph *)NULL) {
// Unknown character.
return 0.0f;
}
return glyph->get_advance() * glyph_scale;
return glyph->get_advance();
}
////////////////////////////////////////////////////////////////////

View File

@ -65,8 +65,7 @@ public:
wstring wordwrap_to(const wstring &text, float wordwrap_width,
bool preserve_trailing_whitespace);
virtual bool get_glyph(int character, const TextGlyph *&glyph,
float &glyph_scale)=0;
virtual bool get_glyph(int character, const TextGlyph *&glyph)=0;
protected:
bool _is_valid;

View File

@ -67,6 +67,24 @@ operator = (const TextGlyph &copy) {
_advance = copy._advance;
}
////////////////////////////////////////////////////////////////////
// Function: TextGlyph::get_geom
// Access: Public
// Description: Returns a Geom that renders the particular glyph.
////////////////////////////////////////////////////////////////////
INLINE PT(Geom) TextGlyph::
get_geom() const {
if (_geom == (Geom *)NULL) {
return _geom;
}
// We always return a copy of the geom. That will allow the caller
// to modify its vertices without fear of stomping on other copies;
// it is also critical for the DynamicTextGlyph, which depends on
// this behavior to properly count references to this glyph.
return _geom->make_copy();
}
////////////////////////////////////////////////////////////////////
// Function: TextGlyph::get_state
// Access: Public

View File

@ -20,27 +20,9 @@
////////////////////////////////////////////////////////////////////
// Function: TextGlyph::Destructor
// Access: Public, Virtual
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
TextGlyph::
~TextGlyph() {
}
////////////////////////////////////////////////////////////////////
// Function: TextGlyph::get_geom
// Access: Public, Virtual
// Description: Returns a Geom that renders the particular glyph.
////////////////////////////////////////////////////////////////////
PT(Geom) TextGlyph::
get_geom() const {
if (_geom == (Geom *)NULL) {
return _geom;
}
// We always return a copy of the geom. That will allow the caller
// to modify its vertices without fear of stomping on other copies;
// it is also critical for the DynamicTextGlyph, which depends on
// this behavior to properly count references to this glyph.
return _geom->make_copy();
}

View File

@ -39,7 +39,7 @@ public:
INLINE void operator = (const TextGlyph &copy);
virtual ~TextGlyph();
virtual PT(Geom) get_geom() const;
INLINE PT(Geom) get_geom() const;
INLINE const RenderState *get_state() const;
INLINE float get_advance() const;

View File

@ -202,6 +202,74 @@ get_line_height() const {
return 0.0f;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::set_small_caps
// Access: Published
// Description: Sets the small_caps flag. When this is set,
// lowercase letters are generated as scaled-down
// versions of their uppercase equivalents. This is
// particularly useful to set for fonts that do not have
// lowercase letters.
//
// It is also a good idea to set this for a (dynamic)
// font that has already implemented lowercase letters
// as scaled-down versions of their uppercase
// equivalents, since without this flag the texture
// memory may needlessly duplicate equivalent glyphs for
// upper and lowercase letters. Setting this flag
// causes the texture memory to share the mixed-case
// letters.
//
// The amount by which the lowercase letters are scaled
// is specified by set_small_caps_scale().
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
set_small_caps(bool small_caps) {
if (small_caps) {
_flags |= F_small_caps;
} else {
_flags &= ~F_small_caps;
}
invalidate_with_measure();
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::get_small_caps
// Access: Published
// Description: Returns the small_caps flag. See set_small_caps().
////////////////////////////////////////////////////////////////////
INLINE bool TextNode::
get_small_caps() const {
return (_flags & F_small_caps) != 0;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::set_small_caps_scale
// Access: Published
// Description: Sets the scale factor applied to lowercase letters
// from their uppercase equivalents, when the small_caps
// flag is in effect. See set_small_caps(). Normally,
// this will be a number less than one.
////////////////////////////////////////////////////////////////////
INLINE void TextNode::
set_small_caps_scale(float small_caps_scale) {
_small_caps_scale = small_caps_scale;
invalidate_with_measure();
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::get_small_caps_scale
// Access: Published
// Description: Returns the scale factor applied to lowercase letters
// from their uppercase equivalents, when the small_caps
// flag is in effect. See set_small_caps() and
// set_small_caps_scale().
////////////////////////////////////////////////////////////////////
INLINE float TextNode::
get_small_caps_scale() const {
return _small_caps_scale;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::set_slant
// Access: Published
@ -1156,6 +1224,30 @@ get_char(int index) const {
return _wtext[index];
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::get_text_as_ascii
// Access: Published
// Description: Returns the text associated with the node, converted
// as nearly as possible to a fully-ASCII
// representation. This means replacing accented
// letters with their unaccented ASCII equivalents.
//
// It is possible that some characters in the string
// cannot be converted to ASCII. (The string may
// involve symbols like the copyright symbol, for
// instance, or it might involve letters in some other
// alphabet such as Greek or Cyrillic, or even Latin
// letters like thorn or eth that are not part of the
// ASCII character set.) In this case, as much of the
// string as possible will be converted to ASCII, and
// the nonconvertible characters will remain encoded in
// the encoding specified by set_encoding().
////////////////////////////////////////////////////////////////////
INLINE string TextNode::
get_text_as_ascii() const {
return encode_wtext(get_wtext_as_ascii());
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::calc_width
// Access: Published

View File

@ -23,6 +23,7 @@
#include "fontPool.h"
#include "default_font.h"
#include "dynamicTextFont.h"
#include "unicodeLatinMap.h"
#include "compose_matrix.h"
#include "geom.h"
@ -54,6 +55,13 @@ PT(TextFont) TextNode::_default_font;
bool TextNode::_loaded_default_font = false;
TextNode::Encoding TextNode::_default_encoding;
// This is the factor by which CP_tiny scales the character down.
static const float tiny_accent_scale = 0.3f;
// This is the factor by which the advance is reduced for the first
// character of a two-character ligature.
static const float ligature_advance_scale = 0.6f;
////////////////////////////////////////////////////////////////////
// Function: TextNode::Constructor
// Access: Published
@ -71,6 +79,11 @@ TextNode(const string &name) : PandaNode(name) {
_align = A_left;
_wordwrap_width = 1.0f;
if (text_small_caps) {
_flags |= F_small_caps;
}
_small_caps_scale = text_small_caps_scale;
_text_color.set(1.0f, 1.0f, 1.0f, 1.0f);
_frame_color.set(1.0f, 1.0f, 1.0f, 1.0f);
_card_color.set(1.0f, 1.0f, 1.0f, 1.0f);
@ -397,6 +410,49 @@ generate() {
return root;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::get_wtext_as_ascii
// Access: Published
// Description: Returns the text associated with the node, converted
// as nearly as possible to a fully-ASCII
// representation. This means replacing accented
// letters with their unaccented ASCII equivalents.
//
// It is possible that some characters in the string
// cannot be converted to ASCII. (The string may
// involve symbols like the copyright symbol, for
// instance, or it might involve letters in some other
// alphabet such as Greek or Cyrillic, or even Latin
// letters like thorn or eth that are not part of the
// ASCII character set.) In this case, as much of the
// string as possible will be converted to ASCII, and
// the nonconvertible characters will remain in their
// original form.
////////////////////////////////////////////////////////////////////
wstring TextNode::
get_wtext_as_ascii() const {
get_wtext();
wstring result;
wstring::const_iterator si;
for (si = _wtext.begin(); si != _wtext.end(); ++si) {
wchar_t character = (*si);
const UnicodeLatinMap::Entry *map_entry =
UnicodeLatinMap::look_up(character);
if (map_entry != NULL && map_entry->_ascii_equiv != 0) {
result += (wchar_t)map_entry->_ascii_equiv;
if (map_entry->_ascii_additional != 0) {
result += (wchar_t)map_entry->_ascii_additional;
}
} else {
result += character;
}
}
return result;
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::encode_wchar
// Access: Public
@ -870,7 +926,8 @@ do_measure() {
_ul3d = _ul3d * _transform;
_lr3d = _lr3d * _transform;
}
#ifndef CPPPARSER // interrogate has a bit of trouble with wstring.
////////////////////////////////////////////////////////////////////
@ -895,10 +952,18 @@ assemble_row(wstring::iterator &si, const wstring::iterator &send,
} else {
// A printable character.
bool got_glyph;
const TextGlyph *glyph;
const TextGlyph *second_glyph;
UnicodeLatinMap::AccentType accent_type;
int additional_flags;
float glyph_scale;
if (!font->get_glyph(character, glyph, glyph_scale)) {
float advance_scale;
get_character_glyphs(character, font,
got_glyph, glyph, second_glyph, accent_type,
additional_flags, glyph_scale, advance_scale);
if (!got_glyph) {
text_cat.warning()
<< "No definition in " << font->get_name()
<< " for character " << character;
@ -910,35 +975,87 @@ assemble_row(wstring::iterator &si, const wstring::iterator &send,
<< "\n";
}
// Build up a temporary array of the Geoms that go into this
// character. Normally, there is only one Geom per character,
// but it may involve multiple Geoms if we need to add cheesy
// accents or ligatures.
static const int max_geoms = 10;
Geom *geom_array[max_geoms];
int num_geoms = 0;
int gi;
float advance = 0.0f;
if (glyph != (TextGlyph *)NULL) {
PT(Geom) char_geom = glyph->get_geom();
const RenderState *state = glyph->get_state();
if (char_geom != (Geom *)NULL) {
LMatrix4f mat2 = LMatrix4f::scale_mat(glyph_scale);
mat2.set_row(3, LVector3f(xpos, 0.0f, 0.0f));
LMatrix4f xform = mat2 * mat;
dest->add_geom(char_geom, glyph->get_state());
geom_array[num_geoms++] = char_geom;
}
advance = glyph->get_advance() * advance_scale;
}
if (second_glyph != (TextGlyph *)NULL) {
PT(Geom) second_char_geom = second_glyph->get_geom();
if (second_char_geom != (Geom *)NULL) {
second_char_geom->transform_vertices(LMatrix4f::translate_mat(advance, 0.0f, 0.0f));
dest->add_geom(second_char_geom, second_glyph->get_state());
geom_array[num_geoms++] = second_char_geom;
}
advance += second_glyph->get_advance();
}
// Transform the vertices of the geom appropriately. We
// assume the geom is non-indexed.
PTA_Vertexf coords;
PTA_ushort index;
char_geom->get_coords(coords, index);
PTA_Vertexf new_coords;
new_coords.reserve(coords.size());
PTA_Vertexf::const_iterator vi;
for (vi = coords.begin(); vi != coords.end(); ++vi) {
new_coords.push_back((*vi) * xform);
}
nassertr(new_coords.size() == coords.size(), false);
char_geom->set_coords(new_coords);
// Now compute the matrix that will transform the glyph (or
// glyphs) into position.
LMatrix4f glyph_xform = LMatrix4f::scale_mat(glyph_scale);
// Now add the geom to the destination node.
dest->add_geom(char_geom, state);
if (accent_type != UnicodeLatinMap::AT_none || additional_flags != 0) {
// If we have some special handling to perform, do so now.
// This will probably require the bounding volume of the
// glyph, so go get that.
LPoint3f min_vert, max_vert;
bool found_any = false;
for (gi = 0; gi < num_geoms; gi++) {
geom_array[gi]->calc_tight_bounds(min_vert, max_vert, found_any);
}
xpos += glyph->get_advance() * glyph_scale;
if (found_any) {
LPoint3f centroid = (min_vert + max_vert) / 2.0f;
tack_on_accent(accent_type, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
if ((additional_flags & UnicodeLatinMap::AF_turned) != 0) {
// Invert the character. Should we also invert the accent
// mark, so that an accent that would have been above the
// glyph will now be below it? That's what we do here,
// which is probably the right thing to do for n-tilde,
// but not for most of the rest of the accent marks. For
// now we'll assume there are no characters with accent
// marks that also have the turned flag.
// We rotate the character around its centroid, which may
// not always be the right point, but it's the best we've
// got and it's probably pretty close.
LMatrix4f rotate =
LMatrix4f::translate_mat(-centroid) *
LMatrix4f::rotate_mat_normaxis(180.0f, LVecBase3f(0.0f, 1.0f, 0.0f)) *
LMatrix4f::translate_mat(centroid);
glyph_xform *= rotate;
}
}
}
glyph_xform(3, 0) += xpos;
LMatrix4f net_xform = glyph_xform * mat;
// Finally, transform all the Geoms for this character into
// place. Again, normally there is only one Geom per character;
// there will only be multiple Geoms if we have added accents or
// ligatures.
for (gi = 0; gi < num_geoms; gi++) {
geom_array[gi]->transform_vertices(net_xform);
}
xpos += advance * glyph_scale;
}
++si;
}
@ -1035,13 +1152,27 @@ measure_row(wstring::iterator &si, const wstring::iterator &send,
} else {
// A printable character.
bool got_glyph;
const TextGlyph *glyph;
const TextGlyph *second_glyph;
UnicodeLatinMap::AccentType accent_type;
int additional_flags;
float glyph_scale;
font->get_glyph(character, glyph, glyph_scale);
float advance_scale;
get_character_glyphs(character, font,
got_glyph, glyph, second_glyph, accent_type,
additional_flags, glyph_scale, advance_scale);
float advance = 0.0f;
if (glyph != (TextGlyph *)NULL) {
xpos += glyph->get_advance() * glyph_scale;
advance = glyph->get_advance() * advance_scale;
}
if (second_glyph != (TextGlyph *)NULL) {
advance += second_glyph->get_advance();
}
xpos += advance * glyph_scale;
}
++si;
}
@ -1092,6 +1223,356 @@ measure_text(wstring::iterator si, const wstring::iterator &send,
}
#endif // CPPPARSER
////////////////////////////////////////////////////////////////////
// Function: TextNode::get_character_glyphs
// Access: Private
// Description: Looks up the glyph(s) from the font for the
// appropriate character. If the desired glyph isn't
// available (especially in the case of an accented
// letter), tries to find a suitable replacement.
// Normally, only one glyph is returned per character,
// but in the case we have to simulate a missing
// ligature in the font, two glyphs might be returned.
//
// All parameters except the first two are output
// parameters. got_glyph is set true if the glyph (or
// an acceptable substitute) is successfully found,
// false otherwise; but even if it is false, glyph might
// still be non-NULL, indicating a stand-in glyph for a
// missing character.
////////////////////////////////////////////////////////////////////
void TextNode::
get_character_glyphs(int character, TextFont *font,
bool &got_glyph, const TextGlyph *&glyph,
const TextGlyph *&second_glyph,
UnicodeLatinMap::AccentType &accent_type,
int &additional_flags,
float &glyph_scale, float &advance_scale) {
got_glyph = false;
glyph = NULL;
second_glyph = NULL;
accent_type = UnicodeLatinMap::AT_none;
additional_flags = 0;
glyph_scale = 1.0f;
advance_scale = 1.0f;
// Maybe we should remap the character to something else--e.g. a
// small capital.
const UnicodeLatinMap::Entry *map_entry =
UnicodeLatinMap::look_up(character);
if (map_entry != NULL) {
if (get_small_caps() && map_entry->_toupper_character != character) {
character = map_entry->_toupper_character;
map_entry = UnicodeLatinMap::look_up(character);
glyph_scale = get_small_caps_scale();
}
}
got_glyph = font->get_glyph(character, glyph);
if (!got_glyph && map_entry != NULL && map_entry->_ascii_equiv != 0) {
// If we couldn't find the Unicode glyph, try the ASCII
// equivalent (without the accent marks).
got_glyph = font->get_glyph(map_entry->_ascii_equiv, glyph);
if (!got_glyph && map_entry->_toupper_character != character) {
// If we still couldn't find it, try the uppercase
// equivalent.
character = map_entry->_toupper_character;
map_entry = UnicodeLatinMap::look_up(character);
if (map_entry != NULL) {
got_glyph = font->get_glyph(map_entry->_ascii_equiv, glyph);
}
}
if (got_glyph) {
accent_type = map_entry->_accent_type;
additional_flags = map_entry->_additional_flags;
bool got_second_glyph = false;
if (map_entry->_ascii_additional != 0) {
// There's another character, too--probably a ligature.
got_second_glyph =
font->get_glyph(map_entry->_ascii_additional, second_glyph);
}
if ((additional_flags & UnicodeLatinMap::AF_ligature) != 0 &&
got_second_glyph) {
// If we have two letters that are supposed to be in a
// ligature, just jam them together.
additional_flags &= ~UnicodeLatinMap::AF_ligature;
advance_scale = ligature_advance_scale;
}
if ((additional_flags & UnicodeLatinMap::AF_smallcap) != 0) {
additional_flags &= ~UnicodeLatinMap::AF_smallcap;
glyph_scale = get_small_caps_scale();
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::tack_on_accent
// Access: Private
// Description: This is a cheesy attempt to tack on an accent to an
// ASCII letter for which we don't have the appropriate
// already-accented glyph in the font.
////////////////////////////////////////////////////////////////////
void TextNode::
tack_on_accent(UnicodeLatinMap::AccentType accent_type,
const LPoint3f &min_vert, const LPoint3f &max_vert,
const LPoint3f &centroid,
TextFont *font, GeomNode *dest,
Geom *geom_array[], int &num_geoms) {
switch (accent_type) {
case UnicodeLatinMap::AT_grave:
// We use the slash as the grave and acute accents. ASCII does
// have a grave accent character, but a lot of fonts put the
// reverse apostrophe there instead. And some fonts (particularly
// fonts from mf) don't even do backslash.
tack_on_accent('/', CP_above, CT_tiny_mirror_x, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_acute:
tack_on_accent('/', CP_above, CT_tiny, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_breve:
tack_on_accent(')', CP_above, CT_tiny_rotate_90, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_inverted_breve:
tack_on_accent('(', CP_above, CT_tiny_rotate_90, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_circumflex:
tack_on_accent('^', CP_above, CT_none, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_circumflex_below:
tack_on_accent('^', CP_below, CT_none, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_caron:
tack_on_accent('^', CP_above, CT_mirror_y, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_tilde:
tack_on_accent('~', CP_above, CT_none, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_tilde_below:
tack_on_accent('~', CP_below, CT_none, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_diaeresis:
tack_on_accent(':', CP_above, CT_rotate_90, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_diaeresis_below:
tack_on_accent(':', CP_below, CT_rotate_90, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_dot_above:
tack_on_accent('.', CP_above, CT_none, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_dot_below:
tack_on_accent('.', CP_below, CT_none, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_macron:
tack_on_accent('-', CP_above, CT_none, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_line_below:
tack_on_accent('-', CP_below, CT_none, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_ring_above:
tack_on_accent('o', CP_top, CT_tiny, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_ring_below:
tack_on_accent('o', CP_bottom, CT_tiny, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_cedilla:
tack_on_accent(',', CP_bottom, CT_none, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_comma_below:
tack_on_accent(',', CP_below, CT_none, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_ogonek:
tack_on_accent(',', CP_bottom, CT_mirror_x, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
case UnicodeLatinMap::AT_stroke:
tack_on_accent('/', CP_within, CT_none, min_vert, max_vert, centroid,
font, dest, geom_array, num_geoms);
break;
default:
// There are lots of other crazy kinds of accents. Forget 'em.
break;
}
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::tack_on_accent
// Access: Private
// Description: Generates a cheesy accent mark above (or below, etc.)
// the character.
////////////////////////////////////////////////////////////////////
void TextNode::
tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement,
TextNode::CheesyTransform transform,
const LPoint3f &min_vert, const LPoint3f &max_vert,
const LPoint3f &centroid,
TextFont *font, GeomNode *dest,
Geom *geom_array[], int &num_geoms) {
TextGlyph *accent_glyph;
if (font->get_glyph(accent_mark, accent_glyph)) {
PT(Geom) accent_geom = accent_glyph->get_geom();
if (accent_geom != (Geom *)NULL) {
LPoint3f min_accent, max_accent;
bool found_any = false;
accent_geom->calc_tight_bounds(min_accent, max_accent, found_any);
if (found_any) {
float t, u;
LMatrix4f accent_mat;
switch (transform) {
case CT_none:
accent_mat = LMatrix4f::ident_mat();
break;
case CT_mirror_x:
accent_mat = LMatrix4f::scale_mat(-1.0f, 1.0f, 1.0f);
t = -min_accent[0];
min_accent[0] = -max_accent[0];
max_accent[0] = t;
break;
case CT_mirror_y:
accent_mat = LMatrix4f::scale_mat(1.0f, -1.0f, 1.0f);
t = -min_accent[2];
min_accent[2] = -max_accent[2];
max_accent[2] = t;
break;
case CT_rotate_90:
accent_mat =
LMatrix4f::rotate_mat_normaxis(90.0f, LVecBase3f(0.0f, 1.0f, 0.0f));
// rotate min, max
t = min_accent[0];
u = max_accent[0];
min_accent[0] = min_accent[2];
max_accent[0] = max_accent[2];
min_accent[2] = -u;
max_accent[2] = -t;
break;
case CT_tiny:
accent_mat = LMatrix4f::scale_mat(tiny_accent_scale);
min_accent *= tiny_accent_scale;
max_accent *= tiny_accent_scale;
break;
case CT_tiny_mirror_x:
accent_mat = LMatrix4f::scale_mat(-tiny_accent_scale, 1.0f, tiny_accent_scale);
t = -min_accent[0] * tiny_accent_scale;
min_accent[0] = -max_accent[0] * tiny_accent_scale;
max_accent[0] = t;
break;
case CT_tiny_rotate_90:
accent_mat =
LMatrix4f::rotate_mat_normaxis(90.0f, LVecBase3f(0.0f, 1.0f, 0.0f)) *
LMatrix4f::scale_mat(tiny_accent_scale);
// rotate min, max
t = min_accent[0];
u = max_accent[0];
min_accent[0] = min_accent[2] * tiny_accent_scale;
max_accent[0] = max_accent[2] * tiny_accent_scale;
min_accent[2] = -u * tiny_accent_scale;
max_accent[2] = -t * tiny_accent_scale;
break;
}
LPoint3f accent_centroid = (min_accent + max_accent) / 2.0f;
float accent_height = max_accent[2] - min_accent[2];
LVector3f trans;
switch (placement) {
case CP_above:
// A little above the character.
trans.set(centroid[0] - accent_centroid[0], 0.0f,
max_vert[2] - accent_centroid[2] + accent_height * 0.5);
break;
case CP_below:
// A little below the character.
trans.set(centroid[0] - accent_centroid[0], 0.0f,
min_vert[2] - accent_centroid[2] - accent_height * 0.5);
break;
case CP_top:
// Touching the top of the character.
trans.set(centroid[0] - accent_centroid[0], 0.0f,
max_vert[2] - accent_centroid[2]);
break;
case CP_bottom:
// Touching the bottom of the character.
trans.set(centroid[0] - accent_centroid[0], 0.0f,
min_vert[2] - accent_centroid[2]);
break;
case CP_within:
// Centered within the character.
trans.set(centroid[0] - accent_centroid[0], 0.0f,
centroid[2] - accent_centroid[2]);
break;
}
accent_mat.set_row(3, trans);
accent_geom->transform_vertices(accent_mat);
dest->add_geom(accent_geom, accent_glyph->get_state());
geom_array[num_geoms++] = accent_geom;
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::make_frame
// Access: Private

View File

@ -23,8 +23,8 @@
#include "config_text.h"
#include "textFont.h"
#include "unicodeLatinMap.h"
#include "pandaNode.h"
#include "luse.h"
class StringDecoder;
@ -89,6 +89,11 @@ PUBLISHED:
INLINE float get_line_height() const;
INLINE void set_small_caps(bool small_caps);
INLINE bool get_small_caps() const;
INLINE void set_small_caps_scale(float small_caps_scale);
INLINE float get_small_caps_scale() const;
INLINE void set_slant(float slant);
INLINE float get_slant() const;
@ -182,6 +187,7 @@ PUBLISHED:
INLINE void append_char(int character);
INLINE int get_num_chars() const;
INLINE int get_char(int index) const;
INLINE string get_text_as_ascii() const;
INLINE float calc_width(int character) const;
INLINE float calc_width(const string &line) const;
@ -213,6 +219,7 @@ public:
INLINE void set_wtext(const wstring &wtext);
INLINE const wstring &get_wtext() const;
INLINE void append_wtext(const wstring &text);
wstring get_wtext_as_ascii() const;
INLINE float calc_width(const wstring &line) const;
INLINE wstring wordwrap_to(const wstring &wtext, float wordwrap_width,
@ -262,6 +269,42 @@ private:
LVector2f &ul, LVector2f &lr, int &num_rows);
#endif // CPPPARSER
enum CheesyPlacement {
CP_above,
CP_below,
CP_top,
CP_bottom,
CP_within,
};
enum CheesyTransform {
CT_none,
CT_mirror_x,
CT_mirror_y,
CT_rotate_90,
CT_tiny,
CT_tiny_mirror_x,
CT_tiny_rotate_90,
};
void get_character_glyphs(int character, TextFont *font,
bool &got_glyph, const TextGlyph *&glyph,
const TextGlyph *&second_glyph,
UnicodeLatinMap::AccentType &accent_type,
int &additional_flags,
float &glyph_scale, float &advance_scale);
void tack_on_accent(UnicodeLatinMap::AccentType accent_type,
const LPoint3f &min_vert, const LPoint3f &max_vert,
const LPoint3f &centroid,
TextFont *font, GeomNode *dest,
Geom *geom_array[], int &num_geoms);
void tack_on_accent(char accent_mark, CheesyPlacement placement,
CheesyTransform transform,
const LPoint3f &min_vert, const LPoint3f &max_vert,
const LPoint3f &centroid,
TextFont *font, GeomNode *dest,
Geom *geom_array[], int &num_geoms);
PT(PandaNode) make_frame();
PT(PandaNode) make_card();
PT(PandaNode) make_card_with_border();
@ -281,22 +324,23 @@ private:
Colorf _card_color;
enum Flags {
F_has_text_color = 0x0001,
F_has_wordwrap = 0x0002,
F_has_frame = 0x0004,
F_frame_as_margin = 0x0008,
F_has_card = 0x0010,
F_card_as_margin = 0x0020,
F_has_card_texture = 0x0040,
F_has_shadow = 0x0080,
F_frame_corners = 0x0100,
F_card_transp = 0x0200,
F_has_card_border = 0x0400,
F_expand_amp = 0x0800,
F_got_text = 0x1000,
F_got_wtext = 0x2000,
F_needs_rebuild = 0x4000,
F_needs_measure = 0x8000,
F_has_text_color = 0x00000001,
F_has_wordwrap = 0x00000002,
F_has_frame = 0x00000004,
F_frame_as_margin = 0x00000008,
F_has_card = 0x00000010,
F_card_as_margin = 0x00000020,
F_has_card_texture = 0x00000040,
F_has_shadow = 0x00000080,
F_frame_corners = 0x00000100,
F_card_transp = 0x00000200,
F_has_card_border = 0x00000400,
F_expand_amp = 0x00000800,
F_got_text = 0x00001000,
F_got_wtext = 0x00002000,
F_needs_rebuild = 0x00004000,
F_needs_measure = 0x00008000,
F_small_caps = 0x00010000,
};
int _flags;
@ -305,6 +349,7 @@ private:
float _frame_width;
float _card_border_size;
float _card_border_uv_portion;
float _small_caps_scale;
LVector2f _frame_ul, _frame_lr;
LVector2f _card_ul, _card_lr;

View File

@ -9,3 +9,4 @@
#include "stringDecoder.cxx"
#include "textFont.cxx"
#include "textGlyph.cxx"
#include "unicodeLatinMap.cxx"

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,146 @@
// Filename: unicodeLatinMap.h
// Created by: drose (01Feb03)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef UNICODELATINMAP_H
#define UNICODELATINMAP_H
#include "pandabase.h"
#include "pmap.h"
////////////////////////////////////////////////////////////////////
// Class : UnicodeLatinMap
// Description : This class mainly serves as a container for a largish
// table of the subset of the Unicode character set that
// corresponds to the Latin alphabet, with its various
// accent marks and so on. Specifically, this table
// indicates how to map between the Unicode accented
// character and the corresponding ASCII equivalent
// without the accent mark; as well as how to switch
// case from upper to lower while retaining the Unicode
// accent marks.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA UnicodeLatinMap {
public:
enum AccentType {
AT_none,
AT_acute,
AT_acute_and_dot_above,
AT_breve,
AT_breve_and_acute,
AT_breve_and_dot_below,
AT_breve_and_grave,
AT_breve_and_hook_above,
AT_breve_and_tilde,
AT_breve_below,
AT_caron,
AT_caron_and_dot_above,
AT_cedilla,
AT_cedilla_and_acute,
AT_cedilla_and_breve,
AT_circumflex,
AT_circumflex_and_acute,
AT_circumflex_and_dot_below,
AT_circumflex_and_grave,
AT_circumflex_and_hook_above,
AT_circumflex_and_tilde,
AT_circumflex_below,
AT_comma_below,
AT_curl,
AT_diaeresis,
AT_diaeresis_and_acute,
AT_diaeresis_and_caron,
AT_diaeresis_and_grave,
AT_diaeresis_and_macron,
AT_diaeresis_below,
AT_dot_above,
AT_dot_above_and_macron,
AT_dot_below,
AT_dot_below_and_dot_above,
AT_dot_below_and_macron,
AT_double_acute,
AT_double_grave,
AT_grave,
AT_hook,
AT_hook_above,
AT_horn,
AT_horn_and_acute,
AT_horn_and_dot_below,
AT_horn_and_grave,
AT_horn_and_hook_above,
AT_horn_and_tilde,
AT_inverted_breve,
AT_line_below,
AT_macron,
AT_macron_and_acute,
AT_macron_and_diaeresis,
AT_macron_and_grave,
AT_ogonek,
AT_ogonek_and_macron,
AT_ring_above,
AT_ring_above_and_acute,
AT_ring_below,
AT_stroke,
AT_stroke_and_acute,
AT_stroke_and_hook,
AT_tilde,
AT_tilde_and_acute,
AT_tilde_and_diaeresis,
AT_tilde_and_macron,
AT_tilde_below,
AT_topbar,
};
enum AdditionalFlags {
AF_ligature = 0x0001,
AF_turned = 0x0002,
AF_reversed = 0x0004,
AF_smallcap = 0x0008,
AF_dotless = 0x0010,
};
enum CharType {
CT_upper,
CT_lower,
CT_punct,
};
class Entry {
public:
wchar_t _character;
CharType _char_type;
char _ascii_equiv;
char _ascii_additional;
wchar_t _tolower_character;
wchar_t _toupper_character;
AccentType _accent_type;
int _additional_flags;
};
static const Entry *look_up(wchar_t character);
private:
static void init();
static bool _initialized;
typedef pmap<wchar_t, const Entry *> ByCharacter;
static ByCharacter _by_character;
enum { max_direct_chars = 256 };
static const Entry *_direct_chars[max_direct_chars];
};
#endif