PageRenderTime 62ms CodeModel.GetById 32ms RepoModel.GetById 0ms app.codeStats 1ms

/src/IECoreGL/Selector.cpp

http://cortex-vfx.googlecode.com/
C++ | 462 lines | 338 code | 75 blank | 49 comment | 21 complexity | c813af2d0c77c39617cc0e64fb73691d MD5 | raw file
Possible License(s): BSD-3-Clause
  1. //////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 2012-2013, Image Engine Design Inc. All rights reserved.
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. //
  12. // * Redistributions in binary form must reproduce the above copyright
  13. // notice, this list of conditions and the following disclaimer in the
  14. // documentation and/or other materials provided with the distribution.
  15. //
  16. // * Neither the name of Image Engine Design nor the names of any
  17. // other contributors to this software may be used to endorse or
  18. // promote products derived from this software without specific prior
  19. // written permission.
  20. //
  21. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS
  22. // IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
  23. // THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
  24. // PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
  25. // CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
  26. // EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
  27. // PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
  28. // PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
  29. // LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
  30. // NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
  31. // SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  32. //
  33. //////////////////////////////////////////////////////////////////////////
  34. #include "boost/format.hpp"
  35. #include "IECore/MessageHandler.h"
  36. #include "IECore/Exception.h"
  37. #include "IECoreGL/HitRecord.h"
  38. #include "IECoreGL/Selector.h"
  39. #include "IECoreGL/ColorTexture.h"
  40. #include "IECoreGL/UIntTexture.h"
  41. #include "IECoreGL/DepthTexture.h"
  42. #include "IECoreGL/Exception.h"
  43. #include "IECoreGL/Shader.h"
  44. #include "IECoreGL/ShaderStateComponent.h"
  45. #include "IECoreGL/NameStateComponent.h"
  46. #include "IECoreGL/FrameBuffer.h"
  47. #include "IECoreGL/TypedStateComponent.h"
  48. #include "IECoreGL/Primitive.h"
  49. using namespace IECoreGL;
  50. //////////////////////////////////////////////////////////////////////////
  51. // Selector::Implementation
  52. //////////////////////////////////////////////////////////////////////////
  53. class Selector::Implementation : public IECore::RefCounted
  54. {
  55. public :
  56. Implementation( Selector *parent )
  57. : m_parent( parent ), m_mode( Invalid ), m_baseState( new State( true /* complete */ ) )
  58. {
  59. }
  60. void begin( const Imath::Box2f &region, Mode mode = GLSelect )
  61. {
  62. if( g_currentSelector )
  63. {
  64. throw( IECore::Exception( "Another Selector is already active" ) );
  65. }
  66. g_currentSelector = this->m_parent;
  67. GLdouble projectionMatrix[16];
  68. glGetDoublev( GL_PROJECTION_MATRIX, projectionMatrix );
  69. GLint viewport[4];
  70. glGetIntegerv( GL_VIEWPORT, viewport );
  71. Imath::V2f regionCenter = region.center();
  72. Imath::V2f regionSize = region.size();
  73. regionCenter.x = viewport[0] + viewport[2] * regionCenter.x;
  74. regionCenter.y = viewport[1] + viewport[3] * (1.0f - regionCenter.y);
  75. regionSize.x *= viewport[2];
  76. regionSize.y *= viewport[3];
  77. glMatrixMode( GL_PROJECTION );
  78. glLoadIdentity();
  79. gluPickMatrix( regionCenter.x, regionCenter.y, regionSize.x, regionSize.y, viewport );
  80. glMultMatrixd( projectionMatrix );
  81. glMatrixMode( GL_MODELVIEW );
  82. m_mode = mode;
  83. switch( m_mode )
  84. {
  85. case GLSelect :
  86. beginGLSelect();
  87. break;
  88. case IDRender :
  89. beginIDRender();
  90. break;
  91. case OcclusionQuery :
  92. beginOcclusionQuery();
  93. break;
  94. default :
  95. assert( 0 );
  96. }
  97. glPushAttrib( GL_ALL_ATTRIB_BITS );
  98. }
  99. void loadName( GLuint name )
  100. {
  101. switch( m_mode )
  102. {
  103. case GLSelect :
  104. loadNameGLSelect( name );
  105. break;
  106. case IDRender :
  107. loadNameIDRender( name );
  108. break;
  109. case OcclusionQuery :
  110. loadNameOcclusionQuery( name );
  111. break;
  112. default :
  113. assert( 0 );
  114. }
  115. }
  116. size_t end( std::vector<HitRecord> &hits )
  117. {
  118. glPopAttrib();
  119. g_currentSelector = 0;
  120. const Mode mode = m_mode;
  121. m_mode = Invalid;
  122. switch( mode )
  123. {
  124. case GLSelect :
  125. return endGLSelect( hits );
  126. case IDRender :
  127. return endIDRender( hits );
  128. case OcclusionQuery :
  129. return endOcclusionQuery( hits );
  130. default :
  131. assert( 0 );
  132. }
  133. return 0;
  134. }
  135. State *baseState()
  136. {
  137. return m_baseState;
  138. }
  139. void loadIDShader( const IECoreGL::Shader *shader )
  140. {
  141. const IECoreGL::Shader::Parameter *nameParameter = shader->uniformParameter( "ieCoreGLNameIn" );
  142. if( !nameParameter )
  143. {
  144. throw IECore::Exception( "ID shader does not have an ieCoreGLNameIn parameter" );
  145. }
  146. GLint fragDataLocation = glGetFragDataLocation( shader->program(), "ieCoreGLNameOut" );
  147. if( fragDataLocation < 0 )
  148. {
  149. throw IECore::Exception( "ID shader does not have an ieCoreGLNameOut output" );
  150. }
  151. m_nameUniformLocation = nameParameter->location;
  152. glUseProgram( shader->program() );
  153. std::vector<GLenum> buffers;
  154. buffers.resize( fragDataLocation + 1, GL_NONE );
  155. buffers[buffers.size()-1] = GL_COLOR_ATTACHMENT0;
  156. glDrawBuffers( buffers.size(), &buffers[0] );
  157. }
  158. static Selector *currentSelector()
  159. {
  160. return g_currentSelector;
  161. }
  162. private :
  163. Selector *m_parent;
  164. Mode m_mode;
  165. StatePtr m_baseState;
  166. static Selector *g_currentSelector;
  167. //////////////////////////////////////////////////////////////////////////
  168. // GLSelect mode
  169. //////////////////////////////////////////////////////////////////////////
  170. std::vector<GLuint> m_selectBuffer;
  171. void beginGLSelect()
  172. {
  173. m_selectBuffer.resize( 20000 ); // enough to select 5000 distinct objects
  174. glSelectBuffer( m_selectBuffer.size(), &(m_selectBuffer[0]) );
  175. glRenderMode( GL_SELECT );
  176. glInitNames();
  177. glPushName( 0 );
  178. }
  179. void loadNameGLSelect( GLuint name )
  180. {
  181. glLoadName( name );
  182. }
  183. size_t endGLSelect( std::vector<HitRecord> &hits )
  184. {
  185. int numHits = glRenderMode( GL_RENDER );
  186. if( numHits < 0 )
  187. {
  188. IECore::msg( IECore::Msg::Warning, "IECoreGL::Selector::end", "Selection buffer overflow." );
  189. numHits *= -1;
  190. }
  191. // get the hits out of the select buffer.
  192. GLuint *hitRecord = &(m_selectBuffer[0]);
  193. for( int i=0; i<numHits; i++ )
  194. {
  195. HitRecord h( hitRecord );
  196. hits.push_back( h );
  197. hitRecord += h.offsetToNext();
  198. }
  199. return hits.size();
  200. }
  201. //////////////////////////////////////////////////////////////////////////
  202. // IDRender mode
  203. //////////////////////////////////////////////////////////////////////////
  204. FrameBufferPtr m_frameBuffer;
  205. boost::shared_ptr<FrameBuffer::ScopedBinding> m_frameBufferBinding;
  206. GLint m_prevProgram;
  207. GLint m_prevViewport[4];
  208. GLint m_nameUniformLocation;
  209. static Shader *idShader()
  210. {
  211. static const char *fragmentSource =
  212. "#version 330\n"
  213. ""
  214. "uniform uint ieCoreGLNameIn;"
  215. ""
  216. "layout( location=0 ) out uint ieCoreGLNameOut;"
  217. ""
  218. "void main()"
  219. "{"
  220. " ieCoreGLNameOut = ieCoreGLNameIn;"
  221. "}";
  222. static ShaderPtr s = new Shader( "", fragmentSource );
  223. return s.get();
  224. }
  225. static std::vector<StateComponentPtr> &idStateComponents()
  226. {
  227. static std::vector<StateComponentPtr> s;
  228. if( !s.size() )
  229. {
  230. s.push_back( new ShaderStateComponent( new Shader::Setup( idShader() ) ) );
  231. s.push_back( new Primitive::DrawBound( false ) );
  232. s.push_back( new Primitive::DrawWireframe( false ) );
  233. s.push_back( new Primitive::DrawOutline( false ) );
  234. s.push_back( new Primitive::DrawPoints( false ) );
  235. }
  236. return s;
  237. }
  238. void beginIDRender()
  239. {
  240. m_frameBuffer = new FrameBuffer();
  241. m_frameBuffer->setColor( new UIntTexture( 128, 128 ) );
  242. m_frameBuffer->setDepth( new DepthTexture( 128, 128 ) );
  243. m_frameBuffer->validate();
  244. m_frameBufferBinding = boost::shared_ptr<FrameBuffer::ScopedBinding>( new FrameBuffer::ScopedBinding( *m_frameBuffer ) );
  245. glGetIntegerv( GL_VIEWPORT, m_prevViewport );
  246. glViewport( 0, 0, 128, 128 );
  247. glClearColor( 0.0, 0.0, 0.0, 1.0 );
  248. glClearDepth( 1.0 );
  249. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  250. const std::vector<StateComponentPtr> &stateComponents = idStateComponents();
  251. for( std::vector<StateComponentPtr>::const_iterator it = stateComponents.begin(), eIt = stateComponents.end(); it != eIt; it++ )
  252. {
  253. m_baseState->add( *it, true /* override */ );
  254. }
  255. glGetIntegerv( GL_CURRENT_PROGRAM, &m_prevProgram );
  256. loadIDShader( idShader() );
  257. }
  258. void loadNameIDRender( GLuint name )
  259. {
  260. Exception::throwIfError();
  261. glUniform1ui( m_nameUniformLocation, name );
  262. }
  263. size_t endIDRender( std::vector<HitRecord> &hits )
  264. {
  265. glUseProgram( m_prevProgram );
  266. glViewport( m_prevViewport[0], m_prevViewport[1], m_prevViewport[2], m_prevViewport[3] );
  267. m_frameBufferBinding.reset();
  268. IECore::ImagePrimitivePtr idsImage = m_frameBuffer->getColor()->imagePrimitive();
  269. const IECore::UIntVectorData *idsData = static_cast<const IECore::UIntVectorData *>( idsImage->variables["Y"].data.get() );
  270. const std::vector<unsigned int> ids = idsData->readable();
  271. IECore::ImagePrimitivePtr zImage = m_frameBuffer->getDepth()->imagePrimitive();
  272. const IECore::FloatVectorData *zData = static_cast<const IECore::FloatVectorData *>( zImage->variables["Z"].data.get() );
  273. const std::vector<float> z = zData->readable();
  274. std::map<unsigned int, HitRecord> idRecords;
  275. for( size_t i = 0, e = ids.size(); i < e; i++ )
  276. {
  277. if( ids[i] == 0 )
  278. {
  279. continue;
  280. }
  281. std::map<unsigned int, HitRecord>::iterator it = idRecords.find( ids[i] );
  282. if( it == idRecords.end() )
  283. {
  284. HitRecord r( Imath::limits<float>::max(), Imath::limits<float>::min(), NameStateComponent::nameFromGLName( ids[i] ) );
  285. it = idRecords.insert( std::pair<unsigned int, HitRecord>( ids[i], r ) ).first;
  286. }
  287. it->second.depthMin = std::min( it->second.depthMin, z[i] );
  288. it->second.depthMax = std::max( it->second.depthMax, z[i] );
  289. }
  290. hits.clear();
  291. hits.reserve( idRecords.size() );
  292. for( std::map<unsigned int, HitRecord>::const_iterator it = idRecords.begin(), eIt = idRecords.end(); it != eIt; it++ )
  293. {
  294. hits.push_back( it->second );
  295. }
  296. const std::vector<StateComponentPtr> &stateComponents = idStateComponents();
  297. for( std::vector<StateComponentPtr>::const_iterator it = stateComponents.begin(), eIt = stateComponents.end(); it != eIt; it++ )
  298. {
  299. m_baseState->add( const_cast<StateComponent *>( State::defaultState()->get( (*it)->typeId() ) ), false /* no override */ );
  300. }
  301. return hits.size();
  302. }
  303. //////////////////////////////////////////////////////////////////////////
  304. // OcclusionQuery
  305. //////////////////////////////////////////////////////////////////////////
  306. std::vector<GLuint> m_queries;
  307. std::vector<GLuint> m_queryNames;
  308. static DepthTestStateComponent *depthTestStateComponent()
  309. {
  310. static DepthTestStateComponentPtr d = new DepthTestStateComponent( false );
  311. return d.get();
  312. }
  313. void beginOcclusionQuery()
  314. {
  315. m_queries.resize( 0 );
  316. m_queryNames.resize( 0 );
  317. glClearColor( 0.0, 0.0, 0.0, 1.0 );
  318. glClearDepth( 1.0 );
  319. glClear( GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT );
  320. m_baseState->add( depthTestStateComponent(), true /* override */ );
  321. }
  322. void loadNameOcclusionQuery( GLuint name )
  323. {
  324. if( m_queries.size() )
  325. {
  326. glEndQuery( GL_ANY_SAMPLES_PASSED );
  327. }
  328. m_queries.push_back( 0 );
  329. glGenQueries( 1, &(m_queries[m_queries.size()-1]) );
  330. glBeginQuery( GL_ANY_SAMPLES_PASSED, m_queries[m_queries.size()-1] );
  331. m_queryNames.push_back( name );
  332. }
  333. size_t endOcclusionQuery( std::vector<HitRecord> &hits )
  334. {
  335. if( m_queries.size() )
  336. {
  337. glEndQuery( GL_ANY_SAMPLES_PASSED );
  338. }
  339. for( size_t i = 0, e = m_queries.size(); i < e; i++ )
  340. {
  341. GLuint samplesPassed = 0;
  342. glGetQueryObjectuiv( m_queries[i], GL_QUERY_RESULT, &samplesPassed );
  343. if( samplesPassed )
  344. {
  345. hits.push_back( HitRecord( 0, 0, NameStateComponent::nameFromGLName( m_queryNames[i] ) ) );
  346. }
  347. }
  348. glDeleteQueries( m_queries.size(), &(m_queries[0]) );
  349. m_baseState->add( const_cast<DepthTestStateComponent *>( State::defaultState()->get<DepthTestStateComponent>() ), false /* no override */ );
  350. return hits.size();
  351. }
  352. };
  353. Selector *Selector::Implementation::g_currentSelector = 0;
  354. //////////////////////////////////////////////////////////////////////////
  355. // Selector
  356. //////////////////////////////////////////////////////////////////////////
  357. Selector::Selector()
  358. : m_implementation( new Implementation( this ) )
  359. {
  360. }
  361. Selector::~Selector()
  362. {
  363. }
  364. void Selector::begin( const Imath::Box2f &region, Mode mode )
  365. {
  366. m_implementation->begin( region, mode );
  367. }
  368. void Selector::loadName( GLuint name )
  369. {
  370. m_implementation->loadName( name );
  371. }
  372. size_t Selector::end( std::vector<HitRecord> &hits )
  373. {
  374. return m_implementation->end( hits );
  375. }
  376. State *Selector::baseState()
  377. {
  378. return m_implementation->baseState();
  379. }
  380. void Selector::loadIDShader( const IECoreGL::Shader *idShader )
  381. {
  382. m_implementation->loadIDShader( idShader );
  383. }
  384. Selector *Selector::currentSelector()
  385. {
  386. return Implementation::currentSelector();
  387. }