#ifndef WALLS_H #define WALLS_H #include #include "../gl/GLHelper.h" #include "../gl/GLTriangles.h" #include "../gl/GLLines.h" #include "../Renderable.h" #include "../gl/Shader.h" class Walls : public Renderable { private: Floorplan::Floor* floor; GLTriangles triangles; GLLines outlines; bool outlineOnly = false; bool transparent = false; public: /** ctor */ Walls(Floorplan::Floor* floor) : floor(floor) { setOutlineOnly(false); } void initGL() override { build(); triangles.build(); triangles.setDiffuse(":/res/gl/tex/wall3.jpg"); triangles.setNormalMap(":/res/gl/tex/wall3_normal.jpg"); outlines.build(); } /** render the floor */ void _render(const RenderParams& params) override { // skip me? if (params.clipAboveHeight_m < floor->atHeight) {return;} if (transparent) { program.setUniformValue("alpha", 0.5f); glEnable(GL_BLEND); } else { program.setUniformValue("alpha", 1.0f); glDisable(GL_BLEND); } if (outlineOnly) { glLineWidth(1); outlines.render(&program); } else { triangles.render(&program); } glDisable(GL_BLEND); } /** render only the outline? */ void setOutlineOnly(const bool outline) override { this->outlineOnly = outline; if (outlineOnly) { loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentLine.glsl"); program.setUniformValue("color", QVector4D(0.9, 0.9, 0.9, 1.0)); } else { loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTex.glsl"); program.setUniformValue("texDiffuse", 0); program.setUniformValue("texNormalMap", 1); } } void setTransparent(const bool transparent) override { this->transparent = transparent; } private: void build() { for (Floorplan::FloorObstacle* obstacle : floor->obstacles) { if (dynamic_cast(obstacle)) { Floorplan::FloorObstacleLine* line = dynamic_cast(obstacle); if (line->type != Floorplan::ObstacleType::WALL) {continue;} addFace(line->from, line->to, floor->getStartingZ(), floor->getEndingZ()); } else if (dynamic_cast(obstacle)) { Floorplan::FloorObstacleDoor* door = dynamic_cast(obstacle); addFace(door->from, door->to, floor->getStartingZ() + door->height, floor->getEndingZ()); } } } void addFace(const Point2 from, const Point2 to, const float h1, const float h2) { const QVector3D vert1(from.x, h1, from.y); const QVector3D vert2(to.x, h1, to.y); const QVector3D vert3(to.x, h2, to.y); const QVector3D vert4(from.x, h2, from.y); const QVector3D n1 = GLHelper::getNormal(vert1, vert2, vert3); const QVector3D n2 = -n1; QVector3D tan = (vert1-vert2).normalized(); tan = GLHelper::isCCW(vert1, vert2, vert3) ? (tan) : (-tan); const float l = from.getDistance(to); const float h = h2-h1; const float o = std::min(from.length(), to.length()); const QVector2D tex1(o+0, h); // start texturing at the ceiling so above-door-sections and walls have the same textre const QVector2D tex2(o+l, h); const QVector2D tex3(o+l, 0); const QVector2D tex4(o+0, 0); const float s = 0.65; { const VertNormTexTan vnt1(vert1, n1, tex1*s, tan); const VertNormTexTan vnt2(vert2, n1, tex2*s, tan); const VertNormTexTan vnt3(vert3, n1, tex3*s, tan); const VertNormTexTan vnt4(vert4, n1, tex4*s, tan); triangles.addQuadCCW(vnt1, vnt2, vnt3, vnt4); } { const VertNormTexTan vnt1(vert1, n2, tex1*s, -tan); const VertNormTexTan vnt2(vert2, n2, tex2*s, -tan); const VertNormTexTan vnt3(vert3, n2, tex3*s, -tan); const VertNormTexTan vnt4(vert4, n2, tex4*s, -tan); triangles.addQuadCW(vnt1, vnt2, vnt3, vnt4); } outlines.addLine(vert1, vert2); outlines.addLine(vert2, vert3); outlines.addLine(vert3, vert4); outlines.addLine(vert4, vert1); } //private: // // QVector2D tex(const QVector3D vert) { // return QVector2D(vert.x(), vert.y()); // } }; #endif // WALLS_H