Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

panda/src/parametrics/ropeNode.cxx

Go to the documentation of this file.
00001 // Filename: ropeNode.cxx
00002 // Created by:  drose (04Dec02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) 2001, Disney Enterprises, Inc.  All rights reserved
00008 //
00009 // All use of this software is subject to the terms of the Panda 3d
00010 // Software license.  You should have received a copy of this license
00011 // along with this source code; you will also find a current copy of
00012 // the license at http://www.panda3d.org/license.txt .
00013 //
00014 // To contact the maintainers of this program write to
00015 // panda3d@yahoogroups.com .
00016 //
00017 ////////////////////////////////////////////////////////////////////
00018 
00019 #include "ropeNode.h"
00020 #include "cullTraverser.h"
00021 #include "cullTraverserData.h"
00022 #include "cullableObject.h"
00023 #include "cullHandler.h"
00024 #include "geomLinestrip.h"
00025 #include "geomTristrip.h"
00026 #include "bamWriter.h"
00027 #include "bamReader.h"
00028 #include "datagram.h"
00029 #include "datagramIterator.h"
00030 
00031 TypeHandle RopeNode::_type_handle;
00032 
00033 ////////////////////////////////////////////////////////////////////
00034 //     Function: RopeNode::CData::make_copy
00035 //       Access: Public, Virtual
00036 //  Description:
00037 ////////////////////////////////////////////////////////////////////
00038 CycleData *RopeNode::CData::
00039 make_copy() const {
00040   return new CData(*this);
00041 }
00042 
00043 ////////////////////////////////////////////////////////////////////
00044 //     Function: RopeNode::CData::write_datagram
00045 //       Access: Public, Virtual
00046 //  Description: Writes the contents of this object to the datagram
00047 //               for shipping out to a Bam file.
00048 ////////////////////////////////////////////////////////////////////
00049 void RopeNode::CData::
00050 write_datagram(BamWriter *writer, Datagram &dg) const {
00051   // For now, we write a NULL pointer.  Eventually we will write out
00052   // the NurbsCurveEvaluator pointer.
00053   writer->write_pointer(dg, (TypedWritable *)NULL);
00054 }
00055 
00056 ////////////////////////////////////////////////////////////////////
00057 //     Function: RopeNode::CData::fillin
00058 //       Access: Public, Virtual
00059 //  Description: This internal function is called by make_from_bam to
00060 //               read in all of the relevant data from the BamFile for
00061 //               the new RopeNode.
00062 ////////////////////////////////////////////////////////////////////
00063 void RopeNode::CData::
00064 fillin(DatagramIterator &scan, BamReader *reader) {
00065   // For now, we skip over the NULL pointer that we wrote out.
00066   reader->skip_pointer(scan);
00067 }
00068 
00069 ////////////////////////////////////////////////////////////////////
00070 //     Function: RopeNode::Constructor
00071 //       Access: Public
00072 //  Description:
00073 ////////////////////////////////////////////////////////////////////
00074 RopeNode::
00075 RopeNode(const string &name) :
00076   PandaNode(name)
00077 {
00078 }
00079 
00080 ////////////////////////////////////////////////////////////////////
00081 //     Function: RopeNode::Copy Constructor
00082 //       Access: Protected
00083 //  Description:
00084 ////////////////////////////////////////////////////////////////////
00085 RopeNode::
00086 RopeNode(const RopeNode &copy) :
00087   PandaNode(copy),
00088   _cycler(copy._cycler)
00089 {
00090 }
00091 
00092 ////////////////////////////////////////////////////////////////////
00093 //     Function: RopeNode::make_copy
00094 //       Access: Public, Virtual
00095 //  Description: Returns a newly-allocated Node that is a shallow copy
00096 //               of this one.  It will be a different Node pointer,
00097 //               but its internal data may or may not be shared with
00098 //               that of the original Node.
00099 ////////////////////////////////////////////////////////////////////
00100 PandaNode *RopeNode::
00101 make_copy() const {
00102   return new RopeNode(*this);
00103 }
00104 
00105 ////////////////////////////////////////////////////////////////////
00106 //     Function: RopeNode::safe_to_transform
00107 //       Access: Public, Virtual
00108 //  Description: Returns true if it is generally safe to transform
00109 //               this particular kind of Node by calling the xform()
00110 //               method, false otherwise.  For instance, it's usually
00111 //               a bad idea to attempt to xform a RopeNode.
00112 ////////////////////////////////////////////////////////////////////
00113 bool RopeNode::
00114 safe_to_transform() const {
00115   return false;
00116 }
00117 
00118 ////////////////////////////////////////////////////////////////////
00119 //     Function: RopeNode::has_cull_callback
00120 //       Access: Public, Virtual
00121 //  Description: Should be overridden by derived classes to return
00122 //               true if cull_callback() has been defined.  Otherwise,
00123 //               returns false to indicate cull_callback() does not
00124 //               need to be called for this node during the cull
00125 //               traversal.
00126 ////////////////////////////////////////////////////////////////////
00127 bool RopeNode::
00128 has_cull_callback() const {
00129   return true;
00130 }
00131 
00132 ////////////////////////////////////////////////////////////////////
00133 //     Function: RopeNode::cull_callback
00134 //       Access: Public, Virtual
00135 //  Description: If has_cull_callback() returns true, this function
00136 //               will be called during the cull traversal to perform
00137 //               any additional operations that should be performed at
00138 //               cull time.  This may include additional manipulation
00139 //               of render state or additional visible/invisible
00140 //               decisions, or any other arbitrary operation.
00141 //
00142 //               By the time this function is called, the node has
00143 //               already passed the bounding-volume test for the
00144 //               viewing frustum, and the node's transform and state
00145 //               have already been applied to the indicated
00146 //               CullTraverserData object.
00147 //
00148 //               The return value is true if this node should be
00149 //               visible, or false if it should be culled.
00150 ////////////////////////////////////////////////////////////////////
00151 bool RopeNode::
00152 cull_callback(CullTraverser *trav, CullTraverserData &data) {
00153   // Create some geometry on-the-fly to render the rope.
00154   if (get_num_segs() > 0) {
00155     NurbsCurveEvaluator *curve = get_curve();
00156     PT(NurbsCurveResult) result = curve->evaluate(data._node_path.get_node_path());
00157 
00158     if (result->get_num_segments() > 0) {
00159       switch (get_render_mode()) {
00160       case RM_thread:
00161         render_thread(trav, data, result);
00162         break;
00163 
00164       case RM_billboard:
00165         render_billboard(trav, data, result);
00166         break;
00167       }
00168     }
00169   }
00170   
00171   return true;
00172 }
00173 
00174 ////////////////////////////////////////////////////////////////////
00175 //     Function: RopeNode::output
00176 //       Access: Public, Virtual
00177 //  Description: 
00178 ////////////////////////////////////////////////////////////////////
00179 void RopeNode::
00180 output(ostream &out) const {
00181   PandaNode::output(out);
00182   out << " " << get_curve();
00183 }
00184 
00185 ////////////////////////////////////////////////////////////////////
00186 //     Function: RopeNode::write
00187 //       Access: Public, Virtual
00188 //  Description: 
00189 ////////////////////////////////////////////////////////////////////
00190 void RopeNode::
00191 write(ostream &out, int indent_level) const {
00192   PandaNode::write(out, indent_level);
00193   indent(out, indent_level) << get_curve() << "\n";
00194 }
00195 
00196 ////////////////////////////////////////////////////////////////////
00197 //     Function: RopeNode::reset_bound
00198 //       Access: Published
00199 //  Description: Recomputes the bounding volume.  This is normally
00200 //               called automatically, but it must occasionally be
00201 //               called explicitly when the curve has changed
00202 //               properties outside of this node's knowledge.
00203 ////////////////////////////////////////////////////////////////////
00204 void RopeNode::
00205 reset_bound(const NodePath &rel_to) {
00206   do_recompute_bound(rel_to);
00207   changed_internal_bound();
00208 }
00209 
00210 ////////////////////////////////////////////////////////////////////
00211 //     Function: RopeNode::recompute_internal_bound
00212 //       Access: Protected, Virtual
00213 //  Description: Called when needed to recompute the node's
00214 //               _internal_bound object.  Nodes that contain anything
00215 //               of substance should redefine this to do the right
00216 //               thing.
00217 ////////////////////////////////////////////////////////////////////
00218 BoundingVolume *RopeNode::
00219 recompute_internal_bound() {
00220   return do_recompute_bound(NodePath(this));
00221 }
00222 
00223 ////////////////////////////////////////////////////////////////////
00224 //     Function: RopeNode::do_recompute_bound
00225 //       Access: Private
00226 //  Description: Does the actual internal recompute.
00227 ////////////////////////////////////////////////////////////////////
00228 BoundingVolume *RopeNode::
00229 do_recompute_bound(const NodePath &rel_to) {
00230   // First, get ourselves a fresh, empty bounding volume.
00231   BoundingVolume *bound = PandaNode::recompute_internal_bound();
00232   nassertr(bound != (BoundingVolume *)NULL, bound);
00233   
00234   NurbsCurveEvaluator *curve = get_curve();
00235   if (curve != (NurbsCurveEvaluator *)NULL) {
00236     pvector<LPoint3f> verts;
00237     get_curve()->get_vertices(verts, rel_to);
00238     
00239     GeometricBoundingVolume *gbv;
00240     DCAST_INTO_R(gbv, bound, bound);
00241     gbv->around(&verts[0], &verts[verts.size() - 1]);
00242   }
00243   return bound;
00244 }
00245 
00246 ////////////////////////////////////////////////////////////////////
00247 //     Function: RopeNode::render_thread
00248 //       Access: Private
00249 //  Description: Draws the rope in RM_thread mode.  This uses a
00250 //               GeomLinestrip to draw the rope in the simplest
00251 //               possible method, generally resulting in a
00252 //               one-pixel-wide curve.
00253 //
00254 //               In this mode, the thickness parameter represents a
00255 //               thickness in pixels, and is passed to the linestrip.
00256 //               However, you should be aware the DirectX does not
00257 //               support line thickness.
00258 ////////////////////////////////////////////////////////////////////
00259 void RopeNode::
00260 render_thread(CullTraverser *trav, CullTraverserData &data, 
00261               NurbsCurveResult *result) {
00262   UVMode uv_mode = get_uv_mode();
00263   LVecBase2f uv_scale = get_uv_scale();
00264 
00265   PTA_Vertexf verts;
00266   PTA_TexCoordf uvs;
00267   PTA_Colorf colors;
00268   PTA_int lengths;
00269 
00270   int num_verts = get_num_segs() + 1;
00271   int num_segments = result->get_num_segments();
00272   float dist = 0.0f;
00273   for (int segment = 0; segment < num_segments; segment++) {
00274     LPoint3f last_point;
00275     for (int i = 0; i < num_verts; i++) {
00276       float t = (float)i / (float)(num_verts - 1);
00277       LPoint3f point;
00278       result->eval_segment_point(segment, t, point);
00279       verts.push_back(point);
00280 
00281       t = result->get_segment_t(segment, t);
00282       switch (uv_mode) {
00283       case UV_none:
00284         break;
00285         
00286       case UV_parametric:
00287         uvs.push_back(TexCoordf(t * uv_scale[0], 0.0f));
00288         break;
00289 
00290       case UV_distance:
00291         if (i != 0) {
00292           LVector3f vec = point - last_point;
00293           dist += vec.length();
00294         }
00295         uvs.push_back(TexCoordf(dist * uv_scale[0], 0.0f));
00296         break;
00297 
00298       case UV_distance2:
00299         if (i != 0) {
00300           LVector3f vec = point - last_point;
00301           dist += vec.length_squared();
00302         }
00303         uvs.push_back(TexCoordf(dist * uv_scale[0], 0.0f));
00304         break;
00305       }
00306 
00307       last_point = point;
00308     }
00309     lengths.push_back(num_verts);
00310   }
00311 
00312   colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
00313   
00314   PT(GeomLinestrip) geom = new GeomLinestrip;
00315   geom->set_width(get_thickness());
00316   geom->set_num_prims(num_segments);
00317   geom->set_coords(verts);
00318   if (uv_mode != UV_none) {
00319     geom->set_texcoords(uvs, G_PER_VERTEX);
00320   }
00321   geom->set_colors(colors, G_OVERALL);
00322   geom->set_lengths(lengths);
00323   
00324   CullableObject *object = new CullableObject(geom, data._state,
00325                                               data._render_transform);
00326   trav->get_cull_handler()->record_object(object);
00327 }
00328 
00329 ////////////////////////////////////////////////////////////////////
00330 //     Function: RopeNode::render_billboard
00331 //       Access: Private
00332 //  Description: Draws the rope in RM_billboard mode.  This draws a
00333 //               series of triangle strips oriented to be
00334 //               perpendicular to the camera plane.
00335 //
00336 //               In this mode, thickness is in spatial units, and
00337 //               determines the with of the triangle strips.
00338 ////////////////////////////////////////////////////////////////////
00339 void RopeNode::
00340 render_billboard(CullTraverser *trav, CullTraverserData &data, 
00341                  NurbsCurveResult *result) {
00342   const TransformState *net_transform = data._net_transform;
00343   const TransformState *camera_transform = trav->get_camera_transform();
00344 
00345   CPT(TransformState) rel_transform =
00346     net_transform->invert_compose(camera_transform);
00347   LVector3f camera_vec = LVector3f::forward() * rel_transform->get_mat();
00348 
00349   float thickness = get_thickness();
00350   float radius = thickness * 0.5f;
00351   UVMode uv_mode = get_uv_mode();
00352   LVecBase2f uv_scale = get_uv_scale();
00353 
00354   // We can't just build one tristrip per segment.  Instead, we should
00355   // build one continuous tristrip for all connected segments, so we
00356   // can stitch them together properly at the seams.
00357 
00358   int num_verts = get_num_segs() + 1;
00359   int num_segments = result->get_num_segments();
00360 
00361   vector_Vertexf center_verts;
00362   vector_int center_lengths;
00363   vector_float center_t;
00364 
00365   LPoint3f point;
00366   int cur_length = 0;
00367   for (int segment = 0; segment < num_segments; segment++) {
00368     LPoint3f first_point;
00369     result->eval_segment_point(segment, 0.0f, first_point);
00370     if (cur_length == 0 || point != first_point) {
00371       // If the first point of this segment is different from the last
00372       // point of the previous segment, end the tristrip and store the
00373       // point.
00374       if (cur_length != 0) {
00375         center_lengths.push_back(cur_length);
00376       }
00377       center_verts.push_back(first_point);
00378       center_t.push_back(result->get_segment_t(segment, 0.0f));
00379       cur_length = 1;
00380     }
00381 
00382     // Store all the remaining points in this segment.
00383     for (int i = 1; i < num_verts; i++) {
00384       float t = (float)i / (float)(num_verts - 1);
00385       result->eval_segment_point(segment, t, point);
00386       center_verts.push_back(point);
00387       center_t.push_back(result->get_segment_t(segment, t));
00388       cur_length++;
00389     }
00390   }
00391   if (cur_length != 0) {
00392     center_lengths.push_back(cur_length);
00393   }
00394 
00395   // Now we have stored one or more sequences of vertices down the
00396   // center strips.  Go back and convert them into actual tristrips.
00397 
00398   PTA_Vertexf verts;
00399   PTA_TexCoordf uvs;
00400   PTA_Colorf colors;
00401   PTA_int lengths;
00402 
00403   int vi = 0;
00404   int num_prims = 0;
00405   float dist = 0.0f;
00406   for (int i = 0; i < (int)center_lengths.size(); i++) {
00407     int length = center_lengths[i];
00408     for (int j = 0; j < length; j++) {
00409       const Vertexf &point = center_verts[vi + j];
00410       float t = center_t[vi + j];
00411       LVector3f tangent;
00412       // Rather than evaluating the curve for the tangent, we derive
00413       // it from the neighboring points.  This gives us better
00414       // behavior at the endpoints, where the tangent might go to
00415       // zero.
00416       if (j == 0) {
00417         tangent = center_verts[vi + j + 1] - point;
00418       } else if (j == length - 1) {
00419         tangent = point - center_verts[vi + j - 1];
00420       } else {
00421         tangent = center_verts[vi + j + 1] - center_verts[vi + j - 1];
00422       }
00423       LVector3f cross = normalize(tangent.cross(camera_vec));
00424       cross *= radius;
00425       verts.push_back(point + cross);
00426       verts.push_back(point - cross);
00427       switch (uv_mode) {
00428       case UV_none:
00429         break;
00430 
00431       case UV_parametric:
00432         uvs.push_back(TexCoordf(t * uv_scale[0], uv_scale[1]));
00433         uvs.push_back(TexCoordf(t * uv_scale[0], 0.0f));
00434         break;
00435 
00436       case UV_distance:
00437         if (j != 0) {
00438           LVector3f vec = point - center_verts[vi + j - 1];
00439           dist += vec.length();
00440         }
00441         uvs.push_back(TexCoordf(dist * uv_scale[0], thickness * uv_scale[1]));
00442         uvs.push_back(TexCoordf(dist * uv_scale[0], 0.0f));
00443         break;
00444 
00445       case UV_distance2:
00446         if (j != 0) {
00447           LVector3f vec = point - center_verts[vi + j - 1];
00448           dist += vec.length_squared();
00449         }
00450         uvs.push_back(TexCoordf(dist * uv_scale[0], thickness * uv_scale[1]));
00451         uvs.push_back(TexCoordf(dist * uv_scale[0], 0.0f));
00452         break;
00453       }
00454     }
00455     vi += length;
00456     lengths.push_back(length * 2);
00457     num_prims++;
00458   }
00459 
00460   colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
00461   
00462   PT(Geom) geom = new GeomTristrip;
00463   geom->set_num_prims(num_prims);
00464   geom->set_coords(verts);
00465   if (uv_mode != UV_none) {
00466     geom->set_texcoords(uvs, G_PER_VERTEX);
00467   }
00468   geom->set_colors(colors, G_OVERALL);
00469   geom->set_lengths(lengths);
00470   
00471   CullableObject *object = new CullableObject(geom, data._state,
00472                                               data._render_transform);
00473   trav->get_cull_handler()->record_object(object);
00474 }
00475 
00476 ////////////////////////////////////////////////////////////////////
00477 //     Function: RopeNode::register_with_read_factory
00478 //       Access: Public, Static
00479 //  Description: Tells the BamReader how to create objects of type
00480 //               RopeNode.
00481 ////////////////////////////////////////////////////////////////////
00482 void RopeNode::
00483 register_with_read_factory() {
00484   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00485 }
00486 
00487 ////////////////////////////////////////////////////////////////////
00488 //     Function: RopeNode::write_datagram
00489 //       Access: Public, Virtual
00490 //  Description: Writes the contents of this object to the datagram
00491 //               for shipping out to a Bam file.
00492 ////////////////////////////////////////////////////////////////////
00493 void RopeNode::
00494 write_datagram(BamWriter *manager, Datagram &dg) {
00495   PandaNode::write_datagram(manager, dg);
00496   manager->write_cdata(dg, _cycler);
00497 }
00498 
00499 ////////////////////////////////////////////////////////////////////
00500 //     Function: RopeNode::make_from_bam
00501 //       Access: Protected, Static
00502 //  Description: This function is called by the BamReader's factory
00503 //               when a new object of type RopeNode is encountered
00504 //               in the Bam file.  It should create the RopeNode
00505 //               and extract its information from the file.
00506 ////////////////////////////////////////////////////////////////////
00507 TypedWritable *RopeNode::
00508 make_from_bam(const FactoryParams &params) {
00509   RopeNode *node = new RopeNode("");
00510   DatagramIterator scan;
00511   BamReader *manager;
00512 
00513   parse_params(params, scan, manager);
00514   node->fillin(scan, manager);
00515 
00516   return node;
00517 }
00518 
00519 ////////////////////////////////////////////////////////////////////
00520 //     Function: RopeNode::fillin
00521 //       Access: Protected
00522 //  Description: This internal function is called by make_from_bam to
00523 //               read in all of the relevant data from the BamFile for
00524 //               the new RopeNode.
00525 ////////////////////////////////////////////////////////////////////
00526 void RopeNode::
00527 fillin(DatagramIterator &scan, BamReader *manager) {
00528   PandaNode::fillin(scan, manager);
00529   manager->read_cdata(scan, _cycler);
00530 }

Generated on Fri May 2 00:40:53 2003 for Panda by doxygen1.3