18 #undef interface // I don't know where this symbol is defined, but it interferes with FreeType. 60 DynamicTextFont(
const Filename &font_filename,
int face_index) {
62 _is_valid = load_font(font_filename, face_index);
63 TextFont::set_name(FreetypeFont::get_name());
64 TextFont::_line_height = FreetypeFont::get_line_height();
65 TextFont::_space_advance = FreetypeFont::get_space_advance();
67 _fg.set(1.0f, 1.0f, 1.0f, 1.0f);
68 _bg.set(1.0f, 1.0f, 1.0f, 0.0f);
69 _outline_color.set(1.0f, 1.0f, 1.0f, 0.0f);
70 _outline_width = 0.0f;
71 _outline_feather = 0.0f;
73 _tex_format = Texture::F_alpha;
74 _needs_image_processing =
false;
82 DynamicTextFont(
const char *font_data,
int data_length,
int face_index) {
84 _is_valid = load_font(font_data, data_length, face_index);
85 TextFont::set_name(FreetypeFont::get_name());
86 TextFont::_line_height = FreetypeFont::_line_height;
87 TextFont::_space_advance = FreetypeFont::_space_advance;
89 _fg.set(1.0f, 1.0f, 1.0f, 1.0f);
90 _bg.set(1.0f, 1.0f, 1.0f, 0.0f);
91 _outline_color.set(1.0f, 1.0f, 1.0f, 0.0f);
92 _outline_width = 0.0f;
93 _outline_feather = 0.0f;
95 _tex_format = Texture::F_alpha;
96 _needs_image_processing =
false;
103 DynamicTextFont(
const DynamicTextFont ©) :
106 _texture_margin(copy._texture_margin),
107 _poly_margin(copy._poly_margin),
108 _page_size(copy._page_size),
109 _minfilter(copy._minfilter),
110 _magfilter(copy._magfilter),
111 _anisotropic_degree(copy._anisotropic_degree),
112 _render_mode(copy._render_mode),
115 _outline_color(copy._outline_color),
116 _outline_width(copy._outline_width),
117 _outline_feather(copy._outline_feather),
118 _has_outline(copy._has_outline),
119 _tex_format(copy._tex_format),
120 _needs_image_processing(copy._needs_image_processing),
132 if (_hb_font !=
nullptr) {
133 hb_font_destroy(_hb_font);
143 return new DynamicTextFont(*
this);
152 int DynamicTextFont::
153 get_num_pages()
const {
154 return _pages.size();
163 DynamicTextPage *DynamicTextFont::
164 get_page(
int n)
const {
165 nassertr(n >= 0 && n < (
int)_pages.size(),
nullptr);
173 int DynamicTextFont::
175 int removed_count = 0;
180 for (ci = _cache.begin(); ci != _cache.end(); ++ci) {
184 new_cache.insert(new_cache.end(), (*ci));
190 _cache.swap(new_cache);
194 for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
195 DynamicTextPage *page = (*pi);
196 page->garbage_collect(
this);
199 return removed_count;
211 void DynamicTextFont::
215 _empty_glyphs.clear();
218 if (_hb_font !=
nullptr) {
219 hb_font_destroy(_hb_font);
228 void DynamicTextFont::
229 write(std::ostream &out,
int indent_level)
const {
230 static const int max_glyph_name = 1024;
231 char glyph_name[max_glyph_name];
234 <<
"DynamicTextFont " << get_name() <<
", " 235 << get_num_pages() <<
" pages, " 236 << _cache.size() <<
" glyphs:\n";
237 Cache::const_iterator ci;
238 for (ci = _cache.begin(); ci != _cache.end(); ++ci) {
239 int glyph_index = (*ci).first;
240 indent(out, indent_level + 2)
243 FT_Face face = acquire_face();
244 if (FT_HAS_GLYPH_NAMES(face)) {
245 int error = FT_Get_Glyph_Name(face, glyph_index,
246 glyph_name, max_glyph_name);
250 if (!error && strcmp(glyph_name,
".notdef") != 0) {
251 out <<
" (" << glyph_name <<
")";
267 bool DynamicTextFont::
268 get_glyph(
int character, CPT(
TextGlyph) &glyph) {
274 FT_Face face = acquire_face();
275 int glyph_index = FT_Get_Char_Index(face, character);
276 if (text_cat.is_spam()) {
278 << *
this <<
" maps " << character <<
" to glyph " << glyph_index <<
"\n";
281 Cache::iterator ci = _cache.find(glyph_index);
282 if (ci != _cache.end()) {
283 glyph = (*ci).second;
285 glyph = make_glyph(character, face, glyph_index);
286 _cache.insert(Cache::value_type(glyph_index, glyph.p()));
289 if (glyph.is_null()) {
290 glyph = get_invalid_glyph();
295 return (glyph_index != 0);
303 PN_stdfloat DynamicTextFont::
304 get_kerning(
int first,
int second)
const {
309 FT_Face face = acquire_face();
310 if (!FT_HAS_KERNING(face)) {
315 int first_index = FT_Get_Char_Index(face, first);
316 int second_index = FT_Get_Char_Index(face, second);
319 FT_Get_Kerning(face, first_index, second_index, FT_KERNING_DEFAULT, &delta);
322 return delta.x / (_font_pixels_per_unit * 64);
328 bool DynamicTextFont::
329 get_glyph_by_index(
int character,
int glyph_index, CPT(
TextGlyph) &glyph) {
335 Cache::iterator ci = _cache.find(glyph_index);
336 if (ci != _cache.end()) {
337 glyph = (*ci).second;
339 FT_Face face = acquire_face();
340 glyph = make_glyph(character, face, glyph_index);
341 _cache.insert(Cache::value_type(glyph_index, glyph.p()));
345 if (glyph.is_null()) {
346 glyph = get_invalid_glyph();
357 hb_font_t *DynamicTextFont::
358 get_hb_font()
const {
360 if (_hb_font !=
nullptr) {
364 FT_Face face = acquire_face();
365 _hb_font = hb_ft_font_create(face,
nullptr);
377 void DynamicTextFont::
379 _texture_margin = text_texture_margin;
380 _poly_margin = text_poly_margin;
381 _page_size.set(text_page_size[0], text_page_size[1]);
386 _minfilter = text_minfilter;
387 _magfilter = text_magfilter;
391 _anisotropic_degree = text_anisotropic_degree;
393 _render_mode = text_render_mode;
394 _winding_order = WO_default;
405 void DynamicTextFont::
408 for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
409 DynamicTextPage *page = (*pi);
410 page->set_minfilter(_minfilter);
411 page->set_magfilter(_magfilter);
412 page->set_anisotropic_degree(_anisotropic_degree);
420 void DynamicTextFont::
421 determine_tex_format() {
422 nassertv(get_num_pages() == 0);
424 _has_outline = (_outline_color != _bg && _outline_width > 0.0f);
425 _needs_image_processing =
true;
427 bool needs_color =
false;
428 bool needs_grayscale =
false;
429 bool needs_alpha =
false;
431 if (_fg[1] != _fg[0] || _fg[2] != _fg[0] ||
432 _bg[1] != _bg[0] || _bg[2] != _bg[0] ||
433 (_has_outline && (_outline_color[1] != _outline_color[0] || _outline_color[2] != _outline_color[0]))) {
438 }
else if (_fg[0] != 1.0f || _fg[1] != 1.0f || _fg[2] != 1.0f ||
439 _bg[0] != 1.0f || _bg[1] != 1.0f || _bg[2] != 1.0f ||
440 (_has_outline && (_outline_color[0] != 1.0f || _outline_color[1] != 1.0f || _outline_color[2] != 1.0f))) {
442 needs_grayscale =
true;
445 if (_fg[3] != 1.0f || _bg[3] != 1.0f ||
446 (_has_outline && (_outline_color[3] != 1.0f))) {
453 _tex_format = Texture::F_rgba;
455 _tex_format = Texture::F_rgb;
457 }
else if (needs_grayscale) {
459 _tex_format = Texture::F_luminance_alpha;
461 _tex_format = Texture::F_luminance;
465 _tex_format = Texture::F_alpha;
468 _fg == LColor(1.0f, 1.0f, 1.0f, 1.0f) &&
469 _bg == LColor(1.0f, 1.0f, 1.0f, 0.0f)) {
472 _needs_image_processing =
false;
477 _tex_format = Texture::F_luminance;
488 make_glyph(
int character, FT_Face face,
int glyph_index) {
489 if (!load_glyph(face, glyph_index,
false)) {
493 FT_GlyphSlot slot = face->glyph;
494 FT_Bitmap &bitmap = slot->bitmap;
496 if ((bitmap.width == 0 || bitmap.rows == 0) && (glyph_index == 0)) {
505 PN_stdfloat advance = slot->advance.x / 64.0;
506 advance /= _font_pixels_per_unit;
508 if (_render_mode != RM_texture &&
509 slot->format == ft_glyph_format_outline) {
534 decompose_outline(slot->outline);
538 switch (_render_mode) {
540 render_wireframe_contours(glyph);
544 render_polygon_contours(glyph,
true,
false);
548 render_polygon_contours(glyph,
false,
true);
552 render_polygon_contours(glyph,
true,
true);
556 case RM_distance_field:
562 PN_stdfloat tex_x_size, tex_y_size, tex_x_orig, tex_y_orig;
564 TransparencyAttrib::Mode alpha_mode;
566 if (_render_mode == RM_texture) {
568 if (slot->format != ft_glyph_format_bitmap) {
569 FT_Render_Glyph(slot, ft_render_mode_normal);
572 tex_x_size = bitmap.width;
573 tex_y_size = bitmap.rows;
574 tex_x_orig = slot->bitmap_left;
575 tex_y_orig = slot->bitmap_top;
576 alpha_mode = TransparencyAttrib::M_alpha;
581 FT_Outline_Get_CBox(&slot->outline, &bounds);
583 bounds.xMin = bounds.xMin & ~63;
584 bounds.yMin = bounds.yMin & ~63;
585 bounds.xMax = (bounds.xMax + 63) & ~63;
586 bounds.yMax = (bounds.yMax + 63) & ~63;
588 tex_x_size = (bounds.xMax - bounds.xMin) >> 6;
589 tex_y_size = (bounds.yMax - bounds.yMin) >> 6;
590 tex_x_orig = (bounds.xMin >> 6);
591 tex_y_orig = (bounds.yMax >> 6);
592 alpha_mode = TransparencyAttrib::M_binary;
595 if (tex_x_size == 0 || tex_y_size == 0) {
599 new DynamicTextGlyph(character, advance);
600 _empty_glyphs.push_back(glyph);
604 DynamicTextGlyph *glyph;
608 if (_render_mode == RM_distance_field) {
609 tex_x_size /= _scale_factor;
610 tex_y_size /= _scale_factor;
611 int int_x_size = (int)ceil(tex_x_size);
612 int int_y_size = (int)ceil(tex_y_size);
615 int_x_size += outline * 2;
616 int_y_size += outline * 2;
617 tex_x_size += outline * 2;
618 tex_y_size += outline * 2;
620 PNMImage image(int_x_size, int_y_size, PNMImage::CT_grayscale);
621 render_distance_field(image, outline, bounds.xMin, bounds.yMin);
623 glyph = slot_glyph(character, int_x_size, int_y_size, advance);
624 if (!_needs_image_processing) {
625 copy_pnmimage_to_texture(image, glyph);
627 blend_pnmimage_to_texture(image, glyph, _fg);
630 }
else if (_tex_pixels_per_unit == _font_pixels_per_unit &&
631 !_needs_image_processing) {
635 glyph = slot_glyph(character, bitmap.width, bitmap.rows, advance);
636 copy_bitmap_to_texture(bitmap, glyph);
641 tex_x_size /= _scale_factor;
642 tex_y_size /= _scale_factor;
643 int int_x_size = (int)ceil(tex_x_size);
644 int int_y_size = (int)ceil(tex_y_size);
645 int bmp_x_size = (int)(int_x_size * _scale_factor + 0.5f);
646 int bmp_y_size = (int)(int_y_size * _scale_factor + 0.5f);
648 PNMImage image(bmp_x_size, bmp_y_size, PNMImage::CT_grayscale);
649 copy_bitmap_to_pnmimage(bitmap, image);
651 PNMImage reduced(int_x_size, int_y_size, PNMImage::CT_grayscale);
652 reduced.quick_filter_from(image);
655 PN_stdfloat outline_pixels = _outline_width / _points_per_unit * _tex_pixels_per_unit;
656 outline = (int)ceil(outline_pixels);
658 int_x_size += outline * 2;
659 int_y_size += outline * 2;
660 tex_x_size += outline * 2;
661 tex_y_size += outline * 2;
662 glyph = slot_glyph(character, int_x_size, int_y_size, advance);
666 PNMImage padded(int_x_size, int_y_size, PNMImage::CT_grayscale);
667 padded.copy_sub_image(reduced, outline, outline);
668 copy_pnmimage_to_texture(padded, glyph);
671 copy_pnmimage_to_texture(reduced, glyph);
675 DynamicTextPage *page = glyph->get_page();
676 if (page !=
nullptr) {
677 int bitmap_top = (int)floor(tex_y_orig + outline * _scale_factor + 0.5f);
678 int bitmap_left = (int)floor(tex_x_orig - outline * _scale_factor + 0.5f);
680 tex_x_size += glyph->_margin * 2;
681 tex_y_size += glyph->_margin * 2;
684 PN_stdfloat tex_poly_margin = _poly_margin / _tex_pixels_per_unit;
685 PN_stdfloat origin_y = bitmap_top / _font_pixels_per_unit;
686 PN_stdfloat origin_x = bitmap_left / _font_pixels_per_unit;
688 LVecBase4 dimensions(
689 origin_x - tex_poly_margin,
690 origin_y - tex_y_size / _tex_pixels_per_unit - tex_poly_margin,
691 origin_x + tex_x_size / _tex_pixels_per_unit + tex_poly_margin,
692 origin_y + tex_poly_margin);
697 LVecBase2i page_size = page->get_size();
699 ((PN_stdfloat)(glyph->_x - _poly_margin) + 0.5f) / page_size[0],
700 1.0f - ((PN_stdfloat)(glyph->_y + _poly_margin + tex_y_size) + 0.5f) / page_size[1],
701 ((PN_stdfloat)(glyph->_x + _poly_margin + tex_x_size) + 0.5f) / page_size[0],
702 1.0f - ((PN_stdfloat)(glyph->_y - _poly_margin) + 0.5f) / page_size[1]);
705 state = RenderState::make(TextureAttrib::make(page),
706 TransparencyAttrib::make(alpha_mode));
707 state = state->add_attrib(ColorAttrib::make_flat(LColor(1.0f, 1.0f, 1.0f, 1.0f)), -1);
709 glyph->set_quad(dimensions, texcoords, state);
720 void DynamicTextFont::
721 copy_bitmap_to_texture(
const FT_Bitmap &bitmap, DynamicTextGlyph *glyph) {
722 if (bitmap.pixel_mode == ft_pixel_mode_grays && bitmap.num_grays == 256) {
725 unsigned char *buffer_row = bitmap.buffer;
726 for (
int yi = 0; yi < (int)bitmap.rows; yi++) {
728 unsigned char *texture_row = glyph->get_row(yi);
729 nassertv(texture_row !=
nullptr);
730 memcpy(texture_row, buffer_row, bitmap.width);
731 buffer_row += bitmap.pitch;
734 }
else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
737 unsigned char *buffer_row = bitmap.buffer;
738 for (
int yi = 0; yi < (int)bitmap.rows; yi++) {
739 unsigned char *texture_row = glyph->get_row(yi);
740 nassertv(texture_row !=
nullptr);
743 unsigned char *b = buffer_row;
744 for (
int xi = 0; xi < (int)bitmap.width; xi++) {
746 texture_row[xi] = 0xff;
748 texture_row[xi] = 0x00;
757 buffer_row += bitmap.pitch;
761 }
else if (bitmap.pixel_mode == ft_pixel_mode_grays) {
764 unsigned char *buffer_row = bitmap.buffer;
765 for (
int yi = 0; yi < (int)bitmap.rows; yi++) {
766 unsigned char *texture_row = glyph->get_row(yi);
767 nassertv(texture_row !=
nullptr);
768 for (
int xi = 0; xi < (int)bitmap.width; xi++) {
769 texture_row[xi] = (int)(buffer_row[xi] * 255) / (bitmap.num_grays - 1);
771 buffer_row += bitmap.pitch;
776 <<
"Unexpected pixel mode in bitmap: " << (int)bitmap.pixel_mode <<
"\n";
784 void DynamicTextFont::
785 copy_pnmimage_to_texture(
const PNMImage &image, DynamicTextGlyph *glyph) {
786 if (!_needs_image_processing) {
788 nassertv(glyph->_page->get_num_components() == 1);
789 for (
int yi = 0; yi < image.
get_y_size(); yi++) {
790 unsigned char *texture_row = glyph->get_row(yi);
791 nassertv(texture_row !=
nullptr);
792 for (
int xi = 0; xi < image.
get_x_size(); xi++) {
801 PN_stdfloat outline_pixels = _outline_width / _points_per_unit * _tex_pixels_per_unit;
808 PN_stdfloat f = _outline_feather * _outline_feather;
810 for (
int yi = 0; yi < outline.get_y_size(); yi++) {
811 for (
int xi = 0; xi < outline.get_x_size(); xi++) {
812 PN_stdfloat v = outline.get_gray(xi, yi);
817 outline.set_gray(xi, yi, 1.0);
820 outline.set_gray(xi, yi, v / f);
826 blend_pnmimage_to_texture(outline, glyph, _outline_color);
832 blend_pnmimage_to_texture(image, glyph, _fg);
841 void DynamicTextFont::
842 blend_pnmimage_to_texture(
const PNMImage &image, DynamicTextGlyph *glyph,
844 LColor fgv = fg * 255.0f;
846 int num_components = glyph->_page->get_num_components();
847 if (num_components == 1) {
850 if (glyph->_page->get_format() != Texture::F_alpha) {
854 for (
int yi = 0; yi < image.
get_y_size(); yi++) {
855 unsigned char *texture_row = glyph->get_row(yi);
856 nassertv(texture_row !=
nullptr);
857 for (
int xi = 0; xi < image.
get_x_size(); xi++) {
858 unsigned char *tr = texture_row + xi;
859 PN_stdfloat t = (PN_stdfloat)image.
get_gray(xi, yi);
860 tr[0] = (
unsigned char)(tr[0] + t * (fgv[ci] - tr[0]));
864 }
else if (num_components == 2) {
867 for (
int yi = 0; yi < image.
get_y_size(); yi++) {
868 unsigned char *texture_row = glyph->get_row(yi);
869 nassertv(texture_row !=
nullptr);
870 for (
int xi = 0; xi < image.
get_x_size(); xi++) {
871 unsigned char *tr = texture_row + xi * 2;
872 PN_stdfloat t = (PN_stdfloat)image.
get_gray(xi, yi);
873 tr[0] = (
unsigned char)(tr[0] + t * (fgv[0] - tr[0]));
874 tr[1] = (
unsigned char)(tr[1] + t * (fgv[3] - tr[1]));
878 }
else if (num_components == 3) {
881 for (
int yi = 0; yi < image.
get_y_size(); yi++) {
882 unsigned char *texture_row = glyph->get_row(yi);
883 nassertv(texture_row !=
nullptr);
884 for (
int xi = 0; xi < image.
get_x_size(); xi++) {
885 unsigned char *tr = texture_row + xi * 3;
886 PN_stdfloat t = (PN_stdfloat)image.
get_gray(xi, yi);
887 tr[0] = (
unsigned char)(tr[0] + t * (fgv[2] - tr[0]));
888 tr[1] = (
unsigned char)(tr[1] + t * (fgv[1] - tr[1]));
889 tr[2] = (
unsigned char)(tr[2] + t * (fgv[0] - tr[2]));
896 for (
int yi = 0; yi < image.
get_y_size(); yi++) {
897 unsigned char *texture_row = glyph->get_row(yi);
898 nassertv(texture_row !=
nullptr);
899 for (
int xi = 0; xi < image.
get_x_size(); xi++) {
900 unsigned char *tr = texture_row + xi * 4;
901 PN_stdfloat t = (PN_stdfloat)image.
get_gray(xi, yi);
902 tr[0] = (
unsigned char)(tr[0] + t * (fgv[2] - tr[0]));
903 tr[1] = (
unsigned char)(tr[1] + t * (fgv[1] - tr[1]));
904 tr[2] = (
unsigned char)(tr[2] + t * (fgv[0] - tr[2]));
905 tr[3] = (
unsigned char)(tr[3] + t * (fgv[3] - tr[3]));
917 DynamicTextGlyph *DynamicTextFont::
918 slot_glyph(
int character,
int x_size,
int y_size, PN_stdfloat advance) {
920 x_size += _texture_margin * 2;
921 y_size += _texture_margin * 2;
923 if (!_pages.empty()) {
928 _preferred_page = _preferred_page % _pages.size();
929 int pi = _preferred_page;
932 DynamicTextPage *page = _pages[pi];
933 DynamicTextGlyph *glyph = page->slot_glyph(character, x_size, y_size, _texture_margin, advance);
934 if (glyph !=
nullptr) {
937 _preferred_page = pi;
941 if (page->is_empty()) {
944 <<
"Glyph of size " << x_size <<
" by " << y_size
945 <<
" pixels won't fit on an empty page.\n";
949 pi = (pi + 1) % _pages.size();
950 }
while (pi != _preferred_page);
954 if (garbage_collect() != 0) {
956 return slot_glyph(character, x_size, y_size, advance);
961 _preferred_page = _pages.size();
962 PT(DynamicTextPage) page =
new DynamicTextPage(
this, _preferred_page);
963 _pages.push_back(page);
964 return page->slot_glyph(character, x_size, y_size, _texture_margin, advance);
972 void DynamicTextFont::
973 render_wireframe_contours(
TextGlyph *glyph) {
981 Contours::const_iterator ci;
982 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
983 const Contour &contour = (*ci);
984 Points::const_iterator pi;
986 for (pi = contour._points.begin(); pi != contour._points.end(); ++pi) {
987 const LPoint2 &p = (*pi)._p;
988 vertex.add_data3(p[0], 0.0f, p[1]);
991 lines->add_next_vertices(contour._points.size());
992 lines->close_primitive();
995 glyph->
set_geom(vdata, lines, RenderState::make_empty());
1003 void DynamicTextFont::
1004 render_polygon_contours(
TextGlyph *glyph,
bool face,
bool extrude) {
1014 Contours::iterator ci;
1019 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
1020 Contour &contour = (*ci);
1024 for (
size_t i = 0; i < contour._points.size() - 1; ++i) {
1025 const LPoint2 &p = contour._points[i]._p;
1026 vertex.add_data3(p[0], 0.0f, p[1]);
1027 normal.add_data3(0.0f, -1.0f, 0.0f);
1036 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
1037 const Contour &contour = (*ci);
1039 if (contour._is_solid && !contour._points.empty()) {
1041 for (
size_t i = 0; i < contour._points.size() - 1; ++i) {
1046 Contours::iterator cj;
1047 for (cj = _contours.begin(); cj != _contours.end(); ++cj) {
1048 Contour &hole = (*cj);
1049 if (!hole._is_solid && !hole._points.empty()) {
1051 for (
size_t j = 0; j < hole._points.size() - 1; ++j) {
1059 for (
int ti = 0; ti < num_triangles; ++ti) {
1063 tris->close_primitive();
1073 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
1074 const Contour &contour = (*ci);
1076 for (
size_t i = 0; i < contour._points.size(); ++i) {
1077 const ContourPoint &cp = contour._points[i];
1078 const LPoint2 &p = cp._p;
1079 const LVector2 &t_in = cp._in;
1080 const LVector2 &t_out = cp._out;
1082 LVector3 n_in(t_in[1], 0.0f, -t_in[0]);
1083 vertex.add_data3(p[0], 1.0f, p[1]);
1084 vertex.add_data3(p[0], 0.0f, p[1]);
1085 normal.add_data3(n_in);
1086 normal.add_data3(n_in);
1089 int vi = vertex.get_write_row();
1090 tris->add_vertex(vi - 4);
1091 tris->add_vertex(vi - 2);
1092 tris->add_vertex(vi - 1);
1093 tris->close_primitive();
1094 tris->add_vertex(vi - 1);
1095 tris->add_vertex(vi - 3);
1096 tris->add_vertex(vi - 4);
1097 tris->close_primitive();
1100 if (i != contour._points.size() - 1 && !t_in.almost_equal(t_out)) {
1103 LVector3 n_out(t_out[1], 0.0f, -t_out[0]);
1104 vertex.add_data3(p[0], 1.0f, p[1]);
1105 vertex.add_data3(p[0], 0.0f, p[1]);
1106 normal.add_data3(n_out);
1107 normal.add_data3(n_out);
1114 int back_start = vertex.get_write_row();
1116 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
1117 Contour &contour = (*ci);
1118 for (
size_t i = 0; i < contour._points.size() - 1; ++i) {
1119 const LPoint2 &p = contour._points[i]._p;
1120 vertex.add_data3(p[0], 1.0f, p[1]);
1121 normal.add_data3(0.0f, 1.0f, 0.0f);
1126 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
1127 const Contour &contour = (*ci);
1129 if (contour._is_solid && !contour._points.empty()) {
1131 for (
size_t i = 0; i < contour._points.size() - 1; ++i) {
1136 Contours::iterator cj;
1137 for (cj = _contours.begin(); cj != _contours.end(); ++cj) {
1138 Contour &hole = (*cj);
1139 if (!hole._is_solid && !hole._points.empty()) {
1141 for (
size_t j = 0; j < hole._points.size() - 1; ++j) {
1149 for (
int ti = 0; ti < num_triangles; ++ti) {
1153 tris->close_primitive();
1160 glyph->
set_geom(vdata, tris, RenderState::make_empty());
1167 #endif // HAVE_FREETYPE get_ref_count
Returns the current reference count.
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
xelval get_gray_val(int x, int y) const
Returns the gray component color at the indicated pixel.
void triangulate()
Does the work of triangulating the specified polygon.
float get_gray(int x, int y) const
Returns the gray component color at the indicated pixel.
int get_triangle_v0(int n) const
Returns vertex 0 of the nth triangle generated by the previous call to triangulate().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void begin_hole()
Finishes the previous hole, if any, and prepares to add a new hole.
int get_triangle_v2(int n) const
Returns vertex 2 of the nth triangle generated by the previous call to triangulate().
void set_geom(GeomVertexData *vdata, GeomPrimitive *prim, const RenderState *state)
Sets the geom from a pre-built Geom object.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void add_hole_vertex(int index)
Adds the next consecutive vertex of the current hole.
An encapsulation of a font; i.e.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
void clear_polygon()
Removes the current polygon definition (and its set of holes), but does not clear the vertex pool.
The name of a file, such as a texture file or an Egg file.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
This class can triangulate a convex or concave polygon, even one with holes.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
A representation of a single glyph (character) from a font.
void gaussian_filter_from(float radius, const PNMImage ©)
Makes a resized copy of the indicated image into this one using the indicated filter.
bool is_left_winding() const
Returns true if the polygon vertices are listed in counterclockwise order, or false if they appear to...
int get_num_triangles() const
Returns the number of triangles generated by the previous call to triangulate().
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
get_num_vertices
Returns the number of vertices in the pool.
void add_polygon_vertex(int index)
Adds the next consecutive vertex of the polygon.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
Defines a series of line strips.
Defines a series of disconnected triangles.
TypeHandle is the identifier used to differentiate C++ class types.
int get_triangle_v1(int n) const
Returns vertex 1 of the nth triangle generated by the previous call to triangulate().
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
int add_vertex(const LPoint2d &point)
Adds a new vertex to the vertex pool.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.