00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "ropeNode.h"
00016 #include "cullTraverser.h"
00017 #include "cullTraverserData.h"
00018 #include "cullableObject.h"
00019 #include "cullHandler.h"
00020 #include "renderState.h"
00021 #include "renderModeAttrib.h"
00022 #include "colorAttrib.h"
00023 #include "bamWriter.h"
00024 #include "bamReader.h"
00025 #include "datagram.h"
00026 #include "datagramIterator.h"
00027 #include "pStatTimer.h"
00028 #include "geom.h"
00029 #include "geomLinestrips.h"
00030 #include "geomTristrips.h"
00031 #include "geomVertexWriter.h"
00032 #include "boundingSphere.h"
00033
00034 TypeHandle RopeNode::_type_handle;
00035
00036 PStatCollector RopeNode::_rope_node_pcollector("*:RopeNode");
00037
00038
00039
00040
00041
00042
00043 CycleData *RopeNode::CData::
00044 make_copy() const {
00045 return new CData(*this);
00046 }
00047
00048
00049
00050
00051
00052
00053
00054 void RopeNode::CData::
00055 write_datagram(BamWriter *writer, Datagram &dg) const {
00056
00057
00058 writer->write_pointer(dg, (TypedWritable *)NULL);
00059 }
00060
00061
00062
00063
00064
00065
00066
00067
00068 void RopeNode::CData::
00069 fillin(DatagramIterator &scan, BamReader *reader) {
00070
00071 reader->skip_pointer(scan);
00072 }
00073
00074
00075
00076
00077
00078
00079 RopeNode::
00080 RopeNode(const string &name) :
00081 PandaNode(name)
00082 {
00083 set_cull_callback();
00084 }
00085
00086
00087
00088
00089
00090
00091 RopeNode::
00092 RopeNode(const RopeNode ©) :
00093 PandaNode(copy),
00094 _cycler(copy._cycler)
00095 {
00096 }
00097
00098
00099
00100
00101
00102
00103
00104
00105
00106 PandaNode *RopeNode::
00107 make_copy() const {
00108 return new RopeNode(*this);
00109 }
00110
00111
00112
00113
00114
00115
00116
00117
00118
00119 bool RopeNode::
00120 safe_to_transform() const {
00121 return false;
00122 }
00123
00124
00125
00126
00127
00128
00129
00130
00131
00132
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149 bool RopeNode::
00150 cull_callback(CullTraverser *trav, CullTraverserData &data) {
00151
00152 PStatTimer timer(_rope_node_pcollector);
00153
00154
00155 if (get_num_subdiv() > 0) {
00156 NurbsCurveEvaluator *curve = get_curve();
00157 if (curve != (NurbsCurveEvaluator *)NULL) {
00158 PT(NurbsCurveResult) result;
00159 if (has_matrix()) {
00160 result = curve->evaluate(data._node_path.get_node_path(), get_matrix());
00161 } else {
00162 result = curve->evaluate(data._node_path.get_node_path());
00163 }
00164
00165 if (result->get_num_segments() > 0) {
00166 switch (get_render_mode()) {
00167 case RM_thread:
00168 render_thread(trav, data, result);
00169 break;
00170
00171 case RM_tape:
00172 render_tape(trav, data, result);
00173 break;
00174
00175 case RM_billboard:
00176 render_billboard(trav, data, result);
00177 break;
00178
00179 case RM_tube:
00180 render_tube(trav, data, result);
00181 break;
00182 }
00183 }
00184 }
00185 }
00186
00187 return true;
00188 }
00189
00190
00191
00192
00193
00194
00195
00196
00197
00198
00199
00200 bool RopeNode::
00201 is_renderable() const {
00202 return true;
00203 }
00204
00205
00206
00207
00208
00209
00210 void RopeNode::
00211 output(ostream &out) const {
00212 PandaNode::output(out);
00213 NurbsCurveEvaluator *curve = get_curve();
00214 if (curve != (NurbsCurveEvaluator *)NULL) {
00215 out << " " << *curve;
00216 } else {
00217 out << " (no curve)";
00218 }
00219 }
00220
00221
00222
00223
00224
00225
00226 void RopeNode::
00227 write(ostream &out, int indent_level) const {
00228 PandaNode::write(out, indent_level);
00229 indent(out, indent_level) << *get_curve() << "\n";
00230 }
00231
00232
00233
00234
00235
00236
00237
00238
00239
00240 void RopeNode::
00241 reset_bound(const NodePath &rel_to) {
00242 Thread *current_thread = Thread::get_current_thread();
00243 int pipeline_stage = current_thread->get_pipeline_stage();
00244 do_recompute_bounds(rel_to, pipeline_stage, current_thread);
00245 mark_internal_bounds_stale(current_thread);
00246 }
00247
00248
00249
00250
00251
00252
00253
00254
00255
00256 void RopeNode::
00257 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
00258 int &internal_vertices,
00259 int pipeline_stage,
00260 Thread *current_thread) const {
00261 PT(BoundingVolume) bounds =
00262 do_recompute_bounds(NodePath((PandaNode *)this), pipeline_stage,
00263 current_thread);
00264
00265 internal_bounds = bounds;
00266 internal_vertices = 0;
00267 }
00268
00269
00270
00271
00272
00273
00274
00275
00276 CPT(GeomVertexFormat) RopeNode::
00277 get_format(bool support_normals) const {
00278 PT(GeomVertexArrayFormat) array_format = new GeomVertexArrayFormat
00279 (InternalName::get_vertex(), 3, Geom::NT_float32,
00280 Geom::C_point);
00281
00282 if (support_normals && get_normal_mode() == NM_vertex) {
00283 array_format->add_column
00284 (InternalName::get_normal(), 3, Geom::NT_float32,
00285 Geom::C_vector);
00286 }
00287 if (get_use_vertex_color()) {
00288 array_format->add_column
00289 (InternalName::get_color(), 1, Geom::NT_packed_dabc,
00290 Geom::C_color);
00291 }
00292 if (get_uv_mode() != UV_none) {
00293 array_format->add_column
00294 (InternalName::get_texcoord(), 2, Geom::NT_float32,
00295 Geom::C_texcoord);
00296 }
00297
00298 return GeomVertexFormat::register_format(array_format);
00299 }
00300
00301
00302
00303
00304
00305
00306 PT(BoundingVolume) RopeNode::
00307 do_recompute_bounds(const NodePath &rel_to, int pipeline_stage,
00308 Thread *current_thread) const {
00309
00310
00311
00312
00313
00314 PT(BoundingVolume) bound = new BoundingSphere;
00315
00316 NurbsCurveEvaluator *curve = get_curve();
00317 if (curve != (NurbsCurveEvaluator *)NULL) {
00318 pvector<LPoint3f> verts;
00319 get_curve()->get_vertices(verts, rel_to);
00320
00321 if (has_matrix()) {
00322
00323 const LMatrix4f &mat = get_matrix();
00324 pvector<LPoint3f>::iterator vi;
00325 for (vi = verts.begin(); vi != verts.end(); ++vi) {
00326 (*vi) = (*vi) * mat;
00327 }
00328 }
00329
00330 GeometricBoundingVolume *gbv;
00331 DCAST_INTO_R(gbv, bound, bound);
00332 gbv->around(&verts[0], &verts[0] + verts.size());
00333 }
00334 return bound;
00335 }
00336
00337
00338
00339
00340
00341
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351 void RopeNode::
00352 render_thread(CullTraverser *trav, CullTraverserData &data,
00353 NurbsCurveResult *result) const {
00354 CurveSegments curve_segments;
00355 get_connected_segments(curve_segments, result);
00356
00357
00358
00359
00360 PT(GeomVertexData) vdata = new GeomVertexData
00361 ("rope", get_format(false), Geom::UH_stream);
00362
00363 compute_thread_vertices(vdata, curve_segments);
00364
00365 PT(GeomLinestrips) strip = new GeomLinestrips(Geom::UH_stream);
00366 CurveSegments::const_iterator si;
00367 for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
00368 const CurveSegment &segment = (*si);
00369
00370 strip->add_next_vertices(segment.size());
00371 strip->close_primitive();
00372 }
00373
00374 PT(Geom) geom = new Geom(vdata);
00375 geom->add_primitive(strip);
00376
00377 CPT(RenderAttrib) thick = RenderModeAttrib::make(RenderModeAttrib::M_unchanged, get_thickness());
00378 CPT(RenderState) state = data._state->add_attrib(thick);
00379 if (get_use_vertex_color()) {
00380 state = state->add_attrib(ColorAttrib::make_vertex());
00381 }
00382
00383 CullableObject *object =
00384 new CullableObject(geom, state,
00385 data.get_net_transform(trav),
00386 data.get_modelview_transform(trav),
00387 trav->get_gsg());
00388 trav->get_cull_handler()->record_object(object, trav);
00389 }
00390
00391
00392
00393
00394
00395
00396
00397
00398
00399
00400
00401 void RopeNode::
00402 render_tape(CullTraverser *trav, CullTraverserData &data,
00403 NurbsCurveResult *result) const {
00404 CurveSegments curve_segments;
00405 get_connected_segments(curve_segments, result);
00406
00407
00408
00409
00410 PT(GeomVertexData) vdata = new GeomVertexData
00411 ("rope", get_format(false), Geom::UH_stream);
00412
00413 compute_billboard_vertices(vdata, -get_tube_up(),
00414 curve_segments, result);
00415
00416 PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
00417 CurveSegments::const_iterator si;
00418 for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
00419 const CurveSegment &segment = (*si);
00420
00421 strip->add_next_vertices(segment.size() * 2);
00422 strip->close_primitive();
00423 }
00424
00425 PT(Geom) geom = new Geom(vdata);
00426 geom->add_primitive(strip);
00427
00428 CPT(RenderState) state = data._state;
00429 if (get_use_vertex_color()) {
00430 state = state->add_attrib(ColorAttrib::make_vertex());
00431 }
00432
00433 CullableObject *object =
00434 new CullableObject(geom, state,
00435 data.get_net_transform(trav),
00436 data.get_modelview_transform(trav),
00437 trav->get_gsg());
00438 trav->get_cull_handler()->record_object(object, trav);
00439 }
00440
00441
00442
00443
00444
00445
00446
00447
00448
00449
00450
00451 void RopeNode::
00452 render_billboard(CullTraverser *trav, CullTraverserData &data,
00453 NurbsCurveResult *result) const {
00454 const TransformState *net_transform = data.get_net_transform(trav);
00455 const TransformState *camera_transform = trav->get_camera_transform();
00456
00457 CPT(TransformState) rel_transform =
00458 net_transform->invert_compose(camera_transform);
00459 LVector3f camera_vec = LVector3f::forward() * rel_transform->get_mat();
00460
00461 CurveSegments curve_segments;
00462 get_connected_segments(curve_segments, result);
00463
00464
00465
00466
00467 PT(GeomVertexData) vdata = new GeomVertexData
00468 ("rope", get_format(false), Geom::UH_stream);
00469
00470 compute_billboard_vertices(vdata, camera_vec,
00471 curve_segments, result);
00472
00473 PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
00474 CurveSegments::const_iterator si;
00475 for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
00476 const CurveSegment &segment = (*si);
00477
00478 strip->add_next_vertices(segment.size() * 2);
00479 strip->close_primitive();
00480 }
00481
00482 PT(Geom) geom = new Geom(vdata);
00483 geom->add_primitive(strip);
00484
00485 CPT(RenderState) state = data._state;
00486 if (get_use_vertex_color()) {
00487 state = state->add_attrib(ColorAttrib::make_vertex());
00488 }
00489
00490 CullableObject *object =
00491 new CullableObject(geom, state,
00492 data.get_net_transform(trav),
00493 data.get_modelview_transform(trav),
00494 trav->get_gsg());
00495 trav->get_cull_handler()->record_object(object, trav);
00496 }
00497
00498
00499
00500
00501
00502
00503
00504
00505
00506
00507 void RopeNode::
00508 render_tube(CullTraverser *trav, CullTraverserData &data,
00509 NurbsCurveResult *result) const {
00510 CurveSegments curve_segments;
00511 get_connected_segments(curve_segments, result);
00512
00513
00514
00515
00516 int num_slices = get_num_slices();
00517 int num_verts_per_slice;
00518
00519 PT(GeomVertexData) vdata = new GeomVertexData
00520 ("rope", get_format(true), Geom::UH_stream);
00521
00522 compute_tube_vertices(vdata, num_verts_per_slice,
00523 curve_segments, result);
00524
00525 PT(GeomTristrips) strip = new GeomTristrips(Geom::UH_stream);
00526
00527
00528 int vi = 0;
00529 CurveSegments::const_iterator si;
00530 for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
00531 const CurveSegment &segment = (*si);
00532
00533 for (int s = 0; s < num_slices; ++s) {
00534 int s1 = (s + 1) % num_verts_per_slice;
00535
00536 for (size_t j = 0; j < segment.size(); ++j) {
00537 strip->add_vertex((vi + j) * num_verts_per_slice + s);
00538 strip->add_vertex((vi + j) * num_verts_per_slice + s1);
00539 }
00540
00541 strip->close_primitive();
00542 }
00543 vi += (int)segment.size();
00544 }
00545
00546 PT(Geom) geom = new Geom(vdata);
00547 geom->add_primitive(strip);
00548
00549 CPT(RenderState) state = data._state;
00550 if (get_use_vertex_color()) {
00551 state = state->add_attrib(ColorAttrib::make_vertex());
00552 }
00553
00554 CullableObject *object =
00555 new CullableObject(geom, state,
00556 data.get_net_transform(trav),
00557 data.get_modelview_transform(trav),
00558 trav->get_gsg());
00559 trav->get_cull_handler()->record_object(object, trav);
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575 void RopeNode::
00576 get_connected_segments(RopeNode::CurveSegments &curve_segments,
00577 const NurbsCurveResult *result) const {
00578 int num_verts = get_num_subdiv() + 1;
00579 int num_segments = result->get_num_segments();
00580 bool use_vertex_color = get_use_vertex_color();
00581 bool use_vertex_thickness = get_use_vertex_thickness();
00582
00583 CurveSegment *curve_segment = NULL;
00584 LPoint3f last_point;
00585
00586 for (int segment = 0; segment < num_segments; ++segment) {
00587 LPoint3f point;
00588 result->eval_segment_point(segment, 0.0f, point);
00589
00590 if (curve_segment == (CurveSegment *)NULL ||
00591 !point.almost_equal(last_point)) {
00592
00593
00594
00595 curve_segments.push_back(CurveSegment());
00596 curve_segment = &curve_segments.back();
00597
00598 CurveVertex vtx;
00599 vtx._p = point;
00600 vtx._t = result->get_segment_t(segment, 0.0f);
00601 if (use_vertex_color) {
00602 result->eval_segment_extended_points(segment, 0.0f,
00603 get_vertex_color_dimension(),
00604 &vtx._c[0], 4);
00605 }
00606 if (use_vertex_thickness) {
00607 vtx._thickness =
00608 result->eval_segment_extended_point(segment, 0.0f,
00609 get_vertex_thickness_dimension());
00610 }
00611
00612 curve_segment->push_back(vtx);
00613 }
00614
00615
00616 for (int i = 1; i < num_verts; ++i) {
00617 float t = (float)i / (float)(num_verts - 1);
00618
00619 CurveVertex vtx;
00620 result->eval_segment_point(segment, t, vtx._p);
00621 vtx._t = result->get_segment_t(segment, t);
00622 if (use_vertex_color) {
00623 result->eval_segment_extended_points(segment, t,
00624 get_vertex_color_dimension(),
00625 &vtx._c[0], 4);
00626 }
00627 if (use_vertex_thickness) {
00628 vtx._thickness =
00629 result->eval_segment_extended_point(segment, t,
00630 get_vertex_thickness_dimension());
00631 }
00632
00633 curve_segment->push_back(vtx);
00634
00635 last_point = vtx._p;
00636 }
00637 }
00638 }
00639
00640
00641
00642
00643
00644
00645
00646
00647 void RopeNode::
00648 compute_thread_vertices(GeomVertexData *vdata,
00649 const RopeNode::CurveSegments &curve_segments) const {
00650 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00651 GeomVertexWriter color(vdata, InternalName::get_color());
00652 GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
00653
00654 UVMode uv_mode = get_uv_mode();
00655 float uv_scale = get_uv_scale();
00656 bool u_dominant = get_uv_direction();
00657 bool use_vertex_color = get_use_vertex_color();
00658
00659 float dist = 0.0f;
00660 CurveSegments::const_iterator si;
00661 for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
00662 const CurveSegment &segment = (*si);
00663 for (size_t j = 0; j < segment.size(); ++j) {
00664 vertex.add_data3f(segment[j]._p);
00665
00666 if (use_vertex_color) {
00667 color.add_data4f(segment[j]._c);
00668 }
00669
00670 float uv_t = compute_uv_t(dist, uv_mode, uv_scale, segment, j);
00671
00672 if (uv_mode != UV_none) {
00673 if (u_dominant) {
00674 texcoord.add_data2f(uv_t, 0.0f);
00675 } else {
00676 texcoord.add_data2f(0.0f, uv_t);
00677 }
00678 }
00679 }
00680 }
00681 }
00682
00683
00684
00685
00686
00687
00688
00689
00690 void RopeNode::
00691 compute_billboard_vertices(GeomVertexData *vdata,
00692 const LVector3f &camera_vec,
00693 const RopeNode::CurveSegments &curve_segments,
00694 NurbsCurveResult *result) const {
00695 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00696 GeomVertexWriter color(vdata, InternalName::get_color());
00697 GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
00698
00699 float thickness = get_thickness();
00700 float overall_radius = thickness * 0.5f;
00701 float radius = overall_radius;
00702 UVMode uv_mode = get_uv_mode();
00703 float uv_scale = get_uv_scale();
00704 bool u_dominant = get_uv_direction();
00705 bool use_vertex_color = get_use_vertex_color();
00706 bool use_vertex_thickness = get_use_vertex_thickness();
00707
00708 float dist = 0.0f;
00709 CurveSegments::const_iterator si;
00710 for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
00711 const CurveSegment &segment = (*si);
00712 for (size_t j = 0; j < segment.size(); ++j) {
00713 LVector3f tangent;
00714 compute_tangent(tangent, segment, j, result);
00715
00716 LVector3f norm = cross(tangent, camera_vec);
00717 norm.normalize();
00718
00719 if (use_vertex_thickness) {
00720 radius = overall_radius * segment[j]._thickness;
00721 }
00722
00723 vertex.add_data3f(segment[j]._p + norm * radius);
00724 vertex.add_data3f(segment[j]._p - norm * radius);
00725
00726 if (use_vertex_color) {
00727 color.add_data4f(segment[j]._c);
00728 color.add_data4f(segment[j]._c);
00729 }
00730
00731 float uv_t = compute_uv_t(dist, uv_mode, uv_scale, segment, j);
00732
00733 if (uv_mode != UV_none) {
00734 if (u_dominant) {
00735 texcoord.add_data2f(uv_t, 1.0f);
00736 texcoord.add_data2f(uv_t, 0.0f);
00737 } else {
00738 texcoord.add_data2f(1.0f, uv_t);
00739 texcoord.add_data2f(0.0f, uv_t);
00740 }
00741 }
00742 }
00743 }
00744 }
00745
00746
00747
00748
00749
00750
00751
00752
00753 void RopeNode::
00754 compute_tube_vertices(GeomVertexData *vdata,
00755 int &num_verts_per_slice,
00756 const RopeNode::CurveSegments &curve_segments,
00757 NurbsCurveResult *result) const {
00758 GeomVertexWriter vertex(vdata, InternalName::get_vertex());
00759 GeomVertexWriter normal(vdata, InternalName::get_normal());
00760 GeomVertexWriter color(vdata, InternalName::get_color());
00761 GeomVertexWriter texcoord(vdata, InternalName::get_texcoord());
00762
00763 int num_slices = get_num_slices();
00764 num_verts_per_slice = num_slices;
00765
00766 float thickness = get_thickness();
00767 float overall_radius = thickness * 0.5f;
00768 float radius = overall_radius;
00769 UVMode uv_mode = get_uv_mode();
00770 float uv_scale = get_uv_scale();
00771 bool u_dominant = get_uv_direction();
00772 NormalMode normal_mode = get_normal_mode();
00773 bool use_vertex_color = get_use_vertex_color();
00774 bool use_vertex_thickness = get_use_vertex_thickness();
00775
00776
00777
00778
00779 if (uv_mode != UV_none) {
00780 ++num_verts_per_slice;
00781 }
00782
00783 LVector3f up = get_tube_up();
00784
00785 float dist = 0.0f;
00786 CurveSegments::const_iterator si;
00787 for (si = curve_segments.begin(); si != curve_segments.end(); ++si) {
00788 const CurveSegment &segment = (*si);
00789 for (size_t j = 0; j < segment.size(); ++j) {
00790 LVector3f tangent;
00791 compute_tangent(tangent, segment, j, result);
00792
00793 LVector3f norm = cross(tangent, up);
00794 norm.normalize();
00795 up = cross(norm, tangent);
00796
00797 LMatrix3f rotate = LMatrix3f::rotate_mat(360.0f / (float)num_slices,
00798 tangent);
00799
00800 float uv_t = compute_uv_t(dist, uv_mode, uv_scale, segment, j);
00801
00802 for (int s = 0; s < num_verts_per_slice; ++s) {
00803 if (use_vertex_thickness) {
00804 radius = overall_radius * segment[j]._thickness;
00805 }
00806
00807 vertex.add_data3f(segment[j]._p + norm * radius);
00808
00809 if (normal_mode == NM_vertex) {
00810 normal.add_data3f(norm);
00811 }
00812
00813 if (use_vertex_color) {
00814 color.add_data4f(segment[j]._c);
00815 }
00816
00817 norm = norm * rotate;
00818
00819 if (uv_mode != UV_none) {
00820 float uv_s = (float)s / (float)num_slices;
00821 if (u_dominant) {
00822 texcoord.add_data2f(uv_t, uv_s);
00823 } else {
00824 texcoord.add_data2f(uv_s, uv_t);
00825 }
00826 }
00827 }
00828 }
00829 }
00830 }
00831
00832
00833
00834
00835
00836
00837
00838 void RopeNode::
00839 compute_tangent(LVector3f &tangent, const RopeNode::CurveSegment &segment,
00840 size_t j, NurbsCurveResult *result) {
00841
00842
00843
00844
00845
00846
00847
00848
00849
00850
00851
00852
00853
00854
00855
00856
00857 if (j == 0) {
00858 tangent = segment[j + 1]._p - segment[j]._p;
00859 } else if (j == segment.size() - 1) {
00860 tangent = segment[j]._p - segment[j - 1]._p;
00861 } else {
00862 tangent = segment[j + 1]._p - segment[j - 1]._p;
00863 }
00864 }
00865
00866
00867
00868
00869
00870
00871
00872 float RopeNode::
00873 compute_uv_t(float &dist, const RopeNode::UVMode &uv_mode,
00874 float uv_scale, const RopeNode::CurveSegment &segment,
00875 size_t j) {
00876 switch (uv_mode) {
00877 case UV_none:
00878 return 0.0f;
00879
00880 case UV_parametric:
00881 return segment[j]._t * uv_scale;
00882
00883 case UV_distance:
00884 if (j != 0) {
00885 LVector3f vec = segment[j]._p - segment[j - 1]._p;
00886 dist += vec.length();
00887 }
00888 return dist * uv_scale;
00889
00890 case UV_distance2:
00891 if (j != 0) {
00892 LVector3f vec = segment[j]._p - segment[j - 1]._p;
00893 dist += vec.length_squared();
00894 }
00895 return dist * uv_scale;
00896 }
00897
00898 return 0.0f;
00899 }
00900
00901
00902
00903
00904
00905
00906
00907 void RopeNode::
00908 register_with_read_factory() {
00909 BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00910 }
00911
00912
00913
00914
00915
00916
00917
00918 void RopeNode::
00919 write_datagram(BamWriter *manager, Datagram &dg) {
00920 PandaNode::write_datagram(manager, dg);
00921 manager->write_cdata(dg, _cycler);
00922 }
00923
00924
00925
00926
00927
00928
00929
00930
00931
00932 TypedWritable *RopeNode::
00933 make_from_bam(const FactoryParams ¶ms) {
00934 RopeNode *node = new RopeNode("");
00935 DatagramIterator scan;
00936 BamReader *manager;
00937
00938 parse_params(params, scan, manager);
00939 node->fillin(scan, manager);
00940
00941 return node;
00942 }
00943
00944
00945
00946
00947
00948
00949
00950
00951 void RopeNode::
00952 fillin(DatagramIterator &scan, BamReader *manager) {
00953 PandaNode::fillin(scan, manager);
00954 manager->read_cdata(scan, _cycler);
00955 }