initial commit

This commit is contained in:
ccolin 2020-12-22 13:15:23 +01:00
commit 7fbe0814d5
12 changed files with 619 additions and 0 deletions

16
projet.pro Normal file
View File

@ -0,0 +1,16 @@
QT += core gui widgets
TARGET = projet
TEMPLATE = app
DEFINES += QT_DEPRECATED_WARNINGS
CONFIG += qt debug
SOURCES += src/main.cc
SOURCES += src/main_window.cc
SOURCES += src/opengl_mesh.cc
SOURCES += src/opengl_widget.cc
SOURCES += src/drone_controller.cc
HEADERS += src/main_window.hh
HEADERS += src/opengl_mesh.hh
HEADERS += src/opengl_widget.hh
HEADERS += src/drone_controller.hh

108
src/boid.cc Normal file
View File

@ -0,0 +1,108 @@
#include "main_window.hh"
#include <QVector3D>
#include <QRandomGenerator>
struct Fish {
QVector3D pos;
QVector3D vel;
float size;
float dist = 10;
float sqdist;
OpenGLMesh mesh;
Fish(QVector3D pos, OpenGLMesh mesh)
:pos(pos),
sqdist(dist * dist),
mesh(mesh) {}
void step() {
pos += vel;
mesh.mat.setToIdentity();
QMatrix4x4 rot;
rot.lookAt(pos, vel, {0, 1, 0});
mesh.mat.translate(pos);
// mesh.mat = rot * mesh.mat;
}
bool in_neighborhood(const QVector3D &p) const {
return (p - pos).lengthSquared() < sqdist;
}
};
struct Banc {
QVector<Fish> fishes;
Banc() {}
Banc(size_t nfishes) {
OpenGLMesh fish_mesh = OpenGLMesh({
0, .1, 0,
-.0866, -.05, 0,
.0866, -.05, 0,
});
QRandomGenerator *rng = QRandomGenerator::global();
for (size_t i = 0; i < nfishes; i++) {
Fish fish({
(float) (rng->generateDouble() * 3 - 1.5),
(float) (rng->generateDouble() * 3 - 1.5),
(float) (rng->generateDouble() * 3 - 1.5)
}, fish_mesh);
fishes.append(fish);
}
}
void step() {
QVector<Fish> neighbors;
for (Fish &fish : fishes) {
QVector3D neighbors_cog;
QVector3D neighbors_vel;
size_t nneighbors = 0;
for (Fish &fish_b : fishes) {
if (fish_b.in_neighborhood(fish.pos)) {
nneighbors++;
neighbors_cog += fish_b.pos;
neighbors_vel += fish_b.vel;
}
}
neighbors_cog /= nneighbors;
neighbors_vel /= nneighbors;
QVector3D v1 = -(fish.pos - neighbors_cog);
QVector3D v2 = fish.vel - neighbors_vel;
QVector3D v3 = neighbors_cog - fish.pos;
QVector3D v = 1.5 * v1 + v2 + v3;
float L = .001;
fish.vel = (1-L) * fish.vel + L * v;
fish.step();
}
}
};
Banc banc;
void MainWindow::init() {
banc = Banc(10);
for (Fish &fish : banc.fishes) {
glw.meshes.append(&fish.mesh);
}
}
void MainWindow::step() {
banc.step();
OpenGLWidget::instance->update();
}
void OpenGLWidget::paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (const Fish &fish : banc.fishes) {
glUniformMatrix4fv(model_attr, 1, GL_FALSE, fish.mesh.mat.data());
glBindVertexArray(fish.mesh.vao);
glDrawArrays(GL_TRIANGLES, 0, fish.mesh.nverts);
}
}

102
src/drone_controller.cc Normal file
View File

@ -0,0 +1,102 @@
#include "drone_controller.hh"
#include <QJsonArray>
#include <QDebug>
Waypoint::Waypoint(unsigned frame, QVector3D pos)
:frame(frame),
pos(pos) {}
Waypoint::Waypoint(const QJsonObject &json)
:Waypoint(json["frame"].toInt(),
QVector3D(json["position"]["lng_X"].toInt(),
json["position"]["alt_Y"].toInt(),
json["position"]["lat_Z"].toInt())) {}
Drone::Drone(const QJsonObject &json) {
QJsonArray ja = json["waypoints"].toArray();
waypoints.reserve(ja.size());
for (const QJsonValue &o : ja) {
waypoints.append(Waypoint(o.toObject()));
}
}
const QVector<Waypoint> Drone::getWaypoints() const {
return waypoints;
}
DroneController::DroneController(const QJsonObject &json)
:framerate(json["framerate"].toInt()) {
// TODO: REMOVE!!
framerate = 1;
QJsonArray ja = json["drones"].toArray();
drones.reserve(ja.size());
for (const QJsonValue &o : ja) {
drones.append(Drone(o.toObject()));
}
for (const Drone &d : drones) {
for (const Waypoint &wp : d.getWaypoints()) {
if (wp.frame > duration) duration = wp.frame;
}
}
connect(&timer, &QTimer::timeout, this, &DroneController::step);
pause();
}
DroneController::~DroneController() {
}
int DroneController::getDuration() const {
return duration;
}
void DroneController::step() {
qDebug() << "frame " << frame << "/" << duration
<< " (" << (double) frame / duration * 100 << "%)";
emit frameChanged(frame);
frame++;
}
void DroneController::play() {
paused = false;
timer.start(1000. / framerate);
qDebug() << "playing";
}
void DroneController::pause() {
paused = true;
timer.stop();
qDebug() << "pausing";
}
void DroneController::suspend() {
bool old_paused = paused;
pause();
paused = old_paused;
}
void DroneController::resume() {
if (!paused) play();
}
void DroneController::seek(int frame) {
if (this->frame == frame) return;
this->frame = frame;
step();
}

57
src/drone_controller.hh Normal file
View File

@ -0,0 +1,57 @@
#ifndef DRONE_CONTROLLER_HH
#define DRONE_CONTROLLER_HH
#include <QJsonObject>
#include <QVector3D>
#include <QTimer>
struct Waypoint {
int frame;
QVector3D pos;
Waypoint(unsigned frame, QVector3D pos);
Waypoint(const QJsonObject &json);
};
class Drone {
QVector<Waypoint> waypoints;
public:
Drone(const QJsonObject &json);
const QVector<Waypoint> getWaypoints() const;
};
class DroneController : public QObject {
Q_OBJECT
int framerate;
int frame = 0;
int duration = 0;
QVector<Drone> drones;
QTimer timer;
bool paused = true;
public:
DroneController(const QJsonObject &json);
~DroneController();
int getDuration() const;
signals:
void frameChanged(int frame);
private slots:
void step();
public slots:
void play();
void pause();
void suspend();
void resume();
void seek(int frame);
};
#endif

11
src/main.cc Normal file
View File

@ -0,0 +1,11 @@
#include "main_window.hh"
#include <QApplication>
int main(int argc, char *argv[]) {
QApplication app(argc, argv);
MainWindow mw;
mw.show();
return app.exec();
}

73
src/main_window.cc Normal file
View File

@ -0,0 +1,73 @@
#include "main_window.hh"
#include <QApplication>
#include <QFile>
#include <QFileDialog>
#include <QJsonDocument>
#include <QStyle>
MainWindow::MainWindow(QWidget *parent) {
(void) parent;
connect(&glw, &OpenGLWidget::initialized,
this, &MainWindow::onOpenGLWidgetInitialized);
// connect(&timer, &QTimer::timeout, this, &MainWindow::step);
setCentralWidget(&glw);
addToolBar(Qt::TopToolBarArea, &top_tb);
open_action = top_tb.addAction("Ouvrir…", [&]() {
open(QFileDialog::getOpenFileName(this, "Ouvrir un fichier JSON"));
});
open_action->setEnabled(false);
addToolBar(Qt::BottomToolBarArea, &bottom_tb);
playpause_action = bottom_tb.addAction(style()->standardIcon(QStyle::SP_MediaPlay), "",
this, &MainWindow::play);
playpause_action->setEnabled(false);
slider = new QSlider(Qt::Horizontal);
bottom_tb.addWidget(slider);
slider->setEnabled(false);
}
void MainWindow::play() {
dc->play();
playpause_action->setIcon(style()->standardIcon(QStyle::SP_MediaPause));
disconnect(playpause_action, &QAction::triggered, nullptr, nullptr);
connect(playpause_action, &QAction::triggered, this, &MainWindow::pause);
}
void MainWindow::pause() {
dc->pause();
playpause_action->setIcon(style()->standardIcon(QStyle::SP_MediaPlay));
disconnect(playpause_action, &QAction::triggered, nullptr, nullptr);
connect(playpause_action, &QAction::triggered, this, &MainWindow::play);
}
void MainWindow::open(const QString &path) {
QFile file(path);
if (!file.open(QIODevice::ReadOnly)) {
qWarning("Impossible douvrir le fichier.");
return;
}
QByteArray data = file.readAll();
QJsonDocument json_doc = QJsonDocument::fromJson(data);
if (dc) delete dc;
dc = new DroneController(json_doc.object());
playpause_action->setEnabled(true);
slider->setMinimum(0);
slider->setMaximum(dc->getDuration());
connect(slider, &QSlider::sliderPressed, dc, &DroneController::suspend);
connect(slider, &QSlider::sliderReleased, dc, &DroneController::resume);
connect(slider, &QSlider::valueChanged, dc, &DroneController::seek);
connect(dc, &DroneController::frameChanged, slider, &QSlider::setValue);
slider->setEnabled(true);
}
void MainWindow::onOpenGLWidgetInitialized() {
if (qApp->arguments().size() == 2) {
open(qApp->arguments().at(1));
}
open_action->setEnabled(true);
}

36
src/main_window.hh Normal file
View File

@ -0,0 +1,36 @@
#ifndef MAIN_WINDOW_HH
#define MAIN_WINDOW_HH
#include "opengl_widget.hh"
#include "drone_controller.hh"
#include <QMainWindow>
#include <QTimer>
#include <QToolBar>
#include <QSlider>
class MainWindow : public QMainWindow {
Q_OBJECT
OpenGLWidget glw;
QTimer timer;
QToolBar top_tb;
QToolBar bottom_tb;
QAction *open_action;
QAction *playpause_action;
QSlider *slider;
DroneController *dc = nullptr;
void play();
void pause();
public:
MainWindow(QWidget *parent=nullptr);
void open(const QString &path);
private slots:
void onOpenGLWidgetInitialized();
};
#endif

19
src/opengl_mesh.cc Normal file
View File

@ -0,0 +1,19 @@
#include "opengl_mesh.hh"
#include "opengl_widget.hh"
OpenGLMesh::OpenGLMesh(QVector<float> verts) {
OpenGLWidget::instance->makeCurrent();
QOpenGLFunctions_4_4_Core *glf = OpenGLWidget::instance;
nverts = verts.size() / 3;
glf->glGenVertexArrays(1, &vao);
glf->glGenBuffers(1, &vbo);
glf->glBindVertexArray(vao);
glf->glBindBuffer(GL_ARRAY_BUFFER, vbo);
glf->glBufferData(GL_ARRAY_BUFFER, nverts * 3 * sizeof (GLfloat), verts.data(), GL_STATIC_DRAW);
glf->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0);
glf->glEnableVertexAttribArray(0);
glf->glBindVertexArray(0);
OpenGLWidget::instance->doneCurrent();
}

18
src/opengl_mesh.hh Normal file
View File

@ -0,0 +1,18 @@
#ifndef MESH_HH
#define MESH_HH
#include <QMatrix4x4>
#include <QVector>
#include <QOpenGLFunctions>
struct OpenGLMesh {
GLuint vao, vbo;
unsigned nverts;
QMatrix4x4 mat;
OpenGLMesh(QVector<float> verts);
};
#endif

143
src/opengl_widget.cc Normal file
View File

@ -0,0 +1,143 @@
#include "opengl_widget.hh"
static const GLchar *vertex_shader_source = R"glsl(
#version 330 core
layout(location = 0) in vec3 pos;
uniform mat4 proj;
uniform mat4 view;
uniform mat4 model;
void main() {
gl_Position = proj * view * model * vec4(pos, 1.0);
}
)glsl";
static const GLchar *fragment_shader_source = R"glsl(
#version 330 core
out vec4 final_col;
void main() {
final_col = vec4(0, 0, 0, 1);
}
)glsl";
static void GLAPIENTRY opengl_debug_cb(GLenum source, GLenum type, GLuint id,
GLenum severity, GLsizei length,
const GLchar* message,
const void* userParam) {
(void) source; (void) type; (void) id; (void) severity; (void) length;
(void) userParam;
qDebug() << "OpenGL debug output:" << message;
}
OpenGLWidget *OpenGLWidget::instance = nullptr;
OpenGLWidget::OpenGLWidget(QWidget *parent)
:QOpenGLWidget(parent) {
OpenGLWidget::instance = this;
}
OpenGLWidget::~OpenGLWidget() {
OpenGLWidget::instance = nullptr;
}
void OpenGLWidget::initializeGL() {
initializeOpenGLFunctions();
GLint major, minor;
glGetIntegerv(GL_MAJOR_VERSION, &major);
glGetIntegerv(GL_MINOR_VERSION, &minor);
qDebug("OpenGL version %d.%d", major, minor);
glEnable(GL_DEBUG_OUTPUT);
glDebugMessageCallback(opengl_debug_cb, 0);
/* Compile the vertex shader. */
GLuint vertex_shader = glCreateShader(GL_VERTEX_SHADER);
glShaderSource(vertex_shader, 1, &vertex_shader_source, NULL);
glCompileShader(vertex_shader);
GLint status;
glGetShaderiv(vertex_shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
char log[1024];
glGetShaderInfoLog(vertex_shader, sizeof log, NULL, log);
fprintf(stderr, "Failed to compile the vertex shader: %s\n", log);
exit(1);
}
/* Compile the fragment shader. */
GLuint fragment_shader = glCreateShader(GL_FRAGMENT_SHADER);
glShaderSource(fragment_shader, 1, &fragment_shader_source, NULL);
glCompileShader(fragment_shader);
glGetShaderiv(fragment_shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
char log[1024];
glGetShaderInfoLog(fragment_shader, sizeof log, NULL, log);
fprintf(stderr, "Failed to compile the fragment shader: %s\n", log);
exit(1);
}
/* Link the shader program. */
GLuint shader_program = glCreateProgram();
glAttachShader(shader_program, vertex_shader);
glAttachShader(shader_program, fragment_shader);
glBindFragDataLocation(shader_program, 0, "out_color");
glLinkProgram(shader_program);
glGetProgramiv(shader_program, GL_LINK_STATUS, &status);
if (status != GL_TRUE) {
char log[1024];
glGetProgramInfoLog(shader_program, sizeof log, NULL, log);
fprintf(stderr, "Failed to link the shader program: %s\n", log);
exit(1);
}
/* Use it. */
glUseProgram(shader_program);
/* Get the position attribute. */
pos_attr = glGetAttribLocation(shader_program, "pos");
proj_attr = glGetUniformLocation(shader_program, "proj");
view_attr = glGetUniformLocation(shader_program, "view");
model_attr = glGetUniformLocation(shader_program, "model");
QMatrix4x4 view;
view.translate(0, 0, 5);
glUniformMatrix4fv(view_attr, 1, GL_FALSE, view.data());
QMatrix4x4 trans;
trans.translate(0, 0, -5);
glUniformMatrix4fv(view_attr, 1, GL_FALSE, trans.data());
glClearColor(1, 1, 1, 0);
glEnable(GL_DEPTH_TEST);
glEnable(GL_MULTISAMPLE);
emit initialized();
}
void OpenGLWidget::resizeGL(int w, int h) {
QMatrix4x4 projection;
projection.perspective(FOV, (float) w/h, .1, 100);
glUniformMatrix4fv(proj_attr, 1, GL_FALSE, projection.data());
}
void OpenGLWidget::paintGL() {
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
for (const OpenGLMesh &mesh : meshes) {
glUniformMatrix4fv(model_attr, 1, GL_FALSE, mesh.mat.data());
glBindVertexArray(mesh.vao);
glDrawArrays(GL_TRIANGLES, 0, mesh.nverts);
}
}

35
src/opengl_widget.hh Normal file
View File

@ -0,0 +1,35 @@
#ifndef OPENGL_WIDGET_HH
#define OPENGL_WIDGET_HH
#include "opengl_mesh.hh"
#include <QOpenGLWidget>
#include <QMatrix4x4>
#include <QOpenGLFunctions_4_4_Core>
#include <QOpenGLShaderProgram>
#define FOV 70
class OpenGLWidget : public QOpenGLWidget, public QOpenGLFunctions_4_4_Core {
Q_OBJECT
GLuint pos_attr, proj_attr, view_attr, model_attr;
public:
static OpenGLWidget *instance;
QVector<OpenGLMesh> meshes;
OpenGLWidget(QWidget *parent=nullptr);
~OpenGLWidget();
void initializeGL() override;
void resizeGL(int w, int h) override;
void paintGL() override;
signals:
void initialized();
};
#endif

1
waypoints.json Normal file

File diff suppressed because one or more lines are too long