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

panda/src/distort/projectionScreen.cxx

Go to the documentation of this file.
00001 // Filename: projectionScreen.cxx
00002 // Created by:  drose (11Dec01)
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 "projectionScreen.h"
00020 #include "geomNode.h"
00021 #include "geom.h"
00022 #include "geomTristrip.h"
00023 #include "transformState.h"
00024 #include "workingNodePath.h"
00025 #include "switchNode.h"
00026 
00027 TypeHandle ProjectionScreen::_type_handle;
00028 
00029 ////////////////////////////////////////////////////////////////////
00030 //     Function: ProjectionScreen::Constructor
00031 //       Access: Published
00032 //  Description: 
00033 ////////////////////////////////////////////////////////////////////
00034 ProjectionScreen::
00035 ProjectionScreen(const string &name) : PandaNode(name)
00036 {
00037   _invert_uvs = project_invert_uvs;
00038   _vignette_on = false;
00039   _vignette_color.set(0.0f, 0.0f, 0.0f, 1.0f);
00040   _frame_color.set(1.0f, 1.0f, 1.0f, 1.0f);
00041   _computed_rel_top_mat = false;
00042   _stale = true;
00043 }
00044 
00045 ////////////////////////////////////////////////////////////////////
00046 //     Function: ProjectionScreen::Destructor
00047 //       Access: Public, Virtual
00048 //  Description: 
00049 ////////////////////////////////////////////////////////////////////
00050 ProjectionScreen::
00051 ~ProjectionScreen() {
00052 }
00053 
00054 ////////////////////////////////////////////////////////////////////
00055 //     Function: ProjectionScreen::Copy Constructor
00056 //       Access: Protected
00057 //  Description: 
00058 ////////////////////////////////////////////////////////////////////
00059 ProjectionScreen::
00060 ProjectionScreen(const ProjectionScreen &copy) :
00061   PandaNode(copy),
00062   _projector(copy._projector),
00063   _projector_node(copy._projector_node),
00064   _vignette_on(copy._vignette_on),
00065   _vignette_color(copy._vignette_color),
00066   _frame_color(copy._frame_color)
00067 {
00068   _computed_rel_top_mat = false;
00069   _stale = true;
00070 }
00071 
00072 ////////////////////////////////////////////////////////////////////
00073 //     Function: ProjectionScreen::make_copy
00074 //       Access: Public, Virtual
00075 //  Description: Returns a newly-allocated Node that is a shallow copy
00076 //               of this one.  It will be a different Node pointer,
00077 //               but its internal data may or may not be shared with
00078 //               that of the original Node.
00079 ////////////////////////////////////////////////////////////////////
00080 PandaNode *ProjectionScreen::
00081 make_copy() const {
00082   return new ProjectionScreen(*this);
00083 }
00084 
00085 ////////////////////////////////////////////////////////////////////
00086 //     Function: ProjectionScreen::has_cull_callback
00087 //       Access: Public, Virtual
00088 //  Description: Should be overridden by derived classes to return
00089 //               true if cull_callback() has been defined.  Otherwise,
00090 //               returns false to indicate cull_callback() does not
00091 //               need to be called for this node during the cull
00092 //               traversal.
00093 ////////////////////////////////////////////////////////////////////
00094 bool ProjectionScreen::
00095 has_cull_callback() const {
00096   return true;
00097 }
00098 
00099 ////////////////////////////////////////////////////////////////////
00100 //     Function: ProjectionScreen::cull_callback
00101 //       Access: Public, Virtual
00102 //  Description: If has_cull_callback() returns true, this function
00103 //               will be called during the cull traversal to perform
00104 //               any additional operations that should be performed at
00105 //               cull time.  This may include additional manipulation
00106 //               of render state or additional visible/invisible
00107 //               decisions, or any other arbitrary operation.
00108 //
00109 //               By the time this function is called, the node has
00110 //               already passed the bounding-volume test for the
00111 //               viewing frustum, and the node's transform and state
00112 //               have already been applied to the indicated
00113 //               CullTraverserData object.
00114 //
00115 //               The return value is true if this node should be
00116 //               visible, or false if it should be culled.
00117 ////////////////////////////////////////////////////////////////////
00118 bool ProjectionScreen::
00119 cull_callback(CullTraverser *, CullTraverserData &) {
00120   recompute_if_stale();
00121   return true;
00122 }
00123 
00124 ////////////////////////////////////////////////////////////////////
00125 //     Function: ProjectionScreen::set_projector
00126 //       Access: Published
00127 //  Description: Specifies the LensNode that is to serve as the
00128 //               projector for this screen.  The relative position of
00129 //               the LensNode to the ProjectionScreen, as well as the
00130 //               properties of the lens associated with the LensNode,
00131 //               determines the UV's that will be assigned to the
00132 //               geometry within the ProjectionScreen.
00133 //
00134 //               The NodePath must refer to a LensNode (or a Camera).
00135 ////////////////////////////////////////////////////////////////////
00136 void ProjectionScreen::
00137 set_projector(const NodePath &projector) {
00138   _projector_node = (LensNode *)NULL;
00139   _projector = projector;
00140   if (!projector.is_empty()) {
00141     nassertv(projector.node()->is_of_type(LensNode::get_class_type()));
00142     _projector_node = DCAST(LensNode, projector.node());
00143     _stale = true;
00144   }
00145 }
00146 
00147 ////////////////////////////////////////////////////////////////////
00148 //     Function: ProjectionScreen::generate_screen
00149 //       Access: Published
00150 //  Description: Synthesizes a polygon mesh based on the projection
00151 //               area of the indicated projector.  This generates and
00152 //               returns a new GeomNode but does not automatically
00153 //               parent it to the ProjectionScreen node; see
00154 //               regenerate_screen().
00155 //
00156 //               The specified projector need not be the same as the
00157 //               projector given to the ProjectionScreen with
00158 //               set_projector() (although this is often what you
00159 //               want).
00160 //
00161 //               num_x_verts and num_y_verts specify the number of
00162 //               vertices to make in the grid across the horizontal
00163 //               and vertical dimension of the projector,
00164 //               respectively; distance represents the approximate
00165 //               distance of the screen from the lens center.
00166 ////////////////////////////////////////////////////////////////////
00167 PT(GeomNode) ProjectionScreen::
00168 generate_screen(const NodePath &projector, const string &screen_name,
00169                 int num_x_verts, int num_y_verts, float distance) {
00170   nassertr(!projector.is_empty() && 
00171            projector.node()->is_of_type(LensNode::get_class_type()),
00172            NULL);
00173   LensNode *projector_node = DCAST(LensNode, projector.node());
00174   nassertr(projector_node->get_lens() != NULL, NULL);
00175 
00176   // First, get the relative coordinate space of the projector.
00177   LMatrix4f rel_mat;
00178   NodePath this_np(this);
00179   rel_mat = projector.get_mat(this_np);
00180 
00181   // Now compute all the vertices for the screen.  These are arranged
00182   // in order from left to right and bottom to top.
00183   int num_verts = num_x_verts * num_y_verts;
00184   Lens *lens = projector_node->get_lens();
00185   float t = (distance - lens->get_near()) / (lens->get_far() - lens->get_near());
00186 
00187   PTA_Vertexf coords;
00188   coords.reserve(num_verts);
00189   float x_scale = 2.0f / (num_x_verts - 1);
00190   float y_scale = 2.0f / (num_y_verts - 1);
00191   for (int yi = 0; yi < num_y_verts; yi++) {
00192     for (int xi = 0; xi < num_x_verts; xi++) {
00193       LPoint2f film = LPoint2f((float)xi * x_scale - 1.0f,
00194                                (float)yi * y_scale - 1.0f);
00195       LPoint3f near_point, far_point;
00196       lens->extrude(film, near_point, far_point);
00197       
00198       LPoint3f point = near_point + t * (far_point - near_point);
00199       point = point * rel_mat;
00200       
00201       coords.push_back(point);
00202     }
00203   }
00204   nassertr((int)coords.size() == num_verts, NULL);
00205 
00206   // Now synthesize a triangle mesh.  We run triangle strips
00207   // horizontally across the grid.
00208   int num_tstrips = (num_y_verts-1);
00209   int tstrip_length = 2*(num_x_verts-1)+2;
00210 
00211   PTA_int lengths;
00212   PTA_ushort vindex;
00213 
00214   // Set the lengths array.  we are creating num_tstrips t-strips,
00215   // each of which has tstrip_length vertices.
00216   lengths.reserve(num_tstrips);
00217   int n;
00218   for (n = 0; n < num_tstrips; n++) {
00219     lengths.push_back(tstrip_length);
00220   }
00221   nassertr((int)lengths.size() == num_tstrips, NULL);
00222 
00223   // Now fill up the index array into the vertices.  This lays out the
00224   // order of the vertices in each t-strip.
00225   vindex.reserve(num_tstrips * tstrip_length);
00226   n = 0;
00227   int ti, si;
00228   for (ti = 1; ti < num_y_verts; ti++) {
00229     vindex.push_back(ti * num_x_verts);
00230     for (si = 1; si < num_x_verts; si++) {
00231       vindex.push_back((ti - 1) * num_x_verts + (si-1));
00232       vindex.push_back(ti * num_x_verts + si);
00233     }
00234     vindex.push_back((ti - 1) * num_x_verts + (num_x_verts-1));
00235   }
00236   nassertr((int)vindex.size() == num_tstrips * tstrip_length, NULL);
00237 
00238   GeomTristrip *geom = new GeomTristrip;
00239   geom->set_num_prims(num_tstrips);
00240   geom->set_lengths(lengths);
00241 
00242   geom->set_coords(coords, G_PER_VERTEX, vindex);
00243 
00244   // Make it white.
00245   PTA_Colorf colors;
00246   colors.push_back(Colorf(1.0f, 1.0f, 1.0f, 1.0f));
00247   geom->set_colors(colors, G_OVERALL);
00248 
00249   // Now create a GeomNode to hold this mesh.
00250   PT(GeomNode) geom_node = new GeomNode(screen_name);
00251   geom_node->add_geom(geom);
00252 
00253   _stale = true;
00254   ++_last_screen;
00255   return geom_node;
00256 }
00257 
00258 ////////////////////////////////////////////////////////////////////
00259 //     Function: ProjectionScreen::regenerate_screen
00260 //       Access: Published
00261 //  Description: Removes all the children from the ProjectionScreen
00262 //               node, and adds the newly generated child returned by
00263 //               generate_screen().
00264 ////////////////////////////////////////////////////////////////////
00265 void ProjectionScreen::
00266 regenerate_screen(const NodePath &projector, const string &screen_name,
00267                   int num_x_verts, int num_y_verts, float distance) {
00268   // First, remove all existing children.
00269   remove_all_children();
00270 
00271   // And attach a new child.
00272   PT(GeomNode) geom_node = 
00273     generate_screen(projector, screen_name, num_x_verts, num_y_verts, 
00274                     distance);
00275   add_child(geom_node);
00276 }
00277 
00278 ////////////////////////////////////////////////////////////////////
00279 //     Function: ProjectionScreen::make_flat_mesh
00280 //       Access: Published
00281 //  Description: Generates a deep copy of the hierarchy at the
00282 //               ProjectionScreen node and below, with vertices
00283 //               flattened into two dimensions as if they were seen by
00284 //               the indicated camera node.
00285 //
00286 //               This is useful for rendering an image as seen through
00287 //               a non-linear lens.  The resulting mesh will have
00288 //               vertices in the range [-1, 1] in both x and y, and
00289 //               may be then rendered with an ordinary orthographic
00290 //               lens, to generate the effect of seeing the image
00291 //               through the specified non-linear lens.
00292 //
00293 //               The returned node has no parent; it is up to the
00294 //               caller to parent it somewhere or store it so that it
00295 //               does not get dereferenced and deleted.
00296 ////////////////////////////////////////////////////////////////////
00297 PT(PandaNode) ProjectionScreen::
00298 make_flat_mesh(const NodePath &camera) {
00299   nassertr(!camera.is_empty() && 
00300            camera.node()->is_of_type(LensNode::get_class_type()),
00301            NULL);
00302   LensNode *camera_node = DCAST(LensNode, camera.node());
00303   nassertr(camera_node->get_lens() != (Lens *)NULL, NULL);
00304 
00305   // First, ensure the UV's are up-to-date.
00306   recompute_if_stale();
00307 
00308   PT(PandaNode) top = new PandaNode(get_name());
00309   NodePath this_np(this);
00310 
00311   LMatrix4f rel_mat;
00312   bool computed_rel_mat = false;
00313   make_mesh_children(top, this_np, camera, rel_mat, computed_rel_mat);
00314 
00315   return top;
00316 }
00317 
00318 ////////////////////////////////////////////////////////////////////
00319 //     Function: ProjectionScreen::recompute
00320 //       Access: Published
00321 //  Description: Recomputes all the UV's for geometry below the
00322 //               ProjectionScreen node, as if the texture were
00323 //               projected from the associated projector.
00324 //
00325 //               This function is normally called automatically
00326 //               whenever the relevant properties change, so it should
00327 //               not normally need to be called directly by the user.
00328 //               However, it does no harm to call this if there is any
00329 //               doubt.
00330 ////////////////////////////////////////////////////////////////////
00331 void ProjectionScreen::
00332 recompute() {
00333   NodePath this_np(this);
00334   do_recompute(this_np);
00335 }
00336 
00337 ////////////////////////////////////////////////////////////////////
00338 //     Function: ProjectionScreen::recompute_if_stale
00339 //       Access: Public
00340 //  Description: Calls recompute() only if the relative transform
00341 //               between the ProjectionScreen and the projector has
00342 //               changed, or if any other relevant property has
00343 //               changed.
00344 ////////////////////////////////////////////////////////////////////
00345 void ProjectionScreen::
00346 recompute_if_stale() {
00347   if (_projector_node != (LensNode *)NULL && 
00348       _projector_node->get_lens() != (Lens *)NULL) {
00349     UpdateSeq lens_change = _projector_node->get_lens()->get_last_change();
00350     if (_stale || lens_change != _projector_lens_change) {
00351       recompute();
00352 
00353     } else {
00354       // Get the relative transform to ensure it hasn't changed.
00355       NodePath this_np(this);
00356       const LMatrix4f &top_mat = this_np.get_mat(_projector);
00357       if (!_rel_top_mat.almost_equal(top_mat)) {
00358         _rel_top_mat = top_mat;
00359         _computed_rel_top_mat = true;
00360         do_recompute(this_np);
00361       }
00362     }
00363   }
00364 }
00365 
00366 ////////////////////////////////////////////////////////////////////
00367 //     Function: ProjectionScreen::do_recompute
00368 //       Access: Private
00369 //  Description: Starts the recomputation process.
00370 ////////////////////////////////////////////////////////////////////
00371 void ProjectionScreen::
00372 do_recompute(const NodePath &this_np) {
00373   if (_projector_node != (LensNode *)NULL && 
00374       _projector_node->get_lens() != (Lens *)NULL) {
00375     _colors.clear();
00376     _colors.push_back(_vignette_color);
00377     _colors.push_back(_frame_color);
00378 
00379     recompute_node(this_np, _rel_top_mat, _computed_rel_top_mat);
00380     // Make sure this flag is set to false for next time.
00381     _computed_rel_top_mat = false;
00382 
00383     _projector_lens_change = _projector_node->get_lens()->get_last_change();
00384     _stale = false;
00385   }
00386 }
00387 
00388 ////////////////////////////////////////////////////////////////////
00389 //     Function: ProjectionScreen::recompute_node
00390 //       Access: Private
00391 //  Description: Recurses over all geometry at the indicated node and
00392 //               below, looking for GeomNodes that want to have new
00393 //               UV's computed.  When a new transform space is
00394 //               encountered, a new relative matrix is computed.
00395 ////////////////////////////////////////////////////////////////////
00396 void ProjectionScreen::
00397 recompute_node(const WorkingNodePath &np, LMatrix4f &rel_mat,
00398                bool &computed_rel_mat) {
00399   PandaNode *node = np.node();
00400   if (node->is_geom_node()) {
00401     recompute_geom_node(np, rel_mat, computed_rel_mat);
00402   }
00403 
00404   if (node->is_exact_type(SwitchNode::get_class_type())) {
00405     // We make a special case for switch nodes only.  Other kinds of
00406     // selective child nodes, like LOD's and sequence nodes, will get
00407     // all of their children traversed; switch nodes will only
00408     // traverse the currently active child.
00409     int i = DCAST(SwitchNode, node)->get_visible_child();
00410     if (i >= 0 && i < node->get_num_children()) {
00411       PandaNode *child = node->get_child(i);
00412       recompute_child(WorkingNodePath(np, child), rel_mat, computed_rel_mat);
00413     }
00414 
00415   } else {
00416     // A non-switch node.  Recurse on all children.
00417     int num_children = node->get_num_children();
00418     for (int i = 0; i < num_children; i++) {
00419       PandaNode *child = node->get_child(i);
00420       recompute_child(WorkingNodePath(np, child), rel_mat, computed_rel_mat);
00421     }
00422   }
00423 }
00424 
00425 ////////////////////////////////////////////////////////////////////
00426 //     Function: ProjectionScreen::recompute_child
00427 //       Access: Private
00428 //  Description: Works in conjunction with recompute_node() to recurse
00429 //               over the whole graph.  This is called on each child
00430 //               of a given node.
00431 ////////////////////////////////////////////////////////////////////
00432 void ProjectionScreen::
00433 recompute_child(const WorkingNodePath &np, LMatrix4f &rel_mat,
00434                 bool &computed_rel_mat) {
00435   PandaNode *child = np.node();
00436 
00437   const TransformState *transform = child->get_transform();
00438   if (!transform->is_identity()) {
00439     // This child node has a transform; therefore, we must recompute
00440     // the relative matrix from this point.
00441     LMatrix4f new_rel_mat;
00442     bool computed_new_rel_mat = false;
00443     recompute_node(np, new_rel_mat, computed_new_rel_mat);
00444     
00445   } else {
00446     // This child has no transform, so we can use the same transform
00447     // space from before.
00448     recompute_node(np, rel_mat, computed_rel_mat);
00449   }
00450 }
00451 
00452 ////////////////////////////////////////////////////////////////////
00453 //     Function: ProjectionScreen::recompute_geom_node
00454 //       Access: Private
00455 //  Description: Recomputes the UV's just for the indicated GeomNode.
00456 ////////////////////////////////////////////////////////////////////
00457 void ProjectionScreen::
00458 recompute_geom_node(const WorkingNodePath &np, LMatrix4f &rel_mat, 
00459                     bool &computed_rel_mat) {
00460   GeomNode *node = DCAST(GeomNode, np.node());
00461   if (!computed_rel_mat) {
00462     // All right, time to compute the matrix.
00463     NodePath true_np = np.get_node_path();
00464     rel_mat = true_np.get_mat(_projector);
00465     computed_rel_mat = true;
00466   }
00467 
00468   int num_geoms = node->get_num_geoms();
00469   for (int i = 0; i < num_geoms; i++) {
00470     Geom *geom = node->get_geom(i);
00471     recompute_geom(geom, rel_mat);
00472   }
00473 }
00474 
00475 ////////////////////////////////////////////////////////////////////
00476 //     Function: ProjectionScreen::recompute_geom
00477 //       Access: Private
00478 //  Description: Recomputes the UV's just for the indicated Geom.
00479 ////////////////////////////////////////////////////////////////////
00480 void ProjectionScreen::
00481 recompute_geom(Geom *geom, const LMatrix4f &rel_mat) {
00482   static const LMatrix3f lens_to_uv
00483     (0.5f, 0.0f, 0.0f,
00484      0.0f, 0.5f, 0.0f,
00485      0.5f, 0.5f, 1.0f);
00486 
00487   static const LMatrix3f lens_to_uv_inverted
00488     (0.5f, 0.0f, 0.0f,
00489      0.0f,-0.5f, 0.0f,
00490      0.5f, 0.5f, 1.0f);
00491 
00492   PTA_TexCoordf uvs;
00493   PTA_ushort color_index;
00494   Lens *lens = _projector_node->get_lens();
00495   nassertv(lens != (Lens *)NULL);
00496 
00497   const LMatrix3f &to_uv = _invert_uvs ? lens_to_uv_inverted : lens_to_uv;
00498 
00499   // Iterate through all the vertices in the Geom.
00500   int num_vertices = geom->get_num_vertices();
00501   Geom::VertexIterator vi = geom->make_vertex_iterator();
00502 
00503   for (int i = 0; i < num_vertices; i++) {
00504     const Vertexf &vert = geom->get_next_vertex(vi);
00505 
00506     // For each vertex, project to the film plane.
00507     LPoint2f film(0.0, 0.0);
00508     bool good = lens->project(vert * rel_mat, film);
00509 
00510     // Now the lens gives us coordinates in the range [-1, 1].
00511     // Rescale these to [0, 1].
00512     uvs.push_back(film * to_uv);
00513 
00514     // If we have vignette color in effect, color the vertex according
00515     // to whether it fell in front of the lens or not.
00516     if (_vignette_on) {
00517       color_index.push_back(good ? 1 : 0);
00518     }
00519   }
00520 
00521   // Now set the UV's.
00522   geom->set_texcoords(uvs, G_PER_VERTEX);
00523 
00524   if (_vignette_on) {
00525     geom->set_colors(_colors, G_PER_VERTEX, color_index);
00526   }
00527 }
00528 
00529 ////////////////////////////////////////////////////////////////////
00530 //     Function: ProjectionScreen::make_mesh_node
00531 //       Access: Private
00532 //  Description: Recurses over all geometry at the indicated node and
00533 //               below, and generates a corresponding node hierarchy
00534 //               with all the geometry copied, but flattened into 2-d,
00535 //               as seen from the indicated camera.  Returns the newly
00536 //               created node, or NULL if no node was created.
00537 ////////////////////////////////////////////////////////////////////
00538 PandaNode *ProjectionScreen::
00539 make_mesh_node(PandaNode *result_parent, const WorkingNodePath &np,
00540                const NodePath &camera,
00541                LMatrix4f &rel_mat, bool &computed_rel_mat) {
00542   PandaNode *node = np.node();
00543   if (!node->safe_to_flatten()) {
00544     // If we can't safely flatten this node, ignore it (and all of its
00545     // children) completely.  It's got no business being here anyway.
00546     return NULL;
00547   }
00548 
00549   PT(PandaNode) new_node;
00550   if (node->is_geom_node()) {
00551     new_node = make_mesh_geom_node(np, camera, rel_mat, computed_rel_mat);
00552   } else {
00553     new_node = node->make_copy();
00554   }
00555 
00556   // Now attach the new node to the result.
00557   result_parent->add_child(new_node);
00558   make_mesh_children(new_node, np, camera, rel_mat, computed_rel_mat);
00559   return new_node;
00560 }
00561 
00562 ////////////////////////////////////////////////////////////////////
00563 //     Function: ProjectionScreen::make_mesh_children
00564 //       Access: Private
00565 //  Description: Walks over the list of children for the indicated
00566 //               node, calling make_mesh_node() on each one.
00567 ////////////////////////////////////////////////////////////////////
00568 void ProjectionScreen::
00569 make_mesh_children(PandaNode *new_node, const WorkingNodePath &np,
00570                    const NodePath &camera,
00571                    LMatrix4f &rel_mat, bool &computed_rel_mat) {
00572   PandaNode *node = np.node();
00573   int num_children = node->get_num_children();
00574   for (int i = 0; i < num_children; i++) {
00575     PandaNode *child = node->get_child(i);
00576     PandaNode *new_child;
00577 
00578     const TransformState *transform = child->get_transform();
00579     if (!transform->is_identity()) {
00580       // This child node has a transform; therefore, we must recompute
00581       // the relative matrix from this point.
00582       LMatrix4f new_rel_mat;
00583       bool computed_new_rel_mat = false;
00584       new_child = make_mesh_node(new_node, WorkingNodePath(np, child), camera,
00585                                  new_rel_mat, computed_new_rel_mat);
00586 
00587     } else {
00588       // This child has no transform, so we can use the same transform
00589       // space from before.
00590       new_child = make_mesh_node(new_node, WorkingNodePath(np, child), camera,
00591                                  rel_mat, computed_rel_mat);
00592     }
00593 
00594     // Copy all of the render state (except TransformState) to the
00595     // new arc.
00596     new_child->set_state(child->get_state());
00597   }
00598 }
00599 
00600 ////////////////////////////////////////////////////////////////////
00601 //     Function: ProjectionScreen::make_mesh_geom_node
00602 //       Access: Private
00603 //  Description: Makes a new GeomNode, just like the given one, except
00604 //               flattened into two dimensions as seen by the
00605 //               indicated camera.
00606 ////////////////////////////////////////////////////////////////////
00607 PT(GeomNode) ProjectionScreen::
00608 make_mesh_geom_node(const WorkingNodePath &np, const NodePath &camera,
00609                     LMatrix4f &rel_mat, bool &computed_rel_mat) {
00610   GeomNode *node = DCAST(GeomNode, np.node());
00611   PT(GeomNode) new_node = new GeomNode(node->get_name());
00612   LensNode *lens_node = DCAST(LensNode, camera.node());
00613 
00614   if (!computed_rel_mat) {
00615     // All right, time to compute the matrix.
00616     NodePath true_np = np.get_node_path();
00617     rel_mat = true_np.get_mat(camera);
00618     computed_rel_mat = true;
00619   }
00620 
00621   int num_geoms = node->get_num_geoms();
00622   for (int i = 0; i < num_geoms; i++) {
00623     Geom *geom = node->get_geom(i);
00624     PT(Geom) new_geom = 
00625       make_mesh_geom(geom, lens_node->get_lens(), rel_mat);
00626     if (new_geom != (Geom *)NULL) {
00627       new_node->add_geom(new_geom, node->get_geom_state(i));
00628     }
00629   }
00630 
00631   return new_node;
00632 }
00633 
00634 ////////////////////////////////////////////////////////////////////
00635 //     Function: ProjectionScreen::make_mesh_geom
00636 //       Access: Private
00637 //  Description: Makes a new Geom, just like the given one, except
00638 //               flattened into two dimensions as seen by the
00639 //               indicated lens.  Any triangle in the original mesh
00640 //               that involves an unprojectable vertex is eliminated.
00641 ////////////////////////////////////////////////////////////////////
00642 PT(Geom) ProjectionScreen::
00643 make_mesh_geom(Geom *geom, Lens *lens, LMatrix4f &rel_mat) {
00644   Geom *new_geom = geom->make_copy();
00645   PT(Geom) result = new_geom;
00646 
00647   PTA_Vertexf coords;
00648   GeomBindType bind;
00649   PTA_ushort vindex;
00650 
00651   new_geom->get_coords(coords, bind, vindex);
00652 
00653   PTA_Vertexf new_coords;
00654   new_coords.reserve(coords.size());
00655   for (int i = 0; i < (int)coords.size(); i++) {
00656     const Vertexf &vert = coords[i];
00657 
00658     // Project each vertex into the film plane, but use three
00659     // dimensions so the Z coordinate remains meaningful.
00660     LPoint3f film(0.0f, 0.0f, 0.0f);
00661     lens->project(vert * rel_mat, film);
00662 
00663     new_coords.push_back(film);
00664   }
00665 
00666   new_geom->set_coords(new_coords, bind, vindex);
00667 
00668   return result;
00669 }

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