Panda3D
 All Classes Functions Variables Enumerations
portalNode.cxx
00001 // Filename: portalNode.cxx
00002 // Created by:  drose (16Mar02)
00003 //
00004 ////////////////////////////////////////////////////////////////////
00005 //
00006 // PANDA 3D SOFTWARE
00007 // Copyright (c) Carnegie Mellon University.  All rights reserved.
00008 //
00009 // All use of this software is subject to the terms of the revised BSD
00010 // license.  You should have received a copy of this license along
00011 // with this source code in a file named "LICENSE."
00012 //
00013 ////////////////////////////////////////////////////////////////////
00014 
00015 #include "portalNode.h"
00016 
00017 #include "geomNode.h"
00018 #include "cullTraverserData.h"
00019 #include "cullTraverser.h"
00020 #include "renderState.h"
00021 #include "portalClipper.h"
00022 #include "transformState.h"
00023 #include "colorScaleAttrib.h"
00024 #include "transparencyAttrib.h"
00025 #include "datagram.h"
00026 #include "datagramIterator.h"
00027 #include "bamReader.h"
00028 #include "bamWriter.h"
00029 
00030 #include "plane.h"
00031 
00032 TypeHandle PortalNode::_type_handle;
00033 
00034 
00035 ////////////////////////////////////////////////////////////////////
00036 //     Function: PortalNode::Constructor
00037 //       Access: Public
00038 //  Description: Default constructor, just an empty node, no geo
00039 //               This is used to read portal from model. You can also
00040 //               use this from python to create an empty portal. Then
00041 //               you can set the vertices yourself, with addVertex.
00042 ////////////////////////////////////////////////////////////////////
00043 PortalNode::
00044 PortalNode(const string &name) :
00045   PandaNode(name),
00046   _from_portal_mask(PortalMask::all_on()),
00047   _into_portal_mask(PortalMask::all_on()),
00048   _flags(0)
00049 {
00050   set_cull_callback();
00051 
00052   _visible = false;
00053   _open = true;
00054   _clip_plane = false;
00055   _max_depth = 10;
00056 }
00057 
00058 ////////////////////////////////////////////////////////////////////
00059 //     Function: PortalNode::Constructor
00060 //       Access: Public
00061 //  Description: Create a default rectangle as portal. Use this
00062 //               to create an arbitrary portal and setup from Python
00063 ////////////////////////////////////////////////////////////////////
00064 PortalNode::
00065 PortalNode(const string &name, LPoint3 pos, PN_stdfloat scale) :
00066   PandaNode(name),
00067   _from_portal_mask(PortalMask::all_on()),
00068   _into_portal_mask(PortalMask::all_on()),
00069   _flags(0)
00070 {
00071   set_cull_callback();
00072 
00073   add_vertex(LPoint3(pos[0]-1.0*scale, pos[1], pos[2]-1.0*scale));
00074   add_vertex(LPoint3(pos[0]+1.0*scale, pos[1], pos[2]-1.0*scale));
00075   add_vertex(LPoint3(pos[0]+1.0*scale, pos[1], pos[2]+1.0*scale));
00076   add_vertex(LPoint3(pos[0]-1.0*scale, pos[1], pos[2]+1.0*scale));
00077 
00078   _visible = false;
00079   _open = true;
00080   _clip_plane = false;
00081   _max_depth = 10;
00082 }
00083 
00084 ////////////////////////////////////////////////////////////////////
00085 //     Function: PortalNode::Copy Constructor
00086 //       Access: Protected
00087 //  Description:
00088 ////////////////////////////////////////////////////////////////////
00089 PortalNode::
00090 PortalNode(const PortalNode &copy) :
00091   PandaNode(copy),
00092   _from_portal_mask(copy._from_portal_mask),
00093   _into_portal_mask(copy._into_portal_mask),
00094   _flags(copy._flags),
00095   _vertices(copy._vertices),
00096   _cell_in(copy._cell_in),
00097   _cell_out(copy._cell_out),
00098   _clip_plane(copy._clip_plane),
00099   _visible(copy._visible),
00100   _open(copy._open),
00101   _max_depth(copy._max_depth)
00102 {
00103 }
00104 
00105 ////////////////////////////////////////////////////////////////////
00106 //     Function: PortalNode::Destructor
00107 //       Access: Public, Virtual
00108 //  Description:
00109 ////////////////////////////////////////////////////////////////////
00110 PortalNode::
00111 ~PortalNode() {
00112 }
00113 
00114 ////////////////////////////////////////////////////////////////////
00115 //     Function: PortalNode::make_copy
00116 //       Access: Public, Virtual
00117 //  Description: Returns a newly-allocated Node that is a shallow copy
00118 //               of this one.  It will be a different Node pointer,
00119 //               but its internal data may or may not be shared with
00120 //               that of the original Node.
00121 ////////////////////////////////////////////////////////////////////
00122 PandaNode *PortalNode::
00123 make_copy() const {
00124   return new PortalNode(*this);
00125 }
00126 
00127 ////////////////////////////////////////////////////////////////////
00128 //     Function: PortalNode::preserve_name
00129 //       Access: Public, Virtual
00130 //  Description: Returns true if the node's name has extrinsic meaning
00131 //               and must be preserved across a flatten operation,
00132 //               false otherwise.
00133 ////////////////////////////////////////////////////////////////////
00134 bool PortalNode::
00135 preserve_name() const {
00136   return true;
00137 }
00138 
00139 ////////////////////////////////////////////////////////////////////
00140 //     Function: PortalNode::enable_clipping_planes
00141 //       Access: Public, Virtual
00142 //  Description: initialize the clipping planes and renderstate
00143 ////////////////////////////////////////////////////////////////////
00144 void PortalNode::
00145 enable_clipping_planes() {
00146   _top_plane_node = new PlaneNode("top");
00147   NodePath top_plane_np = NodePath(this).attach_new_node(_top_plane_node);
00148 
00149   _bottom_plane_node = new PlaneNode("bottom");
00150   NodePath bottom_plane_np = NodePath(this).attach_new_node(_bottom_plane_node);
00151 
00152   _left_plane_node = new PlaneNode("left");
00153   NodePath left_plane_np = NodePath(this).attach_new_node(_left_plane_node);
00154 
00155   _right_plane_node = new PlaneNode("right");
00156   NodePath right_plane_np = NodePath(this).attach_new_node(_right_plane_node);
00157 
00158   CPT(RenderAttrib) plane_attrib = ClipPlaneAttrib::make();
00159   plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(top_plane_np));
00160   plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(bottom_plane_np));
00161   plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(left_plane_np));
00162   plane_attrib = DCAST(ClipPlaneAttrib, plane_attrib)->add_on_plane(NodePath(right_plane_np));
00163 
00164   _clip_state = RenderState::make(plane_attrib);
00165 }
00166 
00167 ////////////////////////////////////////////////////////////////////
00168 //     Function: PortalNode::xform
00169 //       Access: Public, Virtual
00170 //  Description: Transforms the contents of this node by the indicated
00171 //               matrix, if it means anything to do so.  For most
00172 //               kinds of nodes, this does nothing.
00173 ////////////////////////////////////////////////////////////////////
00174 void PortalNode::
00175 xform(const LMatrix4 &mat) {
00176   nassertv(!mat.is_nan());
00177 
00178 }
00179 
00180 ////////////////////////////////////////////////////////////////////
00181 //     Function: PortalNode::combine_with
00182 //       Access: Public, Virtual
00183 //  Description: Collapses this node with the other node, if possible,
00184 //               and returns a pointer to the combined node, or NULL
00185 //               if the two nodes cannot safely be combined.
00186 //
00187 //               The return value may be this, other, or a new node
00188 //               altogether.
00189 //
00190 //               This function is called from GraphReducer::flatten(),
00191 //               and need not deal with children; its job is just to
00192 //               decide whether to collapse the two nodes and what the
00193 //               collapsed node should look like.
00194 ////////////////////////////////////////////////////////////////////
00195 PandaNode *PortalNode::
00196 combine_with(PandaNode *other) {
00197   if (is_exact_type(get_class_type()) &&
00198       other->is_exact_type(get_class_type())) {
00199     // Two PortalNodes can combine, but only if they have the same
00200     // name, because the name is often meaningful.
00201     PortalNode *cother = DCAST(PortalNode, other);
00202     if (get_name() == cother->get_name()) {
00203       return this;
00204     }
00205 
00206     // Two PortalNodes with different names can't combine.
00207     return (PandaNode *)NULL;
00208   }
00209 
00210   return PandaNode::combine_with(other);
00211 }
00212 
00213 ////////////////////////////////////////////////////////////////////
00214 //     Function: PortalNode::cull_callback
00215 //       Access: Public, Virtual
00216 //  Description: This function will be called during the cull
00217 //               traversal to perform reduced frustum
00218 //               culling. Basically, once the scenegraph comes across
00219 //               a portal node, it calculates a CulltraverserData with
00220 //               which cell, this portal leads out to and the new
00221 //               frustum.  Then it traverses that child
00222 //
00223 //               The return value is true if this node should be
00224 //               visible, or false if it should be culled.
00225 ////////////////////////////////////////////////////////////////////
00226 bool PortalNode::
00227 cull_callback(CullTraverser *trav, CullTraverserData &data) {
00228   Thread *current_thread = trav->get_current_thread();
00229 
00230   PortalClipper *portal_viewer = trav->get_portal_clipper();
00231   set_visible(false);
00232   if (is_open() && !_cell_out.is_empty() && portal_viewer && data._portal_depth <= _max_depth) {
00233     portal_cat.debug() << "checking portal node  " << *this << endl;
00234     portal_cat.debug() << "portal_depth is " << data._portal_depth << endl;
00235     PT(GeometricBoundingVolume) vf = trav->get_view_frustum();
00236     PT(BoundingVolume) reduced_frustum;
00237     
00238     // remember old viewport and frustum, so we can restore them for the siblings. (it gets changed by the prepare_portal call)
00239     LPoint2 old_reduced_viewport_min, old_reduced_viewport_max;
00240     portal_viewer->get_reduced_viewport(old_reduced_viewport_min, old_reduced_viewport_max);
00241     PT(BoundingHexahedron) old_bh = portal_viewer->get_reduced_frustum();
00242 
00243     if (portal_viewer->prepare_portal(data._node_path.get_node_path())) {
00244       if ((reduced_frustum = portal_viewer->get_reduced_frustum())) {
00245         // remember current clip state, we might change it
00246         CPT(RenderState) old_clip_state = portal_viewer->get_clip_state();
00247 
00248         set_visible(true);
00249         // The frustum is in camera space
00250         vf = DCAST(GeometricBoundingVolume, reduced_frustum);
00251         
00252         // create a copy of this reduced frustum, we'll transform it from camera space to the cell_out space
00253         PT(BoundingHexahedron) new_bh = DCAST(BoundingHexahedron, vf->make_copy());
00254         
00255         // Get the net trasform of the _cell_out as seen from the camera.
00256         CPT(TransformState) cell_transform = _cell_out.get_net_transform();
00257         CPT(TransformState) frustum_transform = cell_transform ->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform());
00258 
00259         // transform to _cell_out space
00260         new_bh->xform(frustum_transform->get_mat());
00261         
00262         CPT(RenderState) next_state = data._state;
00263 
00264         // set clipping planes, if desired..
00265         if (_clip_plane) {
00266           // create a copy of this reduced frustum, we'll transform it from camera space to this portal node's space (because the clip planes are attached to this node)
00267           PT(BoundingHexahedron) temp_bh = DCAST(BoundingHexahedron, vf->make_copy());
00268           CPT(TransformState) temp_frustum_transform = data._node_path.get_node_path().get_net_transform()->invert_compose(portal_viewer->_scene_setup->get_cull_center().get_net_transform());
00269           
00270           portal_cat.spam() << "clipping plane frustum transform " << *temp_frustum_transform << endl;
00271           portal_cat.spam() << "frustum before transform " << *temp_bh << endl; 
00272           // transform to portalNode space
00273           temp_bh->xform(temp_frustum_transform->get_mat());
00274 
00275           portal_cat.spam() << "frustum after transform " << *temp_bh << endl;
00276           
00277           _left_plane_node->set_plane(-temp_bh->get_plane(4)); // left plane of bh
00278           _right_plane_node->set_plane(-temp_bh->get_plane(2));// right plane of bh
00279           _top_plane_node->set_plane(-temp_bh->get_plane(3)); // top plane of bh
00280           _bottom_plane_node->set_plane(-temp_bh->get_plane(1));// bottom plane of bh
00281 
00282           portal_cat.spam() << "left plane " << *_left_plane_node << endl;
00283           portal_cat.spam() << "right plane " << *_right_plane_node << endl;
00284           portal_cat.spam() << "top plane " << *_top_plane_node << endl;
00285           portal_cat.spam() << "bottom plane " << *_bottom_plane_node << endl;
00286 
00287           // remember the clip state we just generated
00288           portal_viewer->set_clip_state(_clip_state);
00289 
00290           if (old_clip_state) {
00291             portal_cat.spam() << "parent clip state " << *old_clip_state << endl;
00292           } else {
00293             portal_cat.spam() << "parent clip state None" << endl;
00294           }
00295           portal_cat.spam() << "own clip state " << *_clip_state << endl;
00296           portal_cat.spam() << "next state " << *next_state << endl;
00297 
00298           // undo parent clip state and compose our new clip state ito the new state
00299           if (old_clip_state != NULL) {
00300               next_state = old_clip_state->invert_compose(next_state);
00301               portal_cat.spam() << "next state after removing parent state " << *next_state << endl;
00302           }
00303           next_state = next_state->compose(_clip_state);
00304           portal_cat.spam() << "next state after composition " << *next_state << endl;
00305         }
00306 
00307         CullTraverserData next_data(_cell_out, 
00308                                     cell_transform,
00309                                     next_state, new_bh,
00310                                     current_thread);
00311         next_data._portal_depth = data._portal_depth + 1;
00312 
00313         portal_viewer->set_reduced_frustum(new_bh);
00314         portal_cat.spam() << "cull_callback: before traversing " << _cell_out.get_name() << endl;
00315         trav->traverse_below(next_data);
00316         portal_cat.spam() << "cull_callback: after traversing " << _cell_out.get_name() << endl;
00317 
00318         // restore clip state
00319         portal_viewer->set_clip_state(old_clip_state);
00320       }
00321     }
00322     // reset portal viewer frustum for the siblings;
00323     portal_viewer->set_reduced_frustum(old_bh);
00324     // reset portal viewer viewport for the siblings;
00325     portal_viewer->set_reduced_viewport(old_reduced_viewport_min, old_reduced_viewport_max);
00326   }
00327   // Now carry on to render our child nodes.
00328   return true;
00329 }
00330 
00331 ////////////////////////////////////////////////////////////////////
00332 //     Function: PortalNode::is_renderable
00333 //       Access: Public, Virtual
00334 //  Description: Returns true if there is some value to visiting this
00335 //               particular node during the cull traversal for any
00336 //               camera, false otherwise.  This will be used to
00337 //               optimize the result of get_net_draw_show_mask(), so
00338 //               that any subtrees that contain only nodes for which
00339 //               is_renderable() is false need not be visited.
00340 ////////////////////////////////////////////////////////////////////
00341 bool PortalNode::
00342 is_renderable() const {
00343   return true;
00344 }
00345 
00346 
00347 ////////////////////////////////////////////////////////////////////
00348 //     Function: PortalNode::output
00349 //       Access: Public, Virtual
00350 //  Description: Writes a brief description of the node to the
00351 //               indicated output stream.  This is invoked by the <<
00352 //               operator.  It may be overridden in derived classes to
00353 //               include some information relevant to the class.
00354 ////////////////////////////////////////////////////////////////////
00355 void PortalNode::
00356 output(ostream &out) const {
00357   PandaNode::output(out);
00358 }
00359 
00360 /*
00361 ////////////////////////////////////////////////////////////////////
00362 //     Function: PortalNode::draw
00363 //       Access: Public
00364 //  Description: Draws the vertices of this portal rectangle to the 
00365 //               screen with a line 
00366 
00367 ////////////////////////////////////////////////////////////////////
00368 void PortalNode::
00369 draw() const {
00370   move_to(get_vertex(0));
00371   draw_to(get_vertex(1));
00372   draw_to(get_vertex(2));
00373   draw_to(get_vertex(3));
00374 }
00375 */
00376 
00377 ////////////////////////////////////////////////////////////////////
00378 //     Function: PortalNode::compute_internal_bounds
00379 //       Access: Protected, Virtual
00380 //  Description: Called when needed to recompute the node's
00381 //               _internal_bound object.  Nodes that contain anything
00382 //               of substance should redefine this to do the right
00383 //               thing.
00384 ////////////////////////////////////////////////////////////////////
00385 void PortalNode::
00386 compute_internal_bounds(CPT(BoundingVolume) &internal_bounds,
00387                         int &internal_vertices,
00388                         int pipeline_stage,
00389                         Thread *current_thread) const {
00390   // First, get ourselves a fresh, empty bounding volume.
00391   PT(BoundingVolume) bound = new BoundingSphere;
00392   GeometricBoundingVolume *gbv = DCAST(GeometricBoundingVolume, bound);
00393 
00394   // Now actually compute the bounding volume by putting it around all
00395   // of our vertices.
00396 
00397   const LPoint3 *vertices_begin = &_vertices[0];
00398   const LPoint3 *vertices_end = vertices_begin + _vertices.size();
00399 
00400   // Now actually compute the bounding volume by putting it around all
00401   gbv->around(vertices_begin, vertices_end);
00402 
00403   internal_bounds = bound;
00404   internal_vertices = 0;
00405 }
00406 
00407 ////////////////////////////////////////////////////////////////////
00408 //     Function: PortalNode::get_last_pos_state
00409 //       Access: Protected
00410 //  Description: Returns a RenderState for rendering the ghosted
00411 //               portal rectangle that represents the previous frame's
00412 //               position, for those collision nodes that indicate a
00413 //               velocity.
00414 ////////////////////////////////////////////////////////////////////
00415 CPT(RenderState) PortalNode::
00416 get_last_pos_state() {
00417   // Once someone asks for this pointer, we hold its reference count
00418   // and never free it.
00419   static CPT(RenderState) state = (const RenderState *)NULL;
00420   if (state == (const RenderState *)NULL) {
00421     state = RenderState::make
00422       (ColorScaleAttrib::make(LVecBase4(1.0f, 1.0f, 1.0f, 0.5f)),
00423        TransparencyAttrib::make(TransparencyAttrib::M_alpha));
00424   }
00425 
00426   return state;
00427 }
00428 
00429 
00430 ////////////////////////////////////////////////////////////////////
00431 //     Function: PortalNode::register_with_read_factory
00432 //       Access: Public, Static
00433 //  Description: Tells the BamReader how to create objects of type
00434 //               PortalNode.
00435 ////////////////////////////////////////////////////////////////////
00436 void PortalNode::
00437 register_with_read_factory() {
00438   BamReader::get_factory()->register_factory(get_class_type(), make_from_bam);
00439 }
00440 
00441 ////////////////////////////////////////////////////////////////////
00442 //     Function: PortalNode::write_datagram
00443 //       Access: Public, Virtual
00444 //  Description: Writes the contents of this object to the datagram
00445 //               for shipping out to a Bam file.
00446 ////////////////////////////////////////////////////////////////////
00447 void PortalNode::
00448 write_datagram(BamWriter *manager, Datagram &dg) {
00449   PandaNode::write_datagram(manager, dg);
00450 
00451   dg.add_uint16(_vertices.size());
00452   for (Vertices::const_iterator vi = _vertices.begin();
00453        vi != _vertices.end();
00454        ++vi) {
00455     (*vi).write_datagram(dg);
00456   }
00457 }
00458 
00459 ////////////////////////////////////////////////////////////////////
00460 //     Function: PortalNode::complete_pointers
00461 //       Access: Public, Virtual
00462 //  Description: Receives an array of pointers, one for each time
00463 //               manager->read_pointer() was called in fillin().
00464 //               Returns the number of pointers processed.
00465 ////////////////////////////////////////////////////////////////////
00466 int PortalNode::
00467 complete_pointers(TypedWritable **p_list, BamReader *manager) {
00468   int pi = PandaNode::complete_pointers(p_list, manager);
00469 
00470   return pi;
00471 }
00472 
00473 ////////////////////////////////////////////////////////////////////
00474 //     Function: PortalNode::make_from_bam
00475 //       Access: Protected, Static
00476 //  Description: This function is called by the BamReader's factory
00477 //               when a new object of type PortalNode is encountered
00478 //               in the Bam file.  It should create the PortalNode
00479 //               and extract its information from the file.
00480 ////////////////////////////////////////////////////////////////////
00481 TypedWritable *PortalNode::
00482 make_from_bam(const FactoryParams &params) {
00483   PortalNode *node = new PortalNode("");
00484   DatagramIterator scan;
00485   BamReader *manager;
00486 
00487   parse_params(params, scan, manager);
00488   node->fillin(scan, manager);
00489 
00490   return node;
00491 }
00492 
00493 ////////////////////////////////////////////////////////////////////
00494 //     Function: PortalNode::fillin
00495 //       Access: Protected
00496 //  Description: This internal function is called by make_from_bam to
00497 //               read in all of the relevant data from the BamFile for
00498 //               the new PortalNode.
00499 ////////////////////////////////////////////////////////////////////
00500 void PortalNode::
00501 fillin(DatagramIterator &scan, BamReader *manager) {
00502   PandaNode::fillin(scan, manager);
00503 
00504   int num_vertices = scan.get_uint16();
00505   _vertices.reserve(num_vertices);
00506   for (int i = 0; i < num_vertices; i++) {
00507     LPoint3 vertex;
00508     vertex.read_datagram(scan);
00509     _vertices.push_back(vertex);
00510   }
00511 
00512   /*
00513   _from_portal_mask.set_word(scan.get_uint32());
00514   _into_portal_mask.set_word(scan.get_uint32());
00515   _flags = scan.get_uint8();
00516   */
00517 }
 All Classes Functions Variables Enumerations