arbeit
Main Page | Namespace List | Class Hierarchy | Alphabetical List | Compound List | File List | Namespace Members | Compound Members | File Members

Pick.h

Go to the documentation of this file.
00001 //------------------------------------------------------------------------
00002 //C++ 
00003 //                   ________    ____   ___ 
00004 //                  |        \  /    | /  /
00005 //                  +---+     \/     |/  /
00006 //                  +--+|  |\    /|     < 
00007 //                  |  ||  | \  / |  |\  \ 
00008 //                  |      |  \/  |  | \  \ 
00009 //                   \_____|      |__|  \__\
00010 //                       Copyright  2003 
00011 //                      Joe Michael Kniss
00012 //               "All Your Base are Belong to Us"
00013 //-------------------------------------------------------------------------
00014 
00015 /// Pick.h
00016 
00017 
00018 #ifndef __GL_PICK_DOT_H
00019 #define __GL_PICK_DOT_H
00020 
00021 #include <vector>
00022 
00023 ////////////////////////////////////////////////////////////////
00024 /// PickInfo, contains the information related to a particular
00025 ///  object that was under the mouse during a pick. 
00026 ///  a vector of these are created by the "Pick" object 
00027 ///    specified below. \n
00028 ///  TODO: maybe make this counted and have the PickInfoVec hold
00029 ///    smartptrs so we aren't copying the data so much.
00030 class PickInfo {
00031 public:
00032    ~PickInfo() 
00033    {
00034       if(data) delete[] data;
00035    }
00036 
00037    ///@name Z values from/on the picked object
00038    ///@{
00039    ///  these will be in [0-1] range, where 0=near clip, 1=far clip
00040    double z1;  //< nearest z value (likely what you care about)
00041    double z2;  //< farthes z value
00042    ///@}
00043 
00044    ///@name data pushed on the gl name stack
00045    ///   -when object was rendered
00046    ///@{
00047    int dataSize;       //< how many names were associated with this pick
00048    unsigned int *data; //< the name data vector, lenght = dataSize
00049    ///@}
00050 
00051 public: 
00052    /// a user should "rarely" have to create one of these!
00053    /// normal usage of "Pick" will handle creation of the PickInfo
00054    ///   for you.  You might, however, need to copy this for later use.
00055 
00056    PickInfo() : data(0), dataSize(0), z1(0xffffffff), z2(0xffffffff) {}
00057    PickInfo(double Z1, double Z2, unsigned int *pbuf, unsigned int num)
00058       : z1(Z1), z2(Z2), data(0), dataSize(num)
00059    {
00060       if(num)
00061       {
00062          data = new unsigned int[num+1];
00063          for(unsigned int i=0; i<num; ++i) data[i] = pbuf[i];
00064       }
00065    }
00066    PickInfo(const PickInfo &p)
00067       : z1(p.z1), z2(p.z2), data(0), dataSize(p.dataSize)
00068    {
00069       if(p.dataSize && p.data)
00070       {
00071          data = new unsigned int[p.dataSize];
00072          for(int i=0; i<p.dataSize; ++i) data[i] = p.data[i];
00073       }
00074    }
00075    PickInfo &operator=(const PickInfo &p)
00076    {
00077       if(data) delete[] data;
00078       data = 0;
00079       if(p.dataSize && p.data)
00080       {
00081          data = new unsigned int[p.dataSize];
00082          for(int i=0; i<p.dataSize; ++i) data[i] = p.data[i];
00083       }
00084       return *this;
00085    }
00086 
00087 };
00088 
00089 ////////////////////////////////////////////////////////////////
00090 /// a standard vector of PickInfos
00091 ///
00092 typedef std::vector<PickInfo>  PickInfoVec;
00093 ///
00094 ////////////////////////////////////////////////////////////////
00095 
00096 ////////////////////////////////////////////////////////////////
00097 /// Pick, 
00098 ///   creates a PickInfoVec in sorted order from least 
00099 ///   to greatest z1 when "endPick()" is called:
00100 /// Here's how it works:
00101 ///  - You get a mouse event with an x,y screen space position 
00102 ///  - You determine if it warents a pick
00103 ///  - If it does, create a Pick object
00104 ///  - call Pick::startPickGL()
00105 ///  - call your draw function
00106 ///  - call Pick::endPickGL() & capture PickInfoVec
00107 ///
00108 ///  The PickInfoVec is now filled with the pick info.
00109 ///    This info is sorted based on z1 in increasing order.
00110 ///    Use this info to handle picking how ever you like.
00111 ///
00112 ///  If you are doing a whole lot of picking, you may want
00113 ///  to create a single pick object and keep it around so you
00114 ///  aren't creating and deleating the pick buffer so much.
00115 ///
00116 ///  Here is an example:
00117 /// \code
00118 ///  ... in a mouse-down function (double/int x, double/int y)
00119 ///  Pick p();
00120 ///  p.startPickGL(x,y,4); // starting picking
00121 ///  {  /// I use brackets to keep the code clean :)
00122 ///     draw();          // my draw function
00123 ///  }
00124 ///  PickInfoVec pinfo = p.endPickGL();
00125 ///  if(pinfo.size())
00126 ///     myTopObjId0  = pinfo[0].data[0];
00127 /// \endcode
00128 ///  You might need to flip the y, ie. p.startPickGL(x,height-y-1,4);..
00129 ///
00130 /// Note: This class sets the "GL_PROJECTION" matrix, so if
00131 ///   you are setting it every render pass, you need make sure
00132 ///   that you don't while picking is going on.  Once Pick::endPickGL()
00133 ///   has been called, the projection matrix will be reset to
00134 ///   what it was before Pick::startPickGL() was called.  Just make
00135 ///   sure that you don't modify the projection matrix between
00136 ///   these calls, or you will get some strange picking behavior.
00137 ///   The projection matrix that you are using for rendering should
00138 ///   be the current projection matrix when you call Pick::startPickGL().
00139 ////////////////////////////////////////////////////////////////
00140 
00141 class Pick {
00142 public:
00143    ////////////////////////////////////////////////////////////////
00144    /// how big do you want the pick buffer to be?
00145    ///  depends on how much data you will be pushing on the 
00146    ///  gl name stack, and the depth complexity of the scene;
00147    ///  1024 is probably ample.
00148    Pick(int pickBufferSize = 1024)
00149       : _pickBuffer(new unsigned int[pickBufferSize]), 
00150         _pbSize(pickBufferSize),
00151         _picking(false)
00152    {}
00153    Pick(const Pick &p)
00154       : _pickBuffer(new unsigned int[p._pbSize]),
00155         _pbSize(p._pbSize),
00156         _picking(false)
00157    {}
00158    Pick &operator=(const Pick &p)
00159    {
00160       if(_pickBuffer) delete[] _pickBuffer;
00161       _pickBuffer = new unsigned int[p._pbSize];
00162       _pbSize = p._pbSize;
00163       return *this;
00164    }
00165    ~Pick() { if(_pickBuffer) delete[] _pickBuffer; }
00166 
00167    ////////////////////////////////////////////////////////////////
00168    /// begin a pick, you need to call your draw loop and then
00169    ///   endPick when you are done.
00170    ///
00171    void        startPickGL(double x, double y, double pickWin = 4);
00172    ///
00173    ////////////////////////////////////////////////////////////////
00174 
00175    ////////////////////////////////////////////////////////////////
00176    /// you should render all "pickable" objects between these calls
00177    ////////////////////////////////////////////////////////////////
00178    
00179    ////////////////////////////////////////////////////////////////
00180    /// end a pick, creates a pick information vector
00181    ///
00182    PickInfoVec endPickGL();
00183    ///
00184    ////////////////////////////////////////////////////////////////
00185 
00186 protected:
00187    unsigned int *_pickBuffer;
00188    int           _pbSize;
00189    bool          _picking;
00190 };
00191 
00192 
00193 #endif
00194 
00195 

Send questions, comments, and bug reports to:
jmk