current revision
This commit is contained in:
222
ui/map/3D/FloorRenderer.h
Normal file
222
ui/map/3D/FloorRenderer.h
Normal file
@@ -0,0 +1,222 @@
|
||||
#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
|
||||
Reference in New Issue
Block a user