DynamicTextFont::RenderMode
This commit is contained in:
parent
7f225df16d
commit
629b215aee
|
|
@ -53,6 +53,18 @@ get_vertex(int n) const {
|
|||
return _vertices[n];
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Triangulator::is_left_winding
|
||||
// Access: Published
|
||||
// Description: Returns true if the polygon vertices are listed in
|
||||
// counterclockwise order, or false if they appear to be
|
||||
// listed in clockwise order.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE bool Triangulator::
|
||||
is_left_winding() const {
|
||||
return check_left_winding(_polygon);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Triangulator::Triangle::Constructor
|
||||
// Access: Private
|
||||
|
|
|
|||
|
|
@ -72,9 +72,10 @@ clear_polygon() {
|
|||
// This vertex should index into the vertex pool
|
||||
// established by repeated calls to add_vertex().
|
||||
//
|
||||
// The vertices should be listed in counterclockwise
|
||||
// order, and should not be repeated. In particular, do
|
||||
// not repeat the first vertex at the end.
|
||||
// The vertices may be listed in either clockwise or
|
||||
// counterclockwise order. Vertices should not be
|
||||
// repeated. In particular, do not repeat the first
|
||||
// vertex at the end.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Triangulator::
|
||||
add_polygon_vertex(int index) {
|
||||
|
|
@ -99,8 +100,9 @@ begin_hole() {
|
|||
// This vertex should index into the vertex pool
|
||||
// established by repeated calls to add_vertex().
|
||||
//
|
||||
// The vertices should be listed in clockwise order, and
|
||||
// should not be repeated.
|
||||
// The vertices may be listed in either clockwise or
|
||||
// counterclockwise order. Vertices should not be
|
||||
// repeated.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Triangulator::
|
||||
add_hole_vertex(int index) {
|
||||
|
|
@ -123,11 +125,11 @@ triangulate() {
|
|||
// Set up the list of segments.
|
||||
seg.clear();
|
||||
seg.push_back(segment_t()); // we don't use the first entry.
|
||||
make_segment(_polygon);
|
||||
make_segment(_polygon, true);
|
||||
|
||||
Holes::const_iterator hi;
|
||||
for (hi = _holes.begin(); hi != _holes.end(); ++hi) {
|
||||
make_segment(*hi);
|
||||
make_segment(*hi, false);
|
||||
}
|
||||
|
||||
// Shuffle the segment index.
|
||||
|
|
@ -305,30 +307,75 @@ get_triangle_v2(int n) const {
|
|||
#define LENGTH(v0) (sqrt((v0).x * (v0).x + (v0).y * (v0).y))
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Triangulator::check_left_winding
|
||||
// Access: Private
|
||||
// Description: Returns true if the list of vertices is
|
||||
// counter-clockwise, false if it is clockwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool Triangulator::
|
||||
check_left_winding(const vector_int &range) const {
|
||||
// We do this by computing the polygon's signed area. If it comes
|
||||
// out negative, the polygon is right-winding.
|
||||
|
||||
double area = 0.0;
|
||||
size_t j = range.size() - 1;
|
||||
for (size_t i = 0; i < range.size(); ++i) {
|
||||
const LPoint2d &p0 = _vertices[range[j]];
|
||||
const LPoint2d &p1 = _vertices[range[i]];
|
||||
area += p0[0] * p1[1] - p0[1] * p1[0];
|
||||
j = i;
|
||||
}
|
||||
|
||||
return area >= 0.0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: Triangulator::make_segment
|
||||
// Access: Private
|
||||
// Description: Converts a linear list of integer vertices to a list
|
||||
// of segment_t.
|
||||
// of segment_t. If want_left_winding is true, the list
|
||||
// is reversed if necessary to make it left-winding;
|
||||
// otherwise, it is reversed to make it right-winding.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void Triangulator::
|
||||
make_segment(const vector_int &range) {
|
||||
make_segment(const vector_int &range, bool want_left_winding) {
|
||||
int num_points = (int)range.size();
|
||||
nassertv(num_points >= 2);
|
||||
|
||||
int first = (int)seg.size();
|
||||
int last = first + num_points - 1;
|
||||
|
||||
seg.push_back(segment_t(this, range[0], range[1],
|
||||
last, first + 1));
|
||||
if (want_left_winding == check_left_winding(range)) {
|
||||
// Keep it in its natural order.
|
||||
int first = (int)seg.size();
|
||||
int last = first + num_points - 1;
|
||||
|
||||
seg.push_back(segment_t(this, range[0], range[1],
|
||||
last, first + 1));
|
||||
|
||||
for (int i = 1; i < num_points - 1; ++i) {
|
||||
seg.push_back(segment_t(this, range[i], range[i + 1],
|
||||
first + i - 1, first + i + 1));
|
||||
}
|
||||
|
||||
seg.push_back(segment_t(this, range[num_points - 1], range[0],
|
||||
last - 1, first));
|
||||
|
||||
} else {
|
||||
// Reverse it.
|
||||
seg.push_back(segment_t(this, range[0], range[num_points - 1],
|
||||
last, first + 1));
|
||||
|
||||
for (int i = 1; i < num_points - 1; ++i) {
|
||||
seg.push_back(segment_t(this, range[num_points - i], range[num_points - i - 1],
|
||||
first + i - 1, first + i + 1));
|
||||
}
|
||||
|
||||
seg.push_back(segment_t(this, range[1], range[0],
|
||||
last - 1, first));
|
||||
|
||||
for (int i = 1; i < num_points - 1; ++i) {
|
||||
seg.push_back(segment_t(this, range[i], range[i + 1],
|
||||
first + i - 1, first + i + 1));
|
||||
}
|
||||
|
||||
seg.push_back(segment_t(this, range[num_points - 1], range[0],
|
||||
last - 1, first));
|
||||
}
|
||||
|
||||
/* Return the next segment in the generated random ordering of all the */
|
||||
|
|
|
|||
|
|
@ -52,6 +52,7 @@ PUBLISHED:
|
|||
|
||||
void clear_polygon();
|
||||
void add_polygon_vertex(int index);
|
||||
INLINE bool is_left_winding() const;
|
||||
|
||||
void begin_hole();
|
||||
void add_hole_vertex(int index);
|
||||
|
|
@ -170,7 +171,8 @@ private:
|
|||
|
||||
vector_int visited;
|
||||
|
||||
void make_segment(const vector_int &range);
|
||||
bool check_left_winding(const vector_int &range) const;
|
||||
void make_segment(const vector_int &range, bool want_left_winding);
|
||||
|
||||
int choose_segment();
|
||||
static double math_log2(double v);
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ INLINE NurbsCurveResult::
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NurbsCurveResult::get_start_t
|
||||
// Access: Public
|
||||
// Access: Published
|
||||
// Description: Returns the first legal value of t on the curve.
|
||||
// Usually this is 0.0.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
@ -39,7 +39,7 @@ get_start_t() const {
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NurbsCurveResult::get_end_t
|
||||
// Access: Public
|
||||
// Access: Published
|
||||
// Description: Returns the last legal value of t on the curve.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float NurbsCurveResult::
|
||||
|
|
@ -124,7 +124,7 @@ eval_extended_points(float t, int d, float result[], int num_values) {
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NurbsCurveResult::get_num_segments
|
||||
// Access: Public
|
||||
// Access: Published
|
||||
// Description: Returns the number of piecewise continuous segments
|
||||
// within the curve. This number is usually not
|
||||
// important unless you plan to call
|
||||
|
|
@ -137,7 +137,7 @@ get_num_segments() const {
|
|||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NurbsCurveResult::get_segment_t
|
||||
// Access: Public
|
||||
// Access: Published
|
||||
// Description: Accepts a t value in the range [0, 1], and assumed to
|
||||
// be relative to the indicated segment (as in
|
||||
// eval_segment_point()), and returns the corresponding
|
||||
|
|
@ -147,3 +147,59 @@ INLINE float NurbsCurveResult::
|
|||
get_segment_t(int segment, float t) const {
|
||||
return t * (_basis.get_to(segment) - _basis.get_from(segment)) + _basis.get_from(segment);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NurbsCurveResult::get_num_samples
|
||||
// Access: Published
|
||||
// Description: Returns the number of sample points generated by the
|
||||
// previous call to adaptive_sample().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE int NurbsCurveResult::
|
||||
get_num_samples() const {
|
||||
return (int)_adaptive_result.size();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NurbsCurveResult::get_sample_t
|
||||
// Access: Published
|
||||
// Description: Returns the t value of the nth sample point generated
|
||||
// by the previous call to adaptive_sample().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE float NurbsCurveResult::
|
||||
get_sample_t(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_adaptive_result.size(), 0.0f);
|
||||
return _adaptive_result[n]._t;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NurbsCurveResult::get_sample_point
|
||||
// Access: Published
|
||||
// Description: Returns the point on the curve of the nth sample
|
||||
// point generated by the previous call to
|
||||
// adaptive_sample().
|
||||
//
|
||||
// For tangents, or extended points, you should use
|
||||
// get_sample_t() and pass it into eval_tangent() or
|
||||
// eval_extended_point().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE const LPoint3f &NurbsCurveResult::
|
||||
get_sample_point(int n) const {
|
||||
nassertr(n >= 0 && n < (int)_adaptive_result.size(), LPoint3f::zero());
|
||||
return _adaptive_result[n]._point;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NurbsCurveResult::get_segment_t
|
||||
// Access: Public
|
||||
// Description: Accepts a t value in the range [0, 1], and assumed to
|
||||
// be relative to the indicated segment (as in
|
||||
// eval_segment_point()), and returns the corresponding
|
||||
// t value in the entire curve (as in eval_point()).
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE NurbsCurveResult::AdaptiveSample::
|
||||
AdaptiveSample(float t, const LPoint3f &point) :
|
||||
_t(t),
|
||||
_point(point)
|
||||
{
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -199,6 +199,41 @@ eval_segment_extended_points(int segment, float t, int d,
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NurbsCurveResult::adaptive_sample
|
||||
// Access: Published
|
||||
// Description: Determines the set of subdivisions necessary to
|
||||
// approximate the curve with a set of linear segments,
|
||||
// no point of which is farther than tolerance units
|
||||
// from the actual curve.
|
||||
//
|
||||
// After this call, you may walk through the resulting
|
||||
// set of samples with get_num_samples(),
|
||||
// get_sample_t(), and get_sample_point().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void NurbsCurveResult::
|
||||
adaptive_sample(float tolerance) {
|
||||
float tolerance_2 = tolerance * tolerance;
|
||||
_adaptive_result.clear();
|
||||
|
||||
LPoint3f p0, p1;
|
||||
|
||||
int num_segments = _basis.get_num_segments();
|
||||
for (int segment = 0; segment < num_segments; ++segment) {
|
||||
eval_segment_point(segment, 0.0f, p0);
|
||||
if (segment == 0 || !p0.almost_equal(p1)) {
|
||||
// We explicitly push the first point, and the boundary point
|
||||
// anytime the segment boundary is discontinuous.
|
||||
_adaptive_result.push_back(AdaptiveSample(_basis.get_from(segment), p0));
|
||||
}
|
||||
|
||||
eval_segment_point(segment, 1.0f, p1);
|
||||
|
||||
// Then we recusrively get the remaining points in the segment.
|
||||
r_adaptive_sample(segment, 0.0f, p0, 1.0f, p1, tolerance_2);
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NurbsCurveResult::find_segment
|
||||
// Access: Private
|
||||
|
|
@ -264,3 +299,46 @@ r_find_segment(float t, int top, int bot) const {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NurbsCurveResult::r_adaptive_sample
|
||||
// Access: Private
|
||||
// Description: Recursively subdivides a potential evaluation of the
|
||||
// segment until it is found to be within tolerance.
|
||||
// This will add everything up to and including t1, but
|
||||
// excluding t0.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void NurbsCurveResult::
|
||||
r_adaptive_sample(int segment, float t0, const LPoint3f &p0,
|
||||
float t1, const LPoint3f &p1, float tolerance_2) {
|
||||
float tmid = (t0 + t1) * 0.5f;
|
||||
LPoint3f pmid;
|
||||
eval_segment_point(segment, tmid, pmid);
|
||||
|
||||
if (sqr_dist_to_line(pmid, p0, p1 - p0) > tolerance_2) {
|
||||
// The line is still too curved--subdivide.
|
||||
r_adaptive_sample(segment, t0, p0, tmid, pmid, tolerance_2);
|
||||
r_adaptive_sample(segment, tmid, pmid, t1, p1, tolerance_2);
|
||||
|
||||
} else {
|
||||
// The line is sufficiently close. Stop here.
|
||||
_adaptive_result.push_back(AdaptiveSample(_basis.scale_t(segment, t1), p1));
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: NurbsCurveResult::sqr_dist_to_line
|
||||
// Access: Private, Static
|
||||
// Description: A support function for r_adaptive_sample(), this
|
||||
// computes the minimum distance from a point to a line,
|
||||
// and returns the distance squared.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
float NurbsCurveResult::
|
||||
sqr_dist_to_line(const LPoint3f &point, const LPoint3f &origin,
|
||||
const LVector3f &vec) {
|
||||
LVector3f norm = vec;
|
||||
norm.normalize();
|
||||
LVector3f d = point - origin;
|
||||
float hyp_2 = d.length_squared();
|
||||
float leg = d.dot(norm);
|
||||
return hyp_2 - leg * leg;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
#include "pandabase.h"
|
||||
#include "referenceCount.h"
|
||||
#include "nurbsBasisVector.h"
|
||||
#include "vector_float.h"
|
||||
|
||||
class NurbsVertex;
|
||||
|
||||
|
|
@ -63,11 +64,21 @@ PUBLISHED:
|
|||
void eval_segment_extended_points(int segment, float t, int d,
|
||||
float result[], int num_values) const;
|
||||
INLINE float get_segment_t(int segment, float t) const;
|
||||
|
||||
void adaptive_sample(float tolerance);
|
||||
INLINE int get_num_samples() const;
|
||||
INLINE float get_sample_t(int n) const;
|
||||
INLINE const LPoint3f &get_sample_point(int n) const;
|
||||
|
||||
private:
|
||||
int find_segment(float t);
|
||||
int r_find_segment(float t, int top, int bot) const;
|
||||
|
||||
void r_adaptive_sample(int segment, float t0, const LPoint3f &p0,
|
||||
float t1, const LPoint3f &p1, float tolerance_2);
|
||||
static float sqr_dist_to_line(const LPoint3f &point, const LPoint3f &origin,
|
||||
const LVector3f &vec);
|
||||
|
||||
NurbsBasisVector _basis;
|
||||
const NurbsVertex *_verts;
|
||||
|
||||
|
|
@ -77,10 +88,18 @@ private:
|
|||
typedef pvector<LMatrix4f> ComposedGeom;
|
||||
ComposedGeom _composed;
|
||||
|
||||
|
||||
int _last_segment;
|
||||
float _last_from;
|
||||
float _last_to;
|
||||
|
||||
class AdaptiveSample {
|
||||
public:
|
||||
INLINE AdaptiveSample(float t, const LPoint3f &point);
|
||||
float _t;
|
||||
LPoint3f _point;
|
||||
};
|
||||
typedef pvector<AdaptiveSample> AdaptiveResult;
|
||||
AdaptiveResult _adaptive_result;
|
||||
};
|
||||
|
||||
#include "nurbsCurveResult.I"
|
||||
|
|
|
|||
|
|
@ -170,12 +170,18 @@ unload_font() {
|
|||
// false otherwise.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
bool FreetypeFont::
|
||||
load_glyph(int glyph_index) {
|
||||
load_glyph(int glyph_index, bool prerender) {
|
||||
int flags = FT_LOAD_RENDER;
|
||||
if (!_native_antialias) {
|
||||
flags |= FT_LOAD_MONOCHROME;
|
||||
}
|
||||
|
||||
if (!prerender) {
|
||||
// If we want to render as an outline font, don't pre-render it to
|
||||
// a bitmap.
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
int error = FT_Load_Glyph(_face, glyph_index, flags);
|
||||
if (error) {
|
||||
pnmtext_cat.error()
|
||||
|
|
|
|||
|
|
@ -76,7 +76,7 @@ public:
|
|||
INLINE static float get_points_per_inch();
|
||||
|
||||
protected:
|
||||
bool load_glyph(int glyph_index);
|
||||
bool load_glyph(int glyph_index, bool prerender = true);
|
||||
void copy_bitmap_to_pnmimage(const FT_Bitmap &bitmap, PNMImage &image);
|
||||
|
||||
private:
|
||||
|
|
@ -99,7 +99,7 @@ protected:
|
|||
|
||||
FT_Face _face;
|
||||
|
||||
private:
|
||||
protected:
|
||||
bool _font_loaded;
|
||||
|
||||
// This string is used to hold the data read from the font file in
|
||||
|
|
|
|||
|
|
@ -7,7 +7,8 @@
|
|||
#define TARGET text
|
||||
#define LOCAL_LIBS \
|
||||
putil gobj pgraph linmath \
|
||||
pnmtext pnmimage gsgbase mathutil
|
||||
pnmtext pnmimage gsgbase mathutil \
|
||||
parametrics
|
||||
|
||||
#define COMBINED_SOURCES $[TARGET]_composite1.cxx $[TARGET]_composite2.cxx
|
||||
|
||||
|
|
|
|||
|
|
@ -182,6 +182,10 @@ ConfigVariableEnum<Texture::WrapMode> text_wrap_mode
|
|||
("text-wrap-mode", Texture::WM_border_color,
|
||||
PRC_DESC("The default wrap mode for dynamic text fonts"));
|
||||
|
||||
ConfigVariableEnum<DynamicTextFont::RenderMode> text_render_mode
|
||||
("text-render-mode", DynamicTextFont::RM_texture,
|
||||
PRC_DESC("The default render mode for dynamic text fonts"));
|
||||
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
|
|
|
|||
|
|
@ -102,7 +102,8 @@ get_pixels_per_unit() const {
|
|||
// larger than 1.0 to improve the font's antialiasing
|
||||
// (since FreeType doesn't really do a swell job of
|
||||
// antialiasing by itself). There is some performance
|
||||
// implication for setting this different than 1.0.
|
||||
// implication for setting this different than 1.0, but
|
||||
// it is probably small.
|
||||
//
|
||||
// This should only be called before any characters have
|
||||
// been requested out of the font, or immediately after
|
||||
|
|
@ -360,6 +361,54 @@ get_anisotropic_degree() const {
|
|||
return _anisotropic_degree;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::set_render_mode
|
||||
// Access: Published
|
||||
// Description: Specifies the way the glyphs on this particular font
|
||||
// are generated. The default is RM_texture, which is
|
||||
// the only mode supported for bitmap fonts. Other modes
|
||||
// are possible for most modern fonts.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void DynamicTextFont::
|
||||
set_render_mode(DynamicTextFont::RenderMode render_mode) {
|
||||
_render_mode = render_mode;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::get_render_mode
|
||||
// Access: Published
|
||||
// Description: Returns the way the glyphs on this particular font
|
||||
// are generated. See set_render_mode().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE DynamicTextFont::RenderMode DynamicTextFont::
|
||||
get_render_mode() const {
|
||||
return _render_mode;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::set_winding_order
|
||||
// Access: Published
|
||||
// Description: Specifies an explicitly winding order on this
|
||||
// particular font. This is only necessary if the
|
||||
// render_mode is RM_polygon or RM_solid, and only if
|
||||
// FreeType appears to guess wrong on this font.
|
||||
// Normally, you should leave this at WO_default.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE void DynamicTextFont::
|
||||
set_winding_order(DynamicTextFont::WindingOrder winding_order) {
|
||||
_winding_order = winding_order;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::get_winding_order
|
||||
// Access: Published
|
||||
// Description: Returns the winding order set via set_winding_order().
|
||||
////////////////////////////////////////////////////////////////////
|
||||
INLINE DynamicTextFont::WindingOrder DynamicTextFont::
|
||||
get_winding_order() const {
|
||||
return _winding_order;
|
||||
}
|
||||
|
||||
INLINE ostream &
|
||||
operator << (ostream &out, const DynamicTextFont &dtf) {
|
||||
return out << dtf.get_name();
|
||||
|
|
|
|||
|
|
@ -20,10 +20,29 @@
|
|||
|
||||
#ifdef HAVE_FREETYPE
|
||||
|
||||
#undef interface // I don't know where this symbol is defined, but it interferes with FreeType.
|
||||
#include FT_OUTLINE_H
|
||||
#include FT_STROKER_H
|
||||
#include FT_BBOX_H
|
||||
#ifdef FT_BITMAP_H
|
||||
#include FT_BITMAP_H
|
||||
#endif
|
||||
|
||||
#include "config_text.h"
|
||||
#include "config_util.h"
|
||||
#include "config_express.h"
|
||||
#include "virtualFileSystem.h"
|
||||
#include "geomVertexData.h"
|
||||
#include "geomVertexFormat.h"
|
||||
#include "geomVertexWriter.h"
|
||||
#include "geomLinestrips.h"
|
||||
#include "geomTriangles.h"
|
||||
#include "renderState.h"
|
||||
#include "string_utils.h"
|
||||
#include "triangulator.h"
|
||||
#include "nurbsCurveEvaluator.h"
|
||||
#include "nurbsCurveResult.h"
|
||||
//#include "renderModeAttrib.h"
|
||||
|
||||
TypeHandle DynamicTextFont::_type_handle;
|
||||
|
||||
|
|
@ -229,6 +248,51 @@ get_glyph(int character, const TextGlyph *&glyph) {
|
|||
return (glyph_index != 0 && glyph != (DynamicTextGlyph *)NULL);
|
||||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::string_render_mode
|
||||
// Access: Public
|
||||
// Description: Returns the RenderMode value associated with the given
|
||||
// string representation, or RM_invalid if the string
|
||||
// does not match any known RenderMode value.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DynamicTextFont::RenderMode DynamicTextFont::
|
||||
string_render_mode(const string &string) {
|
||||
if (cmp_nocase_uh(string, "texture") == 0) {
|
||||
return RM_texture;
|
||||
} else if (cmp_nocase_uh(string, "wireframe") == 0) {
|
||||
return RM_wireframe;
|
||||
} else if (cmp_nocase_uh(string, "polygon") == 0) {
|
||||
return RM_polygon;
|
||||
} else if (cmp_nocase_uh(string, "extruded") == 0) {
|
||||
return RM_extruded;
|
||||
} else if (cmp_nocase_uh(string, "solid") == 0) {
|
||||
return RM_solid;
|
||||
} else {
|
||||
return RM_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::string_winding_order
|
||||
// Access: Public
|
||||
// Description: Returns the WindingOrder value associated with the given
|
||||
// string representation, or WO_invalid if the string
|
||||
// does not match any known WindingOrder value.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
DynamicTextFont::WindingOrder DynamicTextFont::
|
||||
string_winding_order(const string &string) {
|
||||
if (cmp_nocase_uh(string, "default") == 0) {
|
||||
return WO_default;
|
||||
} else if (cmp_nocase_uh(string, "left") == 0) {
|
||||
return WO_left;
|
||||
} else if (cmp_nocase_uh(string, "right") == 0) {
|
||||
return WO_right;
|
||||
} else {
|
||||
return WO_invalid;
|
||||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::initialize
|
||||
// Access: Private
|
||||
|
|
@ -253,6 +317,9 @@ initialize() {
|
|||
// require generating mipmaps, but does require hardware support.
|
||||
_anisotropic_degree = text_anisotropic_degree;
|
||||
|
||||
_render_mode = text_render_mode;
|
||||
_winding_order = WO_default;
|
||||
|
||||
_preferred_page = 0;
|
||||
}
|
||||
|
||||
|
|
@ -284,7 +351,7 @@ update_filters() {
|
|||
////////////////////////////////////////////////////////////////////
|
||||
DynamicTextGlyph *DynamicTextFont::
|
||||
make_glyph(int character, int glyph_index) {
|
||||
if (!load_glyph(glyph_index)) {
|
||||
if (!load_glyph(glyph_index, false)) {
|
||||
return (DynamicTextGlyph *)NULL;
|
||||
}
|
||||
|
||||
|
|
@ -293,6 +360,79 @@ make_glyph(int character, int glyph_index) {
|
|||
|
||||
float advance = slot->advance.x / 64.0;
|
||||
|
||||
if (_render_mode != RM_texture &&
|
||||
slot->format == ft_glyph_format_outline) {
|
||||
// Re-stroke the glyph to make it an outline glyph.
|
||||
/*
|
||||
FT_Stroker stroker;
|
||||
FT_Stroker_New(_face->memory, &stroker);
|
||||
FT_Stroker_Set(stroker, 16 * 16, FT_STROKER_LINECAP_BUTT,
|
||||
FT_STROKER_LINEJOIN_ROUND, 0);
|
||||
|
||||
FT_Stroker_ParseOutline(stroker, &slot->outline, 0);
|
||||
|
||||
FT_UInt num_points, num_contours;
|
||||
FT_Stroker_GetCounts(stroker, &num_points, &num_contours);
|
||||
|
||||
FT_Outline border;
|
||||
FT_Outline_New(_ft_library, num_points, num_contours, &border);
|
||||
border.n_points = 0;
|
||||
border.n_contours = 0;
|
||||
FT_Stroker_Export(stroker, &border);
|
||||
FT_Stroker_Done(stroker);
|
||||
|
||||
FT_Outline_Done(_ft_library, &slot->outline);
|
||||
memcpy(&slot->outline, &border, sizeof(border));
|
||||
*/
|
||||
|
||||
// Ask FreeType to extract the contours out of the outline
|
||||
// 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.
|
||||
if (FT_Outline_Get_Orientation(&slot->outline) == FT_ORIENTATION_FILL_RIGHT) {
|
||||
wo = WO_right;
|
||||
} else {
|
||||
wo = WO_left;
|
||||
}
|
||||
}
|
||||
|
||||
if (wo != WO_left) {
|
||||
FT_Outline_Reverse(&slot->outline);
|
||||
}
|
||||
|
||||
_contours.clear();
|
||||
FT_Outline_Decompose(&slot->outline, &funcs, (void *)this);
|
||||
|
||||
PT(DynamicTextGlyph) glyph =
|
||||
new DynamicTextGlyph(character, advance / _font_pixels_per_unit);
|
||||
switch (_render_mode) {
|
||||
case RM_wireframe:
|
||||
render_wireframe_contours(glyph);
|
||||
return glyph;
|
||||
|
||||
case RM_polygon:
|
||||
render_polygon_contours(glyph);
|
||||
return glyph;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Render the glyph if necessary.
|
||||
if (slot->format != ft_glyph_format_bitmap) {
|
||||
FT_Render_Glyph(slot, FT_RENDER_MODE_NORMAL);
|
||||
}
|
||||
|
||||
if (bitmap.width == 0 || bitmap.rows == 0) {
|
||||
// If we got an empty bitmap, it's a special case.
|
||||
PT(DynamicTextGlyph) glyph =
|
||||
|
|
@ -485,4 +625,305 @@ slot_glyph(int character, int x_size, int y_size) {
|
|||
}
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::render_wireframe_contours
|
||||
// Access: Private
|
||||
// Description: Converts from the _contours list to an actual glyph
|
||||
// geometry, as a wireframe render.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DynamicTextFont::
|
||||
render_wireframe_contours(DynamicTextGlyph *glyph) {
|
||||
PT(GeomVertexData) vdata = new GeomVertexData
|
||||
(string(), GeomVertexFormat::get_v3(),
|
||||
Geom::UH_static);
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
|
||||
PT(GeomLinestrips) lines = new GeomLinestrips(Geom::UH_static);
|
||||
|
||||
Contours::const_iterator ci;
|
||||
for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
|
||||
const Contour &contour = (*ci);
|
||||
Points::const_iterator pi;
|
||||
|
||||
for (pi = contour._points.begin(); pi != contour._points.end(); ++pi) {
|
||||
const LPoint2f &p = (*pi);
|
||||
vertex.add_data3f(p[0], 0.0f, p[1]);
|
||||
}
|
||||
|
||||
lines->add_next_vertices(contour._points.size());
|
||||
lines->close_primitive();
|
||||
}
|
||||
|
||||
glyph->set_geom(vdata, lines, RenderState::make_empty());
|
||||
_contours.clear();
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::render_polygon_contours
|
||||
// Access: Private
|
||||
// Description: Converts from the _contours list to an actual glyph
|
||||
// geometry, as a polygon render.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DynamicTextFont::
|
||||
render_polygon_contours(DynamicTextGlyph *glyph) {
|
||||
PT(GeomVertexData) vdata = new GeomVertexData
|
||||
(string(), GeomVertexFormat::get_v3(),
|
||||
Geom::UH_static);
|
||||
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
||||
|
||||
PT(GeomTriangles) tris = new GeomTriangles(Geom::UH_static);
|
||||
Triangulator t;
|
||||
|
||||
// First, build up the list of vertices, and determine which
|
||||
// contours are solid and which are holes.
|
||||
Contours::iterator ci;
|
||||
for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
|
||||
Contour &contour = (*ci);
|
||||
|
||||
t.clear_polygon();
|
||||
contour._start_vertex = t.get_num_vertices();
|
||||
for (size_t i = 0; i < contour._points.size() - 1; ++i) {
|
||||
const LPoint2f &p = contour._points[i];
|
||||
vertex.add_data3f(p[0], 0.0f, p[1]);
|
||||
int vi = t.add_vertex(p[0], p[1]);
|
||||
t.add_polygon_vertex(vi);
|
||||
}
|
||||
|
||||
contour._is_solid = t.is_left_winding();
|
||||
}
|
||||
|
||||
// Now go back and generate the actual triangles.
|
||||
for (ci = _contours.begin(); ci != _contours.end(); ++ci) {
|
||||
const Contour &contour = (*ci);
|
||||
|
||||
if (contour._is_solid && !contour._points.empty()) {
|
||||
t.clear_polygon();
|
||||
for (size_t i = 0; i < contour._points.size() - 1; ++i) {
|
||||
t.add_polygon_vertex(contour._start_vertex + i);
|
||||
}
|
||||
|
||||
// Also add all the holes to each polygon.
|
||||
Contours::iterator cj;
|
||||
for (cj = _contours.begin(); cj != _contours.end(); ++cj) {
|
||||
Contour &hole = (*cj);
|
||||
if (!hole._is_solid && !hole._points.empty()) {
|
||||
t.begin_hole();
|
||||
for (size_t j = 0; j < hole._points.size() - 1; ++j) {
|
||||
t.add_hole_vertex(hole._start_vertex + j);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
t.triangulate();
|
||||
int num_triangles = t.get_num_triangles();
|
||||
for (int ti = 0; ti < num_triangles; ++ti) {
|
||||
tris->add_vertex(t.get_triangle_v0(ti));
|
||||
tris->add_vertex(t.get_triangle_v1(ti));
|
||||
tris->add_vertex(t.get_triangle_v2(ti));
|
||||
tris->close_primitive();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
glyph->set_geom(vdata, tris, RenderState::make_empty());
|
||||
// glyph->set_geom(vdata, tris, RenderState::make(RenderModeAttrib::make(RenderModeAttrib::M_wireframe)));
|
||||
_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.
|
||||
float scale = 1.0f / (64.0f * self->_font_pixels_per_unit);
|
||||
LPoint2f p = LPoint2f(to->x, to->y) * scale;
|
||||
|
||||
self->_contours.push_back(Contour());
|
||||
self->_contours.back()._points.push_back(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.
|
||||
float scale = 1.0f / (64.0f * self->_font_pixels_per_unit);
|
||||
LPoint2f p = LPoint2f(to->x, to->y) * scale;
|
||||
|
||||
self->_contours.back()._points.push_back(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);
|
||||
const LPoint2f &q = self->_contours.back()._points.back();
|
||||
|
||||
// Convert from 26.6 pixel units to Panda units.
|
||||
float scale = 1.0f / (64.0f * self->_font_pixels_per_unit);
|
||||
|
||||
LPoint2f c = LPoint2f(control->x, control->y) * scale;
|
||||
LPoint2f p = LPoint2f(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, LVecBase3f(q[0], q[1], 0.0f));
|
||||
nce.set_vertex(1, LVecBase3f(c[0], c[1], 0.0f));
|
||||
nce.set_vertex(2, LVecBase3f(p[0], p[1], 0.0f));
|
||||
|
||||
PT(NurbsCurveResult) ncr = nce.evaluate();
|
||||
|
||||
// Sample it down so that the lines approximate the curve to within
|
||||
// a "pixel."
|
||||
ncr->adaptive_sample(1.0f / self->_font_pixels_per_unit);
|
||||
|
||||
int num_samples = ncr->get_num_samples();
|
||||
for (int i = 1; i < num_samples; ++i) {
|
||||
const LPoint3f &p = ncr->get_sample_point(i);
|
||||
self->_contours.back()._points.push_back(LPoint2f(p[0], p[1]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// 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);
|
||||
const LPoint2f &q = self->_contours.back()._points.back();
|
||||
|
||||
// Convert from 26.6 pixel units to Panda units.
|
||||
float scale = 1.0f / (64.0f * self->_font_pixels_per_unit);
|
||||
|
||||
LPoint2f c1 = LPoint2f(control1->x, control1->y) * scale;
|
||||
LPoint2f c2 = LPoint2f(control2->x, control2->y) * scale;
|
||||
LPoint2f p = LPoint2f(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, LVecBase3f(q[0], q[1], 0.0f));
|
||||
nce.set_vertex(1, LVecBase3f(c1[0], c1[1], 0.0f));
|
||||
nce.set_vertex(2, LVecBase3f(c2[0], c2[1], 0.0f));
|
||||
nce.set_vertex(3, LVecBase3f(p[0], p[1], 0.0f));
|
||||
|
||||
PT(NurbsCurveResult) ncr = nce.evaluate();
|
||||
|
||||
// Sample it down so that the lines approximate the curve to within
|
||||
// a "pixel."
|
||||
ncr->adaptive_sample(1.0f / self->_font_pixels_per_unit);
|
||||
|
||||
int num_samples = ncr->get_num_samples();
|
||||
for (int i = 1; i < num_samples; ++i) {
|
||||
const LPoint3f &p = ncr->get_sample_point(i);
|
||||
self->_contours.back()._points.push_back(LPoint2f(p[0], p[1]));
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::RenderMode output operator
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
ostream &
|
||||
operator << (ostream &out, DynamicTextFont::RenderMode rm) {
|
||||
switch (rm) {
|
||||
case DynamicTextFont::RM_texture:
|
||||
return out << "texture";
|
||||
case DynamicTextFont::RM_wireframe:
|
||||
return out << "wireframe";
|
||||
case DynamicTextFont::RM_polygon:
|
||||
return out << "polygon";
|
||||
case DynamicTextFont::RM_extruded:
|
||||
return out << "extruded";
|
||||
case DynamicTextFont::RM_solid:
|
||||
return out << "solid";
|
||||
|
||||
case DynamicTextFont::RM_invalid:
|
||||
return out << "invalid";
|
||||
}
|
||||
|
||||
return out << "(**invalid DynamicTextFont::RenderMode(" << (int)rm << ")**)";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::RenderMode input operator
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
istream &
|
||||
operator >> (istream &in, DynamicTextFont::RenderMode &rm) {
|
||||
string word;
|
||||
in >> word;
|
||||
|
||||
rm = DynamicTextFont::string_render_mode(word);
|
||||
return in;
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::WindingOrder output operator
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
ostream &
|
||||
operator << (ostream &out, DynamicTextFont::WindingOrder wo) {
|
||||
switch (wo) {
|
||||
case DynamicTextFont::WO_default:
|
||||
return out << "default";
|
||||
case DynamicTextFont::WO_left:
|
||||
return out << "left";
|
||||
case DynamicTextFont::WO_right:
|
||||
return out << "right";
|
||||
|
||||
case DynamicTextFont::WO_invalid:
|
||||
return out << "invalid";
|
||||
}
|
||||
|
||||
return out << "(**invalid DynamicTextFont::WindingOrder(" << (int)wo << ")**)";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextFont::WindingOrder input operator
|
||||
// Description:
|
||||
////////////////////////////////////////////////////////////////////
|
||||
istream &
|
||||
operator >> (istream &in, DynamicTextFont::WindingOrder &wo) {
|
||||
string word;
|
||||
in >> word;
|
||||
|
||||
wo = DynamicTextFont::string_winding_order(word);
|
||||
return in;
|
||||
}
|
||||
|
||||
#endif // HAVE_FREETYPE
|
||||
|
|
|
|||
|
|
@ -45,6 +45,34 @@
|
|||
////////////////////////////////////////////////////////////////////
|
||||
class EXPCL_PANDA DynamicTextFont : public TextFont, public FreetypeFont {
|
||||
PUBLISHED:
|
||||
enum RenderMode {
|
||||
// Each glyph is a single textured rectangle
|
||||
RM_texture,
|
||||
|
||||
// Each glyph is a lot of line segments
|
||||
RM_wireframe,
|
||||
|
||||
// Each glyph is a lot of triangles
|
||||
RM_polygon,
|
||||
|
||||
// a 3-D outline, like a cookie cutter
|
||||
RM_extruded,
|
||||
|
||||
// combination of RM_extruded and RM_polygon
|
||||
RM_solid,
|
||||
|
||||
// Returned by string_render_mode() for an invalid match.
|
||||
RM_invalid,
|
||||
};
|
||||
|
||||
enum WindingOrder {
|
||||
WO_default,
|
||||
WO_left,
|
||||
WO_right,
|
||||
|
||||
WO_invalid,
|
||||
};
|
||||
|
||||
DynamicTextFont(const Filename &font_filename, int face_index = 0);
|
||||
DynamicTextFont(const char *font_data, int data_length, int face_index);
|
||||
virtual ~DynamicTextFont();
|
||||
|
|
@ -84,6 +112,11 @@ PUBLISHED:
|
|||
INLINE void set_anisotropic_degree(int anisotropic_degree);
|
||||
INLINE int get_anisotropic_degree() const;
|
||||
|
||||
INLINE void set_render_mode(RenderMode render_mode);
|
||||
INLINE RenderMode get_render_mode() const;
|
||||
INLINE void set_winding_order(WindingOrder winding_order);
|
||||
INLINE WindingOrder get_winding_order() const;
|
||||
|
||||
int get_num_pages() const;
|
||||
DynamicTextPage *get_page(int n) const;
|
||||
|
||||
|
|
@ -95,6 +128,9 @@ PUBLISHED:
|
|||
public:
|
||||
virtual bool get_glyph(int character, const TextGlyph *&glyph);
|
||||
|
||||
static RenderMode string_render_mode(const string &string);
|
||||
static WindingOrder string_winding_order(const string &string);
|
||||
|
||||
private:
|
||||
void initialize();
|
||||
void update_filters();
|
||||
|
|
@ -103,6 +139,17 @@ private:
|
|||
void copy_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph);
|
||||
DynamicTextGlyph *slot_glyph(int character, int x_size, int y_size);
|
||||
|
||||
void render_wireframe_contours(DynamicTextGlyph *glyph);
|
||||
void render_polygon_contours(DynamicTextGlyph *glyph);
|
||||
|
||||
static int outline_move_to(const FT_Vector *to, void *user);
|
||||
static int outline_line_to(const FT_Vector *to, void *user);
|
||||
static int outline_conic_to(const FT_Vector *control,
|
||||
const FT_Vector *to, void *user);
|
||||
static int outline_cubic_to(const FT_Vector *control1,
|
||||
const FT_Vector *control2,
|
||||
const FT_Vector *to, void *user);
|
||||
|
||||
int _texture_margin;
|
||||
float _poly_margin;
|
||||
int _page_x_size, _page_y_size;
|
||||
|
|
@ -111,6 +158,9 @@ private:
|
|||
Texture::FilterType _magfilter;
|
||||
int _anisotropic_degree;
|
||||
|
||||
RenderMode _render_mode;
|
||||
WindingOrder _winding_order;
|
||||
|
||||
typedef pvector< PT(DynamicTextPage) > Pages;
|
||||
Pages _pages;
|
||||
int _preferred_page;
|
||||
|
|
@ -127,6 +177,18 @@ private:
|
|||
typedef pvector< PT(DynamicTextGlyph) > EmptyGlyphs;
|
||||
EmptyGlyphs _empty_glyphs;
|
||||
|
||||
typedef pvector<LPoint2f> Points;
|
||||
|
||||
class Contour {
|
||||
public:
|
||||
Points _points;
|
||||
bool _is_solid;
|
||||
int _start_vertex;
|
||||
};
|
||||
|
||||
typedef pvector<Contour> Contours;
|
||||
Contours _contours;
|
||||
|
||||
public:
|
||||
static TypeHandle get_class_type() {
|
||||
return _type_handle;
|
||||
|
|
@ -149,6 +211,11 @@ private:
|
|||
|
||||
INLINE ostream &operator << (ostream &out, const DynamicTextFont &dtf);
|
||||
|
||||
EXPCL_PANDA ostream &operator << (ostream &out, DynamicTextFont::RenderMode rm);
|
||||
EXPCL_PANDA istream &operator >> (istream &in, DynamicTextFont::RenderMode &rm);
|
||||
EXPCL_PANDA ostream &operator << (ostream &out, DynamicTextFont::WindingOrder wo);
|
||||
EXPCL_PANDA istream &operator >> (istream &in, DynamicTextFont::WindingOrder &wo);
|
||||
|
||||
#include "dynamicTextFont.I"
|
||||
|
||||
#endif // HAVE_FREETYPE
|
||||
|
|
|
|||
|
|
@ -168,4 +168,30 @@ make_geom(int bitmap_top, int bitmap_left, float advance, float poly_margin,
|
|||
}
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////
|
||||
// Function: DynamicTextGlyph::set_geom
|
||||
// Access: Public
|
||||
// Description: Sets the geom from a pre-built object.
|
||||
////////////////////////////////////////////////////////////////////
|
||||
void DynamicTextGlyph::
|
||||
set_geom(GeomVertexData *vdata, GeomPrimitive *prim,
|
||||
const RenderState *state) {
|
||||
// This function is called when _geom_count = 1, because it was
|
||||
// constructed via the empty Glyph constructor.
|
||||
nassertv(_geom_count == 1);
|
||||
_geom_count--;
|
||||
|
||||
PT(Geom) geom = new GeomTextGlyph(this, vdata);
|
||||
geom->add_primitive(prim);
|
||||
_geom = geom;
|
||||
|
||||
// The above will increment our _geom_count to 1. Reset it back
|
||||
// down to 0, since our own internal Geom doesn't count.
|
||||
nassertv(_geom_count == 1);
|
||||
_geom_count--;
|
||||
|
||||
_state = state;
|
||||
}
|
||||
|
||||
|
||||
#endif // HAVE_FREETYPE
|
||||
|
|
|
|||
|
|
@ -53,6 +53,8 @@ public:
|
|||
void make_geom(int top, int left, float advance, float poly_margin,
|
||||
float tex_x_size, float tex_y_size,
|
||||
float font_pixels_per_unit, float tex_pixels_per_unit);
|
||||
void set_geom(GeomVertexData *vdata, GeomPrimitive *prim,
|
||||
const RenderState *state);
|
||||
|
||||
DynamicTextPage *_page;
|
||||
int _geom_count;
|
||||
|
|
|
|||
|
|
@ -289,6 +289,8 @@ load_default_font() {
|
|||
// Loading the compiled-in FreeType font is relatively easy.
|
||||
_default_font = new DynamicTextFont((const char *)default_font_data,
|
||||
default_font_size, 0);
|
||||
// The compiled-in font seems to confuse FreeType about its winding order.
|
||||
((DynamicTextFont *)_default_font.p())->set_winding_order(DynamicTextFont::WO_left);
|
||||
|
||||
#else
|
||||
// The compiled-in Bam font requires creating a BamFile object to
|
||||
|
|
|
|||
Loading…
Reference in New Issue