jubilant-funicular
PrimitiveBatch.cpp
1 #include <algorithm>
2 
3 #include "nta/PrimitiveBatch.h"
4 
5 namespace nta {
7  }
8  PrimitiveBatch::~PrimitiveBatch() {
9  if (m_vbo != 0) {
10  glDeleteBuffers(1, &m_vbo);
11  }
12  if (m_vao != 0) {
13  glDeleteVertexArrays(1, &m_vao);
14  }
15  for (int i = 0; i < m_primitives.size(); i++) {
16  delete m_primitives[i];
17  }
18  m_primitives.clear();
19  m_renderBatches.clear();
20  }
22  return m_primitives.size();
23  }
26  }
28  if (m_vbo == 0) {
29  glGenBuffers(1, &m_vbo);
30  }
31  if (m_vao == 0) {
32  glGenVertexArrays(1, &m_vao);
33  }
34  glBindVertexArray(m_vao);
35  glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
36  for (int i = 0; i < NUM_VERTEX_ATTRIBS; i++) {
37  auto& attrib = Vertex2D::attribs[i];
38 
39  glEnableVertexAttribArray(i);
40  glVertexAttribPointer(i, attrib.size, attrib.type, attrib.normalized, sizeof(Vertex2D),
41  attrib.pointer);
42  }
43  glBindVertexArray(0);
44  }
46  for (int i = 0; i < m_primitives.size(); i++) {
47  delete m_primitives[i];
48  }
49  m_primitives.clear();
50  m_renderBatches.clear();
51  }
55  }
57  // sort overall by depth
58  std::stable_sort(m_primitives.begin(), m_primitives.end(), compareDepth);
59  // sort same depth subsets by primitive
60  int begin = 0;
61  for (int i = 1; i < m_primitives.size(); i++) {
62  if (m_primitives[i]->depth != m_primitives[i-1]->depth) {
63  std::stable_sort(m_primitives.begin()+begin, m_primitives.begin()+i, comparePrimitive);
64  begin = i;
65  }
66  }
67  // sort same depth and primitive subsets by texture
68  begin = 0;
69  for (int i = 1; i < m_primitives.size(); i++) {
70  if (m_primitives[i]->depth != m_primitives[i-1]->depth ||
71  m_primitives[i]->vertices.size() != m_primitives[i-1]->vertices.size()) {
72  std::stable_sort(m_primitives.begin()+begin, m_primitives.begin()+i, compareTexture);
73  begin = i;
74  }
75  }
76  }
77  bool PrimitiveBatch::compareDepth(Primitive* lhs, Primitive* rhs) {
78  return (lhs->depth < rhs->depth);
79  }
81  return (lhs->textureID < rhs->textureID);
82  }
83  bool PrimitiveBatch::comparePrimitive(Primitive* lhs, Primitive* rhs) {
84  return (lhs->vertices.size() < rhs->vertices.size());
85  }
87  if (m_primitives.empty()) {
88  return;
89  }
90  int numVertices = 0; // total number of vertices
91  std::for_each(m_primitives.begin(), m_primitives.end(), [&numVertices](const Primitive* p) {
92  numVertices += p->vertices.size();
93  });
94 
95  std::vector<Vertex2D> vertexData(numVertices);
96  m_renderBatches.emplace_back(m_primitives[0]->textureID, 0, m_primitives[0]->vertices.size(),
97  toPrimitiveType(m_primitives[0]->vertices.size()));
98  int cv = 0; // current vertex
99  for (int i = 0; i < m_primitives[0]->vertices.size(); i++) {
100  vertexData[cv++] = m_primitives[0]->vertices[i];
101  }
102  int offset = m_primitives[0]->vertices.size();
103 
105  // some computers don't use GL_QUADS or GL_POLYGON
106  for (int cp = 1; cp < m_primitives.size(); cp++) { // current primitive
107  // Each primitive using GL_POLYGON needs to be its own
108  // batch in order to be rendered currectly
109  if (m_primitives[cp]->textureID != m_primitives[cp-1]->textureID ||
110  m_primitives[cp]->vertices.size() != m_primitives[cp-1]->vertices.size() ||
111  m_renderBatches.back().mode == GL_POLYGON) {
112  m_renderBatches.emplace_back(m_primitives[cp]->textureID, offset,
113  m_primitives[cp]->vertices.size(),
114  toPrimitiveType(m_primitives[cp]->vertices.size()));
115  } else {
116  m_renderBatches.back().numVertices += m_primitives[cp]->vertices.size();
117  }
118  for (int i = 0; i < m_primitives[cp]->vertices.size(); i++) {
119  vertexData[cv++] = m_primitives[cp]->vertices[i];
120  }
121  offset += m_primitives[cp]->vertices.size();
122  }
123  glBindBuffer(GL_ARRAY_BUFFER, m_vbo);
124  glBufferData(GL_ARRAY_BUFFER, vertexData.size()*sizeof(Vertex2D), nullptr, GL_DYNAMIC_DRAW);
125  glBufferSubData(GL_ARRAY_BUFFER, 0, vertexData.size()*sizeof(Vertex2D), vertexData.data());
126  glBindBuffer(GL_ARRAY_BUFFER, 0);
127  }
128  GLenum PrimitiveBatch::toPrimitiveType(unsigned int numVertices) const {
129  switch(numVertices) {
130  case 1: return GL_POINTS; break;
131  case 2: return GL_LINES; break;
132  case 3: return GL_TRIANGLES; break;
133  case 4: return GL_QUADS; break;
134  default: return GL_POLYGON; break;
135  }
136  }
138  m_primitives.push_back(primitive);
139  }
140  void PrimitiveBatch::addPrimitive(const std::initializer_list<Vertex2D>& vertices,
141  GLuint textureID, float depth) {
142  m_primitives.push_back(new Primitive(vertices, textureID, depth));
143  }
144  void PrimitiveBatch::addPrimitive(std::size_t numSides, crvec2 center, float sideLength,
145  crvec4 color, float orientation, float depth) {
146  m_primitives.push_back(new Primitive(numSides, center, sideLength, color, orientation, depth));
147  }
148  void PrimitiveBatch::render() const {
149  glBindVertexArray(m_vao);
150  for (int i = 0; i < m_renderBatches.size(); i++) {
151  glBindTexture(GL_TEXTURE_2D, m_renderBatches[i].textureID);
152  glDrawArrays(m_renderBatches[i].mode, m_renderBatches[i].offset,
153  m_renderBatches[i].numVertices);
154  }
155  glBindVertexArray(0);
156  }
157 }
nta::PrimitiveBatch::PrimitiveBatch
PrimitiveBatch()
constructor and destructor
Definition: PrimitiveBatch.cpp:6
nta::PrimitiveBatch::render
void render() const
renders the primitives
Definition: PrimitiveBatch.cpp:148
nta::PrimitiveBatch::createVertexArrayObject
void createVertexArrayObject()
creates vertex array object
Definition: PrimitiveBatch.cpp:27
nta::PrimitiveBatch::toPrimitiveType
GLenum toPrimitiveType(unsigned int numVertices) const
return primitive to be drawn
Definition: PrimitiveBatch.cpp:128
nta::Primitive::vertices
std::vector< Vertex2D > vertices
the vertices that make up the primitive
Definition: PrimitiveBatch.h:43
nta::PrimitiveBatch::createRenderBatches
void createRenderBatches()
creates render batches
Definition: PrimitiveBatch.cpp:86
nta::PrimitiveBatch::init
void init()
initializes the batch
Definition: PrimitiveBatch.cpp:24
nta::PrimitiveBatch::numPrimitives
int numPrimitives() const
returns number of primitives to be rendered
Definition: PrimitiveBatch.cpp:21
nta::PrimitiveBatch::begin
void begin()
begins collection of primitive
Definition: PrimitiveBatch.cpp:45
nta::PrimitiveBatch::m_primitives
std::vector< Primitive * > m_primitives
Definition: PrimitiveBatch.h:62
nta
Definition: Animation2D.h:6
nta::Primitive::textureID
GLuint textureID
the texture used by the primitive
Definition: PrimitiveBatch.h:41
nta::PrimitiveBatch::m_renderBatches
std::vector< RenderBatch > m_renderBatches
the render batches used to draw the primitives
Definition: PrimitiveBatch.h:64
nta::PrimitiveBatch::addPrimitive
void addPrimitive(Primitive *primitive)
adds a primitive to the batch
Definition: PrimitiveBatch.cpp:137
nta::Vertex2D
represents a vertex in 2 dimensions
Definition: Vertex.h:26
nta::PrimitiveBatch::compareTexture
static bool compareTexture(Primitive *lhs, Primitive *rhs)
comparers used for sorting
Definition: PrimitiveBatch.cpp:80
nta::PrimitiveBatch::end
void end()
ends collection of primitive and prepares for rendering
Definition: PrimitiveBatch.cpp:52
nta::Primitive
represents a primitive (point, line, triangle, etc.)
Definition: PrimitiveBatch.h:8
nta::PrimitiveBatch::m_vao
GLuint m_vao
ids for the vertex buffer object and vertex array object used for rendering
Definition: PrimitiveBatch.h:66
nta::PrimitiveBatch::sortPrimitives
void sortPrimitives()
sorts primitives
Definition: PrimitiveBatch.cpp:56
nta::Primitive::depth
float depth
the depth of the primitive
Definition: PrimitiveBatch.h:39