openGL work and other parts
4
Stairs.h
Normal file
@@ -0,0 +1,4 @@
|
||||
#ifndef STAIRS_H
|
||||
#define STAIRS_H
|
||||
|
||||
#endif // STAIRS_H
|
||||
109
lib/gpc/Polygon.h
Normal 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
133
lib/gpc/gpc.h
Executable 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
@@ -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
@@ -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
|
||||
124
map/Geometry.cpp
@@ -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);
|
||||
|
||||
}
|
||||
@@ -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
|
||||
153
map/MapView.cpp
@@ -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();*/
|
||||
}
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
|
||||
2
qml.qrc
@@ -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>
|
||||
|
||||
@@ -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
@@ -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;
|
||||
|
||||
|
||||
}
|
||||
25
res/gl/fragmentTexSimple.glsl
Normal 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
|
After Width: | Height: | Size: 1.5 KiB |
BIN
res/gl/tex/door1.jpg
Normal file
|
After Width: | Height: | Size: 255 KiB |
BIN
res/gl/tex/door2.jpg
Normal file
|
After Width: | Height: | Size: 9.8 KiB |
BIN
res/gl/tex/door2_normal.jpg
Normal file
|
After Width: | Height: | Size: 16 KiB |
BIN
res/gl/tex/floor1.jpg
Normal file
|
After Width: | Height: | Size: 84 KiB |
BIN
res/gl/tex/floor2.jpg
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
res/gl/tex/floor2_normal.jpg
Normal file
|
After Width: | Height: | Size: 90 KiB |
BIN
res/gl/tex/floor3.jpg
Normal file
|
After Width: | Height: | Size: 14 KiB |
BIN
res/gl/tex/floor3_normal.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
res/gl/tex/floor4.jpg
Normal file
|
After Width: | Height: | Size: 31 KiB |
BIN
res/gl/tex/floor4_normal.jpg
Normal file
|
After Width: | Height: | Size: 46 KiB |
BIN
res/gl/tex/granite1.jpg
Normal file
|
After Width: | Height: | Size: 32 KiB |
BIN
res/gl/tex/granite1_normal.jpg
Normal file
|
After Width: | Height: | Size: 60 KiB |
BIN
res/gl/tex/wall1.jpg
Normal file
|
After Width: | Height: | Size: 218 KiB |
BIN
res/gl/tex/wall2_normal.jpg
Normal file
|
After Width: | Height: | Size: 97 KiB |
BIN
res/gl/tex/wood1.jpg
Normal file
|
After Width: | Height: | Size: 181 KiB |
@@ -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);
|
||||
|
||||
}
|
||||
|
||||
12
yasmin.pro
@@ -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 \
|
||||
|
||||