diff --git a/panda/src/text/dynamicTextFont.I b/panda/src/text/dynamicTextFont.I index d1ee1772e7..cb65b07ff6 100644 --- a/panda/src/text/dynamicTextFont.I +++ b/panda/src/text/dynamicTextFont.I @@ -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 diff --git a/panda/src/text/dynamicTextFont.cxx b/panda/src/text/dynamicTextFont.cxx index 81ca7dcc4d..f3ef71684a 100644 --- a/panda/src/text/dynamicTextFont.cxx +++ b/panda/src/text/dynamicTextFont.cxx @@ -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])); + } } } } diff --git a/panda/src/text/dynamicTextFont.h b/panda/src/text/dynamicTextFont.h index af8f7db4b9..33028a78f0 100644 --- a/panda/src/text/dynamicTextFont.h +++ b/panda/src/text/dynamicTextFont.h @@ -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; diff --git a/panda/src/text/dynamicTextGlyph.cxx b/panda/src/text/dynamicTextGlyph.cxx index 02cd951d10..f1e36410e4 100644 --- a/panda/src/text/dynamicTextGlyph.cxx +++ b/panda/src/text/dynamicTextGlyph.cxx @@ -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(), diff --git a/panda/src/text/dynamicTextGlyph.h b/panda/src/text/dynamicTextGlyph.h index 99f06131a7..5470b7143e 100644 --- a/panda/src/text/dynamicTextGlyph.h +++ b/panda/src/text/dynamicTextGlyph.h @@ -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); diff --git a/panda/src/text/dynamicTextPage.cxx b/panda/src/text/dynamicTextPage.cxx index 549ada494e..eee4609b85 100644 --- a/panda/src/text/dynamicTextPage.cxx +++ b/panda/src/text/dynamicTextPage.cxx @@ -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); } } diff --git a/panda/src/text/dynamicTextPage.h b/panda/src/text/dynamicTextPage.h index 7d4424a916..efa89b537c 100644 --- a/panda/src/text/dynamicTextPage.h +++ b/panda/src/text/dynamicTextPage.h @@ -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; diff --git a/panda/src/text/textAssembler.cxx b/panda/src/text/textAssembler.cxx index 8fe727747d..7426510fda 100644 --- a/panda/src/text/textAssembler.cxx +++ b/panda/src/text/textAssembler.cxx @@ -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()) { diff --git a/panda/src/text/textProperties.cxx b/panda/src/text/textProperties.cxx index f1a050e084..78ad76ec75 100644 --- a/panda/src/text/textProperties.cxx +++ b/panda/src/text/textProperties.cxx @@ -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;