00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "textNode.h"
00020 #include "textGlyph.h"
00021 #include "stringDecoder.h"
00022 #include "config_text.h"
00023 #include "fontPool.h"
00024 #include "default_font.h"
00025 #include "dynamicTextFont.h"
00026 #include "unicodeLatinMap.h"
00027
00028 #include "compose_matrix.h"
00029 #include "geom.h"
00030 #include "geomTristrip.h"
00031 #include "geomLinestrip.h"
00032 #include "geomPoint.h"
00033 #include "geomNode.h"
00034 #include "notify.h"
00035 #include "transformState.h"
00036 #include "colorAttrib.h"
00037 #include "colorScaleAttrib.h"
00038 #include "cullBinAttrib.h"
00039 #include "textureAttrib.h"
00040 #include "transparencyAttrib.h"
00041 #include "sceneGraphReducer.h"
00042 #include "indent.h"
00043 #include "cullTraverser.h"
00044 #include "cullTraverserData.h"
00045 #include "geometricBoundingVolume.h"
00046 #include "accumulatedAttribs.h"
00047 #include "renderState.h"
00048 #include "cullFaceAttrib.h"
00049 #include "dcast.h"
00050
00051 #include <stdio.h>
00052 #include <ctype.h>
00053
00054 TypeHandle TextNode::_type_handle;
00055
00056 PT(TextFont) TextNode::_default_font;
00057 bool TextNode::_loaded_default_font = false;
00058
00059
00060 static const float small_accent_scale = 0.6f;
00061
00062
00063 static const float tiny_accent_scale = 0.4f;
00064
00065
00066 static const float squash_accent_scale_x = 0.8f;
00067 static const float squash_accent_scale_y = 0.5f;
00068
00069
00070 static const float small_squash_accent_scale_x = 0.6f;
00071 static const float small_squash_accent_scale_y = 0.3f;
00072
00073
00074
00075 static const float ligature_advance_scale = 0.6f;
00076
00077
00078
00079
00080
00081
00082 TextNode::
00083 TextNode(const string &name) : PandaNode(name) {
00084 _slant = 0.0f;
00085
00086 _flags = 0;
00087 _align = A_left;
00088 _wordwrap_width = 1.0f;
00089
00090 if (text_small_caps) {
00091 _flags |= F_small_caps;
00092 }
00093 _small_caps_scale = text_small_caps_scale;
00094
00095 _text_color.set(1.0f, 1.0f, 1.0f, 1.0f);
00096 _frame_color.set(1.0f, 1.0f, 1.0f, 1.0f);
00097 _card_color.set(1.0f, 1.0f, 1.0f, 1.0f);
00098 _shadow_color.set(1.0f, 1.0f, 1.0f, 1.0f);
00099
00100 _frame_width = 1.0f;
00101
00102 _frame_ul.set(0.0f, 0.0f);
00103 _frame_lr.set(0.0f, 0.0f);
00104 _card_ul.set(0.0f, 0.0f);
00105 _card_lr.set(0.0f, 0.0f);
00106 _shadow_offset.set(0.0f, 0.0f);
00107
00108 _draw_order = 1;
00109
00110 _transform = LMatrix4f::ident_mat();
00111 _coordinate_system = CS_default;
00112
00113 _ul2d.set(0.0f, 0.0f);
00114 _lr2d.set(0.0f, 0.0f);
00115 _ul3d.set(0.0f, 0.0f, 0.0f);
00116 _lr3d.set(0.0f, 0.0f, 0.0f);
00117 _num_rows = 0;
00118 }
00119
00120
00121
00122
00123
00124
00125 TextNode::
00126 ~TextNode() {
00127 }
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138 string TextNode::
00139 wordwrap_to(const string &text, float wordwrap_width,
00140 bool preserve_trailing_whitespace) const {
00141 nassertr(_font != (TextFont *)NULL, text);
00142 wstring decoded = decode_text(text);
00143 wstring wrapped =
00144 _font->wordwrap_to(decoded, wordwrap_width, preserve_trailing_whitespace);
00145 return encode_wtext(wrapped);
00146 }
00147
00148
00149
00150
00151
00152
00153
00154 void TextNode::
00155 write(ostream &out, int indent_level) const {
00156 indent(out, indent_level)
00157 << "TextNode " << get_name() << "\n";
00158 if (_font != (TextFont *)NULL) {
00159 indent(out, indent_level + 2)
00160 << "with font " << _font->get_name() << "\n";
00161 }
00162 if (has_text_color()) {
00163 indent(out, indent_level + 2)
00164 << "text color is " << _text_color << "\n";
00165 } else {
00166 indent(out, indent_level + 2)
00167 << "text color is unchanged from source\n";
00168 }
00169 indent(out, indent_level + 2)
00170 << "alignment is ";
00171 switch (_align) {
00172 case A_left:
00173 out << "A_left\n";
00174 break;
00175
00176 case A_right:
00177 out << "A_right\n";
00178 break;
00179
00180 case A_center:
00181 out << "A_center\n";
00182 break;
00183 }
00184
00185 if (has_wordwrap()) {
00186 indent(out, indent_level + 2)
00187 << "Word-wrapping at " << _wordwrap_width << " units.\n";
00188 }
00189
00190 if (has_frame()) {
00191 indent(out, indent_level + 2)
00192 << "frame of color " << _frame_color << " at "
00193 << get_frame_as_set() << " line width " << _frame_width << "\n";
00194 if (get_frame_corners()) {
00195 indent(out, indent_level + 2)
00196 << "frame corners are enabled\n";
00197 }
00198 if (is_frame_as_margin()) {
00199 indent(out, indent_level + 2)
00200 << "frame coordinates are specified as margin; actual frame is:\n"
00201 << get_frame_actual() << "\n";
00202 } else {
00203 indent(out, indent_level + 2)
00204 << "frame coordinates are actual\n";
00205 }
00206 }
00207 if (has_card()) {
00208 indent(out, indent_level + 2)
00209 << "card of color " << _card_color << " at "
00210 << get_card_as_set() << "\n";
00211 if (is_card_as_margin()) {
00212 indent(out, indent_level + 2)
00213 << "card coordinates are specified as margin; actual card is:\n"
00214 << get_card_actual() << "\n";
00215 } else {
00216 indent(out, indent_level + 2)
00217 << "card coordinates are actual\n";
00218 }
00219 }
00220 if (has_shadow()) {
00221 indent(out, indent_level + 2)
00222 << "shadow of color " << _shadow_color << " at "
00223 << _shadow_offset << "\n";
00224 }
00225 if (has_bin()) {
00226 indent(out, indent_level + 2)
00227 << "bin is " << _bin << "\n";
00228 }
00229 indent(out, indent_level + 2)
00230 << "draw order is " << _draw_order << ", "
00231 << _draw_order + 1 << ", " << _draw_order + 2 << "\n";
00232
00233 LVecBase3f scale, hpr, trans;
00234 if (decompose_matrix(_transform, scale, hpr, trans, _coordinate_system)) {
00235 indent(out, indent_level + 2)
00236 << "transform is:\n"
00237 << " scale: " << scale << "\n"
00238 << " hpr: " << hpr << "\n"
00239 << " trans: " << hpr << "\n";
00240 } else {
00241 indent(out, indent_level + 2)
00242 << "transform is:\n" << _transform;
00243 }
00244 indent(out, indent_level + 2)
00245 << "in coordinate system " << _coordinate_system << "\n";
00246
00247 indent(out, indent_level + 2)
00248 << "\ntext is " << get_text() << "\n";
00249 }
00250
00251
00252
00253
00254
00255
00256
00257
00258 PT(PandaNode) TextNode::
00259 generate() {
00260 if (text_cat.is_debug()) {
00261 text_cat.debug()
00262 << "Rebuilding " << *this << " with '" << get_text() << "'\n";
00263 }
00264
00265
00266
00267
00268
00269
00270
00271
00272
00273
00274
00275 _ul2d.set(0.0f, 0.0f);
00276 _lr2d.set(0.0f, 0.0f);
00277 _ul3d.set(0.0f, 0.0f, 0.0f);
00278 _lr3d.set(0.0f, 0.0f, 0.0f);
00279 _num_rows = 0;
00280
00281
00282 PT(PandaNode) root = new PandaNode(get_text());
00283
00284 if (!has_text()) {
00285 return root;
00286 }
00287
00288 TextFont *font = get_font();
00289 if (font == (TextFont *)NULL) {
00290 font = get_default_font();
00291 }
00292
00293 if (font == (TextFont *)NULL) {
00294 return root;
00295 }
00296
00297
00298
00299
00300 LMatrix4f mat =
00301 LMatrix4f::convert_mat(CS_zup_right, _coordinate_system) *
00302 _transform;
00303
00304 root->set_transform(TransformState::make_mat(mat));
00305
00306 wstring wtext = get_wtext();
00307 if (has_wordwrap()) {
00308 wtext = font->wordwrap_to(wtext, _wordwrap_width, false);
00309 }
00310
00311
00312 LVector2f ul, lr;
00313 int num_rows = 0;
00314 PT(PandaNode) text_root =
00315 assemble_text(wtext.begin(), wtext.end(), font,
00316 ul, lr, num_rows);
00317
00318
00319
00320 PT(PandaNode) text = new PandaNode("text");
00321 root->add_child(text, _draw_order + 2);
00322 text->add_child(text_root);
00323
00324 if (has_text_color()) {
00325 text->set_attrib(ColorAttrib::make_flat(_text_color));
00326 if (_text_color[3] != 1.0) {
00327 text->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
00328 }
00329 }
00330
00331 if (has_bin()) {
00332 text->set_attrib(CullBinAttrib::make(_bin, _draw_order + 2));
00333 }
00334
00335
00336
00337 _num_rows = num_rows;
00338 _ul2d = ul;
00339 _lr2d = lr;
00340 _ul3d.set(ul[0], 0.0f, ul[1]);
00341 _lr3d.set(lr[0], 0.0f, lr[1]);
00342
00343 _ul3d = _ul3d * _transform;
00344 _lr3d = _lr3d * _transform;
00345
00346
00347 _flags &= ~F_needs_measure;
00348
00349
00350
00351
00352 if (has_shadow()) {
00353
00354
00355
00356
00357
00358
00359 LMatrix4f offset =
00360 LMatrix4f::translate_mat(_shadow_offset[0], 0.0f, -_shadow_offset[1]);
00361 PT(PandaNode) shadow = new PandaNode("shadow");
00362 root->add_child(shadow, _draw_order + 1);
00363 shadow->add_child(text_root);
00364 shadow->set_transform(TransformState::make_mat(offset));
00365 shadow->set_attrib(ColorAttrib::make_flat(_shadow_color));
00366
00367 if (_shadow_color[3] != 1.0f) {
00368 shadow->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
00369 }
00370
00371 if (has_bin()) {
00372 shadow->set_attrib(CullBinAttrib::make(_bin, _draw_order + 1));
00373 }
00374 }
00375
00376 if (has_frame()) {
00377 PT(PandaNode) frame_root = make_frame();
00378 root->add_child(frame_root, _draw_order + 1);
00379 frame_root->set_attrib(ColorAttrib::make_flat(_frame_color));
00380 if (_frame_color[3] != 1.0f) {
00381 frame_root->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
00382 }
00383
00384 if (has_bin()) {
00385 frame_root->set_attrib(CullBinAttrib::make(_bin, _draw_order + 1));
00386 }
00387 }
00388
00389 if (has_card()) {
00390 PT(PandaNode) card_root;
00391 if (has_card_border())
00392 card_root = make_card_with_border();
00393 else
00394 card_root = make_card();
00395 root->add_child(card_root, _draw_order);
00396 card_root->set_attrib(ColorAttrib::make_flat(_card_color));
00397 if (_card_color[3] != 1.0f) {
00398 card_root->set_attrib(TransparencyAttrib::make(TransparencyAttrib::M_alpha));
00399 }
00400 if (has_card_texture()) {
00401 card_root->set_attrib(TextureAttrib::make(_card_texture));
00402 }
00403
00404 if (has_bin()) {
00405 card_root->set_attrib(CullBinAttrib::make(_bin, _draw_order));
00406 }
00407 }
00408
00409
00410
00411
00412 if (text_flatten) {
00413 SceneGraphReducer gr;
00414 gr.apply_attribs(root);
00415 gr.flatten(root, true);
00416 }
00417
00418 return root;
00419 }
00420
00421
00422
00423
00424
00425
00426
00427
00428
00429
00430
00431
00432 int TextNode::
00433 get_unsafe_to_apply_attribs() const {
00434
00435
00436
00437 return
00438 SceneGraphReducer::TT_tex_matrix |
00439 SceneGraphReducer::TT_other;
00440 }
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451
00452
00453
00454 void TextNode::
00455 apply_attribs_to_vertices(const AccumulatedAttribs &attribs, int attrib_types,
00456 GeomTransformer &transformer) {
00457 if ((attrib_types & SceneGraphReducer::TT_transform) != 0) {
00458 const LMatrix4f &mat = attribs._transform->get_mat();
00459 _transform *= mat;
00460
00461 if ((_flags & F_needs_measure) == 0) {
00462
00463
00464
00465 _ul3d = _ul3d * mat;
00466 _lr3d = _lr3d * mat;
00467 }
00468 }
00469 if ((attrib_types & SceneGraphReducer::TT_color) != 0) {
00470 if (attribs._color != (const RenderAttrib *)NULL) {
00471 const ColorAttrib *ca = DCAST(ColorAttrib, attribs._color);
00472 if (ca->get_color_type() == ColorAttrib::T_flat) {
00473 const Colorf &c = ca->get_color();
00474 _text_color = c;
00475 _frame_color = c;
00476 _card_color = c;
00477 _shadow_color = c;
00478 _flags |= F_has_text_color;
00479 }
00480 }
00481 }
00482 if ((attrib_types & SceneGraphReducer::TT_color_scale) != 0) {
00483 if (attribs._color_scale != (const RenderAttrib *)NULL) {
00484 const ColorScaleAttrib *csa = DCAST(ColorScaleAttrib, attribs._color_scale);
00485 const LVecBase4f &s = csa->get_scale();
00486 if (s != LVecBase4f(1.0f, 1.0f, 1.0f, 1.0f)) {
00487 _text_color[0] *= s[0];
00488 _text_color[1] *= s[1];
00489 _text_color[2] *= s[2];
00490 _text_color[3] *= s[3];
00491 _frame_color[0] *= s[0];
00492 _frame_color[1] *= s[1];
00493 _frame_color[2] *= s[2];
00494 _frame_color[3] *= s[3];
00495 _card_color[0] *= s[0];
00496 _card_color[1] *= s[1];
00497 _card_color[2] *= s[2];
00498 _card_color[3] *= s[3];
00499 _shadow_color[0] *= s[0];
00500 _shadow_color[1] *= s[1];
00501 _shadow_color[2] *= s[2];
00502 _shadow_color[3] *= s[3];
00503 }
00504 }
00505 }
00506
00507
00508
00509 if ((_flags & F_needs_rebuild) == 0 &&
00510 _internal_geom != (PandaNode *)NULL) {
00511 SceneGraphReducer gr;
00512 gr.apply_attribs(_internal_geom, attribs, attrib_types, transformer);
00513 }
00514 }
00515
00516
00517
00518
00519
00520
00521
00522
00523
00524
00525
00526
00527
00528
00529
00530
00531
00532 CPT(TransformState) TextNode::
00533 calc_tight_bounds(LPoint3f &min_point, LPoint3f &max_point, bool &found_any,
00534 const TransformState *transform) const {
00535 CPT(TransformState) next_transform =
00536 PandaNode::calc_tight_bounds(min_point, max_point, found_any, transform);
00537
00538 check_rebuild();
00539
00540 if (_internal_geom != (PandaNode *)NULL) {
00541 _internal_geom->calc_tight_bounds(min_point, max_point,
00542 found_any, next_transform);
00543 }
00544
00545 return next_transform;
00546 }
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557 bool TextNode::
00558 has_cull_callback() const {
00559 return true;
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581 bool TextNode::
00582 cull_callback(CullTraverser *trav, CullTraverserData &data) {
00583 check_rebuild();
00584 if (_internal_geom != (PandaNode *)NULL) {
00585
00586 CullTraverserData next_data(data, _internal_geom);
00587 trav->traverse(next_data);
00588 }
00589
00590
00591 return true;
00592 }
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602 BoundingVolume *TextNode::
00603 recompute_internal_bound() {
00604
00605 BoundingVolume *bound = PandaNode::recompute_internal_bound();
00606 nassertr(bound != (BoundingVolume *)NULL, bound);
00607
00608 GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound);
00609
00610
00611
00612
00613 check_measure();
00614
00615 LPoint3f vertices[8];
00616 vertices[0].set(_ul3d[0], _ul3d[1], _ul3d[2]);
00617 vertices[1].set(_ul3d[0], _ul3d[1], _lr3d[2]);
00618 vertices[2].set(_ul3d[0], _lr3d[1], _ul3d[2]);
00619 vertices[3].set(_ul3d[0], _lr3d[1], _lr3d[2]);
00620 vertices[4].set(_lr3d[0], _ul3d[1], _ul3d[2]);
00621 vertices[5].set(_lr3d[0], _ul3d[1], _lr3d[2]);
00622 vertices[6].set(_lr3d[0], _lr3d[1], _ul3d[2]);
00623 vertices[7].set(_lr3d[0], _lr3d[1], _lr3d[2]);
00624
00625 gbv->around(vertices, vertices + 8);
00626
00627 return bound;
00628 }
00629
00630
00631
00632
00633
00634
00635
00636 void TextNode::
00637 do_rebuild() {
00638 _flags &= ~(F_needs_rebuild | F_needs_measure);
00639 _internal_geom = generate();
00640 }
00641
00642
00643
00644
00645
00646
00647
00648
00649
00650 void TextNode::
00651 do_measure() {
00652 _flags &= ~F_needs_measure;
00653
00654 _ul2d.set(0.0f, 0.0f);
00655 _lr2d.set(0.0f, 0.0f);
00656 _ul3d.set(0.0f, 0.0f, 0.0f);
00657 _lr3d.set(0.0f, 0.0f, 0.0f);
00658 _num_rows = 0;
00659
00660 if (!has_text()) {
00661 return;
00662 }
00663
00664 TextFont *font = get_font();
00665 if (font == (TextFont *)NULL) {
00666 font = get_default_font();
00667 }
00668
00669 if (font == (TextFont *)NULL) {
00670 return;
00671 }
00672
00673 wstring wtext = get_wtext();
00674 if (has_wordwrap()) {
00675 wtext = font->wordwrap_to(wtext, _wordwrap_width, false);
00676 }
00677
00678 LVector2f ul, lr;
00679 int num_rows = 0;
00680 measure_text(wtext.begin(), wtext.end(), font,
00681 ul, lr, num_rows);
00682
00683 _num_rows = num_rows;
00684 _ul2d = ul;
00685 _lr2d = lr;
00686 _ul3d.set(ul[0], 0.0f, ul[1]);
00687 _lr3d.set(lr[0], 0.0f, lr[1]);
00688
00689 _ul3d = _ul3d * _transform;
00690 _lr3d = _lr3d * _transform;
00691 }
00692
00693
00694 #ifndef CPPPARSER // interrogate has a bit of trouble with wstring.
00695
00696
00697
00698
00699
00700
00701
00702
00703
00704
00705 float TextNode::
00706 assemble_row(wstring::iterator &si, const wstring::iterator &send,
00707 TextFont *font, GeomNode *dest, const LMatrix4f &mat) {
00708 float xpos = 0.0f;
00709 while (si != send && (*si) != '\n') {
00710 wchar_t character = *si;
00711
00712 if (character == ' ') {
00713
00714 xpos += font->get_space_advance();
00715
00716 } else {
00717
00718 bool got_glyph;
00719 const TextGlyph *glyph;
00720 const TextGlyph *second_glyph;
00721 UnicodeLatinMap::AccentType accent_type;
00722 int additional_flags;
00723 float glyph_scale;
00724 float advance_scale;
00725 get_character_glyphs(character, font,
00726 got_glyph, glyph, second_glyph, accent_type,
00727 additional_flags, glyph_scale, advance_scale);
00728
00729 if (!got_glyph) {
00730 text_cat.warning()
00731 << "No definition in " << font->get_name()
00732 << " for character " << character;
00733 if (character < 128 && isprint((unsigned int)character)) {
00734 text_cat.warning(false)
00735 << " ('" << (char)character << "')";
00736 }
00737 text_cat.warning(false)
00738 << "\n";
00739 }
00740
00741
00742
00743
00744
00745 static const int max_geoms = 10;
00746 Geom *geom_array[max_geoms];
00747 int num_geoms = 0;
00748 int gi;
00749
00750 float advance = 0.0f;
00751
00752 if (glyph != (TextGlyph *)NULL) {
00753 PT(Geom) char_geom = glyph->get_geom();
00754 if (char_geom != (Geom *)NULL) {
00755 dest->add_geom(char_geom, glyph->get_state());
00756 geom_array[num_geoms++] = char_geom;
00757 }
00758 advance = glyph->get_advance() * advance_scale;
00759 }
00760 if (second_glyph != (TextGlyph *)NULL) {
00761 PT(Geom) second_char_geom = second_glyph->get_geom();
00762 if (second_char_geom != (Geom *)NULL) {
00763 second_char_geom->transform_vertices(LMatrix4f::translate_mat(advance, 0.0f, 0.0f));
00764 dest->add_geom(second_char_geom, second_glyph->get_state());
00765 geom_array[num_geoms++] = second_char_geom;
00766 }
00767 advance += second_glyph->get_advance();
00768 }
00769
00770
00771
00772 LMatrix4f glyph_xform = LMatrix4f::scale_mat(glyph_scale);
00773
00774 if (accent_type != UnicodeLatinMap::AT_none || additional_flags != 0) {
00775
00776
00777
00778 LPoint3f min_vert, max_vert;
00779 bool found_any = false;
00780 for (gi = 0; gi < num_geoms; gi++) {
00781 geom_array[gi]->calc_tight_bounds(min_vert, max_vert, found_any);
00782 }
00783
00784 if (found_any) {
00785 LPoint3f centroid = (min_vert + max_vert) / 2.0f;
00786 tack_on_accent(accent_type, min_vert, max_vert, centroid,
00787 font, dest, geom_array, num_geoms);
00788
00789 if ((additional_flags & UnicodeLatinMap::AF_turned) != 0) {
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799
00800
00801 LMatrix4f rotate =
00802 LMatrix4f::translate_mat(-centroid) *
00803 LMatrix4f::rotate_mat_normaxis(180.0f, LVecBase3f(0.0f, -1.0f, 0.0f)) *
00804 LMatrix4f::translate_mat(centroid);
00805 glyph_xform *= rotate;
00806 }
00807 }
00808 }
00809
00810 glyph_xform(3, 0) += xpos;
00811 LMatrix4f net_xform = glyph_xform * mat;
00812
00813
00814
00815
00816
00817 for (gi = 0; gi < num_geoms; gi++) {
00818 geom_array[gi]->transform_vertices(net_xform);
00819 }
00820
00821 xpos += advance * glyph_scale;
00822 }
00823 ++si;
00824 }
00825
00826 return xpos;
00827 }
00828
00829
00830
00831
00832
00833
00834
00835
00836 PT(PandaNode) TextNode::
00837 assemble_text(wstring::iterator si, const wstring::iterator &send,
00838 TextFont *font, LVector2f &ul, LVector2f &lr, int &num_rows) {
00839 float line_height = font->get_line_height();
00840
00841 ul.set(0.0f, 0.8f * line_height);
00842 lr.set(0.0f, 0.0f);
00843
00844
00845 PT(GeomNode) root_node = new GeomNode("text");
00846
00847 float posy = 0.0f;
00848 while (si != send) {
00849
00850
00851
00852 wstring::iterator tsi = si;
00853 float row_width = measure_row(tsi, send, font);
00854
00855 LMatrix4f mat = LMatrix4f::ident_mat();
00856 if (_align == A_left) {
00857 mat.set_row(3, LVector3f(0.0f, 0.0f, posy));
00858 lr[0] = max(lr[0], row_width);
00859
00860 } else if (_align == A_right) {
00861 mat.set_row(3, LVector3f(-row_width, 0.0f, posy));
00862 ul[0] = min(ul[0], -row_width);
00863
00864 } else {
00865 float half_row_width=0.5f*row_width;
00866 mat.set_row(3, LVector3f(-half_row_width, 0.0f, posy));
00867 lr[0] = max(lr[0], half_row_width);
00868 ul[0] = min(ul[0], -half_row_width);
00869 }
00870
00871
00872
00873 if (_slant != 0.0f) {
00874 LMatrix4f shear(1.0f, 0.0f, 0.0f, 0.0f,
00875 0.0f, 1.0f, 0.0f, 0.0f,
00876 _slant, 0.0f, 1.0f, 0.0f,
00877 0.0f, 0.0f, 0.0f, 1.0f);
00878 mat = shear * mat;
00879 }
00880
00881
00882
00883 assemble_row(si, send, font, root_node, mat);
00884 if (si != send) {
00885
00886 ++si;
00887 }
00888
00889 posy -= line_height;
00890 num_rows++;
00891 }
00892
00893 lr[1] = posy + 0.8f * line_height;
00894
00895 return root_node.p();
00896 }
00897
00898
00899
00900
00901
00902
00903
00904
00905 float TextNode::
00906 measure_row(wstring::iterator &si, const wstring::iterator &send,
00907 TextFont *font) {
00908 float xpos = 0.0f;
00909 while (si != send && *si != '\n') {
00910 wchar_t character = *si;
00911
00912 if (character == ' ') {
00913
00914 xpos += font->get_space_advance();
00915
00916 } else {
00917
00918 bool got_glyph;
00919 const TextGlyph *glyph;
00920 const TextGlyph *second_glyph;
00921 UnicodeLatinMap::AccentType accent_type;
00922 int additional_flags;
00923 float glyph_scale;
00924 float advance_scale;
00925 get_character_glyphs(character, font,
00926 got_glyph, glyph, second_glyph, accent_type,
00927 additional_flags, glyph_scale, advance_scale);
00928
00929 float advance = 0.0f;
00930
00931 if (glyph != (TextGlyph *)NULL) {
00932 advance = glyph->get_advance() * advance_scale;
00933 }
00934 if (second_glyph != (TextGlyph *)NULL) {
00935 advance += second_glyph->get_advance();
00936 }
00937
00938 xpos += advance * glyph_scale;
00939 }
00940 ++si;
00941 }
00942
00943 return xpos;
00944 }
00945
00946
00947
00948
00949
00950
00951
00952 void TextNode::
00953 measure_text(wstring::iterator si, const wstring::iterator &send,
00954 TextFont *font, LVector2f &ul, LVector2f &lr, int &num_rows) {
00955 float line_height = font->get_line_height();
00956
00957 ul.set(0.0f, 0.8f * line_height);
00958 lr.set(0.0f, 0.0f);
00959
00960 float posy = 0.0f;
00961 while (si != send) {
00962 float row_width = measure_row(si, send, font);
00963 if (si != send) {
00964
00965 ++si;
00966 }
00967
00968 if (_align == A_left) {
00969 lr[0] = max(lr[0], row_width);
00970
00971 } else if (_align == A_right) {
00972 ul[0] = min(ul[0], -row_width);
00973
00974 } else {
00975 float half_row_width=0.5f*row_width;
00976
00977 lr[0] = max(lr[0], half_row_width);
00978 ul[0] = min(ul[0], -half_row_width);
00979 }
00980
00981 posy -= line_height;
00982 num_rows++;
00983 }
00984
00985 lr[1] = posy + 0.8f * line_height;
00986 }
00987 #endif // CPPPARSER
00988
00989
00990
00991
00992
00993
00994
00995
00996
00997
00998
00999
01000
01001
01002
01003
01004
01005
01006
01007 void TextNode::
01008 get_character_glyphs(int character, TextFont *font,
01009 bool &got_glyph, const TextGlyph *&glyph,
01010 const TextGlyph *&second_glyph,
01011 UnicodeLatinMap::AccentType &accent_type,
01012 int &additional_flags,
01013 float &glyph_scale, float &advance_scale) {
01014 got_glyph = false;
01015 glyph = NULL;
01016 second_glyph = NULL;
01017 accent_type = UnicodeLatinMap::AT_none;
01018 additional_flags = 0;
01019 glyph_scale = 1.0f;
01020 advance_scale = 1.0f;
01021
01022
01023
01024 const UnicodeLatinMap::Entry *map_entry =
01025 UnicodeLatinMap::look_up(character);
01026 if (map_entry != NULL) {
01027 if (get_small_caps() && map_entry->_toupper_character != character) {
01028 character = map_entry->_toupper_character;
01029 map_entry = UnicodeLatinMap::look_up(character);
01030 glyph_scale = get_small_caps_scale();
01031 }
01032 }
01033
01034 got_glyph = font->get_glyph(character, glyph);
01035 if (!got_glyph && map_entry != NULL && map_entry->_ascii_equiv != 0) {
01036
01037
01038 got_glyph = font->get_glyph(map_entry->_ascii_equiv, glyph);
01039
01040 if (!got_glyph && map_entry->_toupper_character != character) {
01041
01042
01043 character = map_entry->_toupper_character;
01044 map_entry = UnicodeLatinMap::look_up(character);
01045 if (map_entry != NULL) {
01046 got_glyph = font->get_glyph(map_entry->_ascii_equiv, glyph);
01047 }
01048 }
01049
01050 if (got_glyph) {
01051 accent_type = map_entry->_accent_type;
01052 additional_flags = map_entry->_additional_flags;
01053
01054 bool got_second_glyph = false;
01055 if (map_entry->_ascii_additional != 0) {
01056
01057 got_second_glyph =
01058 font->get_glyph(map_entry->_ascii_additional, second_glyph);
01059 }
01060
01061 if ((additional_flags & UnicodeLatinMap::AF_ligature) != 0 &&
01062 got_second_glyph) {
01063
01064
01065 additional_flags &= ~UnicodeLatinMap::AF_ligature;
01066 advance_scale = ligature_advance_scale;
01067 }
01068
01069 if ((additional_flags & UnicodeLatinMap::AF_smallcap) != 0) {
01070 additional_flags &= ~UnicodeLatinMap::AF_smallcap;
01071 glyph_scale = get_small_caps_scale();
01072 }
01073 }
01074 }
01075 }
01076
01077
01078
01079
01080
01081
01082
01083
01084
01085 void TextNode::
01086 tack_on_accent(UnicodeLatinMap::AccentType accent_type,
01087 const LPoint3f &min_vert, const LPoint3f &max_vert,
01088 const LPoint3f ¢roid,
01089 TextFont *font, GeomNode *dest,
01090 Geom *geom_array[], int &num_geoms) {
01091 switch (accent_type) {
01092 case UnicodeLatinMap::AT_grave:
01093
01094
01095
01096
01097 tack_on_accent('/', CP_above, CT_small_squash_mirror_y, min_vert, max_vert, centroid,
01098 font, dest, geom_array, num_geoms);
01099 break;
01100
01101 case UnicodeLatinMap::AT_acute:
01102 tack_on_accent('/', CP_above, CT_small_squash, min_vert, max_vert, centroid,
01103 font, dest, geom_array, num_geoms);
01104 break;
01105
01106 case UnicodeLatinMap::AT_breve:
01107 tack_on_accent(')', CP_above, CT_tiny_rotate_270, min_vert, max_vert, centroid,
01108 font, dest, geom_array, num_geoms);
01109 break;
01110
01111 case UnicodeLatinMap::AT_inverted_breve:
01112 tack_on_accent('(', CP_above, CT_tiny_rotate_270, min_vert, max_vert, centroid,
01113 font, dest, geom_array, num_geoms);
01114 break;
01115
01116 case UnicodeLatinMap::AT_circumflex:
01117 tack_on_accent('^', CP_above, CT_none, min_vert, max_vert, centroid,
01118 font, dest, geom_array, num_geoms) ||
01119 tack_on_accent('v', CP_above, CT_squash_mirror_y, min_vert, max_vert, centroid,
01120 font, dest, geom_array, num_geoms);
01121 break;
01122
01123 case UnicodeLatinMap::AT_circumflex_below:
01124 tack_on_accent('^', CP_below, CT_none, min_vert, max_vert, centroid,
01125 font, dest, geom_array, num_geoms) ||
01126 tack_on_accent('v', CP_below, CT_squash_mirror_y, min_vert, max_vert, centroid,
01127 font, dest, geom_array, num_geoms);
01128 break;
01129
01130 case UnicodeLatinMap::AT_caron:
01131 tack_on_accent('^', CP_above, CT_mirror_y, min_vert, max_vert, centroid,
01132 font, dest, geom_array, num_geoms) ||
01133 tack_on_accent('v', CP_above, CT_squash, min_vert, max_vert, centroid,
01134 font, dest, geom_array, num_geoms);
01135
01136 break;
01137
01138 case UnicodeLatinMap::AT_tilde:
01139 tack_on_accent('~', CP_above, CT_none, min_vert, max_vert, centroid,
01140 font, dest, geom_array, num_geoms) ||
01141 tack_on_accent('s', CP_above, CT_squash_mirror_diag, min_vert, max_vert, centroid,
01142 font, dest, geom_array, num_geoms);
01143 break;
01144
01145 case UnicodeLatinMap::AT_tilde_below:
01146 tack_on_accent('~', CP_below, CT_none, min_vert, max_vert, centroid,
01147 font, dest, geom_array, num_geoms) ||
01148 tack_on_accent('s', CP_below, CT_squash_mirror_diag, min_vert, max_vert, centroid,
01149 font, dest, geom_array, num_geoms);
01150 break;
01151
01152 case UnicodeLatinMap::AT_diaeresis:
01153 tack_on_accent(':', CP_above, CT_small_rotate_270, min_vert, max_vert, centroid,
01154 font, dest, geom_array, num_geoms);
01155 break;
01156
01157 case UnicodeLatinMap::AT_diaeresis_below:
01158 tack_on_accent(':', CP_below, CT_small_rotate_270, min_vert, max_vert, centroid,
01159 font, dest, geom_array, num_geoms);
01160 break;
01161
01162 case UnicodeLatinMap::AT_dot_above:
01163 tack_on_accent('.', CP_above, CT_none, min_vert, max_vert, centroid,
01164 font, dest, geom_array, num_geoms);
01165 break;
01166
01167 case UnicodeLatinMap::AT_dot_below:
01168 tack_on_accent('.', CP_below, CT_none, min_vert, max_vert, centroid,
01169 font, dest, geom_array, num_geoms);
01170 break;
01171
01172 case UnicodeLatinMap::AT_macron:
01173 tack_on_accent('-', CP_above, CT_none, min_vert, max_vert, centroid,
01174 font, dest, geom_array, num_geoms);
01175 break;
01176
01177 case UnicodeLatinMap::AT_line_below:
01178 tack_on_accent('-', CP_below, CT_none, min_vert, max_vert, centroid,
01179 font, dest, geom_array, num_geoms);
01180 break;
01181
01182 case UnicodeLatinMap::AT_ring_above:
01183 tack_on_accent('o', CP_top, CT_tiny, min_vert, max_vert, centroid,
01184 font, dest, geom_array, num_geoms);
01185 break;
01186
01187 case UnicodeLatinMap::AT_ring_below:
01188 tack_on_accent('o', CP_bottom, CT_tiny, min_vert, max_vert, centroid,
01189 font, dest, geom_array, num_geoms);
01190 break;
01191
01192 case UnicodeLatinMap::AT_cedilla:
01193 tack_on_accent('c', CP_bottom, CT_tiny_mirror_x, min_vert, max_vert, centroid,
01194 font, dest, geom_array, num_geoms);
01195
01196
01197
01198
01199 break;
01200
01201 case UnicodeLatinMap::AT_comma_below:
01202 tack_on_accent(',', CP_below, CT_none, min_vert, max_vert, centroid,
01203 font, dest, geom_array, num_geoms);
01204 break;
01205
01206 case UnicodeLatinMap::AT_ogonek:
01207 tack_on_accent(',', CP_bottom, CT_mirror_x, min_vert, max_vert, centroid,
01208 font, dest, geom_array, num_geoms);
01209 break;
01210
01211 case UnicodeLatinMap::AT_stroke:
01212 tack_on_accent('/', CP_within, CT_none, min_vert, max_vert, centroid,
01213 font, dest, geom_array, num_geoms);
01214 break;
01215
01216 default:
01217
01218 break;
01219 }
01220 }
01221
01222
01223
01224
01225
01226
01227
01228
01229
01230 bool TextNode::
01231 tack_on_accent(char accent_mark, TextNode::CheesyPlacement placement,
01232 TextNode::CheesyTransform transform,
01233 const LPoint3f &min_vert, const LPoint3f &max_vert,
01234 const LPoint3f ¢roid,
01235 TextFont *font, GeomNode *dest,
01236 Geom *geom_array[], int &num_geoms) {
01237
01238 const TextGlyph *accent_glyph;
01239 if (font->get_glyph(accent_mark, accent_glyph)) {
01240 PT(Geom) accent_geom = accent_glyph->get_geom();
01241 if (accent_geom != (Geom *)NULL) {
01242 LPoint3f min_accent, max_accent;
01243 bool found_any = false;
01244 accent_geom->calc_tight_bounds(min_accent, max_accent, found_any);
01245 if (found_any) {
01246 float t, u;
01247 LMatrix4f accent_mat;
01248
01249
01250
01251 bool mirrored = false;
01252
01253 switch (transform) {
01254 case CT_none:
01255 accent_mat = LMatrix4f::ident_mat();
01256 break;
01257
01258 case CT_mirror_x:
01259 accent_mat = LMatrix4f::scale_mat(-1.0f, 1.0f, 1.0f);
01260 t = min_accent[0];
01261 min_accent[0] = -max_accent[0];
01262 max_accent[0] = -t;
01263 mirrored = true;
01264 break;
01265
01266 case CT_mirror_y:
01267 accent_mat = LMatrix4f::scale_mat(1.0f, 1.0f, -1.0f);
01268 t = min_accent[2];
01269 min_accent[2] = -max_accent[2];
01270 max_accent[2] = -t;
01271 mirrored = true;
01272 break;
01273
01274 case CT_rotate_90:
01275 accent_mat =
01276 LMatrix4f::rotate_mat_normaxis(90.0f, LVecBase3f(0.0f, -1.0f, 0.0f));
01277
01278 t = min_accent[0];
01279 u = max_accent[0];
01280 max_accent[0] = -min_accent[2];
01281 min_accent[0] = -max_accent[2];
01282 max_accent[2] = u;
01283 min_accent[2] = t;
01284 break;
01285
01286 case CT_rotate_180:
01287 accent_mat = LMatrix4f::scale_mat(-1.0f, -1.0f, 1.0f);
01288
01289 t = min_accent[0];
01290 min_accent[0] = -max_accent[0];
01291 max_accent[0] = -t;
01292 t = min_accent[2];
01293 min_accent[2] = -max_accent[2];
01294 max_accent[2] = -t;
01295 break;
01296
01297 case CT_rotate_270:
01298 accent_mat =
01299 LMatrix4f::rotate_mat_normaxis(270.0f, LVecBase3f(0.0f, -1.0f, 0.0f));
01300
01301 t = min_accent[0];
01302 u = max_accent[0];
01303 min_accent[0] = min_accent[2];
01304 max_accent[0] = max_accent[2];
01305 min_accent[2] = -u;
01306 max_accent[2] = -t;
01307 break;
01308
01309 case CT_squash:
01310 accent_mat = LMatrix4f::scale_mat(squash_accent_scale_x, 1.0f, squash_accent_scale_y);
01311 min_accent[0] *= squash_accent_scale_x;
01312 max_accent[0] *= squash_accent_scale_x;
01313 min_accent[2] *= squash_accent_scale_y;
01314 max_accent[2] *= squash_accent_scale_y;
01315 break;
01316
01317 case CT_squash_mirror_y:
01318 accent_mat = LMatrix4f::scale_mat(squash_accent_scale_x, 1.0f, -squash_accent_scale_y);
01319 min_accent[0] *= squash_accent_scale_x;
01320 max_accent[0] *= squash_accent_scale_x;
01321 t = min_accent[2];
01322 min_accent[2] = -max_accent[2] * squash_accent_scale_y;
01323 max_accent[2] = -t * squash_accent_scale_y;
01324 mirrored = true;
01325 break;
01326
01327 case CT_squash_mirror_diag:
01328 accent_mat =
01329 LMatrix4f::rotate_mat_normaxis(270.0f, LVecBase3f(0.0f, -1.0f, 0.0f)) *
01330 LMatrix4f::scale_mat(-squash_accent_scale_x, 1.0f, squash_accent_scale_y);
01331
01332
01333 t = min_accent[0];
01334 u = max_accent[0];
01335 min_accent[0] = min_accent[2] * -squash_accent_scale_x;
01336 max_accent[0] = max_accent[2] * -squash_accent_scale_x;
01337 min_accent[2] = -u * squash_accent_scale_y;
01338 max_accent[2] = -t * squash_accent_scale_y;
01339 mirrored = true;
01340 break;
01341
01342 case CT_small_squash:
01343 accent_mat = LMatrix4f::scale_mat(small_squash_accent_scale_x, 1.0f, small_squash_accent_scale_y);
01344 min_accent[0] *= small_squash_accent_scale_x;
01345 max_accent[0] *= small_squash_accent_scale_x;
01346 min_accent[2] *= small_squash_accent_scale_y;
01347 max_accent[2] *= small_squash_accent_scale_y;
01348 break;
01349
01350 case CT_small_squash_mirror_y:
01351 accent_mat = LMatrix4f::scale_mat(small_squash_accent_scale_x, 1.0f, -small_squash_accent_scale_y);
01352 min_accent[0] *= small_squash_accent_scale_x;
01353 max_accent[0] *= small_squash_accent_scale_x;
01354 t = min_accent[2];
01355 min_accent[2] = -max_accent[2] * small_squash_accent_scale_y;
01356 max_accent[2] = -t * small_squash_accent_scale_y;
01357 mirrored = true;
01358 break;
01359
01360 case CT_small:
01361 accent_mat = LMatrix4f::scale_mat(small_accent_scale);
01362 min_accent *= small_accent_scale;
01363 max_accent *= small_accent_scale;
01364 break;
01365
01366 case CT_small_rotate_270:
01367 accent_mat =
01368 LMatrix4f::rotate_mat_normaxis(270.0f, LVecBase3f(0.0f, -1.0f, 0.0f)) *
01369 LMatrix4f::scale_mat(small_accent_scale);
01370
01371
01372 t = min_accent[0];
01373 u = max_accent[0];
01374 min_accent[0] = min_accent[2] * small_accent_scale;
01375 max_accent[0] = max_accent[2] * small_accent_scale;
01376 min_accent[2] = -u * small_accent_scale;
01377 max_accent[2] = -t * small_accent_scale;
01378 break;
01379
01380 case CT_tiny:
01381 accent_mat = LMatrix4f::scale_mat(tiny_accent_scale);
01382 min_accent *= tiny_accent_scale;
01383 max_accent *= tiny_accent_scale;
01384 break;
01385
01386 case CT_tiny_mirror_x:
01387 accent_mat = LMatrix4f::scale_mat(-tiny_accent_scale, 1.0f, tiny_accent_scale);
01388
01389 t = min_accent[0];
01390 min_accent[0] = -max_accent[0] * tiny_accent_scale;
01391 max_accent[0] = -t * tiny_accent_scale;
01392 min_accent[2] *= tiny_accent_scale;
01393 max_accent[2] *= tiny_accent_scale;
01394 mirrored = true;
01395 break;
01396
01397 case CT_tiny_rotate_270:
01398 accent_mat =
01399 LMatrix4f::rotate_mat_normaxis(270.0f, LVecBase3f(0.0f, -1.0f, 0.0f)) *
01400 LMatrix4f::scale_mat(tiny_accent_scale);
01401
01402
01403 t = min_accent[0];
01404 u = max_accent[0];
01405 min_accent[0] = min_accent[2] * tiny_accent_scale;
01406 max_accent[0] = max_accent[2] * tiny_accent_scale;
01407 min_accent[2] = -u * tiny_accent_scale;
01408 max_accent[2] = -t * tiny_accent_scale;
01409 break;
01410 }
01411
01412 LPoint3f accent_centroid = (min_accent + max_accent) / 2.0f;
01413 float accent_height = max_accent[2] - min_accent[2];
01414 LVector3f trans;
01415 switch (placement) {
01416 case CP_above:
01417
01418 trans.set(centroid[0] - accent_centroid[0], 0.0f,
01419 max_vert[2] - accent_centroid[2] + accent_height * 0.5);
01420 break;
01421
01422 case CP_below:
01423
01424 trans.set(centroid[0] - accent_centroid[0], 0.0f,
01425 min_vert[2] - accent_centroid[2] - accent_height * 0.5);
01426 break;
01427
01428 case CP_top:
01429
01430 trans.set(centroid[0] - accent_centroid[0], 0.0f,
01431 max_vert[2] - accent_centroid[2]);
01432 break;
01433
01434 case CP_bottom:
01435
01436 trans.set(centroid[0] - accent_centroid[0], 0.0f,
01437 min_vert[2] - accent_centroid[2]);
01438 break;
01439
01440 case CP_within:
01441
01442 trans.set(centroid[0] - accent_centroid[0], 0.0f,
01443 centroid[2] - accent_centroid[2]);
01444 break;
01445 }
01446
01447 accent_mat.set_row(3, trans);
01448 accent_geom->transform_vertices(accent_mat);
01449
01450 if (mirrored) {
01451
01452
01453 static CPT(RenderState) disable_backface;
01454 if (disable_backface == (const RenderState *)NULL) {
01455 disable_backface = RenderState::make
01456 (CullFaceAttrib::make(CullFaceAttrib::M_cull_none));
01457 }
01458
01459 CPT(RenderState) state =
01460 accent_glyph->get_state()->compose(disable_backface);
01461 dest->add_geom(accent_geom, state);
01462 } else {
01463 dest->add_geom(accent_geom, accent_glyph->get_state());
01464 }
01465 geom_array[num_geoms++] = accent_geom;
01466
01467 return true;
01468 }
01469 }
01470 }
01471
01472 return false;
01473 }
01474
01475
01476
01477
01478
01479
01480 PT(PandaNode) TextNode::
01481 make_frame() {
01482 PT(GeomNode) frame_geode = new GeomNode("frame");
01483
01484 LVector4f dimensions = get_frame_actual();
01485 float left = dimensions[0];
01486 float right = dimensions[1];
01487 float bottom = dimensions[2];
01488 float top = dimensions[3];
01489
01490 GeomLinestrip *geoset = new GeomLinestrip;
01491 PTA_int lengths=PTA_int::empty_array(0);
01492 PTA_Vertexf verts;
01493 lengths.push_back(5);
01494 verts.push_back(Vertexf(left, 0.0f, top));
01495 verts.push_back(Vertexf(left, 0.0f, bottom));
01496 verts.push_back(Vertexf(right, 0.0f, bottom));
01497 verts.push_back(Vertexf(right, 0.0f, top));
01498 verts.push_back(Vertexf(left, 0.0f, top));
01499
01500 geoset->set_num_prims(1);
01501 geoset->set_lengths(lengths);
01502
01503 geoset->set_coords(verts);
01504 geoset->set_width(_frame_width);
01505 frame_geode->add_geom(geoset);
01506
01507 if (get_frame_corners()) {
01508 GeomPoint *geoset = new GeomPoint;
01509
01510 geoset->set_num_prims(4);
01511 geoset->set_coords(verts);
01512 geoset->set_size(_frame_width);
01513 frame_geode->add_geom(geoset);
01514 }
01515
01516 return frame_geode.p();
01517 }
01518
01519
01520
01521
01522
01523
01524 PT(PandaNode) TextNode::
01525 make_card() {
01526 PT(GeomNode) card_geode = new GeomNode("card");
01527
01528 LVector4f dimensions = get_card_actual();
01529 float left = dimensions[0];
01530 float right = dimensions[1];
01531 float bottom = dimensions[2];
01532 float top = dimensions[3];
01533
01534 GeomTristrip *geoset = new GeomTristrip;
01535 PTA_int lengths=PTA_int::empty_array(0);
01536 lengths.push_back(4);
01537
01538 PTA_Vertexf verts;
01539 verts.push_back(Vertexf::rfu(left, 0.02f, top));
01540 verts.push_back(Vertexf::rfu(left, 0.02f, bottom));
01541 verts.push_back(Vertexf::rfu(right, 0.02f, top));
01542 verts.push_back(Vertexf::rfu(right, 0.02f, bottom));
01543
01544 geoset->set_num_prims(1);
01545 geoset->set_lengths(lengths);
01546
01547 geoset->set_coords(verts);
01548
01549 if (has_card_texture()) {
01550 PTA_TexCoordf uvs;
01551 uvs.push_back(TexCoordf(0.0f, 1.0f));
01552 uvs.push_back(TexCoordf(0.0f, 0.0f));
01553 uvs.push_back(TexCoordf(1.0f, 1.0f));
01554 uvs.push_back(TexCoordf(1.0f, 0.0f));
01555
01556 geoset->set_texcoords(uvs, G_PER_VERTEX);
01557 }
01558
01559 card_geode->add_geom(geoset);
01560
01561 return card_geode.p();
01562 }
01563
01564
01565
01566
01567
01568
01569
01570
01571 PT(PandaNode) TextNode::
01572 make_card_with_border() {
01573 PT(GeomNode) card_geode = new GeomNode("card");
01574
01575 LVector4f dimensions = get_card_actual();
01576 float left = dimensions[0];
01577 float right = dimensions[1];
01578 float bottom = dimensions[2];
01579 float top = dimensions[3];
01580
01581
01582
01583
01584
01585
01586
01587
01588
01589 GeomTristrip *geoset = new GeomTristrip;
01590 PTA_int lengths;
01591 lengths.push_back(8);
01592 lengths.push_back(8);
01593 lengths.push_back(8);
01594
01595 PTA_Vertexf verts;
01596
01597 verts.push_back(Vertexf::rfu(left, 0.02f, top));
01598 verts.push_back(Vertexf::rfu(left, 0.02f, top - _card_border_size));
01599 verts.push_back(Vertexf::rfu(left + _card_border_size, 0.02f, top));
01600 verts.push_back(Vertexf::rfu(left + _card_border_size, 0.02f,
01601 top - _card_border_size));
01602
01603 verts.push_back(Vertexf::rfu(right - _card_border_size, 0.02f, top));
01604 verts.push_back(Vertexf::rfu(right - _card_border_size, 0.02f,
01605 top - _card_border_size));
01606 verts.push_back(Vertexf::rfu(right, 0.02f, top));
01607 verts.push_back(Vertexf::rfu(right, 0.02f, top - _card_border_size));
01608
01609 verts.push_back(Vertexf::rfu(left, 0.02f, bottom + _card_border_size));
01610 verts.push_back(Vertexf::rfu(left, 0.02f, bottom));
01611 verts.push_back(Vertexf::rfu(left + _card_border_size, 0.02f,
01612 bottom + _card_border_size));
01613 verts.push_back(Vertexf::rfu(left + _card_border_size, 0.02f, bottom));
01614
01615 verts.push_back(Vertexf::rfu(right - _card_border_size, 0.02f,
01616 bottom + _card_border_size));
01617 verts.push_back(Vertexf::rfu(right - _card_border_size, 0.02f, bottom));
01618 verts.push_back(Vertexf::rfu(right, 0.02f, bottom + _card_border_size));
01619 verts.push_back(Vertexf::rfu(right, 0.02f, bottom));
01620
01621 PTA_ushort indices;
01622
01623 indices.push_back(0);
01624 indices.push_back(1);
01625 indices.push_back(2);
01626 indices.push_back(3);
01627 indices.push_back(4);
01628 indices.push_back(5);
01629 indices.push_back(6);
01630 indices.push_back(7);
01631
01632 indices.push_back(1);
01633 indices.push_back(8);
01634 indices.push_back(3);
01635 indices.push_back(10);
01636 indices.push_back(5);
01637 indices.push_back(12);
01638 indices.push_back(7);
01639 indices.push_back(14);
01640
01641 indices.push_back(8);
01642 indices.push_back(9);
01643 indices.push_back(10);
01644 indices.push_back(11);
01645 indices.push_back(12);
01646 indices.push_back(13);
01647 indices.push_back(14);
01648 indices.push_back(15);
01649
01650 geoset->set_num_prims(3);
01651 geoset->set_lengths(lengths);
01652
01653 geoset->set_coords(verts,indices);
01654
01655 if (has_card_texture()) {
01656 PTA_TexCoordf uvs;
01657 uvs.push_back(TexCoordf(0.0f, 1.0f));
01658 uvs.push_back(TexCoordf(0.0f, 1.0f - _card_border_uv_portion));
01659 uvs.push_back(TexCoordf(0.0f + _card_border_uv_portion, 1.0f));
01660 uvs.push_back(TexCoordf(0.0f + _card_border_uv_portion,
01661 1.0f - _card_border_uv_portion));
01662 uvs.push_back(TexCoordf( 1.0f -_card_border_uv_portion, 1.0f));
01663 uvs.push_back(TexCoordf( 1.0f -_card_border_uv_portion,
01664 1.0f - _card_border_uv_portion));
01665 uvs.push_back(TexCoordf(1.0f, 1.0f));
01666 uvs.push_back(TexCoordf(1.0f, 1.0f - _card_border_uv_portion));
01667
01668 uvs.push_back(TexCoordf(0.0f, _card_border_uv_portion));
01669 uvs.push_back(TexCoordf(0.0f, 0.0f));
01670 uvs.push_back(TexCoordf(_card_border_uv_portion, _card_border_uv_portion));
01671 uvs.push_back(TexCoordf(_card_border_uv_portion, 0.0f));
01672
01673 uvs.push_back(TexCoordf(1.0f - _card_border_uv_portion, _card_border_uv_portion));
01674 uvs.push_back(TexCoordf(1.0f - _card_border_uv_portion, 0.0f));
01675 uvs.push_back(TexCoordf(1.0f, _card_border_uv_portion));
01676 uvs.push_back(TexCoordf(1.0f, 0.0f));
01677
01678
01679 geoset->set_texcoords(uvs, G_PER_VERTEX, indices);
01680
01681 }
01682
01683 card_geode->add_geom(geoset);
01684
01685 return card_geode.p();
01686 }
01687
01688
01689
01690
01691
01692
01693
01694
01695
01696
01697
01698 void TextNode::
01699 load_default_font() {
01700 _loaded_default_font = true;
01701
01702 if (!text_default_font.empty()) {
01703
01704 _default_font = FontPool::load_font(text_default_font);
01705 if (_default_font->is_valid()) {
01706 return;
01707 }
01708 }
01709
01710
01711 #if defined(HAVE_FREETYPE) && defined(COMPILE_IN_DEFAULT_FONT)
01712 _default_font = new DynamicTextFont((const char *)default_font_data,
01713 default_font_size, 0);
01714 if (_default_font->is_valid()) {
01715 return;
01716 }
01717 #endif
01718
01719
01720
01721
01722
01723 _default_font = FontPool::load_font("cmss12");
01724 }