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

panda/src/egg/eggBinMaker.h

Go to the documentation of this file.
00001 // Filename: eggBinMaker.h
00002 // Created by:  drose (21Jan99)
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 #ifndef EGGBINMAKER_H
00020 #define EGGBINMAKER_H
00021 
00022 ///////////////////////////////////////////////////////////////////
00023 //
00024 // EggBinMaker
00025 //
00026 // This is a handy class for collecting related nodes together.  Its
00027 // purpose is to make it easier to process egg files for converting to
00028 // another scene graph format.  Egg is very general and allows nodes
00029 // to be parented willy-nilly anywhere you like, while many other
00030 // scene graph formats have requirements that certain kinds of nodes
00031 // be grouped together.
00032 //
00033 // Although EggBinMaker can be used to group any kinds of nodes
00034 // together, one of the most common examples is grouping polygons into
00035 // polysets.  Egg allows individual polygons to be parented directly
00036 // to any group node, while most scene graph formats prefer to have
00037 // polygons with similar attributes grouped into some kind of a
00038 // polyset node.  Therefore, the following usage discussion will use
00039 // grouping polygons into polysets as an example.
00040 //
00041 // EggBinMaker is actually an abstract class; it cannot be used
00042 // directly.  To use it, you must create a subclass and redefine some
00043 // or all of its virtual functions to specify the precise behavior you
00044 // require.
00045 //
00046 // You must define at least the following function:
00047 //
00048 // virtual int get_bin_number(const EggNode *node);
00049 //
00050 //    This function identifies the kinds of nodes in the graph, for
00051 //    instance EggPolygons, that are to be put into bins.  It will be
00052 //    called once for each node encountered, and it should return
00053 //    nonzero if the node is to be binned, and zero otherwise.  To
00054 //    group polygons into polysets, this function might look like:
00055 //
00056 //        virtual int get_bin_number(const EggNode *node) {
00057 //          if (node->is_of_type(EggPolygon::get_class_type())) {
00058 //            return 1;
00059 //          } else {
00060 //            return 0;
00061 //          }
00062 //        }
00063 //
00064 //
00065 //    This function may also return the bin number that a given node
00066 //    should be dropped into.  The bin number is completely arbitrary,
00067 //    and it just serves to differentiate different bins.
00068 //
00069 //    By default, all sibling nodes will be dropped into the same bin;
00070 //    you can redefine this to sort nodes further into categories.
00071 //    For instance, if you wanted to put textured polygons into a
00072 //    different polyset than untextured polygons, you might define
00073 //    this function as follows:
00074 //
00075 //        virtual int get_bin_number(const EggNode *node) {
00076 //          if (node->is_of_type(EggPolygon::get_class_type())) {
00077 //            EggPolygon *poly = DCAST(EggPolygon, node);
00078 //            return (poly->has_texture()) ? 1 : 2;
00079 //          } else {
00080 //            return 0;
00081 //          }
00082 //        }
00083 //
00084 //    Of course, unrelated nodes--nodes that belong to different
00085 //    parents--will never be placed into the same bin together,
00086 //    regardless of the bin number.
00087 //
00088 //    It is important to note that it is not necessarily true that
00089 //    there is only one bin for each bin number.  If you redefine
00090 //    sorts_less(), below, you provide a finer-grained control that
00091 //    may create multiple bins for a given bin number.
00092 //
00093 //    This function may be called several times for a given node, and
00094 //    it should return the same number each time.
00095 //
00096 //
00097 // You may also redefine any or all of the following functions:
00098 //
00099 // virtual bool sorts_less(int bin_number, const EggNode *a, const EggNode *b);
00100 //
00101 //    Sometimes a simple bin number alone is not enough.  For
00102 //    instance, suppose you needed to group together not just all
00103 //    textured polygons, but all polygons that shared a particular
00104 //    texture map.  Two polygons that are each textured with a
00105 //    different texture map should go into different polysets.  To do
00106 //    this with bin numbers, you'd have to know ahead of time all the
00107 //    texture maps that are in use, and assign a unique number to each
00108 //    one.
00109 //
00110 //    sorts_less() can make this unnecessary.  It's a finer-grained
00111 //    sorting than by bin numbers.  Once two nodes have been grouped
00112 //    together into the same bin number, sorts_less is called on them.
00113 //    If it returns true, then node a should be placed into an earlier
00114 //    bin than node b, even though they share the same bin number.  If
00115 //    sorts_less(a, b) and sorts_less(b, a) both return false, then
00116 //    nodes a and b are placed into the same bin.
00117 //
00118 //    To continue the example, and sort polygons into different bins
00119 //    based on the texture map:
00120 //
00121 //        virtual bool sorts_less(int bin_number,
00122 //                                const EggNode *a, const EggNode *b) {
00123 //          if (bin_number == 2) {
00124 //            // bin 2, textured geometry
00125 //            return (a->get_texture() < b->get_texture());
00126 //          } else {
00127 //            // bin 1, untextured geometry
00128 //            return false;
00129 //          }
00130 //        }
00131 //
00132 //    The actual comparison can be arbitrary, as long as it is
00133 //    consistent.  Its only purpose is to assign some ordering among
00134 //    bins.  In the example, for instance, the comparison is based on
00135 //    the pointer to the texture maps--it doesn't matter which comes
00136 //    before the other, as long as it's consistent.
00137 //
00138 //    In particular, it should never be true that sorts_less(a, b) and
00139 //    sorts_less(b, a) both return true--that is a clear
00140 //    contradiction.
00141 //
00142 //    Of course, if you're using sorts_less() anyway, you could put
00143 //    *all* of the logic for binning into this function; there's no
00144 //    need to use both get_bin_number() and sorts_less(), necessarily.
00145 //    In the current example, here's another version of sorts_less()
00146 //    that accomplishes the same thing as the combined effects of the
00147 //    above get_bin_number() and sorts_less() working together:
00148 //
00149 //        virtual bool sorts_less(int bin_number,
00150 //                                const EggNode *a, const EggNode *b) {
00151 //          if (a->has_texture() != b->has_texture()) {
00152 //            return ((int)a->has_texture() < (int)b->has_texture());
00153 //          }
00154 //          if (a->has_texture()) {
00155 //            return (a->get_texture() < b->get_texture());
00156 //          }
00157 //          return false;
00158 //        }
00159 //
00160 //
00161 // virtual bool collapse_group(const EggGroup *group, int bin_number);
00162 //
00163 //    After all the nodes have been assigned to bins and the
00164 //    individual bins (polysets) have been created, it might turn out
00165 //    that some groups have had all their children placed into the
00166 //    same bin.  In this case, the group node is now redundant, since
00167 //    it contains just the one child, the new EggBin (polyset) node.
00168 //    It might be advantageous to remove the group and collapse its
00169 //    properties into the new node.
00170 //
00171 //    In this case (and this case only), collapse_group() will be
00172 //    called, given the node and the bin number.  If it returns true,
00173 //    the node will indeed be collapsed into its bin; otherwise, they
00174 //    will be left separate.
00175 //
00176 //    The point is that there might be some attributes in the group
00177 //    node (for instance, a matrix transform) that cannot be
00178 //    represented in a polyset node in the new scene graph format, so
00179 //    there may be some cases in which the group cannot be safely
00180 //    collapsed.  Since the egg library cannot know about which such
00181 //    cases cause problems, it leaves it up to you.  The default
00182 //    behavior is never to collapse nodes.
00183 //
00184 //
00185 // virtual string get_bin_name(int bin_number);
00186 //
00187 //    This function is called as each new bin is created, to
00188 //    optionally define a name for the new node.  If it returns the
00189 //    empty string, the node name will be empty, unless it was
00190 //    collapsed with its parent group, in which case it will inherit
00191 //    its former parent's name.
00192 //
00193 //
00194 //
00195 // Once you have subclassed EggBinMaker and defined the functions as
00196 // you require, you use it by simply calling make_bins() one or more
00197 // times, passing it the pointer to the root of the scene graph or of
00198 // some subgraph.  It will traverse the subgraph and create a series
00199 // of EggBin objects, as required, moving all the binned geometry
00200 // under the EggBin objects.  The return value is the number of
00201 // EggBins created.  Each EggBin stores its bin number, which may be
00202 // retrieved via get_bin_number().
00203 //
00204 ///////////////////////////////////////////////////////////////////
00205 
00206 
00207 #include <pandabase.h>
00208 
00209 #include "eggObject.h"
00210 
00211 #include <pointerTo.h>
00212 #include <notify.h>
00213 
00214 #include "pset.h"
00215 #include "pmap.h"
00216 
00217 class EggNode;
00218 class EggGroup;
00219 class EggGroupNode;
00220 class EggBin;
00221 class EggBinMaker;
00222 
00223 ////////////////////////////////////////////////////////////////////
00224 //       Class : EggBinMakerCompareNodes
00225 // Description : This is just an STL function object, used to sort
00226 //               nodes within EggBinMaker.  It's part of the private
00227 //               interface; ignore it.
00228 ////////////////////////////////////////////////////////////////////
00229 class EXPCL_PANDAEGG EggBinMakerCompareNodes {
00230 public:
00231   EggBinMakerCompareNodes() {
00232     // We need to have a default constructor to compile, but it should
00233     // never be called.
00234     nassertv(false);
00235   }
00236   EggBinMakerCompareNodes(EggBinMaker *ebm) : _ebm(ebm) { }
00237   bool operator ()(const EggNode *a, const EggNode *b) const;
00238 
00239   EggBinMaker *_ebm;
00240 };
00241 
00242 
00243 ////////////////////////////////////////////////////////////////////
00244 //       Class : EggBinMaker
00245 // Description : This is a handy class for collecting related nodes
00246 //               together.  It is an abstract class; to use it you
00247 //               must subclass off of it.  See the somewhat lengthy
00248 //               comment above.
00249 ////////////////////////////////////////////////////////////////////
00250 class EXPCL_PANDAEGG EggBinMaker : public EggObject {
00251 public:
00252   EggBinMaker();
00253   ~EggBinMaker();
00254 
00255   int make_bins(EggGroupNode *root_group);
00256 
00257   virtual int
00258   get_bin_number(const EggNode *node)=0;
00259 
00260   virtual bool
00261   sorts_less(int bin_number, const EggNode *a, const EggNode *b);
00262 
00263   virtual bool
00264   collapse_group(const EggGroup *group, int bin_number);
00265 
00266   virtual string
00267   get_bin_name(int bin_number);
00268 
00269 private:
00270   // The logic is two-pass.  First, we make a scene graph traversal
00271   // and store all the pointers into the GroupNodes/SortedNodes
00272   // structure, which groups nodes by their parent group, and then
00273   // sorted into bin order.
00274   typedef pmultiset<PT(EggNode), EggBinMakerCompareNodes> SortedNodes;
00275   typedef pmap<EggGroupNode *, SortedNodes> GroupNodes;
00276 
00277   // Then we walk through that list and create a Bins/Nodes structure
00278   // for each group, which separates out the nodes into the individual
00279   // bins.
00280   typedef pvector< PT(EggNode) > Nodes;
00281   typedef pvector<Nodes> Bins;
00282 
00283   void collect_nodes(EggGroupNode *group);
00284   int get_bins_for_group(GroupNodes::const_iterator gi);
00285   void make_bins_for_group(EggGroupNode *group, const Bins &bins);
00286   void setup_bin(EggBin *bin, const Nodes &nodes);
00287 
00288   GroupNodes _group_nodes;
00289 
00290 
00291 public:
00292 
00293   static TypeHandle get_class_type() {
00294     return _type_handle;
00295   }
00296   static void init_type() {
00297     EggObject::init_type();
00298     register_type(_type_handle, "EggBinMaker",
00299                   EggObject::get_class_type());
00300   }
00301   virtual TypeHandle get_type() const {
00302     return get_class_type();
00303   }
00304   virtual TypeHandle force_init_type() {init_type(); return get_class_type();}
00305 
00306 private:
00307   static TypeHandle _type_handle;
00308 
00309 };
00310 
00311 #endif
00312 
00313 

Generated on Fri May 2 00:37:29 2003 for Panda by doxygen1.3