34 const PN_stdfloat FreetypeFont::_points_per_unit = 10.0f;
37 const PN_stdfloat FreetypeFont::_points_per_inch = 72.0f;
46 _point_size = text_point_size;
47 _requested_pixels_per_unit = text_pixels_per_unit;
48 _tex_pixels_per_unit = text_pixels_per_unit;
49 _requested_scale_factor = text_scale_factor;
50 _scale_factor = text_scale_factor;
51 _native_antialias = text_native_antialias;
52 _winding_order = WO_default;
55 _space_advance = 0.25f;
67 FreetypeFont(
const FreetypeFont ©) :
69 _point_size(copy._point_size),
70 _requested_pixels_per_unit(copy._requested_pixels_per_unit),
71 _tex_pixels_per_unit(copy._tex_pixels_per_unit),
72 _requested_scale_factor(copy._requested_scale_factor),
73 _scale_factor(copy._scale_factor),
74 _native_antialias(copy._native_antialias),
75 _font_pixels_per_unit(copy._font_pixels_per_unit),
76 _winding_order(copy._winding_order),
77 _line_height(copy._line_height),
78 _space_advance(copy._space_advance),
80 _char_size(copy._char_size),
82 _pixel_width(copy._pixel_width),
83 _pixel_height(copy._pixel_height)
93 load_font(
const Filename &font_filename,
int face_index) {
95 _face =
new FreetypeFace;
98 <<
"Unable to read font " << font_filename
99 <<
": FreeType library not initialized properly.\n";
109 exists = vfs->read_file(path, _face->_font_data,
true);
112 error = FT_New_Memory_Face(_face->_ft_library,
113 (
const FT_Byte *)_face->_font_data.data(),
114 _face->_font_data.length(),
117 _face->set_face(face);
124 <<
"Unable to find font file " << font_filename <<
"\n";
126 if (error == FT_Err_Unknown_File_Format) {
128 <<
"Unable to read font " << font_filename <<
": unknown file format.\n";
131 <<
"Unable to read font " << font_filename <<
": invalid.\n";
134 okflag = reset_scale();
150 load_font(
const char *font_data,
int data_length,
int face_index) {
152 _face =
new FreetypeFace;
154 if (!_face->_ft_ok) {
156 <<
"Unable to read font: FreeType library not initialized properly.\n";
163 error = FT_New_Memory_Face(_face->_ft_library,
164 (
const FT_Byte *)font_data, data_length,
166 _face->set_face(face);
169 if (error == FT_Err_Unknown_File_Format) {
171 <<
"Unable to read font: unknown file format.\n";
174 <<
"Unable to read font: invalid.\n";
177 okflag = reset_scale();
200 FreetypeFont::WindingOrder FreetypeFont::
201 string_winding_order(
const string &
string) {
202 if (cmp_nocase_uh(
string,
"default") == 0) {
204 }
else if (cmp_nocase_uh(
string,
"left") == 0) {
206 }
else if (cmp_nocase_uh(
string,
"right") == 0) {
218 load_glyph(FT_Face face,
int glyph_index,
bool prerender) {
219 int flags = FT_LOAD_RENDER;
220 if (!_native_antialias) {
221 flags |= FT_LOAD_MONOCHROME;
230 int error = FT_Load_Glyph(face, glyph_index, flags);
233 <<
"Unable to render glyph " << glyph_index <<
"\n";
244 copy_bitmap_to_pnmimage(
const FT_Bitmap &bitmap,
PNMImage &image) {
245 if (bitmap.pixel_mode == ft_pixel_mode_grays &&
246 bitmap.num_grays == (
int)image.
get_maxval() + 1) {
249 unsigned char *buffer_row = bitmap.buffer;
250 for (
int yi = 0; yi < (int)bitmap.rows; yi++) {
251 for (
int xi = 0; xi < (int)bitmap.width; xi++) {
254 buffer_row += bitmap.pitch;
257 }
else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
260 unsigned char *buffer_row = bitmap.buffer;
261 for (
int yi = 0; yi < (int)bitmap.rows; yi++) {
264 unsigned char *b = buffer_row;
265 for (
int xi = 0; xi < (int)bitmap.width; xi++) {
278 buffer_row += bitmap.pitch;
282 }
else if (bitmap.pixel_mode == ft_pixel_mode_grays) {
285 unsigned char *buffer_row = bitmap.buffer;
286 for (
int yi = 0; yi < (int)bitmap.rows; yi++) {
287 for (
int xi = 0; xi < (int)bitmap.width; xi++) {
288 image.
set_gray(xi, yi, (PN_stdfloat)buffer_row[xi] / (bitmap.num_grays - 1));
290 buffer_row += bitmap.pitch;
295 <<
"Unexpected pixel mode in bitmap: " << (int)bitmap.pixel_mode <<
"\n";
306 if (_face ==
nullptr) {
312 FT_Face face = _face->acquire_face(0, 0, 0, 0);
317 _tex_pixels_per_unit = _requested_pixels_per_unit;
318 _scale_factor = _requested_scale_factor;
319 _font_pixels_per_unit = _tex_pixels_per_unit * _scale_factor;
323 PN_stdfloat units_per_inch = (_points_per_inch / _points_per_unit);
324 _dpi = (int)(_font_pixels_per_unit * units_per_inch);
325 _char_size = (int)(_point_size * 64);
327 int error = FT_Set_Char_Size(face, _char_size, _char_size, _dpi, _dpi);
332 int desired_height = (int)(_font_pixels_per_unit * _point_size / _points_per_unit + 0.5f);
334 int largest_size = -1;
335 if (face->num_fixed_sizes > 0) {
338 for (
int i = 0; i < face->num_fixed_sizes; i++) {
339 int diff = face->available_sizes[i].height - desired_height;
340 if (diff > 0 && (best_size == -1 || diff < best_diff)) {
344 if (face->available_sizes[i].height > face->available_sizes[largest_size].height) {
350 best_size = largest_size;
353 if (best_size >= 0) {
354 _pixel_height = face->available_sizes[best_size].height;
355 _pixel_width = face->available_sizes[best_size].width;
356 error = FT_Set_Pixel_Sizes(face, _pixel_width, _pixel_height);
358 _font_pixels_per_unit = _pixel_height * _points_per_unit / _point_size;
359 _scale_factor = _font_pixels_per_unit / _tex_pixels_per_unit;
361 if (_scale_factor < 1.0) {
364 _tex_pixels_per_unit = _font_pixels_per_unit;
371 pnmtext_cat.warning()
372 <<
"Unable to set " << get_name()
373 <<
" to " << _point_size <<
"pt at " << _dpi <<
" dpi.\n";
375 _face->release_face(face);
379 _line_height = face->size->metrics.height / (_font_pixels_per_unit * 64.0f);
382 error = FT_Load_Char(face,
' ', FT_LOAD_DEFAULT);
385 _space_advance = 0.25f * _line_height;
388 _space_advance = face->glyph->advance.x / (_font_pixels_per_unit * 64.0f);
391 _face->release_face(face);
399 render_distance_field(
PNMImage &image,
int outline,
int min_x,
int min_y) {
400 Contours::const_iterator ci;
402 PN_stdfloat offset_x = -outline / _tex_pixels_per_unit;
403 PN_stdfloat offset_y = (image.
get_y_size() - 1 - outline) / _tex_pixels_per_unit;;
405 offset_x += min_x / (64.0f * _font_pixels_per_unit);
406 offset_y += min_y / (64.0f * _font_pixels_per_unit);
408 PN_stdfloat scale = _tex_pixels_per_unit / (outline * 2);
410 for (
int y = 0; y < image.
get_y_size(); ++y) {
411 LPoint2 p(0, offset_y - (y / _tex_pixels_per_unit));
413 for (
int x = 0; x < image.
get_x_size(); ++x) {
414 p[0] = offset_x + (x / _tex_pixels_per_unit);
416 PN_stdfloat min_dist_sq = 100000000;
417 int winding_number = 0;
419 for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
423 const Contour &contour = (*ci);
425 for (
size_t i = 1; i < contour._points.size(); ++i) {
426 const LPoint2 &begin = contour._points[i - 1]._p;
427 const LPoint2 &end = contour._points[i]._p;
428 PN_stdfloat radius = contour._points[i]._radius;
430 LVector2 v = end - begin;
431 PN_stdfloat length_sq = v.length_squared();
434 if (length_sq == 0) {
435 dist_sq = (p - begin).length_squared();
437 }
else if (radius != 0) {
439 LVector2 v1 = begin - contour._points[i]._center;
440 LVector2 v2 = end - contour._points[i]._center;
441 LVector2 vp = p - contour._points[i]._center;
442 PN_stdfloat dist_to_center = vp.length();
443 vp /= dist_to_center;
446 PN_stdfloat range = v1.dot(v2);
447 if (vp.dot(v1) > range && vp.dot(v2) > range) {
448 dist_sq = dist_to_center - radius;
449 bool inside = dist_sq < 0;
455 if (begin[1] <= p[1]) {
457 if (inside != (v[0] * v1[1] > v[1] * v1[0])) {
462 if (end[1] <= p[1]) {
463 if (inside == (v[0] * v1[1] > v[1] * v1[0])) {
470 dist_sq = std::min((p - begin).length_squared(), (p - end).length_squared());
471 if (begin[1] <= p[1]) {
473 if ((v[0] * (p[1] - begin[1]) > v[1] * (p[0] - begin[0]))) {
478 if (end[1] <= p[1]) {
479 if ((v[0] * (p[1] - begin[1]) < v[1] * (p[0] - begin[0]))) {
488 if (begin[1] <= p[1]) {
490 if ((v[0] * (p[1] - begin[1]) > v[1] * (p[0] - begin[0]))) {
495 if (end[1] <= p[1]) {
496 if ((v[0] * (p[1] - begin[1]) < v[1] * (p[0] - begin[0]))) {
502 PN_stdfloat t = v.dot(p - begin) / length_sq;
504 dist_sq = (p - begin).length_squared();
505 }
else if (t >= 1.0) {
506 dist_sq = (p - end).length_squared();
508 dist_sq = (p - (begin + v * t)).length_squared();
512 min_dist_sq = std::min(min_dist_sq, dist_sq);
516 int sign = (winding_number != 0) ? 1 : -1;
518 PN_stdfloat signed_dist = csqrt(min_dist_sq) * sign;
519 image.
set_gray(x, y, signed_dist * scale + (PN_stdfloat)0.5);
528 decompose_outline(FT_Outline &outline) {
529 FT_Outline_Funcs funcs;
530 memset(&funcs, 0,
sizeof(funcs));
531 funcs.move_to = (FT_Outline_MoveTo_Func)outline_move_to;
532 funcs.line_to = (FT_Outline_LineTo_Func)outline_line_to;
533 funcs.conic_to = (FT_Outline_ConicTo_Func)outline_conic_to;
534 funcs.cubic_to = (FT_Outline_CubicTo_Func)outline_cubic_to;
536 WindingOrder wo = _winding_order;
537 if (wo == WO_default) {
540 #ifdef FT_ORIENTATION_FILL_RIGHT
541 if (FT_Outline_Get_Orientation(&outline) == FT_ORIENTATION_FILL_RIGHT) {
554 FT_Outline_Reverse(&outline);
558 FT_Outline_Decompose(&outline, &funcs, (
void *)
this);
566 outline_move_to(
const FT_Vector *to,
void *user) {
567 FreetypeFont *
self = (FreetypeFont *)user;
570 PN_stdfloat scale = 1.0f / (64.0f *
self->_font_pixels_per_unit);
571 LPoint2 p = LPoint2(to->x, to->y) * scale;
573 if (self->_contours.empty() ||
574 !self->_contours.back()._points.empty()) {
575 self->_contours.push_back(Contour());
586 outline_line_to(
const FT_Vector *to,
void *user) {
587 FreetypeFont *
self = (FreetypeFont *)user;
588 nassertr(!self->_contours.empty(), 1);
591 PN_stdfloat scale = 1.0f / (64.0f *
self->_font_pixels_per_unit);
592 LPoint2 p = LPoint2(to->x, to->y) * scale;
595 LVector2 t = (p -
self->_q);
598 if (self->_contours.back()._points.empty()) {
599 self->_contours.back()._points.push_back(ContourPoint(self->_q, LVector2::zero(), t));
601 self->_contours.back()._points.back().connect_to(t);
604 self->_contours.back()._points.push_back(ContourPoint(p, t, LVector2::zero()));
614 outline_conic_to(
const FT_Vector *control,
615 const FT_Vector *to,
void *user) {
616 FreetypeFont *
self = (FreetypeFont *)user;
617 nassertr(!self->_contours.empty(), 1);
620 PN_stdfloat scale = 1.0f / (64.0f *
self->_font_pixels_per_unit);
622 LPoint2 c = LPoint2(control->x, control->y) * scale;
623 LPoint2 p = LPoint2(to->x, to->y) * scale;
630 nce.
set_vertex(0, LVecBase3(self->_q[0], self->_q[1], 0.0f));
631 nce.
set_vertex(1, LVecBase3(c[0], c[1], 0.0f));
632 nce.
set_vertex(2, LVecBase3(p[0], p[1], 0.0f));
637 return self->outline_nurbs(ncr);
645 outline_cubic_to(
const FT_Vector *control1,
const FT_Vector *control2,
646 const FT_Vector *to,
void *user) {
647 FreetypeFont *
self = (FreetypeFont *)user;
648 nassertr(!self->_contours.empty(), 1);
651 PN_stdfloat scale = 1.0f / (64.0f *
self->_font_pixels_per_unit);
653 LPoint2 c1 = LPoint2(control1->x, control1->y) * scale;
654 LPoint2 c2 = LPoint2(control2->x, control2->y) * scale;
655 LPoint2 p = LPoint2(to->x, to->y) * scale;
662 nce.
set_vertex(0, LVecBase3(self->_q[0], self->_q[1], 0.0f));
663 nce.
set_vertex(1, LVecBase3(c1[0], c1[1], 0.0f));
664 nce.
set_vertex(2, LVecBase3(c2[0], c2[1], 0.0f));
665 nce.
set_vertex(3, LVecBase3(p[0], p[1], 0.0f));
670 return self->outline_nurbs(ncr);
684 bool needs_connect =
false;
686 if (_contours.back()._points.empty()) {
691 needs_connect =
true;
694 for (
int i = start; i < num_samples; ++i) {
698 PN_stdfloat st0 = st, st1 = st;
702 if (i < num_samples - 1) {
710 LVector3 t = p1 - p0;
714 _contours.back()._points.back().connect_to(LVector2(t[0], t[1]));
715 needs_connect =
false;
718 _contours.back()._points.push_back(ContourPoint(p[0], p[1], t[0], t[1]));
728 PN_stdfloat temp = v1.length_squared();
729 PN_stdfloat bc = (v2[0]*v2[0] + v2[1]*v2[1] - temp) * (PN_stdfloat)0.5f;
730 PN_stdfloat cd = (temp - p[0]*p[0] - p[1]*p[1]) * (PN_stdfloat)0.5f;
731 PN_stdfloat det = (v2[0]-v1[0])*(v1[1]-p[1])-(v1[0]-p[0])*(v2[1]-v1[1]);
732 if (!IS_NEARLY_ZERO(det)) {
734 center[0] = (bc*(v1[1]-p[1])-cd*(v2[1]-v1[1]));
735 center[1] = ((v2[0]-v1[0])*cd-(v1[0]-p[0])*bc);
737 _contours.back()._points.back()._center = center;
738 _contours.back()._points.back()._radius = (center - v1).length();
750 operator << (ostream &out, FreetypeFont::WindingOrder wo) {
752 case FreetypeFont::WO_default:
753 return out <<
"default";
754 case FreetypeFont::WO_left:
755 return out <<
"left";
756 case FreetypeFont::WO_right:
757 return out <<
"right";
759 case FreetypeFont::WO_invalid:
760 return out <<
"invalid";
763 return out <<
"(**invalid FreetypeFont::WindingOrder(" << (int)wo <<
")**)";
770 operator >> (istream &in, FreetypeFont::WindingOrder &wo) {
774 wo = FreetypeFont::string_winding_order(word);
The name of a file, such as a texture file or an Egg file.
A base class for all things which can have a name.
This class is an abstraction for evaluating NURBS curves.
void reset(int num_vertices)
Resets all the vertices and knots to their default values, and sets the curve up with the indicated n...
void set_vertex(int i, const LVecBase4 &vertex)
Sets the nth control vertex of the curve, as a vertex in 4-d homogeneous space.
void set_order(int order)
Sets the order of the curve.
The result of a NurbsCurveEvaluator.
get_sample_point
Returns the point on the curve of the nth sample point generated by the previous call to adaptive_sam...
get_sample_t
Returns the t value of the nth sample point generated by the previous call to adaptive_sample().
bool eval_point(PN_stdfloat t, LVecBase3 &point)
Computes the point on the curve corresponding to the indicated value in parametric time.
void adaptive_sample(PN_stdfloat tolerance)
Determines the set of subdivisions necessary to approximate the curve with a set of linear segments,...
get_num_samples
Returns the number of sample points generated by the previous call to adaptive_sample().
The name of this class derives from the fact that we originally implemented it as a layer on top of t...
void set_gray(int x, int y, float gray)
Sets the gray component color at the indicated pixel.
void set_gray_val(int x, int y, xelval gray)
Sets the gray component color at the indicated pixel.
void local_object()
This function should be called, once, immediately after creating a new instance of some ReferenceCoun...
A hierarchy of directories and files that appears to be one continuous file system,...
bool resolve_filename(Filename &filename, const DSearchPath &searchpath, const std::string &default_extension=std::string()) const
Searches the given search path for the filename.
static VirtualFileSystem * get_global_ptr()
Returns the default global VirtualFileSystem.
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.