Developer Documentation
Loading...
Searching...
No Matches
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#include <ACG/GL/acg_glew.hh>
45#include <ACG/GL/gl.hh>
46#include <ACG/GL/GLState.hh>
47#include <ACG/ShaderUtils/GLSLShader.hh>
48
49#include <QTextStream>
50
51#include "VertexDeclaration.hh"
52
53
54namespace ACG
55{
56
57VertexElement::VertexElement()
58 : type_(0), numElements_(0), usage_(VERTEX_USAGE_SHADER_INPUT), shaderInputName_(0), pointer_(0), divisor_(0), vbo_(0)
59{
60}
61
62
63void VertexElement::setByteOffset(unsigned int _offset)
64{
65 // union cast instead of reinterpret_cast for cross-platform compatibility
66 union ptr2uint
67 {
68 unsigned long u;
69 const void* p;
70 } offset;
71
72 offset.u = static_cast<unsigned long>(_offset);
73
74 pointer_ = offset.p;
75}
76
77unsigned int VertexElement::getByteOffset() const
78{
79 // union cast instead of reinterpret_cast for cross-platform compatibility
80 union ptr2uint
81 {
82 unsigned long u;
83 const void* p;
84 } offset;
85
86 offset.p = pointer_;
87
88 return static_cast<unsigned int>(offset.u);
89}
90
91bool VertexElement::operator ==(const VertexElement &_other) const
92{
93 return (type_ == _other.type_) &&
94 (numElements_ == _other.numElements_) &&
95 (usage_ == _other.usage_) &&
96 (shaderInputName_ == _other.shaderInputName_) &&
97 (pointer_ == _other.pointer_) &&
98 (divisor_ == _other.divisor_) &&
99 (vbo_ == _other.vbo_);
100}
101
102VertexDeclaration::VertexDeclaration()
103: vertexStride_(0), strideUserDefined_(0)
104{
105
106}
107
108
109VertexDeclaration::~VertexDeclaration()
110{
111
112}
113
114
116{
117 addElements(1, _pElement);
118}
119
120void VertexDeclaration::addElement(unsigned int _type,
121 unsigned int _numElements,
122 VERTEX_USAGE _usage,
123 const void* _pointer,
124 const char* _shaderInputName,
125 unsigned int _divisor,
126 unsigned int _vbo)
127{
128 VertexElement* ve = new VertexElement();
129
130 ve->type_ = _type;
131 ve->numElements_ = _numElements;
132 ve->usage_ = _usage;
133 ve->shaderInputName_ = _shaderInputName;
134 ve->pointer_ = _pointer;
135 ve->divisor_ = _divisor;
136 ve->vbo_ = _vbo;
137 addElement(ve);
138
139 delete ve;
140}
141
142void VertexDeclaration::addElement(unsigned int _type,
143 unsigned int _numElements,
144 VERTEX_USAGE _usage,
145 size_t _byteOffset,
146 const char* _shaderInputName,
147 unsigned int _divisor,
148 unsigned int _vbo)
149{
150 VertexElement* ve = new VertexElement();
151
152 ve->type_ = _type;
153 ve->numElements_ = _numElements;
154 ve->usage_ = _usage;
155 ve->shaderInputName_ = _shaderInputName;
156 ve->pointer_ = (void*)_byteOffset;
157 ve->divisor_ = _divisor;
158 ve->vbo_ = _vbo;
159
160 addElement(ve);
161
162 delete ve;
163}
164
165
166void VertexDeclaration::addElements(unsigned int _numElements, const VertexElement* _pElements)
167{
168 elements_.reserve(elements_.size() + _numElements);
169
170 for (unsigned int i = 0; i < _numElements; ++i)
171 {
172 VertexElement tmp = _pElements[i];
174 elements_.push_back(tmp);
175 }
176
178
180 {
181 // recompute vertex stride from declaration (based on last element)
182
183 unsigned int n = getNumElements();
184
185 if (n)
186 {
187 // stride = offset of last element + sizeof last element - offset of first element
188
189 // union instead of reinterpret_cast for cross-platform compatibility
190 union ptr2uint
191 {
192 unsigned long u;
193 const void* p;
194 } lastOffset, firstOffset;
195
196
197
198 std::map<unsigned int, VertexElement*> vboFirstElements;
199 std::map<unsigned int, VertexElement*> vboLastElements;
200
201 for (unsigned int i = 0; i < n; ++i)
202 {
203 if (vboFirstElements.find(elements_[i].vbo_) == vboFirstElements.end())
204 vboFirstElements[elements_[i].vbo_] = &elements_[i];
205
206 vboLastElements[elements_[i].vbo_] = &elements_[i];
207 }
208
209
210 for (std::map<unsigned int, VertexElement*>::iterator it = vboFirstElements.begin(); it != vboFirstElements.end(); ++it)
211 {
212 VertexElement* lastElement = vboLastElements[it->first];
213 firstOffset.p = it->second->pointer_;
214 lastOffset.p = lastElement->pointer_;
215
216 vertexStridesVBO_[it->first] = static_cast<unsigned int>(lastOffset.u + getElementSize( lastElement ) - firstOffset.u);
217 }
218
219 vertexStride_ = vertexStridesVBO_.begin()->second;
220 }
221 }
222
223}
224
225
226// union instead of reinterpret_cast for cross-platform compatibility, must be global for use in std::map
228{
229 unsigned long u;
230 const void* p;
231};
232
234{
235 unsigned int numElements = getNumElements();
236
237 if (!numElements) return;
238
239
240 // separate offsets for each vbo
241
242 std::map<unsigned int, VertexDeclaration_ptr2uint> vboOffsets;
243 std::map<unsigned int, VertexElement*> vboPrevElements;
244
245 for (unsigned int i = 0; i < numElements; ++i)
246 {
247 if (vboOffsets.find(elements_[i].vbo_) == vboOffsets.end())
248 {
249 vboOffsets[elements_[i].vbo_].p = elements_[i].pointer_;
250 vboPrevElements[elements_[i].vbo_] = &elements_[i];
251 }
252 }
253
254 for (unsigned int i = 0; i < numElements; ++i)
255 {
256 VertexElement* el = &elements_[i];
257
258 bool updateOffset = false;
259
260 if (el->pointer_)
261 {
262 vboOffsets[el->vbo_].p = el->pointer_;
263 vboPrevElements[el->vbo_] = el;
264 }
265 else
266 {
267 VertexElement* prevEl = vboPrevElements[el->vbo_];
268 if (prevEl != el)
269 {
270 updateOffset = true;
271 vboOffsets[el->vbo_].u += getElementSize(prevEl);
272 }
273 vboPrevElements[el->vbo_] = el;
274 }
275
276 if (updateOffset)
277 el->pointer_ = vboOffsets[el->vbo_].p;
278 }
279}
280
281
283{
284 if (!_pElem->shaderInputName_)
285 {
286 assert(_pElem->usage_ != VERTEX_USAGE_SHADER_INPUT);
287
288 const char* sz = "";
289
290 switch (_pElem->usage_)
291 {
292 case VERTEX_USAGE_POSITION: sz = "inPosition"; break;
293 case VERTEX_USAGE_NORMAL: sz = "inNormal"; break;
294 case VERTEX_USAGE_TEXCOORD: sz = "inTexCoord"; break;
295 case VERTEX_USAGE_COLOR: sz = "inColor"; break;
296 case VERTEX_USAGE_BLENDWEIGHTS: sz = "inBlendWeights"; break;
297 case VERTEX_USAGE_BLENDINDICES: sz = "inBlendIndices"; break;
298
299 default:
300 std::cerr << "VertexDeclaration::updateShaderInputName - unknown vertex usage - " << _pElem->usage_ << std::endl;
301 break;
302 }
303
304 _pElem->shaderInputName_ = sz;
305 }
306}
307
308
310{
311 return elements_.size();
312}
313
314
315size_t VertexDeclaration::getGLTypeSize(unsigned int _type)
316{
317 size_t size = 0;
318
319 switch (_type)
320 {
321 case GL_DOUBLE:
322 size = 8; break;
323
324 case GL_FLOAT:
325 case GL_UNSIGNED_INT:
326 case GL_INT:
327 size = 4; break;
328
329// case GL_HALF_FLOAT_ARB:
330 case 0x140B: // = GL_HALF_FLOAT_ARB
331 case GL_SHORT:
332 case GL_UNSIGNED_SHORT:
333 size = 2; break;
334
335 case GL_BYTE:
336 case GL_UNSIGNED_BYTE:
337 size = 1; break;
338
339 default:
340 std::cerr << "VertexDeclaration::getElementSize - unknown type - " << _type << std::endl;
341 break;
342 }
343
344 return size;
345}
346
347
348
350{
351 return _pElement ? getGLTypeSize(_pElement->type_) * _pElement->numElements_ : 0;
352}
353
354
355
356
357
358
359
360
362{
363 unsigned int numElements = getNumElements();
364 unsigned int vertexStride = getVertexStride();
365
366 for (unsigned int i = 0; i < numElements; ++i)
367 {
368 const VertexElement* pElem = getElement(i);
369
370 switch (pElem->usage_)
371 {
373 {
374 ACG::GLState::vertexPointer(pElem->numElements_, pElem->type_, vertexStride, pElem->pointer_);
375 ACG::GLState::enableClientState(GL_VERTEX_ARRAY);
376 } break;
377
379 {
380 ACG::GLState::colorPointer(pElem->numElements_, pElem->type_, vertexStride, pElem->pointer_);
381 ACG::GLState::enableClientState(GL_COLOR_ARRAY);
382 } break;
383
385 {
386 glClientActiveTexture(GL_TEXTURE0);
387 ACG::GLState::texcoordPointer(pElem->numElements_, pElem->type_, vertexStride, pElem->pointer_);
388 ACG::GLState::enableClientState(GL_TEXTURE_COORD_ARRAY);
389 } break;
390
392 {
393 assert(pElem->numElements_ == 3);
394
395 ACG::GLState::normalPointer(pElem->type_, vertexStride, pElem->pointer_);
396 ACG::GLState::enableClientState(GL_NORMAL_ARRAY);
397 } break;
398
399 default: break;
400 }
401
402
403 }
404}
405
406
408{
409 unsigned int numElements = getNumElements();
410
411 for (unsigned int i = 0; i < numElements; ++i)
412 {
413 const VertexElement* pElem = getElement(i);
414
415 switch (pElem->usage_)
416 {
417 case VERTEX_USAGE_POSITION: ACG::GLState::disableClientState(GL_VERTEX_ARRAY); break;
418 case VERTEX_USAGE_COLOR: ACG::GLState::disableClientState(GL_COLOR_ARRAY); break;
419 case VERTEX_USAGE_TEXCOORD: ACG::GLState::disableClientState(GL_TEXTURE_COORD_ARRAY); break;
420 case VERTEX_USAGE_NORMAL: ACG::GLState::disableClientState(GL_NORMAL_ARRAY); break;
421
422 default: break;
423 }
424 }
425}
426
427
428
430{
431 assert(_prog);
432
433 // setup correct attribute locations as specified
434
435 unsigned int numElements = getNumElements();
436
437 for (unsigned int i = 0; i < numElements; ++i)
438 {
439 unsigned int vertexStride = getVertexStride(i);
440
441 const VertexElement* pElem = &elements_[i];
442
443 int loc = _prog->getAttributeLocation(pElem->shaderInputName_);
444
445 if (loc != -1)
446 {
447 // default: map integers to [-1, 1] or [0, 1] range
448 // exception: blend indices for gpu skinning eventually
449 GLboolean normalizeElem = GL_TRUE;
450
451 if (pElem->usage_ == VERTEX_USAGE_BLENDINDICES)
452 normalizeElem = GL_FALSE;
453
454 GLint curVBO = 0;
455 if (pElem->vbo_)
456 {
457 glGetIntegerv(GL_ARRAY_BUFFER_BINDING, &curVBO);
458 glBindBuffer(GL_ARRAY_BUFFER, pElem->vbo_);
459 }
460
461 glVertexAttribPointer(loc, pElem->numElements_, pElem->type_, normalizeElem, vertexStride, pElem->pointer_);
462
464 {
465 if( openGLVersionTest(3,3) )
466 {
467 glVertexAttribDivisor(loc, pElem->divisor_);
468 }
469 else
470 {
471 glVertexAttribDivisorARB(loc, pElem->divisor_);
472 }
473 }
474 else if (pElem->divisor_)
475 std::cerr << "error: VertexDeclaration::activateShaderPipeline - instanced arrays not supported by gpu!" << std::endl;
476
477 glEnableVertexAttribArray(loc);
478
479 if (curVBO)
480 glBindBuffer(GL_ARRAY_BUFFER, curVBO);
481 }
482 }
483}
484
485
487{
488 assert(_prog);
489
490 unsigned int numElements = getNumElements();
491
492 for (unsigned int i = 0; i < numElements; ++i)
493 {
494 const VertexElement* pElem = &elements_[i];
495
496 int loc = _prog->getAttributeLocation(pElem->shaderInputName_);
497
498 if (loc != -1)
499 {
500 glDisableVertexAttribArray(loc);
501
502 if (supportsInstancedArrays() && pElem->divisor_)
503 {
504 if( openGLVersionTest(3,3) )
505 {
506 glVertexAttribDivisor(loc, 0);
507 }
508 else
509 {
510 glVertexAttribDivisorARB(loc, 0);
511 }
512 }
513 }
514 }
515}
516
517
518
520{
521 return &elements_[i];
522}
523
524
526{
527 for (size_t i = 0; i < elements_.size(); ++i)
528 if (elements_[i].usage_ == _usage)
529 return int(i);
530
531 return -1;
532}
533
535{
536 int eid = findElementIdByUsage(_usage);
537
538 if (eid >= 0)
539 return getElement((unsigned int)eid);
540
541 return 0;
542}
543
544
545unsigned int VertexDeclaration::getVertexStride(unsigned int i) const
546{
548 return vertexStride_;
549
550 const VertexElement* element = getElement(i);
551
552 if (element)
553 {
554 unsigned int vbo = getElement(i)->vbo_;
555 std::map<unsigned int, unsigned int>::const_iterator it = vertexStridesVBO_.find(vbo);
556
557 return (it != vertexStridesVBO_.end()) ? it->second : vertexStride_;
558 }
559
560 return 0;
561}
562
563
564void VertexDeclaration::setVertexStride(unsigned int _stride)
565{
567 vertexStride_ = _stride;
568}
569
571{
573 vertexStride_ = 0;
574
575 elements_.clear();
576 vertexStridesVBO_.clear();
577}
578
579
581{
582 // maps VERTEX_USAGE -> string
583 const char* usageStrings[] =
584 {
585 "POSITION",
586 "NORMAL",
587 "TEXCOORD",
588 "COLOR",
589 "BLENDWEIGHTS",
590 "BLENDINDICES"
591 };
592
593 QString result;
594
595 QTextStream resultStrm(&result);
596 resultStrm << "stride = " << getVertexStride() << "\n";
597
598
599 for (unsigned int i = 0; i < getNumElements(); ++i)
600 {
601 const VertexElement* el = getElement(i);
602
603 // convert element-type GLEnum to string
604 const char* typeString = "";
605
606 switch (el->type_)
607 {
608 case GL_FLOAT: typeString = "GL_FLOAT"; break;
609 case GL_DOUBLE: typeString = "GL_DOUBLE"; break;
610
611 case GL_INT: typeString = "GL_INT"; break;
612 case GL_UNSIGNED_INT: typeString = "GL_UNSIGNED_INT"; break;
613
614 case GL_SHORT: typeString = "GL_SHORT"; break;
615 case GL_UNSIGNED_SHORT: typeString = "GL_UNSIGNED_SHORT"; break;
616
617 case GL_BYTE: typeString = "GL_BYTE"; break;
618 case GL_UNSIGNED_BYTE: typeString = "GL_UNSIGNED_BYTE"; break;
619 default: typeString = "unknown"; break;
620 }
621
622 // get usage in string form
623 const char* usage = (el->usage_ < VERTEX_USAGE_SHADER_INPUT) ? usageStrings[el->usage_] : el->shaderInputName_;
624
625 resultStrm << "element " << i
626 << " - [type: " << typeString
627 << ", count: " << el->numElements_
628 << ", usage: " << usage
629 << ", shader-input: " << el->shaderInputName_
630 << ", offset: " << el->pointer_
631 << ", divisor: " << el->divisor_
632 << ", vbo: " << el->vbo_
633 << ", stride: " << getVertexStride(i)
634 << "]\n";
635 }
636
637 return result;
638}
639
641{
644 return false;
645
646 if (elements_ != _other.elements_)
647 return false;
648
650 return false;
651
652 return true;
653}
654
656{
657 static int status_ = -1;
658
659 if (status_ < 0) // core in 3.3
660 status_ = (checkExtensionSupported("GL_ARB_instanced_arrays") || openGLVersion(3,3)) ? 1 : 0;
661
662 return status_ > 0;
663}
664
665//=============================================================================
666} // namespace ACG
667//=============================================================================
static void disableClientState(GLenum _cap)
replaces glDisableClientState, supports locking
Definition GLState.cc:1584
static void colorPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glColorPointer, supports locking
Definition GLState.cc:2005
static void vertexPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glVertexPointer, supports locking
Definition GLState.cc:1961
static void normalPointer(GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glNormalPointer, supports locking
Definition GLState.cc:1983
static void enableClientState(GLenum _cap)
replaces glEnableClientState, supports locking
Definition GLState.cc:1570
static void texcoordPointer(GLint _size, GLenum _type, GLsizei _stride, const GLvoid *_pointer)
replaces glTexcoordPointer, supports locking
Definition GLState.cc:2027
Class to define the vertex input layout.
bool operator==(const VertexDeclaration &_other) const
int strideUserDefined_
Flag that indicates, whether the stride was set by user or derived automatically.
int findElementIdByUsage(VERTEX_USAGE _usage) const
void addElement(const VertexElement *_pElement)
static size_t getGLTypeSize(unsigned int _type)
void setVertexStride(unsigned int _stride)
unsigned int getNumElements() const
unsigned int vertexStride_
Offset in bytes between each vertex.
void updateShaderInputName(VertexElement *_pElem)
void deactivateShaderPipeline(GLSL::Program *_prog) const
unsigned int getVertexStride(unsigned int i=0) const
static size_t getElementSize(const VertexElement *_pElement)
const VertexElement * getElement(unsigned int i) const
std::map< unsigned int, unsigned int > vertexStridesVBO_
Map vbo to offset in bytes between each vertex in that vbo.
static bool supportsInstancedArrays()
const VertexElement * findElementByUsage(VERTEX_USAGE _usage) const
void activateShaderPipeline(GLSL::Program *_prog) const
void addElements(unsigned int _numElements, const VertexElement *_pElements)
GLSL program class.
int getAttributeLocation(const char *_name)
Get location of the specified attribute.
Namespace providing different geometric functions concerning angles.
bool ACGDLLEXPORT openGLVersionTest(const int _major, const int _minor)
Definition gl.hh:275
bool checkExtensionSupported(const std::string &_extension)
Definition gl.cc:107
bool openGLVersion(const int _major, const int _minor, bool _verbose)
Definition gl.cc:129
VERTEX_USAGE
-— input name in vertex shader ----—
@ VERTEX_USAGE_NORMAL
"inNormal"
@ VERTEX_USAGE_COLOR
"inColor"
@ VERTEX_USAGE_POSITION
"inPosition"
@ VERTEX_USAGE_BLENDWEIGHTS
"inBlendWeights"
@ VERTEX_USAGE_BLENDINDICES
"inBlendIndices"
@ VERTEX_USAGE_TEXCOORD
"inTexCoord"
@ VERTEX_USAGE_SHADER_INPUT
defined by user via VertexElement::shaderInputName_
Description of one vertex element.
unsigned int divisor_
For instanced rendering: Step rate describing how many instances are drawn before advancing to the ne...
unsigned int numElements_
how many elements of type_
const void * pointer_
Offset in bytes to the first occurrence of this element in vertex buffer; Or address to vertex data i...
unsigned int vbo_
Explicit vbo source of this element, set to 0 if the buffer bound at the time of activating the decla...
VERTEX_USAGE usage_
position, normal, shader input ..
unsigned int type_
GL_FLOAT, GL_UNSIGNED_BYTE, GL_INT, ...
const char * shaderInputName_
set shader input name, if usage_ = VERTEX_USAGE_USER_DEFINED otherwise this is set automatically,...