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

4
Stairs.h Normal file
View File

@@ -0,0 +1,4 @@
#ifndef STAIRS_H
#define STAIRS_H
#endif // STAIRS_H

109
lib/gpc/Polygon.h Normal file
View File

@@ -0,0 +1,109 @@
#ifndef GPC_POLYGON_H
#define GPC_POLYGON_H
#include <Indoor/floorplan/v2/Floorplan.h>
#include "gpc.h"
class Polygon {
struct GPCPolygon : gpc_polygon {
GPCPolygon() {
// contour = (gpc_vertex_list*) calloc(0, 1024);
// contour->num_vertices = 0;
// contour->vertex = (gpc_vertex*) calloc(0, 1024);
// hole = (int*) calloc(0, 1024);
num_contours = 0;
contour = nullptr;
hole = nullptr;
}
~GPCPolygon() {
if (contour) {
gpc_free_polygon(this);
//free(contour->vertex); contour->vertex = nullptr;
}
free(contour); contour = nullptr;
free(hole); hole = nullptr;
}
GPCPolygon& operator = (const GPCPolygon& o) = delete;
GPCPolygon& operator = (GPCPolygon& o) {
this->contour = o.contour;
this->hole = o.hole;
this->num_contours = o.num_contours;
o.contour = nullptr;
o.hole = nullptr;
return *this;
}
};
private:
GPCPolygon state;
public:
void add(const Floorplan::Polygon2& poly) {
GPCPolygon cur = toGPC(poly);
//GPCPolygon out;
gpc_polygon_clip(GPC_UNION, &state, &cur, &state);
//state = out;
}
void remove(const Floorplan::Polygon2& poly) {
GPCPolygon cur = toGPC(poly);
//GPCPolygon out;
gpc_polygon_clip(GPC_DIFF, &state, &cur, &state);
//state = out;
}
std::vector<std::vector<Point3>> get(float z) {
gpc_tristrip res;
res.num_strips = 0;
res.strip = nullptr;
//res.strip = (gpc_vertex_list*) malloc(1024);
gpc_polygon_to_tristrip(&state, &res);
std::vector<std::vector<Point3>> trias;
for (int i = 0; i < res.num_strips; ++i) {
gpc_vertex_list lst = res.strip[i];
std::vector<Point3> tria;
for (int j = 0; j < lst.num_vertices; ++j) {
gpc_vertex& vert = lst.vertex[j];
Point3 p3(vert.x, vert.y, z);
tria.push_back(p3);
}
trias.push_back(tria);
}
gpc_free_tristrip(&res);
return std::move(trias);
}
private:
GPCPolygon toGPC(Floorplan::Polygon2 poly) {
std::vector<gpc_vertex> verts;
for (Point2 p2 : poly.points) {
gpc_vertex vert; vert.x = p2.x; vert.y = p2.y;
verts.push_back(vert);
}
GPCPolygon gpol;
gpc_vertex_list list;
list.num_vertices = verts.size();
list.vertex = verts.data();
gpc_add_contour(&gpol, &list, 0);
return gpol;
}
};
#endif // GPC_POLYGON_H

2472
lib/gpc/gpc.cpp Executable file

File diff suppressed because it is too large Load Diff

133
lib/gpc/gpc.h Executable file
View File

@@ -0,0 +1,133 @@
/*
===========================================================================
Project: Generic Polygon Clipper
A new algorithm for calculating the difference, intersection,
exclusive-or or union of arbitrary polygon sets.
File: gpc.h
Author: Alan Murta (email: gpc@cs.man.ac.uk)
Version: 2.32
Date: 17th December 2004
Copyright: (C) Advanced Interfaces Group,
University of Manchester.
This software is free for non-commercial use. It may be copied,
modified, and redistributed provided that this copyright notice
is preserved on all copies. The intellectual property rights of
the algorithms used reside with the University of Manchester
Advanced Interfaces Group.
You may not use this software, in whole or in part, in support
of any commercial product without the express consent of the
author.
There is no warranty or other guarantee of fitness of this
software for any purpose. It is provided solely "as is".
===========================================================================
*/
#ifndef __gpc_h
#define __gpc_h
#include <stdio.h>
/*
===========================================================================
Constants
===========================================================================
*/
/* Increase GPC_EPSILON to encourage merging of near coincident edges */
#define GPC_EPSILON (DBL_EPSILON)
#define GPC_VERSION "2.32"
/*
===========================================================================
Public Data Types
===========================================================================
*/
typedef enum /* Set operation type */
{
GPC_DIFF, /* Difference */
GPC_INT, /* Intersection */
GPC_XOR, /* Exclusive or */
GPC_UNION /* Union */
} gpc_op;
typedef struct /* Polygon vertex structure */
{
double x; /* Vertex x component */
double y; /* vertex y component */
} gpc_vertex;
typedef struct /* Vertex list structure */
{
int num_vertices; /* Number of vertices in list */
gpc_vertex *vertex; /* Vertex array pointer */
} gpc_vertex_list;
typedef struct /* Polygon set structure */
{
int num_contours; /* Number of contours in polygon */
int *hole; /* Hole / external contour flags */
gpc_vertex_list *contour; /* Contour array pointer */
} gpc_polygon;
typedef struct /* Tristrip set structure */
{
int num_strips; /* Number of tristrips */
gpc_vertex_list *strip; /* Tristrip array pointer */
} gpc_tristrip;
/*
===========================================================================
Public Function Prototypes
===========================================================================
*/
void gpc_read_polygon (FILE *infile_ptr,
int read_hole_flags,
gpc_polygon *polygon);
void gpc_write_polygon (FILE *outfile_ptr,
int write_hole_flags,
gpc_polygon *polygon);
void gpc_add_contour (gpc_polygon *polygon,
gpc_vertex_list *contour,
int hole);
void gpc_polygon_clip (gpc_op set_operation,
gpc_polygon *subject_polygon,
gpc_polygon *clip_polygon,
gpc_polygon *result_polygon);
void gpc_tristrip_clip (gpc_op set_operation,
gpc_polygon *subject_polygon,
gpc_polygon *clip_polygon,
gpc_tristrip *result_tristrip);
void gpc_polygon_to_tristrip (gpc_polygon *polygon,
gpc_tristrip *tristrip);
void gpc_free_polygon (gpc_polygon *polygon);
void gpc_free_tristrip (gpc_tristrip *tristrip);
#endif
/*
===========================================================================
End of file: gpc.h
===========================================================================
*/

225
main.cpp
View File

@@ -7,11 +7,23 @@
#include <QMainWindow>
#include <QGridLayout>
#include <Indoor/math/Interpolator.h>
#include <Indoor/grid/factory/v2/Importance.h>
#include <Indoor/nav/dijkstra/Dijkstra.h>
#include <Indoor/nav/dijkstra/DijkstraPath.h>
#include "sensors/SensorFactory.h"
#include "map/MapView.h"
#include <iostream>
#include <Indoor/floorplan/v2/FloorplanReader.h>
#include <Indoor/api/DummyAPI.h>
#include <Indoor/sensors/radio/WiFiGridNode.h>
#include <Indoor/sensors/radio/WiFiGridEstimator.h>
#include <Indoor/sensors/radio/model/WiFiModelLogDist.h>
class LeListener : public SensorListener<WiFiSensorData>, public SensorListener<AccelerometerData>, public SensorListener<StepData> {
public:
@@ -29,23 +41,43 @@ public:
};
struct MyNode : public GridPoint, public GridNode, public WiFiGridNode<10> {
float imp;
MyNode() {;}
MyNode(const float x_cm, const float y_cm, const float z_cm) : GridPoint(x_cm, y_cm, z_cm) {;}
static void staticSerialize(std::ostream& out) {
WiFiGridNode::staticSerialize(out);
}
static void staticDeserialize(std::istream& inp) {
WiFiGridNode::staticDeserialize(inp);
}
};
int main(int argc, char *argv[]) {
//// test();
// LeListener listener;
// WiFiSensor& wifi = SensorFactory::getWiFi();
// wifi.addListener(&listener);
// wifi.start();
//// AccelerometerSensor& acc = SensorFactory::getAccelerometer();
//// acc.addListener(&listener);
//// acc.start();
// StepSensor& steps = SensorFactory::getSteps();
// steps.addListener(&listener);
// steps.start();;
int sizeOfNode = sizeof(MyNode);
// std::this_thread::sleep_for(std::chrono::seconds(10000));
std::vector<Point3> points = {
Point3(1140,530,1060), Point3(1140,2100,1060), Point3(1140,2880,1060), Point3(1140,4442.21,1060), Point3(1190,4840,1060), Point3(1660,4840,890), Point3(1660,5040,890), Point3(1180,5040,720), Point3(1180,4840,720), Point3(1180,4460,720), Point3(2350,4460,720), Point3(4440,4440,720), Point3(5183.26,4280,720), Point3(5800,4280,550), Point3(6110,4280,380), Point3(7680,4280,380), Point3(7680,3860,190), Point3(7680,3400,0), Point3(7400,3400,0), Point3(7400,4030,0)
};
std::vector<Point3> path;
Interpolator<int, Point3> interpol;
int ts = 0;
Point3 last = points[0];
for (Point3 p : points) {
const float dist = p.getDistance(last);
const float diffMS = (dist / 100.0f) / 1.5f * 1000;
ts += diffMS;
interpol.add(ts, p);
last = p;
path.push_back(p / 100.0f);
}
@@ -54,22 +86,175 @@ int main(int argc, char *argv[]) {
// OpenGL Setup
QSurfaceFormat format;
format.setDepthBufferSize(24);
format.setDepthBufferSize(16);
QSurfaceFormat::setDefaultFormat(format);
// QMainWindow* win = new QMainWindow();
// QVBoxLayout* lay = new QVBoxLayout();
// win->setLayout(lay);
Floorplan::IndoorMap* im = Floorplan::Reader::readFromFile("/mnt/data/workspaces/IndoorMap/maps/SHL21.xml");
Grid<MyNode> grid(20);
GridFactory<MyNode> gf(grid);
// build
//gf.build(im);
//Importance::addImportance(grid, 0);
//std::ofstream out("/tmp/grid.dat");
//grid.write(out); out.close();
// read
std::ifstream inp("/tmp/grid.dat");
grid.reset();
grid.read(inp);
// estimate WiFi signal strengths
WiFiModelLogDist mdlLogDist(-40.0f, 2.25f);
WiFiGridEstimator::estimate(grid, mdlLogDist, im);
MapView* map = new MapView();
// lay->addWidget(map);
map->setMinimumHeight(200);
map->setMinimumWidth(200);
map->setMap(im);
//map->setPath(path);
map->show();
// win->setMinimumWidth(400);
// win->setMinimumHeight(400);
// win->show();
struct DijkstraMapper {
Grid<MyNode>& grid;
DijkstraMapper(Grid<MyNode>& grid) : grid(grid) {;}
int getNumNeighbors(const MyNode& n) const {return grid.getNumNeighbors(n);}
const MyNode* getNeighbor(const MyNode& n, const int idx) const {return &grid.getNeighbor(n, idx);}
float getWeightBetween(const MyNode& n1, const MyNode& n2) const {return n1.getDistanceInCM(n2) / n2.imp;}
};
struct LeListener : public APIListener {
Grid<MyNode>& grid;
Dijkstra<MyNode>& d;
const DijkstraNode<MyNode>* dnEnd;
MapView* map;
Point3 nextPos;
Point3 pos1;
Point3 pos2;
LeListener(Grid<MyNode>& grid, Dijkstra<MyNode>& d, const DijkstraNode<MyNode>* dnEnd, MapView* map) : grid(grid), d(d), dnEnd(dnEnd), map(map) {
std::thread t(&LeListener::update, this);
t.detach();
}
/** the currently estimated path to the target has changed */
virtual void onPathUpdate(const std::vector<Point3>& curPath) override {
}
/** the currently estimated position has changed */
virtual void onPositionUpdate(const Point3 pos) override {
nextPos = pos;
// update the path to the target
const GridPoint xxx(pos.x, pos.y, pos.z);
const DijkstraNode<MyNode>* dnStart = d.getNode( grid.getNearestNode(xxx) );
const DijkstraPath<MyNode> dp(dnStart, dnEnd);
map->setPath(dp);
}
void update() {
std::this_thread::sleep_for(std::chrono::milliseconds(700));
const int transMS = 500;
const int updateMS = 75;
const float factor1 = ((float) updateMS / (float) transMS) * 0.7;
const float factor2 = factor1 * 0.4f;
const Point3 human(0, 0, 180);
while(true) {
std::this_thread::sleep_for(std::chrono::milliseconds(updateMS));
// Point3 diff = (nextPos - pos1);
// if (diff.length() > 30) {diff = diff.normalized() * 30;} else {diff *= factor1;}
// pos1 += diff;
// pos2 += diff*0.5;
pos1 = pos1 * (1-factor1) + nextPos * (factor1); // fast update
pos2 = pos2 * (1-factor2) + nextPos * (factor2); // slow update
const Point3 dir = pos2 - pos1;
map->setLookAt((pos1+human) / 100.0f, (dir) / 100.0f);
}
}
};
DummyAPI api("/mnt/data/workspaces/navindoor");
api.setTarget(4);
Dijkstra<MyNode> d;
//GridPoint end(points.front().x, points.front().y, points.front().z);
GridPoint end(api.getDst().x, api.getDst().y, api.getDst().z);
d.build(&grid.getNearestNode(end), DijkstraMapper(grid));
const DijkstraNode<MyNode>* dnEnd = d.getNode(grid.getNearestNode(end));
api.addListener(new LeListener(grid, d, dnEnd, map));
api.setSpeed(2);
api.startNavigation();
// auto run = [&] () {
// //int ts = 0;
// int ts = 97000;
// while(ts < interpol.getMaxKey() && ts >= 0) {
// std::this_thread::sleep_for(std::chrono::milliseconds(50));
// //ts += 50;
// ts -= 150;
// const Point3 human(0, 0, 180);
//// const Point3 pos0 = interpol.get(ts-500);
//// const Point3 pos1 = interpol.get(ts+500);
// const Point3 pos = interpol.get(ts);
//// //const Point3 dir = Point3(-50000, -50000, 50000);//pos0 - pos;
//// Point3 dir = pos1 - pos0; dir.z /= 2; // only slight down/up looking
//// map->setLookAt((pos+human) / 100.0f, (dir) / 100.0f);
// GridPoint cur(pos.x, pos.y, pos.z);
// const DijkstraNode<MyNode>* dnStart = d.getNode( grid.getNearestNode(cur) );
// DijkstraPath<MyNode> dp(dnStart, dnEnd);
// map->setPath(dp);
//// Point3 next =
//// dp.getFromStart(2).element->inCentimeter() +
//// dp.getFromStart(4).element->inCentimeter() +
//// dp.getFromStart(6).element->inCentimeter();
//// next /= 3;
//// const Point3 dir = pos - next ;
// static Point3 lastPos;
// lastPos = lastPos * 0.85 + pos * 0.15;
// const Point3 dir = lastPos - pos ;
// map->setLookAt((pos+human) / 100.0f, (dir) / 100.0f);
// }
// };
// std::thread t(run);
// QQmlApplicationEngine engine;
// engine.load(QUrl(QStringLiteral("qrc:/main.qml")));

222
map/FloorRenderer.h Normal file
View 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

View File

@@ -1,124 +0,0 @@
#include "Geometry.h"
#include <QVector2D>
#include <QVector3D>
struct VertexData
{
QVector3D position;
QVector2D texCoord;
};
Geometry::Geometry() : indexBuf(QOpenGLBuffer::IndexBuffer) {
initializeOpenGLFunctions();
// Generate 2 VBOs
arrayBuf.create();
indexBuf.create();
// Initializes cube geometry and transfers it to VBOs
initCubeGeometry();
}
Geometry::~Geometry() {
arrayBuf.destroy();
indexBuf.destroy();
}
void Geometry::initCubeGeometry() {
// For cube we would need only 8 vertices but we have to
// duplicate vertex for each face because texture coordinate
// is different.
VertexData vertices[] = {
// Vertex data for face 0
{QVector3D(-1.0f, -1.0f, 1.0f), QVector2D(0.0f, 0.0f)}, // v0
{QVector3D( 1.0f, -1.0f, 1.0f), QVector2D(0.33f, 0.0f)}, // v1
{QVector3D(-1.0f, 1.0f, 1.0f), QVector2D(0.0f, 0.5f)}, // v2
{QVector3D( 1.0f, 1.0f, 1.0f), QVector2D(0.33f, 0.5f)}, // v3
// Vertex data for face 1
{QVector3D( 1.0f, -1.0f, 1.0f), QVector2D( 0.0f, 0.5f)}, // v4
{QVector3D( 1.0f, -1.0f, -1.0f), QVector2D(0.33f, 0.5f)}, // v5
{QVector3D( 1.0f, 1.0f, 1.0f), QVector2D(0.0f, 1.0f)}, // v6
{QVector3D( 1.0f, 1.0f, -1.0f), QVector2D(0.33f, 1.0f)}, // v7
// Vertex data for face 2
{QVector3D( 1.0f, -1.0f, -1.0f), QVector2D(0.66f, 0.5f)}, // v8
{QVector3D(-1.0f, -1.0f, -1.0f), QVector2D(1.0f, 0.5f)}, // v9
{QVector3D( 1.0f, 1.0f, -1.0f), QVector2D(0.66f, 1.0f)}, // v10
{QVector3D(-1.0f, 1.0f, -1.0f), QVector2D(1.0f, 1.0f)}, // v11
// Vertex data for face 3
{QVector3D(-1.0f, -1.0f, -1.0f), QVector2D(0.66f, 0.0f)}, // v12
{QVector3D(-1.0f, -1.0f, 1.0f), QVector2D(1.0f, 0.0f)}, // v13
{QVector3D(-1.0f, 1.0f, -1.0f), QVector2D(0.66f, 0.5f)}, // v14
{QVector3D(-1.0f, 1.0f, 1.0f), QVector2D(1.0f, 0.5f)}, // v15
// Vertex data for face 4
{QVector3D(-1.0f, -1.0f, -1.0f), QVector2D(0.33f, 0.0f)}, // v16
{QVector3D( 1.0f, -1.0f, -1.0f), QVector2D(0.66f, 0.0f)}, // v17
{QVector3D(-1.0f, -1.0f, 1.0f), QVector2D(0.33f, 0.5f)}, // v18
{QVector3D( 1.0f, -1.0f, 1.0f), QVector2D(0.66f, 0.5f)}, // v19
// Vertex data for face 5
{QVector3D(-1.0f, 1.0f, 1.0f), QVector2D(0.33f, 0.5f)}, // v20
{QVector3D( 1.0f, 1.0f, 1.0f), QVector2D(0.66f, 0.5f)}, // v21
{QVector3D(-1.0f, 1.0f, -1.0f), QVector2D(0.33f, 1.0f)}, // v22
{QVector3D( 1.0f, 1.0f, -1.0f), QVector2D(0.66f, 1.0f)} // v23
};
// Indices for drawing cube faces using triangle strips.
// Triangle strips can be connected by duplicating indices
// between the strips. If connecting strips have opposite
// vertex order then last index of the first strip and first
// index of the second strip needs to be duplicated. If
// connecting strips have same vertex order then only last
// index of the first strip needs to be duplicated.
GLushort indices[] = {
0, 1, 2, 3, 3, // Face 0 - triangle strip ( v0, v1, v2, v3)
4, 4, 5, 6, 7, 7, // Face 1 - triangle strip ( v4, v5, v6, v7)
8, 8, 9, 10, 11, 11, // Face 2 - triangle strip ( v8, v9, v10, v11)
12, 12, 13, 14, 15, 15, // Face 3 - triangle strip (v12, v13, v14, v15)
16, 16, 17, 18, 19, 19, // Face 4 - triangle strip (v16, v17, v18, v19)
20, 20, 21, 22, 23 // Face 5 - triangle strip (v20, v21, v22, v23)
};
// Transfer vertex data to VBO 0
arrayBuf.bind();
arrayBuf.allocate(vertices, 24 * sizeof(VertexData));
// Transfer index data to VBO 1
indexBuf.bind();
indexBuf.allocate(indices, 34 * sizeof(GLushort));
}
void Geometry::drawCubeGeometry(QOpenGLShaderProgram *program) {
// Tell OpenGL which VBOs to use
arrayBuf.bind();
indexBuf.bind();
// Offset for position
quintptr offset = 0;
// Tell OpenGL programmable pipeline how to locate vertex position data
int vertexLocation = program->attributeLocation("a_position");
program->enableAttributeArray(vertexLocation);
program->setAttributeBuffer(vertexLocation, GL_FLOAT, offset, 3, sizeof(VertexData));
// Offset for texture coordinate
offset += sizeof(QVector3D);
// Tell OpenGL programmable pipeline how to locate vertex texture coordinate data
int texcoordLocation = program->attributeLocation("a_texcoord");
program->enableAttributeArray(texcoordLocation);
program->setAttributeBuffer(texcoordLocation, GL_FLOAT, offset, 2, sizeof(VertexData));
// Draw cube geometry using indices from VBO 1
glDrawElements(GL_TRIANGLE_STRIP, 34, GL_UNSIGNED_SHORT, 0);
}

View File

@@ -1,23 +0,0 @@
#ifndef GEOMETRY_H
#define GEOMETRY_H
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
class Geometry : protected QOpenGLFunctions
{
public:
Geometry();
virtual ~Geometry();
void drawCubeGeometry(QOpenGLShaderProgram *program);
private:
void initCubeGeometry();
QOpenGLBuffer arrayBuf;
QOpenGLBuffer indexBuf;
};
#endif // GEOMETRY_H

View File

@@ -1,7 +1,13 @@
#include "MapView.h"
#include <QGLShaderProgram>
#include "Geometry.h"
#include "elements/Walls.h"
#include "elements/Ground.h"
#include "elements/Handrails.h"
#include "elements/Stairs.h"
#include "elements/Doors.h"
#include "elements/Path.h"
// http://doc.qt.io/qt-5/qtopengl-cube-example.html
@@ -10,31 +16,42 @@ MapView::MapView(QWidget* parent) : QOpenGLWidget(parent) {
};
void MapView::setMap(Floorplan::IndoorMap* map) {
for (Floorplan::Floor* floor : map->floors) {
elements.push_back(new Ground(floor));
elements.push_back(new Walls(floor));
elements.push_back(new Handrails(floor));
elements.push_back(new Stairs(floor));
elements.push_back(new Doors(floor));
}
this->path = new Path();
elements.push_back(this->path);
}
void MapView::setPath(const std::vector<Point3>& path) {
this->path->set(path);
}
void MapView::timerEvent(QTimerEvent *) {
update();
}
void MapView::initializeGL() {
//qglClearColor(Qt::black);
//glEnable(GL_DEPTH_TEST);
//glEnable(GL_CULL_FACE);
//glShadeModel(GL_SMOOTH);
//glEnable(GL_LIGHTING);
//glEnable(GL_LIGHT0);
//static GLfloat lightPosition[4] = { 0, 0, 10, 1.0 };
//glLightfv(GL_LIGHT0, GL_POSITION, lightPosition);
initializeOpenGLFunctions();
geo = new Geometry();
glEnable(GL_DEPTH_TEST);
glEnable(GL_CULL_FACE);
if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex, ":/res/gl/vertex1.glsl")) {throw "1";}
if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment, ":/res/gl/fragment1.glsl")) {throw "2";}
if (!program.link()) {throw "3";}
if (!program.bind()) {throw "4";}
for (Renderable* r : elements) {
r->initGL();
}
timer.start(60, this);
@@ -42,11 +59,6 @@ void MapView::initializeGL() {
void MapView::paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//glLoadIdentity();
//glTranslatef(0.0, 0.0, -10.0);
//glRotatef(20 / 16.0, 1.0, 0.0, 0.0);
//glRotatef(30 / 16.0, 0.0, 1.0, 0.0);
//glRotatef(60 / 16.0, 0.0, 0.0, 1.0);
draw();
}
@@ -55,75 +67,66 @@ void MapView::resizeGL(int w, int h) {
// Calculate aspect ratio
qreal aspect = qreal(w) / qreal(h ? h : 1);
// Set near plane to 3.0, far plane to 7.0, field of view 45 degrees
const qreal zNear = 3.0, zFar = 7.0, fov = 45.0;
// viewing frustrum [0:50] meter
const qreal zNear = 0.02, zFar = 50, fov = 50.0;
// Reset projection
projection.setToIdentity();
matProject.setToIdentity();
matProject.scale(-1, 1, 1);
glCullFace(GL_FRONT);
//matProject.scale(0.05, 0.05, 0.05);
matProject.perspective(fov, aspect, zNear, zFar);
//matProject.scale(-0.01, 0.01, 0.01);
// Set perspective projection
projection.perspective(fov, aspect, zNear, zFar);
}
void MapView::setLookAt(const Point3 pos_m, const Point3 dir) {
QVector3D qDir(dir.x, dir.z, dir.y);
QVector3D lookAt = QVector3D(pos_m.x, pos_m.z, pos_m.y);
QVector3D eye = lookAt + qDir * 0.1;
QVector3D up = QVector3D(0,1,0);
matView.setToIdentity();
//matView.scale(0.01, 0.01, 0.01);
matView.lookAt(eye, lookAt, up);
//matView.scale(0.99, 1, 1);
//matView.translate(0.7, 0, 0);
lightPos = eye + QVector3D(0.0, 4.0, 0.0);
eyePos = eye;
}
void MapView::draw() {
static float angularSpeed = 0;
angularSpeed += 0.5;
// Clear color and depth buffer
// clear everything
glClearColor(0,0,0,1);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//static float angularSpeed = 0;
//angularSpeed += 1.5;
//texture->bind();
QVector3D rotationAxis(1,1,1);
QQuaternion rotation = QQuaternion::fromAxisAndAngle(rotationAxis, angularSpeed);
//QVector3D rotationAxis(1,1,1);
//QQuaternion rotation = QQuaternion::fromAxisAndAngle(rotationAxis, angularSpeed);
// Calculate model view transformation
QMatrix4x4 matrix;
matrix.translate(0.0, 0.0, -5.0);
matrix.rotate(rotation);
QMatrix4x4 matModel;
//matModel.setToIdentity();
//matModel.translate(0.0, 0.0, 0.0);
//matModel.rotate(rotation);
// Set modelview-projection matrix
program.setUniformValue("mvp_matrix", projection * matrix);
for (Renderable* r : elements) {
// Use texture unit 0 which contains cube.png
program.setUniformValue("texture", 0);
QOpenGLShaderProgram& program = r->getProgram();
program.bind();
// Draw cube geometry
geo->drawCubeGeometry(&program);
// set the matrices
program.setUniformValue("m_matrix", matModel);
program.setUniformValue("mv_matrix", matView * matModel);
program.setUniformValue("mvp_matrix", matProject * matView * matModel);
program.setUniformValue("lightWorldPos", lightPos);
program.setUniformValue("eyeWorldPos", eyePos);
//qglColor(Qt::red);
/*glBegin(GL_QUADS);
glNormal3f(0,0,-1);
glVertex3f(-1,-1,0);
glVertex3f(-1,1,0);
glVertex3f(1,1,0);
glVertex3f(1,-1,0);
r->render();
}
glEnd();
glBegin(GL_TRIANGLES);
glNormal3f(0,-1,0.707);
glVertex3f(-1,-1,0);
glVertex3f(1,-1,0);
glVertex3f(0,0,1.2);
glEnd();
glBegin(GL_TRIANGLES);
glNormal3f(1,0, 0.707);
glVertex3f(1,-1,0);
glVertex3f(1,1,0);
glVertex3f(0,0,1.2);
glEnd();
glBegin(GL_TRIANGLES);
glNormal3f(0,1,0.707);
glVertex3f(1,1,0);
glVertex3f(-1,1,0);
glVertex3f(0,0,1.2);
glEnd();
glBegin(GL_TRIANGLES);
glNormal3f(-1,0,0.707);
glVertex3f(-1,1,0);
glVertex3f(-1,-1,0);
glVertex3f(0,0,1.2);
glEnd();*/
}

View File

@@ -6,22 +6,57 @@
#include <QOpenGLShaderProgram>
#include <QBasicTimer>
class Geometry;
#include <Indoor/geo/Point3.h>
#include <Indoor/nav/dijkstra/DijkstraPath.h>
#include "elements/Path.h"
namespace Floorplan {
class IndoorMap;
}
class Renderable;
class Path;
class MapView : public QOpenGLWidget, protected QOpenGLFunctions {
private:
QMatrix4x4 projection;
QOpenGLShaderProgram program;
Geometry* geo;
QMatrix4x4 matProject;
QMatrix4x4 matView;
QVector3D lightPos;
QVector3D eyePos;
QBasicTimer timer;
std::vector<Renderable*> elements;
Path* path;
public:
MapView(QWidget* parent = 0);
/** set the map to display */
void setMap(Floorplan::IndoorMap* map);
/** the position to look at */
void setLookAt(const Point3 pos, const Point3 dir = Point3(-1, -1, 0.1));
/** set the path to disply */
void setPath(const std::vector<Point3>& path);
/** set the path to disply */
template <typename Node> void setPath(const DijkstraPath<Node>& path) {
this->path->set(path);
}
protected:
void timerEvent(QTimerEvent *e) Q_DECL_OVERRIDE;

40
map/Renderable.h Normal file
View File

@@ -0,0 +1,40 @@
#ifndef RENDERABLE_H
#define RENDERABLE_H
#include <QOpenGLShaderProgram>
class Renderable {
protected:
QOpenGLShaderProgram program;
public:
/** get the renderable's shader */
QOpenGLShaderProgram& getProgram() {return program;}
/** render the renderable */
void render() {
program.bind();
_render();
}
virtual void initGL() = 0;
virtual void _render() = 0;
protected:
/** helper method to build the shader */
void loadShader(const QString& vertex, const QString& fragment) {
if (!program.addShaderFromSourceFile(QOpenGLShader::Vertex, vertex)) {throw "1";}
if (!program.addShaderFromSourceFile(QOpenGLShader::Fragment, fragment)) {throw "2";}
if (!program.link()) {throw "3";}
if (!program.bind()) {throw "4";}
}
};
#endif // RENDERABLE_H

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

55
map/gl/GL.h Normal file
View File

@@ -0,0 +1,55 @@
#ifndef HELPER_GL_H
#define HELPER_GL_H
#include <QOpenGLFunctions>
#include <QOpenGLShaderProgram>
#include <QOpenGLBuffer>
#include <QOpenGLTexture>
struct Vert {
QVector3D vert;
Vert(QVector3D vert) : vert(vert) {;}
int getVertOffset() const {return 0;}
bool operator == (const Vert& o) const {return (vert == o.vert);}
};
struct VertNorm {
QVector3D vert;
QVector3D norm;
VertNorm(QVector3D vert, QVector3D norm) : vert(vert), norm(norm) {;}
int getVertOffset() const {return 0;}
int getNormOffset() const {return sizeof(QVector3D);}
int getTanOffset() const {throw "error";}
bool operator == (const VertNorm& o) const {return (vert == o.vert) && (norm == o.norm);}
static bool hasTangent() {return false;}
};
struct VertNormTex {
QVector3D vert;
QVector3D norm;
QVector2D tex;
VertNormTex(QVector3D vert, QVector3D norm, QVector3D tex) : vert(vert), norm(norm), tex(tex) {;}
int getVertOffset() const {return 0;}
int getNormOffset() const {return sizeof(QVector3D);}
int getTexOffset() const {return sizeof(QVector3D)*2;}
int getTanOffset() const {throw "error";}
bool operator == (const VertNormTex& o) const {return (vert == o.vert) && (norm == o.norm) && (tex == o.tex);}
static bool hasTangent() {return false;}
};
struct VertNormTexTan {
QVector3D vert;
QVector3D norm;
QVector2D tex;
QVector3D tan;
VertNormTexTan(QVector3D vert, QVector3D norm, QVector3D tex, QVector3D tan) : vert(vert), norm(norm), tex(tex), tan(tan) {;}
int getVertOffset() const {return 0;}
int getNormOffset() const {return sizeof(QVector3D);}
int getTexOffset() const {return sizeof(QVector3D)*2;}
int getTanOffset() const {return sizeof(QVector3D)*2 + sizeof(QVector2D);}
bool operator == (const VertNormTexTan& o) const {return (vert == o.vert) && (norm == o.norm) && (tex == o.tex) && (tan == o.tan);}
static bool hasTangent() {return true;}
};
#endif // HELPER_GL_H

67
map/gl/GLHelper.h Normal file
View File

@@ -0,0 +1,67 @@
#ifndef MAP_HELPER_H
#define MAP_HELPER_H
#include <Indoor/geo/Point3.h>
#include <QOpenGLFunctions>
class GLHelper {
public:
static QVector3D getNormal(const QVector3D& v1, const QVector3D& v2, const QVector3D& v3) {
// get two of the triangle's edges
const QVector4D v21 = v2-v1;
const QVector4D v31 = v3-v1;
const QVector3D n = QVector3D::crossProduct(v21.toVector3D(), v31.toVector3D()).normalized();
return isCCW(v1, v2, v3) ? (n) : (-n);
}
/**
* is the triangle given by p1,p2,p3 CCW?
* NOTE: uses OUR coordinate system (x,y,z) where z is the floor-height
*/
static bool isCCW(const Point3 p1, const Point3 p2, const Point3 p3) {
const QVector3D v1(p1.x, p1.z, p1.y);
const QVector3D v2(p2.x, p2.z, p2.y);
const QVector3D v3(p3.x, p3.z, p3.y);
return isCCW(v1, v2, v3);
}
/**
* is the triangle given by p1,p2,p3 CCW?
* NOTE: uses OpenGL coordinate system (x,z,y) (our z is the floor-height)
*/
static bool isCCW(const QVector3D& p1, const QVector3D& p2, const QVector3D& p3) {
// camera position
QMatrix4x4 proj; proj.lookAt(QVector3D(-1,20,-1), QVector3D(0,0,0), QVector3D(0,1,0));
// to camera space
QVector4D v1(p1.x(), p1.y(), p1.z(), 1);
QVector4D v2(p2.x(), p2.y(), p2.z(), 1);
QVector4D v3(p3.x(), p3.y(), p3.z(), 1);
v1 = proj * v1;
v2 = proj * v2;
v3 = proj * v3;
// get two of the triangle's edges
const QVector4D v21 = v2-v1;
const QVector4D v31 = v3-v1;
// check the angle between both
const float angle = QVector2D::dotProduct(v21.toVector2D(), v31.toVector2D());
return angle > 0;
// const QVector3D n = QVector3D::crossProduct(v21.toVector3D(), v31.toVector3D());
// return n.z() > 0;
}
};
#endif // MAP_HELPER_H

126
map/gl/GLLines.h Normal file
View File

@@ -0,0 +1,126 @@
#ifndef GLLINES_H
#define GLLINES_H
#include <QOpenGLFunctions>
#include "GL.h"
#include "GLHelper.h"
#include <Indoor/geo/Point3.h>
class GLLines : protected QOpenGLFunctions {
private:
QOpenGLBuffer arrayBuf;
QOpenGLBuffer indexBuf;
std::vector<Vert> vertices;
std::vector<GLushort> indices;
int mode = GL_LINES;
public:
/** ctor */
GLLines() : arrayBuf(QOpenGLBuffer::VertexBuffer), indexBuf(QOpenGLBuffer::IndexBuffer) {
;
}
/** dtor */
~GLLines() {
arrayBuf.destroy();
indexBuf.destroy();
}
/** add a new face to this element */
void addLine(const QVector3D& p1, const QVector3D& p2) {
// add vertices (remove duplicates!)
const int i1 = addOnce(p1);
const int i2 = addOnce(p2);
// add indices
indices.push_back(i1);
indices.push_back(i2);
}
void addVertex(const QVector3D& p1) {
const int i1 = addOnce(p1);
indices.push_back(i1);
}
/** build the underlying buffers */
void build() {
initializeOpenGLFunctions();
// 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 rebuild() {
if (indexBuf.isCreated()) {indexBuf.destroy();}
if (arrayBuf.isCreated()) {arrayBuf.destroy();}
build();
}
void clear() {
indices.clear();
vertices.clear();
}
void setMode(const int mode) {
this->mode = mode;
}
/** render the element */
void render(QOpenGLShaderProgram *program) {
// Tell OpenGL which VBOs to use
arrayBuf.bind();
indexBuf.bind();
// vertices
int vertLoc = program->attributeLocation("a_position");
program->enableAttributeArray(vertLoc);
program->setAttributeBuffer(vertLoc, GL_FLOAT, vertices[0].getVertOffset(), 3, sizeof(vertices[0]));
// Draw cube geometry using indices from VBO 1
glDrawElements(mode, indices.size(), GL_UNSIGNED_SHORT, 0);
}
private:
/** to conserve memory, avoid duplicate VNTs! */
int addOnce(const Vert& vnt) {
const auto it = std::find(vertices.begin(), vertices.end(), vnt);
if (it == vertices.end()) {
const int idx = vertices.size();
vertices.push_back(vnt);
return idx;
} else {
const int idx = it - vertices.begin();
return idx;
}
}
};
#endif // GLLINES_H

205
map/gl/GLTriangles.h Normal file
View File

@@ -0,0 +1,205 @@
#ifndef GLTRIANGLES_H
#define GLTRIANGLES_H
#include <QOpenGLFunctions>
#include "GL.h"
#include "GLHelper.h"
#include <type_traits>
#include <Indoor/geo/Point3.h>
template <typename T> class GLTriangles : protected QOpenGLFunctions {
private:
QOpenGLBuffer arrayBuf;
QOpenGLBuffer indexBuf;
QOpenGLTexture* textures[4];
std::vector<T> vertices;
std::vector<GLushort> indices;
public:
/** ctor */
GLTriangles() : arrayBuf(QOpenGLBuffer::VertexBuffer), indexBuf(QOpenGLBuffer::IndexBuffer), textures() {
;
}
/** dtor */
~GLTriangles() {
arrayBuf.destroy();
indexBuf.destroy();
for (int i = 0; i < 4; ++i) {delete textures[i];}
}
/** set the to-be-used texture */
void setTexture(const int slot, const QString& textureFile) {
const QImage img(textureFile);
if (img.width() <= 0) {throw "error";}
QOpenGLTexture* texture = new QOpenGLTexture(img);
texture->setMinificationFilter(QOpenGLTexture::Linear);
texture->setMagnificationFilter(QOpenGLTexture::Linear);
texture->setWrapMode(QOpenGLTexture::Repeat);
texture->generateMipMaps();
textures[slot] = texture;
}
void setDiffuse(const QString& textureFile) {
setTexture(0, textureFile);
}
void setNormalMap(const QString& textureFile) {
setTexture(1, textureFile);
}
/** add a new face to this element */
void addFaceCCW(const T& vnt1, const T& vnt2, const T& vnt3) {
addFace(vnt1, vnt2, vnt3, 1);
}
/** add a new face to this element */
void addFaceCW(const T& vnt1, const T& vnt2, const T& vnt3) {
addFace(vnt1, vnt2, vnt3, 2);
}
/** add a new quad to this element */
void addQuadCCW(const T& vnt1, const T& vnt2, const T& vnt3, const T& vnt4) {
addFace(vnt1, vnt2, vnt3, 1);
addFace(vnt3, vnt4, vnt1, 1);
}
/** add a new quad to this element */
void addQuadCW(const T& vnt1, const T& vnt2, const T& vnt3, const T& vnt4) {
addFace(vnt1, vnt2, vnt3, 2);
addFace(vnt3, vnt4, vnt1, 2);
}
/** add a new quad to this element */
void addQuad(const T& vnt1, const T& vnt2, const T& vnt3, const T& vnt4) {
addFace(vnt1, vnt2, vnt3, 0);
addFace(vnt3, vnt4, vnt1, 0);
}
/** build the underlying buffers */
void build() {
initializeOpenGLFunctions();
// 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 rebuild() {
if (indexBuf.isCreated()) {indexBuf.destroy();}
if (arrayBuf.isCreated()) {arrayBuf.destroy();}
build();
}
void clear() {
indices.clear();
vertices.clear();
}
/** render the element */
void render(QOpenGLShaderProgram* program) {
// Tell OpenGL which VBOs to use
arrayBuf.bind();
indexBuf.bind();
for (int i = 0; i < 4; ++i) {
if (textures[i]) { textures[i]->bind(i); }
}
// 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]));
// bind tangent data?
if (T::hasTangent()) {
int tanLocation = program->attributeLocation("a_tangent");
program->enableAttributeArray(tanLocation);
program->setAttributeBuffer(tanLocation, GL_FLOAT, vertices[0].getTanOffset(), 3, sizeof(vertices[0]));
}
// texture
program->setUniformValue("texture", 0);
// Draw cube geometry using indices from VBO 1
glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, 0);
}
private:
void addFace(const T& vnt1, const T& vnt2, const T& vnt3, const int mode) {
// add vertices (remove duplicates!)
const int i1 = addOnce(vnt1);
const int i2 = addOnce(vnt2);
const int i3 = addOnce(vnt3);
// get current orientation
const bool ccw = GLHelper::isCCW(vnt1.vert, vnt2.vert, vnt3.vert);
// create indices
if (mode == 0 || (mode == 1 && ccw) || (mode == 2 && !ccw) ) {
indices.push_back(i1);
indices.push_back(i2);
indices.push_back(i3);
} else {
indices.push_back(i3);
indices.push_back(i2);
indices.push_back(i1);
}
}
/** to conserve memory, avoid duplicate VNTs! */
int addOnce(const T& vnt) {
const auto it = std::find(vertices.begin(), vertices.end(), vnt);
if (it == vertices.end()) {
const int idx = vertices.size();
vertices.push_back(vnt);
return idx;
} else {
const int idx = it - vertices.begin();
return idx;
}
}
};
#endif // GLTRIANGLES_H

View File

@@ -2,5 +2,7 @@
<qresource prefix="/">
<file>res/gl/fragment1.glsl</file>
<file>res/gl/vertex1.glsl</file>
<file>res/gl/tex/floor1.jpg</file>
<file>res/gl/tex/wall1.jpg</file>
</qresource>
</RCC>

View File

@@ -4,13 +4,17 @@ precision mediump int;
precision mediump float;
#endif
uniform sampler2D texture;
uniform vec3 lightWorldPos;
uniform vec4 color;
// interpolated values
varying vec3 v_WorldPos;
varying vec3 v_normal;
varying vec2 v_texcoord;
void main()
{
void main() {
// Set fragment color from texture
gl_FragColor = texture2D(texture, v_texcoord);
gl_FragColor = vec4(1,1,1,1);
gl_FragColor = color;
}

76
res/gl/fragmentTex.glsl Normal file
View File

@@ -0,0 +1,76 @@
#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif
uniform vec3 eyeWorldPos;
uniform vec3 lightWorldPos;
uniform sampler2D texDiffuse;
uniform sampler2D texNormalMap;
// interpolated values
varying vec3 v_WorldPos;
varying vec3 v_CamPos;
varying vec3 v_normal;
varying vec2 v_texcoord;
varying mat3 normalMat;
void main() {
// diffuse fragment color
vec4 ambient = texture2D(texDiffuse, v_texcoord);
vec4 diffuse = ambient * vec4(0.8, 0.6, 0.35, 1.0);
vec4 specular = vec4(1,1,1,1);
// get the normal from the normal map
//vec3 normal = vec3(0,0,1);
vec3 normal = normalize(texture2D(texNormalMap, v_texcoord).rgb - 0.5) * 2.0;
// and convert from texture's normal-space into the object's normal-space using the normal-matrix
normal = normalize(normalMat * normal);
// direction from fragment towards the light
vec3 lightDir = normalize(lightWorldPos - v_WorldPos);
// direction from fragment towards the eye
vec3 eyeDir = normalize(eyeWorldPos - v_WorldPos);
// diffuse lighting
float diffuseIntensity = max(dot(lightDir, normal), 0.0);
// specular lighting
// vec3 h = normalize(lightDir + eyeDir);
// float intSpec = max(dot(h, normal), 0.0);
// float specularIntensity = pow(intSpec, 2.0);
float specularIntensity = pow(max(0.0, dot(eyeDir, reflect(-lightDir, normal))), 16);
// distance between fragment and light (in meter)
float distToLight_m = length(lightWorldPos - v_WorldPos);
float lightInt = clamp(1.0 / (distToLight_m / 10.0), 0.0, 1.0);
// Set fragment color from texture
vec4 finalColor =
ambient * 0.05 +
diffuse * 0.95 * diffuseIntensity * lightInt +
clamp(specular * specularIntensity, 0.0, 1.0) * 1.0;
gl_FragColor = clamp(finalColor, 0.0, 1.0);
// FOG
//float mixing = pow((1.0 - v_CamPos.z * 3.0), 2);
//gl_FragColor = mix(gl_FragColor, vec4(0.5, 0.5, 0.5, 1.0), 1.0-mixing);
//gl_FragColor = gl_FragColor * 1;
// gl_FragColor =
// ambient * 0.001 +
// diffuse * 0.009 * diffuseIntensity +
// specular * 0.6 * specularIntensity;
}

View File

@@ -0,0 +1,25 @@
#ifdef GL_ES
// Set default precision to medium
precision mediump int;
precision mediump float;
#endif
//uniform vec3 eyeWorldPos;
//uniform vec3 lightWorldPos;
uniform sampler2D texDiffuse;
// interpolated values
//varying vec3 v_WorldPos;
//varying vec3 v_normal;
varying vec2 v_texcoord;
void main() {
// fragment color
vec4 ambient = texture2D(texDiffuse, v_texcoord);
// set
gl_FragColor = ambient;
}

BIN
res/gl/tex/arrows.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
res/gl/tex/door1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 255 KiB

BIN
res/gl/tex/door2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.8 KiB

BIN
res/gl/tex/door2_normal.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
res/gl/tex/floor1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
res/gl/tex/floor2.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

BIN
res/gl/tex/floor3.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 20 KiB

BIN
res/gl/tex/floor4.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 31 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

BIN
res/gl/tex/granite1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

BIN
res/gl/tex/wall1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 218 KiB

BIN
res/gl/tex/wall2_normal.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
res/gl/tex/wood1.jpg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 181 KiB

View File

@@ -4,19 +4,39 @@ precision mediump int;
precision mediump float;
#endif
uniform mat4 m_matrix;
uniform mat4 mv_matrix;
uniform mat4 mvp_matrix;
attribute vec4 a_position;
attribute vec3 a_position;
attribute vec3 a_normal;
attribute vec2 a_texcoord;
attribute vec3 a_tangent;
varying vec3 v_WorldPos;
varying vec3 v_CamPos;
varying vec3 v_normal;
varying vec2 v_texcoord;
varying mat3 normalMat;
void main()
{
// Calculate vertex position in screen space
gl_Position = mvp_matrix * a_position;
void main() {
// Pass texture coordinate to fragment shader
// Value will be automatically interpolated to fragments inside polygon faces
// interpolation:
v_WorldPos = vec3(m_matrix * vec4(a_position, 1.0));
v_CamPos = vec3(mv_matrix * vec4(a_position, 1.0));
v_normal = a_normal;//normalize(vec3(mv_matrix * vec4(a_normal, 0.0)));
v_texcoord = a_texcoord;
// http://www.opengl-tutorial.org/intermediate-tutorials/tutorial-13-normal-mapping/
vec3 bitangent = cross(a_normal, a_tangent);
normalMat = mat3(a_tangent, bitangent, a_normal);
// 2D position for the vertex
gl_Position = mvp_matrix * vec4(a_position, 1.0);
}

View File

@@ -22,7 +22,9 @@ OTHER_FILES += \
SOURCES += \
main.cpp \
map/MapView.cpp \
map/Geometry.cpp
map/Geometry.cpp \
lib/gpc/gpc.cpp \
../Indoor/lib/tinyxml/tinyxml2.cpp
RESOURCES += qml.qrc
@@ -40,6 +42,7 @@ INSTALLS += target
# android-sources/src/WiFi.java
HEADERS += \
lib/gpc/gpc.h \
sensors/linux/WiFiSensorLinux.h \
sensors/android/WiFiSensorAndroid.h \
sensors/StepSensor.h \
@@ -53,7 +56,12 @@ HEADERS += \
misc/fixc11.h \
sensors/dummy/WiFiSensorDummy.h \
map/MapView.h \
map/Geometry.h
map/Geometry.h \
map/FloorRenderer.h \
map/Ground.h \
lib/gpc/Polygon.h \
map/GL.h \
Stairs.h
DISTFILES += \
android-sources/src/MyActivity.java \