add scale_factor

This commit is contained in:
David Rose 2002-11-27 22:38:41 +00:00
parent c77fcbe00a
commit 0efa534315
7 changed files with 248 additions and 79 deletions

View File

@ -36,12 +36,13 @@ ConfigureFn(config_text) {
const bool text_flatten = config_text.GetBool("text-flatten", true);
const bool text_update_cleared_glyphs = config_text.GetBool("text-update-cleared-glyphs", false);
const int text_anisotropic_degree = config_text.GetInt("text-anisotropic-degree", 1);
const int text_texture_margin = config_text.GetInt("text-texture-margin", 3);
const float text_poly_margin = config_text.GetFloat("text-poly-margin", 1.0f);
const int text_texture_margin = config_text.GetInt("text-texture-margin", 2);
const float text_poly_margin = config_text.GetFloat("text-poly-margin", 0.6f);
const int text_page_x_size = config_text.GetInt("text-page-x-size", 256);
const int text_page_y_size = config_text.GetInt("text-page-y-size", 256);
const float text_point_size = config_text.GetFloat("text-point-size", 10.0f);
const float text_pixels_per_unit = config_text.GetFloat("text-pixels-per-unit", 30.0f);
const float text_scale_factor = config_text.GetFloat("text-scale-factor", 2.0f);
const bool text_small_caps = config_text.GetBool("text-small-caps", false);
const float text_small_caps_scale = config_text.GetFloat("text-small-caps-scale", 0.8f);

View File

@ -36,6 +36,7 @@ extern const int text_page_x_size;
extern const int text_page_y_size;
extern const float text_point_size;
extern const float text_pixels_per_unit;
extern const float text_scale_factor;
extern const bool text_small_caps;
extern const float text_small_caps_scale;

View File

@ -67,7 +67,7 @@ set_pixels_per_unit(float pixels_per_unit) {
// If this assertion fails, you didn't call clear() first. RTFM.
nassertr(get_num_pages() == 0, false);
_pixels_per_unit = pixels_per_unit;
_tex_pixels_per_unit = pixels_per_unit;
return reset_scale();
}
@ -79,7 +79,43 @@ set_pixels_per_unit(float pixels_per_unit) {
////////////////////////////////////////////////////////////////////
INLINE float DynamicTextFont::
get_pixels_per_unit() const {
return _pixels_per_unit;
return _tex_pixels_per_unit;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::set_scale_factor
// Access: Published
// Description: Sets the factor by which the font is rendered larger
// by the FreeType library before being filtered down to
// its actual size in the texture as specified by
// set_pixels_per_unit(). This may be set to a number
// 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.
//
// This should only be called before any characters have
// been requested out of the font, or immediately after
// calling clear().
////////////////////////////////////////////////////////////////////
INLINE bool DynamicTextFont::
set_scale_factor(float scale_factor) {
// If this assertion fails, you didn't call clear() first. RTFM.
nassertr(get_num_pages() == 0, false);
_scale_factor = scale_factor;
return reset_scale();
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_scale_factor
// Access: Published
// Description: Returns the antialiasing scale factor. See
// set_scale_factor().
////////////////////////////////////////////////////////////////////
INLINE float DynamicTextFont::
get_scale_factor() const {
return _scale_factor;
}
////////////////////////////////////////////////////////////////////

View File

@ -55,7 +55,8 @@ DynamicTextFont(const Filename &font_filename, int face_index) {
_page_x_size = text_page_x_size;
_page_y_size = text_page_y_size;
_point_size = text_point_size;
_pixels_per_unit = text_pixels_per_unit;
_tex_pixels_per_unit = text_pixels_per_unit;
_scale_factor = text_scale_factor;
_small_caps = text_small_caps;
_small_caps_scale = text_small_caps_scale;
@ -337,14 +338,19 @@ update_filters() {
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::reset_scale
// Access: Private
// Description: Resets the font to use the current _point_size and
// _pixels_per_unit. Returns true if successful, false
// otherwise.
// Description: Resets the font based on the current values for
// _point_size, _tex_pixels_per_unit, and _scale_factor.
// Returns true if successful, false otherwise.
////////////////////////////////////////////////////////////////////
bool DynamicTextFont::
reset_scale() {
// The font may be rendered larger (by a factor of _scale_factor),
// and then reduced into the texture. Hence the difference between
// _font_pixels_per_unit aned _tex_pixels_per_unit.
_font_pixels_per_unit = _tex_pixels_per_unit * _scale_factor;
float units_per_inch = (points_per_inch / points_per_unit);
int dpi = (int)(_pixels_per_unit * units_per_inch);
int dpi = (int)(_font_pixels_per_unit * units_per_inch);
int error = FT_Set_Char_Size(_face,
(int)(_point_size * 64), (int)(_point_size * 64),
@ -353,7 +359,7 @@ reset_scale() {
// If we were unable to set a particular char size, perhaps we
// have a non-scalable font. Try to figure out the closest
// available size.
int desired_height = (int)(_pixels_per_unit * _point_size / points_per_unit + 0.5f);
int desired_height = (int)(_font_pixels_per_unit * _point_size / points_per_unit + 0.5f);
int best_size = -1;
if (_face->num_fixed_sizes > 0) {
best_size = 0;
@ -375,7 +381,8 @@ reset_scale() {
<< "Using " << pixel_height << "-pixel font for "
<< get_name() << "\n";
_pixels_per_unit = pixel_height * points_per_unit / _point_size;
_font_pixels_per_unit = pixel_height * points_per_unit / _point_size;
_tex_pixels_per_unit = _font_pixels_per_unit;
}
}
}
@ -388,7 +395,7 @@ reset_scale() {
return false;
}
_line_height = _face->size->metrics.height / (_pixels_per_unit * 64.0f);
_line_height = _face->size->metrics.height / (_font_pixels_per_unit * 64.0f);
// Determine the correct width for a space.
error = FT_Load_Char(_face, ' ', FT_LOAD_DEFAULT);
@ -397,7 +404,7 @@ reset_scale() {
_space_advance = 0.25f * _line_height;
} else {
_space_advance = _face->glyph->advance.x / (_pixels_per_unit * 64.0f);
_space_advance = _face->glyph->advance.x / (_font_pixels_per_unit * 64.0f);
}
return true;
@ -427,77 +434,190 @@ make_glyph(int glyph_index) {
if (bitmap.width == 0 || bitmap.rows == 0) {
// If we got an empty bitmap, it's a special case.
PT(DynamicTextGlyph) glyph = new DynamicTextGlyph(advance / _pixels_per_unit);
PT(DynamicTextGlyph) glyph =
new DynamicTextGlyph(advance / _font_pixels_per_unit);
_empty_glyphs.push_back(glyph);
return glyph;
} else {
DynamicTextGlyph *glyph = slot_glyph(bitmap.width, bitmap.rows);
DynamicTextGlyph *glyph;
if (bitmap.pixel_mode == ft_pixel_mode_grays && bitmap.num_grays == 256) {
// This is the easy case: we can memcpy the rendered glyph
// directly into our texture image, one row at a time.
unsigned char *buffer_row = bitmap.buffer;
for (int yi = 0; yi < bitmap.rows; yi++) {
unsigned char *texture_row = glyph->get_row(yi);
nassertr(texture_row != (unsigned char *)NULL, (DynamicTextGlyph *)NULL);
memcpy(texture_row, buffer_row, bitmap.width);
buffer_row += bitmap.pitch;
}
} else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
// This is a little bit more work: we have to expand the
// one-bit-per-pixel bitmap into a one-byte-per-pixel texture.
unsigned char *buffer_row = bitmap.buffer;
for (int yi = 0; yi < bitmap.rows; yi++) {
unsigned char *texture_row = glyph->get_row(yi);
nassertr(texture_row != (unsigned char *)NULL, (DynamicTextGlyph *)NULL);
int bit = 0x80;
unsigned char *b = buffer_row;
for (int xi = 0; xi < bitmap.width; xi++) {
if (*b & bit) {
texture_row[xi] = 0xff;
} else {
texture_row[xi] = 0x00;
}
bit >>= 1;
if (bit == 0) {
++b;
bit = 0x80;
}
}
buffer_row += bitmap.pitch;
}
} else if (bitmap.pixel_mode == ft_pixel_mode_grays) {
// Here we must expand a grayscale pixmap with n levels of gray
// into our 256-level texture.
unsigned char *buffer_row = bitmap.buffer;
for (int yi = 0; yi < bitmap.rows; yi++) {
unsigned char *texture_row = glyph->get_row(yi);
nassertr(texture_row != (unsigned char *)NULL, (DynamicTextGlyph *)NULL);
for (int xi = 0; xi < bitmap.width; xi++) {
texture_row[xi] = (int)(buffer_row[xi] * 255) / (bitmap.num_grays - 1);
}
buffer_row += bitmap.pitch;
}
if (_tex_pixels_per_unit == _font_pixels_per_unit) {
// If the bitmap produced from the font doesn't require scaling
// before it goes to the texture, we can just copy it directly
// into the texture.
glyph = slot_glyph(bitmap.width, bitmap.rows);
copy_bitmap_to_texture(bitmap, glyph);
} else {
text_cat.error()
<< "Unexpected pixel mode in bitmap: " << (int)bitmap.pixel_mode << "\n";
}
// Otherwise, we need to copy to a PNMImage first, so we can
// scale it; and then copy it to the texture from there.
int tex_x_size = (int)(bitmap.width / _scale_factor + 0.5f);
int tex_y_size = (int)(bitmap.rows / _scale_factor + 0.5f);
glyph = slot_glyph(tex_x_size, tex_y_size);
PNMImage image(bitmap.width, bitmap.rows, PNMImage::CT_grayscale);
copy_bitmap_to_pnmimage(bitmap, image);
PNMImage reduced(tex_x_size, tex_y_size, PNMImage::CT_grayscale);
reduced.quick_filter_from(image);
copy_pnmimage_to_texture(reduced, glyph);
}
glyph->_page->mark_dirty(Texture::DF_image);
glyph->make_geom(slot->bitmap_top, slot->bitmap_left, advance,
_poly_margin, _pixels_per_unit);
glyph->make_geom(slot->bitmap_top, slot->bitmap_left, advance, _poly_margin,
_font_pixels_per_unit, _tex_pixels_per_unit);
return glyph;
}
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::copy_bitmap_to_texture
// Access: Private
// Description: Copies a bitmap as rendered by FreeType directly into
// the texture memory image for the indicated glyph,
// without any scaling of pixels.
////////////////////////////////////////////////////////////////////
void DynamicTextFont::
copy_bitmap_to_texture(const FT_Bitmap &bitmap, DynamicTextGlyph *glyph) {
if (bitmap.pixel_mode == ft_pixel_mode_grays && bitmap.num_grays == 256) {
// This is the easy case: we can memcpy the rendered glyph
// directly into our texture image, one row at a time.
unsigned char *buffer_row = bitmap.buffer;
for (int yi = 0; yi < bitmap.rows; yi++) {
unsigned char *texture_row = glyph->get_row(yi);
nassertv(texture_row != (unsigned char *)NULL);
memcpy(texture_row, buffer_row, bitmap.width);
buffer_row += bitmap.pitch;
}
} else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
// This is a little bit more work: we have to expand the
// one-bit-per-pixel bitmap into a one-byte-per-pixel texture.
unsigned char *buffer_row = bitmap.buffer;
for (int yi = 0; yi < bitmap.rows; yi++) {
unsigned char *texture_row = glyph->get_row(yi);
nassertv(texture_row != (unsigned char *)NULL);
int bit = 0x80;
unsigned char *b = buffer_row;
for (int xi = 0; xi < bitmap.width; xi++) {
if (*b & bit) {
texture_row[xi] = 0xff;
} else {
texture_row[xi] = 0x00;
}
bit >>= 1;
if (bit == 0) {
++b;
bit = 0x80;
}
}
buffer_row += bitmap.pitch;
}
} else if (bitmap.pixel_mode == ft_pixel_mode_grays) {
// Here we must expand a grayscale pixmap with n levels of gray
// into our 256-level texture.
unsigned char *buffer_row = bitmap.buffer;
for (int yi = 0; yi < bitmap.rows; yi++) {
unsigned char *texture_row = glyph->get_row(yi);
nassertv(texture_row != (unsigned char *)NULL);
for (int xi = 0; xi < bitmap.width; xi++) {
texture_row[xi] = (int)(buffer_row[xi] * 255) / (bitmap.num_grays - 1);
}
buffer_row += bitmap.pitch;
}
} else {
text_cat.error()
<< "Unexpected pixel mode in bitmap: " << (int)bitmap.pixel_mode << "\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::copy_bitmap_to_pnmimage
// Access: Private
// Description: Copies a bitmap as rendered by FreeType into a
// PNMImage, so it can be rescaled.
////////////////////////////////////////////////////////////////////
void DynamicTextFont::
copy_bitmap_to_pnmimage(const FT_Bitmap &bitmap, PNMImage &image) {
if (bitmap.pixel_mode == ft_pixel_mode_grays &&
bitmap.num_grays == (int)image.get_maxval() + 1) {
// This is the easy case: we can copy the rendered glyph
// directly into our image, one pixel at a time.
unsigned char *buffer_row = bitmap.buffer;
for (int yi = 0; yi < bitmap.rows; yi++) {
for (int xi = 0; xi < bitmap.width; xi++) {
image.set_gray_val(xi, yi, buffer_row[xi]);
}
buffer_row += bitmap.pitch;
}
} else if (bitmap.pixel_mode == ft_pixel_mode_mono) {
// This is a little bit more work: we have to expand the
// one-bit-per-pixel bitmap into a one-byte-per-pixel image.
unsigned char *buffer_row = bitmap.buffer;
for (int yi = 0; yi < bitmap.rows; yi++) {
xelval maxval = image.get_maxval();
int bit = 0x80;
unsigned char *b = buffer_row;
for (int xi = 0; xi < bitmap.width; xi++) {
if (*b & bit) {
image.set_gray_val(xi, yi, maxval);
} else {
image.set_gray_val(xi, yi, 0);
}
bit >>= 1;
if (bit == 0) {
++b;
bit = 0x80;
}
}
buffer_row += bitmap.pitch;
}
} else if (bitmap.pixel_mode == ft_pixel_mode_grays) {
// Here we must expand a grayscale pixmap with n levels of gray
// into our 256-level texture.
unsigned char *buffer_row = bitmap.buffer;
for (int yi = 0; yi < bitmap.rows; yi++) {
for (int xi = 0; xi < bitmap.width; xi++) {
image.set_gray(xi, yi, (float)buffer_row[xi] / (bitmap.num_grays - 1));
}
buffer_row += bitmap.pitch;
}
} else {
text_cat.error()
<< "Unexpected pixel mode in bitmap: " << (int)bitmap.pixel_mode << "\n";
}
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::copy_pnmimage_to_texture
// Access: Private
// Description: Copies a bitmap stored in a PNMImage into
// the texture memory image for the indicated glyph.
////////////////////////////////////////////////////////////////////
void DynamicTextFont::
copy_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph) {
for (int yi = 0; yi < image.get_y_size(); yi++) {
unsigned char *texture_row = glyph->get_row(yi);
nassertv(texture_row != (unsigned char *)NULL);
for (int xi = 0; xi < image.get_x_size(); xi++) {
texture_row[xi] = image.get_gray_val(xi, yi);
}
}
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::slot_glyph
// Access: Private

View File

@ -53,6 +53,9 @@ PUBLISHED:
INLINE bool set_pixels_per_unit(float pixels_per_unit);
INLINE float get_pixels_per_unit() const;
INLINE bool set_scale_factor(float scale_factor);
INLINE float get_scale_factor() const;
INLINE void set_small_caps(bool small_caps);
INLINE bool get_small_caps() const;
INLINE void set_small_caps_scale(float small_caps_scale);
@ -94,12 +97,17 @@ private:
void update_filters();
bool reset_scale();
DynamicTextGlyph *make_glyph(int glyph_index);
void copy_bitmap_to_texture(const FT_Bitmap &bitmap, DynamicTextGlyph *glyph);
void copy_bitmap_to_pnmimage(const FT_Bitmap &bitmap, PNMImage &image);
void copy_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph);
DynamicTextGlyph *slot_glyph(int x_size, int y_size);
static void initialize_ft_library();
float _point_size;
float _pixels_per_unit;
float _tex_pixels_per_unit;
float _scale_factor;
float _font_pixels_per_unit;
bool _small_caps;
float _small_caps_scale;
int _texture_margin;

View File

@ -108,18 +108,21 @@ erase() {
// the pen should be advanced after drawing this glyph.
////////////////////////////////////////////////////////////////////
void DynamicTextGlyph::
make_geom(int bitmap_top, int bitmap_left,
float advance, float poly_margin, float pixels_per_unit) {
make_geom(int bitmap_top, int bitmap_left, float advance, float poly_margin,
float font_pixels_per_unit, float tex_pixels_per_unit) {
nassertv(_page != (DynamicTextPage *)NULL);
// This function should not be called twice.
nassertv(_geom_count == 0);
// Determine the corners of the rectangle in geometric units.
float top = (bitmap_top + poly_margin) / pixels_per_unit;
float left = (bitmap_left - poly_margin) / pixels_per_unit;
float bottom = (bitmap_top - _y_size - poly_margin) / pixels_per_unit;
float right = (bitmap_left + _x_size + poly_margin) / pixels_per_unit;
float tex_poly_margin = poly_margin / tex_pixels_per_unit;
float origin_y = bitmap_top / font_pixels_per_unit;
float origin_x = bitmap_left / font_pixels_per_unit;
float top = origin_y + tex_poly_margin;
float left = origin_x - tex_poly_margin;
float bottom = origin_y - _y_size / tex_pixels_per_unit - tex_poly_margin;
float right = origin_x + _x_size / tex_pixels_per_unit + tex_poly_margin;
// And the corresponding corners in UV units.
float uv_top = 1.0f - (float)(_y - poly_margin) / _page->get_y_size();
@ -162,7 +165,7 @@ make_geom(int bitmap_top, int bitmap_left,
_state = RenderState::make(TextureAttrib::make(_page),
TransparencyAttrib::make(TransparencyAttrib::M_alpha));
_advance = advance / pixels_per_unit;
_advance = advance / font_pixels_per_unit;
}

View File

@ -51,7 +51,7 @@ public:
unsigned char *get_row(int y);
void erase();
void make_geom(int top, int left, float advance, float poly_margin,
float pixels_per_unit);
float font_pixels_per_unit, float tex_pixels_per_unit);
DynamicTextPage *_page;
int _geom_count;