DynamicTextFont::set_outline()

This commit is contained in:
David Rose 2009-01-17 02:47:16 +00:00
parent 31091e8974
commit 89aeadbc72
9 changed files with 520 additions and 36 deletions

View File

@ -405,6 +405,164 @@ get_winding_order() const {
return _winding_order;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::set_fg
// Access: Published
// Description: Changes the color of the foreground pixels of the
// font as they are rendered into the font texture. The
// default is (1, 1, 1, 1), or opaque white, which
// allows text created with the font to be colored
// individually. Normally, you would not change this
// unless you really need a particular color effect to
// appear in the font itself.
//
// This should only be called before any characters have
// been requested out of the font, or immediately after
// calling clear().
////////////////////////////////////////////////////////////////////
INLINE void DynamicTextFont::
set_fg(const Colorf &fg) {
// If this assertion fails, you didn't call clear() first. RTFM.
nassertv(get_num_pages() == 0);
_fg = fg;
determine_tex_format();
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_fg
// Access: Published
// Description: Returns the color of the foreground pixels of the
// font as they are rendered into the font texture.
// See set_fg().
////////////////////////////////////////////////////////////////////
INLINE const Colorf &DynamicTextFont::
get_fg() const {
return _fg;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::set_bg
// Access: Published
// Description: Changes the color of the background pixels of the
// font as they are rendered into the font texture. The
// default is (1, 1, 1, 0), or transparent white, which
// allows text created with the font to be colored
// individually. (Note that it should not generally be
// (0, 0, 0, 0), which would tend to bleed into the
// foreground color, unless you have also specified a
// outline color of (0, 0, 0, 1)) .
//
// Normally, you would not change this unless you really
// need a particular color effect to appear in the font
// itself.
//
// This should only be called before any characters have
// been requested out of the font, or immediately after
// calling clear().
////////////////////////////////////////////////////////////////////
INLINE void DynamicTextFont::
set_bg(const Colorf &bg) {
// If this assertion fails, you didn't call clear() first. RTFM.
nassertv(get_num_pages() == 0);
_bg = bg;
determine_tex_format();
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_bg
// Access: Published
// Description: Returns the color of the background pixels of the
// font as they are rendered into the font texture.
// See set_bg().
////////////////////////////////////////////////////////////////////
INLINE const Colorf &DynamicTextFont::
get_bg() const {
return _bg;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::set_outline
// Access: Published
// Description: Sets up the font to have an outline around each font
// letter. This is achieved via a Gaussian post-process
// as each letter is generated; there is some runtime
// cost for this effect, but it is minimal as each
// letter is normally generated only once and then
// cached.
//
// The color is the desired color of the outline, width
// is the number of pixels beyond the letter that the
// outline extends, and feather is a number in the range
// 0.0 .. 1.0 that controls the softness of the outline.
// Set the width to 0.0 to disable the outline.
//
// This should only be called before any characters have
// been requested out of the font, or immediately after
// calling clear().
////////////////////////////////////////////////////////////////////
INLINE void DynamicTextFont::
set_outline(const Colorf &outline_color, float outline_width,
float outline_feather) {
// If this assertion fails, you didn't call clear() first. RTFM.
nassertv(get_num_pages() == 0);
_outline_color = outline_color;
_outline_width = outline_width;
_outline_feather = outline_feather;
determine_tex_format();
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_outline_color
// Access: Published
// Description: Returns the color of the outline pixels of the
// font as they are rendered into the font texture.
// See set_outline().
////////////////////////////////////////////////////////////////////
INLINE const Colorf &DynamicTextFont::
get_outline_color() const {
return _outline_color;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_outline_width
// Access: Published
// Description: Returns the width of the outline pixels of the
// font, as the number of pixels beyond each letter.
// See set_outline().
////////////////////////////////////////////////////////////////////
INLINE float DynamicTextFont::
get_outline_width() const {
return _outline_width;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_outline_feather
// Access: Published
// Description: Returns the softness of the outline pixels of the
// font, as a value in the range 0.0 to 1.0.
// See set_outline().
////////////////////////////////////////////////////////////////////
INLINE float DynamicTextFont::
get_outline_feather() const {
return _outline_feather;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_tex_format
// Access: Published
// Description: Returns the texture format used to render the
// individual pages. This is set automatically
// according to the colors selected.
////////////////////////////////////////////////////////////////////
INLINE Texture::Format DynamicTextFont::
get_tex_format() const {
return _tex_format;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::ContourPoint::Constructor
// Access: Public

View File

@ -63,6 +63,15 @@ DynamicTextFont(const Filename &font_filename, int face_index) {
TextFont::set_name(FreetypeFont::get_name());
TextFont::_line_height = FreetypeFont::get_line_height();
TextFont::_space_advance = FreetypeFont::get_space_advance();
_fg.set(1.0f, 1.0f, 1.0f, 1.0f);
_bg.set(1.0f, 1.0f, 1.0f, 0.0f);
_outline_color.set(1.0f, 1.0f, 1.0f, 0.0f);
_outline_width = 0.0f;
_outline_feather = 0.0f;
_has_outline = false;
_tex_format = Texture::F_alpha;
_needs_image_processing = false;
}
////////////////////////////////////////////////////////////////////
@ -79,6 +88,15 @@ DynamicTextFont(const char *font_data, int data_length, int face_index) {
TextFont::set_name(FreetypeFont::get_name());
TextFont::_line_height = FreetypeFont::_line_height;
TextFont::_space_advance = FreetypeFont::_space_advance;
_fg.set(1.0f, 1.0f, 1.0f, 1.0f);
_bg.set(1.0f, 1.0f, 1.0f, 0.0f);
_outline_color.set(1.0f, 1.0f, 1.0f, 0.0f);
_outline_width = 0.0f;
_outline_feather = 0.0f;
_has_outline = false;
_tex_format = Texture::F_alpha;
_needs_image_processing = false;
}
////////////////////////////////////////////////////////////////////
@ -151,7 +169,7 @@ garbage_collect() {
Pages::iterator pi;
for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
DynamicTextPage *page = (*pi);
page->garbage_collect();
page->garbage_collect(this);
}
return removed_count;
@ -303,6 +321,75 @@ update_filters() {
}
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::determine_tex_format
// Access: Private
// Description: Examines the _fg, _bg, and _outline colors to
// determine the appropriate format for the font pages,
// including the outline properties.
////////////////////////////////////////////////////////////////////
void DynamicTextFont::
determine_tex_format() {
nassertv(get_num_pages() == 0);
_has_outline = (_outline_color != _bg && _outline_width > 0.0f);
_needs_image_processing = true;
bool needs_color = false;
bool needs_grayscale = false;
bool needs_alpha = false;
if (_fg[1] != _fg[0] || _fg[2] != _fg[0] ||
_bg[1] != _bg[0] || _bg[2] != _bg[0] ||
(_has_outline && (_outline_color[1] != _outline_color[0] || _outline_color[2] != _outline_color[0]))) {
// At least one of fg, bg, or outline contains a color, not just a
// grayscale value.
needs_color = true;
} else if (_fg[0] != 1.0f || _fg[1] != 1.0f || _fg[2] != 1.0f ||
_bg[0] != 1.0f || _bg[1] != 1.0f || _bg[2] != 1.0f ||
(_has_outline && (_outline_color[0] != 1.0f || _outline_color[1] != 1.0f || _outline_color[2] != 1.0f))) {
// fg, bg, and outline contain non-white grayscale values.
needs_grayscale = true;
}
if (_fg[3] != 1.0f || _bg[3] != 1.0f ||
(_has_outline && (_outline_color[3] != 1.0f))) {
// fg, bg, and outline contain non-opaque alpha values.
needs_alpha = true;
}
if (needs_color) {
if (needs_alpha) {
_tex_format = Texture::F_rgba;
} else {
_tex_format = Texture::F_rgb;
}
} else if (needs_grayscale) {
if (needs_alpha) {
_tex_format = Texture::F_luminance_alpha;
} else {
_tex_format = Texture::F_luminance;
}
} else {
if (needs_alpha) {
_tex_format = Texture::F_alpha;
if (!_has_outline &&
_fg == Colorf(1.0f, 1.0f, 1.0f, 1.0f) &&
_bg == Colorf(1.0f, 1.0f, 1.0f, 0.0f)) {
// This is the standard font color. It can be copied directly
// without any need for special processing.
_needs_image_processing = false;
}
} else {
// This won't be a very interesting font.
_tex_format = Texture::F_luminance;
}
}
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::make_glyph
// Access: Private
@ -432,33 +519,53 @@ make_glyph(int character, int glyph_index) {
float tex_x_size = bitmap.width;
float tex_y_size = bitmap.rows;
if (_tex_pixels_per_unit == _font_pixels_per_unit) {
int outline = 0;
if (_tex_pixels_per_unit == _font_pixels_per_unit &&
!_needs_image_processing) {
// 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.
// or any other processing before it goes to the texture, we can
// just copy it directly into the texture.
glyph = slot_glyph(character, bitmap.width, bitmap.rows);
copy_bitmap_to_texture(bitmap, glyph);
} else {
// Otherwise, we need to copy to a PNMImage first, so we can
// scale it; and then copy it to the texture from there.
// scale it and/or process it; and then copy it to the texture
// from there.
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);
int bmp_x_size = (int)(int_x_size * _scale_factor + 0.5f);
int bmp_y_size = (int)(int_y_size * _scale_factor + 0.5f);
glyph = slot_glyph(character, int_x_size, int_y_size);
PNMImage image(bmp_x_size, bmp_y_size, PNMImage::CT_grayscale);
copy_bitmap_to_pnmimage(bitmap, image);
PNMImage reduced(int_x_size, int_y_size, PNMImage::CT_grayscale);
reduced.quick_filter_from(image);
copy_pnmimage_to_texture(reduced, glyph);
outline = (int)ceil(_outline_width);
int_x_size += outline * 2;
int_y_size += outline * 2;
tex_x_size += outline * 2;
tex_y_size += outline * 2;
glyph = slot_glyph(character, int_x_size, int_y_size);
if (outline != 0) {
// Pad the glyph image to make room for the outline.
PNMImage padded(int_x_size, int_y_size, PNMImage::CT_grayscale);
padded.copy_sub_image(reduced, outline, outline);
copy_pnmimage_to_texture(padded, glyph);
} else {
copy_pnmimage_to_texture(reduced, glyph);
}
}
glyph->make_geom(slot->bitmap_top, slot->bitmap_left,
glyph->make_geom(slot->bitmap_top + outline * _scale_factor,
slot->bitmap_left - outline * _scale_factor,
advance, _poly_margin,
tex_x_size, tex_y_size,
_font_pixels_per_unit, _tex_pixels_per_unit);
@ -541,11 +648,125 @@ copy_bitmap_to_texture(const FT_Bitmap &bitmap, DynamicTextGlyph *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);
if (!_needs_image_processing) {
// Copy the image directly into the alpha component of the
// texture.
nassertv(glyph->_page->get_num_components() == 1);
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);
}
}
} else {
if (_has_outline) {
// Gaussian blur the glyph to generate an outline.
PNMImage outline(image.get_x_size(), image.get_y_size(), PNMImage::CT_grayscale);
outline.gaussian_filter_from(_outline_width, image);
// Filter the resulting outline to make a harder edge.
for (int yi = 0; yi < outline.get_y_size(); yi++) {
for (int xi = 0; xi < outline.get_x_size(); xi++) {
float v = outline.get_gray(xi, yi);
if (v == 0.0f) {
// Do nothing.
} else if (v >= _outline_feather) {
// Clamp to 1.
outline.set_gray(xi, yi, 1.0);
} else {
// Linearly scale the range 0 .. _outline_feather onto 0 .. 1.
outline.set_gray(xi, yi, v / _outline_feather);
}
}
}
// Now blend that into the texture.
blend_pnmimage_to_texture(outline, glyph, _outline_color);
}
// Colorize the image as we copy it in. This assumes the previous
// color at this part of the texture was already initialized to
// the background color.
blend_pnmimage_to_texture(image, glyph, _fg);
}
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::blend_pnmimage_to_texture
// Access: Private
// Description: Blends the PNMImage into the appropriate part of the
// texture, where 0.0 in the image indicates the color
// remains the same, and 1.0 indicates the color is
// assigned the indicated foreground color.
////////////////////////////////////////////////////////////////////
void DynamicTextFont::
blend_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph,
const Colorf &fg) {
Colorf fgv = fg * 255.0f;
int num_components = glyph->_page->get_num_components();
if (num_components == 1) {
// Luminance or alpha.
int ci = 3;
if (glyph->_page->get_format() != Texture::F_alpha) {
ci = 0;
}
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++) {
unsigned char *tr = texture_row + xi;
float t = (float)image.get_gray(xi, yi);
tr[0] = (unsigned char)(tr[0] + t * (fgv[ci] - tr[0]));
}
}
} else if (num_components == 2) {
// Luminance + alpha.
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++) {
unsigned char *tr = texture_row + xi * 2;
float t = (float)image.get_gray(xi, yi);
tr[0] = (unsigned char)(tr[0] + t * (fgv[0] - tr[0]));
tr[1] = (unsigned char)(tr[1] + t * (fgv[3] - tr[1]));
}
}
} else if (num_components == 3) {
// RGB.
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++) {
unsigned char *tr = texture_row + xi * 3;
float t = (float)image.get_gray(xi, yi);
tr[0] = (unsigned char)(tr[0] + t * (fgv[2] - tr[0]));
tr[1] = (unsigned char)(tr[1] + t * (fgv[1] - tr[1]));
tr[2] = (unsigned char)(tr[2] + t * (fgv[0] - tr[2]));
}
}
} else { // (num_components == 4)
// RGBA.
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++) {
unsigned char *tr = texture_row + xi * 4;
float t = (float)image.get_gray(xi, yi);
tr[0] = (unsigned char)(tr[0] + t * (fgv[2] - tr[0]));
tr[1] = (unsigned char)(tr[1] + t * (fgv[1] - tr[1]));
tr[2] = (unsigned char)(tr[2] + t * (fgv[0] - tr[2]));
tr[3] = (unsigned char)(tr[3] + t * (fgv[3] - tr[3]));
}
}
}
}

View File

@ -86,6 +86,17 @@ PUBLISHED:
INLINE void set_winding_order(WindingOrder winding_order);
INLINE WindingOrder get_winding_order() const;
INLINE void set_fg(const Colorf &fg);
INLINE const Colorf &get_fg() const;
INLINE void set_bg(const Colorf &bg);
INLINE const Colorf &get_bg() const;
INLINE void set_outline(const Colorf &outline_color, float outline_width,
float outline_feather);
INLINE const Colorf &get_outline_color() const;
INLINE float get_outline_width() const;
INLINE float get_outline_feather() const;
INLINE Texture::Format get_tex_format() const;
int get_num_pages() const;
DynamicTextPage *get_page(int n) const;
MAKE_SEQ(get_pages, get_num_pages, get_page);
@ -101,9 +112,12 @@ public:
private:
void initialize();
void update_filters();
void determine_tex_format();
DynamicTextGlyph *make_glyph(int character, int glyph_index);
void copy_bitmap_to_texture(const FT_Bitmap &bitmap, DynamicTextGlyph *glyph);
void copy_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph);
void blend_pnmimage_to_texture(const PNMImage &image, DynamicTextGlyph *glyph,
const Colorf &fg);
DynamicTextGlyph *slot_glyph(int character, int x_size, int y_size);
void render_wireframe_contours(DynamicTextGlyph *glyph);
@ -129,6 +143,13 @@ private:
RenderMode _render_mode;
WindingOrder _winding_order;
Colorf _fg, _bg, _outline_color;
float _outline_width;
float _outline_feather;
bool _has_outline;
Texture::Format _tex_format;
bool _needs_image_processing;
typedef pvector< PT(DynamicTextPage) > Pages;
Pages _pages;
int _preferred_page;

View File

@ -59,7 +59,9 @@ get_row(int y) {
y = _page->get_y_size() - 1 - y;
int offset = (y * _page->get_x_size()) + x;
return _page->modify_ram_image() + offset;
int pixel_width = _page->get_num_components() * _page->get_component_width();
return _page->modify_ram_image() + offset * pixel_width;
}
////////////////////////////////////////////////////////////////////
@ -68,18 +70,14 @@ get_row(int y) {
// Description: Erases the glyph from the texture map.
////////////////////////////////////////////////////////////////////
void DynamicTextGlyph::
erase() {
erase(DynamicTextFont *font) {
nassertv(_page != (DynamicTextPage *)NULL);
nassertv(_page->has_ram_image());
int ysizetop = _page->get_y_size() - 1;
int width = _page->get_x_size();
unsigned char *buffer = _page->modify_ram_image();
for (int y = _y; y < _y + _y_size; y++) {
int offset = (ysizetop - y) * width + _x;
memset(buffer + offset, 0, _x_size);
}
_page->fill_region(_x, _y, _x_size, _y_size, font->get_bg());
}
////////////////////////////////////////////////////////////////////
@ -121,7 +119,7 @@ make_geom(int bitmap_top, int bitmap_left, float advance, float poly_margin,
float uv_bottom = 1.0f - ((float)(_y + poly_margin + tex_y_size) + 0.5f) / _page->get_y_size();
float uv_right = ((float)(_x + poly_margin + tex_x_size) + 0.5f) / _page->get_x_size();
// Create a corresponding triangle pair. We use a pair of indexed
// triangles rther than a single triangle strip, to avoid the bad
// triangles rather than a single triangle strip, to avoid the bad
// vertex duplication behavior with lots of two-triangle strips.
PT(GeomVertexData) vdata = new GeomVertexData
(string(), GeomVertexFormat::get_v3t2(),

View File

@ -22,6 +22,7 @@
#include "textGlyph.h"
class DynamicTextPage;
class DynamicTextFont;
////////////////////////////////////////////////////////////////////
// Class : DynamicTextGlyph
@ -45,7 +46,7 @@ public:
INLINE bool intersects(int x, int y, int x_size, int y_size) const;
unsigned char *get_row(int y);
void erase();
void erase(DynamicTextFont *font);
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);

View File

@ -40,7 +40,7 @@ DynamicTextPage(DynamicTextFont *font, int page_number) :
_x_size = _font->get_page_x_size();
_y_size = _font->get_page_y_size();
setup_2d_texture(_x_size, _y_size, T_unsigned_byte, F_alpha);
setup_2d_texture(_x_size, _y_size, T_unsigned_byte, font->get_tex_format());
// Assign a name to the Texture.
ostringstream strm;
@ -59,12 +59,15 @@ DynamicTextPage(DynamicTextFont *font, int page_number) :
// at the edges at all.
set_wrap_u(text_wrap_mode);
set_wrap_v(text_wrap_mode);
set_border_color(Colorf(0.0f, 0.0f, 0.0f, 0.0f));
set_border_color(font->get_bg());
// Fill the page with the font's background color.
fill_region(0, 0, _x_size, _y_size, font->get_bg());
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextPage::slot_glyph
// Access: Publiic
// Access: Public
// Description: Finds space within the page for a glyph of the
// indicated size. If space is found, creates a new
// glyph object and returns it; otherwise, returns NULL.
@ -85,6 +88,89 @@ slot_glyph(int character, int x_size, int y_size, int margin) {
return glyph;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextPage::fill_region
// Access: Private
// Description: Fills a rectangular region of the texture with the
// indicated color.
////////////////////////////////////////////////////////////////////
void DynamicTextPage::
fill_region(int x, int y, int x_size, int y_size, const Colorf &color) {
nassertv(x >= 0 && x < _x_size && y >= 0 && y < _y_size);
int num_components = get_num_components();
if (num_components == 1) {
// Luminance or alpha.
int ci = 3;
if (get_format() != Texture::F_alpha) {
ci = 0;
}
unsigned char v = (unsigned char)(color[ci] * 255.0f);
unsigned char *image = modify_ram_image();
for (int yi = y; yi < y + y_size; yi++) {
unsigned char *row = image + yi * _x_size;
memset(row + x, v, x_size);
}
} else if (num_components == 2) {
// Luminance + alpha.
union {
unsigned char p[2];
PN_uint16 v;
} v;
v.p[0] = (unsigned char)(color[0] * 255.0f);
v.p[1] = (unsigned char)(color[3] * 255.0f);
PN_uint16 *image = (PN_uint16 *)modify_ram_image().p();
for (int yi = y; yi < y + y_size; yi++) {
PN_uint16 *row = image + yi * _x_size ;
for (int xi = x; xi < x + x_size; xi++) {
row[xi] = v.v;
}
}
} else if (num_components == 3) {
// RGB.
unsigned char p0 = (unsigned char)(color[2] * 255.0f);
unsigned char p1 = (unsigned char)(color[1] * 255.0f);
unsigned char p2 = (unsigned char)(color[0] * 255.0f);
unsigned char *image = modify_ram_image();
for (int yi = y; yi < y + y_size; yi++) {
unsigned char *row = image + yi * _x_size * 3;
for (int xi = x; xi < x + x_size; xi++) {
row[xi * 3] = p0;
row[xi * 3 + 1] = p1;
row[xi * 3 + 2] = p2;
}
}
} else { // (num_components == 4)
// RGBA.
union {
unsigned char p[4];
PN_uint32 v;
} v;
v.p[0] = (unsigned char)(color[2] * 255.0f);
v.p[1] = (unsigned char)(color[1] * 255.0f);
v.p[2] = (unsigned char)(color[0] * 255.0f);
v.p[3] = (unsigned char)(color[3] * 255.0f);
PN_uint32 *image = (PN_uint32 *)modify_ram_image().p();
for (int yi = y; yi < y + y_size; yi++) {
PN_uint32 *row = image + yi * _x_size;
for (int xi = x; xi < x + x_size; xi++) {
row[xi] = v.v;
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextPage::garbage_collect
// Access: Private
@ -95,7 +181,7 @@ slot_glyph(int character, int x_size, int y_size, int margin) {
// font's index first.
////////////////////////////////////////////////////////////////////
int DynamicTextPage::
garbage_collect() {
garbage_collect(DynamicTextFont *font) {
int removed_count = 0;
Glyphs new_glyphs;
@ -108,7 +194,7 @@ garbage_collect() {
} else {
// Drop this one.
removed_count++;
glyph->erase();
glyph->erase(font);
}
}

View File

@ -43,13 +43,14 @@ public:
INLINE int get_x_size() const;
INLINE int get_y_size() const;
void fill_region(int x, int y, int x_size, int y_size, const Colorf &color);
PUBLISHED:
INLINE bool is_empty() const;
private:
int garbage_collect();
int garbage_collect(DynamicTextFont *font);
private:
bool find_hole(int &x, int &y, int x_size, int y_size) const;
DynamicTextGlyph *find_overlap(int x, int y, int x_size, int y_size) const;

View File

@ -589,11 +589,9 @@ assemble_text() {
}
if (properties->has_shadow()) {
if (properties->has_shadow_color()) {
shadow_state = shadow_state->add_attrib(ColorAttrib::make_flat(properties->get_shadow_color()));
if (properties->get_shadow_color()[3] != 1.0) {
shadow_state = shadow_state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
}
shadow_state = shadow_state->add_attrib(ColorAttrib::make_flat(properties->get_shadow_color()));
if (properties->get_shadow_color()[3] != 1.0) {
shadow_state = shadow_state->add_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
}
if (properties->has_bin()) {

View File

@ -44,7 +44,7 @@ TextProperties() {
_wordwrap_width = 0.0f;
_preserve_trailing_whitespace = false;
_text_color.set(1.0f, 1.0f, 1.0f, 1.0f);
_shadow_color.set(1.0f, 1.0f, 1.0f, 1.0f);
_shadow_color.set(0.0f, 0.0f, 0.0f, 1.0f);
_shadow_offset.set(0.0f, 0.0f);
_draw_order = 1;
_tab_width = text_tab_width;