Overhaul text generation; now 75x as fast as before.
This commit is contained in:
parent
0fffcdfc6b
commit
a453ec1925
|
|
@ -369,6 +369,8 @@ static const UnicodeLatinMap::Entry latin_map[] = {
|
|||
UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_reversed },
|
||||
{ 0x0258, UnicodeLatinMap::CT_lower, 'e', 0, 0x0258, 0x018e,
|
||||
UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_reversed },
|
||||
{ 0x0259, UnicodeLatinMap::CT_lower, 'e', 0, 0x0259, 0x018f,
|
||||
UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_turned },
|
||||
{ 0x0066, UnicodeLatinMap::CT_lower, 'f', 0, 0x0066, 0x0046,
|
||||
UnicodeLatinMap::AT_none, 0 },
|
||||
{ 0x0046, UnicodeLatinMap::CT_upper, 'F', 0, 0x0066, 0x0046,
|
||||
|
|
@ -465,7 +467,9 @@ static const UnicodeLatinMap::Entry latin_map[] = {
|
|||
UnicodeLatinMap::AT_line_below, 0 },
|
||||
{ 0x029c, UnicodeLatinMap::CT_upper, 'H', 0, 0x0068, 0x029c,
|
||||
UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_smallcap },
|
||||
{ 0x0195, UnicodeLatinMap::CT_lower, 'h', 'v', 0x0195, 0x195,
|
||||
{ 0x0195, UnicodeLatinMap::CT_lower, 'h', 'v', 0x0195, 0x01f6,
|
||||
UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_ligature },
|
||||
{ 0x01f6, UnicodeLatinMap::CT_upper, 'H', 'v', 0x0195, 0x01f6,
|
||||
UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_ligature },
|
||||
{ 0x0127, UnicodeLatinMap::CT_lower, 'h', 0, 0x0127, 0x0126,
|
||||
UnicodeLatinMap::AT_stroke, 0 },
|
||||
|
|
|
|||
|
|
@ -162,7 +162,7 @@ update_type(To *ptr) {
|
|||
// (Assignment to a NULL pointer also works, of course.)
|
||||
////////////////////////////////////////////////////////////////////
|
||||
template<class T>
|
||||
INLINE void PointerToBase<T>::
|
||||
ALWAYS_INLINE void PointerToBase<T>::
|
||||
clear() {
|
||||
reassign((To *)NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -55,7 +55,7 @@ protected:
|
|||
// vs. non-const later.
|
||||
|
||||
PUBLISHED:
|
||||
INLINE void clear();
|
||||
ALWAYS_INLINE void clear();
|
||||
|
||||
void output(ostream &out) const;
|
||||
};
|
||||
|
|
|
|||
|
|
@ -50,7 +50,7 @@ PointerToVoid(const PointerToVoid &) {
|
|||
// false otherwise. (Direct comparison to a NULL
|
||||
// pointer also works.)
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool PointerToVoid::
|
||||
ALWAYS_INLINE bool PointerToVoid::
|
||||
is_null() const {
|
||||
return (_void_ptr == (void *)NULL);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,7 +42,7 @@ private:
|
|||
INLINE PointerToVoid(const PointerToVoid ©);
|
||||
|
||||
PUBLISHED:
|
||||
INLINE bool is_null() const;
|
||||
ALWAYS_INLINE bool is_null() const;
|
||||
INLINE size_t get_hash() const;
|
||||
|
||||
public:
|
||||
|
|
|
|||
|
|
@ -260,8 +260,18 @@ get_poly_margin() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void DynamicTextFont::
|
||||
set_page_size(int x_size, int y_size) {
|
||||
_page_x_size = x_size;
|
||||
_page_y_size = y_size;
|
||||
_page_size.set(x_size, y_size);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::get_page_size
|
||||
// Access: Published
|
||||
// Description: Returns the size of the textures that are created
|
||||
// for the DynamicTextFont. See set_page_size().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVecBase2i &DynamicTextFont::
|
||||
get_page_size() const {
|
||||
return _page_size;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -272,7 +282,7 @@ set_page_size(int x_size, int y_size) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int DynamicTextFont::
|
||||
get_page_x_size() const {
|
||||
return _page_x_size;
|
||||
return _page_size.get_x();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -283,7 +293,7 @@ get_page_x_size() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int DynamicTextFont::
|
||||
get_page_y_size() const {
|
||||
return _page_y_size;
|
||||
return _page_size.get_y();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -44,6 +44,8 @@
|
|||
#include "nurbsCurveResult.h"
|
||||
//#include "renderModeAttrib.h"
|
||||
//#include "antialiasAttrib.h"
|
||||
#include "colorAttrib.h"
|
||||
#include "textureAttrib.h"
|
||||
|
||||
TypeHandle DynamicTextFont::_type_handle;
|
||||
|
||||
|
|
@ -110,8 +112,7 @@ DynamicTextFont(const DynamicTextFont ©) :
|
|||
FreetypeFont(copy),
|
||||
_texture_margin(copy._texture_margin),
|
||||
_poly_margin(copy._poly_margin),
|
||||
_page_x_size(copy._page_x_size),
|
||||
_page_y_size(copy._page_y_size),
|
||||
_page_size(copy._page_size),
|
||||
_minfilter(copy._minfilter),
|
||||
_magfilter(copy._magfilter),
|
||||
_anisotropic_degree(copy._anisotropic_degree),
|
||||
|
|
@ -194,8 +195,8 @@ garbage_collect() {
|
|||
Cache new_cache;
|
||||
Cache::iterator ci;
|
||||
for (ci = _cache.begin(); ci != _cache.end(); ++ci) {
|
||||
DynamicTextGlyph *glyph = (*ci).second;
|
||||
if (glyph == (DynamicTextGlyph *)NULL || glyph->_geom_count != 0) {
|
||||
TextGlyph *glyph = (*ci).second;
|
||||
if (glyph == (TextGlyph *)NULL || glyph->get_ref_count() > 1) {
|
||||
// Keep this one.
|
||||
new_cache.insert(new_cache.end(), (*ci));
|
||||
} else {
|
||||
|
|
@ -252,7 +253,7 @@ write(ostream &out, int indent_level) const {
|
|||
Cache::const_iterator ci;
|
||||
for (ci = _cache.begin(); ci != _cache.end(); ++ci) {
|
||||
int glyph_index = (*ci).first;
|
||||
DynamicTextGlyph *glyph = (*ci).second;
|
||||
TextGlyph *glyph = (*ci).second;
|
||||
indent(out, indent_level + 2)
|
||||
<< glyph_index;
|
||||
|
||||
|
|
@ -269,7 +270,7 @@ write(ostream &out, int indent_level) const {
|
|||
}
|
||||
release_face(face);
|
||||
|
||||
out << ", count = " << glyph->_geom_count << "\n";
|
||||
out << '\n';
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -285,7 +286,7 @@ write(ostream &out, int indent_level) const {
|
|||
// printable glyph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool DynamicTextFont::
|
||||
get_glyph(int character, const TextGlyph *&glyph) {
|
||||
get_glyph(int character, CPT(TextGlyph) &glyph) {
|
||||
if (!_is_valid) {
|
||||
glyph = (TextGlyph *)NULL;
|
||||
return false;
|
||||
|
|
@ -302,12 +303,12 @@ get_glyph(int character, const TextGlyph *&glyph) {
|
|||
if (ci != _cache.end()) {
|
||||
glyph = (*ci).second;
|
||||
} else {
|
||||
DynamicTextGlyph *dynamic_glyph = make_glyph(character, face, glyph_index);
|
||||
TextGlyph *dynamic_glyph = make_glyph(character, face, glyph_index);
|
||||
_cache.insert(Cache::value_type(glyph_index, dynamic_glyph));
|
||||
glyph = dynamic_glyph;
|
||||
}
|
||||
|
||||
if (glyph == (DynamicTextGlyph *)NULL) {
|
||||
if (glyph == (TextGlyph *)NULL) {
|
||||
glyph = get_invalid_glyph();
|
||||
glyph_index = 0;
|
||||
}
|
||||
|
|
@ -327,8 +328,7 @@ void DynamicTextFont::
|
|||
initialize() {
|
||||
_texture_margin = text_texture_margin;
|
||||
_poly_margin = text_poly_margin;
|
||||
_page_x_size = text_page_size[0];
|
||||
_page_y_size = text_page_size[1];
|
||||
_page_size.set(text_page_size[0], text_page_size[1]);
|
||||
|
||||
// We don't necessarily want to use mipmaps, since we don't want to
|
||||
// regenerate those every time the texture changes, but we probably
|
||||
|
|
@ -442,10 +442,10 @@ determine_tex_format() {
|
|||
// newly-created TextGlyph object, or NULL if the
|
||||
// glyph cannot be created for some reason.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DynamicTextGlyph *DynamicTextFont::
|
||||
TextGlyph *DynamicTextFont::
|
||||
make_glyph(int character, FT_Face face, int glyph_index) {
|
||||
if (!load_glyph(face, glyph_index, false)) {
|
||||
return (DynamicTextGlyph *)NULL;
|
||||
return (TextGlyph *)NULL;
|
||||
}
|
||||
|
||||
FT_GlyphSlot slot = face->glyph;
|
||||
|
|
@ -461,6 +461,7 @@ make_glyph(int character, FT_Face face, int glyph_index) {
|
|||
}
|
||||
|
||||
PN_stdfloat advance = slot->advance.x / 64.0;
|
||||
advance /= _font_pixels_per_unit;
|
||||
|
||||
if (_render_mode != RM_texture &&
|
||||
slot->format == ft_glyph_format_outline) {
|
||||
|
|
@ -520,8 +521,8 @@ make_glyph(int character, FT_Face face, int glyph_index) {
|
|||
_contours.clear();
|
||||
FT_Outline_Decompose(&slot->outline, &funcs, (void *)this);
|
||||
|
||||
PT(DynamicTextGlyph) glyph =
|
||||
new DynamicTextGlyph(character, advance / _font_pixels_per_unit);
|
||||
PT(TextGlyph) glyph =
|
||||
new TextGlyph(character, advance);
|
||||
switch (_render_mode) {
|
||||
case RM_wireframe:
|
||||
render_wireframe_contours(glyph);
|
||||
|
|
@ -553,8 +554,8 @@ make_glyph(int character, FT_Face face, int glyph_index) {
|
|||
if (bitmap.width == 0 || bitmap.rows == 0) {
|
||||
// If we got an empty bitmap, it's a special case.
|
||||
|
||||
PT(DynamicTextGlyph) glyph =
|
||||
new DynamicTextGlyph(character, advance / _font_pixels_per_unit);
|
||||
PT(TextGlyph) glyph =
|
||||
new TextGlyph(character, advance);
|
||||
_empty_glyphs.push_back(glyph);
|
||||
return glyph;
|
||||
|
||||
|
|
@ -571,7 +572,7 @@ make_glyph(int character, FT_Face face, int glyph_index) {
|
|||
// If the bitmap produced from the font doesn't require scaling
|
||||
// or any other processing before it goes to the texture, we can
|
||||
// just copy it directly into the texture.
|
||||
glyph = slot_glyph(character, bitmap.width, bitmap.rows);
|
||||
glyph = slot_glyph(character, bitmap.width, bitmap.rows, advance);
|
||||
copy_bitmap_to_texture(bitmap, glyph);
|
||||
|
||||
} else {
|
||||
|
|
@ -599,7 +600,7 @@ make_glyph(int character, FT_Face face, int glyph_index) {
|
|||
int_y_size += outline * 2;
|
||||
tex_x_size += outline * 2;
|
||||
tex_y_size += outline * 2;
|
||||
glyph = slot_glyph(character, int_x_size, int_y_size);
|
||||
glyph = slot_glyph(character, int_x_size, int_y_size, advance);
|
||||
|
||||
if (outline != 0) {
|
||||
// Pad the glyph image to make room for the outline.
|
||||
|
|
@ -612,11 +613,43 @@ make_glyph(int character, FT_Face face, int glyph_index) {
|
|||
}
|
||||
}
|
||||
|
||||
glyph->make_geom((int)floor(slot->bitmap_top + outline * _scale_factor + 0.5f),
|
||||
(int)floor(slot->bitmap_left - outline * _scale_factor + 0.5f),
|
||||
advance, _poly_margin,
|
||||
tex_x_size, tex_y_size,
|
||||
_font_pixels_per_unit, _tex_pixels_per_unit);
|
||||
DynamicTextPage *page = glyph->get_page();
|
||||
if (page != NULL) {
|
||||
int bitmap_top = (int)floor(slot->bitmap_top + outline * _scale_factor + 0.5f);
|
||||
int bitmap_left = (int)floor(slot->bitmap_left - outline * _scale_factor + 0.5f);
|
||||
|
||||
tex_x_size += glyph->_margin * 2;
|
||||
tex_y_size += glyph->_margin * 2;
|
||||
|
||||
// Determine the corners of the rectangle in geometric units.
|
||||
PN_stdfloat tex_poly_margin = _poly_margin / _tex_pixels_per_unit;
|
||||
PN_stdfloat origin_y = bitmap_top / _font_pixels_per_unit;
|
||||
PN_stdfloat origin_x = bitmap_left / _font_pixels_per_unit;
|
||||
|
||||
LVecBase4 dimensions(
|
||||
origin_x - tex_poly_margin,
|
||||
origin_y - tex_y_size / _tex_pixels_per_unit - tex_poly_margin,
|
||||
origin_x + tex_x_size / _tex_pixels_per_unit + tex_poly_margin,
|
||||
origin_y + tex_poly_margin);
|
||||
|
||||
// And the corresponding corners in UV units. We add 0.5f to center
|
||||
// the UV in the middle of its texel, to minimize roundoff errors
|
||||
// when we are close to 1-to-1 pixel size.
|
||||
LVecBase2i page_size = page->get_size();
|
||||
LVecBase4 texcoords(
|
||||
((PN_stdfloat)(glyph->_x - _poly_margin) + 0.5f) / page_size[0],
|
||||
1.0f - ((PN_stdfloat)(glyph->_y + _poly_margin + tex_y_size) + 0.5f) / page_size[1],
|
||||
((PN_stdfloat)(glyph->_x + _poly_margin + tex_x_size) + 0.5f) / page_size[0],
|
||||
1.0f - ((PN_stdfloat)(glyph->_y - _poly_margin) + 0.5f) / page_size[1]);
|
||||
|
||||
CPT(RenderState) state;
|
||||
state = RenderState::make(TextureAttrib::make(page),
|
||||
TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
||||
state = state->add_attrib(ColorAttrib::make_flat(LColor(1.0f, 1.0f, 1.0f, 1.0f)), -1);
|
||||
|
||||
glyph->set_quad(dimensions, texcoords, state);
|
||||
}
|
||||
|
||||
return glyph;
|
||||
}
|
||||
}
|
||||
|
|
@ -835,7 +868,7 @@ blend_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph,
|
|||
// filled in yet except with its size.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DynamicTextGlyph *DynamicTextFont::
|
||||
slot_glyph(int character, int x_size, int y_size) {
|
||||
slot_glyph(int character, int x_size, int y_size, PN_stdfloat advance) {
|
||||
// Increase the indicated size by the current margin.
|
||||
x_size += _texture_margin * 2;
|
||||
y_size += _texture_margin * 2;
|
||||
|
|
@ -850,7 +883,7 @@ slot_glyph(int character, int x_size, int y_size) {
|
|||
|
||||
do {
|
||||
DynamicTextPage *page = _pages[pi];
|
||||
DynamicTextGlyph *glyph = page->slot_glyph(character, x_size, y_size, _texture_margin);
|
||||
DynamicTextGlyph *glyph = page->slot_glyph(character, x_size, y_size, _texture_margin, advance);
|
||||
if (glyph != (DynamicTextGlyph *)NULL) {
|
||||
// Once we found a page to hold the glyph, that becomes our
|
||||
// new preferred page.
|
||||
|
|
@ -874,7 +907,7 @@ slot_glyph(int character, int x_size, int y_size) {
|
|||
// glyphs?
|
||||
if (garbage_collect() != 0) {
|
||||
// Yes, we just freed up some space. Try once more, recursively.
|
||||
return slot_glyph(character, x_size, y_size);
|
||||
return slot_glyph(character, x_size, y_size, advance);
|
||||
|
||||
} else {
|
||||
// No good; all recorded glyphs are actually in use. We need to
|
||||
|
|
@ -882,7 +915,7 @@ slot_glyph(int character, int x_size, int y_size) {
|
|||
_preferred_page = _pages.size();
|
||||
PT(DynamicTextPage) page = new DynamicTextPage(this, _preferred_page);
|
||||
_pages.push_back(page);
|
||||
return page->slot_glyph(character, x_size, y_size, _texture_margin);
|
||||
return page->slot_glyph(character, x_size, y_size, _texture_margin, advance);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -893,7 +926,7 @@ slot_glyph(int character, int x_size, int y_size) {
|
|||
// geometry, as a wireframe render.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DynamicTextFont::
|
||||
render_wireframe_contours(DynamicTextGlyph *glyph) {
|
||||
render_wireframe_contours(TextGlyph *glyph) {
|
||||
PT(GeomVertexData) vdata = new GeomVertexData
|
||||
(string(), GeomVertexFormat::get_v3(),
|
||||
Geom::UH_static);
|
||||
|
|
@ -926,7 +959,7 @@ render_wireframe_contours(DynamicTextGlyph *glyph) {
|
|||
// geometry, as a polygon render.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DynamicTextFont::
|
||||
render_polygon_contours(DynamicTextGlyph *glyph, bool face, bool extrude) {
|
||||
render_polygon_contours(TextGlyph *glyph, bool face, bool extrude) {
|
||||
PT(GeomVertexData) vdata = new GeomVertexData
|
||||
(string(), GeomVertexFormat::get_v3n3(),
|
||||
Geom::UH_static);
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ PUBLISHED:
|
|||
INLINE PN_stdfloat get_poly_margin() const;
|
||||
|
||||
INLINE void set_page_size(int x_size, int y_size);
|
||||
INLINE const LVecBase2i &get_page_size() const;
|
||||
INLINE int get_page_x_size() const;
|
||||
INLINE int get_page_y_size() const;
|
||||
|
||||
|
|
@ -110,21 +111,21 @@ PUBLISHED:
|
|||
virtual void write(ostream &out, int indent_level) const;
|
||||
|
||||
public:
|
||||
virtual bool get_glyph(int character, const TextGlyph *&glyph);
|
||||
virtual bool get_glyph(int character, CPT(TextGlyph) &glyph);
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
void update_filters();
|
||||
void determine_tex_format();
|
||||
DynamicTextGlyph *make_glyph(int character, FT_Face face, int glyph_index);
|
||||
TextGlyph *make_glyph(int character, FT_Face face, int glyph_index);
|
||||
void copy_bitmap_to_texture(const FT_Bitmap &bitmap, DynamicTextGlyph *glyph);
|
||||
void copy_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph);
|
||||
void blend_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph,
|
||||
const LColor &fg);
|
||||
DynamicTextGlyph *slot_glyph(int character, int x_size, int y_size);
|
||||
DynamicTextGlyph *slot_glyph(int character, int x_size, int y_size, PN_stdfloat advance);
|
||||
|
||||
void render_wireframe_contours(DynamicTextGlyph *glyph);
|
||||
void render_polygon_contours(DynamicTextGlyph *glyph, bool face, bool extrude);
|
||||
void render_wireframe_contours(TextGlyph *glyph);
|
||||
void render_polygon_contours(TextGlyph *glyph, bool face, bool extrude);
|
||||
|
||||
static int outline_move_to(const FT_Vector *to, void *user);
|
||||
static int outline_line_to(const FT_Vector *to, void *user);
|
||||
|
|
@ -137,7 +138,7 @@ private:
|
|||
|
||||
int _texture_margin;
|
||||
PN_stdfloat _poly_margin;
|
||||
int _page_x_size, _page_y_size;
|
||||
LVecBase2i _page_size;
|
||||
|
||||
SamplerState::FilterType _minfilter;
|
||||
SamplerState::FilterType _magfilter;
|
||||
|
|
@ -159,14 +160,14 @@ private:
|
|||
|
||||
// This doesn't need to be a reference-counting pointer, because the
|
||||
// reference to each glyph is kept by the DynamicTextPage object.
|
||||
typedef pmap<int, DynamicTextGlyph *> Cache;
|
||||
typedef pmap<int, TextGlyph *> Cache;
|
||||
Cache _cache;
|
||||
|
||||
// This is a list of the glyphs that do not have any printable
|
||||
// properties (e.g. space), but still have an advance measure. We
|
||||
// store them here to keep their reference counts; they also appear
|
||||
// in the above table.
|
||||
typedef pvector< PT(DynamicTextGlyph) > EmptyGlyphs;
|
||||
typedef pvector< PT(TextGlyph) > EmptyGlyphs;
|
||||
EmptyGlyphs _empty_glyphs;
|
||||
|
||||
class ContourPoint {
|
||||
|
|
|
|||
|
|
@ -21,16 +21,13 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE DynamicTextGlyph::
|
||||
DynamicTextGlyph(int character, DynamicTextPage *page, int x, int y,
|
||||
int x_size, int y_size, int margin) :
|
||||
TextGlyph(character),
|
||||
int x_size, int y_size, int margin, PN_stdfloat advance) :
|
||||
TextGlyph(character, advance),
|
||||
_page(page),
|
||||
_x(x), _y(y),
|
||||
_x_size(x_size), _y_size(y_size),
|
||||
_margin(margin),
|
||||
_top(0), _left(0), _bottom(0), _right(0),
|
||||
_uv_top(0), _uv_left(0), _uv_bottom(0), _uv_right(0)
|
||||
_margin(margin)
|
||||
{
|
||||
_geom_count = 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -42,14 +39,12 @@ DynamicTextGlyph(int character, DynamicTextPage *page, int x, int y,
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE DynamicTextGlyph::
|
||||
DynamicTextGlyph(int character, PN_stdfloat advance) :
|
||||
TextGlyph(character),
|
||||
TextGlyph(character, advance),
|
||||
_page((DynamicTextPage *)NULL),
|
||||
_x(0), _y(0),
|
||||
_x_size(0), _y_size(0),
|
||||
_margin(0)
|
||||
{
|
||||
_advance = advance;
|
||||
_geom_count = 1;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -105,17 +100,6 @@ intersects(int x, int y, int x_size, int y_size) const {
|
|||
y >= mbot || hbot <= _y);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextGlyph::get_top
|
||||
// Access: Published
|
||||
// Description: Returns the vertex coordinates that can be used when
|
||||
// creating a custom text renderer.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_stdfloat DynamicTextGlyph::
|
||||
get_top() const {
|
||||
return _top;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextGlyph::get_left
|
||||
// Access: Published
|
||||
|
|
@ -124,7 +108,7 @@ get_top() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_stdfloat DynamicTextGlyph::
|
||||
get_left() const {
|
||||
return _left;
|
||||
return _quad_dimensions[0];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -135,7 +119,7 @@ get_left() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_stdfloat DynamicTextGlyph::
|
||||
get_bottom() const {
|
||||
return _bottom;
|
||||
return _quad_dimensions[1];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -146,18 +130,18 @@ get_bottom() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_stdfloat DynamicTextGlyph::
|
||||
get_right() const {
|
||||
return _right;
|
||||
return _quad_dimensions[2];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextGlyph::get_uv_top
|
||||
// Function: DynamicTextGlyph::get_top
|
||||
// Access: Published
|
||||
// Description: Returns the UV coordinates that can be used when
|
||||
// Description: Returns the vertex coordinates that can be used when
|
||||
// creating a custom text renderer.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_stdfloat DynamicTextGlyph::
|
||||
get_uv_top() const {
|
||||
return _uv_top;
|
||||
get_top() const {
|
||||
return _quad_dimensions[3];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -168,7 +152,7 @@ get_uv_top() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_stdfloat DynamicTextGlyph::
|
||||
get_uv_left() const {
|
||||
return _uv_left;
|
||||
return _quad_texcoords[0];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -179,7 +163,7 @@ get_uv_left() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_stdfloat DynamicTextGlyph::
|
||||
get_uv_bottom() const {
|
||||
return _uv_bottom;
|
||||
return _quad_texcoords[1];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -190,5 +174,16 @@ get_uv_bottom() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_stdfloat DynamicTextGlyph::
|
||||
get_uv_right() const {
|
||||
return _uv_right;
|
||||
return _quad_texcoords[2];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextGlyph::get_uv_top
|
||||
// Access: Published
|
||||
// Description: Returns the UV coordinates that can be used when
|
||||
// creating a custom text renderer.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PN_stdfloat DynamicTextGlyph::
|
||||
get_uv_top() const {
|
||||
return _quad_texcoords[3];
|
||||
}
|
||||
|
|
|
|||
|
|
@ -87,118 +87,6 @@ erase(DynamicTextFont *font) {
|
|||
font->get_bg());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextGlyph::make_geom
|
||||
// Access: Public
|
||||
// Description: Creates the actual geometry for the glyph. The
|
||||
// parameters bitmap_top and bitmap_left are from
|
||||
// FreeType, and indicate the position of the top left
|
||||
// corner of the bitmap relative to the glyph's origin.
|
||||
// The advance number represents the number of pixels
|
||||
// the pen should be advanced after drawing this glyph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DynamicTextGlyph::
|
||||
make_geom(int bitmap_top, int bitmap_left, PN_stdfloat advance, PN_stdfloat poly_margin,
|
||||
PN_stdfloat tex_x_size, PN_stdfloat tex_y_size,
|
||||
PN_stdfloat font_pixels_per_unit, PN_stdfloat tex_pixels_per_unit) {
|
||||
nassertv(_page != (DynamicTextPage *)NULL);
|
||||
|
||||
// This function should not be called twice.
|
||||
nassertv(_geom_count == 0);
|
||||
|
||||
tex_x_size += _margin * 2;
|
||||
tex_y_size += _margin * 2;
|
||||
|
||||
// Determine the corners of the rectangle in geometric units.
|
||||
PN_stdfloat tex_poly_margin = poly_margin / tex_pixels_per_unit;
|
||||
PN_stdfloat origin_y = bitmap_top / font_pixels_per_unit;
|
||||
PN_stdfloat origin_x = bitmap_left / font_pixels_per_unit;
|
||||
_top = origin_y + tex_poly_margin;
|
||||
_left = origin_x - tex_poly_margin;
|
||||
_bottom = origin_y - tex_y_size / tex_pixels_per_unit - tex_poly_margin;
|
||||
_right = origin_x + tex_x_size / tex_pixels_per_unit + tex_poly_margin;
|
||||
|
||||
// And the corresponding corners in UV units. We add 0.5f to center
|
||||
// the UV in the middle of its texel, to minimize roundoff errors
|
||||
// when we are close to 1-to-1 pixel size.
|
||||
_uv_top = 1.0f - ((PN_stdfloat)(_y - poly_margin) + 0.5f) / _page->get_y_size();
|
||||
_uv_left = ((PN_stdfloat)(_x - poly_margin) + 0.5f) / _page->get_x_size();
|
||||
_uv_bottom = 1.0f - ((PN_stdfloat)(_y + poly_margin + tex_y_size) + 0.5f) / _page->get_y_size();
|
||||
_uv_right = ((PN_stdfloat)(_x + poly_margin + tex_x_size) + 0.5f) / _page->get_x_size();
|
||||
|
||||
// Create a corresponding triangle pair. We use a pair of indexed
|
||||
// triangles rather than a single triangle strip, to avoid the bad
|
||||
// vertex duplication behavior with lots of two-triangle strips.
|
||||
PT(GeomVertexData) vdata = new GeomVertexData
|
||||
(string(), GeomVertexFormat::get_v3t2(),
|
||||
Geom::UH_static);
|
||||
vdata->unclean_set_num_rows(4);
|
||||
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
|
||||
|
||||
vertex.add_data3(_left, 0, _top);
|
||||
vertex.add_data3(_left, 0, _bottom);
|
||||
vertex.add_data3(_right, 0, _top);
|
||||
vertex.add_data3(_right, 0, _bottom);
|
||||
|
||||
texcoord.add_data2(_uv_left, _uv_top);
|
||||
texcoord.add_data2(_uv_left, _uv_bottom);
|
||||
texcoord.add_data2(_uv_right, _uv_top);
|
||||
texcoord.add_data2(_uv_right, _uv_bottom);
|
||||
|
||||
PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
|
||||
tris->reserve_num_vertices(6);
|
||||
tris->add_vertex(0);
|
||||
tris->add_vertex(1);
|
||||
tris->add_vertex(2);
|
||||
tris->close_primitive();
|
||||
tris->add_vertex(2);
|
||||
tris->add_vertex(1);
|
||||
tris->add_vertex(3);
|
||||
tris->close_primitive();
|
||||
|
||||
PT(Geom) geom = new GeomTextGlyph(this, vdata);
|
||||
geom->add_primitive(tris);
|
||||
_geom = geom;
|
||||
|
||||
// The above will increment our _geom_count to 1. Reset it back
|
||||
// down to 0, since our own internal Geom doesn't count.
|
||||
nassertv(_geom_count == 1);
|
||||
_geom_count--;
|
||||
|
||||
_state = RenderState::make(TextureAttrib::make(_page),
|
||||
TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
||||
_state = _state->add_attrib(ColorAttrib::make_flat(LColor(1.0f, 1.0f, 1.0f, 1.0f)), -1);
|
||||
|
||||
_advance = advance / font_pixels_per_unit;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextGlyph::set_geom
|
||||
// Access: Public
|
||||
// Description: Sets the geom from a pre-built object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DynamicTextGlyph::
|
||||
set_geom(GeomVertexData *vdata, GeomPrimitive *prim,
|
||||
const RenderState *state) {
|
||||
// This function is called when _geom_count = 1, because it was
|
||||
// constructed via the empty Glyph constructor.
|
||||
nassertv(_geom_count == 1);
|
||||
_geom_count--;
|
||||
|
||||
PT(Geom) geom = new GeomTextGlyph(this, vdata);
|
||||
geom->add_primitive(prim);
|
||||
_geom = geom;
|
||||
|
||||
// The above will increment our _geom_count to 1. Reset it back
|
||||
// down to 0, since our own internal Geom doesn't count.
|
||||
nassertv(_geom_count == 1);
|
||||
_geom_count--;
|
||||
|
||||
_state = state;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextGlyph::is_whitespace
|
||||
// Access: Public, Virtual
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ class EXPCL_PANDA_TEXT DynamicTextGlyph : public TextGlyph {
|
|||
public:
|
||||
INLINE DynamicTextGlyph(int character, DynamicTextPage *page,
|
||||
int x, int y, int x_size, int y_size,
|
||||
int margin);
|
||||
int margin, PN_stdfloat advance);
|
||||
INLINE DynamicTextGlyph(int character, PN_stdfloat advance);
|
||||
private:
|
||||
INLINE DynamicTextGlyph(const DynamicTextGlyph ©);
|
||||
|
|
@ -48,34 +48,28 @@ PUBLISHED:
|
|||
|
||||
INLINE bool intersects(int x, int y, int x_size, int y_size) const;
|
||||
|
||||
INLINE PN_stdfloat get_top() const;
|
||||
INLINE PN_stdfloat get_left() const;
|
||||
INLINE PN_stdfloat get_bottom() const;
|
||||
INLINE PN_stdfloat get_right() const;
|
||||
INLINE PN_stdfloat get_top() const;
|
||||
|
||||
INLINE PN_stdfloat get_uv_top() const;
|
||||
INLINE PN_stdfloat get_uv_left() const;
|
||||
INLINE PN_stdfloat get_uv_bottom() const;
|
||||
INLINE PN_stdfloat get_uv_right() const;
|
||||
INLINE PN_stdfloat get_uv_top() const;
|
||||
|
||||
public:
|
||||
unsigned char *get_row(int y);
|
||||
void erase(DynamicTextFont *font);
|
||||
void make_geom(int top, int left, PN_stdfloat advance, PN_stdfloat poly_margin,
|
||||
PN_stdfloat tex_x_size, PN_stdfloat tex_y_size,
|
||||
PN_stdfloat font_pixels_per_unit, PN_stdfloat tex_pixels_per_unit);
|
||||
void set_geom(GeomVertexData *vdata, GeomPrimitive *prim,
|
||||
const RenderState *state);
|
||||
virtual bool is_whitespace() const;
|
||||
|
||||
DynamicTextPage *_page;
|
||||
int _geom_count;
|
||||
|
||||
int _x, _y;
|
||||
int _x_size, _y_size;
|
||||
int _margin;
|
||||
PN_stdfloat _top, _left, _bottom, _right;
|
||||
PN_stdfloat _uv_top, _uv_left, _uv_bottom, _uv_right;
|
||||
|
||||
friend class DynamicTextFont;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
|
|
|
|||
|
|
@ -13,6 +13,16 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextPage::get_size
|
||||
// Access: Published
|
||||
// Description: Returns the size of the page (texture), in pixels.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LVecBase2i &DynamicTextPage::
|
||||
get_size() const {
|
||||
return _size;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextPage::get_x_size
|
||||
// Access: Published
|
||||
|
|
@ -20,7 +30,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int DynamicTextPage::
|
||||
get_x_size() const {
|
||||
return _x_size;
|
||||
return _size.get_x();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -30,10 +40,9 @@ get_x_size() const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int DynamicTextPage::
|
||||
get_y_size() const {
|
||||
return _y_size;
|
||||
return _size.get_y();
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextPage::is_empty
|
||||
// Access: Published
|
||||
|
|
|
|||
|
|
@ -38,10 +38,9 @@ DynamicTextPage(DynamicTextFont *font, int page_number) :
|
|||
// doesn't usually have a high fill factor.
|
||||
set_quality_level(text_quality_level);
|
||||
|
||||
_x_size = _font->get_page_x_size();
|
||||
_y_size = _font->get_page_y_size();
|
||||
_size = _font->get_page_size();
|
||||
|
||||
setup_2d_texture(_x_size, _y_size, T_unsigned_byte, font->get_tex_format());
|
||||
setup_2d_texture(_size[0], _size[1], T_unsigned_byte, font->get_tex_format());
|
||||
|
||||
// Assign a name to the Texture.
|
||||
ostringstream strm;
|
||||
|
|
@ -63,7 +62,7 @@ DynamicTextPage(DynamicTextFont *font, int page_number) :
|
|||
set_border_color(font->get_bg());
|
||||
|
||||
// Fill the page with the font's background color.
|
||||
fill_region(0, 0, _x_size, _y_size, font->get_bg());
|
||||
fill_region(0, 0, _size[0], _size[1], font->get_bg());
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -74,7 +73,8 @@ DynamicTextPage(DynamicTextFont *font, int page_number) :
|
|||
// glyph object and returns it; otherwise, returns NULL.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DynamicTextGlyph *DynamicTextPage::
|
||||
slot_glyph(int character, int x_size, int y_size, int margin) {
|
||||
slot_glyph(int character, int x_size, int y_size, int margin,
|
||||
PN_stdfloat advance) {
|
||||
int x, y;
|
||||
if (!find_hole(x, y, x_size, y_size)) {
|
||||
// No room for the glyph.
|
||||
|
|
@ -84,7 +84,7 @@ slot_glyph(int character, int x_size, int y_size, int margin) {
|
|||
// The glyph can be fit at (x, y). Slot it.
|
||||
PT(DynamicTextGlyph) glyph =
|
||||
new DynamicTextGlyph(character, this,
|
||||
x, y, x_size, y_size, margin);
|
||||
x, y, x_size, y_size, margin, advance);
|
||||
_glyphs.push_back(glyph);
|
||||
return glyph;
|
||||
}
|
||||
|
|
@ -97,7 +97,7 @@ slot_glyph(int character, int x_size, int y_size, int margin) {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
void DynamicTextPage::
|
||||
fill_region(int x, int y, int x_size, int y_size, const LColor &color) {
|
||||
nassertv(x >= 0 && x + x_size <= _x_size && y >= 0 && y + y_size <= _y_size);
|
||||
nassertv(x >= 0 && x + x_size <= _size[0] && y >= 0 && y + y_size <= _size[1]);
|
||||
int num_components = get_num_components();
|
||||
if (num_components == 1) {
|
||||
// Luminance or alpha.
|
||||
|
|
@ -110,7 +110,7 @@ fill_region(int x, int y, int x_size, int y_size, const LColor &color) {
|
|||
|
||||
unsigned char *image = modify_ram_image();
|
||||
for (int yi = y; yi < y + y_size; yi++) {
|
||||
unsigned char *row = image + yi * _x_size;
|
||||
unsigned char *row = image + yi * _size[0];
|
||||
memset(row + x, v, x_size);
|
||||
}
|
||||
|
||||
|
|
@ -127,7 +127,7 @@ fill_region(int x, int y, int x_size, int y_size, const LColor &color) {
|
|||
|
||||
PN_uint16 *image = (PN_uint16 *)modify_ram_image().p();
|
||||
for (int yi = y; yi < y + y_size; yi++) {
|
||||
PN_uint16 *row = image + yi * _x_size ;
|
||||
PN_uint16 *row = image + yi * _size[0] ;
|
||||
for (int xi = x; xi < x + x_size; xi++) {
|
||||
row[xi] = v.v;
|
||||
}
|
||||
|
|
@ -142,7 +142,7 @@ fill_region(int x, int y, int x_size, int y_size, const LColor &color) {
|
|||
|
||||
unsigned char *image = modify_ram_image();
|
||||
for (int yi = y; yi < y + y_size; yi++) {
|
||||
unsigned char *row = image + yi * _x_size * 3;
|
||||
unsigned char *row = image + yi * _size[0] * 3;
|
||||
for (int xi = x; xi < x + x_size; xi++) {
|
||||
row[xi * 3] = p0;
|
||||
row[xi * 3 + 1] = p1;
|
||||
|
|
@ -164,12 +164,12 @@ fill_region(int x, int y, int x_size, int y_size, const LColor &color) {
|
|||
|
||||
PN_uint32 *image = (PN_uint32 *)modify_ram_image().p();
|
||||
for (int yi = y; yi < y + y_size; yi++) {
|
||||
PN_uint32 *row = image + yi * _x_size;
|
||||
PN_uint32 *row = image + yi * _size[0];
|
||||
for (int xi = x; xi < x + x_size; xi++) {
|
||||
row[xi] = v.v;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -189,7 +189,8 @@ garbage_collect(DynamicTextFont *font) {
|
|||
Glyphs::iterator gi;
|
||||
for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
|
||||
DynamicTextGlyph *glyph = (*gi);
|
||||
if (glyph->_geom_count != 0) {
|
||||
cerr << glyph->get_character() << " - " << glyph->get_ref_count() << "\n";
|
||||
if (glyph->get_ref_count() > 1) {
|
||||
// Keep this one.
|
||||
new_glyphs.insert(new_glyphs.end(), (*gi));
|
||||
} else {
|
||||
|
|
@ -214,11 +215,11 @@ garbage_collect(DynamicTextFont *font) {
|
|||
bool DynamicTextPage::
|
||||
find_hole(int &x, int &y, int x_size, int y_size) const {
|
||||
y = 0;
|
||||
while (y + y_size <= _y_size) {
|
||||
int next_y = _y_size;
|
||||
while (y + y_size <= _size[1]) {
|
||||
int next_y = _size[1];
|
||||
// Scan along the row at 'y'.
|
||||
x = 0;
|
||||
while (x + x_size <= _x_size) {
|
||||
while (x + x_size <= _size[0]) {
|
||||
int next_x = x;
|
||||
|
||||
// Consider the spot at x, y.
|
||||
|
|
|
|||
|
|
@ -37,10 +37,11 @@ class EXPCL_PANDA_TEXT DynamicTextPage : public Texture {
|
|||
public:
|
||||
DynamicTextPage(DynamicTextFont *font, int page_number);
|
||||
|
||||
DynamicTextGlyph *slot_glyph(int character,
|
||||
int x_size, int y_size, int margin);
|
||||
DynamicTextGlyph *slot_glyph(int character, int x_size, int y_size,
|
||||
int margin, PN_stdfloat advance);
|
||||
|
||||
PUBLISHED:
|
||||
INLINE const LVecBase2i &get_size() const;
|
||||
INLINE int get_x_size() const;
|
||||
INLINE int get_y_size() const;
|
||||
|
||||
|
|
@ -58,7 +59,7 @@ private:
|
|||
typedef pvector< PT(DynamicTextGlyph) > Glyphs;
|
||||
Glyphs _glyphs;
|
||||
|
||||
int _x_size, _y_size;
|
||||
LVecBase2i _size;
|
||||
|
||||
DynamicTextFont *_font;
|
||||
|
||||
|
|
|
|||
|
|
@ -13,9 +13,6 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "geomTextGlyph.h"
|
||||
|
||||
#ifdef HAVE_FREETYPE
|
||||
|
||||
#include "datagramIterator.h"
|
||||
#include "bamReader.h"
|
||||
#include "indent.h"
|
||||
|
|
@ -26,26 +23,25 @@ TypeHandle GeomTextGlyph::_type_handle;
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomTextGlyph::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
GeomTextGlyph::
|
||||
GeomTextGlyph(DynamicTextGlyph *glyph, const GeomVertexData *data) :
|
||||
GeomTextGlyph(const TextGlyph *glyph, const GeomVertexData *data) :
|
||||
Geom(data)
|
||||
{
|
||||
// Initially, there is only one glyph in the Geom. There might be
|
||||
// additional Glyphs later when we flatten the graph and call
|
||||
// Geom::unify().
|
||||
if (glyph != (DynamicTextGlyph *)NULL) {
|
||||
if (glyph != (const TextGlyph *)NULL) {
|
||||
_glyphs.reserve(1);
|
||||
_glyphs.push_back(glyph);
|
||||
glyph->_geom_count++;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomTextGlyph::Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
GeomTextGlyph::
|
||||
GeomTextGlyph(const GeomVertexData *data) :
|
||||
|
|
@ -57,59 +53,48 @@ GeomTextGlyph(const GeomVertexData *data) :
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomTextGlyph::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
GeomTextGlyph::
|
||||
GeomTextGlyph(const GeomTextGlyph ©) :
|
||||
Geom(copy),
|
||||
_glyphs(copy._glyphs)
|
||||
{
|
||||
Glyphs::iterator gi;
|
||||
for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
|
||||
DynamicTextGlyph *glyph = (*gi);
|
||||
nassertv(glyph != (DynamicTextGlyph *)NULL);
|
||||
glyph->_geom_count++;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomTextGlyph::Copy Constructor
|
||||
// Access: Public
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
GeomTextGlyph::
|
||||
GeomTextGlyph(const Geom ©, const TextGlyph *glyph) :
|
||||
Geom(copy)
|
||||
{
|
||||
if (glyph != (const TextGlyph *)NULL) {
|
||||
_glyphs.reserve(1);
|
||||
_glyphs.push_back(glyph);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomTextGlyph::Copy Assignment Operator
|
||||
// Access: Public
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomTextGlyph::
|
||||
operator = (const GeomTextGlyph ©) {
|
||||
Geom::operator = (copy);
|
||||
|
||||
Glyphs::iterator gi;
|
||||
for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
|
||||
DynamicTextGlyph *glyph = (*gi);
|
||||
nassertv(glyph != (DynamicTextGlyph *)NULL);
|
||||
glyph->_geom_count--;
|
||||
nassertv((*gi)->_geom_count >= 0);
|
||||
}
|
||||
_glyphs = copy._glyphs;
|
||||
for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
|
||||
DynamicTextGlyph *glyph = (*gi);
|
||||
nassertv(glyph != (DynamicTextGlyph *)NULL);
|
||||
glyph->_geom_count++;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomTextGlyph::Destructor
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
GeomTextGlyph::
|
||||
~GeomTextGlyph() {
|
||||
Glyphs::iterator gi;
|
||||
for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
|
||||
DynamicTextGlyph *glyph = (*gi);
|
||||
nassertv(glyph != (DynamicTextGlyph *)NULL);
|
||||
glyph->_geom_count--;
|
||||
nassertv(glyph->_geom_count >= 0);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -149,11 +134,8 @@ copy_primitives_from(const Geom *other) {
|
|||
DCAST_INTO_R(tother, other, false);
|
||||
|
||||
// Also copy the glyph pointers.
|
||||
Glyphs::const_iterator gi;
|
||||
for (gi = tother->_glyphs.begin(); gi != tother->_glyphs.end(); ++gi) {
|
||||
_glyphs.push_back(*gi);
|
||||
(*gi)->_geom_count++;
|
||||
}
|
||||
_glyphs.reserve(_glyphs.size() + tother->_glyphs.size());
|
||||
_glyphs.insert(_glyphs.end(), tother->_glyphs.begin(), tother->_glyphs.end());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
|
@ -176,18 +158,15 @@ count_geom(const Geom *other) {
|
|||
const GeomTextGlyph *tother;
|
||||
DCAST_INTO_V(tother, other);
|
||||
|
||||
Glyphs::const_iterator gi;
|
||||
for (gi = tother->_glyphs.begin(); gi != tother->_glyphs.end(); ++gi) {
|
||||
_glyphs.push_back(*gi);
|
||||
(*gi)->_geom_count++;
|
||||
}
|
||||
_glyphs.reserve(_glyphs.size() + tother->_glyphs.size());
|
||||
_glyphs.insert(_glyphs.end(), tother->_glyphs.begin(), tother->_glyphs.end());
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomTextGlyph::output
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomTextGlyph::
|
||||
output(ostream &out) const {
|
||||
|
|
@ -195,8 +174,8 @@ output(ostream &out) const {
|
|||
out << ", glyphs: [";
|
||||
Glyphs::const_iterator gi;
|
||||
for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
|
||||
DynamicTextGlyph *glyph = (*gi);
|
||||
nassertv(glyph != (DynamicTextGlyph *)NULL);
|
||||
const TextGlyph *glyph = (*gi);
|
||||
nassertv(glyph != (const TextGlyph *)NULL);
|
||||
out << " " << glyph->get_character();
|
||||
}
|
||||
out << " ]";
|
||||
|
|
@ -205,7 +184,7 @@ output(ostream &out) const {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomTextGlyph::write
|
||||
// Access: Public, Virtual
|
||||
// Description:
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomTextGlyph::
|
||||
write(ostream &out, int indent_level) const {
|
||||
|
|
@ -214,13 +193,24 @@ write(ostream &out, int indent_level) const {
|
|||
<< "Glyphs: [";
|
||||
Glyphs::const_iterator gi;
|
||||
for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
|
||||
DynamicTextGlyph *glyph = (*gi);
|
||||
nassertv(glyph != (DynamicTextGlyph *)NULL);
|
||||
const TextGlyph *glyph = (*gi);
|
||||
nassertv(glyph != (const TextGlyph *)NULL);
|
||||
out << " " << glyph->get_character();
|
||||
}
|
||||
out << " ]\n";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomTextGlyph::add_glyph
|
||||
// Access: Public
|
||||
// Description: Adds a glyph to the list of glyphs referenced by
|
||||
// this Geom.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void GeomTextGlyph::
|
||||
add_glyph(const TextGlyph *glyph) {
|
||||
_glyphs.push_back(glyph);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: GeomTextGlyph::register_with_factory
|
||||
// Access: Public, Static
|
||||
|
|
@ -238,7 +228,7 @@ register_with_read_factory() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
TypedWritable* GeomTextGlyph::
|
||||
make_GeomTextGlyph(const FactoryParams ¶ms) {
|
||||
GeomTextGlyph *me = new GeomTextGlyph((DynamicTextGlyph *)NULL,
|
||||
GeomTextGlyph *me = new GeomTextGlyph((const TextGlyph *)NULL,
|
||||
(GeomVertexData *)NULL);
|
||||
DatagramIterator scan;
|
||||
BamReader *manager;
|
||||
|
|
@ -247,5 +237,3 @@ make_GeomTextGlyph(const FactoryParams ¶ms) {
|
|||
me->fillin(scan, manager);
|
||||
return me;
|
||||
}
|
||||
|
||||
#endif // HAVE_FREETYPE
|
||||
|
|
|
|||
|
|
@ -17,15 +17,12 @@
|
|||
|
||||
#include "pandabase.h"
|
||||
#include "geom.h"
|
||||
|
||||
#ifdef HAVE_FREETYPE
|
||||
|
||||
#include "dynamicTextGlyph.h"
|
||||
#include "textGlyph.h"
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Class : GeomTextGlyph
|
||||
// Description : This is a specialization on Geom for containing a
|
||||
// primitive intended to represent a DynamicTextGlyph.
|
||||
// primitive intended to represent a TextGlyph.
|
||||
// Its sole purpose is to maintain the geom count on the
|
||||
// glyph, so we can determine the actual usage count on
|
||||
// a dynamic glyph (and thus know when it is safe to
|
||||
|
|
@ -33,10 +30,10 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA_TEXT GeomTextGlyph : public Geom {
|
||||
public:
|
||||
GeomTextGlyph(DynamicTextGlyph *glyph,
|
||||
const GeomVertexData *data);
|
||||
GeomTextGlyph(const TextGlyph *glyph, const GeomVertexData *data);
|
||||
GeomTextGlyph(const GeomVertexData *data);
|
||||
GeomTextGlyph(const GeomTextGlyph ©);
|
||||
GeomTextGlyph(const Geom ©, const TextGlyph *glyph);
|
||||
void operator = (const GeomTextGlyph ©);
|
||||
virtual ~GeomTextGlyph();
|
||||
ALLOC_DELETED_CHAIN(GeomTextGlyph);
|
||||
|
|
@ -48,8 +45,12 @@ public:
|
|||
virtual void output(ostream &out) const;
|
||||
virtual void write(ostream &out, int indent_level = 0) const;
|
||||
|
||||
void add_glyph(const TextGlyph *glyph);
|
||||
|
||||
friend class TextAssembler;
|
||||
|
||||
private:
|
||||
typedef pvector< PT(DynamicTextGlyph) > Glyphs;
|
||||
typedef pvector< CPT(TextGlyph) > Glyphs;
|
||||
Glyphs _glyphs;
|
||||
|
||||
public:
|
||||
|
|
@ -77,11 +78,4 @@ private:
|
|||
|
||||
#include "geomTextGlyph.I"
|
||||
|
||||
#else // HAVE_FREETYPE
|
||||
|
||||
// Without Freetype, a GeomTextGlyph is really just an ordinary Geom.
|
||||
typedef Geom GeomTextGlyph;
|
||||
|
||||
#endif // HAVE_FREETYPE
|
||||
|
||||
#endif // GEOMTEXTGLYPH_H
|
||||
|
|
|
|||
|
|
@ -234,7 +234,7 @@ write(ostream &out, int indent_level) const {
|
|||
// printable glyph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool StaticTextFont::
|
||||
get_glyph(int character, const TextGlyph *&glyph) {
|
||||
get_glyph(int character, CPT(TextGlyph) &glyph) {
|
||||
Glyphs::const_iterator gi = _glyphs.find(character);
|
||||
if (gi == _glyphs.end()) {
|
||||
// No definition for this character.
|
||||
|
|
|
|||
|
|
@ -47,7 +47,7 @@ PUBLISHED:
|
|||
virtual void write(ostream &out, int indent_level) const;
|
||||
|
||||
public:
|
||||
virtual bool get_glyph(int character, const TextGlyph *&glyph);
|
||||
virtual bool get_glyph(int character, CPT(TextGlyph) &glyph);
|
||||
|
||||
private:
|
||||
void find_character_gsets(PandaNode *root, CPT(Geom) &ch, CPT(Geom) &dot,
|
||||
|
|
|
|||
|
|
@ -522,24 +522,6 @@ ComputedProperties(ComputedProperties *based_on, const wstring &wname,
|
|||
<< "Unknown TextProperties: " << name << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextAssembler::GlyphPlacement::add_piece
|
||||
// Access: Public
|
||||
// Description: Adds a piece of the glyph, consisting of a single
|
||||
// Geom and an associated RenderState. Typically, a
|
||||
// glyph will have exactly one piece; there will only be
|
||||
// multiple pieces in the case of cheesy accent marks or
|
||||
// ligatures.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void TextAssembler::GlyphPlacement::
|
||||
add_piece(Geom *geom, const RenderState *state) {
|
||||
Piece piece;
|
||||
piece._geom = geom;
|
||||
piece._state = state;
|
||||
_pieces.push_back(piece);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextAssembler::GeomCollectorKey::Constructor
|
||||
|
|
|
|||
File diff suppressed because it is too large
Load Diff
|
|
@ -164,12 +164,10 @@ private:
|
|||
// And here it is, wordwrapped.
|
||||
TextBlock _text_block;
|
||||
|
||||
#ifndef CPPPARSER // interrogate has a bit of trouble with wstring iterators.
|
||||
void scan_wtext(TextString &output_string,
|
||||
wstring::const_iterator &si,
|
||||
const wstring::const_iterator &send,
|
||||
ComputedProperties *current_cprops);
|
||||
#endif // CPPPARSER
|
||||
|
||||
bool wordwrap_text();
|
||||
|
||||
|
|
@ -179,13 +177,6 @@ private:
|
|||
// These structures are built up by assemble_paragraph() and
|
||||
// assemble_row(). They represent the actual Geoms as laid out in a
|
||||
// paragraph.
|
||||
|
||||
class Piece {
|
||||
public:
|
||||
PT(Geom) _geom;
|
||||
CPT(RenderState) _state;
|
||||
};
|
||||
typedef pvector<Piece> Pieces;
|
||||
|
||||
class GeomCollectorKey {
|
||||
public:
|
||||
|
|
@ -218,26 +209,50 @@ private:
|
|||
};
|
||||
typedef pmap<GeomCollectorKey, GeomCollector> GeomCollectorMap;
|
||||
|
||||
class GlyphPlacement : public MemoryBase {
|
||||
struct QuadDef {
|
||||
// Copying this class is a performance hotspot, hence we define the
|
||||
// move constructor.
|
||||
ALWAYS_INLINE QuadDef() {}
|
||||
ALWAYS_INLINE QuadDef(const QuadDef ©) :
|
||||
_dimensions(copy._dimensions), _uvs(copy._uvs),
|
||||
_slantl(copy._slantl), _slanth(copy._slanth),
|
||||
_glyph(copy._glyph) {}
|
||||
|
||||
#ifdef USE_MOVE_SEMANTICS
|
||||
ALWAYS_INLINE QuadDef(QuadDef &&from) NOEXCEPT :
|
||||
_dimensions(from._dimensions), _uvs(from._uvs),
|
||||
_slantl(from._slantl), _slanth(from._slanth),
|
||||
_glyph(move(from._glyph)) {}
|
||||
#endif
|
||||
|
||||
LVecBase4 _dimensions;
|
||||
LVecBase4 _uvs;
|
||||
PN_stdfloat _slantl, _slanth;
|
||||
CPT(TextGlyph) _glyph;
|
||||
};
|
||||
typedef pvector<QuadDef> QuadDefs;
|
||||
typedef pmap<CPT(RenderState), QuadDefs> QuadMap;
|
||||
|
||||
void generate_quads(GeomNode *geom_node, const QuadMap &quad_map);
|
||||
|
||||
class GlyphPlacement {
|
||||
public:
|
||||
INLINE void add_piece(Geom *geom, const RenderState *state);
|
||||
void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
|
||||
bool &found_any, Thread *current_thread) const;
|
||||
void assign_to(GeomNode *geom_node, const RenderState *state) const;
|
||||
void assign_copy_to(GeomNode *geom_node, const RenderState *state,
|
||||
const LMatrix4 &extra_xform) const;
|
||||
void assign_to(GeomNode *geom_node, const RenderState *state,
|
||||
const LVector2 &offset = LVector2::zero()) const;
|
||||
|
||||
void assign_append_to(GeomCollectorMap &geom_collector_map, const RenderState *state,
|
||||
const LMatrix4 &extra_xform) const;
|
||||
void copy_graphic_to(PandaNode *node, const RenderState *state,
|
||||
const LMatrix4 &extra_xform) const;
|
||||
const LVector2 &offset = LVector2::zero()) const;
|
||||
void assign_quad_to(QuadMap &quad_map, const RenderState *state,
|
||||
const LVector2 &offset = LVector2::zero()) const;
|
||||
void copy_graphic_to(PandaNode *node, const RenderState *state) const;
|
||||
|
||||
Pieces _pieces;
|
||||
CPT(TextGlyph) _glyph;
|
||||
PT(PandaNode) _graphic_model;
|
||||
LMatrix4 _xform;
|
||||
PN_stdfloat _xpos, _ypos;
|
||||
PN_stdfloat _scale, _slant;
|
||||
const TextProperties *_properties;
|
||||
};
|
||||
typedef pvector<GlyphPlacement *> PlacedGlyphs;
|
||||
typedef pvector<GlyphPlacement> PlacedGlyphs;
|
||||
|
||||
void assemble_paragraph(PlacedGlyphs &placed_glyphs);
|
||||
void assemble_row(TextRow &row,
|
||||
|
|
@ -281,8 +296,8 @@ private:
|
|||
|
||||
static void
|
||||
get_character_glyphs(int character, const TextProperties *properties,
|
||||
bool &got_glyph, const TextGlyph *&glyph,
|
||||
const TextGlyph *&second_glyph,
|
||||
bool &got_glyph, CPT(TextGlyph) &glyph,
|
||||
CPT(TextGlyph) &second_glyph,
|
||||
UnicodeLatinMap::AccentType &accent_type,
|
||||
int &additional_flags,
|
||||
PN_stdfloat &glyph_scale, PN_stdfloat &advance_scale);
|
||||
|
|
@ -291,13 +306,13 @@ private:
|
|||
tack_on_accent(UnicodeLatinMap::AccentType accent_type,
|
||||
const LPoint3 &min_vert, const LPoint3 &max_vert,
|
||||
const LPoint3 ¢roid,
|
||||
const TextProperties *properties, GlyphPlacement *placement) const;
|
||||
const TextProperties *properties, GlyphPlacement &placement) const;
|
||||
bool
|
||||
tack_on_accent(char accent_mark, CheesyPosition position,
|
||||
CheesyTransform transform,
|
||||
const LPoint3 &min_vert, const LPoint3 &max_vert,
|
||||
const LPoint3 ¢roid,
|
||||
const TextProperties *properties, GlyphPlacement *placement) const;
|
||||
const TextProperties *properties, GlyphPlacement &placement) const;
|
||||
|
||||
// These are filled in by assemble_paragraph().
|
||||
LVector2 _ul;
|
||||
|
|
|
|||
|
|
@ -87,9 +87,9 @@ set_space_advance(PN_stdfloat space_advance) {
|
|||
// it may still return a printable glyph, or it may
|
||||
// return NULL.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const TextGlyph *TextFont::
|
||||
INLINE CPT(TextGlyph) TextFont::
|
||||
get_glyph(int character) {
|
||||
const TextGlyph *glyph = NULL;
|
||||
CPT(TextGlyph) glyph;
|
||||
get_glyph(character, glyph);
|
||||
return glyph;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -78,12 +78,12 @@ PUBLISHED:
|
|||
|
||||
INLINE PN_stdfloat get_space_advance() const;
|
||||
INLINE void set_space_advance(PN_stdfloat space_advance);
|
||||
INLINE const TextGlyph *get_glyph(int character);
|
||||
INLINE CPT(TextGlyph) get_glyph(int character);
|
||||
|
||||
virtual void write(ostream &out, int indent_level) const;
|
||||
|
||||
public:
|
||||
virtual bool get_glyph(int character, const TextGlyph *&glyph)=0;
|
||||
virtual bool get_glyph(int character, CPT(TextGlyph) &glyph)=0;
|
||||
TextGlyph *get_invalid_glyph();
|
||||
|
||||
static RenderMode string_render_mode(const string &string);
|
||||
|
|
|
|||
|
|
@ -16,14 +16,15 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextGlyph::Default constructor
|
||||
// Access: Public
|
||||
// Description: This constructor makes an invalid glyph.
|
||||
// Description: This constructor makes an empty glyph.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE TextGlyph::
|
||||
TextGlyph(int character) :
|
||||
_character(character)
|
||||
TextGlyph(int character, PN_stdfloat advance) :
|
||||
_character(character),
|
||||
_geom((Geom *)NULL),
|
||||
_advance(advance),
|
||||
_has_quad(false)
|
||||
{
|
||||
_geom = (Geom *)NULL;
|
||||
_advance = 0.0f;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -37,8 +38,12 @@ TextGlyph(int character, const Geom *geom,
|
|||
_character(character),
|
||||
_geom(geom),
|
||||
_state(state),
|
||||
_advance(advance)
|
||||
{
|
||||
_advance(advance),
|
||||
_has_quad(false)
|
||||
{
|
||||
if (geom != NULL) {
|
||||
check_quad_geom();
|
||||
}
|
||||
if (_state == (RenderState *)NULL) {
|
||||
_state = RenderState::make_empty();
|
||||
}
|
||||
|
|
@ -54,8 +59,11 @@ TextGlyph(const TextGlyph ©) :
|
|||
_character(copy._character),
|
||||
_geom(copy._geom),
|
||||
_state(copy._state),
|
||||
_advance(copy._advance)
|
||||
{
|
||||
_advance(copy._advance),
|
||||
_has_quad(copy._has_quad),
|
||||
_quad_dimensions(copy._quad_dimensions),
|
||||
_quad_texcoords(copy._quad_texcoords)
|
||||
{
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -69,6 +77,9 @@ operator = (const TextGlyph ©) {
|
|||
_geom = copy._geom;
|
||||
_state = copy._state;
|
||||
_advance = copy._advance;
|
||||
_has_quad = copy._has_quad;
|
||||
_quad_dimensions = copy._quad_dimensions;
|
||||
_quad_texcoords = copy._quad_texcoords;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -83,28 +94,40 @@ get_character() const {
|
|||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextGlyph::get_geom
|
||||
// Function: TextGlyph::has_quad
|
||||
// Access: Public
|
||||
// Description: Returns a Geom that renders the particular glyph.
|
||||
// Description: Returns true if this glyph contains the definition
|
||||
// for a simple quad, rather than a more complex piece
|
||||
// of geometry.
|
||||
//
|
||||
// You may still call get_geom() even if this returns
|
||||
// true, which will synthesize a Geom for this quad.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE PT(Geom) TextGlyph::
|
||||
get_geom(Geom::UsageHint usage_hint) const {
|
||||
if (_geom == (Geom *)NULL) {
|
||||
return NULL;
|
||||
INLINE bool TextGlyph::
|
||||
has_quad() const {
|
||||
return _has_quad;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextGlyph::get_quad
|
||||
// Access: Public
|
||||
// Description: Assuming that this glyph is representable as a
|
||||
// textured quad, returns its dimensions and UV range.
|
||||
// Returns false if it is not representable as a quad,
|
||||
// or if it is whitespace.
|
||||
//
|
||||
// The order of the components is left, bottom,
|
||||
// right, top.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool TextGlyph::
|
||||
get_quad(LVecBase4 &dimensions, LVecBase4 &texcoords) const {
|
||||
if (!_has_quad) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// 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.
|
||||
PT(Geom) new_geom = _geom->make_copy();
|
||||
new_geom->set_usage_hint(usage_hint);
|
||||
const GeomVertexData *vdata = new_geom->get_vertex_data();
|
||||
nassertr(vdata != NULL, new_geom);
|
||||
if (vdata->get_usage_hint() != usage_hint) {
|
||||
new_geom->modify_vertex_data()->set_usage_hint(usage_hint);
|
||||
}
|
||||
return new_geom;
|
||||
dimensions = _quad_dimensions;
|
||||
texcoords = _quad_texcoords;
|
||||
return true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -27,7 +27,7 @@ TextGlyph::
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextGlyph::is_whitespace
|
||||
// Access: Public, Virtual
|
||||
// Access: Published, Virtual
|
||||
// Description: Returns true if this glyph represents invisible
|
||||
// whitespace, or false if it corresponds to some
|
||||
// visible character.
|
||||
|
|
@ -38,3 +38,276 @@ is_whitespace() const {
|
|||
// all glyphs are non-whitespace.
|
||||
return false;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextGlyph::get_geom
|
||||
// Access: Published
|
||||
// Description: Returns a Geom that renders the particular glyph.
|
||||
// It will be generated if necessary.
|
||||
//
|
||||
// This method will always return a copy of the Geom,
|
||||
// so the caller is free to modify it.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
PT(Geom) TextGlyph::
|
||||
get_geom(Geom::UsageHint usage_hint) const {
|
||||
if (_geom.is_null()) {
|
||||
// Maybe we have yet to generate a suitable Geom.
|
||||
if (_has_quad) {
|
||||
((TextGlyph *)this)->make_quad_geom();
|
||||
if (_geom.is_null()) {
|
||||
return (Geom *)NULL;
|
||||
}
|
||||
} else {
|
||||
// Nope.
|
||||
return (Geom *)NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// 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 important that we store a reference to this glyph on
|
||||
// the Geom, since the DynamicTextFont relies on counting references
|
||||
// to determine whether a glyph is no longer used.
|
||||
PT(Geom) new_geom = new GeomTextGlyph(*_geom, this);
|
||||
new_geom->set_usage_hint(usage_hint);
|
||||
const GeomVertexData *vdata = new_geom->get_vertex_data();
|
||||
nassertr(vdata != NULL, new_geom);
|
||||
if (vdata->get_usage_hint() != usage_hint) {
|
||||
new_geom->modify_vertex_data()->set_usage_hint(usage_hint);
|
||||
}
|
||||
return new_geom;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextGlyph::calc_tight_bounds
|
||||
// Access: Public
|
||||
// Description: Expands min_point and max_point to include all of the
|
||||
// vertices in the glyph, if any. found_any is set
|
||||
// true if any points are found. It is the caller's
|
||||
// responsibility to initialize min_point, max_point,
|
||||
// and found_any before calling this function.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TextGlyph::
|
||||
calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
|
||||
bool &found_any, Thread *current_thread) const {
|
||||
if (_has_quad) {
|
||||
found_any = true;
|
||||
min_point.set(_quad_dimensions[0], 0, _quad_dimensions[1]);
|
||||
max_point.set(_quad_dimensions[2], 0, _quad_dimensions[3]);
|
||||
|
||||
} else if (!_geom.is_null()) {
|
||||
_geom->calc_tight_bounds(min_point, max_point, found_any, current_thread);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextGlyph::set_quad
|
||||
// Access: Public
|
||||
// Description: Sets the glyph using the given quad parameters.
|
||||
// Any Geom assigned will be cleared.
|
||||
// The order of the components is left, bottom,
|
||||
// right, top.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TextGlyph::
|
||||
set_quad(const LVecBase4 &dimensions, const LVecBase4 &texcoords,
|
||||
const RenderState *state) {
|
||||
_geom.clear();
|
||||
|
||||
_quad_dimensions = dimensions;
|
||||
_quad_texcoords = texcoords;
|
||||
_has_quad = true;
|
||||
_state = state;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextGlyph::set_geom
|
||||
// Access: Public
|
||||
// Description: Sets the geom from a pre-built Geom object.
|
||||
// Any quad parameters assigned will be cleared.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TextGlyph::
|
||||
set_geom(GeomVertexData *vdata, GeomPrimitive *prim,
|
||||
const RenderState *state) {
|
||||
PT(Geom) geom = new Geom(vdata);
|
||||
geom->add_primitive(prim);
|
||||
_geom = geom;
|
||||
|
||||
_has_quad = false;
|
||||
_state = state;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextGlyph::check_quad_geom
|
||||
// Access: Private
|
||||
// Description: Checks if the geom that was passed in is actually
|
||||
// a quad, and if so, sets the appropriate quad
|
||||
// parameters.
|
||||
//
|
||||
// This is useful when loading static text fonts, so
|
||||
// that they can still benefit from the fast text
|
||||
// assembly that is done for quads.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TextGlyph::
|
||||
check_quad_geom() {
|
||||
// Currently it looks for rather specific signs that this glyph
|
||||
// has been generated using egg-mkfont. For now, this is fine.
|
||||
CPT(GeomVertexData) vdata = _geom->get_vertex_data();
|
||||
if (vdata->get_num_rows() != 4) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Does it appear to have a single primitive with two triangles?
|
||||
if (_geom->get_num_primitives() != 1) {
|
||||
return;
|
||||
}
|
||||
CPT(GeomPrimitive) prim = _geom->get_primitive(0);
|
||||
if (!prim->is_indexed() ||
|
||||
prim->get_primitive_type() != GeomPrimitive::PT_polygons) {
|
||||
return;
|
||||
}
|
||||
if (!prim->is_of_type(GeomTriangles::get_class_type())) {
|
||||
prim = prim->decompose();
|
||||
}
|
||||
if (prim->get_num_vertices() != 6) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that it has a vertex column and optionally a texcoord column.
|
||||
CPT(GeomVertexFormat) format = vdata->get_format();
|
||||
if (format->get_num_columns() > 2 ||
|
||||
!format->has_column(InternalName::get_vertex())) {
|
||||
return;
|
||||
}
|
||||
if (format->has_column(InternalName::get_texcoord()) != (format->get_num_columns() == 2)) {
|
||||
// The second column, if there is one, is not a texcoord.
|
||||
return;
|
||||
}
|
||||
|
||||
// Check that the vertices are arranged in a square.
|
||||
GeomVertexReader vertex(vdata, InternalName::get_vertex());
|
||||
LVecBase3 v = vertex.get_data3();
|
||||
if (!IS_NEARLY_ZERO(v[1])) {
|
||||
return;
|
||||
}
|
||||
PN_stdfloat minx = v[0];
|
||||
PN_stdfloat maxx = v[0];
|
||||
PN_stdfloat miny = v[2];
|
||||
PN_stdfloat maxy = v[2];
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
v = vertex.get_data3();
|
||||
if (!IS_NEARLY_ZERO(v[1])) {
|
||||
return;
|
||||
}
|
||||
if (!IS_NEARLY_EQUAL(v[0], minx) && !IS_NEARLY_EQUAL(v[0], maxx)) {
|
||||
if (!IS_NEARLY_EQUAL(minx, maxx)) {
|
||||
return;
|
||||
}
|
||||
minx = min(v[0], minx);
|
||||
maxx = max(v[0], maxx);
|
||||
}
|
||||
if (!IS_NEARLY_EQUAL(v[2], miny) && !IS_NEARLY_EQUAL(v[2], maxy)) {
|
||||
if (!IS_NEARLY_EQUAL(miny, maxy)) {
|
||||
return;
|
||||
}
|
||||
miny = min(v[2], miny);
|
||||
maxy = max(v[2], maxy);
|
||||
}
|
||||
}
|
||||
|
||||
PN_stdfloat minu = 0;
|
||||
PN_stdfloat maxu = 0;
|
||||
PN_stdfloat minv = 0;
|
||||
PN_stdfloat maxv = 0;
|
||||
|
||||
// Same for the texcoord data.
|
||||
if (format->has_column(InternalName::get_texcoord())) {
|
||||
GeomVertexReader texcoord(vdata, InternalName::get_texcoord());
|
||||
LVecBase2 tc = texcoord.get_data2();
|
||||
minu = tc[0];
|
||||
maxu = tc[0];
|
||||
minv = tc[1];
|
||||
maxv = tc[1];
|
||||
|
||||
for (int i = 0; i < 3; ++i) {
|
||||
tc = texcoord.get_data2();
|
||||
if (!IS_NEARLY_EQUAL(tc[0], minu) && !IS_NEARLY_EQUAL(tc[0], maxu)) {
|
||||
if (!IS_NEARLY_EQUAL(minu, maxu)) {
|
||||
return;
|
||||
}
|
||||
minu = min(tc[0], minu);
|
||||
maxu = max(tc[0], maxu);
|
||||
}
|
||||
if (!IS_NEARLY_EQUAL(tc[1], minv) && !IS_NEARLY_EQUAL(tc[1], maxv)) {
|
||||
if (!IS_NEARLY_EQUAL(minv, maxv)) {
|
||||
return;
|
||||
}
|
||||
minv = min(tc[1], minv);
|
||||
maxv = max(tc[1], maxv);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_quad_dimensions.set(minx, miny, maxx, maxy);
|
||||
_quad_texcoords.set(minu, minv, maxu, maxv);
|
||||
_has_quad = true;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: TextGlyph::make_quad_geom
|
||||
// Access: Private
|
||||
// Description: Generates a Geom representing this text glyph, if
|
||||
// at all possible.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void TextGlyph::
|
||||
make_quad_geom() {
|
||||
// The default implementation is to generate a Geom based on the
|
||||
// get_quad() implementation, if any.
|
||||
LVecBase4 dimensions, uvs;
|
||||
if (!get_quad(dimensions, uvs)) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create a corresponding triangle pair. We use a pair of indexed
|
||||
// triangles rather than a single triangle strip, to avoid the bad
|
||||
// vertex duplication behavior with lots of two-triangle strips.
|
||||
PT(GeomVertexData) vdata = new GeomVertexData
|
||||
(string(), GeomVertexFormat::get_v3t2(), Geom::UH_static);
|
||||
vdata->unclean_set_num_rows(4);
|
||||
|
||||
PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
|
||||
|
||||
{
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
|
||||
|
||||
PT(GeomVertexArrayData) indices = tris->modify_vertices();
|
||||
indices->unclean_set_num_rows(6);
|
||||
|
||||
GeomVertexWriter index(indices, 0);
|
||||
|
||||
vertex.set_data3(dimensions[0], 0, dimensions[3]);
|
||||
vertex.set_data3(dimensions[0], 0, dimensions[1]);
|
||||
vertex.set_data3(dimensions[2], 0, dimensions[3]);
|
||||
vertex.set_data3(dimensions[2], 0, dimensions[1]);
|
||||
|
||||
texcoord.set_data2(uvs[0], uvs[3]);
|
||||
texcoord.set_data2(uvs[0], uvs[1]);
|
||||
texcoord.set_data2(uvs[2], uvs[3]);
|
||||
texcoord.set_data2(uvs[2], uvs[1]);
|
||||
|
||||
index.set_data1i(0);
|
||||
index.set_data1i(1);
|
||||
index.set_data1i(2);
|
||||
index.set_data1i(2);
|
||||
index.set_data1i(1);
|
||||
index.set_data1i(3);
|
||||
}
|
||||
|
||||
// We create a regular Geom here, not a GeomTextGlyph, since doing so
|
||||
// would create a circular reference. When the get_geom method makes
|
||||
// a copy, it will add in a pointer to this text glyph.
|
||||
PT(Geom) geom = new Geom(vdata);
|
||||
geom->add_primitive(tris);
|
||||
_geom = geom;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -30,7 +30,7 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA_TEXT TextGlyph : public TypedReferenceCount {
|
||||
public:
|
||||
INLINE TextGlyph(int character);
|
||||
INLINE TextGlyph(int character, PN_stdfloat advance=0);
|
||||
INLINE TextGlyph(int character, const Geom *geom,
|
||||
const RenderState *state, PN_stdfloat advance);
|
||||
INLINE TextGlyph(const TextGlyph ©);
|
||||
|
|
@ -39,18 +39,42 @@ public:
|
|||
|
||||
PUBLISHED:
|
||||
INLINE int get_character() const;
|
||||
INLINE PT(Geom) get_geom(Geom::UsageHint usage_hint) const;
|
||||
INLINE bool has_quad() const;
|
||||
INLINE bool get_quad(LVecBase4 &dimensions, LVecBase4 &texcoords) const;
|
||||
INLINE const RenderState *get_state() const;
|
||||
INLINE PN_stdfloat get_advance() const;
|
||||
|
||||
virtual bool is_whitespace() const;
|
||||
|
||||
PT(Geom) get_geom(Geom::UsageHint usage_hint) const;
|
||||
|
||||
public:
|
||||
void calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point,
|
||||
bool &found_any, Thread *current_thread) const;
|
||||
|
||||
void set_quad(const LVecBase4 &dimensions, const LVecBase4 &texcoords,
|
||||
const RenderState *state);
|
||||
|
||||
void set_geom(GeomVertexData *vdata, GeomPrimitive *prim,
|
||||
const RenderState *state);
|
||||
|
||||
private:
|
||||
void check_quad_geom();
|
||||
void make_quad_geom();
|
||||
|
||||
protected:
|
||||
int _character;
|
||||
CPT(Geom) _geom;
|
||||
CPT(RenderState) _state;
|
||||
PN_stdfloat _advance;
|
||||
|
||||
bool _has_quad;
|
||||
// top, left, bottom, right
|
||||
LVecBase4 _quad_dimensions;
|
||||
LVecBase4 _quad_texcoords;
|
||||
|
||||
friend class GeomTextGlyph;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
|
|
|
|||
Loading…
Reference in New Issue