60DynamicTextFont(
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;
82DynamicTextFont(
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;
103DynamicTextFont(
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);
153get_num_pages()
const {
154 return _pages.size();
163DynamicTextPage *DynamicTextFont::
164get_page(
int n)
const {
165 nassertr(n >= 0 && n < (
int)_pages.size(),
nullptr);
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;
211void DynamicTextFont::
215 _empty_glyphs.clear();
218 if (_hb_font !=
nullptr) {
219 hb_font_destroy(_hb_font);
228void DynamicTextFont::
229write(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 <<
")";
267bool DynamicTextFont::
268get_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);
303PN_stdfloat DynamicTextFont::
304get_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);
328bool DynamicTextFont::
329get_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();
357hb_font_t *DynamicTextFont::
360 if (_hb_font !=
nullptr) {
364 FT_Face face = acquire_face();
365 _hb_font = hb_ft_font_create(face,
nullptr);
377void 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;
405void 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);
420void DynamicTextFont::
421determine_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;
488make_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);
720void DynamicTextFont::
721copy_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";
784void DynamicTextFont::
785copy_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;
802 outline.gaussian_filter_from(outline_pixels * 0.707, image);
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);
841void DynamicTextFont::
842blend_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]));
917DynamicTextGlyph *DynamicTextFont::
918slot_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);
972void DynamicTextFont::
973render_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());
1003void DynamicTextFont::
1004render_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());
The name of a file, such as a texture file or an Egg file.
Defines a series of line strips.
Defines a series of disconnected triangles.
This defines the actual numeric vertex data stored in a Geom, in the structure defined by a particula...
This object provides a high-level interface for quickly writing a sequence of numeric values from a v...
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
float get_gray(int x, int y) const
Returns the gray component color at the indicated pixel.
xelval get_gray_val(int x, int y) const
Returns the gray component color at the indicated pixel.
get_ref_count
Returns the current reference count.
This represents a unique collection of RenderAttrib objects that correspond to a particular renderabl...
An encapsulation of a font; i.e.
A representation of a single glyph (character) from a font.
void set_geom(GeomVertexData *vdata, GeomPrimitive *prim, const RenderState *state)
Sets the geom from a pre-built Geom object.
This class can triangulate a convex or concave polygon, even one with holes.
int get_triangle_v0(int n) const
Returns vertex 0 of the nth triangle generated by the previous call to triangulate().
void add_polygon_vertex(int index)
Adds the next consecutive vertex of the polygon.
void clear_polygon()
Removes the current polygon definition (and its set of holes), but does not clear the vertex pool.
bool is_left_winding() const
Returns true if the polygon vertices are listed in counterclockwise order, or false if they appear to...
int get_triangle_v1(int n) const
Returns vertex 1 of the nth triangle generated by the previous call to triangulate().
int get_num_triangles() const
Returns the number of triangles generated by the previous call to triangulate().
int add_vertex(const LPoint2d &point)
Adds a new vertex to the vertex pool.
void add_hole_vertex(int index)
Adds the next consecutive vertex of the current hole.
void triangulate()
Does the work of triangulating the specified polygon.
void begin_hole()
Finishes the previous hole, if any, and prepares to add a new hole.
get_num_vertices
Returns the number of vertices in the pool.
int get_triangle_v2(int n) const
Returns vertex 2 of the nth triangle generated by the previous call to triangulate().
TypeHandle is the identifier used to differentiate C++ class types.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
std::ostream & indent(std::ostream &out, int indent_level)
A handy function for doing text formatting.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.