#ifndef MV3DELEMENTFLOOROUTLINE_H #define MV3DELEMENTFLOOROUTLINE_H #include #include "misc/Cube.h" #include "MV3DElement.h" #include "../../lib/gpc/gpc.h" #include "misc/Polygon.h" #include "misc/Shader.h" class MV3DElementFloorOutline : public MV3DElement { Floorplan::Floor* f; Floorplan::FloorOutline* out; struct ToRender { Point2 cacheSum; Polygon* pol = nullptr; std::vector> trias; }; std::unordered_map elements; public: /** ctor */ MV3DElementFloorOutline(Floorplan::Floor* f, Floorplan::FloorOutline* out) : f(f), out(out) { ; } protected: /** repaint me */ void render(const RenderSettings& rs) override { rebuildIfNeeded(); rs.shader->bind(); glDisable(GL_CULL_FACE); QMatrix4x4 mat; rs.shader->setModelMatrix(mat); for (auto& it : elements) { //Polygon& pol = it.second->pol; std::vector>& trias = it.second->trias; if (it.first == "outdoor") { rs.shader->setColor(0.0, 0.5, 0.0); } else { rs.shader->setColor(0.2, 0.2, 0.2); } std::vector values; std::vector normals; for (const std::vector& tria : trias) { for (int i = 2; i < tria.size(); ++i) { const Point3 p1 = tria[i-2]; const Point3 p2 = tria[i-1]; const Point3 p3 = tria[i-0]; values.push_back(p1.x); values.push_back(p1.y); values.push_back(p1.z); values.push_back(p2.x); values.push_back(p2.y); values.push_back(p2.z); values.push_back(p3.x); values.push_back(p3.y); values.push_back(p3.z); normals.push_back(0); normals.push_back(1); normals.push_back(0); normals.push_back(0); normals.push_back(1); normals.push_back(0); normals.push_back(0); normals.push_back(1); normals.push_back(0); } } rs.shader->setVertices(values.data()); rs.shader->setNormals(normals.data()); glDrawArrays(GL_TRIANGLES, 0, values.size() / 3); rs.shader->unsetVertices(); rs.shader->unsetNormals(); /* TODO_GL if (it.first == "outdoor") { glColor3f(0.0, 0.5, 0.0); } else { glColor3f(0.2, 0.2, 0.2); } glDisable(GL_CULL_FACE); for (const std::vector& tria : trias) { glNormal3f(0, 1, 0); glBegin(GL_TRIANGLE_STRIP); for (const Point3& p3 : tria) { glVertex3f(p3.x, p3.z, p3.y); } glEnd(); } glEnable(GL_CULL_FACE); */ } glEnable(GL_CULL_FACE); rs.shader->release(); } void rebuildIfNeeded() { auto filterIndoor = [] (const Floorplan::FloorOutlinePolygon* p) {return p->outdoor == false;}; auto filterOutdoor = [] (const Floorplan::FloorOutlinePolygon* p) {return p->outdoor == true;}; if (elements.empty()) { elements["indoor"] = new ToRender(); elements["outdoor"] = new ToRender(); } rebuildIfNeeded(filterIndoor, elements["indoor"]); rebuildIfNeeded(filterOutdoor, elements["outdoor"]); } template void rebuildIfNeeded(Filter include, ToRender* dst) { const std::vector& polys = *out; // get number of points for rebuild-check Point2 cacheSum(0,0); for (Floorplan::FloorOutlinePolygon* poly : polys) { if (!include(poly)) {continue;} for (Point2 pt : poly->poly.points) { cacheSum += pt; } } // already up to date? if (cacheSum == dst->cacheSum) {return;} dst->cacheSum = cacheSum; // rebuild std::vector add; std::vector rem; if (dst->pol) {delete dst->pol;} dst->pol = new Polygon(); for (Floorplan::FloorOutlinePolygon* poly : polys) { if (!include(poly)) {continue;} switch (poly->method) { case Floorplan::OutlineMethod::ADD: dst->pol->add(poly->poly); break; case Floorplan::OutlineMethod::REMOVE: dst->pol->remove(poly->poly); break; default: throw 1; } } dst->trias = dst->pol->get(f->atHeight); } bool isTransparent() const override { return false; } }; #endif // MV3DELEMENTFLOOROUTLINE_H