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