-
Notifications
You must be signed in to change notification settings - Fork 2
Expand file tree
/
Copy pathGLVertexArray.hpp
More file actions
98 lines (82 loc) · 3.23 KB
/
Copy pathGLVertexArray.hpp
File metadata and controls
98 lines (82 loc) · 3.23 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
#pragma once
/*
* GLVertexArray wraps an OpenGL Vertex Array Object.
* A vertex array object holds a mapping between attribute locations and buffers
* this includes information about the attribute format and layout.
*
* GLVertexArray is a thin wrapper that just provides the basic OpenGL calls.
* The "GLVertexArray::make_binding()" call provides a way to bind typed buffers
* to named program attributes.
*
*/
#include "gl.hpp"
#include "GLBuffer.hpp"
#include <iostream>
#include <set>
//GLVertexArray is a thin wrapper around a vertex array:
struct GLVertexArray {
GLuint array = 0;
GLVertexArray() { glGenVertexArrays(1, &array); }
~GLVertexArray() { if (array != 0) glDeleteVertexArrays(1, &array); }
GLVertexArray(GLVertexArray const &) = delete;
GLVertexArray(GLVertexArray &&from) { std::swap(array, from.array); }
GLVertexArray &operator=(GLVertexArray &&from) { std::swap(array, from.array); return *this; }
//"make_binding" creates a vertex array to bind attributes for a particular program:
static GLVertexArray make_binding(GLuint program,
std::initializer_list< std::pair< GLint, GLAttribPointer > > const &locations
) {
GLVertexArray ret;
glBindVertexArray(ret.array);
std::set< GLuint > bound;
for (auto const &lp : locations) {
if (lp.first == -1) {
if (lp.second.buffer != 0) {
std::cerr << "WARNING: trying to bind unused attribute." << std::endl;
}
} else {
bool duplicate = !bound.insert(lp.first).second;
assert(!duplicate); //shouldn't try to bind same attribute to two different things
if (lp.second.buffer == 0) {
throw std::runtime_error("Trying to bind undefined pointer to active attribute.");
}
glBindBuffer(GL_ARRAY_BUFFER, lp.second.buffer);
if (lp.second.interpretation == KIT_AS_INTEGER) {
glVertexAttribIPointer(lp.first, lp.second.size, lp.second.type, lp.second.stride, (GLbyte *)0 + lp.second.offset);
} else if (lp.second.interpretation == KIT_AS_DOUBLE) {
#ifndef _WIN32
glVertexAttribLPointer(lp.first, lp.second.size, lp.second.type, lp.second.stride, (GLbyte *)0 + lp.second.offset);
#else
assert(0 && "Need to add this to gl_shims");
#endif
} else {
glVertexAttribPointer(lp.first, lp.second.size, lp.second.type,
(lp.second.interpretation == KIT_NORMALIZED_AS_FLOAT ? GL_TRUE : GL_FALSE),
lp.second.stride, (GLbyte *)0 + lp.second.offset);
}
glEnableVertexAttribArray(lp.first);
glBindBuffer(GL_ARRAY_BUFFER, 0);
}
}
GLint active = 0;
glGetProgramiv(program, GL_ACTIVE_ATTRIBUTES, &active);
assert(active > 0); //all programs have at least one attribute.
bool unbound = false;
for (GLuint l = 0; l < (GLuint)active; ++l) {
GLchar name[100];
GLint size = 0;
GLenum type = 0;
glGetActiveAttrib(program, l, 100, NULL, &size, &type, name);
name[99] = '\0';
GLuint idx = glGetAttribLocation(program, name);
if (!bound.count(idx)) {
std::cerr << "ERROR: attribute '" << name << "' [" << idx << "] was not bound." << std::endl;
unbound = true;
} else {
//std::cerr << "INFO: attribute '" << name << "' was bound." << std::endl; //DEBUG
}
}
if (unbound) throw std::runtime_error("Incomplete binding.");
glBindVertexArray(0);
return ret;
}
};