openGL work and other parts

This commit is contained in:
2016-09-11 12:11:54 +02:00
parent 69dfbe6693
commit d910e88220
43 changed files with 4813 additions and 261 deletions

101
map/elements/Doors.h Normal file
View File

@@ -0,0 +1,101 @@
#ifndef DOORS_H
#define DOORS_H
#include <Indoor/floorplan/v2/Floorplan.h>
#include "../gl/GLHelper.h"
#include "../gl/GLTriangles.h"
#include "../Renderable.h"
class Doors : public Renderable {
private:
Floorplan::Floor* floor;
GLTriangles<VertNormTexTan> doors;
public:
/** ctor */
Doors(Floorplan::Floor* floor) : floor(floor) {
;
}
void initGL() override {
build();
doors.setDiffuse(":/res/gl/tex/door2.jpg");
doors.setNormalMap(":/res/gl/tex/door2_normal.jpg");
doors.build();
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTex.glsl");
program.setUniformValue("texDiffuse", 0);
program.setUniformValue("texNormalMap", 1);
}
/** render the floor */
void _render() override {
doors.render(&program);
}
private:
void build() {
for (Floorplan::FloorObstacle* obstacle : floor->obstacles) {
if (dynamic_cast<Floorplan::FloorObstacleDoor*>(obstacle)) {
Floorplan::FloorObstacleDoor* door = dynamic_cast<Floorplan::FloorObstacleDoor*>(obstacle);
addFace(door->from, door->to, floor->getStartingZ(), floor->getStartingZ() + door->height, door->swap);
}
}
}
void addFace(const Point2 from, Point2 to, const float h1, const float h2, const bool swap) {
to = from + (to-from).rotated(60/180.0f*M_PI * ((swap)?(-1):(+1)) );
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 QVector2D tex1(0, 0);
const QVector2D tex2(1, 0);
const QVector2D tex3(1, 1);
const QVector2D tex4(0, 1);
{
const VertNormTexTan vnt1(vert1, n1, tex1, tan);
const VertNormTexTan vnt2(vert2, n1, tex2, tan);
const VertNormTexTan vnt3(vert3, n1, tex3, tan);
const VertNormTexTan vnt4(vert4, n1, tex4, tan);
doors.addQuadCCW(vnt1, vnt2, vnt3, vnt4);
} {
const VertNormTexTan vnt1(vert1, n2, tex1, -tan);
const VertNormTexTan vnt2(vert2, n2, tex2, -tan);
const VertNormTexTan vnt3(vert3, n2, tex3, -tan);
const VertNormTexTan vnt4(vert4, n2, tex4, -tan);
doors.addQuadCW(vnt1, vnt2, vnt3, vnt4);
}
}
};
#endif // DOORS_H

129
map/elements/Ground.h Normal file
View File

@@ -0,0 +1,129 @@
#ifndef GROUND_H
#define GROUND_H
#include <Indoor/floorplan/v2/Floorplan.h>
#include "../gl/GLHelper.h"
#include "../gl/GLTriangles.h"
#include "../Renderable.h"
#include "../../lib/gpc/Polygon.h"
class Ground : public Renderable {
private:
Floorplan::Floor* floor;
GLTriangles<VertNormTexTan> flooring;
GLTriangles<VertNormTexTan> ceiling;
public:
/** ctor */
Ground(Floorplan::Floor* floor) : floor(floor) {
;
}
void initGL() override {
build();
flooring.setDiffuse(":/res/gl/tex/floor4.jpg");
flooring.setNormalMap(":/res/gl/tex/floor4_normal.jpg");
ceiling.setDiffuse(":/res/gl/tex/floor4.jpg");
ceiling.setNormalMap(":/res/gl/tex/floor4_normal.jpg");
flooring.build();
ceiling.build();
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTex.glsl");
program.setUniformValue("texDiffuse", 0);
program.setUniformValue("texNormalMap", 1);
}
/** render the floor */
void _render() override {
flooring.render(&program);
ceiling.render(&program);
}
private:
void build() {
std::vector<gpc_polygon> add;
std::vector<gpc_polygon> rem;
const std::vector<Floorplan::FloorOutlinePolygon*>& polys = floor->outline;
Polygon pol;
for (Floorplan::FloorOutlinePolygon* poly : polys) {
switch (poly->method) {
case Floorplan::OutlineMethod::ADD: pol.add(poly->poly); break;
case Floorplan::OutlineMethod::REMOVE: pol.remove(poly->poly); break;
default: throw 1;
}
}
std::vector<std::vector<Point3>> trias = pol.get(floor->atHeight);
// is stored as TRIANGLE_STRIP
// => triangle might have more than 3 points
for (const std::vector<Point3>& tria : trias) {
const QVector3D normFloor(0, +1, 0);
const QVector3D normCeil(0, +1, 0); // why +1???
const QVector3D t(1,0,0);
const float s = 0.6;
// add vertices
for (int i = 2; i < (int) tria.size(); i+=1) {
const Point3 p1 = tria[i-2];
const Point3 p2 = tria[i-1];
const Point3 p3 = tria[i-0];
const QVector3D vert1(p1.x, p1.z, p1.y);
const QVector3D vert2(p2.x, p2.z, p2.y);
const QVector3D vert3(p3.x, p3.z, p3.y);
{
const VertNormTexTan vnt1(vert1, normFloor, tex(vert1*s), t);
const VertNormTexTan vnt2(vert2, normFloor, tex(vert2*s), t);
const VertNormTexTan vnt3(vert3, normFloor, tex(vert3*s), t);
flooring.addFaceCCW(vnt1, vnt2, vnt3);
} {
const VertNormTexTan vnt1(vert1, normCeil, tex(vert1*s), t);
const VertNormTexTan vnt2(vert2, normCeil, tex(vert2*s), t);
const VertNormTexTan vnt3(vert3, normCeil, tex(vert3*s), t);
ceiling.addFaceCW(vnt1, vnt2, vnt3);
}
}
}
}
private:
QVector2D tex(const QVector3D vert) {
return QVector2D(vert.x(), vert.z());
}
};
#endif // GROUND_H

89
map/elements/Handrails.h Normal file
View File

@@ -0,0 +1,89 @@
#ifndef HANDRAIL_H
#define HANDRAIL_H
#include <Indoor/floorplan/v2/Floorplan.h>
#include "../gl/GLHelper.h"
#include "../gl/GLLines.h"
#include "../Renderable.h"
class Handrails : public Renderable {
private:
Floorplan::Floor* floor;
GLLines lines;
public:
/** ctor */
Handrails(Floorplan::Floor* floor) : floor(floor) {
;
}
void initGL() override {
build();
lines.build();
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentLine.glsl");
program.setUniformValue("color", QVector4D(0.5, 0.5, 0.5, 1.0));
}
/** render the floor */
void _render() override {
glLineWidth(2);
lines.render(&program);
}
private:
void build() {
for (Floorplan::FloorObstacle* obstacle : floor->obstacles) {
if (dynamic_cast<Floorplan::FloorObstacleLine*>(obstacle)) {
Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obstacle);
if (line->type != Floorplan::ObstacleType::HANDRAIL) {continue;}
add(line->from, line->to, floor->getStartingZ());
}
}
}
void add(const Point2 from, const Point2 to, const float h1) {
// handrail height
const float h2 = h1 + 0.8;
const QVector3D v1(to.x, h2, to.y);
const QVector3D v2(from.x, h2, from.y);
// upper
lines.addLine(v1, v2);
const float stepSize = 0.5;
const float len = from.getDistance(to);
const float steps = std::round(len / stepSize);
for (int i = 0; i <= steps; ++i) {
const float percent = (float) i / (float) steps;
const Point2 pos = from + (to-from) * percent;
const QVector3D v1(pos.x, h1, pos.y);
const QVector3D v2(pos.x, h2, pos.y);
lines.addLine(v1, v2);
}
}
};
#endif // HANDRAIL_H

318
map/elements/Path.h Normal file
View File

@@ -0,0 +1,318 @@
#ifndef PATH_H
#define PATH_H
#include <Indoor/floorplan/v2/Floorplan.h>
#include <Indoor/nav/dijkstra/DijkstraPath.h>
#include "../gl/GLHelper.h"
#include "../gl/GLTriangles.h"
#include "../Renderable.h"
#include "../../lib/gpc/Polygon.h"
class Path : public Renderable {
private:
GLTriangles<VertNormTex> lines;
public:
/** ctor */
Path() {
;
}
void initGL() override {
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentLine.glsl");
program.setUniformValue("color", QVector4D(0.0, 0.4, 1.0, 0.6));
//loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTexSimple.glsl");
lines.setDiffuse(":/res/gl/tex/arrows.png");
program.setUniformValue("texNormalMap", 0);
}
/** render the floor */
void _render() override {
lines.rebuild();
glLineWidth(30);
glEnable(GL_BLEND);
glDisable(GL_CULL_FACE);
glBlendFunc (GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
lines.render(&program);
glDisable(GL_BLEND);
glEnable(GL_CULL_FACE);
}
template <typename Node> void set(const DijkstraPath<Node>& path) {
std::vector<Point3> out;
for (const DijkstraNode<Node>* node : path.getVector()) {
if (!node) {break;}
const Node* elem = node->element;
out.push_back(Point3(elem->x_cm/100.0f, elem->y_cm/100.0f, elem->z_cm/100.0f));
}
out = simplify(out);
set(out);
}
/*
void setSimple(const std::vector<Point3>& path) {
lines.clear();
const float s = 0.5;
Point3 lastDir(0,0,0);
std::vector<Floorplan::Quad3> quads;
for (int i = 1; i < (int) path.size(); ++i) {
Point3 pa = path[i-1];
Point3 pb = path[i-0];
const Point3 pc(0, 0, 1);
Point3 dir = pb - pa; dir /= dir.length();
Point3 perb = cross(pa-pb, pc); perb /= perb.length();
const Point3 p1 = pa - perb*s;
const Point3 p2 = pa + perb*s;
const Point3 p3 = pb + perb*s;
const Point3 p4 = pb - perb*s;
if (dir == lastDir) {
quads.back().p3 = p3;
quads.back().p4 = p4;
} else {
quads.push_back(Floorplan::Quad3(p1,p2,p3,p4));
}
lastDir = dir;
// // produce a small gap between path-lines [will be filled with another quad!]
// pa += dir * 0.6;
// pb -= dir * 0.6;
//
}
for (int i = 0; i < (int) quads.size(); ++i) {
// add the line-segment
const Floorplan::Quad3 q1 = quads[i];
addQuad(q1);
// // construct the quad between adjacent segments
// if (i < (int) quads.size() - 1) {
// const Floorplan::Quad3 q2 = quads[i+1];
// const Floorplan::Quad3 q3(q1.p3, q2.p2, q2.p1, q1.p4);
// addQuad(q3);
// }
}
}
*/
/** combine nodes while the direction stays the same (many small quads -> one large quad) */
std::vector<Point3> simplify(const std::vector<Point3>& path) {
std::vector<Point3> out;
Point3 lastDir(0,0,0);
if (!path.empty()) {
out.push_back(path.back());
}
for (int i = path.size() - 1; i >= 1; --i) {
const Point3 pa = path[i-0];
const Point3 pb = path[i-1];
const Point3 dir = (pb - pa).normalized();
if (dir == lastDir) {
out[out.size()-1] = pb;
} else {
out.push_back(pb);
}
lastDir = dir;
}
// remove unneccesary nodes
for (int i = 1; i < (int) out.size() - 1; ++i) {
const Point3 pa = out[i-1];
const Point3 pb = out[i-0];
const Point3 pc = out[i+1];
const float min = 0.6;
const float d1 = pb.getDistance(pa);
const float d2 = pb.getDistance(pc);
if (d1 < min || d2 < min) {
out.erase(out.begin() + i);
}
}
return out;
}
// void set(const std::vector<Point3>& path) {
// lines.clear();
// const float s = 0.4;
// std::vector<Point3> pts;
// for (int i = 0; i < (int) path.size(); ++i) {
// const Point3 pa = path[i-1];
// const Point3 pb = path[i-0];
// const Point3 pc(0, 0, 1);
// const Point3 perb = cross(pa-pb, pc).normalized();
// // quad's edges
// const Point3 p1 = pa - perb*s;
// const Point3 p2 = pa + perb*s;
// const Point3 p3 = pb + perb*s;
// const Point3 p4 = pb - perb*s;
// pts.push_back(p1);
// pts.push_back(p2);
// }
// std::vector<Floorplan::Quad3> quads;
// for (int i = 0; i < (int) pts.size(); i+=2) {
// quads.push_back(Floorplan::Quad3(pts[i+0], pts[i+1], pts[i+3], pts[i+2]));
// }
// float l1 = 0;
// float l2 = 0;
// for (int i = 0; i < (int) quads.size(); ++i) {
// // add the line-segment
// const Floorplan::Quad3 q1 = quads[i];
// l2 += ((q1.p1 + q1.p2) / 2).getDistance( (q1.p3 + q1.p4) / 2 );
// addQuad(q1, l1, l2);
// l1 = l2;
// }
// }
void set(const std::vector<Point3>& path) {
lines.clear();
// half the width of the path
const float s = 0.4;
std::vector<Floorplan::Quad3> quads;
for (int i = 1; i < (int) path.size(); ++i) {
Point3 pa = path[i-1];
Point3 pb = path[i-0];
const Point3 pc(0, 0, 1);
Point3 dir = (pb - pa).normalized();
// produce a small gap between path-segments
// those segments will be smoothly connected using another quad
pa += dir * 0.35;
pb -= dir * 0.35;
const Point3 perb = cross(pa-pb, pc).normalized();
// quad's edges
const Point3 p1 = pa - perb*s;
const Point3 p2 = pa + perb*s;
const Point3 p3 = pb + perb*s;
const Point3 p4 = pb - perb*s;
// add
quads.push_back(Floorplan::Quad3(p1,p2,p3,p4));
}
float l1 = 0;
float l2 = 0;
for (int i = 0; i < (int) quads.size(); ++i) {
// add the line-segment
const Floorplan::Quad3 q1 = quads[i];
l2 += ((q1.p1 + q1.p2) / 2).getDistance( (q1.p3 + q1.p4) / 2 );
addQuad(q1, l1, l2);
l1 = l2;
// done?
if (i == (int) quads.size() - 1) {break;}
// construct the quad between adjacent segments
const Floorplan::Quad3 q2 = quads[i+1];
const Floorplan::Quad3 q3(q1.p4, q1.p3, q2.p2, q2.p1);
l2 += ((q3.p1 + q3.p2) / 2).getDistance( (q3.p3 + q3.p4) / 2 );
addQuad(q3, l1, l2);
l1 = l2;
}
}
private:
void addQuad(const Floorplan::Quad3& q, const float l1, const float l2) {
// move the path upwards (slightly above the ground)
const float h = 0.40;
const QVector3D v1(q.p1.x, q.p1.z+h, q.p1.y);
const QVector3D v2(q.p2.x, q.p2.z+h, q.p2.y);
const QVector3D v3(q.p3.x, q.p3.z+h, q.p3.y);
const QVector3D v4(q.p4.x, q.p4.z+h, q.p4.y);
const QVector3D n(0,1,0);
const QVector2D tex1(0, l1);
const QVector2D tex2(1, l1);
const QVector2D tex3(1, l2);
const QVector2D tex4(0, l2);
// const QVector2D tex1(q.p1.x, q.p1.y);
// const QVector2D tex2(q.p2.x, q.p2.y);
// const QVector2D tex3(q.p3.x, q.p3.y);
// const QVector2D tex4(q.p4.x, q.p4.y);
const VertNormTex vnt1(v1, n, tex1);
const VertNormTex vnt2(v2, n, tex2);
const VertNormTex vnt3(v3, n, tex3);
const VertNormTex vnt4(v4, n, tex4);
lines.addQuadCCW(vnt1, vnt2, vnt3, vnt4);
}
};
#endif // PATH_H

151
map/elements/Stairs.h Normal file
View File

@@ -0,0 +1,151 @@
#ifndef STAIRS_H
#define STAIRS_H
#include <Indoor/floorplan/v2/Floorplan.h>
#include "../gl/GLHelper.h"
#include "../gl/GLTriangles.h"
#include "../Renderable.h"
class Stairs : public Renderable {
private:
Floorplan::Floor* floor;
GLTriangles<VertNormTex> parts;
public:
/** ctor */
Stairs(Floorplan::Floor* floor) : floor(floor) {
;
}
void initGL() override {
build();
parts.setDiffuse(":/res/gl/tex/granite1.jpg");
parts.setNormalMap(":/res/gl/tex/granite1_normal.jpg");
parts.build();
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTex.glsl");
program.setUniformValue("texDiffuse", 0);
program.setUniformValue("texNormalMap", 1);
}
/** render the floor */
void _render() override {
parts.render(&program);
}
private:
void build() {
for (Floorplan::Stair* stair : floor->stairs) {
if (dynamic_cast<Floorplan::Stair*>(stair)) {
Floorplan::StairFreeform* freeform = dynamic_cast<Floorplan::StairFreeform*>(stair);
add(Floorplan::getQuads(freeform->getParts(), floor));
}
}
}
void add(const std::vector<Floorplan::Quad3>& quads) {
for (const Floorplan::Quad3& quad : quads) {
//void addQuad(quad);
stepify(quad);
}
}
void stepify(const Floorplan::Quad3& quad) {
const float len = (quad.p4 - quad.p1).length();
const float stepLen = 0.3;
const int steps = std::round(len / stepLen);
for (int i = 0; i < steps; ++i) {
const float per1 = (float) (i+0) / (float) steps;
const float per2 = (float) (i+1) / (float) steps;
const Point3 p1 = quad.p1 + (quad.p4 - quad.p1) * per1;
const Point3 p2 = quad.p2 + (quad.p3 - quad.p2) * per1;
const Point3 p5 = quad.p2 + (quad.p3 - quad.p2) * per2;
const Point3 p6 = quad.p1 + (quad.p4 - quad.p1) * per2;
Point3 p3 = p5; p3.z = p2.z;
Point3 p4 = p6; p4.z = p1.z;
addQuad(Floorplan::Quad3(p1, p2, p3, p4));
addQuad(Floorplan::Quad3(p3, p4, p6, p5));
}
}
void addQuad(const Floorplan::Quad3& quad) {
const QVector3D vert1(quad.p1.x, quad.p1.z, quad.p1.y);
const QVector3D vert2(quad.p2.x, quad.p2.z, quad.p2.y);
const QVector3D vert3(quad.p3.x, quad.p3.z, quad.p3.y);
const QVector3D vert4(quad.p4.x, quad.p4.z, quad.p4.y);
const QVector3D n1 = GLHelper::getNormal(vert1, vert2, vert3);
const QVector3D n2 = -n1;
// const float o =
// const QVector2D tex1(quad.p1.length(), quad.p1.y);
// const QVector2D tex2(quad.p2.x, quad.p2.y+quad.p2.z);
// const QVector2D tex3(quad.p3.x, quad.p3.y+quad.p3.z);
// const QVector2D tex4(quad.p4.x, quad.p4.y+quad.p4.z);
const float h = quad.p4.getDistance(quad.p1);
const float l = quad.p1.getDistance(quad.p2);
const float o = quad.p1.length();
const float s = 1.1; // 0.5;
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 VertNormTex vnt1(vert1, n1, tex1*s);
// const VertNormTex vnt2(vert2, n1, tex2*s);
// const VertNormTex vnt3(vert3, n1, tex3*s);
// const VertNormTex vnt4(vert4, n1, tex4*s);
{
const VertNormTex vnt1(vert1, n1, tex1*s);
const VertNormTex vnt2(vert2, n1, tex2*s);
const VertNormTex vnt3(vert3, n1, tex3*s);
const VertNormTex vnt4(vert4, n1, tex4*s);
parts.addQuadCCW(vnt1, vnt2, vnt3, vnt4);
} {
const VertNormTex vnt1(vert1, n2, tex1*s);
const VertNormTex vnt2(vert2, n2, tex2*s);
const VertNormTex vnt3(vert3, n2, tex3*s);
const VertNormTex vnt4(vert4, n2, tex4*s);
parts.addQuadCW(vnt1, vnt2, vnt3, vnt4);
}
}
};
#endif // STAIRS_H

120
map/elements/Walls.h Normal file
View File

@@ -0,0 +1,120 @@
#ifndef WALLS_H
#define WALLS_H
#include <Indoor/floorplan/v2/Floorplan.h>
#include "../gl/GLHelper.h"
#include "../gl/GLTriangles.h"
#include "../Renderable.h"
#include "../../lib/gpc/Polygon.h"
class Walls : public Renderable {
private:
Floorplan::Floor* floor;
GLTriangles<VertNormTexTan> walls;
public:
/** ctor */
Walls(Floorplan::Floor* floor) : floor(floor) {
;
}
void initGL() override {
build();
walls.setDiffuse(":/res/gl/tex/floor3.jpg");
walls.setNormalMap(":/res/gl/tex/floor3_normal.jpg");
walls.build();
loadShader(":/res/gl/vertex1.glsl", ":/res/gl/fragmentTex.glsl");
program.setUniformValue("texDiffuse", 0);
program.setUniformValue("texNormalMap", 1);
//glEnable(GL_TEXTURE0 + 1);
}
/** render the floor */
void _render() override {
walls.render(&program);
}
private:
void build() {
for (Floorplan::FloorObstacle* obstacle : floor->obstacles) {
if (dynamic_cast<Floorplan::FloorObstacleLine*>(obstacle)) {
Floorplan::FloorObstacleLine* line = dynamic_cast<Floorplan::FloorObstacleLine*>(obstacle);
if (line->type != Floorplan::ObstacleType::WALL) {continue;}
addFace(line->from, line->to, floor->getStartingZ(), floor->getEndingZ());
} else if (dynamic_cast<Floorplan::FloorObstacleDoor*>(obstacle)) {
Floorplan::FloorObstacleDoor* door = dynamic_cast<Floorplan::FloorObstacleDoor*>(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);
walls.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);
walls.addQuadCW(vnt1, vnt2, vnt3, vnt4);
}
}
//private:
//
// QVector2D tex(const QVector3D vert) {
// return QVector2D(vert.x(), vert.y());
// }
};
#endif // WALLS_H