allow embedded graphics in text paragraphs

This commit is contained in:
David Rose 2006-08-18 23:38:30 +00:00
parent 42fc71791e
commit d300c4a10c
20 changed files with 634 additions and 17 deletions

View File

@ -32,6 +32,20 @@ TextEncoder() {
_flags = (F_got_text | F_got_wtext); _flags = (F_got_text | F_got_wtext);
} }
////////////////////////////////////////////////////////////////////
// Function: TextEncoder::Copy Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE TextEncoder::
TextEncoder(const TextEncoder &copy) :
_flags(copy._flags),
_encoding(copy._encoding),
_text(copy._text),
_wtext(copy._wtext)
{
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextEncoder::set_encoding // Function: TextEncoder::set_encoding
// Access: Published // Access: Published

View File

@ -47,6 +47,7 @@ PUBLISHED:
}; };
INLINE TextEncoder(); INLINE TextEncoder();
INLINE TextEncoder(const TextEncoder &copy);
INLINE void set_encoding(Encoding encoding); INLINE void set_encoding(Encoding encoding);
INLINE Encoding get_encoding() const; INLINE Encoding get_encoding() const;

View File

@ -57,7 +57,8 @@ PGButton::
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
PGButton:: PGButton::
PGButton(const PGButton &copy) : PGButton(const PGButton &copy) :
PGItem(copy) PGItem(copy),
_click_buttons(copy._click_buttons)
{ {
_button_down = false; _button_down = false;
} }

View File

@ -552,3 +552,14 @@ compare_largest(const LVecBase4f *&largest, float &largest_area,
largest_area = new_area; largest_area = new_area;
} }
} }
////////////////////////////////////////////////////////////////////
// Function: PGItem::StateDef::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE PGItem::StateDef::
StateDef() :
_frame_stale(true)
{
}

View File

@ -100,10 +100,34 @@ PGItem(const PGItem &copy) :
_has_frame(copy._has_frame), _has_frame(copy._has_frame),
_frame(copy._frame), _frame(copy._frame),
_state(copy._state), _state(copy._state),
_flags(copy._flags) _flags(copy._flags),
_sounds(copy._sounds)
{ {
_notify = NULL; _notify = NULL;
_region = new PGMouseWatcherRegion(this); _region = new PGMouseWatcherRegion(this);
// We give our region the same name as the region for the PGItem
// we're copying--so that this PGItem will generate the same event
// names when the user interacts with it.
_region->set_name(copy._region->get_name());
// Make a deep copy of all of the original PGItem's StateDefs.
size_t num_state_defs = copy._state_defs.size();
_state_defs.reserve(num_state_defs);
for (size_t i = 0; i < num_state_defs; ++i) {
// We cheat and cast away the const, because the frame is just a
// cache. But we have to get the frame out of the source before we
// can safely copy it.
StateDef &old_sd = (StateDef &)(copy._state_defs[i]);
old_sd._frame.remove_node();
old_sd._frame_stale = true;
StateDef new_sd;
new_sd._root = old_sd._root.copy_to(NodePath());
new_sd._frame_style = old_sd._frame_style;
_state_defs.push_back(new_sd);
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -1135,9 +1159,7 @@ frame_changed() {
void PGItem:: void PGItem::
slot_state_def(int state) { slot_state_def(int state) {
while (state >= (int)_state_defs.size()) { while (state >= (int)_state_defs.size()) {
StateDef def; _state_defs.push_back(StateDef());
def._frame_stale = true;
_state_defs.push_back(def);
} }
} }

View File

@ -207,6 +207,7 @@ private:
class StateDef { class StateDef {
public: public:
INLINE StateDef();
NodePath _root; NodePath _root;
PGFrameStyle _frame_style; PGFrameStyle _frame_style;
NodePath _frame; NodePath _frame;

View File

@ -23,6 +23,7 @@
textAssembler.I textAssembler.h \ textAssembler.I textAssembler.h \
textFont.I textFont.h \ textFont.I textFont.h \
textGlyph.I textGlyph.h \ textGlyph.I textGlyph.h \
textGraphic.I textGraphic.h \
textNode.I textNode.h \ textNode.I textNode.h \
textProperties.I textProperties.h \ textProperties.I textProperties.h \
textPropertiesManager.I textPropertiesManager.h textPropertiesManager.I textPropertiesManager.h
@ -38,6 +39,7 @@
staticTextFont.cxx \ staticTextFont.cxx \
textAssembler.cxx \ textAssembler.cxx \
textFont.cxx textGlyph.cxx \ textFont.cxx textGlyph.cxx \
textGraphic.cxx \
textNode.cxx \ textNode.cxx \
textProperties.cxx \ textProperties.cxx \
textPropertiesManager.cxx textPropertiesManager.cxx
@ -53,6 +55,7 @@
textAssembler.I textAssembler.h \ textAssembler.I textAssembler.h \
textFont.I textFont.h \ textFont.I textFont.h \
textGlyph.I textGlyph.h \ textGlyph.I textGlyph.h \
textGraphic.I textGraphic.h \
textNode.I textNode.h \ textNode.I textNode.h \
textProperties.I textProperties.h \ textProperties.I textProperties.h \
textPropertiesManager.I textPropertiesManager.h textPropertiesManager.I textPropertiesManager.h

View File

@ -118,6 +118,13 @@ ConfigVariableInt text_soft_break_key
"when it is used as a break point, no character is " "when it is used as a break point, no character is "
"introduced in its place.")); "introduced in its place."));
ConfigVariableInt text_embed_graphic_key
("text-embed-graphic-key", 5,
PRC_DESC("This is the decimal character number that, embedded in "
"a string, is used to bracket the name of a model "
"added to the TextPropertiesManager object, to "
"embed an arbitrary graphic image within a paragraph."));
wstring wstring
get_text_soft_hyphen_output() { get_text_soft_hyphen_output() {
static wstring *text_soft_hyphen_output = NULL; static wstring *text_soft_hyphen_output = NULL;

View File

@ -45,6 +45,7 @@ extern ConfigVariableInt text_push_properties_key;
extern ConfigVariableInt text_pop_properties_key; extern ConfigVariableInt text_pop_properties_key;
extern ConfigVariableInt text_soft_hyphen_key; extern ConfigVariableInt text_soft_hyphen_key;
extern ConfigVariableInt text_soft_break_key; extern ConfigVariableInt text_soft_break_key;
extern ConfigVariableInt text_embed_graphic_key;
extern wstring get_text_soft_hyphen_output(); extern wstring get_text_soft_hyphen_output();
extern ConfigVariableDouble text_hyphen_ratio; extern ConfigVariableDouble text_hyphen_ratio;
extern wstring get_text_never_break_before(); extern wstring get_text_never_break_before();

View File

@ -84,7 +84,11 @@ get_num_rows() const {
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
INLINE float TextAssembler:: INLINE float TextAssembler::
calc_width(const TextCharacter &tch) { calc_width(const TextCharacter &tch) {
return calc_width(tch._character, *tch._properties); if (tch._graphic != (TextGraphic *)NULL) {
return calc_width(tch._graphic, *tch._properties);
} else {
return calc_width(tch._character, *tch._properties);
}
} }
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
@ -95,6 +99,20 @@ calc_width(const TextCharacter &tch) {
INLINE TextAssembler::TextCharacter:: INLINE TextAssembler::TextCharacter::
TextCharacter(wchar_t character, const TextProperties *properties) : TextCharacter(wchar_t character, const TextProperties *properties) :
_character(character), _character(character),
_graphic(NULL),
_properties(properties)
{
}
////////////////////////////////////////////////////////////////////
// Function: TextAssembler::TextCharacter::Constructor
// Access: Public
// Description:
////////////////////////////////////////////////////////////////////
INLINE TextAssembler::TextCharacter::
TextCharacter(const TextGraphic *graphic, const TextProperties *properties) :
_character(0),
_graphic(graphic),
_properties(properties) _properties(properties)
{ {
} }

View File

@ -177,7 +177,9 @@ get_wordwrapped_wtext() const {
for (ti = _wordwrapped_string.begin(); for (ti = _wordwrapped_string.begin();
ti != _wordwrapped_string.end(); ti != _wordwrapped_string.end();
++ti) { ++ti) {
wtext += (*ti)._character; if ((*ti)._graphic != (TextGraphic *)NULL) {
wtext += (*ti)._character;
}
} }
return wtext; return wtext;
@ -203,8 +205,13 @@ assemble_text() {
// and put them under a common node. // and put them under a common node.
PT(PandaNode) parent_node = new PandaNode("common"); PT(PandaNode) parent_node = new PandaNode("common");
PT(GeomNode) shadow_node = new GeomNode("shadow"); PT(PandaNode) shadow_node = new PandaNode("shadow");
PT(GeomNode) text_node = new GeomNode("text"); PT(GeomNode) shadow_geom_node = new GeomNode("shadow_geom");
shadow_node->add_child(shadow_geom_node);
PT(PandaNode) text_node = new PandaNode("text");
PT(GeomNode) text_geom_node = new GeomNode("text_geom");
text_node->add_child(text_geom_node);
const TextProperties *properties = NULL; const TextProperties *properties = NULL;
CPT(RenderState) text_state; CPT(RenderState) text_state;
@ -256,16 +263,18 @@ assemble_text() {
// goes, while the place-text function just stomps on the // goes, while the place-text function just stomps on the
// vertices. // vertices.
if (properties->has_shadow()) { if (properties->has_shadow()) {
placement->assign_copy_to(shadow_node, shadow_state, shadow_xform); placement->assign_copy_to(shadow_geom_node, shadow_state, shadow_xform);
placement->copy_graphic_to(shadow_node, shadow_state, shadow_xform);
any_shadow = true; any_shadow = true;
} }
placement->assign_to(text_node, text_state); placement->assign_to(text_geom_node, text_state);
placement->copy_graphic_to(text_node, text_state, LMatrix4f::ident_mat());
delete placement; delete placement;
} }
placed_glyphs.clear(); placed_glyphs.clear();
if (any_shadow) { if (any_shadow) {
// The shadow_node must appear first to guarantee the correct // The shadow_geom_node must appear first to guarantee the correct
// rendering order. // rendering order.
parent_node->add_child(shadow_node); parent_node->add_child(shadow_node);
} }
@ -316,6 +325,17 @@ calc_width(wchar_t character, const TextProperties &properties) {
return advance * glyph_scale; return advance * glyph_scale;
} }
////////////////////////////////////////////////////////////////////
// Function: TextAssembler::calc_width
// Access: Private, Static
// Description: Returns the width of a single TextGraphic image.
////////////////////////////////////////////////////////////////////
float TextAssembler::
calc_width(const TextGraphic *graphic, const TextProperties &properties) {
LVecBase4f frame = graphic->get_frame();
return (frame[1] - frame[0]) * properties.get_glyph_scale();
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextAssembler::scan_wtext // Function: TextAssembler::scan_wtext
// Access: Private // Access: Private
@ -368,7 +388,13 @@ scan_wtext(wstring::const_iterator &si,
// Define the new properties by extending the current properties. // Define the new properties by extending the current properties.
TextProperties *new_properties = new TextProperties(*current_properties); TextProperties *new_properties = new TextProperties(*current_properties);
new_properties->add_properties(manager->get_properties(name)); const TextProperties *named_props = manager->get_properties_ptr(name);
if (named_props != (TextProperties *)NULL) {
new_properties->add_properties(*named_props);
} else {
text_cat.warning()
<< "Unknown TextProperties: " << name << "\n";
}
_properties_list.push_back(new_properties); _properties_list.push_back(new_properties);
// And recursively scan with the nested properties. // And recursively scan with the nested properties.
@ -390,6 +416,45 @@ scan_wtext(wstring::const_iterator &si,
++si; ++si;
return; return;
} else if ((*si) == text_embed_graphic_key) {
// This indicates an embedded graphic. Pull off the name of the
// TextGraphic structure, which is everything until the next
// text_embed_graphic_key.
wstring wname;
++si;
while (si != send && (*si) != text_embed_graphic_key) {
wname += (*si);
++si;
}
if (si == send) {
// We didn't close the text_embed_graphic_key. That's an
// error.
text_cat.warning()
<< "Unclosed embed_graphic in text.\n";
return;
}
++si;
// Now we have to encode the wstring into a string, for lookup
// in the TextPropertiesManager.
string name = _encoder->encode_wtext(wname);
TextPropertiesManager *manager =
TextPropertiesManager::get_global_ptr();
// Get the graphic image.
const TextGraphic *named_graphic = manager->get_graphic_ptr(name);
if (named_graphic != (TextGraphic *)NULL) {
text_string.push_back(TextCharacter(named_graphic, current_properties));
} else {
text_cat.warning()
<< "Unknown TextGraphic: " << name << "\n";
}
} else { } else {
// A normal character. Apply it. // A normal character. Apply it.
text_string.push_back(TextCharacter(*si, current_properties)); text_string.push_back(TextCharacter(*si, current_properties));
@ -771,6 +836,7 @@ assemble_row(TextAssembler::TextString::const_iterator &si,
while (si != send) { while (si != send) {
wchar_t character = (*si)._character; wchar_t character = (*si)._character;
const TextGraphic *graphic = (*si)._graphic;
const TextProperties *properties = (*si)._properties; const TextProperties *properties = (*si)._properties;
TextFont *font = properties->get_font(); TextFont *font = properties->get_font();
@ -782,7 +848,12 @@ assemble_row(TextAssembler::TextString::const_iterator &si,
// And the height of the row is the maximum of all the fonts used // And the height of the row is the maximum of all the fonts used
// within the row. // within the row.
line_height = max(line_height, font->get_line_height()); if (graphic != (TextGraphic *)NULL) {
LVecBase4f frame = graphic->get_frame();
line_height = max(line_height, frame[3] - frame[2]);
} else {
line_height = max(line_height, font->get_line_height());
}
if (character == '\n') { if (character == '\n') {
// The newline character marks the end of the row. // The newline character marks the end of the row.
@ -803,6 +874,38 @@ assemble_row(TextAssembler::TextString::const_iterator &si,
} else if (character == text_soft_hyphen_key) { } else if (character == text_soft_hyphen_key) {
// And so is the 'soft-hyphen' key character. // And so is the 'soft-hyphen' key character.
} else if (graphic != (TextGraphic *)NULL) {
// A special embedded graphic.
GlyphPlacement *placement = new GlyphPlacement;
row_placed_glyphs.push_back(placement);
placement->_graphic_model = graphic->get_model().node();
LVecBase4f frame = graphic->get_frame();
float glyph_scale = properties->get_glyph_scale();
float advance = (frame[1] - frame[0]);
// Now compute the matrix that will transform the glyph (or
// glyphs) into position.
LMatrix4f glyph_xform = LMatrix4f::scale_mat(glyph_scale);
glyph_xform(3, 0) += (xpos - frame[0]);
glyph_xform(3, 2) += (properties->get_glyph_shift() - frame[2]);
if (properties->has_slant()) {
LMatrix4f shear(1.0f, 0.0f, 0.0f, 0.0f,
0.0f, 1.0f, 0.0f, 0.0f,
properties->get_slant(), 0.0f, 1.0f, 0.0f,
0.0f, 0.0f, 0.0f, 1.0f);
glyph_xform = shear * glyph_xform;
}
placement->_xform = glyph_xform;
placement->_properties = properties;
xpos += advance * glyph_scale;
} else { } else {
// A printable character. // A printable character.
bool got_glyph; bool got_glyph;
@ -1482,5 +1585,27 @@ assign_copy_to(GeomNode *geom_node, const RenderState *state,
} }
} }
////////////////////////////////////////////////////////////////////
// Function: TextAssembler::GlyphPlacement::copy_graphic_to
// Access: Private
// Description: If the GlyphPlacement includes a special graphic,
// copies it to the indicated node.
////////////////////////////////////////////////////////////////////
void TextAssembler::GlyphPlacement::
copy_graphic_to(PandaNode *node, const RenderState *state,
const LMatrix4f &extra_xform) const {
if (_graphic_model != (PandaNode *)NULL) {
LMatrix4f new_xform = _xform * extra_xform;
// We need an intermediate node to hold the transform and state.
PT(PandaNode) intermediate_node = new PandaNode("");
node->add_child(intermediate_node);
intermediate_node->set_transform(TransformState::make_mat(new_xform));
intermediate_node->set_state(state);
intermediate_node->add_child(_graphic_model->copy_subgraph());
}
}
#endif // CPPPARSER #endif // CPPPARSER

View File

@ -31,6 +31,7 @@
#include "geom.h" #include "geom.h"
class TextEncoder; class TextEncoder;
class TextGraphic;
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : TextAssembler // Class : TextAssembler
@ -63,6 +64,7 @@ public:
INLINE const LVector2f &get_lr() const; INLINE const LVector2f &get_lr() const;
static float calc_width(wchar_t character, const TextProperties &properties); static float calc_width(wchar_t character, const TextProperties &properties);
static float calc_width(const TextGraphic *graphic, const TextProperties &properties);
private: private:
// These structures are built up and operated on by scan_wtext() and // These structures are built up and operated on by scan_wtext() and
@ -74,7 +76,9 @@ private:
class TextCharacter { class TextCharacter {
public: public:
INLINE TextCharacter(wchar_t character, const TextProperties *properties); INLINE TextCharacter(wchar_t character, const TextProperties *properties);
INLINE TextCharacter(const TextGraphic *graphic, const TextProperties *properties);
wchar_t _character; wchar_t _character;
const TextGraphic *_graphic;
const TextProperties *_properties; const TextProperties *_properties;
}; };
typedef pvector<TextCharacter> TextString; typedef pvector<TextCharacter> TextString;
@ -112,9 +116,12 @@ private:
bool &found_any, Thread *current_thread) const; bool &found_any, Thread *current_thread) const;
void assign_to(GeomNode *geom_node, const RenderState *state) const; void assign_to(GeomNode *geom_node, const RenderState *state) const;
void assign_copy_to(GeomNode *geom_node, const RenderState *state, void assign_copy_to(GeomNode *geom_node, const RenderState *state,
const LMatrix4f &xform) const; const LMatrix4f &extra_xform) const;
void copy_graphic_to(PandaNode *node, const RenderState *state,
const LMatrix4f &extra_xform) const;
Pieces _pieces; Pieces _pieces;
PT(PandaNode) _graphic_model;
LMatrix4f _xform; LMatrix4f _xform;
const TextProperties *_properties; const TextProperties *_properties;
}; };

View File

@ -0,0 +1,116 @@
// Filename: textGraphic.I
// Created by: drose (18Aug06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////////////
// Function: TextGraphic::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE TextGraphic::
TextGraphic() {
_frame = LVecBase4f::zero();
}
////////////////////////////////////////////////////////////////////
// Function: TextGraphic::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE TextGraphic::
TextGraphic(const NodePath &model, const LVecBase4f &frame) :
_model(model),
_frame(frame)
{
}
////////////////////////////////////////////////////////////////////
// Function: TextGraphic::Constructor
// Access: Published
// Description:
////////////////////////////////////////////////////////////////////
INLINE TextGraphic::
TextGraphic(const NodePath &model, float left, float right, float bottom, float top) :
_model(model),
_frame(left, right, bottom, top)
{
}
////////////////////////////////////////////////////////////////////
// Function: TextGraphic::get_model
// Access: Published
// Description: Returns the NodePath associated with the graphic,
// that renders the desired image.
////////////////////////////////////////////////////////////////////
INLINE NodePath TextGraphic::
get_model() const {
return _model;
}
////////////////////////////////////////////////////////////////////
// Function: TextGraphic::set_model
// Access: Published
// Description: Changes the NodePath associated with the graphic.
// This NodePath should contain geometry that will
// render the desired graphic image.
////////////////////////////////////////////////////////////////////
INLINE void TextGraphic::
set_model(const NodePath &model) {
_model = model;
}
////////////////////////////////////////////////////////////////////
// Function: TextGraphic::get_frame
// Access: Published
// Description: Returns the frame specified for the graphic. This is
// the amount of space that will be reserved for the
// graphic when it is embedded in a text paragraph, in
// the form (left, right, bottom, top).
//
// The actual graphic, as rendered by the NodePath
// specified via set_model(), should more or less fit
// within this rectangle. It is not required to fit
// completely within it, but if it does not, it may
// visually overlap with nearby text.
////////////////////////////////////////////////////////////////////
INLINE LVecBase4f TextGraphic::
get_frame() const {
return _frame;
}
////////////////////////////////////////////////////////////////////
// Function: TextGraphic::set_frame
// Access: Published
// Description: Specifies the (left, right, bottom, top) bounding
// frame for the graphic. See get_frame().
////////////////////////////////////////////////////////////////////
INLINE void TextGraphic::
set_frame(const LVecBase4f &frame) {
_frame = frame;
}
////////////////////////////////////////////////////////////////////
// Function: TextGraphic::set_frame
// Access: Published
// Description: Specifies the (left, right, bottom, top) bounding
// frame for the graphic. See get_frame().
////////////////////////////////////////////////////////////////////
INLINE void TextGraphic::
set_frame(float left, float right, float bottom, float top) {
_frame.set(left, right, bottom, top);
}

View File

@ -0,0 +1,19 @@
// Filename: textGraphic.cxx
// Created by: drose (18Aug06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#include "textGraphic.h"

View File

@ -0,0 +1,67 @@
// Filename: textGraphic.h
// Created by: drose (18Aug06)
//
////////////////////////////////////////////////////////////////////
//
// PANDA 3D SOFTWARE
// Copyright (c) 2001 - 2004, 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://etc.cmu.edu/panda3d/docs/license/ .
//
// To contact the maintainers of this program write to
// panda3d-general@lists.sourceforge.net .
//
////////////////////////////////////////////////////////////////////
#ifndef TEXTGRAPHIC_H
#define TEXTGRAPHIC_H
#include "pandabase.h"
#include "config_text.h"
#include "nodePath.h"
////////////////////////////////////////////////////////////////////
// Class : TextGraphic
// Description : This defines a special model that has been
// constructed for the purposes of embedding an
// arbitrary graphic image within a text paragraph.
//
// It can be any arbitrary model, though it should be
// built along the same scale as the text, and it should
// probably be at least mostly two-dimensional.
// Typically, this means it should be constructed in the
// X-Z plane, and it should have a maximum vertical (Z)
// height of 1.0.
//
// The frame specifies an arbitrary bounding volume in
// the form (left, right, bottom, top). This indicates
// the amount of space that will be reserved within the
// paragraph. The actual model is not actually required
// to fit within this rectangle, but if it does not, it
// may visually overlap with nearby text.
////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TextGraphic {
PUBLISHED:
INLINE TextGraphic();
INLINE TextGraphic(const NodePath &model, const LVecBase4f &frame);
INLINE TextGraphic(const NodePath &model, float left, float right, float bottom, float top);
INLINE NodePath get_model() const;
INLINE void set_model(const NodePath &model);
INLINE LVecBase4f get_frame() const;
INLINE void set_frame(const LVecBase4f &frame);
INLINE void set_frame(float left, float right, float bottom, float top);
private:
NodePath _model;
LVecBase4f _frame;
};
#include "textGraphic.I"
#endif

View File

@ -120,6 +120,50 @@ TextNode(const string &name, const TextProperties &copy) :
_lr3d.set(0.0f, 0.0f, 0.0f); _lr3d.set(0.0f, 0.0f, 0.0f);
} }
////////////////////////////////////////////////////////////////////
// Function: TextNode::Copy Constructor
// Access: Published
// Description: OK, this is a true copy constructor.
////////////////////////////////////////////////////////////////////
TextNode::
TextNode(const TextNode &copy) :
PandaNode(copy),
TextEncoder(copy),
TextProperties(copy),
_card_texture(copy._card_texture),
_frame_color(copy._frame_color),
_card_color(copy._card_color),
_flags(copy._flags),
_max_rows(copy._max_rows),
_frame_width(copy._frame_width),
_card_border_size(copy._card_border_size),
_card_border_uv_portion(copy._card_border_uv_portion),
_frame_ul(copy._frame_ul),
_frame_lr(copy._frame_lr),
_card_ul(copy._card_ul),
_card_lr(copy._card_lr),
_transform(copy._transform),
_coordinate_system(copy._coordinate_system),
_ul3d(copy._ul3d),
_lr3d(copy._lr3d),
_assembler(this)
{
invalidate_with_measure();
}
////////////////////////////////////////////////////////////////////
// Function: TextNode::make_copy
// Access: Protected, Virtual
// Description: Returns a newly-allocated Node that is a shallow copy
// of this one. It will be a different Node pointer,
// but its internal data may or may not be shared with
// that of the original Node.
////////////////////////////////////////////////////////////////////
PandaNode *TextNode::
make_copy() const {
return new TextNode(*this);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextNode::Destructor // Function: TextNode::Destructor
// Access: Published // Access: Published
@ -267,8 +311,7 @@ generate() {
PT(PandaNode) text_root = _assembler.assemble_text(); PT(PandaNode) text_root = _assembler.assemble_text();
// Parent the text in. We create an intermediate node so we can // Parent the text in.
// choose to reinstance the text_root as the shadow, below.
PT(PandaNode) text = new PandaNode("text"); PT(PandaNode) text = new PandaNode("text");
root->add_child(text, get_draw_order() + 2); root->add_child(text, get_draw_order() + 2);
text->add_child(text_root); text->add_child(text_root);

View File

@ -57,6 +57,11 @@ class EXPCL_PANDA TextNode : public PandaNode, public TextEncoder, public TextPr
PUBLISHED: PUBLISHED:
TextNode(const string &name); TextNode(const string &name);
TextNode(const string &name, const TextProperties &copy); TextNode(const string &name, const TextProperties &copy);
protected:
TextNode(const TextNode &copy);
virtual PandaNode *make_copy() const;
PUBLISHED:
~TextNode(); ~TextNode();
INLINE float get_line_height() const; INLINE float get_line_height() const;

View File

@ -118,6 +118,105 @@ clear_properties(const string &name) {
_properties.erase(name); _properties.erase(name);
} }
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::set_graphic
// Access: Published
// Description: Defines the TextGraphic associated with the
// indicated name. When the name is subsequently
// encountered in text embedded between \5 characters in
// a TextNode string, the specified graphic will be
// embedded in the text at that point.
//
// If there was already a TextGraphic structure
// associated with this name, it is quietly replaced
// with the new definition.
////////////////////////////////////////////////////////////////////
void TextPropertiesManager::
set_graphic(const string &name, const TextGraphic &graphic) {
_graphics[name] = graphic;
}
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::set_graphic
// Access: Published
// Description: This flavor of set_graphic implicitly creates a frame
// for the model using the model's actual computed
// bounding volume, as derived from
// NodePath::calc_tight_bounds(). Create a TextGraphic
// object first if you want to have explicit control of
// the frame.
////////////////////////////////////////////////////////////////////
void TextPropertiesManager::
set_graphic(const string &name, const NodePath &model) {
LPoint3f min_point, max_point;
model.calc_tight_bounds(min_point, max_point);
TextGraphic graphic(model,
min_point.dot(LVector3f::right()),
max_point.dot(LVector3f::right()),
min_point.dot(LVector3f::up()),
max_point.dot(LVector3f::up()));
_graphics[name] = graphic;
}
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::get_graphic
// Access: Published
// Description: Returns the TextGraphic associated with the
// indicated name. If there was not previously a
// TextGraphic associated with this name, a warning
// is printed and then a default TextGraphic
// structure is associated with the name, and returned.
//
// Call has_graphic() instead to check whether a
// particular name has been defined.
////////////////////////////////////////////////////////////////////
TextGraphic TextPropertiesManager::
get_graphic(const string &name) {
Graphics::const_iterator pi;
pi = _graphics.find(name);
if (pi != _graphics.end()) {
return (*pi).second;
}
text_cat.warning()
<< "Creating default TextGraphic for name '" << name << "'\n";
TextGraphic default_graphic;
_graphics[name] = default_graphic;
return default_graphic;
}
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::has_graphic
// Access: Published
// Description: Returns true if a TextGraphic structure has been
// associated with the indicated name, false otherwise.
// Normally this means set_graphic() has been called
// with this name, but because get_graphic() will
// implicitly create a default TextGraphic structure,
// it may also mean simply that get_graphic() has
// been called with the indicated name.
////////////////////////////////////////////////////////////////////
bool TextPropertiesManager::
has_graphic(const string &name) const {
Graphics::const_iterator pi;
pi = _graphics.find(name);
return (pi != _graphics.end());
}
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::clear_graphic
// Access: Published
// Description: Removes the named TextGraphic structure from the
// manager.
////////////////////////////////////////////////////////////////////
void TextPropertiesManager::
clear_graphic(const string &name) {
_graphics.erase(name);
}
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::write // Function: TextPropertiesManager::write
// Access: Published // Access: Published
@ -146,3 +245,37 @@ get_global_ptr() {
} }
return _global_ptr; return _global_ptr;
} }
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::get_properties_ptr
// Access: Public
// Description: Returns a pointer to the TextProperties with the
// indicated name, or NULL if there is no properties
// with that name.
////////////////////////////////////////////////////////////////////
const TextProperties *TextPropertiesManager::
get_properties_ptr(const string &name) {
Properties::const_iterator pi;
pi = _properties.find(name);
if (pi != _properties.end()) {
return &(*pi).second;
}
return NULL;
}
////////////////////////////////////////////////////////////////////
// Function: TextPropertiesManager::get_graphic_ptr
// Access: Public
// Description: Returns a pointer to the TextGraphic with the
// indicated name, or NULL if there is no graphic
// with that name.
////////////////////////////////////////////////////////////////////
const TextGraphic *TextPropertiesManager::
get_graphic_ptr(const string &name) {
Graphics::const_iterator pi;
pi = _graphics.find(name);
if (pi != _graphics.end()) {
return &(*pi).second;
}
return NULL;
}

View File

@ -23,6 +23,7 @@
#include "config_text.h" #include "config_text.h"
#include "textProperties.h" #include "textProperties.h"
#include "textGraphic.h"
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
// Class : TextPropertiesManager // Class : TextPropertiesManager
@ -44,6 +45,14 @@
// the character "n" will be rendered in the "up" state, // the character "n" will be rendered in the "up" state,
// and then " + y" will be rendered in the normal state // and then " + y" will be rendered in the normal state
// again. // again.
//
// This can also be used to define arbitrary models that
// can serve as embedded graphic images in a text
// paragraph. This works similarly; the convention is
// to create a TextGraphic that describes the graphic
// image, and then associate it here via the
// set_graphic() call. Then "\5name\5" will embed the
// named graphic.
//////////////////////////////////////////////////////////////////// ////////////////////////////////////////////////////////////////////
class EXPCL_PANDA TextPropertiesManager { class EXPCL_PANDA TextPropertiesManager {
protected: protected:
@ -56,14 +65,27 @@ PUBLISHED:
bool has_properties(const string &name) const; bool has_properties(const string &name) const;
void clear_properties(const string &name); void clear_properties(const string &name);
void set_graphic(const string &name, const TextGraphic &graphic);
void set_graphic(const string &name, const NodePath &model);
TextGraphic get_graphic(const string &name);
bool has_graphic(const string &name) const;
void clear_graphic(const string &name);
void write(ostream &out, int indent_level = 0) const; void write(ostream &out, int indent_level = 0) const;
static TextPropertiesManager *get_global_ptr(); static TextPropertiesManager *get_global_ptr();
public:
const TextProperties *get_properties_ptr(const string &name);
const TextGraphic *get_graphic_ptr(const string &name);
private: private:
typedef pmap<string, TextProperties> Properties; typedef pmap<string, TextProperties> Properties;
Properties _properties; Properties _properties;
typedef pmap<string, TextGraphic> Graphics;
Graphics _graphics;
static TextPropertiesManager *_global_ptr; static TextPropertiesManager *_global_ptr;
}; };

View File

@ -1,6 +1,7 @@
#include "textAssembler.cxx" #include "textAssembler.cxx"
#include "textFont.cxx" #include "textFont.cxx"
#include "textGlyph.cxx" #include "textGlyph.cxx"
#include "textGraphic.cxx"
#include "textNode.cxx" #include "textNode.cxx"
#include "textProperties.cxx" #include "textProperties.cxx"
#include "textPropertiesManager.cxx" #include "textPropertiesManager.cxx"