223 lines
6.4 KiB
C++
223 lines
6.4 KiB
C++
#ifndef FLOORRENDERER_H
|
|
#define FLOORRENDERER_H
|
|
|
|
#include <QOpenGLFunctions>
|
|
#include <QOpenGLShaderProgram>
|
|
#include <QOpenGLBuffer>
|
|
#include <Indoor/floorplan/v2/Floorplan.h>
|
|
#include "GL.h"
|
|
|
|
|
|
class FloorRenderer : protected QOpenGLFunctions {
|
|
|
|
private:
|
|
|
|
Floorplan::Floor* floor;
|
|
|
|
QOpenGLBuffer arrayBuf;
|
|
QOpenGLBuffer indexBuf;
|
|
QOpenGLTexture* texture = nullptr;
|
|
|
|
std::vector<VertNormTex> vertices;
|
|
std::vector<GLushort> indices;
|
|
|
|
|
|
public:
|
|
|
|
/** ctor */
|
|
FloorRenderer(Floorplan::Floor* floor) : floor(floor), arrayBuf(QOpenGLBuffer::VertexBuffer), indexBuf(QOpenGLBuffer::IndexBuffer) {
|
|
;
|
|
}
|
|
|
|
/** dctor */
|
|
~FloorRenderer() {
|
|
arrayBuf.destroy();
|
|
indexBuf.destroy();
|
|
delete texture;
|
|
}
|
|
|
|
/** render the floor */
|
|
void render(QOpenGLShaderProgram *program) {
|
|
|
|
// Tell OpenGL which VBOs to use
|
|
arrayBuf.bind();
|
|
indexBuf.bind();
|
|
texture->bind();
|
|
|
|
// 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
|
|
int normLoc = program->attributeLocation("a_normal");
|
|
program->enableAttributeArray(normLoc);
|
|
program->setAttributeBuffer(normLoc, GL_FLOAT, vertices[0].getNormOffset(), 3, sizeof(vertices[0]));
|
|
|
|
int texcoordLocation = program->attributeLocation("a_texcoord");
|
|
program->enableAttributeArray(texcoordLocation);
|
|
program->setAttributeBuffer(texcoordLocation, GL_FLOAT, vertices[0].getTexOffset(), 2, sizeof(vertices[0]));
|
|
|
|
// texture
|
|
program->setUniformValue("texture", 0);
|
|
|
|
// Draw cube geometry using indices from VBO 1
|
|
glDrawElements(GL_QUADS, indices.size(), GL_UNSIGNED_SHORT, 0);
|
|
|
|
}
|
|
|
|
void initGL() {
|
|
initializeOpenGLFunctions();
|
|
build();
|
|
}
|
|
|
|
private:
|
|
|
|
void build() {
|
|
|
|
QImage img(":/res/gl/tex/wall1.jpg");
|
|
texture = new QOpenGLTexture(img);
|
|
texture->setMinificationFilter(QOpenGLTexture::Nearest);
|
|
texture->setMagnificationFilter(QOpenGLTexture::Linear);
|
|
texture->setWrapMode(QOpenGLTexture::Repeat);
|
|
|
|
// build array of vertices and indices
|
|
for (Floorplan::FloorObstacle* obstacle : floor->obstacles) {
|
|
add(floor, obstacle, vertices, indices);
|
|
}
|
|
|
|
// 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 add(Floorplan::Floor* floor, Floorplan::FloorObstacle* obstacle, std::vector<VertNormTex>& vertices, std::vector<GLushort>& indices) {
|
|
|
|
if (dynamic_cast<Floorplan::FloorObstacleLine*>(obstacle)) {
|
|
|
|
Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obstacle);
|
|
if (line->type != Floorplan::ObstacleType::WALL) {return;}
|
|
|
|
// QVector3D p1(line->from.x, floor->getStartingZ(), line->from.y);
|
|
// QVector3D p2(line->to.x, floor->getStartingZ(), line->to.y);
|
|
// QVector3D p3(line->to.x, floor->getEndingZ(), line->to.y);
|
|
// QVector3D p4(line->from.x, floor->getEndingZ(), line->from.y);
|
|
|
|
// addFace(p1,p2,p3,p4, vertices, indices);
|
|
|
|
|
|
addFace(line->from, line->to, floor->getStartingZ(), floor->getEndingZ(), vertices, indices);
|
|
addFace(line->to, line->from, floor->getStartingZ(), floor->getEndingZ(), vertices, indices);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
void addFace(const Point2 from, const Point2 to, const float h1, const float h2, std::vector<VertNormTex>& vertices, std::vector<GLushort>& indices) {
|
|
|
|
// unit-face with unit normal (facing the camera)
|
|
QVector3D p1(-0.5, -0.0, 0);
|
|
QVector3D p2(+0.5, -0.0, 0);
|
|
QVector3D p3(+0.5, +1.0, 0);
|
|
QVector3D p4(-0.5, +1.0, 0);
|
|
QVector3D norm(0, 0, 1);
|
|
|
|
// how to scale the unit-face to match the wall
|
|
const float h = h2-h1;
|
|
const float s = from.getDistance(to);
|
|
QMatrix4x4 scale; scale.scale(s, h, 1);
|
|
|
|
// how to rotate the unit-face to match the wall
|
|
const float angle = std::atan2(to.y - from.y, to.x - from.x);
|
|
const float deg = angle * 180 / M_PI;
|
|
QMatrix4x4 rot; rot.rotate(deg, QVector3D(0,1,0));
|
|
|
|
// how to translate the unit-face to match the wall
|
|
const Point2 center = (from + to) / 2;
|
|
QMatrix4x4 move; move.translate(center.x, h1, center.y);
|
|
|
|
// final matrix
|
|
QMatrix4x4 mat = move * rot * scale;
|
|
|
|
// texture coordinates (scale only)
|
|
const QVector2D tex1 = (scale * p1).toVector2D() / 5;
|
|
const QVector2D tex2 = (scale * p2).toVector2D() / 5;
|
|
const QVector2D tex3 = (scale * p3).toVector2D() / 5;
|
|
const QVector2D tex4 = (scale * p4).toVector2D() / 5;
|
|
|
|
// modify vertices
|
|
p1 = mat * p1;
|
|
p2 = mat * p2;
|
|
p3 = mat * p3;
|
|
p4 = mat * p4;
|
|
norm = (rot * norm).normalized();
|
|
|
|
const int start = vertices.size();
|
|
vertices.push_back(VertNormTex(p1, norm, tex1));
|
|
vertices.push_back(VertNormTex(p2, norm, tex2));
|
|
vertices.push_back(VertNormTex(p3, norm, tex3));
|
|
vertices.push_back(VertNormTex(p4, norm, tex4));
|
|
|
|
indices.push_back(start+0);
|
|
indices.push_back(start+1);
|
|
indices.push_back(start+2);
|
|
indices.push_back(start+3);
|
|
|
|
}
|
|
|
|
// void addFace(QVector3D p1, QVector3D p2, QVector3D p3, QVector3D p4, std::vector<VertNorm>& vertices, std::vector<GLushort>& indices) {
|
|
|
|
// const float s = 50;
|
|
|
|
// // ensure camera facing (for culling)
|
|
// if (p1.x() != p2.x()) {
|
|
// if (p1.x() > p2.x()) {std::swap(p1, p2), std::swap(p3, p4);}
|
|
// } else {
|
|
// if (p1.z() > p2.z()) {std::swap(p1, p2), std::swap(p3, p4);}
|
|
// }
|
|
|
|
// // corresponding normal vector
|
|
// QVector3D norm = QVector3D::crossProduct((p2-p1), (p3-p1)).normalized();
|
|
|
|
// // orient towards the viewport
|
|
// const QVector3D view(-99,-99,-99);
|
|
// if ((view-norm).length() > (view+norm).length()) {norm = -norm;}
|
|
|
|
|
|
// const int start = vertices.size();
|
|
|
|
// indices.push_back(start+0);
|
|
// indices.push_back(start+1);
|
|
// indices.push_back(start+2);
|
|
// indices.push_back(start+3);
|
|
|
|
// vertices.push_back(VertNorm(p1/s, norm));
|
|
// vertices.push_back(VertNorm(p2/s, norm));
|
|
// vertices.push_back(VertNorm(p3/s, norm));
|
|
// vertices.push_back(VertNorm(p4/s, norm));
|
|
|
|
// // and the other side (clockwise, negated normal)
|
|
|
|
// indices.push_back(start+0);
|
|
// indices.push_back(start+3);
|
|
// indices.push_back(start+2);
|
|
// indices.push_back(start+1);
|
|
|
|
// vertices.push_back(VertNorm(p1/s, -norm));
|
|
// vertices.push_back(VertNorm(p2/s, -norm));
|
|
// vertices.push_back(VertNorm(p3/s, -norm));
|
|
// vertices.push_back(VertNorm(p4/s, -norm));
|
|
|
|
// }
|
|
|
|
};
|
|
|
|
#endif // FLOORRENDERER_H
|