m2-ar-projet/src/drone_controller.cc

199 lines
4.6 KiB
C++

#include "drone_controller.hh"
#include "opengl_widget.hh"
#include "load_obj.hh"
#include <QJsonArray>
#include <QDebug>
#include <QOpenGLShaderProgram>
const unsigned char DroneController::sphere_neutral[] = {
166, 166, 166
};
OpenGLMesh *DroneController::sphere = nullptr;
DroneController::DroneController(const QJsonObject &json)
:framerate(json["framerate"].toInt()),
sphere_timer(this) {
sphere_timer.setSingleShot(true);
connect(&sphere_timer, &QTimer::timeout, [&]() {
draw_spheres = false;
OpenGLWidget::instance->update();
});
if (sphere == nullptr) {
OpenGLWidget::instance->makeCurrent();
sphere = new OpenGLMesh(load_obj(":/mdl/sphere.obj", LOAD_OBJ_NORMALS | LOAD_OBJ_UVS),
new QOpenGLTexture(QImage(sphere_neutral, 1, 1, QImage::Format_RGB888)),
OpenGLWidget::instance->getMainProgram());
OpenGLWidget::instance->makeCurrent();
}
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);
}
void DroneController::drawTrajectory(QOpenGLExtraFunctions *f, const Drone &d) const {
OpenGLWidget::instance->getLineProgram()->bind();
OpenGLWidget::instance->getLineProgram()->setUniformValue("color", 1, 0, .532);
size_t trajectory_len = 1;
for (const Waypoint &wp : d.getWaypoints()) {
if (wp.frame > frame) break;
trajectory_len++;
}
GLfloat trajectory[trajectory_len * 3] = {0};
size_t i = 0;
for (const Waypoint &wp : d.getWaypoints()) {
if (wp.frame > frame) break;
trajectory[i] = wp.pos.x();
trajectory[i + 1] = wp.pos.y();
trajectory[i + 2] = wp.pos.z();
i += 3;
}
trajectory[i] = d.getPos().x();
trajectory[i + 1] = d.getPos().y();
trajectory[i + 2] = d.getPos().z();
f->glEnableVertexAttribArray(0);
f->glBindBuffer(GL_ARRAY_BUFFER, 0);
f->glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, trajectory);
glLineWidth(2);
f->glDisable(GL_CULL_FACE);
f->glDrawArrays(GL_LINE_STRIP, 0, trajectory_len);
f->glEnable(GL_CULL_FACE);
OpenGLWidget::instance->getLineProgram()->release();
OpenGLWidget::instance->getMainProgram()->bind();
}
void DroneController::draw(QOpenGLExtraFunctions *f) const {
const QVector<QPair<int, int>> &col = collisions[frame];
for (const Drone &d : drones) {
QMatrix4x4 mat;
mat.translate(d.getPos());
for (const QPair<int, int> &p : col) {
if (d.getId() == p.first || d.getId() == p.second) {
OpenGLWidget::instance->getMainProgram()->setUniformValue("highlight", true);
}
}
d.getMesh()->draw(f, mat);
if (draw_spheres) {
mat.scale(sphere_radius);
sphere->draw(f, mat);
}
OpenGLWidget::instance->getMainProgram()->setUniformValue("highlight", false);
if (draw_trajectories) {
drawTrajectory(f, d);
}
}
}
int DroneController::getDuration() const {
return duration;
}
void DroneController::step() {
for (Drone &d : drones) {
d.setTo(frame);
}
OpenGLWidget::instance->update();
emit frameChanged(frame);
if (frame == duration) {
pause();
} else {
frame++;
}
}
void DroneController::play() {
if (!paused) return;
paused = false;
timer.start(1000. / framerate);
emit playing();
}
void DroneController::pause() {
if (paused) return;
paused = true;
timer.stop();
emit pausing();
}
void DroneController::suspend() {
if (!paused) {
pause();
paused = false;
}
}
void DroneController::resume() {
if (!paused) {
paused = true;
play();
}
}
void DroneController::seek(int frame) {
if (this->frame == frame) return;
this->frame = frame;
step();
}
void DroneController::computeCollisions(double sphere_radius) {
collisions.clear();
double sqDist = sphere_radius * sphere_radius * 4;
for (int i = 0; i < duration; i++) {
for (Drone &a : drones) {
a.setTo(i);
for (Drone &b : drones) {
b.setTo(i);
if (&a == &b) continue;
if (collides(a, b, sqDist)) {
collisions[i].append(QPair<int, int>(a.getId(), b.getId()));
emit collision(a.getId(), b.getId(), i);
}
}
}
}
for (Drone &d : drones) {
d.setTo(frame);
}
}
void DroneController::displaySpheres(double sphere_radius) {
draw_spheres = true;
this->sphere_radius = sphere_radius;
sphere_timer.start(1000);
OpenGLWidget::instance->update();
}
bool DroneController::collides(const Drone &a, const Drone &b, double sqDist) {
return (b.getPos() - a.getPos()).lengthSquared() < sqDist;
}
void DroneController::setDrawTrajectories(bool enable) {
draw_trajectories = enable;
OpenGLWidget::instance->update();
}