Equalizer  1.6.1
eqPly/vertexBufferLeaf.cpp
1 
2 /* Copyright (c) 2007, Tobias Wolf <twolf@access.unizh.ch>
3  * 2008-2012, Stefan Eilemann <eile@equalizergraphics.com>
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions are met:
7  *
8  * - Redistributions of source code must retain the above copyright notice, this
9  * list of conditions and the following disclaimer.
10  * - Redistributions in binary form must reproduce the above copyright notice,
11  * this list of conditions and the following disclaimer in the documentation
12  * and/or other materials provided with the distribution.
13  * - Neither the name of Eyescale Software GmbH nor the names of its
14  * contributors may be used to endorse or promote products derived from this
15  * software without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18  * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE
21  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27  * POSSIBILITY OF SUCH DAMAGE.
28  */
29 
30 
31 #include "vertexBufferLeaf.h"
32 #include "vertexBufferData.h"
33 #include "vertexBufferState.h"
34 #include "vertexData.h"
35 #include <map>
36 
37 namespace mesh
38 {
39 
40 /* Finish partial setup - sort, reindex and merge into global data. */
41 void VertexBufferLeaf::setupTree( VertexData& data, const Index start,
42  const Index length, const Axis axis,
43  const size_t depth,
44  VertexBufferData& globalData )
45 {
46  data.sort( start, length, axis );
47  _vertexStart = globalData.vertices.size();
48  _vertexLength = 0;
49  _indexStart = globalData.indices.size();
50  _indexLength = 0;
51 
52  const bool hasColors = !data.colors.empty();
53 
54  // stores the new indices (relative to _start)
55  std::map< Index, ShortIndex > newIndex;
56 
57  for( Index t = 0; t < length; ++t )
58  {
59  for( Index v = 0; v < 3; ++v )
60  {
61  Index i = data.triangles[start + t][v];
62  if( newIndex.find( i ) == newIndex.end() )
63  {
64  newIndex[i] = _vertexLength++;
65  // assert number of vertices does not exceed SmallIndex range
66  MESHASSERT( _vertexLength );
67  globalData.vertices.push_back( data.vertices[i] );
68  if( hasColors )
69  globalData.colors.push_back( data.colors[i] );
70  globalData.normals.push_back( data.normals[i] );
71  }
72  globalData.indices.push_back( newIndex[i] );
73  ++_indexLength;
74  }
75  }
76 
77 #ifndef NDEBUG
78  MESHINFO << "setupTree" << "( " << _indexStart << ", " << _indexLength
79  << "; start " << _vertexStart << ", " << _vertexLength
80  << " vertices)." << std::endl;
81 #endif
82 }
83 
84 
85 /* Compute the bounding sphere of the leaf's indexed vertices. */
86 const BoundingSphere& VertexBufferLeaf::updateBoundingSphere()
87 {
88  // We determine a bounding sphere by:
89  // 1) Using the inner sphere of the dominant axis of the bounding box as an
90  // estimate
91  // 2) Test all points to be in that sphere
92  // 3) Expand the sphere to contain all points outside.
93 
94 
95  // 1a) initialize and compute a bounding box
96  _boundingBox[0] = _globalData.vertices[ _vertexStart +
97  _globalData.indices[_indexStart] ];
98  _boundingBox[1] = _globalData.vertices[ _vertexStart +
99  _globalData.indices[_indexStart] ];
100 
101  for( Index i = 1 + _indexStart; i < _indexStart + _indexLength; ++i )
102  {
103  const Vertex& vertex = _globalData.vertices[ _vertexStart +
104  _globalData.indices[ i ] ];
105  _boundingBox[0][0] = std::min( _boundingBox[0][0], vertex[0] );
106  _boundingBox[1][0] = std::max( _boundingBox[1][0], vertex[0] );
107  _boundingBox[0][1] = std::min( _boundingBox[0][1], vertex[1] );
108  _boundingBox[1][1] = std::max( _boundingBox[1][1], vertex[1] );
109  _boundingBox[0][2] = std::min( _boundingBox[0][2], vertex[2] );
110  _boundingBox[1][2] = std::max( _boundingBox[1][2], vertex[2] );
111  }
112 
113  // 1b) get inner sphere of bounding box as an initial estimate
114  _boundingSphere.x() = ( _boundingBox[0].x() + _boundingBox[1].x() ) * 0.5f;
115  _boundingSphere.y() = ( _boundingBox[0].y() + _boundingBox[1].y() ) * 0.5f;
116  _boundingSphere.z() = ( _boundingBox[0].z() + _boundingBox[1].z() ) * 0.5f;
117 
118  _boundingSphere.w() = LB_MAX( _boundingBox[1].x() - _boundingBox[0].x(),
119  _boundingBox[1].y() - _boundingBox[0].y() );
120  _boundingSphere.w() = LB_MAX( _boundingBox[1].z() - _boundingBox[0].z(),
121  _boundingSphere.w() );
122  _boundingSphere.w() *= .5f;
123 
124  float radius = _boundingSphere.w();
125  float radiusSquared = radius * radius;
126  Vertex center( _boundingSphere.array );
127 
128  // 2) test all points to be in the estimated bounding sphere
129  for( Index offset = 0; offset < _indexLength; ++offset )
130  {
131  const Vertex& vertex =
132  _globalData.vertices[ _vertexStart +
133  _globalData.indices[_indexStart + offset] ];
134 
135  const Vertex centerToPoint = vertex - center;
136  const float distanceSquared = centerToPoint.squared_length();
137  if( distanceSquared <= radiusSquared ) // point is inside existing BS
138  continue;
139 
140  // 3) expand sphere to contain 'outside' points
141  const float distance = sqrtf( distanceSquared );
142  const float delta = distance - radius;
143 
144  radius = ( radius + distance ) * .5f;
145  radiusSquared = radius * radius;
146  const Vertex normdelta = normalize( centerToPoint ) * ( 0.5f * delta );
147 
148  center += normdelta;
149 
150  LBASSERTINFO( Vertex( vertex-center ).squared_length() <=
151  ( radiusSquared + 2.f * std::numeric_limits<float>::epsilon( )),
152  vertex << " c " << center << " r " << radius << " ("
153  << Vertex( vertex-center ).length() << ")" );
154  }
155 
156 #ifndef NDEBUG
157  // 2a) re-test all points to be in the estimated bounding sphere
158  for( Index offset = 0; offset < _indexLength; ++offset )
159  {
160  const Vertex& vertex =
161  _globalData.vertices[ _vertexStart +
162  _globalData.indices[_indexStart + offset] ];
163 
164  const Vertex centerToPoint = vertex - center;
165  const float distanceSquared = centerToPoint.squared_length();
166  LBASSERTINFO( distanceSquared <=
167  ( radiusSquared + 2.f * std::numeric_limits<float>::epsilon( )),
168  vertex << " c " << center << " r " << radius << " ("
169  << Vertex( vertex-center ).length() << ")" );
170  }
171 #endif
172 
173  // store optimal bounding sphere
174  _boundingSphere.x() = center.x();
175  _boundingSphere.y() = center.y();
176  _boundingSphere.z() = center.z();
177  _boundingSphere.w() = radius;
178 
179 #ifndef NDEBUG
180  MESHINFO << "updateBoundingSphere" << "( " << _boundingSphere << " )."
181  << std::endl;
182 #endif
183 
184  return _boundingSphere;
185 }
186 
187 
188 /* Compute the range of this child. */
189 void VertexBufferLeaf::updateRange()
190 {
191  _range[0] = 1.0f * _indexStart / _globalData.indices.size();
192  _range[1] = _range[0] + 1.0f * _indexLength / _globalData.indices.size();
193 
194 #ifndef NDEBUG
195  MESHINFO << "updateRange" << "( " << _range[0] << ", " << _range[1]
196  << " )." << std::endl;
197 #endif
198 }
199 
200 #define glewGetContext state.glewGetContext
201 
202 /* Set up rendering of the leaf nodes. */
203 void VertexBufferLeaf::setupRendering( VertexBufferState& state,
204  GLuint* data ) const
205 {
206  switch( state.getRenderMode() )
207  {
208  case RENDER_MODE_IMMEDIATE:
209  break;
210 
211  case RENDER_MODE_BUFFER_OBJECT:
212  {
213  const char* charThis = reinterpret_cast< const char* >( this );
214 
215  if( data[VERTEX_OBJECT] == state.INVALID )
216  data[VERTEX_OBJECT] = state.newBufferObject( charThis + 0 );
217  glBindBuffer( GL_ARRAY_BUFFER, data[VERTEX_OBJECT] );
218  glBufferData( GL_ARRAY_BUFFER, _vertexLength * sizeof( Vertex ),
219  &_globalData.vertices[_vertexStart], GL_STATIC_DRAW );
220 
221  if( data[NORMAL_OBJECT] == state.INVALID )
222  data[NORMAL_OBJECT] = state.newBufferObject( charThis + 1 );
223  glBindBuffer( GL_ARRAY_BUFFER, data[NORMAL_OBJECT] );
224  glBufferData( GL_ARRAY_BUFFER, _vertexLength * sizeof( Normal ),
225  &_globalData.normals[_vertexStart], GL_STATIC_DRAW );
226 
227  if( data[COLOR_OBJECT] == state.INVALID )
228  data[COLOR_OBJECT] = state.newBufferObject( charThis + 2 );
229  if( state.useColors() )
230  {
231  glBindBuffer( GL_ARRAY_BUFFER, data[COLOR_OBJECT] );
232  glBufferData( GL_ARRAY_BUFFER, _vertexLength * sizeof( Color ),
233  &_globalData.colors[_vertexStart], GL_STATIC_DRAW );
234  }
235 
236  if( data[INDEX_OBJECT] == state.INVALID )
237  data[INDEX_OBJECT] = state.newBufferObject( charThis + 3 );
238  glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, data[INDEX_OBJECT] );
239  glBufferData( GL_ELEMENT_ARRAY_BUFFER,
240  _indexLength * sizeof( ShortIndex ),
241  &_globalData.indices[_indexStart], GL_STATIC_DRAW );
242 
243  break;
244  }
245  case RENDER_MODE_DISPLAY_LIST:
246  default:
247  {
248  if( data[0] == state.INVALID )
249  {
250  char* key = (char*)( this );
251  if( state.useColors( ))
252  ++key;
253  data[0] = state.newDisplayList( key );
254  }
255  glNewList( data[0], GL_COMPILE );
256  renderImmediate( state );
257  glEndList();
258  break;
259  }
260  }
261 }
262 
263 /* Draw the leaf. */
264 void VertexBufferLeaf::draw( VertexBufferState& state ) const
265 {
266  if( state.stopRendering( ))
267  return;
268 
269  state.updateRegion( _boundingBox );
270  switch( state.getRenderMode() )
271  {
272  case RENDER_MODE_IMMEDIATE:
273  renderImmediate( state );
274  return;
275  case RENDER_MODE_BUFFER_OBJECT:
276  renderBufferObject( state );
277  return;
278  case RENDER_MODE_DISPLAY_LIST:
279  default:
280  renderDisplayList( state );
281  return;
282  }
283 }
284 
285 /* Render the leaf with buffer objects. */
286 void VertexBufferLeaf::renderBufferObject( VertexBufferState& state ) const
287 {
288  GLuint buffers[4];
289  for( int i = 0; i < 4; ++i )
290  buffers[i] =
291  state.getBufferObject( reinterpret_cast< const char* >(this) + i );
292  if( buffers[VERTEX_OBJECT] == state.INVALID ||
293  buffers[NORMAL_OBJECT] == state.INVALID ||
294  buffers[COLOR_OBJECT] == state.INVALID ||
295  buffers[INDEX_OBJECT] == state.INVALID )
296 
297  setupRendering( state, buffers );
298 
299  if( state.useColors() )
300  {
301  glBindBuffer( GL_ARRAY_BUFFER, buffers[COLOR_OBJECT] );
302  glColorPointer( 3, GL_UNSIGNED_BYTE, 0, 0 );
303  }
304  glBindBuffer( GL_ARRAY_BUFFER, buffers[NORMAL_OBJECT] );
305  glNormalPointer( GL_FLOAT, 0, 0 );
306  glBindBuffer( GL_ARRAY_BUFFER, buffers[VERTEX_OBJECT] );
307  glVertexPointer( 3, GL_FLOAT, 0, 0 );
308  glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, buffers[INDEX_OBJECT] );
309  glDrawElements( GL_TRIANGLES, GLsizei(_indexLength), GL_UNSIGNED_SHORT, 0 );
310 }
311 
312 
313 /* Render the leaf with a display list. */
314 inline
315 void VertexBufferLeaf::renderDisplayList( VertexBufferState& state ) const
316 {
317  char* key = (char*)( this );
318  if( state.useColors( ))
319  ++key;
320 
321  GLuint displayList = state.getDisplayList( key );
322 
323  if( displayList == state.INVALID )
324  setupRendering( state, &displayList );
325 
326  glCallList( displayList );
327 }
328 
329 
330 /* Render the leaf with immediate mode primitives or vertex arrays. */
331 inline
332 void VertexBufferLeaf::renderImmediate( VertexBufferState& state ) const
333 {
334  glBegin( GL_TRIANGLES );
335  for( Index offset = 0; offset < _indexLength; ++offset )
336  {
337  const Index i =_vertexStart + _globalData.indices[_indexStart + offset];
338  if( state.useColors() )
339  glColor3ubv( &_globalData.colors[i][0] );
340  glNormal3fv( &_globalData.normals[i][0] );
341  glVertex3fv( &_globalData.vertices[i][0] );
342  }
343  glEnd();
344 }
345 
346 
347 /* Read leaf node from memory. */
348 void VertexBufferLeaf::fromMemory( char** addr, VertexBufferData& globalData )
349 {
350  size_t nodeType;
351  memRead( reinterpret_cast< char* >( &nodeType ), addr, sizeof( size_t ) );
352  if( nodeType != LEAF_TYPE )
353  throw MeshException( "Error reading binary file. Expected a leaf "
354  "node, but found something else instead." );
355  VertexBufferBase::fromMemory( addr, globalData );
356  memRead( reinterpret_cast< char* >( &_boundingBox ), addr,
357  sizeof( BoundingBox ) );
358  memRead( reinterpret_cast< char* >( &_vertexStart ), addr,
359  sizeof( Index ) );
360  memRead( reinterpret_cast< char* >( &_vertexLength ), addr,
361  sizeof( ShortIndex ) );
362  memRead( reinterpret_cast< char* >( &_indexStart ), addr,
363  sizeof( Index ) );
364  memRead( reinterpret_cast< char* >( &_indexLength ), addr,
365  sizeof( Index ) );
366 }
367 
368 
369 /* Write leaf node to output stream. */
370 void VertexBufferLeaf::toStream( std::ostream& os )
371 {
372  size_t nodeType = LEAF_TYPE;
373  os.write( reinterpret_cast< char* >( &nodeType ), sizeof( size_t ));
374  VertexBufferBase::toStream( os );
375  os.write( reinterpret_cast< char* >( &_boundingBox ), sizeof( BoundingBox));
376  os.write( reinterpret_cast< char* >( &_vertexStart ), sizeof( Index ));
377  os.write( reinterpret_cast< char* >( &_vertexLength ),sizeof( ShortIndex ));
378  os.write( reinterpret_cast< char* >( &_indexStart ), sizeof( Index ));
379  os.write( reinterpret_cast< char* >( &_indexLength ), sizeof( Index ));
380 }
381 
382 }