|
@@ -40,8 +40,6 @@
|
|
|
#include "renderState.h"
|
|
#include "renderState.h"
|
|
|
#include "string_utils.h"
|
|
#include "string_utils.h"
|
|
|
#include "triangulator.h"
|
|
#include "triangulator.h"
|
|
|
-#include "nurbsCurveEvaluator.h"
|
|
|
|
|
-#include "nurbsCurveResult.h"
|
|
|
|
|
//#include "renderModeAttrib.h"
|
|
//#include "renderModeAttrib.h"
|
|
|
//#include "antialiasAttrib.h"
|
|
//#include "antialiasAttrib.h"
|
|
|
#include "colorAttrib.h"
|
|
#include "colorAttrib.h"
|
|
@@ -117,7 +115,6 @@ DynamicTextFont(const DynamicTextFont ©) :
|
|
|
_magfilter(copy._magfilter),
|
|
_magfilter(copy._magfilter),
|
|
|
_anisotropic_degree(copy._anisotropic_degree),
|
|
_anisotropic_degree(copy._anisotropic_degree),
|
|
|
_render_mode(copy._render_mode),
|
|
_render_mode(copy._render_mode),
|
|
|
- _winding_order(copy._winding_order),
|
|
|
|
|
_fg(copy._fg),
|
|
_fg(copy._fg),
|
|
|
_bg(copy._bg),
|
|
_bg(copy._bg),
|
|
|
_outline_color(copy._outline_color),
|
|
_outline_color(copy._outline_color),
|
|
@@ -195,7 +192,7 @@ garbage_collect() {
|
|
|
Cache new_cache;
|
|
Cache new_cache;
|
|
|
Cache::iterator ci;
|
|
Cache::iterator ci;
|
|
|
for (ci = _cache.begin(); ci != _cache.end(); ++ci) {
|
|
for (ci = _cache.begin(); ci != _cache.end(); ++ci) {
|
|
|
- TextGlyph *glyph = (*ci).second;
|
|
|
|
|
|
|
+ const TextGlyph *glyph = (*ci).second;
|
|
|
if (glyph == (TextGlyph *)NULL || glyph->get_ref_count() > 1) {
|
|
if (glyph == (TextGlyph *)NULL || glyph->get_ref_count() > 1) {
|
|
|
// Keep this one.
|
|
// Keep this one.
|
|
|
new_cache.insert(new_cache.end(), (*ci));
|
|
new_cache.insert(new_cache.end(), (*ci));
|
|
@@ -253,7 +250,7 @@ write(ostream &out, int indent_level) const {
|
|
|
Cache::const_iterator ci;
|
|
Cache::const_iterator ci;
|
|
|
for (ci = _cache.begin(); ci != _cache.end(); ++ci) {
|
|
for (ci = _cache.begin(); ci != _cache.end(); ++ci) {
|
|
|
int glyph_index = (*ci).first;
|
|
int glyph_index = (*ci).first;
|
|
|
- TextGlyph *glyph = (*ci).second;
|
|
|
|
|
|
|
+ const TextGlyph *glyph = (*ci).second;
|
|
|
indent(out, indent_level + 2)
|
|
indent(out, indent_level + 2)
|
|
|
<< glyph_index;
|
|
<< glyph_index;
|
|
|
|
|
|
|
@@ -303,16 +300,15 @@ get_glyph(int character, CPT(TextGlyph) &glyph) {
|
|
|
if (ci != _cache.end()) {
|
|
if (ci != _cache.end()) {
|
|
|
glyph = (*ci).second;
|
|
glyph = (*ci).second;
|
|
|
} else {
|
|
} else {
|
|
|
- TextGlyph *dynamic_glyph = make_glyph(character, face, glyph_index);
|
|
|
|
|
- _cache.insert(Cache::value_type(glyph_index, dynamic_glyph));
|
|
|
|
|
- glyph = dynamic_glyph;
|
|
|
|
|
|
|
+ glyph = make_glyph(character, face, glyph_index);
|
|
|
|
|
+ _cache.insert(Cache::value_type(glyph_index, glyph.p()));
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (glyph == (TextGlyph *)NULL) {
|
|
|
|
|
|
|
+ if (glyph.is_null()) {
|
|
|
glyph = get_invalid_glyph();
|
|
glyph = get_invalid_glyph();
|
|
|
glyph_index = 0;
|
|
glyph_index = 0;
|
|
|
}
|
|
}
|
|
|
-
|
|
|
|
|
|
|
+
|
|
|
release_face(face);
|
|
release_face(face);
|
|
|
return (glyph_index != 0);
|
|
return (glyph_index != 0);
|
|
|
}
|
|
}
|
|
@@ -442,7 +438,7 @@ determine_tex_format() {
|
|
|
// newly-created TextGlyph object, or NULL if the
|
|
// newly-created TextGlyph object, or NULL if the
|
|
|
// glyph cannot be created for some reason.
|
|
// glyph cannot be created for some reason.
|
|
|
////////////////////////////////////////////////////////////////////
|
|
////////////////////////////////////////////////////////////////////
|
|
|
-TextGlyph *DynamicTextFont::
|
|
|
|
|
|
|
+CPT(TextGlyph) DynamicTextFont::
|
|
|
make_glyph(int character, FT_Face face, int glyph_index) {
|
|
make_glyph(int character, FT_Face face, int glyph_index) {
|
|
|
if (!load_glyph(face, glyph_index, false)) {
|
|
if (!load_glyph(face, glyph_index, false)) {
|
|
|
return (TextGlyph *)NULL;
|
|
return (TextGlyph *)NULL;
|
|
@@ -490,36 +486,7 @@ make_glyph(int character, FT_Face face, int glyph_index) {
|
|
|
|
|
|
|
|
// Ask FreeType to extract the contours out of the outline
|
|
// Ask FreeType to extract the contours out of the outline
|
|
|
// description.
|
|
// description.
|
|
|
- FT_Outline_Funcs funcs;
|
|
|
|
|
- memset(&funcs, 0, sizeof(funcs));
|
|
|
|
|
- funcs.move_to = (FT_Outline_MoveTo_Func)outline_move_to;
|
|
|
|
|
- funcs.line_to = (FT_Outline_LineTo_Func)outline_line_to;
|
|
|
|
|
- funcs.conic_to = (FT_Outline_ConicTo_Func)outline_conic_to;
|
|
|
|
|
- funcs.cubic_to = (FT_Outline_CubicTo_Func)outline_cubic_to;
|
|
|
|
|
-
|
|
|
|
|
- WindingOrder wo = _winding_order;
|
|
|
|
|
- if (wo == WO_default) {
|
|
|
|
|
- // If we weren't told an explicit winding order, ask FreeType to
|
|
|
|
|
- // figure it out. Sometimes it appears to guess wrong.
|
|
|
|
|
-#ifdef FT_ORIENTATION_FILL_RIGHT
|
|
|
|
|
- if (FT_Outline_Get_Orientation(&slot->outline) == FT_ORIENTATION_FILL_RIGHT) {
|
|
|
|
|
- wo = WO_right;
|
|
|
|
|
- } else {
|
|
|
|
|
- wo = WO_left;
|
|
|
|
|
- }
|
|
|
|
|
-#else
|
|
|
|
|
- // Hmm. Assign a right-winding (TTF) orientation if FreeType
|
|
|
|
|
- // can't tell us.
|
|
|
|
|
- wo = WO_right;
|
|
|
|
|
-#endif // FT_ORIENTATION_FILL_RIGHT
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- if (wo != WO_left) {
|
|
|
|
|
- FT_Outline_Reverse(&slot->outline);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _contours.clear();
|
|
|
|
|
- FT_Outline_Decompose(&slot->outline, &funcs, (void *)this);
|
|
|
|
|
|
|
+ decompose_outline(slot->outline);
|
|
|
|
|
|
|
|
PT(TextGlyph) glyph =
|
|
PT(TextGlyph) glyph =
|
|
|
new TextGlyph(character, advance);
|
|
new TextGlyph(character, advance);
|
|
@@ -541,17 +508,46 @@ make_glyph(int character, FT_Face face, int glyph_index) {
|
|
|
return glyph;
|
|
return glyph;
|
|
|
|
|
|
|
|
case RM_texture:
|
|
case RM_texture:
|
|
|
|
|
+ case RM_distance_field:
|
|
|
default:
|
|
default:
|
|
|
break;
|
|
break;
|
|
|
}
|
|
}
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- // Render the glyph if necessary.
|
|
|
|
|
- if (slot->format != ft_glyph_format_bitmap) {
|
|
|
|
|
- FT_Render_Glyph(slot, ft_render_mode_normal);
|
|
|
|
|
|
|
+ PN_stdfloat tex_x_size, tex_y_size, tex_x_orig, tex_y_orig;
|
|
|
|
|
+ FT_BBox bounds;
|
|
|
|
|
+ TransparencyAttrib::Mode alpha_mode;
|
|
|
|
|
+
|
|
|
|
|
+ if (_render_mode == RM_texture) {
|
|
|
|
|
+ // Render the glyph if necessary.
|
|
|
|
|
+ if (slot->format != ft_glyph_format_bitmap) {
|
|
|
|
|
+ FT_Render_Glyph(slot, ft_render_mode_normal);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ tex_x_size = bitmap.width;
|
|
|
|
|
+ tex_y_size = bitmap.rows;
|
|
|
|
|
+ tex_x_orig = slot->bitmap_left;
|
|
|
|
|
+ tex_y_orig = slot->bitmap_top;
|
|
|
|
|
+ alpha_mode = TransparencyAttrib::M_alpha;
|
|
|
|
|
+
|
|
|
|
|
+ } else {
|
|
|
|
|
+ // Calculate suitable texture dimensions for the signed distance field.
|
|
|
|
|
+ // This is the same calculation that Freetype uses in its bitmap renderer.
|
|
|
|
|
+ FT_Outline_Get_CBox(&slot->outline, &bounds);
|
|
|
|
|
+
|
|
|
|
|
+ bounds.xMin = bounds.xMin & ~63;
|
|
|
|
|
+ bounds.yMin = bounds.yMin & ~63;
|
|
|
|
|
+ bounds.xMax = (bounds.xMax + 63) & ~63;
|
|
|
|
|
+ bounds.yMax = (bounds.yMax + 63) & ~63;
|
|
|
|
|
+
|
|
|
|
|
+ tex_x_size = (bounds.xMax - bounds.xMin) >> 6;
|
|
|
|
|
+ tex_y_size = (bounds.yMax - bounds.yMin) >> 6;
|
|
|
|
|
+ tex_x_orig = (bounds.xMin >> 6);
|
|
|
|
|
+ tex_y_orig = (bounds.yMax >> 6);
|
|
|
|
|
+ alpha_mode = TransparencyAttrib::M_binary;
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
- if (bitmap.width == 0 || bitmap.rows == 0) {
|
|
|
|
|
|
|
+ if (tex_x_size == 0 || tex_y_size == 0) {
|
|
|
// If we got an empty bitmap, it's a special case.
|
|
// If we got an empty bitmap, it's a special case.
|
|
|
|
|
|
|
|
PT(TextGlyph) glyph =
|
|
PT(TextGlyph) glyph =
|
|
@@ -562,13 +558,32 @@ make_glyph(int character, FT_Face face, int glyph_index) {
|
|
|
} else {
|
|
} else {
|
|
|
DynamicTextGlyph *glyph;
|
|
DynamicTextGlyph *glyph;
|
|
|
|
|
|
|
|
- PN_stdfloat tex_x_size = bitmap.width;
|
|
|
|
|
- PN_stdfloat tex_y_size = bitmap.rows;
|
|
|
|
|
-
|
|
|
|
|
int outline = 0;
|
|
int outline = 0;
|
|
|
|
|
|
|
|
- if (_tex_pixels_per_unit == _font_pixels_per_unit &&
|
|
|
|
|
- !_needs_image_processing) {
|
|
|
|
|
|
|
+ if (_render_mode == RM_distance_field) {
|
|
|
|
|
+ tex_x_size /= _scale_factor;
|
|
|
|
|
+ tex_y_size /= _scale_factor;
|
|
|
|
|
+ int int_x_size = (int)ceil(tex_x_size);
|
|
|
|
|
+ int int_y_size = (int)ceil(tex_y_size);
|
|
|
|
|
+
|
|
|
|
|
+ outline = 4;
|
|
|
|
|
+ int_x_size += outline * 2;
|
|
|
|
|
+ int_y_size += outline * 2;
|
|
|
|
|
+ tex_x_size += outline * 2;
|
|
|
|
|
+ tex_y_size += outline * 2;
|
|
|
|
|
+
|
|
|
|
|
+ PNMImage image(int_x_size, int_y_size, PNMImage::CT_grayscale);
|
|
|
|
|
+ render_distance_field(image, outline, bounds.xMin, bounds.yMin);
|
|
|
|
|
+
|
|
|
|
|
+ glyph = slot_glyph(character, int_x_size, int_y_size, advance);
|
|
|
|
|
+ if (!_needs_image_processing) {
|
|
|
|
|
+ copy_pnmimage_to_texture(image, glyph);
|
|
|
|
|
+ } else {
|
|
|
|
|
+ blend_pnmimage_to_texture(image, glyph, _fg);
|
|
|
|
|
+ }
|
|
|
|
|
+
|
|
|
|
|
+ } else if (_tex_pixels_per_unit == _font_pixels_per_unit &&
|
|
|
|
|
+ !_needs_image_processing) {
|
|
|
// If the bitmap produced from the font doesn't require scaling
|
|
// If the bitmap produced from the font doesn't require scaling
|
|
|
// or any other processing before it goes to the texture, we can
|
|
// or any other processing before it goes to the texture, we can
|
|
|
// just copy it directly into the texture.
|
|
// just copy it directly into the texture.
|
|
@@ -615,8 +630,8 @@ make_glyph(int character, FT_Face face, int glyph_index) {
|
|
|
|
|
|
|
|
DynamicTextPage *page = glyph->get_page();
|
|
DynamicTextPage *page = glyph->get_page();
|
|
|
if (page != NULL) {
|
|
if (page != NULL) {
|
|
|
- int bitmap_top = (int)floor(slot->bitmap_top + outline * _scale_factor + 0.5f);
|
|
|
|
|
- int bitmap_left = (int)floor(slot->bitmap_left - outline * _scale_factor + 0.5f);
|
|
|
|
|
|
|
+ int bitmap_top = (int)floor(tex_y_orig + outline * _scale_factor + 0.5f);
|
|
|
|
|
+ int bitmap_left = (int)floor(tex_x_orig - outline * _scale_factor + 0.5f);
|
|
|
|
|
|
|
|
tex_x_size += glyph->_margin * 2;
|
|
tex_x_size += glyph->_margin * 2;
|
|
|
tex_y_size += glyph->_margin * 2;
|
|
tex_y_size += glyph->_margin * 2;
|
|
@@ -644,7 +659,7 @@ make_glyph(int character, FT_Face face, int glyph_index) {
|
|
|
|
|
|
|
|
CPT(RenderState) state;
|
|
CPT(RenderState) state;
|
|
|
state = RenderState::make(TextureAttrib::make(page),
|
|
state = RenderState::make(TextureAttrib::make(page),
|
|
|
- TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
|
|
|
|
|
|
+ TransparencyAttrib::make(alpha_mode));
|
|
|
state = state->add_attrib(ColorAttrib::make_flat(LColor(1.0f, 1.0f, 1.0f, 1.0f)), -1);
|
|
state = state->add_attrib(ColorAttrib::make_flat(LColor(1.0f, 1.0f, 1.0f, 1.0f)), -1);
|
|
|
|
|
|
|
|
glyph->set_quad(dimensions, texcoords, state);
|
|
glyph->set_quad(dimensions, texcoords, state);
|
|
@@ -1123,179 +1138,4 @@ render_polygon_contours(TextGlyph *glyph, bool face, bool extrude) {
|
|
|
_contours.clear();
|
|
_contours.clear();
|
|
|
}
|
|
}
|
|
|
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: DynamicTextFont::outline_move_to
|
|
|
|
|
-// Access: Private, Static
|
|
|
|
|
-// Description: A callback from FT_Outline_Decompose(). It marks the
|
|
|
|
|
-// beginning of a new contour.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-int DynamicTextFont::
|
|
|
|
|
-outline_move_to(const FT_Vector *to, void *user) {
|
|
|
|
|
- DynamicTextFont *self = (DynamicTextFont *)user;
|
|
|
|
|
-
|
|
|
|
|
- // Convert from 26.6 pixel units to Panda units.
|
|
|
|
|
- PN_stdfloat scale = 1.0f / (64.0f * self->_font_pixels_per_unit);
|
|
|
|
|
- LPoint2 p = LPoint2(to->x, to->y) * scale;
|
|
|
|
|
-
|
|
|
|
|
- if (self->_contours.empty() ||
|
|
|
|
|
- !self->_contours.back()._points.empty()) {
|
|
|
|
|
- self->_contours.push_back(Contour());
|
|
|
|
|
- }
|
|
|
|
|
- self->_q = p;
|
|
|
|
|
- return 0;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: DynamicTextFont::outline_line_to
|
|
|
|
|
-// Access: Private, Static
|
|
|
|
|
-// Description: A callback from FT_Outline_Decompose(). It marks a
|
|
|
|
|
-// straight line in the contour.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-int DynamicTextFont::
|
|
|
|
|
-outline_line_to(const FT_Vector *to, void *user) {
|
|
|
|
|
- DynamicTextFont *self = (DynamicTextFont *)user;
|
|
|
|
|
- nassertr(!self->_contours.empty(), 1);
|
|
|
|
|
-
|
|
|
|
|
- // Convert from 26.6 pixel units to Panda units.
|
|
|
|
|
- PN_stdfloat scale = 1.0f / (64.0f * self->_font_pixels_per_unit);
|
|
|
|
|
- LPoint2 p = LPoint2(to->x, to->y) * scale;
|
|
|
|
|
-
|
|
|
|
|
- // Compute the tangent: this is just the vector from the last point.
|
|
|
|
|
- LVector2 t = (p - self->_q);
|
|
|
|
|
- t.normalize();
|
|
|
|
|
-
|
|
|
|
|
- if (self->_contours.back()._points.empty()) {
|
|
|
|
|
- self->_contours.back()._points.push_back(ContourPoint(self->_q, LVector2::zero(), t));
|
|
|
|
|
- } else {
|
|
|
|
|
- self->_contours.back()._points.back().connect_to(t);
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- self->_contours.back()._points.push_back(ContourPoint(p, t, LVector2::zero()));
|
|
|
|
|
- self->_q = p;
|
|
|
|
|
- return 0;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: DynamicTextFont::outline_conic_to
|
|
|
|
|
-// Access: Private, Static
|
|
|
|
|
-// Description: A callback from FT_Outline_Decompose(). It marks a
|
|
|
|
|
-// parabolic (3rd-order) Bezier curve in the contour.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-int DynamicTextFont::
|
|
|
|
|
-outline_conic_to(const FT_Vector *control,
|
|
|
|
|
- const FT_Vector *to, void *user) {
|
|
|
|
|
- DynamicTextFont *self = (DynamicTextFont *)user;
|
|
|
|
|
- nassertr(!self->_contours.empty(), 1);
|
|
|
|
|
-
|
|
|
|
|
- // Convert from 26.6 pixel units to Panda units.
|
|
|
|
|
- PN_stdfloat scale = 1.0f / (64.0f * self->_font_pixels_per_unit);
|
|
|
|
|
-
|
|
|
|
|
- LPoint2 c = LPoint2(control->x, control->y) * scale;
|
|
|
|
|
- LPoint2 p = LPoint2(to->x, to->y) * scale;
|
|
|
|
|
-
|
|
|
|
|
- // The NurbsCurveEvaluator will evaluate the Bezier segment for us.
|
|
|
|
|
- NurbsCurveEvaluator nce;
|
|
|
|
|
- nce.local_object();
|
|
|
|
|
- nce.set_order(3);
|
|
|
|
|
- nce.reset(3);
|
|
|
|
|
- nce.set_vertex(0, LVecBase3(self->_q[0], self->_q[1], 0.0f));
|
|
|
|
|
- nce.set_vertex(1, LVecBase3(c[0], c[1], 0.0f));
|
|
|
|
|
- nce.set_vertex(2, LVecBase3(p[0], p[1], 0.0f));
|
|
|
|
|
-
|
|
|
|
|
- self->_q = p;
|
|
|
|
|
-
|
|
|
|
|
- PT(NurbsCurveResult) ncr = nce.evaluate();
|
|
|
|
|
- return self->outline_nurbs(ncr);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: DynamicTextFont::outline_cubic_to
|
|
|
|
|
-// Access: Private, Static
|
|
|
|
|
-// Description: A callback from FT_Outline_Decompose(). It marks a
|
|
|
|
|
-// cubic (4th-order) Bezier curve in the contour.
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-int DynamicTextFont::
|
|
|
|
|
-outline_cubic_to(const FT_Vector *control1, const FT_Vector *control2,
|
|
|
|
|
- const FT_Vector *to, void *user) {
|
|
|
|
|
- DynamicTextFont *self = (DynamicTextFont *)user;
|
|
|
|
|
- nassertr(!self->_contours.empty(), 1);
|
|
|
|
|
-
|
|
|
|
|
- // Convert from 26.6 pixel units to Panda units.
|
|
|
|
|
- PN_stdfloat scale = 1.0f / (64.0f * self->_font_pixels_per_unit);
|
|
|
|
|
-
|
|
|
|
|
- LPoint2 c1 = LPoint2(control1->x, control1->y) * scale;
|
|
|
|
|
- LPoint2 c2 = LPoint2(control2->x, control2->y) * scale;
|
|
|
|
|
- LPoint2 p = LPoint2(to->x, to->y) * scale;
|
|
|
|
|
-
|
|
|
|
|
- // The NurbsCurveEvaluator will evaluate the Bezier segment for us.
|
|
|
|
|
- NurbsCurveEvaluator nce;
|
|
|
|
|
- nce.local_object();
|
|
|
|
|
- nce.set_order(4);
|
|
|
|
|
- nce.reset(4);
|
|
|
|
|
- nce.set_vertex(0, LVecBase3(self->_q[0], self->_q[1], 0.0f));
|
|
|
|
|
- nce.set_vertex(1, LVecBase3(c1[0], c1[1], 0.0f));
|
|
|
|
|
- nce.set_vertex(2, LVecBase3(c2[0], c2[1], 0.0f));
|
|
|
|
|
- nce.set_vertex(3, LVecBase3(p[0], p[1], 0.0f));
|
|
|
|
|
-
|
|
|
|
|
- self->_q = p;
|
|
|
|
|
-
|
|
|
|
|
- PT(NurbsCurveResult) ncr = nce.evaluate();
|
|
|
|
|
- return self->outline_nurbs(ncr);
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-// Function: DynamicTextFont::outline_nurbs
|
|
|
|
|
-// Access: Private
|
|
|
|
|
-// Description: Called internally by outline_cubic_to() and
|
|
|
|
|
-// outline_conic_to().
|
|
|
|
|
-////////////////////////////////////////////////////////////////////
|
|
|
|
|
-int DynamicTextFont::
|
|
|
|
|
-outline_nurbs(NurbsCurveResult *ncr) {
|
|
|
|
|
- // Sample it down so that the lines approximate the curve to within
|
|
|
|
|
- // a "pixel."
|
|
|
|
|
- ncr->adaptive_sample(1.0f / _font_pixels_per_unit);
|
|
|
|
|
-
|
|
|
|
|
- int num_samples = ncr->get_num_samples();
|
|
|
|
|
-
|
|
|
|
|
- bool needs_connect = false;
|
|
|
|
|
- int start = 1;
|
|
|
|
|
- if (_contours.back()._points.empty()) {
|
|
|
|
|
- // If we haven't got the first point of this contour yet, we must
|
|
|
|
|
- // add it now.
|
|
|
|
|
- start = 0;
|
|
|
|
|
- } else {
|
|
|
|
|
- needs_connect = true;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- for (int i = start; i < num_samples; ++i) {
|
|
|
|
|
- PN_stdfloat st = ncr->get_sample_t(i);
|
|
|
|
|
- const LPoint3 &p = ncr->get_sample_point(i);
|
|
|
|
|
-
|
|
|
|
|
- PN_stdfloat st0 = st, st1 = st;
|
|
|
|
|
- if (i > 0) {
|
|
|
|
|
- st0 = ncr->get_sample_t(i - 1) * 0.1f + st * 0.9f;
|
|
|
|
|
- }
|
|
|
|
|
- if (i < num_samples - 1) {
|
|
|
|
|
- st1 = ncr->get_sample_t(i + 1) * 0.1f + st * 0.9f;
|
|
|
|
|
- }
|
|
|
|
|
- // Compute the tangent by deltaing nearby points. Don't evaluate
|
|
|
|
|
- // the tangent from the NURBS, since that doesn't appear to be
|
|
|
|
|
- // reliable.
|
|
|
|
|
- LPoint3 p0, p1;
|
|
|
|
|
- ncr->eval_point(st0, p0);
|
|
|
|
|
- ncr->eval_point(st1, p1);
|
|
|
|
|
- LVector3 t = p1 - p0;
|
|
|
|
|
- t.normalize();
|
|
|
|
|
-
|
|
|
|
|
- if (needs_connect) {
|
|
|
|
|
- _contours.back()._points.back().connect_to(LVector2(t[0], t[1]));
|
|
|
|
|
- needs_connect = false;
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- _contours.back()._points.push_back(ContourPoint(p[0], p[1], t[0], t[1]));
|
|
|
|
|
- }
|
|
|
|
|
-
|
|
|
|
|
- return 0;
|
|
|
|
|
-}
|
|
|
|
|
-
|
|
|
|
|
#endif // HAVE_FREETYPE
|
|
#endif // HAVE_FREETYPE
|