|
|
@@ -74,7 +74,7 @@ TextNode(const string &name) : PandaNode(name) {
|
|
|
}
|
|
|
|
|
|
if (text_small_caps) {
|
|
|
- set_small_caps(true);
|
|
|
+ TextProperties::set_small_caps(true);
|
|
|
}
|
|
|
|
|
|
_frame_color.set(1.0f, 1.0f, 1.0f, 1.0f);
|
|
|
@@ -255,11 +255,16 @@ is_whitespace(wchar_t character) const {
|
|
|
*/
|
|
|
PN_stdfloat TextNode::
|
|
|
calc_width(const std::wstring &line) const {
|
|
|
+ TextFont *font = get_font();
|
|
|
+ if (font == nullptr) {
|
|
|
+ return 0.0f;
|
|
|
+ }
|
|
|
+
|
|
|
PN_stdfloat width = 0.0f;
|
|
|
|
|
|
std::wstring::const_iterator si;
|
|
|
for (si = line.begin(); si != line.end(); ++si) {
|
|
|
- width += calc_width(*si);
|
|
|
+ width += TextAssembler::calc_width(*si, *this);
|
|
|
}
|
|
|
|
|
|
return width;
|
|
|
@@ -272,10 +277,10 @@ void TextNode::
|
|
|
output(std::ostream &out) const {
|
|
|
PandaNode::output(out);
|
|
|
|
|
|
- check_rebuild();
|
|
|
+ PT(PandaNode) internal_geom = do_get_internal_geom();
|
|
|
int geom_count = 0;
|
|
|
- if (_internal_geom != nullptr) {
|
|
|
- geom_count = count_geoms(_internal_geom);
|
|
|
+ if (internal_geom != nullptr) {
|
|
|
+ geom_count = count_geoms(internal_geom);
|
|
|
}
|
|
|
|
|
|
out << " (" << geom_count << " geoms)";
|
|
|
@@ -286,6 +291,7 @@ output(std::ostream &out) const {
|
|
|
*/
|
|
|
void TextNode::
|
|
|
write(std::ostream &out, int indent_level) const {
|
|
|
+ MutexHolder holder(_lock);
|
|
|
PandaNode::write(out, indent_level);
|
|
|
TextProperties::write(out, indent_level + 2);
|
|
|
indent(out, indent_level + 2)
|
|
|
@@ -296,167 +302,6 @@ write(std::ostream &out, int indent_level) const {
|
|
|
<< "text is " << get_text() << "\n";
|
|
|
}
|
|
|
|
|
|
-/**
|
|
|
- * Generates the text, according to the parameters indicated within the
|
|
|
- * TextNode, and returns a Node that may be parented within the tree to
|
|
|
- * represent it.
|
|
|
- */
|
|
|
-PT(PandaNode) TextNode::
|
|
|
-generate() {
|
|
|
- PStatTimer timer(_text_generate_pcollector);
|
|
|
- if (text_cat.is_debug()) {
|
|
|
- text_cat.debug()
|
|
|
- << "Rebuilding " << get_type() << " " << get_name()
|
|
|
- << " with '" << get_text() << "'\n";
|
|
|
- }
|
|
|
-
|
|
|
- // The strategy here will be to assemble together a bunch of letters,
|
|
|
- // instanced from the letter hierarchy of font_def, into our own little
|
|
|
- // hierarchy.
|
|
|
-
|
|
|
- // There will be one root over the whole text block, that contains the
|
|
|
- // transform passed in. Under this root there will be another node for each
|
|
|
- // row, that moves the row into the right place horizontally and vertically,
|
|
|
- // and for each row, there is another node for each character.
|
|
|
-
|
|
|
- _ul3d.set(0.0f, 0.0f, 0.0f);
|
|
|
- _lr3d.set(0.0f, 0.0f, 0.0f);
|
|
|
-
|
|
|
- // Now build a new sub-tree for all the text components.
|
|
|
- string name = get_text();
|
|
|
- size_t newline = name.find('\n');
|
|
|
- if (newline != string::npos) {
|
|
|
- name = name.substr(0, newline);
|
|
|
- }
|
|
|
- PT(PandaNode) root = new PandaNode(name);
|
|
|
-
|
|
|
- if (!has_text()) {
|
|
|
- return root;
|
|
|
- }
|
|
|
-
|
|
|
- TextFont *font = get_font();
|
|
|
- if (font == nullptr) {
|
|
|
- return root;
|
|
|
- }
|
|
|
-
|
|
|
- // Compute the overall text transform matrix. We build the text in a Z-up
|
|
|
- // coordinate system and then convert it to whatever the user asked for.
|
|
|
- LMatrix4 mat =
|
|
|
- LMatrix4::convert_mat(CS_zup_right, _coordinate_system) *
|
|
|
- _transform;
|
|
|
-
|
|
|
- CPT(TransformState) transform = TransformState::make_mat(mat);
|
|
|
- root->set_transform(transform);
|
|
|
-
|
|
|
- std::wstring wtext = get_wtext();
|
|
|
-
|
|
|
- // Assemble the text.
|
|
|
- TextAssembler assembler(this);
|
|
|
- assembler.set_properties(*this);
|
|
|
- assembler.set_max_rows(_max_rows);
|
|
|
- assembler.set_usage_hint(_usage_hint);
|
|
|
- assembler.set_dynamic_merge((_flatten_flags & FF_dynamic_merge) != 0);
|
|
|
- bool all_set = assembler.set_wtext(wtext);
|
|
|
- if (all_set) {
|
|
|
- // No overflow.
|
|
|
- _flags &= ~F_has_overflow;
|
|
|
- } else {
|
|
|
- // Overflow.
|
|
|
- _flags |= F_has_overflow;
|
|
|
- }
|
|
|
-
|
|
|
- PT(PandaNode) text_root = assembler.assemble_text();
|
|
|
- _text_ul = assembler.get_ul();
|
|
|
- _text_lr = assembler.get_lr();
|
|
|
- _num_rows = assembler.get_num_rows();
|
|
|
- _wordwrapped_wtext = assembler.get_wordwrapped_wtext();
|
|
|
-
|
|
|
- // Parent the text in.
|
|
|
- PT(PandaNode) text = new PandaNode("text");
|
|
|
- root->add_child(text, get_draw_order() + 2);
|
|
|
- text->add_child(text_root);
|
|
|
-
|
|
|
- // Save the bounding-box information about the text in a form friendly to
|
|
|
- // the user.
|
|
|
- const LVector2 &ul = assembler.get_ul();
|
|
|
- const LVector2 &lr = assembler.get_lr();
|
|
|
- _ul3d.set(ul[0], 0.0f, ul[1]);
|
|
|
- _lr3d.set(lr[0], 0.0f, lr[1]);
|
|
|
-
|
|
|
- _ul3d = _ul3d * _transform;
|
|
|
- _lr3d = _lr3d * _transform;
|
|
|
-
|
|
|
- // Incidentally, that means we don't need to measure the text now.
|
|
|
- _flags &= ~F_needs_measure;
|
|
|
-
|
|
|
- // Now flatten our hierarchy to get rid of the transforms we put in,
|
|
|
- // applying them to the vertices.
|
|
|
-
|
|
|
- NodePath root_np(root);
|
|
|
- if (_flatten_flags & FF_strong) {
|
|
|
- root_np.flatten_strong();
|
|
|
- } else if (_flatten_flags & FF_medium) {
|
|
|
- root_np.flatten_medium();
|
|
|
- } else if (_flatten_flags & FF_light) {
|
|
|
- root_np.flatten_light();
|
|
|
- }
|
|
|
-
|
|
|
- // Now deal with the decorations.
|
|
|
-
|
|
|
- if (has_card()) {
|
|
|
- PT(PandaNode) card_root;
|
|
|
- if (has_card_border()) {
|
|
|
- card_root = make_card_with_border();
|
|
|
- } else {
|
|
|
- card_root = make_card();
|
|
|
- }
|
|
|
- card_root->set_transform(transform);
|
|
|
- card_root->set_attrib(ColorAttrib::make_flat(get_card_color()));
|
|
|
- if (get_card_color()[3] != 1.0f) {
|
|
|
- card_root->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
|
|
- }
|
|
|
- if (has_card_texture()) {
|
|
|
- card_root->set_attrib(TextureAttrib::make(get_card_texture()));
|
|
|
- }
|
|
|
-
|
|
|
- if (has_bin()) {
|
|
|
- card_root->set_attrib(CullBinAttrib::make(get_bin(), get_draw_order()));
|
|
|
- }
|
|
|
-
|
|
|
- // We always apply attribs down to the card vertices.
|
|
|
- SceneGraphReducer gr;
|
|
|
- gr.apply_attribs(card_root);
|
|
|
-
|
|
|
- // In order to decal the text onto the card, the card must become the
|
|
|
- // parent of the text.
|
|
|
- card_root->add_child(root);
|
|
|
- root = card_root;
|
|
|
-
|
|
|
- if (get_card_decal()) {
|
|
|
- card_root->set_effect(DecalEffect::make());
|
|
|
- }
|
|
|
- }
|
|
|
-
|
|
|
- if (has_frame()) {
|
|
|
- PT(PandaNode) frame_root = make_frame();
|
|
|
- frame_root->set_transform(transform);
|
|
|
- root->add_child(frame_root, get_draw_order() + 1);
|
|
|
- frame_root->set_attrib(ColorAttrib::make_flat(get_frame_color()));
|
|
|
- if (get_frame_color()[3] != 1.0f) {
|
|
|
- frame_root->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
|
|
- }
|
|
|
-
|
|
|
- if (has_bin()) {
|
|
|
- frame_root->set_attrib(CullBinAttrib::make(get_bin(), get_draw_order() + 1));
|
|
|
- }
|
|
|
-
|
|
|
- SceneGraphReducer gr;
|
|
|
- gr.apply_attribs(frame_root);
|
|
|
- }
|
|
|
-
|
|
|
- return root;
|
|
|
-}
|
|
|
-
|
|
|
/**
|
|
|
* Returns the actual node that is used internally to render the text, if the
|
|
|
* TextNode is parented within the scene graph.
|
|
|
@@ -465,14 +310,13 @@ generate() {
|
|
|
* you want to get a handle to geometry that represents the text. This method
|
|
|
* is provided as a debugging aid only.
|
|
|
*/
|
|
|
-PandaNode *TextNode::
|
|
|
+PT(PandaNode) TextNode::
|
|
|
get_internal_geom() const {
|
|
|
// Output a nuisance warning to discourage the naive from calling this
|
|
|
// method accidentally.
|
|
|
text_cat.info()
|
|
|
<< "TextNode::get_internal_geom() called.\n";
|
|
|
- check_rebuild();
|
|
|
- return _internal_geom;
|
|
|
+ return do_get_internal_geom();
|
|
|
}
|
|
|
|
|
|
/**
|
|
|
@@ -503,6 +347,7 @@ get_unsafe_to_apply_attribs() const {
|
|
|
void TextNode::
|
|
|
apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
|
|
|
GeomTransformer &transformer) {
|
|
|
+ MutexHolder holder(_lock);
|
|
|
if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
|
|
|
const LMatrix4 &mat = attribs._transform->get_mat();
|
|
|
_transform *= mat;
|
|
|
@@ -520,10 +365,11 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
|
|
|
const ColorAttrib *ca = DCAST(ColorAttrib, attribs._color);
|
|
|
if (ca->get_color_type() == ColorAttrib::T_flat) {
|
|
|
const LColor &c = ca->get_color();
|
|
|
- set_text_color(c);
|
|
|
- set_frame_color(c);
|
|
|
- set_card_color(c);
|
|
|
- set_shadow_color(c);
|
|
|
+ TextProperties::set_text_color(c);
|
|
|
+ TextProperties::set_shadow_color(c);
|
|
|
+ _frame_color = c;
|
|
|
+ _card_color = c;
|
|
|
+ invalidate_no_measure();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -533,29 +379,17 @@ apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
|
|
|
const LVecBase4 &s = csa->get_scale();
|
|
|
if (s != LVecBase4(1.0f, 1.0f, 1.0f, 1.0f)) {
|
|
|
LVecBase4 tc = get_text_color();
|
|
|
- tc[0] *= s[0];
|
|
|
- tc[1] *= s[1];
|
|
|
- tc[2] *= s[2];
|
|
|
- tc[3] *= s[3];
|
|
|
- set_text_color(tc);
|
|
|
+ tc.componentwise_mult(s);
|
|
|
+ TextProperties::set_text_color(tc);
|
|
|
+
|
|
|
LVecBase4 sc = get_shadow_color();
|
|
|
- sc[0] *= s[0];
|
|
|
- sc[1] *= s[1];
|
|
|
- sc[2] *= s[2];
|
|
|
- sc[3] *= s[3];
|
|
|
- set_shadow_color(sc);
|
|
|
- LVecBase4 fc = get_frame_color();
|
|
|
- fc[0] *= s[0];
|
|
|
- fc[1] *= s[1];
|
|
|
- fc[2] *= s[2];
|
|
|
- fc[3] *= s[3];
|
|
|
- set_frame_color(fc);
|
|
|
- LVecBase4 cc = get_card_color();
|
|
|
- cc[0] *= s[0];
|
|
|
- cc[1] *= s[1];
|
|
|
- cc[2] *= s[2];
|
|
|
- cc[3] *= s[3];
|
|
|
- set_card_color(cc);
|
|
|
+ sc.componentwise_mult(s);
|
|
|
+ TextProperties::set_shadow_color(sc);
|
|
|
+
|
|
|
+ _frame_color.componentwise_mult(s);
|
|
|
+ _card_color.componentwise_mult(s);
|
|
|
+
|
|
|
+ invalidate_no_measure();
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
@@ -587,11 +421,10 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any,
|
|
|
PandaNode::calc_tight_bounds(min_point, max_point, found_any, transform,
|
|
|
current_thread);
|
|
|
|
|
|
- check_rebuild();
|
|
|
-
|
|
|
- if (_internal_geom != nullptr) {
|
|
|
- _internal_geom->calc_tight_bounds(min_point, max_point,
|
|
|
- found_any, next_transform, current_thread);
|
|
|
+ PT(PandaNode) geom = do_get_internal_geom();
|
|
|
+ if (geom != nullptr) {
|
|
|
+ geom->calc_tight_bounds(min_point, max_point,
|
|
|
+ found_any, next_transform, current_thread);
|
|
|
}
|
|
|
|
|
|
return next_transform;
|
|
|
@@ -617,10 +450,11 @@ calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any,
|
|
|
*/
|
|
|
bool TextNode::
|
|
|
cull_callback(CullTraverser *trav, CullTraverserData &data) {
|
|
|
- check_rebuild();
|
|
|
- if (_internal_geom != nullptr) {
|
|
|
+
|
|
|
+ PT(PandaNode) internal_geom = do_get_internal_geom();
|
|
|
+ if (internal_geom != nullptr) {
|
|
|
// Render the text with this node.
|
|
|
- CullTraverserData next_data(data, _internal_geom);
|
|
|
+ CullTraverserData next_data(data, internal_geom);
|
|
|
trav->traverse(next_data);
|
|
|
}
|
|
|
|
|
|
@@ -656,17 +490,20 @@ compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
|
|
|
|
|
// Now enclose the bounding box around the text. We can do this without
|
|
|
// actually generating the text, if we have at least measured it.
|
|
|
- check_measure();
|
|
|
-
|
|
|
LPoint3 vertices[8];
|
|
|
- vertices[0].set(_ul3d[0], _ul3d[1], _ul3d[2]);
|
|
|
- vertices[1].set(_ul3d[0], _ul3d[1], _lr3d[2]);
|
|
|
- vertices[2].set(_ul3d[0], _lr3d[1], _ul3d[2]);
|
|
|
- vertices[3].set(_ul3d[0], _lr3d[1], _lr3d[2]);
|
|
|
- vertices[4].set(_lr3d[0], _ul3d[1], _ul3d[2]);
|
|
|
- vertices[5].set(_lr3d[0], _ul3d[1], _lr3d[2]);
|
|
|
- vertices[6].set(_lr3d[0], _lr3d[1], _ul3d[2]);
|
|
|
- vertices[7].set(_lr3d[0], _lr3d[1], _lr3d[2]);
|
|
|
+ {
|
|
|
+ MutexHolder holder(_lock);
|
|
|
+ check_measure();
|
|
|
+
|
|
|
+ vertices[0].set(_ul3d[0], _ul3d[1], _ul3d[2]);
|
|
|
+ vertices[1].set(_ul3d[0], _ul3d[1], _lr3d[2]);
|
|
|
+ vertices[2].set(_ul3d[0], _lr3d[1], _ul3d[2]);
|
|
|
+ vertices[3].set(_ul3d[0], _lr3d[1], _lr3d[2]);
|
|
|
+ vertices[4].set(_lr3d[0], _ul3d[1], _ul3d[2]);
|
|
|
+ vertices[5].set(_lr3d[0], _ul3d[1], _lr3d[2]);
|
|
|
+ vertices[6].set(_lr3d[0], _lr3d[1], _ul3d[2]);
|
|
|
+ vertices[7].set(_lr3d[0], _lr3d[1], _lr3d[2]);
|
|
|
+ }
|
|
|
|
|
|
gbv->around(vertices, vertices + 8);
|
|
|
|
|
|
@@ -681,9 +518,8 @@ compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
|
|
|
void TextNode::
|
|
|
r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state,
|
|
|
GeomTransformer &transformer, Thread *current_thread) {
|
|
|
- check_rebuild();
|
|
|
|
|
|
- PandaNode *child = _internal_geom;
|
|
|
+ PT(PandaNode) child = do_get_internal_geom();
|
|
|
if (child != nullptr) {
|
|
|
CPT(RenderState) child_state = node_state->compose(child->get_state());
|
|
|
child->r_prepare_scene(gsg, child_state, transformer, current_thread);
|
|
|
@@ -698,8 +534,9 @@ r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state,
|
|
|
*/
|
|
|
void TextNode::
|
|
|
do_rebuild() {
|
|
|
+ nassertv(_lock.debug_is_locked());
|
|
|
_flags &= ~(F_needs_rebuild | F_needs_measure);
|
|
|
- _internal_geom = generate();
|
|
|
+ _internal_geom = do_generate();
|
|
|
}
|
|
|
|
|
|
|
|
|
@@ -713,32 +550,216 @@ do_measure() {
|
|
|
do_rebuild();
|
|
|
}
|
|
|
|
|
|
+/**
|
|
|
+ * Generates the text, according to the parameters indicated within the
|
|
|
+ * TextNode, and returns a Node that may be parented within the tree to
|
|
|
+ * represent it.
|
|
|
+ */
|
|
|
+PT(PandaNode) TextNode::
|
|
|
+do_generate() {
|
|
|
+ nassertr(_lock.debug_is_locked(), nullptr);
|
|
|
+
|
|
|
+ PStatTimer timer(_text_generate_pcollector);
|
|
|
+ if (text_cat.is_debug()) {
|
|
|
+ text_cat.debug()
|
|
|
+ << "Rebuilding " << get_type() << " " << get_name()
|
|
|
+ << " with '" << get_text() << "'\n";
|
|
|
+ }
|
|
|
+
|
|
|
+ // The strategy here will be to assemble together a bunch of letters,
|
|
|
+ // instanced from the letter hierarchy of font_def, into our own little
|
|
|
+ // hierarchy.
|
|
|
+
|
|
|
+ // There will be one root over the whole text block, that contains the
|
|
|
+ // transform passed in. Under this root there will be another node for each
|
|
|
+ // row, that moves the row into the right place horizontally and vertically,
|
|
|
+ // and for each row, there is another node for each character.
|
|
|
+
|
|
|
+ _ul3d.set(0.0f, 0.0f, 0.0f);
|
|
|
+ _lr3d.set(0.0f, 0.0f, 0.0f);
|
|
|
+
|
|
|
+ // Now build a new sub-tree for all the text components.
|
|
|
+ string name = get_text();
|
|
|
+ size_t newline = name.find('\n');
|
|
|
+ if (newline != string::npos) {
|
|
|
+ name = name.substr(0, newline);
|
|
|
+ }
|
|
|
+ PT(PandaNode) root = new PandaNode(name);
|
|
|
+
|
|
|
+ if (!has_text()) {
|
|
|
+ return root;
|
|
|
+ }
|
|
|
+
|
|
|
+ TextFont *font = get_font();
|
|
|
+ if (font == nullptr) {
|
|
|
+ return root;
|
|
|
+ }
|
|
|
+
|
|
|
+ // Compute the overall text transform matrix. We build the text in a Z-up
|
|
|
+ // coordinate system and then convert it to whatever the user asked for.
|
|
|
+ LMatrix4 mat =
|
|
|
+ LMatrix4::convert_mat(CS_zup_right, _coordinate_system) *
|
|
|
+ _transform;
|
|
|
+
|
|
|
+ CPT(TransformState) transform = TransformState::make_mat(mat);
|
|
|
+ root->set_transform(transform);
|
|
|
+
|
|
|
+ std::wstring wtext = get_wtext();
|
|
|
+
|
|
|
+ // Assemble the text.
|
|
|
+ TextAssembler assembler(this);
|
|
|
+ assembler.set_properties(*this);
|
|
|
+ assembler.set_max_rows(_max_rows);
|
|
|
+ assembler.set_usage_hint(_usage_hint);
|
|
|
+ assembler.set_dynamic_merge((_flatten_flags & FF_dynamic_merge) != 0);
|
|
|
+ bool all_set = assembler.set_wtext(wtext);
|
|
|
+ if (all_set) {
|
|
|
+ // No overflow.
|
|
|
+ _flags &= ~F_has_overflow;
|
|
|
+ } else {
|
|
|
+ // Overflow.
|
|
|
+ _flags |= F_has_overflow;
|
|
|
+ }
|
|
|
+
|
|
|
+ PT(PandaNode) text_root = assembler.assemble_text();
|
|
|
+ _text_ul = assembler.get_ul();
|
|
|
+ _text_lr = assembler.get_lr();
|
|
|
+ _num_rows = assembler.get_num_rows();
|
|
|
+ _wordwrapped_wtext = assembler.get_wordwrapped_wtext();
|
|
|
+
|
|
|
+ // Parent the text in.
|
|
|
+ PT(PandaNode) text = new PandaNode("text");
|
|
|
+ root->add_child(text, get_draw_order() + 2);
|
|
|
+ text->add_child(text_root);
|
|
|
+
|
|
|
+ // Save the bounding-box information about the text in a form friendly to
|
|
|
+ // the user.
|
|
|
+ const LVector2 &ul = assembler.get_ul();
|
|
|
+ const LVector2 &lr = assembler.get_lr();
|
|
|
+ _ul3d.set(ul[0], 0.0f, ul[1]);
|
|
|
+ _lr3d.set(lr[0], 0.0f, lr[1]);
|
|
|
+
|
|
|
+ _ul3d = _ul3d * _transform;
|
|
|
+ _lr3d = _lr3d * _transform;
|
|
|
+
|
|
|
+ // Incidentally, that means we don't need to measure the text now.
|
|
|
+ _flags &= ~F_needs_measure;
|
|
|
+
|
|
|
+ // Now flatten our hierarchy to get rid of the transforms we put in,
|
|
|
+ // applying them to the vertices.
|
|
|
+
|
|
|
+ NodePath root_np(root);
|
|
|
+ if (_flatten_flags & FF_strong) {
|
|
|
+ root_np.flatten_strong();
|
|
|
+ } else if (_flatten_flags & FF_medium) {
|
|
|
+ root_np.flatten_medium();
|
|
|
+ } else if (_flatten_flags & FF_light) {
|
|
|
+ root_np.flatten_light();
|
|
|
+ }
|
|
|
+
|
|
|
+ // Now deal with the decorations.
|
|
|
+
|
|
|
+ if (_flags & F_has_card) {
|
|
|
+ PT(PandaNode) card_root;
|
|
|
+ if (_flags & F_has_card_border) {
|
|
|
+ card_root = make_card_with_border();
|
|
|
+ } else {
|
|
|
+ card_root = make_card();
|
|
|
+ }
|
|
|
+ card_root->set_transform(transform);
|
|
|
+ card_root->set_attrib(ColorAttrib::make_flat(_card_color));
|
|
|
+ if (_card_color[3] != 1.0f) {
|
|
|
+ card_root->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
|
|
+ }
|
|
|
+ if (_flags & F_has_card_texture) {
|
|
|
+ card_root->set_attrib(TextureAttrib::make(_card_texture));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (has_bin()) {
|
|
|
+ card_root->set_attrib(CullBinAttrib::make(get_bin(), get_draw_order()));
|
|
|
+ }
|
|
|
+
|
|
|
+ // We always apply attribs down to the card vertices.
|
|
|
+ SceneGraphReducer gr;
|
|
|
+ gr.apply_attribs(card_root);
|
|
|
+
|
|
|
+ // In order to decal the text onto the card, the card must become the
|
|
|
+ // parent of the text.
|
|
|
+ card_root->add_child(root);
|
|
|
+ root = card_root;
|
|
|
+
|
|
|
+ if (_flags & F_card_decal) {
|
|
|
+ card_root->set_effect(DecalEffect::make());
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ if (_flags & F_has_frame) {
|
|
|
+ PT(PandaNode) frame_root = make_frame();
|
|
|
+ frame_root->set_transform(transform);
|
|
|
+ root->add_child(frame_root, get_draw_order() + 1);
|
|
|
+ frame_root->set_attrib(ColorAttrib::make_flat(_frame_color));
|
|
|
+ if (_frame_color[3] != 1.0f) {
|
|
|
+ frame_root->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
|
|
|
+ }
|
|
|
+
|
|
|
+ if (has_bin()) {
|
|
|
+ frame_root->set_attrib(CullBinAttrib::make(get_bin(), get_draw_order() + 1));
|
|
|
+ }
|
|
|
+
|
|
|
+ SceneGraphReducer gr;
|
|
|
+ gr.apply_attribs(frame_root);
|
|
|
+ }
|
|
|
+
|
|
|
+ return root;
|
|
|
+}
|
|
|
+
|
|
|
+/**
|
|
|
+ * Returns the actual node that is used internally to render the text, if the
|
|
|
+ * TextNode is parented within the scene graph.
|
|
|
+ */
|
|
|
+PT(PandaNode) TextNode::
|
|
|
+do_get_internal_geom() const {
|
|
|
+ MutexHolder holder(_lock);
|
|
|
+ check_rebuild();
|
|
|
+ return _internal_geom;
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* Creates a frame around the text.
|
|
|
*/
|
|
|
PT(PandaNode) TextNode::
|
|
|
make_frame() {
|
|
|
+ nassertr(_lock.debug_is_locked(), nullptr);
|
|
|
+ nassertr((_flags & F_needs_measure) == 0, nullptr);
|
|
|
+
|
|
|
PT(GeomNode) frame_node = new GeomNode("frame");
|
|
|
|
|
|
- LVector4 dimensions = get_frame_actual();
|
|
|
- PN_stdfloat left = dimensions[0];
|
|
|
- PN_stdfloat right = dimensions[1];
|
|
|
- PN_stdfloat bottom = dimensions[2];
|
|
|
- PN_stdfloat top = dimensions[3];
|
|
|
+ PN_stdfloat left = _frame_ul[0];
|
|
|
+ PN_stdfloat right = _frame_lr[0];
|
|
|
+ PN_stdfloat bottom = _frame_lr[1];
|
|
|
+ PN_stdfloat top = _frame_ul[1];
|
|
|
+
|
|
|
+ if (_flags & F_frame_as_margin) {
|
|
|
+ left = _text_ul[0] - left;
|
|
|
+ right = _text_lr[0] + right;
|
|
|
+ bottom = _text_lr[1] - bottom;
|
|
|
+ top = _text_ul[1] + top;
|
|
|
+ }
|
|
|
|
|
|
CPT(RenderAttrib) thick = RenderModeAttrib::make(RenderModeAttrib::M_unchanged, _frame_width);
|
|
|
CPT(RenderState) state = RenderState::make(thick);
|
|
|
|
|
|
PT(GeomVertexData) vdata = new GeomVertexData
|
|
|
- ("text", GeomVertexFormat::get_v3(), get_usage_hint());
|
|
|
+ ("text", GeomVertexFormat::get_v3(), _usage_hint);
|
|
|
+ vdata->unclean_set_num_rows(4);
|
|
|
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
|
|
|
|
|
- vertex.add_data3(left, 0.0f, top);
|
|
|
- vertex.add_data3(left, 0.0f, bottom);
|
|
|
- vertex.add_data3(right, 0.0f, bottom);
|
|
|
- vertex.add_data3(right, 0.0f, top);
|
|
|
+ vertex.set_data3(left, 0.0f, top);
|
|
|
+ vertex.set_data3(left, 0.0f, bottom);
|
|
|
+ vertex.set_data3(right, 0.0f, bottom);
|
|
|
+ vertex.set_data3(right, 0.0f, top);
|
|
|
|
|
|
- PT(GeomLinestrips) frame = new GeomLinestrips(get_usage_hint());
|
|
|
+ PT(GeomLinestrips) frame = new GeomLinestrips(_usage_hint);
|
|
|
frame->add_consecutive_vertices(0, 4);
|
|
|
frame->add_vertex(0);
|
|
|
frame->close_primitive();
|
|
|
@@ -747,8 +768,8 @@ make_frame() {
|
|
|
geom->add_primitive(frame);
|
|
|
frame_node->add_geom(geom, state);
|
|
|
|
|
|
- if (get_frame_corners()) {
|
|
|
- PT(GeomPoints) corners = new GeomPoints(get_usage_hint());
|
|
|
+ if (_flags & F_frame_corners) {
|
|
|
+ PT(GeomPoints) corners = new GeomPoints(_usage_hint);
|
|
|
corners->add_consecutive_vertices(0, 4);
|
|
|
PT(Geom) geom2 = new Geom(vdata);
|
|
|
geom2->add_primitive(corners);
|
|
|
@@ -763,30 +784,40 @@ make_frame() {
|
|
|
*/
|
|
|
PT(PandaNode) TextNode::
|
|
|
make_card() {
|
|
|
+ nassertr(_lock.debug_is_locked(), nullptr);
|
|
|
+ nassertr((_flags & F_needs_measure) == 0, nullptr);
|
|
|
+
|
|
|
PT(GeomNode) card_node = new GeomNode("card");
|
|
|
|
|
|
- LVector4 dimensions = get_card_actual();
|
|
|
- PN_stdfloat left = dimensions[0];
|
|
|
- PN_stdfloat right = dimensions[1];
|
|
|
- PN_stdfloat bottom = dimensions[2];
|
|
|
- PN_stdfloat top = dimensions[3];
|
|
|
+ PN_stdfloat left = _card_ul[0];
|
|
|
+ PN_stdfloat right = _card_lr[0];
|
|
|
+ PN_stdfloat bottom = _card_lr[1];
|
|
|
+ PN_stdfloat top = _card_ul[1];
|
|
|
+
|
|
|
+ if (_flags & F_card_as_margin) {
|
|
|
+ left = _text_ul[0] - left;
|
|
|
+ right = _text_lr[0] + right;
|
|
|
+ bottom = _text_lr[1] - bottom;
|
|
|
+ top = _text_ul[1] + top;
|
|
|
+ }
|
|
|
|
|
|
PT(GeomVertexData) vdata = new GeomVertexData
|
|
|
- ("text", GeomVertexFormat::get_v3t2(), get_usage_hint());
|
|
|
+ ("text", GeomVertexFormat::get_v3t2(), _usage_hint);
|
|
|
+ vdata->unclean_set_num_rows(4);
|
|
|
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
|
|
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
|
|
|
|
|
|
- vertex.add_data3(left, 0.0f, top);
|
|
|
- vertex.add_data3(left, 0.0f, bottom);
|
|
|
- vertex.add_data3(right, 0.0f, top);
|
|
|
- vertex.add_data3(right, 0.0f, bottom);
|
|
|
+ vertex.set_data3(left, 0.0f, top);
|
|
|
+ vertex.set_data3(left, 0.0f, bottom);
|
|
|
+ vertex.set_data3(right, 0.0f, top);
|
|
|
+ vertex.set_data3(right, 0.0f, bottom);
|
|
|
|
|
|
- texcoord.add_data2(0.0f, 1.0f);
|
|
|
- texcoord.add_data2(0.0f, 0.0f);
|
|
|
- texcoord.add_data2(1.0f, 1.0f);
|
|
|
- texcoord.add_data2(1.0f, 0.0f);
|
|
|
+ texcoord.set_data2(0.0f, 1.0f);
|
|
|
+ texcoord.set_data2(0.0f, 0.0f);
|
|
|
+ texcoord.set_data2(1.0f, 1.0f);
|
|
|
+ texcoord.set_data2(1.0f, 0.0f);
|
|
|
|
|
|
- PT(GeomTristrips) card = new GeomTristrips(get_usage_hint());
|
|
|
+ PT(GeomTristrips) card = new GeomTristrips(_usage_hint);
|
|
|
card->add_consecutive_vertices(0, 4);
|
|
|
card->close_primitive();
|
|
|
|
|
|
@@ -805,13 +836,22 @@ make_card() {
|
|
|
*/
|
|
|
PT(PandaNode) TextNode::
|
|
|
make_card_with_border() {
|
|
|
+ nassertr(_lock.debug_is_locked(), nullptr);
|
|
|
+ nassertr((_flags & F_needs_measure) == 0, nullptr);
|
|
|
+
|
|
|
PT(GeomNode) card_node = new GeomNode("card");
|
|
|
|
|
|
- LVector4 dimensions = get_card_actual();
|
|
|
- PN_stdfloat left = dimensions[0];
|
|
|
- PN_stdfloat right = dimensions[1];
|
|
|
- PN_stdfloat bottom = dimensions[2];
|
|
|
- PN_stdfloat top = dimensions[3];
|
|
|
+ PN_stdfloat left = _card_ul[0];
|
|
|
+ PN_stdfloat right = _card_lr[0];
|
|
|
+ PN_stdfloat bottom = _card_lr[1];
|
|
|
+ PN_stdfloat top = _card_ul[1];
|
|
|
+
|
|
|
+ if (_flags & F_card_as_margin) {
|
|
|
+ left = _text_ul[0] - left;
|
|
|
+ right = _text_lr[0] + right;
|
|
|
+ bottom = _text_lr[1] - bottom;
|
|
|
+ top = _text_ul[1] + top;
|
|
|
+ }
|
|
|
|
|
|
/*
|
|
|
* we now create three tri-strips instead of one with vertices arranged as
|
|
|
@@ -820,57 +860,59 @@ make_card_with_border() {
|
|
|
*/
|
|
|
|
|
|
PT(GeomVertexData) vdata = new GeomVertexData
|
|
|
- ("text", GeomVertexFormat::get_v3t2(), get_usage_hint());
|
|
|
+ ("text", GeomVertexFormat::get_v3t2(), _usage_hint);
|
|
|
+ vdata->unclean_set_num_rows(16);
|
|
|
GeomVertexWriter vertex(vdata, InternalName::get_vertex());
|
|
|
GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
|
|
|
|
|
|
// verts 1,2,3,4
|
|
|
- vertex.add_data3(left, 0.02, top);
|
|
|
- vertex.add_data3(left, 0.02, top - _card_border_size);
|
|
|
- vertex.add_data3(left + _card_border_size, 0.02, top);
|
|
|
- vertex.add_data3(left + _card_border_size, 0.02,
|
|
|
+ vertex.set_data3(left, 0.02, top);
|
|
|
+ vertex.set_data3(left, 0.02, top - _card_border_size);
|
|
|
+ vertex.set_data3(left + _card_border_size, 0.02, top);
|
|
|
+ vertex.set_data3(left + _card_border_size, 0.02,
|
|
|
top - _card_border_size);
|
|
|
// verts 5,6,7,8
|
|
|
- vertex.add_data3(right - _card_border_size, 0.02, top);
|
|
|
- vertex.add_data3(right - _card_border_size, 0.02,
|
|
|
+ vertex.set_data3(right - _card_border_size, 0.02, top);
|
|
|
+ vertex.set_data3(right - _card_border_size, 0.02,
|
|
|
top - _card_border_size);
|
|
|
- vertex.add_data3(right, 0.02, top);
|
|
|
- vertex.add_data3(right, 0.02, top - _card_border_size);
|
|
|
+ vertex.set_data3(right, 0.02, top);
|
|
|
+ vertex.set_data3(right, 0.02, top - _card_border_size);
|
|
|
// verts 9,10,11,12
|
|
|
- vertex.add_data3(left, 0.02, bottom + _card_border_size);
|
|
|
- vertex.add_data3(left, 0.02, bottom);
|
|
|
- vertex.add_data3(left + _card_border_size, 0.02,
|
|
|
+ vertex.set_data3(left, 0.02, bottom + _card_border_size);
|
|
|
+ vertex.set_data3(left, 0.02, bottom);
|
|
|
+ vertex.set_data3(left + _card_border_size, 0.02,
|
|
|
bottom + _card_border_size);
|
|
|
- vertex.add_data3(left + _card_border_size, 0.02, bottom);
|
|
|
+ vertex.set_data3(left + _card_border_size, 0.02, bottom);
|
|
|
// verts 13,14,15,16
|
|
|
- vertex.add_data3(right - _card_border_size, 0.02,
|
|
|
+ vertex.set_data3(right - _card_border_size, 0.02,
|
|
|
bottom + _card_border_size);
|
|
|
- vertex.add_data3(right - _card_border_size, 0.02, bottom);
|
|
|
- vertex.add_data3(right, 0.02, bottom + _card_border_size);
|
|
|
- vertex.add_data3(right, 0.02, bottom);
|
|
|
-
|
|
|
- texcoord.add_data2(0.0f, 1.0f); //1
|
|
|
- texcoord.add_data2(0.0f, 1.0f - _card_border_uv_portion); //2
|
|
|
- texcoord.add_data2(0.0f + _card_border_uv_portion, 1.0f); //3
|
|
|
- texcoord.add_data2(0.0f + _card_border_uv_portion,
|
|
|
+ vertex.set_data3(right - _card_border_size, 0.02, bottom);
|
|
|
+ vertex.set_data3(right, 0.02, bottom + _card_border_size);
|
|
|
+ vertex.set_data3(right, 0.02, bottom);
|
|
|
+
|
|
|
+ texcoord.set_data2(0.0f, 1.0f); //1
|
|
|
+ texcoord.set_data2(0.0f, 1.0f - _card_border_uv_portion); //2
|
|
|
+ texcoord.set_data2(0.0f + _card_border_uv_portion, 1.0f); //3
|
|
|
+ texcoord.set_data2(0.0f + _card_border_uv_portion,
|
|
|
1.0f - _card_border_uv_portion); //4
|
|
|
- texcoord.add_data2(1.0f -_card_border_uv_portion, 1.0f); //5
|
|
|
- texcoord.add_data2(1.0f -_card_border_uv_portion,
|
|
|
+ texcoord.set_data2(1.0f -_card_border_uv_portion, 1.0f); //5
|
|
|
+ texcoord.set_data2(1.0f -_card_border_uv_portion,
|
|
|
1.0f - _card_border_uv_portion); //6
|
|
|
- texcoord.add_data2(1.0f, 1.0f); //7
|
|
|
- texcoord.add_data2(1.0f, 1.0f - _card_border_uv_portion); //8
|
|
|
+ texcoord.set_data2(1.0f, 1.0f); //7
|
|
|
+ texcoord.set_data2(1.0f, 1.0f - _card_border_uv_portion); //8
|
|
|
|
|
|
- texcoord.add_data2(0.0f, _card_border_uv_portion); //9
|
|
|
- texcoord.add_data2(0.0f, 0.0f); //10
|
|
|
- texcoord.add_data2(_card_border_uv_portion, _card_border_uv_portion); //11
|
|
|
- texcoord.add_data2(_card_border_uv_portion, 0.0f); //12
|
|
|
+ texcoord.set_data2(0.0f, _card_border_uv_portion); //9
|
|
|
+ texcoord.set_data2(0.0f, 0.0f); //10
|
|
|
+ texcoord.set_data2(_card_border_uv_portion, _card_border_uv_portion); //11
|
|
|
+ texcoord.set_data2(_card_border_uv_portion, 0.0f); //12
|
|
|
|
|
|
- texcoord.add_data2(1.0f - _card_border_uv_portion, _card_border_uv_portion);//13
|
|
|
- texcoord.add_data2(1.0f - _card_border_uv_portion, 0.0f);//14
|
|
|
- texcoord.add_data2(1.0f, _card_border_uv_portion);//15
|
|
|
- texcoord.add_data2(1.0f, 0.0f);//16
|
|
|
+ texcoord.set_data2(1.0f - _card_border_uv_portion, _card_border_uv_portion);//13
|
|
|
+ texcoord.set_data2(1.0f - _card_border_uv_portion, 0.0f);//14
|
|
|
+ texcoord.set_data2(1.0f, _card_border_uv_portion);//15
|
|
|
+ texcoord.set_data2(1.0f, 0.0f);//16
|
|
|
|
|
|
- PT(GeomTristrips) card = new GeomTristrips(get_usage_hint());
|
|
|
+ PT(GeomTristrips) card = new GeomTristrips(_usage_hint);
|
|
|
+ card->reserve_num_vertices(24);
|
|
|
|
|
|
// tristrip #1
|
|
|
card->add_consecutive_vertices(0, 8);
|