File GLObject.cpp¶
File List > AIAC > Render > GLObject.cpp
Go to the documentation of this file
#include "GLObject.h"
namespace AIAC
{
static const float WEIGHT_TO_CYLINDER_RADIUS_RATE = 1.0f / 64.0f;
// GLObject
void GLObject::BindVBOs(){
#ifndef HEADLESS_TEST
glBindBuffer(GL_ARRAY_BUFFER, vertexBuf);
glEnableVertexAttribArray(0);
glVertexAttribPointer(
0, // attribute 0. No particular reason for 0, but must match the layout in the shader.
3, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(GLvoid *) 0 // array buffer offset
);
glBindBuffer(GL_ARRAY_BUFFER, colorBuf);
glEnableVertexAttribArray(1);
glVertexAttribPointer(
1, // attribute 1. No particular reason for 0, but must match the layout in the shader.
4, // size
GL_FLOAT, // type
GL_FALSE, // normalized?
0, // stride
(GLvoid *) 0 // array buffer offset
);
#endif
}
void GLObject::BufferData(const std::vector<glm::vec3> &vertices, const std::vector<glm::vec4> &colors) {
#ifndef HEADLESS_TEST
glGenBuffers(1, &this->vertexBuf);
glBindBuffer(GL_ARRAY_BUFFER, this->vertexBuf);
glBufferData(GL_ARRAY_BUFFER, sizeof(vertices) * sizeof(glm::vec3), &vertices[0], GL_STATIC_DRAW);
glGenBuffers(1, &this->colorBuf);
glBindBuffer(GL_ARRAY_BUFFER, this->colorBuf);
glBufferData(GL_ARRAY_BUFFER, sizeof(colors) * sizeof(glm::vec4), &colors[0], GL_STATIC_DRAW);
#endif
}
void GLObject::DeleteVBOs() {
#ifndef HEADLESS_TEST
glDeleteBuffers(1, &vertexBuf);
glDeleteBuffers(1, &colorBuf);
#endif
}
// ----------------- //
// GLPointObject //
// ----------------- //
GLPointObject::GLPointObject(const std::vector<glm::vec3> &vertices, const std::vector<glm::vec4> &colors, GLfloat pointSize) {
this->type = GLObjectType::POINTS;
this->size = int(vertices.size());
this->pointSize = pointSize;
GLObject::BufferData(vertices, colors);
}
void GLPointObject::Draw()
{
BindVBOs();
GLfloat prevPointSize;
glGetFloatv(GL_POINT_SIZE, &prevPointSize);
glPointSize(this->pointSize);
glDrawArrays(GL_POINTS, 0, this->size);
glPointSize(prevPointSize);
}
// ----------------- //
// GLLineObject //
// ----------------- //
GLLineObject::GLLineObject(const std::vector<glm::vec3> &vertices, const std::vector<glm::vec4> &colors, GLfloat lineWidth) {
this->type = GLObjectType::LINES;
this->size = vertices.size();
this->lineWidth = lineWidth;
GLObject::BufferData(vertices, colors);
}
void GLLineObject::Draw()
{
BindVBOs();
GLfloat prevLineWidth;
glGetFloatv(GL_LINE_WIDTH, &prevLineWidth);
glLineWidth(lineWidth);
glDrawArrays(GL_LINES, 0, size);
glLineWidth(prevLineWidth);
}
// -------------------- //
// GLMeshObject //
// -------------------- //
GLMeshObject::GLMeshObject(const std::vector<glm::vec3> &vertices, const std::vector<glm::vec4> &colors, const std::vector<uint32_t> &indices) {
this->type = GLObjectType::TRIANGLES;
this->size = indices.size();
this->m_Indices = indices;
this->m_Vertices = vertices;
this->m_Colors = colors;
#ifndef HEADLESS_TEST
glGenBuffers(1, &this->indexBuf);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->indexBuf);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices.size() * sizeof(uint32_t), &indices[0], GL_STATIC_DRAW);
GLObject::BufferData(vertices, colors);
#endif
}
void GLMeshObject::Draw()
{
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, this->indexBuf);
BindVBOs();
glDrawElements(GL_TRIANGLES, this->m_Indices.size(), GL_UNSIGNED_INT, nullptr);
}
// ---------------------- //
// Auxilary functions //
// ---------------------- //
struct CylinderPole {
GLfloat x, z;
};
int GetSectorNum(float radius)
{
// TODO: there is a bug if sector number > 8, now we just set it to 8
// if(radius <= 3){
// return 8;
// }
// if(radius <= 12){
// return 16;
// }
// if(radius <= 24){
// return 24;
// }
return 8;
}
glm::vec3 GetTransformed(glm::mat4 transformMat, float x, float y, float z)
{
glm::vec4 point(x, y, z, 1);
point = transformMat * point;
return {point.x, point.y, point.z};
}
std::vector< std::shared_ptr<GLObject> > CreateCylinder(const glm::vec3 &baseCenter, const glm::vec3 &topCenter, GLfloat radius, glm::vec4 color, glm::vec4 edgeColor, int sectorNum){
// if(sectorNum == -1){
sectorNum = GetSectorNum(radius);
// }
std::vector<CylinderPole> cylinderPoles; // vector of structs
glm::vec3 x1 = baseCenter, x2 = topCenter;
glm::vec3 norm = glm::normalize(x2 - x1);
GLfloat h = glm::length(x2 - x1);
glm::vec3 newX = glm::normalize(glm::cross(norm, glm::vec3(0, 1, 0)));
glm::vec3 newZ = glm::normalize(glm::cross(newX, norm));
glm::mat4 transformMat;
transformMat[0] = glm::vec4(newX, 0);
transformMat[1] = glm::vec4(norm, 0);
transformMat[2] = glm::vec4(newZ, 0);
transformMat[3] = glm::vec4(x1, 1);
for (int i = 0; i < sectorNum; ++i){
GLfloat u = (GLfloat)i / (GLfloat)sectorNum;
CylinderPole cp{
.x = static_cast<GLfloat>(radius * cos(2 * M_PI * u)),
.z = static_cast<GLfloat>(radius * sin(2 * M_PI * u)),
};
cylinderPoles.push_back(cp);
}
std::vector<uint32_t> flattenedIndices;
std::vector<glm::vec3> indices;
std::vector<glm::vec3> vertices;
std::vector<glm::vec3> capContourTop, capContourBase;
vertices.emplace_back(x1); // 0
vertices.emplace_back(x2); // 1
vertices.emplace_back(GetTransformed(transformMat, cylinderPoles[0].x, 0, cylinderPoles[0].z)); // 2
vertices.emplace_back(GetTransformed(transformMat, cylinderPoles[0].x, h, cylinderPoles[0].z)); // 3
capContourBase.push_back(GetTransformed(transformMat, cylinderPoles[0].x, 0, cylinderPoles[0].z));
capContourTop.push_back(GetTransformed(transformMat, cylinderPoles[0].x, h, cylinderPoles[0].z));
int baseCenterIdx = 0;
int topCenterIdx = 1;
int prevBaseVertexIdx = 2;
int prevTopVertexIdx = 3;
int curBaseVertexIdx = 4;
int curTopVertexIdx = 5;
for(int i = 1; i < sectorNum; i++){
capContourBase.emplace_back(GetTransformed(transformMat, cylinderPoles[i].x, 0, cylinderPoles[i].z));
capContourBase.emplace_back(GetTransformed(transformMat, cylinderPoles[i].x, 0, cylinderPoles[i].z));
capContourTop.emplace_back(GetTransformed(transformMat, cylinderPoles[i].x, h, cylinderPoles[i].z));
capContourTop.emplace_back(GetTransformed(transformMat, cylinderPoles[i].x, h, cylinderPoles[i].z));
vertices.emplace_back(GetTransformed(transformMat, cylinderPoles[i].x, 0, cylinderPoles[i].z));
vertices.emplace_back(GetTransformed(transformMat, cylinderPoles[i].x, h, cylinderPoles[i].z));
indices.emplace_back(curBaseVertexIdx ,baseCenterIdx , prevBaseVertexIdx);
indices.emplace_back(prevTopVertexIdx ,topCenterIdx , curTopVertexIdx );
indices.emplace_back(curBaseVertexIdx ,curTopVertexIdx , prevTopVertexIdx );
indices.emplace_back(prevBaseVertexIdx,curBaseVertexIdx, prevTopVertexIdx );
prevBaseVertexIdx = curBaseVertexIdx;
prevTopVertexIdx = curTopVertexIdx;
curBaseVertexIdx += 2;
curTopVertexIdx += 2;
}
// Last one
curBaseVertexIdx = 2;
curTopVertexIdx = 3;
indices.emplace_back(curBaseVertexIdx ,baseCenterIdx , prevBaseVertexIdx);
indices.emplace_back(prevTopVertexIdx ,topCenterIdx , curTopVertexIdx );
indices.emplace_back(curBaseVertexIdx ,curTopVertexIdx , prevTopVertexIdx );
indices.emplace_back(prevBaseVertexIdx,curBaseVertexIdx, prevTopVertexIdx );
capContourBase.emplace_back(GetTransformed(transformMat, cylinderPoles[0].x, 0, cylinderPoles[0].z));
capContourTop.emplace_back(GetTransformed(transformMat, cylinderPoles[0].x, h, cylinderPoles[0].z));
int counter = 0;
for(auto vid: indices){
flattenedIndices.push_back((uint)vid.x);
flattenedIndices.push_back((uint)vid.y);
flattenedIndices.push_back((uint)vid.z);
}
std::vector<glm::vec4> cylinderColorVec(vertices.size(), color);
std::vector<glm::vec4> edgeColorVec(vertices.size(), edgeColor);
std::vector<std::shared_ptr<GLObject>> glObjs;
glObjs.push_back(std::make_shared<GLMeshObject>(vertices, cylinderColorVec, flattenedIndices));
glObjs.push_back(std::make_shared<GLLineObject>(capContourBase, edgeColorVec, 1.0f));
glObjs.push_back(std::make_shared<GLLineObject>(capContourTop, edgeColorVec, 1.0f));
return glObjs;
}
std::vector< std::shared_ptr<GLObject> > CreateCircle(glm::vec3 center, glm::vec3 normal, float radius, glm::vec4 color, glm::vec4 edgeColor, float edgeWeight, int sectorNum){
if(sectorNum == -1){
sectorNum = GetSectorNum(radius);
}
std::vector<glm::vec3> vertices; // vertices.reserve(sectorNum);
std::vector<glm::vec3> edges; // edges.reserve(2 * sectorNum);
std::vector<uint32_t> indices; // indices.reserve(3 * sectorNum);
vertices.emplace_back(center);
// Rodrigues' rotation formula ?
glm::vec3 newX = glm::normalize(glm::cross(normal, glm::vec3(0, 1, 0)));
glm::vec3 newZ = glm::normalize(glm::cross(newX, normal));
glm::mat4 transformMat;
transformMat[0] = glm::vec4(newX, 0);
transformMat[1] = glm::vec4(normal, 0);
transformMat[2] = glm::vec4(newZ, 0);
transformMat[3] = glm::vec4(center, 1);
for (int i = 0; i < sectorNum; ++i){
GLfloat u = (GLfloat)i / (GLfloat)sectorNum;
glm::vec3 vertex = transformMat * glm::vec4(
static_cast<GLfloat>(radius * cos(2 * M_PI * u)),
0,
static_cast<GLfloat>(radius * sin(2 * M_PI * u)),
1
);
vertices.emplace_back(vertex);
}
for (int i = 1; i < sectorNum; ++i){
indices.emplace_back(0);
indices.emplace_back(i);
indices.emplace_back(i + 1);
}
indices.emplace_back(0);
indices.emplace_back(sectorNum);
indices.emplace_back(1);
for (int i = 1; i < sectorNum; ++i){
edges.emplace_back(vertices[i]);
edges.emplace_back(vertices[i + 1]);
}
edges.emplace_back(vertices[sectorNum]);
edges.emplace_back(vertices[1]);
std::vector<glm::vec4> faceColorVec(vertices.size(), color);
std::vector<glm::vec4> edgeColorVec(vertices.size(), edgeColor);
// auto faceObj = std::make_shared<GLMeshObject>(vertices, faceColorVec, indices);
auto edgeObj = std::make_shared<GLLineObject>(edges, edgeColorVec, edgeWeight);
std::vector< std::shared_ptr<GLObject>> glObjs;
glObjs.push_back(edgeObj);
return glObjs;
}
std::vector< std::shared_ptr<GLObject> > CreatePolyline(std::vector<glm::vec3> vertices, bool isClosed, glm::vec4 color, float lineWidth){
// TODO: dealing with lineWidth > 1.0
auto glObjs = std::vector< std::shared_ptr<GLObject> >();
if(vertices.size() < 2){
return glObjs;
}
if(lineWidth <= 1.0f){
std::vector<glm::vec3> lineObjVertices; lineObjVertices.reserve(vertices.size() * 2);
lineObjVertices.emplace_back(vertices[0]);
for (int i = 1; i < vertices.size() - 1; i++) {
lineObjVertices.emplace_back(vertices[i]);
lineObjVertices.emplace_back(vertices[i]);
}
lineObjVertices.emplace_back(vertices[vertices.size() - 1]);
if(isClosed){
lineObjVertices.emplace_back(vertices[vertices.size() - 1]);
lineObjVertices.emplace_back(vertices[0]);
}
std::vector<glm::vec4> colors(lineObjVertices.size(), color);
glObjs.emplace_back(std::make_shared<GLLineObject>(lineObjVertices, colors, lineWidth));
} else {
auto radius = WEIGHT_TO_CYLINDER_RADIUS_RATE * lineWidth;
for(int i = 1; i < vertices.size(); i++){
auto cylinderLine = CreateCylinder(vertices[i - 1], vertices[i], radius, color, color);
glObjs.insert(glObjs.end(), cylinderLine.begin(), cylinderLine.end());
}
if(isClosed){
auto cylinderLine = CreateCylinder(vertices[vertices.size() - 1], vertices[0], radius, color, color);
glObjs.insert(glObjs.end(), cylinderLine.begin(), cylinderLine.end());
}
}
return glObjs;
}
} // namespace AIAC