initial pass at dynamic text

This commit is contained in:
David Rose 2002-02-09 21:56:24 +00:00
parent 68aa6f0e52
commit 9292457ce5
20 changed files with 1054 additions and 38 deletions

View File

@ -2,6 +2,8 @@
dtoolutil:c dtoolbase:c dtool:m
#begin lib_target
#define USE_FREETYPE yes
#define TARGET text
#define LOCAL_LIBS \
cull putil gobj sgattrib graph sgraph linmath sgraphutil pnmimage gsgbase \
@ -11,16 +13,27 @@
#define SOURCES \
config_text.h \
dynamicTextFont.I dynamicTextFont.h \
dynamicTextGlyph.I dynamicTextGlyph.h \
dynamicTextPage.I dynamicTextPage.h \
staticTextFont.I staticTextFont.h \
textFont.I textFont.h \
textGlyph.I textGlyph.h \
textNode.I textNode.h textNode.cxx
#define INCLUDED_SOURCES \
config_text.cxx staticTextFont.cxx textFont.cxx textGlyph.cxx
config_text.cxx \
dynamicTextFont.cxx \
dynamicTextGlyph.cxx \
dynamicTextPage.cxx \
staticTextFont.cxx \
textFont.cxx textGlyph.cxx
#define INSTALL_HEADERS \
config_text.h \
dynamicTextFont.I dynamicTextFont.h \
dynamicTextGlyph.I dynamicTextGlyph.h \
dynamicTextPage.I dynamicTextPage.h \
staticTextFont.I staticTextFont.h \
textFont.I textFont.h \
textGlyph.I textGlyph.h \

View File

@ -18,6 +18,8 @@
#include "config_text.h"
#include "staticTextFont.h"
#include "dynamicTextFont.h"
#include "dynamicTextPage.h"
#include "textFont.h"
#include "textNode.h"
@ -28,6 +30,8 @@ NotifyCategoryDef(text, "");
ConfigureFn(config_text) {
StaticTextFont::init_type();
DynamicTextFont::init_type();
DynamicTextPage::init_type();
TextFont::init_type();
TextNode::init_type();
}

View File

@ -0,0 +1,76 @@
// Filename: dynamicTextFont.I
// Created by: drose (08Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::set_margin
// Access: Published
// Description: Sets the number of pixels of padding that is added
// around the border of each glyph before adding it to
// the texture map. This reduces the bleed in from
// neighboring glyphs in the texture map.
////////////////////////////////////////////////////////////////////
INLINE void DynamicTextFont::
set_margin(int margin) {
_margin = margin;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_margin
// Access: Published
// Description: Returns the number of pixels of padding that is added
// around the border of each glyph. See set_margin().
////////////////////////////////////////////////////////////////////
INLINE int DynamicTextFont::
get_margin() const {
return _margin;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::set_page_size
// Access: Published
// Description: Sets the x, y size of the textures that are created
// for the DynamicTextFont.
////////////////////////////////////////////////////////////////////
INLINE void DynamicTextFont::
set_page_size(int x_size, int y_size) {
_page_x_size = x_size;
_page_y_size = y_size;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_page_x_size
// Access: Published
// Description: Returns the x size of the textures that are created
// for the DynamicTextFont. See set_page_size().
////////////////////////////////////////////////////////////////////
INLINE int DynamicTextFont::
get_page_x_size() const {
return _page_x_size;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_page_y_size
// Access: Published
// Description: Returns the y size of the textures that are created
// for the DynamicTextFont. See set_page_size().
////////////////////////////////////////////////////////////////////
INLINE int DynamicTextFont::
get_page_y_size() const {
return _page_y_size;
}

View File

@ -0,0 +1,284 @@
// Filename: dynamicTextFont.cxx
// Created by: drose (08Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "dynamicTextFont.h"
#ifdef HAVE_FREETYPE
#include "config_text.h"
#include "config_util.h"
FT_Library DynamicTextFont::_ft_library;
bool DynamicTextFont::_ft_initialized = false;
bool DynamicTextFont::_ft_ok = false;
TypeHandle DynamicTextFont::_type_handle;
// This constant determines how big a particular point size font
// appears. By convention, 10 points is 1 foot high.
static const float points_per_unit = 10.0f;
// A universal convention.
static const float points_per_inch = 72.0f;
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::Constructor
// Access: Published
// Description: The constructor expects the name of some font file
// that FreeType can read, along with face_index,
// indicating which font within the file to load
// (usually 0), the point size of the font, and the
// resolution at which to generate the font.
//
// The choice of point size affects the apparent size of
// the generated characters (as well as the clarity),
// while the pixels_per_unit affects only the clarity.
////////////////////////////////////////////////////////////////////
DynamicTextFont::
DynamicTextFont(const Filename &font_filename, int face_index,
float point_size, float pixels_per_unit) {
_margin = 2;
_page_x_size = 256;
_page_y_size = 256;
_pixels_per_unit = pixels_per_unit;
float units_per_inch = (points_per_inch / points_per_unit);
int dpi = (int)(_pixels_per_unit * units_per_inch);
if (!_ft_initialized) {
initialize_ft_library();
}
if (!_ft_ok) {
text_cat.error()
<< "Unable to read font " << font_filename << ": FreeType library not available.\n";
return;
}
Filename path(font_filename);
if (!path.resolve_filename(get_model_path())) {
text_cat.error()
<< "Unable to find font file " << font_filename << "\n";
} else {
string os_specific = path.to_os_specific();
int error = FT_New_Face(_ft_library,
os_specific.c_str(),
face_index,
&_face);
if (error == FT_Err_Unknown_File_Format) {
text_cat.error()
<< "Unable to read font " << font_filename << ": unknown file format.\n";
} else if (error) {
text_cat.error()
<< "Unable to read font " << font_filename << ": invalid.\n";
} else {
string name = _face->family_name;
name += " ";
name += _face->style_name;
_is_valid = true;
set_name(name);
text_cat.info()
<< "Loaded font " << get_name() << "\n";
error = FT_Set_Char_Size(_face,
(int)(point_size * 64), (int)(point_size * 64),
dpi, dpi);
if (error) {
text_cat.warning()
<< "Unable to set point size of " << get_name()
<< " to " << point_size << " at " << dpi << " dots per inch.\n";
}
}
}
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_num_pages
// Access: Published
// Description: Returns the number of pages associated with the font.
// Initially, the font has zero pages; when the first
// piece of text is rendered with the font, it will add
// additional pages as needed. Each page is a Texture
// object that contains the images for each of the
// glyphs currently in use somewhere.
////////////////////////////////////////////////////////////////////
int DynamicTextFont::
get_num_pages() const {
return _pages.size();
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_page
// Access: Published
// Description: Returns the nth page associated with the font.
// Initially, the font has zero pages; when the first
// piece of text is rendered with the font, it will add
// additional pages as needed. Each page is a Texture
// object that contains the images for each of the
// glyphs currently in use somewhere.
////////////////////////////////////////////////////////////////////
DynamicTextPage *DynamicTextFont::
get_page(int n) const {
nassertr(n >= 0 && n < (int)_pages.size(), (DynamicTextPage *)NULL);
return _pages[n];
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::write
// Access: Published, Virtual
// Description:
////////////////////////////////////////////////////////////////////
void DynamicTextFont::
write(ostream &out, int indent_level) const {
indent(out, indent_level)
<< "DynamicTextFont " << get_name() << ".\n";
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::get_glyph
// Access: Public, Virtual
// Description: Returns the glyph associated with the given character
// code, or NULL if there is no such glyph.
////////////////////////////////////////////////////////////////////
const TextGlyph *DynamicTextFont::
get_glyph(int character) {
Cache::iterator ci = _cache.find(character);
if (ci != _cache.end()) {
return (*ci).second;
}
DynamicTextGlyph *glyph = make_glyph(character);
_cache.insert(Cache::value_type(character, glyph));
return glyph;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::make_glyph
// Access: Private
// Description: Slots a space in the texture map for the new
// character and renders the glyph, returning the
// newly-created TextGlyph object, or NULL if the
// glyph cannot be created for some reason.
////////////////////////////////////////////////////////////////////
DynamicTextGlyph *DynamicTextFont::
make_glyph(int character) {
int error = FT_Load_Char(_face, character, FT_LOAD_RENDER);
if (error) {
text_cat.error()
<< "Unable to render character " << character << "\n";
return (DynamicTextGlyph *)NULL;
}
FT_GlyphSlot slot = _face->glyph;
FT_Bitmap &bitmap = slot->bitmap;
if (bitmap.pixel_mode != ft_pixel_mode_grays) {
text_cat.error()
<< "Unexpected pixel mode in bitmap: " << (int)bitmap.pixel_mode << "\n";
return (DynamicTextGlyph *)NULL;
}
if (bitmap.num_grays != 256) {
// We expect 256 levels of grayscale to come back from FreeType,
// since that's what we asked for.
text_cat.warning()
<< "Expected 256 levels of gray, got " << bitmap.num_grays << "\n";
}
DynamicTextGlyph *glyph = slot_glyph(bitmap.width, bitmap.rows);
// Now copy the rendered glyph into the 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);
memcpy(texture_row, buffer_row, bitmap.width);
buffer_row += bitmap.pitch;
}
glyph->_page->mark_dirty(Texture::DF_image);
float advance = slot->advance.x / 64.0;
glyph->make_geom(slot->bitmap_top, slot->bitmap_left, advance,
_pixels_per_unit);
return glyph;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::slot_glyph
// Access: Private
// Description: Chooses a page that will have room for a glyph of the
// indicated size (after expanding the indicated size by
// the current margin). Returns the newly-allocated
// glyph on the chosen page; the glyph has not been
// filled in yet except with its size.
////////////////////////////////////////////////////////////////////
DynamicTextGlyph *DynamicTextFont::
slot_glyph(int x_size, int y_size) {
// Increase the indicated size by the current margin.
x_size += _margin * 2;
y_size += _margin * 2;
Pages::iterator pi;
for (pi = _pages.begin(); pi != _pages.end(); ++pi) {
DynamicTextPage *page = (*pi);
DynamicTextGlyph *glyph = page->slot_glyph(x_size, y_size, _margin);
if (glyph != (DynamicTextGlyph *)NULL) {
return glyph;
}
if (page->is_empty()) {
// If we couldn't even put in on an empty page, we're screwed.
text_cat.error()
<< "Glyph of size " << x_size << " by " << y_size
<< " won't fit on an empty page.\n";
return (DynamicTextGlyph *)NULL;
}
}
// We need to make a new page.
PT(DynamicTextPage) page = new DynamicTextPage(this);
_pages.push_back(page);
return page->slot_glyph(x_size, y_size, _margin);
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextFont::initialize_ft_library
// Access: Private, Static
// Description: Should be called exactly once to initialize the
// FreeType library.
////////////////////////////////////////////////////////////////////
void DynamicTextFont::
initialize_ft_library() {
if (!_ft_initialized) {
int error = FT_Init_FreeType(&_ft_library);
_ft_initialized = true;
if (error) {
text_cat.error()
<< "Unable to initialize FreeType; DynamicTextFonts will not load.\n";
} else {
_ft_ok = true;
}
}
}
#endif // HAVE_FREETYPE

View File

@ -0,0 +1,111 @@
// Filename: dynamicTextFont.h
// Created by: drose (08Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef DYNAMICTEXTFONT_H
#define DYNAMICTEXTFONT_H
#include "pandabase.h"
#ifdef HAVE_FREETYPE
#include "config_text.h"
#include "textFont.h"
#include "dynamicTextGlyph.h"
#include "dynamicTextPage.h"
#include "filename.h"
#include "pvector.h"
#include "pmap.h"
#include <ft2build.h>
#include FT_FREETYPE_H
////////////////////////////////////////////////////////////////////
// Class : DynamicTextFont
// Description : A DynamicTextFont is a special TextFont object that
// rasterizes its glyphs from a standard font file
// (e.g. a TTF file) on the fly. It requires the
// FreeType 2.0 library (or any higher,
// backward-compatible version).
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA DynamicTextFont : public TextFont {
PUBLISHED:
DynamicTextFont(const Filename &font_filename, int face_index,
float point_size, float pixels_per_unit);
INLINE void set_margin(int margin);
INLINE int get_margin() const;
INLINE void set_page_size(int x_size, int y_size);
INLINE int get_page_x_size() const;
INLINE int get_page_y_size() const;
int get_num_pages() const;
DynamicTextPage *get_page(int n) const;
virtual void write(ostream &out, int indent_level) const;
public:
virtual const TextGlyph *get_glyph(int character);
private:
DynamicTextGlyph *make_glyph(int character);
DynamicTextGlyph *slot_glyph(int x_size, int y_size);
static void initialize_ft_library();
int _margin;
int _page_x_size, _page_y_size;
float _pixels_per_unit;
typedef pvector< PT(DynamicTextPage) > Pages;
Pages _pages;
typedef pmap<int, DynamicTextGlyph *> Cache;
Cache _cache;
FT_Face _face;
static FT_Library _ft_library;
static bool _ft_initialized;
static bool _ft_ok;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
TextFont::init_type();
register_type(_type_handle, "DynamicTextFont",
TextFont::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
friend class TextNode;
};
#include "dynamicTextFont.I"
#endif // HAVE_FREETYPE
#endif

View File

@ -0,0 +1,54 @@
// Filename: dynamicTextGlyph.I
// Created by: drose (09Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: DynamicTextGlyph::Constructor
// Access: Publiic
// Description:
////////////////////////////////////////////////////////////////////
INLINE DynamicTextGlyph::
DynamicTextGlyph(DynamicTextPage *page, int x, int y,
int x_size, int y_size, int margin) :
_page(page),
_x(x), _y(y),
_x_size(x_size), _y_size(y_size),
_margin(margin)
{
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextGlyph::intersects
// Access: Public
// Description: Returns true if the particular position this glyph
// has been assigned to overlaps the rectangle whose
// top left corner is at x, y and whose size is given by
// x_size, y_size, or false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool DynamicTextGlyph::
intersects(int x, int y, int x_size, int y_size) const {
int hright = x + x_size;
int hbot = y + y_size;
int mright = _x + _x_size;
int mbot = _y + _y_size;
return !(x >= mright || hright <= _x ||
y >= mbot || hbot <= _y);
}

View File

@ -0,0 +1,116 @@
// Filename: dynamicTextGlyph.cxx
// Created by: drose (09Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "dynamicTextGlyph.h"
#ifdef HAVE_FREETYPE
#include "dynamicTextPage.h"
#include "geomTristrip.h"
#include "textureTransition.h"
#include "transparencyTransition.h"
////////////////////////////////////////////////////////////////////
// Function: DynamicTextGlyph::get_row
// Access: Publiic
// Description: Returns a pointer to the first byte in the pixel
// buffer associated with the leftmost pixel in the
// indicated row, where 0 is the topmost row and _y_size
// - _margin * 2 - 1 is the bottommost row.
////////////////////////////////////////////////////////////////////
unsigned char *DynamicTextGlyph::
get_row(int y) {
nassertr(y >= 0 && y < _y_size - _margin * 2, (unsigned char *)NULL);
nassertr(_page != (DynamicTextPage *)NULL, (unsigned char *)NULL);
nassertr(_page->_pbuffer != (PixelBuffer *)NULL, (unsigned char *)NULL);
// First, offset y by the glyph's start.
y += _y + _margin;
// Also, get the x start.
int x = _x + _margin;
// Invert y.
y = _page->_pbuffer->get_ysize() - 1 - y;
int offset = (y * _page->_pbuffer->get_xsize()) + x;
return _page->_pbuffer->_image + offset;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextGlyph::make_geom
// Access: Publiic
// Description: Creates the actual geometry for the glyph. The
// parameters bitmap_top and bitmap_left are from
// FreeType, and indicate the position of the top left
// corner of the bitmap relative to the glyph's origin.
// The advance number represents the number of pixels
// the pen should be advanced after drawing this glyph.
////////////////////////////////////////////////////////////////////
void DynamicTextGlyph::
make_geom(int bitmap_top, int bitmap_left,
float advance, float pixels_per_unit) {
// Determine the corners of the rectangle in geometric units.
float top = (bitmap_top + _margin) / pixels_per_unit;
float left = (bitmap_left - _margin) / pixels_per_unit;
float bottom = (bitmap_top - _y_size - _margin) / pixels_per_unit;
float right = (bitmap_left + _x_size + _margin) / pixels_per_unit;
// And the corresponding corners in UV units.
float uv_top = 1.0f - (float)_y / _page->get_y_size();
float uv_left = (float)_x / _page->get_x_size();
float uv_bottom = 1.0f - (float)(_y + _y_size) / _page->get_y_size();
float uv_right = (float)(_x + _x_size) / _page->get_x_size();
// Create a corresponding tristrip.
_geom = new GeomTristrip;
PTA_Vertexf coords;
coords.push_back(Vertexf(left, 0, top));
coords.push_back(Vertexf(left, 0, bottom));
coords.push_back(Vertexf(right, 0, top));
coords.push_back(Vertexf(right, 0, bottom));
PTA_TexCoordf texcoords;
texcoords.push_back(TexCoordf(uv_left, uv_top));
texcoords.push_back(TexCoordf(uv_left, uv_bottom));
texcoords.push_back(TexCoordf(uv_right, uv_top));
texcoords.push_back(TexCoordf(uv_right, uv_bottom));
PTA_Colorf colors;
colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
PTA_int lengths;
lengths.push_back(4);
_geom->set_coords(coords);
_geom->set_texcoords(texcoords, G_PER_VERTEX);
_geom->set_colors(colors, G_OVERALL);
_geom->set_lengths(lengths);
_geom->set_num_prims(1);
TextureTransition *tex = new TextureTransition(_page);
TransparencyTransition *trans = new TransparencyTransition(TransparencyProperty::M_alpha);
_trans.set_transition(tex);
_trans.set_transition(trans);
_advance = advance / pixels_per_unit;
}
#endif // HAVE_FREETYPE

View File

@ -0,0 +1,57 @@
// Filename: dynamicTextGlyph.h
// Created by: drose (09Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef DYNAMICTEXTGLYPH_H
#define DYNAMICTEXTGLYPH_H
#include "pandabase.h"
#ifdef HAVE_FREETYPE
#include "textGlyph.h"
class DynamicTextPage;
////////////////////////////////////////////////////////////////////
// Class : DynamicTextGlyph
// Description : A specialization on TextGlyph that is generated and
// stored by a DynamicTextFont. This keeps some
// additional information, such as where the glyph
// appears on a texture map.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA DynamicTextGlyph : public TextGlyph {
public:
INLINE DynamicTextGlyph(DynamicTextPage *page, int x, int y,
int x_size, int y_size, int margin);
INLINE bool intersects(int x, int y, int x_size, int y_size) const;
unsigned char *get_row(int y);
void make_geom(int top, int left, float advance, float pixels_per_unit);
DynamicTextPage *_page;
int _x, _y;
int _x_size, _y_size;
int _margin;
};
#include "dynamicTextGlyph.I"
#endif // HAVE_FREETYPE
#endif

View File

@ -0,0 +1,50 @@
// Filename: dynamicTextPage.I
// Created by: drose (09Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: DynamicTextPage::get_x_size
// Access: Published
// Description: Returns the x size of the page (texture), in pixels.
////////////////////////////////////////////////////////////////////
INLINE int DynamicTextPage::
get_x_size() const {
return _x_size;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextPage::get_y_size
// Access: Published
// Description: Returns the y size of the page (texture), in pixels.
////////////////////////////////////////////////////////////////////
INLINE int DynamicTextPage::
get_y_size() const {
return _y_size;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextPage::is_empty
// Access: Published
// Description: Returns true if the page has no glyphs, false
// otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool DynamicTextPage::
is_empty() const {
return _glyphs.empty();
}

View File

@ -0,0 +1,140 @@
// Filename: dynamicTextPage.cxx
// Created by: drose (09Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#include "dynamicTextPage.h"
#include "dynamicTextFont.h"
#ifdef HAVE_FREETYPE
TypeHandle DynamicTextPage::_type_handle;
////////////////////////////////////////////////////////////////////
// Function: DynamicTextPage::Constructor
// Access: Publiic
// Description:
////////////////////////////////////////////////////////////////////
DynamicTextPage::
DynamicTextPage(DynamicTextFont *font) :
_font(font)
{
_x_size = _font->get_page_x_size();
_y_size = _font->get_page_y_size();
// Initialize the Texture to an empty, black (transparent) image of
// the appropriate size.
_pbuffer = new PixelBuffer(_x_size, _y_size, 1, 1,
PixelBuffer::T_unsigned_byte,
PixelBuffer::F_alpha);
mark_dirty(DF_image);
// We don't necessarily want to use mipmaps, since we don't want to
// regenerate those every time the texture changes, but we do want
// at least linear filtering.
set_magfilter(FT_linear);
set_minfilter(FT_linear);
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextPage::slot_glyph
// Access: Publiic
// 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.
////////////////////////////////////////////////////////////////////
DynamicTextGlyph *DynamicTextPage::
slot_glyph(int x_size, int y_size, int margin) {
int x, y;
if (!find_hole(x, y, x_size, y_size)) {
// No room for the glyph.
return (DynamicTextGlyph *)NULL;
}
// The glyph can be fit at (x, y). Slot it.
PT(DynamicTextGlyph) glyph =
new DynamicTextGlyph(this, x, y, x_size, y_size, margin);
_glyphs.push_back(glyph);
return glyph;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextPage::find_hole
// Access: Private
// Description: Searches for a hole of at least x_size by y_size
// pixels somewhere within the page. If a suitable hole
// is found, sets x and y to the top left corner and
// returns true; otherwise, returns false.
////////////////////////////////////////////////////////////////////
bool DynamicTextPage::
find_hole(int &x, int &y, int x_size, int y_size) const {
y = 0;
while (y + y_size <= _y_size) {
int next_y = _y_size;
// Scan along the row at 'y'.
x = 0;
while (x + x_size <= _x_size) {
int next_x = x;
// Consider the spot at x, y.
DynamicTextGlyph *overlap = find_overlap(x, y, x_size, y_size);
if (overlap == (DynamicTextGlyph *)NULL) {
// Hooray!
return true;
}
next_x = overlap->_x + overlap->_x_size;
next_y = min(next_y, overlap->_y + overlap->_y_size);
nassertr(next_x > x, false);
x = next_x;
}
nassertr(next_y > y, false);
y = next_y;
}
// Nope, wouldn't fit anywhere.
return false;
}
////////////////////////////////////////////////////////////////////
// Function: DynamicTextPage::find_overlap
// Access: Private
// Description: If the rectangle whose top left corner is x, y and
// whose size is x_size, y_size describes an empty hole
// that does not overlap any placed glyphs, returns
// NULL; otherwise, returns the first placed glyph
// that the image does overlap. It is assumed the
// rectangle lies completely within the boundaries of
// the page itself.
////////////////////////////////////////////////////////////////////
DynamicTextGlyph *DynamicTextPage::
find_overlap(int x, int y, int x_size, int y_size) const {
Glyphs::const_iterator gi;
for (gi = _glyphs.begin(); gi != _glyphs.end(); ++gi) {
DynamicTextGlyph *glyph = (*gi);
if (glyph->intersects(x, y, x_size, y_size)) {
return glyph;
}
}
return (DynamicTextGlyph *)NULL;
}
#endif // HAVE_FREETYPE

View File

@ -0,0 +1,85 @@
// Filename: dynamicTextPage.h
// Created by: drose (09Feb02)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001, Disney Enterprises, Inc. All rights reserved
//
// All use of this software is subject to the terms of the Panda 3d
// Software license. You should have received a copy of this license
// along with this source code; you will also find a current copy of
// the license at http://www.panda3d.org/license.txt .
//
// To contact the maintainers of this program write to
// panda3d@yahoogroups.com .
//
////////////////////////////////////////////////////////////////////
#ifndef DYNAMICTEXTPAGE_H
#define DYNAMICTEXTPAGE_H
#include "pandabase.h"
#ifdef HAVE_FREETYPE
#include "texture.h"
#include "dynamicTextGlyph.h"
#include "pointerTo.h"
#include "pvector.h"
class DynamicTextFont;
////////////////////////////////////////////////////////////////////
// Class : DynamicTextPage
// Description : A single "page" of a DynamicTextFont. This is a
// single texture that holds a number of glyphs for
// rendering. The font starts out with one page, and
// will add more as it needs them.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA DynamicTextPage : public Texture {
public:
DynamicTextPage(DynamicTextFont *font);
DynamicTextGlyph *slot_glyph(int x_size, int y_size, int margin);
INLINE int get_x_size() const;
INLINE int get_y_size() const;
PUBLISHED:
INLINE bool is_empty() const;
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;
typedef pvector< PT(DynamicTextGlyph) > Glyphs;
Glyphs _glyphs;
int _x_size, _y_size;
DynamicTextFont *_font;
public:
static TypeHandle get_class_type() {
return _type_handle;
}
static void init_type() {
Texture::init_type();
register_type(_type_handle, "DynamicTextPage",
Texture::get_class_type());
}
virtual TypeHandle get_type() const {
return get_class_type();
}
virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
private:
static TypeHandle _type_handle;
};
#include "dynamicTextPage.I"
#endif // HAVE_FREETYPE
#endif

View File

@ -41,6 +41,7 @@ StaticTextFont(Node *font_def) {
_glyphs.clear();
find_characters(font_def);
_is_valid = !_glyphs.empty();
if (_font->is_of_type(NamedNode::get_class_type())) {
NamedNode *named_node = DCAST(NamedNode, _font);
@ -48,16 +49,6 @@ StaticTextFont(Node *font_def) {
}
}
////////////////////////////////////////////////////////////////////
// Function: StaticTextFont::Destructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
StaticTextFont::
~StaticTextFont() {
}
////////////////////////////////////////////////////////////////////
// Function: StaticTextFont::write
// Access: Published, Virtual
@ -167,13 +158,13 @@ write(ostream &out, int indent_level) const {
// code, or NULL if there is no such glyph.
////////////////////////////////////////////////////////////////////
const TextGlyph *StaticTextFont::
get_glyph(int character) const {
get_glyph(int character) {
Glyphs::const_iterator gi = _glyphs.find(character);
if (gi == _glyphs.end()) {
// No definition for this character.
return (TextGlyph *)NULL;
} else {
return &(*gi).second;
return (*gi).second;
}
}
@ -262,7 +253,7 @@ find_characters(Node *root) {
width = alist[ilist[0]][0];
}
_glyphs[character] = TextGlyph(ch, trans, width);
_glyphs[character] = new TextGlyph(ch, trans, width);
}
} else if (name == "ds") {

View File

@ -19,17 +19,12 @@
#ifndef STATICTEXTFONT_H
#define STATICTEXTFONT_H
#include <pandabase.h>
#include "pandabase.h"
#include "config_text.h"
#include "textFont.h"
#include "textGlyph.h"
#include <typedReferenceCount.h>
#include <namable.h>
#include <pt_Node.h>
#include <allTransitionsWrapper.h>
#include "pt_Node.h"
#include "pmap.h"
class Node;
@ -47,19 +42,18 @@ class GeomPoint;
class EXPCL_PANDA StaticTextFont : public TextFont {
PUBLISHED:
StaticTextFont(Node *font_def);
virtual ~StaticTextFont();
virtual void write(ostream &out, int indent_level) const;
public:
virtual const TextGlyph *get_glyph(int character) const;
virtual const TextGlyph *get_glyph(int character);
private:
bool find_character_gsets(Node *root, Geom *&ch, GeomPoint *&dot,
AllTransitionsWrapper &trans);
void find_characters(Node *root);
typedef pmap<int, TextGlyph> Glyphs;
typedef pmap<int, PT(TextGlyph)> Glyphs;
Glyphs _glyphs;
float _font_height;
PT_Node _font;
@ -80,8 +74,6 @@ public:
private:
static TypeHandle _type_handle;
friend class TextNode;
};
#include "staticTextFont.I"

View File

@ -17,6 +17,17 @@
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: TextFont::is_valid
// Access: Published
// Description: Returns true if the font is valid and ready to use,
// false otherwise.
////////////////////////////////////////////////////////////////////
INLINE bool TextFont::
is_valid() const {
return _is_valid;
}
////////////////////////////////////////////////////////////////////
// Function: TextFont::get_line_height
// Access: Published

View File

@ -40,6 +40,7 @@ isblank(char ch) {
////////////////////////////////////////////////////////////////////
TextFont::
TextFont() {
_is_valid = false;
_line_height = 1.0;
}
@ -59,7 +60,7 @@ TextFont::
// or 0.0 if the character is not known.
////////////////////////////////////////////////////////////////////
float TextFont::
calc_width(int ch) const {
calc_width(int ch) {
if (ch == ' ') {
// A space is a special case.
return 0.25;
@ -82,7 +83,7 @@ calc_width(int ch) const {
// character.
////////////////////////////////////////////////////////////////////
float TextFont::
calc_width(const string &line) const {
calc_width(const string &line) {
float width = 0.0;
string::const_iterator si;
@ -104,7 +105,7 @@ calc_width(const string &line) const {
////////////////////////////////////////////////////////////////////
string TextFont::
wordwrap_to(const string &text, float wordwrap_width,
bool preserve_trailing_whitespace) const {
bool preserve_trailing_whitespace) {
string output_text;
size_t p = 0;

View File

@ -46,19 +46,21 @@ public:
PUBLISHED:
virtual ~TextFont();
INLINE bool is_valid() const;
INLINE float get_line_height() const;
float calc_width(int ch) const;
float calc_width(const string &line) const;
float calc_width(int ch);
float calc_width(const string &line);
string wordwrap_to(const string &text, float wordwrap_width,
bool preserve_trailing_whitespace) const;
bool preserve_trailing_whitespace);
virtual void write(ostream &out, int indent_level) const;
public:
virtual const TextGlyph *get_glyph(int character) const=0;
virtual const TextGlyph *get_glyph(int character)=0;
protected:
bool _is_valid;
float _line_height;
public:

View File

@ -24,6 +24,8 @@
////////////////////////////////////////////////////////////////////
INLINE TextGlyph::
TextGlyph() {
_geom = (Geom *)NULL;
_advance = 0.0f;
}
////////////////////////////////////////////////////////////////////

View File

@ -21,8 +21,10 @@
#include "pandabase.h"
#include "allTransitionsWrapper.h"
#include "referenceCount.h"
#include "geom.h"
#include "pointerTo.h"
class Geom;
class TextGlyph;
////////////////////////////////////////////////////////////////////
@ -31,7 +33,7 @@ class TextGlyph;
// font. This is a piece of renderable geometry of some
// kind.
////////////////////////////////////////////////////////////////////
class TextGlyph {
class TextGlyph : public ReferenceCount {
public:
INLINE TextGlyph();
INLINE TextGlyph(Geom *geom, const AllTransitionsWrapper &trans, float advance);
@ -42,8 +44,8 @@ public:
INLINE const AllTransitionsWrapper &get_trans() const;
INLINE float get_advance() const;
private:
Geom *_geom;
protected:
PT(Geom) _geom;
AllTransitionsWrapper _trans;
float _advance;
};

View File

@ -47,7 +47,29 @@ END_PUBLISH
////////////////////////////////////////////////////////////////////
// Class : TextNode
// Description :
// Description : The primary interface to this module. This class
// does basic text assembly; given a string of text and
// a TextFont object, it creates a piece of geometry
// that may be placed in the 3-d or 2-d world to
// represent the indicated text.
//
// The TextNode may be used in one of two ways.
// Naively, it may be parented to the scene graph
// directly; used in this way, you can optionally call
// freeze() and thaw() between changing many parameters
// in the text at once, to avoid unnecessary expensive
// regeneration with each parameter change. However, it
// will work, if slowly, even if you never call freeze()
// and thaw().
//
// The second way TextNode may be used is as a text
// generator. To use it in this way, call freeze() once
// on the TextNode when you create it, and never call
// thaw(). Do not parent the TextNode to the scene
// graph; instea, set the properties of the text and
// call generate() to return a node which you may parent
// wherever you like. Each time you call generate() a
// new node is returned.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TextNode : public NamedNode {
PUBLISHED:

View File

@ -1,4 +1,7 @@
#include "config_text.cxx"
#include "dynamicTextFont.cxx"
#include "dynamicTextGlyph.cxx"
#include "dynamicTextPage.cxx"
#include "staticTextFont.cxx"
#include "textFont.cxx"
#include "textGlyph.cxx"