Skip to content

Commit a453ec1

Browse files
committed
Overhaul text generation; now 75x as fast as before.
1 parent 0fffcdf commit a453ec1

26 files changed

+1057
-668
lines changed

dtool/src/dtoolutil/unicodeLatinMap.cxx

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -369,6 +369,8 @@ static const UnicodeLatinMap::Entry latin_map[] = {
369369
UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_reversed },
370370
{ 0x0258, UnicodeLatinMap::CT_lower, 'e', 0, 0x0258, 0x018e,
371371
UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_reversed },
372+
{ 0x0259, UnicodeLatinMap::CT_lower, 'e', 0, 0x0259, 0x018f,
373+
UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_turned },
372374
{ 0x0066, UnicodeLatinMap::CT_lower, 'f', 0, 0x0066, 0x0046,
373375
UnicodeLatinMap::AT_none, 0 },
374376
{ 0x0046, UnicodeLatinMap::CT_upper, 'F', 0, 0x0066, 0x0046,
@@ -465,7 +467,9 @@ static const UnicodeLatinMap::Entry latin_map[] = {
465467
UnicodeLatinMap::AT_line_below, 0 },
466468
{ 0x029c, UnicodeLatinMap::CT_upper, 'H', 0, 0x0068, 0x029c,
467469
UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_smallcap },
468-
{ 0x0195, UnicodeLatinMap::CT_lower, 'h', 'v', 0x0195, 0x195,
470+
{ 0x0195, UnicodeLatinMap::CT_lower, 'h', 'v', 0x0195, 0x01f6,
471+
UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_ligature },
472+
{ 0x01f6, UnicodeLatinMap::CT_upper, 'H', 'v', 0x0195, 0x01f6,
469473
UnicodeLatinMap::AT_none, UnicodeLatinMap::AF_ligature },
470474
{ 0x0127, UnicodeLatinMap::CT_lower, 'h', 0, 0x0127, 0x0126,
471475
UnicodeLatinMap::AT_stroke, 0 },

panda/src/express/pointerToBase.I

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -162,7 +162,7 @@ update_type(To *ptr) {
162162
// (Assignment to a NULL pointer also works, of course.)
163163
////////////////////////////////////////////////////////////////////
164164
template<class T>
165-
INLINE void PointerToBase<T>::
165+
ALWAYS_INLINE void PointerToBase<T>::
166166
clear() {
167167
reassign((To *)NULL);
168168
}

panda/src/express/pointerToBase.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,7 +55,7 @@ class PointerToBase : public PointerToVoid {
5555
// vs. non-const later.
5656

5757
PUBLISHED:
58-
INLINE void clear();
58+
ALWAYS_INLINE void clear();
5959

6060
void output(ostream &out) const;
6161
};

panda/src/express/pointerToVoid.I

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ PointerToVoid(const PointerToVoid &) {
5050
// false otherwise. (Direct comparison to a NULL
5151
// pointer also works.)
5252
////////////////////////////////////////////////////////////////////
53-
INLINE bool PointerToVoid::
53+
ALWAYS_INLINE bool PointerToVoid::
5454
is_null() const {
5555
return (_void_ptr == (void *)NULL);
5656
}

panda/src/express/pointerToVoid.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ class EXPCL_PANDAEXPRESS PointerToVoid : public MemoryBase {
4242
INLINE PointerToVoid(const PointerToVoid &copy);
4343

4444
PUBLISHED:
45-
INLINE bool is_null() const;
45+
ALWAYS_INLINE bool is_null() const;
4646
INLINE size_t get_hash() const;
4747

4848
public:

panda/src/text/dynamicTextFont.I

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -260,8 +260,18 @@ get_poly_margin() const {
260260
////////////////////////////////////////////////////////////////////
261261
INLINE void DynamicTextFont::
262262
set_page_size(int x_size, int y_size) {
263-
_page_x_size = x_size;
264-
_page_y_size = y_size;
263+
_page_size.set(x_size, y_size);
264+
}
265+
266+
////////////////////////////////////////////////////////////////////
267+
// Function: DynamicTextFont::get_page_size
268+
// Access: Published
269+
// Description: Returns the size of the textures that are created
270+
// for the DynamicTextFont. See set_page_size().
271+
////////////////////////////////////////////////////////////////////
272+
INLINE const LVecBase2i &DynamicTextFont::
273+
get_page_size() const {
274+
return _page_size;
265275
}
266276

267277
////////////////////////////////////////////////////////////////////
@@ -272,7 +282,7 @@ set_page_size(int x_size, int y_size) {
272282
////////////////////////////////////////////////////////////////////
273283
INLINE int DynamicTextFont::
274284
get_page_x_size() const {
275-
return _page_x_size;
285+
return _page_size.get_x();
276286
}
277287

278288
////////////////////////////////////////////////////////////////////
@@ -283,7 +293,7 @@ get_page_x_size() const {
283293
////////////////////////////////////////////////////////////////////
284294
INLINE int DynamicTextFont::
285295
get_page_y_size() const {
286-
return _page_y_size;
296+
return _page_size.get_y();
287297
}
288298

289299
////////////////////////////////////////////////////////////////////

panda/src/text/dynamicTextFont.cxx

Lines changed: 63 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,8 @@
4444
#include "nurbsCurveResult.h"
4545
//#include "renderModeAttrib.h"
4646
//#include "antialiasAttrib.h"
47+
#include "colorAttrib.h"
48+
#include "textureAttrib.h"
4749

4850
TypeHandle DynamicTextFont::_type_handle;
4951

@@ -110,8 +112,7 @@ DynamicTextFont(const DynamicTextFont &copy) :
110112
FreetypeFont(copy),
111113
_texture_margin(copy._texture_margin),
112114
_poly_margin(copy._poly_margin),
113-
_page_x_size(copy._page_x_size),
114-
_page_y_size(copy._page_y_size),
115+
_page_size(copy._page_size),
115116
_minfilter(copy._minfilter),
116117
_magfilter(copy._magfilter),
117118
_anisotropic_degree(copy._anisotropic_degree),
@@ -194,8 +195,8 @@ garbage_collect() {
194195
Cache new_cache;
195196
Cache::iterator ci;
196197
for (ci = _cache.begin(); ci != _cache.end(); ++ci) {
197-
DynamicTextGlyph *glyph = (*ci).second;
198-
if (glyph == (DynamicTextGlyph *)NULL || glyph->_geom_count != 0) {
198+
TextGlyph *glyph = (*ci).second;
199+
if (glyph == (TextGlyph *)NULL || glyph->get_ref_count() > 1) {
199200
// Keep this one.
200201
new_cache.insert(new_cache.end(), (*ci));
201202
} else {
@@ -252,7 +253,7 @@ write(ostream &out, int indent_level) const {
252253
Cache::const_iterator ci;
253254
for (ci = _cache.begin(); ci != _cache.end(); ++ci) {
254255
int glyph_index = (*ci).first;
255-
DynamicTextGlyph *glyph = (*ci).second;
256+
TextGlyph *glyph = (*ci).second;
256257
indent(out, indent_level + 2)
257258
<< glyph_index;
258259

@@ -269,7 +270,7 @@ write(ostream &out, int indent_level) const {
269270
}
270271
release_face(face);
271272

272-
out << ", count = " << glyph->_geom_count << "\n";
273+
out << '\n';
273274
}
274275
}
275276

@@ -285,7 +286,7 @@ write(ostream &out, int indent_level) const {
285286
// printable glyph.
286287
////////////////////////////////////////////////////////////////////
287288
bool DynamicTextFont::
288-
get_glyph(int character, const TextGlyph *&glyph) {
289+
get_glyph(int character, CPT(TextGlyph) &glyph) {
289290
if (!_is_valid) {
290291
glyph = (TextGlyph *)NULL;
291292
return false;
@@ -302,12 +303,12 @@ get_glyph(int character, const TextGlyph *&glyph) {
302303
if (ci != _cache.end()) {
303304
glyph = (*ci).second;
304305
} else {
305-
DynamicTextGlyph *dynamic_glyph = make_glyph(character, face, glyph_index);
306+
TextGlyph *dynamic_glyph = make_glyph(character, face, glyph_index);
306307
_cache.insert(Cache::value_type(glyph_index, dynamic_glyph));
307308
glyph = dynamic_glyph;
308309
}
309310

310-
if (glyph == (DynamicTextGlyph *)NULL) {
311+
if (glyph == (TextGlyph *)NULL) {
311312
glyph = get_invalid_glyph();
312313
glyph_index = 0;
313314
}
@@ -327,8 +328,7 @@ void DynamicTextFont::
327328
initialize() {
328329
_texture_margin = text_texture_margin;
329330
_poly_margin = text_poly_margin;
330-
_page_x_size = text_page_size[0];
331-
_page_y_size = text_page_size[1];
331+
_page_size.set(text_page_size[0], text_page_size[1]);
332332

333333
// We don't necessarily want to use mipmaps, since we don't want to
334334
// regenerate those every time the texture changes, but we probably
@@ -442,10 +442,10 @@ determine_tex_format() {
442442
// newly-created TextGlyph object, or NULL if the
443443
// glyph cannot be created for some reason.
444444
////////////////////////////////////////////////////////////////////
445-
DynamicTextGlyph *DynamicTextFont::
445+
TextGlyph *DynamicTextFont::
446446
make_glyph(int character, FT_Face face, int glyph_index) {
447447
if (!load_glyph(face, glyph_index, false)) {
448-
return (DynamicTextGlyph *)NULL;
448+
return (TextGlyph *)NULL;
449449
}
450450

451451
FT_GlyphSlot slot = face->glyph;
@@ -461,6 +461,7 @@ make_glyph(int character, FT_Face face, int glyph_index) {
461461
}
462462

463463
PN_stdfloat advance = slot->advance.x / 64.0;
464+
advance /= _font_pixels_per_unit;
464465

465466
if (_render_mode != RM_texture &&
466467
slot->format == ft_glyph_format_outline) {
@@ -520,8 +521,8 @@ make_glyph(int character, FT_Face face, int glyph_index) {
520521
_contours.clear();
521522
FT_Outline_Decompose(&slot->outline, &funcs, (void *)this);
522523

523-
PT(DynamicTextGlyph) glyph =
524-
new DynamicTextGlyph(character, advance / _font_pixels_per_unit);
524+
PT(TextGlyph) glyph =
525+
new TextGlyph(character, advance);
525526
switch (_render_mode) {
526527
case RM_wireframe:
527528
render_wireframe_contours(glyph);
@@ -553,8 +554,8 @@ make_glyph(int character, FT_Face face, int glyph_index) {
553554
if (bitmap.width == 0 || bitmap.rows == 0) {
554555
// If we got an empty bitmap, it's a special case.
555556

556-
PT(DynamicTextGlyph) glyph =
557-
new DynamicTextGlyph(character, advance / _font_pixels_per_unit);
557+
PT(TextGlyph) glyph =
558+
new TextGlyph(character, advance);
558559
_empty_glyphs.push_back(glyph);
559560
return glyph;
560561

@@ -571,7 +572,7 @@ make_glyph(int character, FT_Face face, int glyph_index) {
571572
// If the bitmap produced from the font doesn't require scaling
572573
// or any other processing before it goes to the texture, we can
573574
// just copy it directly into the texture.
574-
glyph = slot_glyph(character, bitmap.width, bitmap.rows);
575+
glyph = slot_glyph(character, bitmap.width, bitmap.rows, advance);
575576
copy_bitmap_to_texture(bitmap, glyph);
576577

577578
} else {
@@ -599,7 +600,7 @@ make_glyph(int character, FT_Face face, int glyph_index) {
599600
int_y_size += outline * 2;
600601
tex_x_size += outline * 2;
601602
tex_y_size += outline * 2;
602-
glyph = slot_glyph(character, int_x_size, int_y_size);
603+
glyph = slot_glyph(character, int_x_size, int_y_size, advance);
603604

604605
if (outline != 0) {
605606
// Pad the glyph image to make room for the outline.
@@ -612,11 +613,43 @@ make_glyph(int character, FT_Face face, int glyph_index) {
612613
}
613614
}
614615

615-
glyph->make_geom((int)floor(slot->bitmap_top + outline * _scale_factor + 0.5f),
616-
(int)floor(slot->bitmap_left - outline * _scale_factor + 0.5f),
617-
advance, _poly_margin,
618-
tex_x_size, tex_y_size,
619-
_font_pixels_per_unit, _tex_pixels_per_unit);
616+
DynamicTextPage *page = glyph->get_page();
617+
if (page != NULL) {
618+
int bitmap_top = (int)floor(slot->bitmap_top + outline * _scale_factor + 0.5f);
619+
int bitmap_left = (int)floor(slot->bitmap_left - outline * _scale_factor + 0.5f);
620+
621+
tex_x_size += glyph->_margin * 2;
622+
tex_y_size += glyph->_margin * 2;
623+
624+
// Determine the corners of the rectangle in geometric units.
625+
PN_stdfloat tex_poly_margin = _poly_margin / _tex_pixels_per_unit;
626+
PN_stdfloat origin_y = bitmap_top / _font_pixels_per_unit;
627+
PN_stdfloat origin_x = bitmap_left / _font_pixels_per_unit;
628+
629+
LVecBase4 dimensions(
630+
origin_x - tex_poly_margin,
631+
origin_y - tex_y_size / _tex_pixels_per_unit - tex_poly_margin,
632+
origin_x + tex_x_size / _tex_pixels_per_unit + tex_poly_margin,
633+
origin_y + tex_poly_margin);
634+
635+
// And the corresponding corners in UV units. We add 0.5f to center
636+
// the UV in the middle of its texel, to minimize roundoff errors
637+
// when we are close to 1-to-1 pixel size.
638+
LVecBase2i page_size = page->get_size();
639+
LVecBase4 texcoords(
640+
((PN_stdfloat)(glyph->_x - _poly_margin) + 0.5f) / page_size[0],
641+
1.0f - ((PN_stdfloat)(glyph->_y + _poly_margin + tex_y_size) + 0.5f) / page_size[1],
642+
((PN_stdfloat)(glyph->_x + _poly_margin + tex_x_size) + 0.5f) / page_size[0],
643+
1.0f - ((PN_stdfloat)(glyph->_y - _poly_margin) + 0.5f) / page_size[1]);
644+
645+
CPT(RenderState) state;
646+
state = RenderState::make(TextureAttrib::make(page),
647+
TransparencyAttrib::make(TransparencyAttrib::M_alpha));
648+
state = state->add_attrib(ColorAttrib::make_flat(LColor(1.0f, 1.0f, 1.0f, 1.0f)), -1);
649+
650+
glyph->set_quad(dimensions, texcoords, state);
651+
}
652+
620653
return glyph;
621654
}
622655
}
@@ -835,7 +868,7 @@ blend_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph,
835868
// filled in yet except with its size.
836869
////////////////////////////////////////////////////////////////////
837870
DynamicTextGlyph *DynamicTextFont::
838-
slot_glyph(int character, int x_size, int y_size) {
871+
slot_glyph(int character, int x_size, int y_size, PN_stdfloat advance) {
839872
// Increase the indicated size by the current margin.
840873
x_size += _texture_margin * 2;
841874
y_size += _texture_margin * 2;
@@ -850,7 +883,7 @@ slot_glyph(int character, int x_size, int y_size) {
850883

851884
do {
852885
DynamicTextPage *page = _pages[pi];
853-
DynamicTextGlyph *glyph = page->slot_glyph(character, x_size, y_size, _texture_margin);
886+
DynamicTextGlyph *glyph = page->slot_glyph(character, x_size, y_size, _texture_margin, advance);
854887
if (glyph != (DynamicTextGlyph *)NULL) {
855888
// Once we found a page to hold the glyph, that becomes our
856889
// new preferred page.
@@ -874,15 +907,15 @@ slot_glyph(int character, int x_size, int y_size) {
874907
// glyphs?
875908
if (garbage_collect() != 0) {
876909
// Yes, we just freed up some space. Try once more, recursively.
877-
return slot_glyph(character, x_size, y_size);
910+
return slot_glyph(character, x_size, y_size, advance);
878911

879912
} else {
880913
// No good; all recorded glyphs are actually in use. We need to
881914
// make a new page.
882915
_preferred_page = _pages.size();
883916
PT(DynamicTextPage) page = new DynamicTextPage(this, _preferred_page);
884917
_pages.push_back(page);
885-
return page->slot_glyph(character, x_size, y_size, _texture_margin);
918+
return page->slot_glyph(character, x_size, y_size, _texture_margin, advance);
886919
}
887920
}
888921

@@ -893,7 +926,7 @@ slot_glyph(int character, int x_size, int y_size) {
893926
// geometry, as a wireframe render.
894927
////////////////////////////////////////////////////////////////////
895928
void DynamicTextFont::
896-
render_wireframe_contours(DynamicTextGlyph *glyph) {
929+
render_wireframe_contours(TextGlyph *glyph) {
897930
PT(GeomVertexData) vdata = new GeomVertexData
898931
(string(), GeomVertexFormat::get_v3(),
899932
Geom::UH_static);
@@ -926,7 +959,7 @@ render_wireframe_contours(DynamicTextGlyph *glyph) {
926959
// geometry, as a polygon render.
927960
////////////////////////////////////////////////////////////////////
928961
void DynamicTextFont::
929-
render_polygon_contours(DynamicTextGlyph *glyph, bool face, bool extrude) {
962+
render_polygon_contours(TextGlyph *glyph, bool face, bool extrude) {
930963
PT(GeomVertexData) vdata = new GeomVertexData
931964
(string(), GeomVertexFormat::get_v3n3(),
932965
Geom::UH_static);

0 commit comments

Comments
 (0)