Developer Documentation
VertexDeclaration.cc
1 /*===========================================================================*\
2  * *
3  * OpenFlipper *
4  * Copyright (c) 2001-2015, RWTH-Aachen University *
5  * Department of Computer Graphics and Multimedia *
6  * All rights reserved. *
7  * www.openflipper.org *
8  * *
9  *---------------------------------------------------------------------------*
10  * This file is part of OpenFlipper. *
11  *---------------------------------------------------------------------------*
12  * *
13  * Redistribution and use in source and binary forms, with or without *
14  * modification, are permitted provided that the following conditions *
15  * are met: *
16  * *
17  * 1. Redistributions of source code must retain the above copyright notice, *
18  * this list of conditions and the following disclaimer. *
19  * *
20  * 2. Redistributions in binary form must reproduce the above copyright *
21  * notice, this list of conditions and the following disclaimer in the *
22  * documentation and/or other materials provided with the distribution. *
23  * *
24  * 3. Neither the name of the copyright holder nor the names of its *
25  * contributors may be used to endorse or promote products derived from *
26  * this software without specific prior written permission. *
27  * *
28  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS *
29  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED *
30  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A *
31  * PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER *
32  * OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, *
33  * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, *
34  * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR *
35  * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF *
36  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING *
37  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS *
38  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. *
39  * *
40 \*===========================================================================*/
41 
42 /*===========================================================================*\
43  * *
44  * $Revision$ *
45  * $Author$ *
46  * $Date$ *
47  * *
48 \*===========================================================================*/
49 
50 #include <ACG/GL/acg_glew.hh>
51 #include <ACG/GL/gl.hh>
52 #include <ACG/GL/GLState.hh>
53 #include <ACG/ShaderUtils/GLSLShader.hh>
54 
55 #include <QTextStream>
56 
57 #include "VertexDeclaration.hh"
58 
59 
60 namespace ACG
61 {
62 
63 VertexElement::VertexElement()
64  : type_(0), numElements_(0), usage_(VERTEX_USAGE_SHADER_INPUT), shaderInputName_(0), pointer_(0), divisor_(0), vbo_(0)
65 {
66 }
67 
68 
69 void VertexElement::setByteOffset(unsigned int _offset)
70 {
71  // union cast instead of reinterpret_cast for cross-platform compatibility
72  union ptr2uint
73  {
74  unsigned long u;
75  const void* p;
76  } offset;
77 
78  offset.u = static_cast<unsigned long>(_offset);
79 
80  pointer_ = offset.p;
81 }
82 
83 unsigned int VertexElement::getByteOffset() const
84 {
85  // union cast instead of reinterpret_cast for cross-platform compatibility
86  union ptr2uint
87  {
88  unsigned long u;
89  const void* p;
90  } offset;
91 
92  offset.p = pointer_;
93 
94  return static_cast<unsigned int>(offset.u);
95 }
96 
97 VertexDeclaration::VertexDeclaration()
98 : vertexStride_(0), strideUserDefined_(0)
99 {
100 
101 }
102 
103 
104 VertexDeclaration::~VertexDeclaration()
105 {
106 
107 }
108 
109 
111 {
112  addElements(1, _pElement);
113 }
114 
115 void VertexDeclaration::addElement(unsigned int _type,
116  unsigned int _numElements,
117  VERTEX_USAGE _usage,
118  const void* _pointer,
119  const char* _shaderInputName,
120  unsigned int _divisor,
121  unsigned int _vbo)
122 {
123  VertexElement* ve = new VertexElement();
124 
125  ve->type_ = _type;
126  ve->numElements_ = _numElements;
127  ve->usage_ = _usage;
128  ve->shaderInputName_ = _shaderInputName;
129  ve->pointer_ = _pointer;
130  ve->divisor_ = _divisor;
131  ve->vbo_ = _vbo;
132  addElement(ve);
133 
134  delete ve;
135 }
136 
137 void VertexDeclaration::addElement(unsigned int _type,
138  unsigned int _numElements,
139  VERTEX_USAGE _usage,
140  size_t _byteOffset,
141  const char* _shaderInputName,
142  unsigned int _divisor,
143  unsigned int _vbo)
144 {
145  VertexElement* ve = new VertexElement();
146 
147  ve->type_ = _type;
148  ve->numElements_ = _numElements;
149  ve->usage_ = _usage;
150  ve->shaderInputName_ = _shaderInputName;
151  ve->pointer_ = (void*)_byteOffset;
152  ve->divisor_ = _divisor;
153  ve->vbo_ = _vbo;
154 
155  addElement(ve);
156 
157  delete ve;
158 }
159 
160 
161 void VertexDeclaration::addElements(unsigned int _numElements, const VertexElement* _pElements)
162 {
163  elements_.reserve(elements_.size() + _numElements);
164 
165  for (unsigned int i = 0; i < _numElements; ++i)
166  {
167  VertexElement tmp = _pElements[i];
168  updateShaderInputName(&tmp);
169  elements_.push_back(tmp);
170  }
171 
172  updateOffsets();
173 
174  if (!strideUserDefined_)
175  {
176  // recompute vertex stride from declaration (based on last element)
177 
178  unsigned int n = getNumElements();
179 
180  if (n)
181  {
182  // stride = offset of last element + sizeof last element - offset of first element
183 
184  // union instead of reinterpret_cast for cross-platform compatibility
185  union ptr2uint
186  {
187  unsigned long u;
188  const void* p;
189  } lastOffset, firstOffset;
190 
191 
192 
193  std::map<unsigned int, VertexElement*> vboFirstElements;
194  std::map<unsigned int, VertexElement*> vboLastElements;
195 
196  for (unsigned int i = 0; i < n; ++i)
197  {
198  if (vboFirstElements.find(elements_[i].vbo_) == vboFirstElements.end())
199  vboFirstElements[elements_[i].vbo_] = &elements_[i];
200 
201  vboLastElements[elements_[i].vbo_] = &elements_[i];
202  }
203 
204 
205  for (std::map<unsigned int, VertexElement*>::iterator it = vboFirstElements.begin(); it != vboFirstElements.end(); ++it)
206  {
207  VertexElement* lastElement = vboLastElements[it->first];
208  firstOffset.p = it->second->pointer_;
209  lastOffset.p = lastElement->pointer_;
210 
211  vertexStridesVBO_[it->first] = static_cast<unsigned int>(lastOffset.u + getElementSize( lastElement ) - firstOffset.u);
212  }
213 
214  vertexStride_ = vertexStridesVBO_.begin()->second;
215  }
216  }
217 
218 }
219 
220 
221 // union instead of reinterpret_cast for cross-platform compatibility, must be global for use in std::map
223 {
224  unsigned long u;
225  const void* p;
226 };
227 
229 {
230  unsigned int numElements = getNumElements();
231 
232  if (!numElements) return;
233 
234 
235  // separate offsets for each vbo
236 
237  std::map<unsigned int, VertexDeclaration_ptr2uint> vboOffsets;
238  std::map<unsigned int, VertexElement*> vboPrevElements;
239 
240  for (unsigned int i = 0; i < numElements; ++i)
241  {
242  if (vboOffsets.find(elements_[i].vbo_) == vboOffsets.end())
243  {
244  vboOffsets[elements_[i].vbo_].p = elements_[i].pointer_;
245  vboPrevElements[elements_[i].vbo_] = &elements_[i];
246  }
247  }
248 
249  for (unsigned int i = 0; i < numElements; ++i)
250  {
251  VertexElement* el = &elements_[i];
252 
253  bool updateOffset = false;
254 
255  if (el->pointer_)
256  {
257  vboOffsets[el->vbo_].p = el->pointer_;
258  vboPrevElements[el->vbo_] = el;
259  }
260  else
261  {
262  VertexElement* prevEl = vboPrevElements[el->vbo_];
263  if (prevEl != el)
264  {
265  updateOffset = true;
266  vboOffsets[el->vbo_].u += getElementSize(prevEl);
267  }
268  vboPrevElements[el->vbo_] = el;
269  }
270 
271  if (updateOffset)
272  el->pointer_ = vboOffsets[el->vbo_].p;
273  }
274 }
275 
276 
278 {
279  if (!_pElem->shaderInputName_)
280  {
281  assert(_pElem->usage_ != VERTEX_USAGE_SHADER_INPUT);
282 
283  const char* sz = "";
284 
285  switch (_pElem->usage_)
286  {
287  case VERTEX_USAGE_POSITION: sz = "inPosition"; break;
288  case VERTEX_USAGE_NORMAL: sz = "inNormal"; break;
289  case VERTEX_USAGE_TEXCOORD: sz = "inTexCoord"; break;
290  case VERTEX_USAGE_COLOR: sz = "inColor"; break;
291  case VERTEX_USAGE_BLENDWEIGHTS: sz = "inBlendWeights"; break;
292  case VERTEX_USAGE_BLENDINDICES: sz = "inBlendIndices"; break;
293 
294  default:
295  std::cerr << "VertexDeclaration::updateShaderInputName - unknown vertex usage - " << _pElem->usage_ << std::endl;
296  break;
297  }
298 
299  _pElem->shaderInputName_ = sz;
300  }
301 }
302 
303 
305 {
306  return elements_.size();
307 }
308 
309 
310 unsigned int VertexDeclaration::getGLTypeSize(unsigned int _type)
311 {
312  unsigned int size = 0;
313 
314  switch (_type)
315  {
316  case GL_DOUBLE:
317  size = 8; break;
318 
319  case GL_FLOAT:
320  case GL_UNSIGNED_INT:
321  case GL_INT:
322  size = 4; break;
323 
324 // case GL_HALF_FLOAT_ARB:
325  case 0x140B: // = GL_HALF_FLOAT_ARB
326  case GL_SHORT:
327  case GL_UNSIGNED_SHORT:
328  size = 2; break;
329 
330  case GL_BYTE:
331  case GL_UNSIGNED_BYTE:
332  size = 1; break;
333 
334  default:
335  std::cerr << "VertexDeclaration::getElementSize - unknown type - " << _type << std::endl;
336  break;
337  }
338 
339  return size;
340 }
341 
342 
343 
344 unsigned int VertexDeclaration::getElementSize(const VertexElement* _pElement)
345 {
346  return _pElement ? getGLTypeSize(_pElement->type_) * _pElement->numElements_ : 0;
347 }
348 
349 
350 
351 
352 
353 
354 
355 
357 {
358  unsigned int numElements = getNumElements();
359  unsigned int vertexStride = getVertexStride();
360 
361  for (unsigned int i = 0; i < numElements; ++i)
362  {
363  const VertexElement* pElem = getElement(i);
364 
365  switch (pElem->usage_)
366  {
368  {
369  ACG::GLState::vertexPointer(pElem->numElements_, pElem->type_, vertexStride, pElem->pointer_);
370  ACG::GLState::enableClientState(GL_VERTEX_ARRAY);
371  } break;
372 
373  case VERTEX_USAGE_COLOR:
374  {
375  ACG::GLState::colorPointer(pElem->numElements_, pElem->type_, vertexStride, pElem->pointer_);
376  ACG::GLState::enableClientState(GL_COLOR_ARRAY);
377  } break;
378 
380  {
381  glClientActiveTexture(GL_TEXTURE0);
382  ACG::GLState::texcoordPointer(pElem->numElements_, pElem->type_, vertexStride, pElem->pointer_);
383  ACG::GLState::enableClientState(GL_TEXTURE_COORD_ARRAY);
384  } break;
385 
386  case VERTEX_USAGE_NORMAL:
387  {
388  assert(pElem->numElements_ == 3);
389 
390  ACG::GLState::normalPointer(pElem->type_, vertexStride, pElem->pointer_);
391  ACG::GLState::enableClientState(GL_NORMAL_ARRAY);
392  } break;
393 
394  default: break;
395  }
396 
397 
398  }
399 }
400 
401 
403 {
404  unsigned int numElements = getNumElements();
405 
406  for (unsigned int i = 0; i < numElements; ++i)
407  {
408  const VertexElement* pElem = getElement(i);
409 
410  switch (pElem->usage_)
411  {
412  case VERTEX_USAGE_POSITION: ACG::GLState::disableClientState(GL_VERTEX_ARRAY); break;
413  case VERTEX_USAGE_COLOR: ACG::GLState::disableClientState(GL_COLOR_ARRAY); break;
414  case VERTEX_USAGE_TEXCOORD: ACG::GLState::disableClientState(GL_TEXTURE_COORD_ARRAY); break;
415  case VERTEX_USAGE_NORMAL: ACG::GLState::disableClientState(GL_NORMAL_ARRAY); break;
416 
417  default: break;
418  }
419  }
420 }
421 
422 
423 
425 {
426  assert(_prog);
427 
428  // setup correct attribute locations as specified
429 
430  unsigned int numElements = getNumElements();
431 
432  for (unsigned int i = 0; i < numElements; ++i)
433  {
434  unsigned int vertexStride = getVertexStride(i);
435 
436  const VertexElement* pElem = &elements_[i];
437 
438  int loc = _prog->getAttributeLocation(pElem->shaderInputName_);
439 
440  if (loc != -1)
441  {
442  // default: map integers to [-1, 1] or [0, 1] range
443  // exception: blend indices for gpu skinning eventually
444  GLboolean normalizeElem = GL_TRUE;
445 
446  if (pElem->usage_ == VERTEX_USAGE_BLENDINDICES)
447  normalizeElem = GL_FALSE;
448 
449  GLint curVBO = 0;
450  if (pElem->vbo_)
451  {
452  glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &curVBO);
453  glBindBuffer(GL_ARRAY_BUFFER, pElem->vbo_);
454  }
455 
456  glVertexAttribPointer(loc, pElem->numElements_, pElem->type_, normalizeElem, vertexStride, pElem->pointer_);
457 
458  if (supportsInstancedArrays())
459  {
460 #ifdef GL_ARB_instanced_arrays
461  glVertexAttribDivisor(loc, pElem->divisor_);
462 #endif
463  }
464  else if (pElem->divisor_)
465  std::cerr << "error: VertexDeclaration::activateShaderPipeline - instanced arrays not supported by gpu!" << std::endl;
466 
467  glEnableVertexAttribArray(loc);
468 
469  if (curVBO)
470  glBindBuffer(GL_ARRAY_BUFFER, curVBO);
471  }
472  }
473 }
474 
475 
477 {
478  assert(_prog);
479 
480  unsigned int numElements = getNumElements();
481 
482  for (unsigned int i = 0; i < numElements; ++i)
483  {
484  const VertexElement* pElem = &elements_[i];
485 
486  int loc = _prog->getAttributeLocation(pElem->shaderInputName_);
487 
488  if (loc != -1)
489  {
490  glDisableVertexAttribArray(loc);
491 
492  if (supportsInstancedArrays() && pElem->divisor_)
493  {
494 #ifdef GL_ARB_instanced_arrays
495  glVertexAttribDivisor(loc, 0);
496 #endif
497  }
498  }
499  }
500 }
501 
502 
503 
504 const VertexElement* VertexDeclaration::getElement(unsigned int i) const
505 {
506  return &elements_[i];
507 }
508 
509 
511 {
512  for (size_t i = 0; i < elements_.size(); ++i)
513  if (elements_[i].usage_ == _usage)
514  return int(i);
515 
516  return -1;
517 }
518 
520 {
521  int eid = findElementIdByUsage(_usage);
522 
523  if (eid >= 0)
524  return getElement((unsigned int)eid);
525 
526  return 0;
527 }
528 
529 
530 unsigned int VertexDeclaration::getVertexStride(unsigned int i) const
531 {
532  if (strideUserDefined_)
533  return vertexStride_;
534 
535  unsigned int vbo = getElement(i)->vbo_;
536  std::map<unsigned int, unsigned int>::const_iterator it = vertexStridesVBO_.find(vbo);
537 
538  return (it != vertexStridesVBO_.end()) ? it->second : vertexStride_;
539 // return vertexStride_;
540 }
541 
542 
543 void VertexDeclaration::setVertexStride(unsigned int _stride)
544 {
545  strideUserDefined_ = 1;
546  vertexStride_ = _stride;
547 }
548 
550 {
551  strideUserDefined_ = 0;
552  vertexStride_ = 0;
553 
554  elements_.clear();
555  vertexStridesVBO_.clear();
556 }
557 
558 
560 {
561  // maps VERTEX_USAGE -> string
562  const char* usageStrings[] =
563  {
564  "POSITION",
565  "NORMAL",
566  "TEXCOORD",
567  "COLOR",
568  "BLENDWEIGHTS",
569  "BLENDINDICES"
570  };
571 
572  QString result;
573 
574  QTextStream resultStrm(&result);
575  resultStrm << "stride = " << getVertexStride() << "\n";
576 
577 
578  for (unsigned int i = 0; i < getNumElements(); ++i)
579  {
580  const VertexElement* el = getElement(i);
581 
582  // convert element-type GLEnum to string
583  const char* typeString = "";
584 
585  switch (el->type_)
586  {
587  case GL_FLOAT: typeString = "GL_FLOAT"; break;
588  case GL_DOUBLE: typeString = "GL_DOUBLE"; break;
589 
590  case GL_INT: typeString = "GL_INT"; break;
591  case GL_UNSIGNED_INT: typeString = "GL_UNSIGNED_INT"; break;
592 
593  case GL_SHORT: typeString = "GL_SHORT"; break;
594  case GL_UNSIGNED_SHORT: typeString = "GL_UNSIGNED_SHORT"; break;
595 
596  case GL_BYTE: typeString = "GL_BYTE"; break;
597  case GL_UNSIGNED_BYTE: typeString = "GL_UNSIGNED_BYTE"; break;
598  default: typeString = "unknown"; break;
599  }
600 
601  // get usage in string form
602  const char* usage = (el->usage_ < VERTEX_USAGE_SHADER_INPUT) ? usageStrings[el->usage_] : el->shaderInputName_;
603 
604  resultStrm << "element " << i
605  << " - [type: " << typeString
606  << ", count: " << el->numElements_
607  << ", usage: " << usage
608  << ", shader-input: " << el->shaderInputName_
609  << ", offset: " << el->pointer_
610  << ", divisor: " << el->divisor_
611  << ", vbo: " << el->vbo_
612  << ", stride: " << getVertexStride(i)
613  << "]\n";
614  }
615 
616  return result;
617 }
618 
620 {
621  static int status_ = -1;
622 
623 #ifdef GL_ARB_instanced_arrays
624  if (status_ < 0) // core in 3.3
625  status_ = (checkExtensionSupported("GL_ARB_instanced_arrays") || openGLVersion(3,3)) ? 1 : 0;
626 #endif
627 
628  return status_ > 0;
629 }
630 
631 //=============================================================================
632 } // namespace ACG
633 //=============================================================================
const VertexElement * findElementByUsage(VERTEX_USAGE _usage) const
static bool supportsInstancedArrays()
unsigned int getVertexStride(unsigned int i=0) const
VERTEX_USAGE
-— input name in vertex shader ----—
unsigned int type_
GL_FLOAT, GL_UNSIGNED_BYTE, GL_INT, ...
void activateShaderPipeline(GLSL::Program *_prog) const
void activateFixedFunction() const
unsigned int getNumElements() const
Description of one vertex element.
int findElementIdByUsage(VERTEX_USAGE _usage) const
unsigned int vbo_
Explicit vbo source of this element, set to 0 if the buffer bound at the time of activating the decla...
void setVertexStride(unsigned int _stride)
const void * pointer_
Offset in bytes to the first occurrence of this element in vertex buffer; Or address to vertex data i...
static void disableClientState(GLenum _cap)
replaces glDisableClientState, supports locking
Definition: GLState.cc:1555
void updateShaderInputName(VertexElement *_pElem)
defined by user via VertexElement::shaderInputName_
static void enableClientState(GLenum _cap)
replaces glEnableClientState, supports locking
Definition: GLState.cc:1541
unsigned int numElements_
how many elements of type_
static void texcoordPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glTexcoordPointer, supports locking
Definition: GLState.cc:1928
VERTEX_USAGE usage_
position, normal, shader input ..
bool openGLVersion(const int _major, const int _minor)
Definition: gl.cc:95
unsigned int divisor_
For instanced rendering: Step rate describing how many instances are drawn before advancing to the ne...
void addElements(unsigned int _numElements, const VertexElement *_pElements)
void setByteOffset(unsigned int _offset)
unsigned int getByteOffset() const
const char * shaderInputName_
set shader input name, if usage_ = VERTEX_USAGE_USER_DEFINED otherwise this is set automatically...
int getAttributeLocation(const char *_name)
Get location of the specified attribute.
Definition: GLSLShader.cc:708
void deactivateFixedFunction() const
Namespace providing different geometric functions concerning angles.
Definition: DBSCANT.cc:51
void deactivateShaderPipeline(GLSL::Program *_prog) const
static void colorPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glColorPointer, supports locking
Definition: GLState.cc:1906
static void vertexPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glVertexPointer, supports locking
Definition: GLState.cc:1862
void addElement(const VertexElement *_pElement)
static unsigned int getElementSize(const VertexElement *_pElement)
static unsigned int getGLTypeSize(unsigned int _type)
bool checkExtensionSupported(const std::string &_extension)
Definition: gl.cc:73
const VertexElement * getElement(unsigned int i) const
GLSL program class.
Definition: GLSLShader.hh:217
static void normalPointer(GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glNormalPointer, supports locking
Definition: GLState.cc:1884