diff --git a/panda/src/text/textNode.I b/panda/src/text/textNode.I index 313685c504..8070504c6b 100644 --- a/panda/src/text/textNode.I +++ b/panda/src/text/textNode.I @@ -33,6 +33,7 @@ get_line_height() const { */ INLINE void TextNode:: set_max_rows(int max_rows) { + MutexHolder holder(_lock); _max_rows = max_rows; invalidate_with_measure(); } @@ -43,6 +44,7 @@ set_max_rows(int max_rows) { */ INLINE void TextNode:: clear_max_rows() { + MutexHolder holder(_lock); _max_rows = 0; invalidate_with_measure(); } @@ -53,6 +55,7 @@ clear_max_rows() { */ INLINE bool TextNode:: has_max_rows() const { + MutexHolder holder(_lock); return _max_rows > 0; } @@ -62,6 +65,7 @@ has_max_rows() const { */ INLINE int TextNode:: get_max_rows() const { + MutexHolder holder(_lock); return _max_rows; } @@ -71,6 +75,7 @@ get_max_rows() const { */ INLINE bool TextNode:: has_overflow() const { + MutexHolder holder(_lock); check_measure(); return (_flags & F_has_overflow) != 0; } @@ -88,6 +93,7 @@ set_frame_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a) { */ INLINE void TextNode:: set_frame_color(const LColor &frame_color) { + MutexHolder holder(_lock); if (_frame_color != frame_color) { _frame_color = frame_color; invalidate_no_measure(); @@ -99,6 +105,7 @@ set_frame_color(const LColor &frame_color) { */ INLINE LColor TextNode:: get_frame_color() const { + MutexHolder holder(_lock); return _frame_color; } @@ -107,7 +114,8 @@ get_frame_color() const { */ INLINE void TextNode:: set_card_border(PN_stdfloat size, PN_stdfloat uv_portion) { - if (!has_card_border() || _card_border_size != size || _card_border_uv_portion != uv_portion) { + MutexHolder holder(_lock); + if ((_flags & F_has_card_border) == 0 || _card_border_size != size || _card_border_uv_portion != uv_portion) { _flags |= F_has_card_border; _card_border_size = size; _card_border_uv_portion = uv_portion; @@ -120,7 +128,8 @@ set_card_border(PN_stdfloat size, PN_stdfloat uv_portion) { */ INLINE void TextNode:: clear_card_border() { - if (has_card_border()) { + MutexHolder holder(_lock); + if (_flags & F_has_card_border) { _flags &= ~F_has_card_border; invalidate_no_measure(); } @@ -131,6 +140,7 @@ clear_card_border() { */ INLINE PN_stdfloat TextNode:: get_card_border_size() const { + MutexHolder holder(_lock); return _card_border_size; } @@ -139,6 +149,7 @@ get_card_border_size() const { */ INLINE PN_stdfloat TextNode:: get_card_border_uv_portion() const { + MutexHolder holder(_lock); return _card_border_uv_portion; } @@ -147,6 +158,7 @@ get_card_border_uv_portion() const { */ INLINE bool TextNode:: has_card_border() const { + MutexHolder holder(_lock); return (_flags & F_has_card_border) != 0; } @@ -163,6 +175,7 @@ set_card_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a) { */ INLINE void TextNode:: set_card_color(const LColor &card_color) { + MutexHolder holder(_lock); if (_card_color != card_color) { _card_color = card_color; invalidate_no_measure(); @@ -174,6 +187,7 @@ set_card_color(const LColor &card_color) { */ INLINE LColor TextNode:: get_card_color() const { + MutexHolder holder(_lock); return _card_color; } @@ -185,7 +199,8 @@ set_card_texture(Texture *card_texture) { if (card_texture == nullptr) { clear_card_texture(); } else { - if (!has_card_texture() || _card_texture != card_texture) { + MutexHolder holder(_lock); + if ((_flags & F_has_card_texture) == 0 || _card_texture != card_texture) { _flags |= F_has_card_texture; _card_texture = card_texture; invalidate_no_measure(); @@ -198,7 +213,8 @@ set_card_texture(Texture *card_texture) { */ INLINE void TextNode:: clear_card_texture() { - if (has_card_texture()) { + MutexHolder holder(_lock); + if (_flags & F_has_card_texture) { _flags &= ~F_has_card_texture; _card_texture = nullptr; invalidate_no_measure(); @@ -210,6 +226,7 @@ clear_card_texture() { */ INLINE bool TextNode:: has_card_texture() const { + MutexHolder holder(_lock); return (_flags & F_has_card_texture) != 0; } @@ -218,6 +235,7 @@ has_card_texture() const { */ INLINE Texture *TextNode:: get_card_texture() const { + MutexHolder holder(_lock); return _card_texture; } @@ -229,6 +247,7 @@ get_card_texture() const { */ INLINE void TextNode:: set_frame_as_margin(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) { + MutexHolder holder(_lock); _flags |= (F_has_frame | F_frame_as_margin); _frame_ul.set(left, top); _frame_lr.set(right, bottom); @@ -243,6 +262,7 @@ set_frame_as_margin(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_ */ INLINE void TextNode:: set_frame_actual(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) { + MutexHolder holder(_lock); _flags |= F_has_frame; _flags &= ~F_frame_as_margin; _frame_ul.set(left, top); @@ -255,6 +275,7 @@ set_frame_actual(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_std */ INLINE void TextNode:: clear_frame() { + MutexHolder holder(_lock); _flags &= ~F_has_frame; invalidate_no_measure(); } @@ -264,6 +285,7 @@ clear_frame() { */ INLINE bool TextNode:: has_frame() const { + MutexHolder holder(_lock); return (_flags & F_has_frame) != 0; } @@ -276,7 +298,8 @@ has_frame() const { */ INLINE bool TextNode:: is_frame_as_margin() const { - nassertr(has_frame(), false); + MutexHolder holder(_lock); + nassertr((_flags & F_has_frame) != 0, false); return (_flags & F_frame_as_margin) != 0; } @@ -288,7 +311,8 @@ is_frame_as_margin() const { */ INLINE LVecBase4 TextNode:: get_frame_as_set() const { - nassertr(has_frame(), LVecBase4(0.0, 0.0, 0.0, 0.0)); + MutexHolder holder(_lock); + nassertr((_flags & F_has_frame) != 0, LVecBase4(0.0, 0.0, 0.0, 0.0)); return LVecBase4(_frame_ul[0], _frame_lr[0], _frame_lr[1], _frame_ul[1]); } @@ -303,18 +327,20 @@ get_frame_as_set() const { */ INLINE LVecBase4 TextNode:: get_frame_actual() const { - if (!has_frame()) { + MutexHolder holder(_lock); + if (_flags & F_has_frame) { + if (_flags & F_frame_as_margin) { + check_measure(); + return LVecBase4(_text_ul[0] - _frame_ul[0], + _text_lr[0] + _frame_lr[0], + _text_lr[1] - _frame_lr[1], + _text_ul[1] + _frame_ul[1]); + } else { + return LVecBase4(_frame_ul[0], _frame_lr[0], _frame_lr[1], _frame_ul[1]); + } + } else { check_measure(); return LVecBase4(_text_ul[0], _text_lr[0], _text_lr[1], _text_ul[1]); - - } else if (is_frame_as_margin()) { - check_measure(); - return LVecBase4(_text_ul[0] - _frame_ul[0], - _text_lr[0] + _frame_lr[0], - _text_lr[1] - _frame_lr[1], - _text_ul[1] + _frame_ul[1]); - } else { - return get_frame_as_set(); } } @@ -323,6 +349,7 @@ get_frame_actual() const { */ INLINE void TextNode:: set_frame_line_width(PN_stdfloat frame_width) { + MutexHolder holder(_lock); _frame_width = frame_width; invalidate_no_measure(); } @@ -332,6 +359,7 @@ set_frame_line_width(PN_stdfloat frame_width) { */ INLINE PN_stdfloat TextNode:: get_frame_line_width() const { + MutexHolder holder(_lock); return _frame_width; } @@ -342,6 +370,7 @@ get_frame_line_width() const { */ INLINE void TextNode:: set_frame_corners(bool corners) { + MutexHolder holder(_lock); if (corners) { _flags |= F_frame_corners; } else { @@ -355,6 +384,7 @@ set_frame_corners(bool corners) { */ INLINE bool TextNode:: get_frame_corners() const { + MutexHolder holder(_lock); return (_flags & F_frame_corners) != 0; } @@ -366,6 +396,7 @@ get_frame_corners() const { */ INLINE void TextNode:: set_card_as_margin(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) { + MutexHolder holder(_lock); _flags |= (F_has_card | F_card_as_margin); _card_ul.set(left, top); _card_lr.set(right, bottom); @@ -380,6 +411,7 @@ set_card_as_margin(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_s */ INLINE void TextNode:: set_card_actual(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdfloat top) { + MutexHolder holder(_lock); _flags |= F_has_card; _flags &= ~F_card_as_margin; _card_ul.set(left, top); @@ -394,6 +426,7 @@ set_card_actual(PN_stdfloat left, PN_stdfloat right, PN_stdfloat bottom, PN_stdf */ INLINE void TextNode:: set_card_decal(bool card_decal) { + MutexHolder holder(_lock); if (card_decal) { _flags |= F_card_decal; } else { @@ -407,6 +440,7 @@ set_card_decal(bool card_decal) { */ INLINE void TextNode:: clear_card() { + MutexHolder holder(_lock); _flags &= ~F_has_card; invalidate_no_measure(); } @@ -416,6 +450,7 @@ clear_card() { */ INLINE bool TextNode:: has_card() const { + MutexHolder holder(_lock); return (_flags & F_has_card) != 0; } @@ -424,6 +459,7 @@ has_card() const { */ INLINE bool TextNode:: get_card_decal() const { + MutexHolder holder(_lock); return (_flags & F_card_decal) != 0; } @@ -436,7 +472,8 @@ get_card_decal() const { */ INLINE bool TextNode:: is_card_as_margin() const { - nassertr(has_card(), false); + MutexHolder holder(_lock); + nassertr((_flags & F_has_card) != 0, false); return (_flags & F_card_as_margin) != 0; } @@ -448,7 +485,8 @@ is_card_as_margin() const { */ INLINE LVecBase4 TextNode:: get_card_as_set() const { - nassertr(has_card(), LVecBase4(0.0, 0.0, 0.0, 0.0)); + MutexHolder holder(_lock); + nassertr((_flags & F_has_card) != 0, LVecBase4(0.0, 0.0, 0.0, 0.0)); return LVecBase4(_card_ul[0], _card_lr[0], _card_lr[1], _card_ul[1]); } @@ -463,18 +501,20 @@ get_card_as_set() const { */ INLINE LVecBase4 TextNode:: get_card_actual() const { - if (!has_card()) { + MutexHolder holder(_lock); + if (_flags & F_has_card) { + if (_flags & F_card_as_margin) { + check_measure(); + return LVecBase4(_text_ul[0] - _card_ul[0], + _text_lr[0] + _card_lr[0], + _text_lr[1] - _card_lr[1], + _text_ul[1] + _card_ul[1]); + } else { + return LVecBase4(_card_ul[0], _card_lr[0], _card_lr[1], _card_ul[1]); + } + } else { check_measure(); return LVecBase4(_text_ul[0], _text_lr[0], _text_lr[1], _text_ul[1]); - - } else if (is_card_as_margin()) { - check_measure(); - return LVecBase4(_text_ul[0] - _card_ul[0], - _text_lr[0] + _card_lr[0], - _text_lr[1] - _card_lr[1], - _text_ul[1] + _card_ul[1]); - } else { - return get_card_as_set(); } } @@ -487,6 +527,8 @@ get_card_actual() const { INLINE LVecBase4 TextNode:: get_card_transformed() const { LVecBase4 card = get_card_actual(); + + MutexHolder holder(_lock); LPoint3 ul = LPoint3(card[0], 0.0, card[3]) * _transform; LPoint3 lr = LPoint3(card[1], 0.0, card[2]) * _transform; @@ -498,6 +540,7 @@ get_card_transformed() const { */ INLINE void TextNode:: set_transform(const LMatrix4 &transform) { + MutexHolder holder(_lock); _transform = transform; invalidate_with_measure(); } @@ -507,6 +550,7 @@ set_transform(const LMatrix4 &transform) { */ INLINE LMatrix4 TextNode:: get_transform() const { + MutexHolder holder(_lock); return _transform; } @@ -515,6 +559,7 @@ get_transform() const { */ INLINE void TextNode:: set_coordinate_system(CoordinateSystem coordinate_system) { + MutexHolder holder(_lock); _coordinate_system = coordinate_system; invalidate_with_measure(); } @@ -524,6 +569,7 @@ set_coordinate_system(CoordinateSystem coordinate_system) { */ INLINE CoordinateSystem TextNode:: get_coordinate_system() const { + MutexHolder holder(_lock); return _coordinate_system; } @@ -535,6 +581,7 @@ get_coordinate_system() const { */ INLINE void TextNode:: set_usage_hint(Geom::UsageHint usage_hint) { + MutexHolder holder(_lock); _usage_hint = usage_hint; invalidate_no_measure(); } @@ -545,6 +592,7 @@ set_usage_hint(Geom::UsageHint usage_hint) { */ INLINE Geom::UsageHint TextNode:: get_usage_hint() const { + MutexHolder holder(_lock); return _usage_hint; } @@ -585,6 +633,7 @@ get_usage_hint() const { */ INLINE void TextNode:: set_flatten_flags(int flatten_flags) { + MutexHolder holder(_lock); _flatten_flags = flatten_flags; } @@ -593,6 +642,7 @@ set_flatten_flags(int flatten_flags) { */ INLINE int TextNode:: get_flatten_flags() const { + MutexHolder holder(_lock); return _flatten_flags; } @@ -602,6 +652,7 @@ get_flatten_flags() const { */ INLINE void TextNode:: set_font(TextFont *font) { + MutexHolder holder(_lock); TextProperties::set_font(font); invalidate_with_measure(); } @@ -611,6 +662,7 @@ set_font(TextFont *font) { */ INLINE void TextNode:: clear_font() { + MutexHolder holder(_lock); TextProperties::clear_font(); invalidate_with_measure(); } @@ -631,6 +683,7 @@ clear_font() { */ INLINE void TextNode:: set_small_caps(bool small_caps) { + MutexHolder holder(_lock); TextProperties::set_small_caps(small_caps); invalidate_with_measure(); } @@ -640,6 +693,7 @@ set_small_caps(bool small_caps) { */ INLINE void TextNode:: clear_small_caps() { + MutexHolder holder(_lock); TextProperties::clear_small_caps(); invalidate_with_measure(); } @@ -651,6 +705,7 @@ clear_small_caps() { */ INLINE void TextNode:: set_small_caps_scale(PN_stdfloat small_caps_scale) { + MutexHolder holder(_lock); TextProperties::set_small_caps_scale(small_caps_scale); invalidate_with_measure(); } @@ -660,6 +715,7 @@ set_small_caps_scale(PN_stdfloat small_caps_scale) { */ INLINE void TextNode:: clear_small_caps_scale() { + MutexHolder holder(_lock); TextProperties::clear_small_caps_scale(); invalidate_with_measure(); } @@ -669,6 +725,7 @@ clear_small_caps_scale() { */ INLINE void TextNode:: set_slant(PN_stdfloat slant) { + MutexHolder holder(_lock); TextProperties::set_slant(slant); invalidate_with_measure(); } @@ -678,6 +735,7 @@ set_slant(PN_stdfloat slant) { */ INLINE void TextNode:: clear_slant() { + MutexHolder holder(_lock); TextProperties::clear_slant(); invalidate_with_measure(); } @@ -687,6 +745,7 @@ clear_slant() { */ INLINE void TextNode:: set_align(TextNode::Alignment align_type) { + MutexHolder holder(_lock); TextProperties::set_align(align_type); invalidate_with_measure(); } @@ -696,6 +755,7 @@ set_align(TextNode::Alignment align_type) { */ INLINE void TextNode:: clear_align() { + MutexHolder holder(_lock); TextProperties::clear_align(); invalidate_with_measure(); } @@ -706,6 +766,7 @@ clear_align() { */ INLINE void TextNode:: set_indent(PN_stdfloat indent) { + MutexHolder holder(_lock); TextProperties::set_indent(indent); invalidate_with_measure(); } @@ -715,6 +776,7 @@ set_indent(PN_stdfloat indent) { */ INLINE void TextNode:: clear_indent() { + MutexHolder holder(_lock); TextProperties::clear_indent(); invalidate_with_measure(); } @@ -725,6 +787,7 @@ clear_indent() { */ INLINE void TextNode:: set_wordwrap(PN_stdfloat wordwrap) { + MutexHolder holder(_lock); TextProperties::set_wordwrap(wordwrap); invalidate_with_measure(); } @@ -735,6 +798,7 @@ set_wordwrap(PN_stdfloat wordwrap) { */ INLINE void TextNode:: clear_wordwrap() { + MutexHolder holder(_lock); TextProperties::clear_wordwrap(); invalidate_with_measure(); } @@ -744,6 +808,7 @@ clear_wordwrap() { */ INLINE void TextNode:: set_text_color(const LColor &text_color) { + MutexHolder holder(_lock); TextProperties::set_text_color(text_color); invalidate_no_measure(); } @@ -762,6 +827,7 @@ set_text_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a) { */ INLINE void TextNode:: clear_text_color() { + MutexHolder holder(_lock); TextProperties::clear_text_color(); invalidate_no_measure(); } @@ -779,6 +845,7 @@ set_shadow_color(PN_stdfloat r, PN_stdfloat g, PN_stdfloat b, PN_stdfloat a) { */ INLINE void TextNode:: set_shadow_color(const LColor &shadow_color) { + MutexHolder holder(_lock); TextProperties::set_shadow_color(shadow_color); invalidate_no_measure(); } @@ -788,6 +855,7 @@ set_shadow_color(const LColor &shadow_color) { */ INLINE void TextNode:: clear_shadow_color() { + MutexHolder holder(_lock); TextProperties::clear_shadow_color(); invalidate_with_measure(); } @@ -807,6 +875,7 @@ set_shadow(PN_stdfloat xoffset, PN_stdfloat yoffset) { */ INLINE void TextNode:: set_shadow(const LVecBase2 &shadow_offset) { + MutexHolder holder(_lock); TextProperties::set_shadow(shadow_offset); invalidate_no_measure(); } @@ -816,6 +885,7 @@ set_shadow(const LVecBase2 &shadow_offset) { */ INLINE void TextNode:: clear_shadow() { + MutexHolder holder(_lock); TextProperties::clear_shadow(); invalidate_no_measure(); } @@ -831,6 +901,7 @@ clear_shadow() { */ INLINE void TextNode:: set_bin(const std::string &bin) { + MutexHolder holder(_lock); TextProperties::set_bin(bin); invalidate_no_measure(); } @@ -841,6 +912,7 @@ set_bin(const std::string &bin) { */ INLINE void TextNode:: clear_bin() { + MutexHolder holder(_lock); TextProperties::clear_bin(); invalidate_no_measure(); } @@ -858,6 +930,7 @@ clear_bin() { */ INLINE int TextNode:: set_draw_order(int draw_order) { + MutexHolder holder(_lock); invalidate_no_measure(); return TextProperties::set_draw_order(draw_order); } @@ -867,6 +940,7 @@ set_draw_order(int draw_order) { */ INLINE void TextNode:: clear_draw_order() { + MutexHolder holder(_lock); TextProperties::clear_draw_order(); invalidate_with_measure(); } @@ -877,6 +951,7 @@ clear_draw_order() { */ INLINE void TextNode:: set_tab_width(PN_stdfloat tab_width) { + MutexHolder holder(_lock); TextProperties::set_tab_width(tab_width); invalidate_with_measure(); } @@ -886,6 +961,7 @@ set_tab_width(PN_stdfloat tab_width) { */ INLINE void TextNode:: clear_tab_width() { + MutexHolder holder(_lock); TextProperties::clear_tab_width(); invalidate_with_measure(); } @@ -897,6 +973,7 @@ clear_tab_width() { */ INLINE void TextNode:: set_glyph_scale(PN_stdfloat glyph_scale) { + MutexHolder holder(_lock); TextProperties::set_glyph_scale(glyph_scale); invalidate_with_measure(); } @@ -906,6 +983,7 @@ set_glyph_scale(PN_stdfloat glyph_scale) { */ INLINE void TextNode:: clear_glyph_scale() { + MutexHolder holder(_lock); TextProperties::clear_glyph_scale(); invalidate_with_measure(); } @@ -917,6 +995,7 @@ clear_glyph_scale() { */ INLINE void TextNode:: set_glyph_shift(PN_stdfloat glyph_shift) { + MutexHolder holder(_lock); TextProperties::set_glyph_shift(glyph_shift); invalidate_with_measure(); } @@ -926,6 +1005,7 @@ set_glyph_shift(PN_stdfloat glyph_shift) { */ INLINE void TextNode:: clear_glyph_shift() { + MutexHolder holder(_lock); TextProperties::clear_glyph_shift(); invalidate_with_measure(); } @@ -936,6 +1016,7 @@ clear_glyph_shift() { */ INLINE void TextNode:: set_text(const std::string &text) { + MutexHolder holder(_lock); TextEncoder::set_text(text); invalidate_with_measure(); } @@ -948,6 +1029,7 @@ set_text(const std::string &text) { */ INLINE void TextNode:: set_text(const std::string &text, TextNode::Encoding encoding) { + MutexHolder holder(_lock); TextEncoder::set_text(text, encoding); invalidate_with_measure(); } @@ -957,6 +1039,7 @@ set_text(const std::string &text, TextNode::Encoding encoding) { */ INLINE void TextNode:: clear_text() { + MutexHolder holder(_lock); TextEncoder::clear_text(); invalidate_with_measure(); } @@ -966,6 +1049,7 @@ clear_text() { */ INLINE void TextNode:: append_text(const std::string &text) { + MutexHolder holder(_lock); TextEncoder::append_text(text); invalidate_with_measure(); } @@ -976,6 +1060,7 @@ append_text(const std::string &text) { */ INLINE void TextNode:: append_unicode_char(wchar_t character) { + MutexHolder holder(_lock); TextEncoder::append_unicode_char(character); invalidate_with_measure(); } @@ -1008,6 +1093,7 @@ calc_width(const std::string &line) const { */ INLINE void TextNode:: set_wtext(const std::wstring &wtext) { + MutexHolder holder(_lock); TextEncoder::set_wtext(wtext); invalidate_with_measure(); } @@ -1017,6 +1103,7 @@ set_wtext(const std::wstring &wtext) { */ INLINE void TextNode:: append_wtext(const std::wstring &wtext) { + MutexHolder holder(_lock); TextEncoder::append_wtext(wtext); invalidate_with_measure(); } @@ -1030,6 +1117,7 @@ append_wtext(const std::wstring &wtext) { */ INLINE std::wstring TextNode:: get_wordwrapped_wtext() const { + MutexHolder holder(_lock); check_measure(); return _wordwrapped_wtext; } @@ -1040,6 +1128,7 @@ get_wordwrapped_wtext() const { */ INLINE PN_stdfloat TextNode:: get_left() const { + MutexHolder holder(_lock); check_measure(); return _text_ul[0]; } @@ -1050,6 +1139,7 @@ get_left() const { */ INLINE PN_stdfloat TextNode:: get_right() const { + MutexHolder holder(_lock); check_measure(); return _text_lr[0]; } @@ -1060,6 +1150,7 @@ get_right() const { */ INLINE PN_stdfloat TextNode:: get_bottom() const { + MutexHolder holder(_lock); check_measure(); return _text_lr[1]; } @@ -1070,6 +1161,7 @@ get_bottom() const { */ INLINE PN_stdfloat TextNode:: get_top() const { + MutexHolder holder(_lock); check_measure(); return _text_ul[1]; } @@ -1079,6 +1171,7 @@ get_top() const { */ INLINE PN_stdfloat TextNode:: get_height() const { + MutexHolder holder(_lock); check_measure(); return _text_ul[1] - _text_lr[1]; } @@ -1088,6 +1181,7 @@ get_height() const { */ INLINE PN_stdfloat TextNode:: get_width() const { + MutexHolder holder(_lock); check_measure(); return _text_lr[0] - _text_ul[0]; } @@ -1098,6 +1192,7 @@ get_width() const { */ INLINE LPoint3 TextNode:: get_upper_left_3d() const { + MutexHolder holder(_lock); check_measure(); return _ul3d; } @@ -1108,6 +1203,7 @@ get_upper_left_3d() const { */ INLINE LPoint3 TextNode:: get_lower_right_3d() const { + MutexHolder holder(_lock); check_measure(); return _lr3d; } @@ -1118,10 +1214,22 @@ get_lower_right_3d() const { */ INLINE int TextNode:: get_num_rows() const { + MutexHolder holder(_lock); check_measure(); return _num_rows; } +/** + * 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() { + MutexHolder holder(_lock); + return do_generate(); +} + /** * Can be called after the TextNode has been fully configured, to force the * node to recompute its text immediately, rather than waiting for it to be @@ -1129,6 +1237,7 @@ get_num_rows() const { */ INLINE void TextNode:: update() { + MutexHolder holder(_lock); check_rebuild(); } @@ -1140,8 +1249,9 @@ update() { */ INLINE void TextNode:: force_update() { - invalidate_with_measure(); - check_rebuild(); + MutexHolder holder(_lock); + mark_internal_bounds_stale(); + do_rebuild(); } /** diff --git a/panda/src/text/textNode.cxx b/panda/src/text/textNode.cxx index a68ebba812..1ecfc1ea65 100644 --- a/panda/src/text/textNode.cxx +++ b/panda/src/text/textNode.cxx @@ -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); @@ -277,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)"; @@ -291,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) @@ -301,13 +302,263 @@ write(std::ostream &out, int indent_level) const { << "text is " << get_text() << "\n"; } +/** + * Returns the actual node that is used internally to render the text, if the + * TextNode is parented within the scene graph. + * + * In general, you should not call this method. Call generate() instead if + * you want to get a handle to geometry that represents the text. This method + * is provided as a debugging aid only. + */ +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"; + return do_get_internal_geom(); +} + +/** + * Returns the union of all attributes from SceneGraphReducer::AttribTypes + * that may not safely be applied to the vertices of this node. If this is + * nonzero, these attributes must be dropped at this node as a state change. + * + * This is a generalization of safe_to_transform(). + */ +int TextNode:: +get_unsafe_to_apply_attribs() const { + // We have no way to apply these kinds of attributes to our TextNode, so + // insist they get dropped into the PandaNode's basic state. + return + SceneGraphReducer::TT_tex_matrix | + SceneGraphReducer::TT_other; +} + +/** + * Applies whatever attributes are specified in the AccumulatedAttribs object + * (and by the attrib_types bitmask) to the vertices on this node, if + * appropriate. If this node uses geom arrays like a GeomNode, the supplied + * GeomTransformer may be used to unify shared arrays across multiple + * different nodes. + * + * This is a generalization of xform(). + */ +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; + + if ((_flags & F_needs_measure) == 0) { + // If we already have a measure, transform it too. We don't need to + // invalidate the 2-d parts, since that's not affected by the transform + // anyway. + _ul3d = _ul3d * mat; + _lr3d = _lr3d * mat; + } + } + if ((attrib_types & SceneGraphReducer::TT_color) != 0) { + if (attribs._color != nullptr) { + const ColorAttrib *ca = DCAST(ColorAttrib, attribs._color); + if (ca->get_color_type() == ColorAttrib::T_flat) { + const LColor &c = ca->get_color(); + TextProperties::set_text_color(c); + TextProperties::set_shadow_color(c); + _frame_color = c; + _card_color = c; + invalidate_no_measure(); + } + } + } + if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) { + if (attribs._color_scale != nullptr) { + const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attribs._color_scale); + const LVecBase4 &s = csa->get_scale(); + if (s != LVecBase4(1.0f, 1.0f, 1.0f, 1.0f)) { + LVecBase4 tc = get_text_color(); + tc.componentwise_mult(s); + TextProperties::set_text_color(tc); + + LVecBase4 sc = get_shadow_color(); + sc.componentwise_mult(s); + TextProperties::set_shadow_color(sc); + + _frame_color.componentwise_mult(s); + _card_color.componentwise_mult(s); + + invalidate_no_measure(); + } + } + } + + // Now propagate the attributes down to our already-generated geometry, if + // we have any. + if ((_flags & F_needs_rebuild) == 0 && + _internal_geom != nullptr) { + SceneGraphReducer gr; + gr.apply_attribs(_internal_geom, attribs, attrib_types, transformer); + } +} + +/** + * This is used to support NodePath::calc_tight_bounds(). It is not intended + * to be called directly, and it has nothing to do with the normal Panda + * bounding-volume computation. + * + * If the node contains any geometry, this updates min_point and max_point to + * enclose its bounding box. found_any is to be set true if the node has any + * geometry at all, or left alone if it has none. This method may be called + * over several nodes, so it may enter with min_point, max_point, and + * found_any already set. + */ +CPT(TransformState) TextNode:: +calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any, + const TransformState *transform, Thread *current_thread) const { + CPT(TransformState) next_transform = + PandaNode::calc_tight_bounds(min_point, max_point, found_any, 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; +} + +/** + * This function will be called during the cull traversal to perform any + * additional operations that should be performed at cull time. This may + * include additional manipulation of render state or additional + * visible/invisible decisions, or any other arbitrary operation. + * + * Note that this function will *not* be called unless set_cull_callback() is + * called in the constructor of the derived class. It is necessary to call + * set_cull_callback() to indicated that we require cull_callback() to be + * called. + * + * By the time this function is called, the node has already passed the + * bounding-volume test for the viewing frustum, and the node's transform and + * state have already been applied to the indicated CullTraverserData object. + * + * The return value is true if this node should be visible, or false if it + * should be culled. + */ +bool TextNode:: +cull_callback(CullTraverser *trav, CullTraverserData &data) { + + PT(PandaNode) internal_geom = do_get_internal_geom(); + if (internal_geom != nullptr) { + // Render the text with this node. + CullTraverserData next_data(data, internal_geom); + trav->traverse(next_data); + } + + // Now continue to render everything else below this node. + return true; +} + +/** + * Returns true if there is some value to visiting this particular node during + * the cull traversal for any camera, false otherwise. This will be used to + * optimize the result of get_net_draw_show_mask(), so that any subtrees that + * contain only nodes for which is_renderable() is false need not be visited. + */ +bool TextNode:: +is_renderable() const { + return true; +} + +/** + * Called when needed to recompute the node's _internal_bound object. Nodes + * that contain anything of substance should redefine this to do the right + * thing. + */ +void TextNode:: +compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, + int &internal_vertices, + int pipeline_stage, + Thread *current_thread) const { + // First, get ourselves a fresh, empty bounding volume. + PT(BoundingVolume) bound = new BoundingSphere; + + GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound); + + // Now enclose the bounding box around the text. We can do this without + // actually generating the text, if we have at least measured it. + LPoint3 vertices[8]; + { + 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); + + internal_bounds = bound; + internal_vertices = 0; // TODO: estimate this better. +} + +/** + * The recursive implementation of prepare_scene(). Don't call this directly; + * call PandaNode::prepare_scene() or NodePath::prepare_scene() instead. + */ +void TextNode:: +r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, + GeomTransformer &transformer, Thread *current_thread) { + + 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); + } + + PandaNode::r_prepare_scene(gsg, node_state, transformer, current_thread); +} + +/** + * Removes any existing children of the TextNode, and adds the newly generated + * text instead. + */ +void TextNode:: +do_rebuild() { + nassertv(_lock.debug_is_locked()); + _flags &= ~(F_needs_rebuild | F_needs_measure); + _internal_geom = do_generate(); +} + + +/** + * Can be called in lieu of do_rebuild() to measure the text and set up the + * bounding boxes properly without actually assembling it. + */ +void TextNode:: +do_measure() { + // We no longer make this a special case. + 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:: -generate() { +do_generate() { + nassertr(_lock.debug_is_locked(), nullptr); + PStatTimer timer(_text_generate_pcollector); if (text_cat.is_debug()) { text_cat.debug() @@ -408,20 +659,20 @@ generate() { // Now deal with the decorations. - if (has_card()) { + if (_flags & F_has_card) { PT(PandaNode) card_root; - if (has_card_border()) { + 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(get_card_color())); - if (get_card_color()[3] != 1.0f) { + 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 (has_card_texture()) { - card_root->set_attrib(TextureAttrib::make(get_card_texture())); + if (_flags & F_has_card_texture) { + card_root->set_attrib(TextureAttrib::make(_card_texture)); } if (has_bin()) { @@ -437,17 +688,17 @@ generate() { card_root->add_child(root); root = card_root; - if (get_card_decal()) { + if (_flags & F_card_decal) { card_root->set_effect(DecalEffect::make()); } } - if (has_frame()) { + 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(get_frame_color())); - if (get_frame_color()[3] != 1.0f) { + frame_root->set_attrib(ColorAttrib::make_flat(_frame_color)); + if (_frame_color[3] != 1.0f) { frame_root->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha)); } @@ -465,271 +716,35 @@ generate() { /** * Returns the actual node that is used internally to render the text, if the * TextNode is parented within the scene graph. - * - * In general, you should not call this method. Call generate() instead if - * you want to get a handle to geometry that represents the text. This method - * is provided as a debugging aid only. */ -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"; +PT(PandaNode) TextNode:: +do_get_internal_geom() const { + MutexHolder holder(_lock); check_rebuild(); return _internal_geom; } -/** - * Returns the union of all attributes from SceneGraphReducer::AttribTypes - * that may not safely be applied to the vertices of this node. If this is - * nonzero, these attributes must be dropped at this node as a state change. - * - * This is a generalization of safe_to_transform(). - */ -int TextNode:: -get_unsafe_to_apply_attribs() const { - // We have no way to apply these kinds of attributes to our TextNode, so - // insist they get dropped into the PandaNode's basic state. - return - SceneGraphReducer::TT_tex_matrix | - SceneGraphReducer::TT_other; -} - -/** - * Applies whatever attributes are specified in the AccumulatedAttribs object - * (and by the attrib_types bitmask) to the vertices on this node, if - * appropriate. If this node uses geom arrays like a GeomNode, the supplied - * GeomTransformer may be used to unify shared arrays across multiple - * different nodes. - * - * This is a generalization of xform(). - */ -void TextNode:: -apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types, - GeomTransformer &transformer) { - if ((attrib_types & SceneGraphReducer::TT_transform) != 0) { - const LMatrix4 &mat = attribs._transform->get_mat(); - _transform *= mat; - - if ((_flags & F_needs_measure) == 0) { - // If we already have a measure, transform it too. We don't need to - // invalidate the 2-d parts, since that's not affected by the transform - // anyway. - _ul3d = _ul3d * mat; - _lr3d = _lr3d * mat; - } - } - if ((attrib_types & SceneGraphReducer::TT_color) != 0) { - if (attribs._color != nullptr) { - 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); - } - } - } - if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) { - if (attribs._color_scale != nullptr) { - const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attribs._color_scale); - 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); - 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); - } - } - } - - // Now propagate the attributes down to our already-generated geometry, if - // we have any. - if ((_flags & F_needs_rebuild) == 0 && - _internal_geom != nullptr) { - SceneGraphReducer gr; - gr.apply_attribs(_internal_geom, attribs, attrib_types, transformer); - } -} - -/** - * This is used to support NodePath::calc_tight_bounds(). It is not intended - * to be called directly, and it has nothing to do with the normal Panda - * bounding-volume computation. - * - * If the node contains any geometry, this updates min_point and max_point to - * enclose its bounding box. found_any is to be set true if the node has any - * geometry at all, or left alone if it has none. This method may be called - * over several nodes, so it may enter with min_point, max_point, and - * found_any already set. - */ -CPT(TransformState) TextNode:: -calc_tight_bounds(LPoint3 &min_point, LPoint3 &max_point, bool &found_any, - const TransformState *transform, Thread *current_thread) const { - CPT(TransformState) next_transform = - 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); - } - - return next_transform; -} - -/** - * This function will be called during the cull traversal to perform any - * additional operations that should be performed at cull time. This may - * include additional manipulation of render state or additional - * visible/invisible decisions, or any other arbitrary operation. - * - * Note that this function will *not* be called unless set_cull_callback() is - * called in the constructor of the derived class. It is necessary to call - * set_cull_callback() to indicated that we require cull_callback() to be - * called. - * - * By the time this function is called, the node has already passed the - * bounding-volume test for the viewing frustum, and the node's transform and - * state have already been applied to the indicated CullTraverserData object. - * - * The return value is true if this node should be visible, or false if it - * should be culled. - */ -bool TextNode:: -cull_callback(CullTraverser *trav, CullTraverserData &data) { - check_rebuild(); - if (_internal_geom != nullptr) { - // Render the text with this node. - CullTraverserData next_data(data, _internal_geom); - trav->traverse(next_data); - } - - // Now continue to render everything else below this node. - return true; -} - -/** - * Returns true if there is some value to visiting this particular node during - * the cull traversal for any camera, false otherwise. This will be used to - * optimize the result of get_net_draw_show_mask(), so that any subtrees that - * contain only nodes for which is_renderable() is false need not be visited. - */ -bool TextNode:: -is_renderable() const { - return true; -} - -/** - * Called when needed to recompute the node's _internal_bound object. Nodes - * that contain anything of substance should redefine this to do the right - * thing. - */ -void TextNode:: -compute_internal_bounds(CPT(BoundingVolume) &internal_bounds, - int &internal_vertices, - int pipeline_stage, - Thread *current_thread) const { - // First, get ourselves a fresh, empty bounding volume. - PT(BoundingVolume) bound = new BoundingSphere; - - GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound); - - // 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]); - - gbv->around(vertices, vertices + 8); - - internal_bounds = bound; - internal_vertices = 0; // TODO: estimate this better. -} - -/** - * The recursive implementation of prepare_scene(). Don't call this directly; - * call PandaNode::prepare_scene() or NodePath::prepare_scene() instead. - */ -void TextNode:: -r_prepare_scene(GraphicsStateGuardianBase *gsg, const RenderState *node_state, - GeomTransformer &transformer, Thread *current_thread) { - check_rebuild(); - - PandaNode *child = _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); - } - - PandaNode::r_prepare_scene(gsg, node_state, transformer, current_thread); -} - -/** - * Removes any existing children of the TextNode, and adds the newly generated - * text instead. - */ -void TextNode:: -do_rebuild() { - _flags &= ~(F_needs_rebuild | F_needs_measure); - _internal_geom = generate(); -} - - -/** - * Can be called in lieu of do_rebuild() to measure the text and set up the - * bounding boxes properly without actually assembling it. - */ -void TextNode:: -do_measure() { - // We no longer make this a special case. - do_rebuild(); -} - /** * 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); @@ -753,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); @@ -769,13 +784,22 @@ 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(), _usage_hint); @@ -793,7 +817,7 @@ make_card() { 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(); @@ -812,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 diff --git a/panda/src/text/textNode.h b/panda/src/text/textNode.h index 4f37f806f4..ecf7dcafcf 100644 --- a/panda/src/text/textNode.h +++ b/panda/src/text/textNode.h @@ -24,6 +24,8 @@ #include "pandaNode.h" #include "luse.h" #include "geom.h" +#include "pmutex.h" +#include "mutexHolder.h" /** * The primary interface to this module. This class does basic text assembly; @@ -225,11 +227,11 @@ PUBLISHED: INLINE int get_num_rows() const; - PT(PandaNode) generate(); + INLINE PT(PandaNode) generate(); INLINE void update(); INLINE void force_update(); - PandaNode *get_internal_geom() const; + PT(PandaNode) get_internal_geom() const; PUBLISHED: MAKE_PROPERTY(max_rows, get_max_rows, set_max_rows); @@ -312,12 +314,16 @@ private: void do_rebuild(); void do_measure(); + PT(PandaNode) do_generate(); + PT(PandaNode) do_get_internal_geom() const; + PT(PandaNode) make_frame(); PT(PandaNode) make_card(); PT(PandaNode) make_card_with_border(); static int count_geoms(PandaNode *node); + Mutex _lock; PT(PandaNode) _internal_geom; PT(Texture) _card_texture;