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, _native_antialias ? ft_render_mode_normal : ft_render_mode_mono);
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 (glyph ==
nullptr) {
627 if (!_needs_image_processing) {
628 copy_pnmimage_to_texture(image, glyph);
630 blend_pnmimage_to_texture(image, glyph, _fg);
633 }
else if (_tex_pixels_per_unit == _font_pixels_per_unit &&
634 !_needs_image_processing) {
638 glyph = slot_glyph(character, bitmap.width, bitmap.rows, advance);
639 if (glyph ==
nullptr) {
642 copy_bitmap_to_texture(bitmap, glyph);
647 tex_x_size /= _scale_factor;
648 tex_y_size /= _scale_factor;
649 int int_x_size = (int)ceil(tex_x_size);
650 int int_y_size = (int)ceil(tex_y_size);
651 int bmp_x_size = (int)(int_x_size * _scale_factor + 0.5f);
652 int bmp_y_size = (int)(int_y_size * _scale_factor + 0.5f);
654 PNMImage image(bmp_x_size, bmp_y_size, PNMImage::CT_grayscale);
655 copy_bitmap_to_pnmimage(bitmap, image);
657 PNMImage reduced(int_x_size, int_y_size, PNMImage::CT_grayscale);
658 reduced.quick_filter_from(image);
661 PN_stdfloat outline_pixels = _outline_width / _points_per_unit * _tex_pixels_per_unit;
662 outline = (int)ceil(outline_pixels);
664 int_x_size += outline * 2;
665 int_y_size += outline * 2;
666 tex_x_size += outline * 2;
667 tex_y_size += outline * 2;
668 glyph = slot_glyph(character, int_x_size, int_y_size, advance);
669 if (glyph ==
nullptr) {
675 PNMImage padded(int_x_size, int_y_size, PNMImage::CT_grayscale);
676 padded.copy_sub_image(reduced, outline, outline);
677 copy_pnmimage_to_texture(padded, glyph);
680 copy_pnmimage_to_texture(reduced, glyph);
684 DynamicTextPage *page = glyph->get_page();
685 if (page !=
nullptr) {
686 int bitmap_top = (int)floor(tex_y_orig + outline * _scale_factor + 0.5f);
687 int bitmap_left = (int)floor(tex_x_orig - outline * _scale_factor + 0.5f);
689 tex_x_size += glyph->_margin * 2;
690 tex_y_size += glyph->_margin * 2;
693 PN_stdfloat tex_poly_margin = _poly_margin / _tex_pixels_per_unit;
694 PN_stdfloat origin_y = bitmap_top / _font_pixels_per_unit;
695 PN_stdfloat origin_x = bitmap_left / _font_pixels_per_unit;
697 LVecBase4 dimensions(
698 origin_x - tex_poly_margin,
699 origin_y - tex_y_size / _tex_pixels_per_unit - tex_poly_margin,
700 origin_x + tex_x_size / _tex_pixels_per_unit + tex_poly_margin,
701 origin_y + tex_poly_margin);
706 LVecBase2i page_size = page->get_size();
708 ((PN_stdfloat)(glyph->_x - _poly_margin) + 0.5f) / page_size[0],
709 1.0f - ((PN_stdfloat)(glyph->_y + _poly_margin + tex_y_size) + 0.5f) / page_size[1],
710 ((PN_stdfloat)(glyph->_x + _poly_margin + tex_x_size) + 0.5f) / page_size[0],
711 1.0f - ((PN_stdfloat)(glyph->_y - _poly_margin) + 0.5f) / page_size[1]);
714 state = RenderState::make(TextureAttrib::make(page),
715 TransparencyAttrib::make(alpha_mode));
716 state = state->add_attrib(ColorAttrib::make_flat(LColor(1.0f, 1.0f, 1.0f, 1.0f)), -1);
718 glyph->set_quad(dimensions, texcoords, state);
729void DynamicTextFont::
730copy_bitmap_to_texture(
const FT_Bitmap &bitmap, DynamicTextGlyph *glyph) {
731 if (bitmap.pixel_mode == ft_pixel_mode_grays && bitmap.num_grays == 256) {
734 unsigned char *buffer_row = bitmap.buffer;
735 for (
int yi = 0; yi < (int)bitmap.rows; yi++) {
737 unsigned char *texture_row = glyph->get_row(yi);
738 nassertv(texture_row !=
nullptr);
739 memcpy(texture_row, buffer_row, bitmap.width);
740 buffer_row += bitmap.pitch;
743 }
else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
746 unsigned char *buffer_row = bitmap.buffer;
747 for (
int yi = 0; yi < (int)bitmap.rows; yi++) {
748 unsigned char *texture_row = glyph->get_row(yi);
749 nassertv(texture_row !=
nullptr);
752 unsigned char *b = buffer_row;
753 for (
int xi = 0; xi < (int)bitmap.width; xi++) {
755 texture_row[xi] = 0xff;
757 texture_row[xi] = 0x00;
766 buffer_row += bitmap.pitch;
770 }
else if (bitmap.pixel_mode == ft_pixel_mode_grays) {
773 unsigned char *buffer_row = bitmap.buffer;
774 for (
int yi = 0; yi < (int)bitmap.rows; yi++) {
775 unsigned char *texture_row = glyph->get_row(yi);
776 nassertv(texture_row !=
nullptr);
777 for (
int xi = 0; xi < (int)bitmap.width; xi++) {
778 texture_row[xi] = (int)(buffer_row[xi] * 255) / (bitmap.num_grays - 1);
780 buffer_row += bitmap.pitch;
785 <<
"Unexpected pixel mode in bitmap: " << (int)bitmap.pixel_mode <<
"\n";
793void DynamicTextFont::
794copy_pnmimage_to_texture(
const PNMImage &image, DynamicTextGlyph *glyph) {
795 if (!_needs_image_processing) {
797 nassertv(glyph->_page->get_num_components() == 1);
798 for (
int yi = 0; yi < image.
get_y_size(); yi++) {
799 unsigned char *texture_row = glyph->get_row(yi);
800 nassertv(texture_row !=
nullptr);
801 for (
int xi = 0; xi < image.
get_x_size(); xi++) {
810 PN_stdfloat outline_pixels = _outline_width / _points_per_unit * _tex_pixels_per_unit;
811 outline.gaussian_filter_from(outline_pixels * 0.707, image);
817 PN_stdfloat f = _outline_feather * _outline_feather;
819 for (
int yi = 0; yi < outline.get_y_size(); yi++) {
820 for (
int xi = 0; xi < outline.get_x_size(); xi++) {
821 PN_stdfloat v = outline.get_gray(xi, yi);
826 outline.set_gray(xi, yi, 1.0);
829 outline.set_gray(xi, yi, v / f);
835 blend_pnmimage_to_texture(outline, glyph, _outline_color);
841 blend_pnmimage_to_texture(image, glyph, _fg);
850void DynamicTextFont::
851blend_pnmimage_to_texture(
const PNMImage &image, DynamicTextGlyph *glyph,
853 LColor fgv = fg * 255.0f;
855 int num_components = glyph->_page->get_num_components();
856 if (num_components == 1) {
859 if (glyph->_page->get_format() != Texture::F_alpha) {
863 for (
int yi = 0; yi < image.
get_y_size(); yi++) {
864 unsigned char *texture_row = glyph->get_row(yi);
865 nassertv(texture_row !=
nullptr);
866 for (
int xi = 0; xi < image.
get_x_size(); xi++) {
867 unsigned char *tr = texture_row + xi;
868 PN_stdfloat t = (PN_stdfloat)image.
get_gray(xi, yi);
869 tr[0] = (
unsigned char)(tr[0] + t * (fgv[ci] - tr[0]));
873 }
else if (num_components == 2) {
876 for (
int yi = 0; yi < image.
get_y_size(); yi++) {
877 unsigned char *texture_row = glyph->get_row(yi);
878 nassertv(texture_row !=
nullptr);
879 for (
int xi = 0; xi < image.
get_x_size(); xi++) {
880 unsigned char *tr = texture_row + xi * 2;
881 PN_stdfloat t = (PN_stdfloat)image.
get_gray(xi, yi);
882 tr[0] = (
unsigned char)(tr[0] + t * (fgv[0] - tr[0]));
883 tr[1] = (
unsigned char)(tr[1] + t * (fgv[3] - tr[1]));
887 }
else if (num_components == 3) {
890 for (
int yi = 0; yi < image.
get_y_size(); yi++) {
891 unsigned char *texture_row = glyph->get_row(yi);
892 nassertv(texture_row !=
nullptr);
893 for (
int xi = 0; xi < image.
get_x_size(); xi++) {
894 unsigned char *tr = texture_row + xi * 3;
895 PN_stdfloat t = (PN_stdfloat)image.
get_gray(xi, yi);
896 tr[0] = (
unsigned char)(tr[0] + t * (fgv[2] - tr[0]));
897 tr[1] = (
unsigned char)(tr[1] + t * (fgv[1] - tr[1]));
898 tr[2] = (
unsigned char)(tr[2] + t * (fgv[0] - tr[2]));
905 for (
int yi = 0; yi < image.
get_y_size(); yi++) {
906 unsigned char *texture_row = glyph->get_row(yi);
907 nassertv(texture_row !=
nullptr);
908 for (
int xi = 0; xi < image.
get_x_size(); xi++) {
909 unsigned char *tr = texture_row + xi * 4;
910 PN_stdfloat t = (PN_stdfloat)image.
get_gray(xi, yi);
911 tr[0] = (
unsigned char)(tr[0] + t * (fgv[2] - tr[0]));
912 tr[1] = (
unsigned char)(tr[1] + t * (fgv[1] - tr[1]));
913 tr[2] = (
unsigned char)(tr[2] + t * (fgv[0] - tr[2]));
914 tr[3] = (
unsigned char)(tr[3] + t * (fgv[3] - tr[3]));
926DynamicTextGlyph *DynamicTextFont::
927slot_glyph(
int character,
int x_size,
int y_size, PN_stdfloat advance) {
929 x_size += _texture_margin * 2;
930 y_size += _texture_margin * 2;
932 if (!_pages.empty()) {
937 _preferred_page = _preferred_page % _pages.size();
938 int pi = _preferred_page;
941 DynamicTextPage *page = _pages[pi];
942 DynamicTextGlyph *glyph = page->slot_glyph(character, x_size, y_size, _texture_margin, advance);
943 if (glyph !=
nullptr) {
946 _preferred_page = pi;
950 if (page->is_empty()) {
955 pi = (pi + 1) % _pages.size();
956 }
while (pi != _preferred_page);
960 if (garbage_collect() != 0) {
962 return slot_glyph(character, x_size, y_size, advance);
968 _preferred_page = _pages.size();
969 PT(DynamicTextPage) page =
new DynamicTextPage(
this, _preferred_page);
970 _pages.push_back(page);
972 DynamicTextGlyph *glyph = page->slot_glyph(character, x_size, y_size, _texture_margin, advance);
973 if (glyph !=
nullptr) {
981 <<
"Glyph of size " << x_size <<
" by " << y_size
982 <<
" pixels won't fit on an empty page.\n";
990void DynamicTextFont::
991render_wireframe_contours(
TextGlyph *glyph) {
999 Contours::const_iterator ci;
1000 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
1001 const Contour &contour = (*ci);
1002 Points::const_iterator pi;
1004 for (pi = contour._points.begin(); pi != contour._points.end(); ++pi) {
1005 const LPoint2 &p = (*pi)._p;
1006 vertex.add_data3(p[0], 0.0f, p[1]);
1009 lines->add_next_vertices(contour._points.size());
1010 lines->close_primitive();
1013 glyph->
set_geom(vdata, lines, RenderState::make_empty());
1021void DynamicTextFont::
1022render_polygon_contours(
TextGlyph *glyph,
bool face,
bool extrude) {
1032 Contours::iterator ci;
1037 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
1038 Contour &contour = (*ci);
1042 for (
size_t i = 0; i < contour._points.size() - 1; ++i) {
1043 const LPoint2 &p = contour._points[i]._p;
1044 vertex.add_data3(p[0], 0.0f, p[1]);
1045 normal.add_data3(0.0f, -1.0f, 0.0f);
1054 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
1055 const Contour &contour = (*ci);
1057 if (contour._is_solid && !contour._points.empty()) {
1059 for (
size_t i = 0; i < contour._points.size() - 1; ++i) {
1064 Contours::iterator cj;
1065 for (cj = _contours.begin(); cj != _contours.end(); ++cj) {
1066 Contour &hole = (*cj);
1067 if (!hole._is_solid && !hole._points.empty()) {
1069 for (
size_t j = 0; j < hole._points.size() - 1; ++j) {
1077 for (
int ti = 0; ti < num_triangles; ++ti) {
1081 tris->close_primitive();
1091 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
1092 const Contour &contour = (*ci);
1094 for (
size_t i = 0; i < contour._points.size(); ++i) {
1095 const ContourPoint &cp = contour._points[i];
1096 const LPoint2 &p = cp._p;
1097 const LVector2 &t_in = cp._in;
1098 const LVector2 &t_out = cp._out;
1100 LVector3 n_in(t_in[1], 0.0f, -t_in[0]);
1101 vertex.add_data3(p[0], 1.0f, p[1]);
1102 vertex.add_data3(p[0], 0.0f, p[1]);
1103 normal.add_data3(n_in);
1104 normal.add_data3(n_in);
1107 int vi = vertex.get_write_row();
1108 tris->add_vertex(vi - 4);
1109 tris->add_vertex(vi - 2);
1110 tris->add_vertex(vi - 1);
1111 tris->close_primitive();
1112 tris->add_vertex(vi - 1);
1113 tris->add_vertex(vi - 3);
1114 tris->add_vertex(vi - 4);
1115 tris->close_primitive();
1118 if (i != contour._points.size() - 1 && !t_in.almost_equal(t_out)) {
1121 LVector3 n_out(t_out[1], 0.0f, -t_out[0]);
1122 vertex.add_data3(p[0], 1.0f, p[1]);
1123 vertex.add_data3(p[0], 0.0f, p[1]);
1124 normal.add_data3(n_out);
1125 normal.add_data3(n_out);
1132 int back_start = vertex.get_write_row();
1134 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
1135 Contour &contour = (*ci);
1136 for (
size_t i = 0; i < contour._points.size() - 1; ++i) {
1137 const LPoint2 &p = contour._points[i]._p;
1138 vertex.add_data3(p[0], 1.0f, p[1]);
1139 normal.add_data3(0.0f, 1.0f, 0.0f);
1144 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
1145 const Contour &contour = (*ci);
1147 if (contour._is_solid && !contour._points.empty()) {
1149 for (
size_t i = 0; i < contour._points.size() - 1; ++i) {
1154 Contours::iterator cj;
1155 for (cj = _contours.begin(); cj != _contours.end(); ++cj) {
1156 Contour &hole = (*cj);
1157 if (!hole._is_solid && !hole._points.empty()) {
1159 for (
size_t j = 0; j < hole._points.size() - 1; ++j) {
1167 for (
int ti = 0; ti < num_triangles; ++ti) {
1171 tris->close_primitive();
1178 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.