224 lines
5.4 KiB
C++
224 lines
5.4 KiB
C++
#ifndef GLTRIANGLES_H
|
|
#define GLTRIANGLES_H
|
|
|
|
#include <QOpenGLFunctions>
|
|
#include "GL.h"
|
|
#include "GLHelper.h"
|
|
|
|
#include <type_traits>
|
|
#include <Indoor/geo/Point3.h>
|
|
|
|
template <typename T> class GLTriangles : protected QOpenGLFunctions {
|
|
|
|
private:
|
|
|
|
QOpenGLBuffer arrayBuf;
|
|
QOpenGLBuffer indexBuf;
|
|
QOpenGLTexture* textures[4];
|
|
|
|
std::vector<T> vertices;
|
|
std::vector<GLuint> indices;
|
|
|
|
public:
|
|
|
|
/** ctor */
|
|
GLTriangles() : arrayBuf(QOpenGLBuffer::VertexBuffer), indexBuf(QOpenGLBuffer::IndexBuffer), textures() {
|
|
;
|
|
}
|
|
|
|
/** dtor */
|
|
~GLTriangles() {
|
|
|
|
arrayBuf.destroy();
|
|
indexBuf.destroy();
|
|
|
|
for (int i = 0; i < 4; ++i) {delete textures[i];}
|
|
|
|
}
|
|
|
|
/** set the to-be-used texture */
|
|
void setTexture(const int slot, const QString& textureFile) {
|
|
|
|
const QImage img(textureFile);
|
|
if (img.width() <= 0) {throw "error";}
|
|
|
|
QOpenGLTexture* texture = new QOpenGLTexture(img);
|
|
texture->setMinificationFilter(QOpenGLTexture::Linear);
|
|
texture->setMagnificationFilter(QOpenGLTexture::Linear);
|
|
texture->setWrapMode(QOpenGLTexture::Repeat);
|
|
texture->generateMipMaps();
|
|
textures[slot] = texture;
|
|
|
|
}
|
|
|
|
void setDiffuse(const QString& textureFile) {
|
|
setTexture(0, textureFile);
|
|
}
|
|
|
|
void setNormalMap(const QString& textureFile) {
|
|
setTexture(1, textureFile);
|
|
}
|
|
|
|
/** add a new face to this element */
|
|
void addFace(const T& vnt1, const T& vnt2, const T& vnt3) {
|
|
addFace(vnt1, vnt2, vnt3, 0);
|
|
}
|
|
|
|
/** add a new face to this element */
|
|
void addFaceCCW(const T& vnt1, const T& vnt2, const T& vnt3) {
|
|
addFace(vnt1, vnt2, vnt3, 1);
|
|
}
|
|
|
|
/** add a new face to this element */
|
|
void addFaceCW(const T& vnt1, const T& vnt2, const T& vnt3) {
|
|
addFace(vnt1, vnt2, vnt3, 2);
|
|
}
|
|
|
|
/** add a new quad to this element */
|
|
void addQuadCCW(const T& vnt1, const T& vnt2, const T& vnt3, const T& vnt4) {
|
|
addFace(vnt1, vnt2, vnt3, 1);
|
|
addFace(vnt3, vnt4, vnt1, 1);
|
|
}
|
|
|
|
/** add a new quad to this element */
|
|
void addQuadCW(const T& vnt1, const T& vnt2, const T& vnt3, const T& vnt4) {
|
|
addFace(vnt1, vnt2, vnt3, 2);
|
|
addFace(vnt3, vnt4, vnt1, 2);
|
|
}
|
|
|
|
/** add a new quad to this element */
|
|
void addQuad(const T& vnt1, const T& vnt2, const T& vnt3, const T& vnt4) {
|
|
addFace(vnt1, vnt2, vnt3, 0);
|
|
addFace(vnt3, vnt4, vnt1, 0);
|
|
}
|
|
|
|
/** build the underlying buffers */
|
|
void build() {
|
|
|
|
initializeOpenGLFunctions();
|
|
|
|
// Transfer vertex data to VBO 0
|
|
arrayBuf.create();
|
|
arrayBuf.bind();
|
|
arrayBuf.allocate(vertices.data(), vertices.size() * sizeof(vertices[0]));
|
|
|
|
// Transfer index data to VBO 1
|
|
indexBuf.create();
|
|
indexBuf.bind();
|
|
indexBuf.allocate(indices.data(), indices.size() * sizeof(indices[0]));
|
|
|
|
}
|
|
|
|
void rebuild() {
|
|
if (indexBuf.isCreated()) {indexBuf.destroy();}
|
|
if (arrayBuf.isCreated()) {arrayBuf.destroy();}
|
|
build();
|
|
}
|
|
|
|
void clear() {
|
|
indices.clear();
|
|
vertices.clear();
|
|
}
|
|
|
|
/** render the element */
|
|
void render(QOpenGLShaderProgram* program) {
|
|
|
|
// nothing to-do?
|
|
if (indices.empty()) {return;}
|
|
|
|
// Tell OpenGL which VBOs to use
|
|
arrayBuf.bind();
|
|
indexBuf.bind();
|
|
|
|
for (int i = 0; i < 4; ++i) {
|
|
if (textures[i]) { textures[i]->bind(i); }
|
|
}
|
|
|
|
// vertices
|
|
int vertLoc = program->attributeLocation("a_position");
|
|
program->enableAttributeArray(vertLoc);
|
|
program->setAttributeBuffer(vertLoc, GL_FLOAT, vertices[0].getVertOffset(), 3, sizeof(vertices[0]));
|
|
|
|
// Tell OpenGL programmable pipeline how to locate vertex texture coordinate data
|
|
if (T::hasNormal()) {
|
|
int normLoc = program->attributeLocation("a_normal");
|
|
program->enableAttributeArray(normLoc);
|
|
program->setAttributeBuffer(normLoc, GL_FLOAT, vertices[0].getNormOffset(), 3, sizeof(vertices[0]));
|
|
}
|
|
|
|
if (T::hasTexCoord()) {
|
|
int texcoordLocation = program->attributeLocation("a_texcoord");
|
|
program->enableAttributeArray(texcoordLocation);
|
|
program->setAttributeBuffer(texcoordLocation, GL_FLOAT, vertices[0].getTexOffset(), 2, sizeof(vertices[0]));
|
|
}
|
|
|
|
// bind tangent data?
|
|
if (T::hasTangent()) {
|
|
int tanLocation = program->attributeLocation("a_tangent");
|
|
program->enableAttributeArray(tanLocation);
|
|
program->setAttributeBuffer(tanLocation, GL_FLOAT, vertices[0].getTanOffset(), 3, sizeof(vertices[0]));
|
|
}
|
|
|
|
// bind color data?
|
|
if (T::hasColor()) {
|
|
int colorLoc = program->attributeLocation("a_color");
|
|
program->enableAttributeArray(colorLoc);
|
|
program->setAttributeBuffer(colorLoc, GL_FLOAT, vertices[0].getColorOffset(), 3, sizeof(vertices[0]));
|
|
}
|
|
|
|
// texture
|
|
program->setUniformValue("texture", 0);
|
|
|
|
// Draw cube geometry using indices from VBO 1
|
|
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_INT, 0);
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
void addFace(const T& vnt1, const T& vnt2, const T& vnt3, const int mode) {
|
|
|
|
// add vertices (remove duplicates!)
|
|
const int i1 = addOnce(vnt1);
|
|
const int i2 = addOnce(vnt2);
|
|
const int i3 = addOnce(vnt3);
|
|
|
|
// get current orientation
|
|
const bool ccw = GLHelper::isCCW(vnt1.vert, vnt2.vert, vnt3.vert);
|
|
|
|
// create indices
|
|
if (mode == 0 || (mode == 1 && ccw) || (mode == 2 && !ccw) ) {
|
|
indices.push_back(i1);
|
|
indices.push_back(i2);
|
|
indices.push_back(i3);
|
|
} else {
|
|
indices.push_back(i3);
|
|
indices.push_back(i2);
|
|
indices.push_back(i1);
|
|
}
|
|
|
|
}
|
|
|
|
/** to conserve memory, avoid duplicate VNTs! */
|
|
int addOnce(const T& vnt) {
|
|
|
|
const auto it = std::find(vertices.begin(), vertices.end(), vnt);
|
|
|
|
if (it == vertices.end()) {
|
|
const int idx = vertices.size();
|
|
vertices.push_back(vnt);
|
|
return idx;
|
|
} else {
|
|
const int idx = it - vertices.begin();
|
|
return idx;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
};
|
|
|
|
#endif // GLTRIANGLES_H
|