summaryrefslogtreecommitdiff
path: root/wave-sim/src/glwidget.cpp
diff options
context:
space:
mode:
authorSebastian Park <SebPark03@gmail.com>2024-04-10 02:45:04 -0400
committerSebastian Park <SebPark03@gmail.com>2024-04-10 02:45:04 -0400
commit47cd8a592ecad52c1b01f27d23476c0a5afeb7f1 (patch)
tree36b9abaff4e92a4a6df0d5ecb0e43e05c3aefd48 /wave-sim/src/glwidget.cpp
parentfd19124693bb32835ad97802ba1950cd5202dbd2 (diff)
initial
Diffstat (limited to 'wave-sim/src/glwidget.cpp')
-rwxr-xr-xwave-sim/src/glwidget.cpp194
1 files changed, 194 insertions, 0 deletions
diff --git a/wave-sim/src/glwidget.cpp b/wave-sim/src/glwidget.cpp
new file mode 100755
index 0000000..ce8af46
--- /dev/null
+++ b/wave-sim/src/glwidget.cpp
@@ -0,0 +1,194 @@
+#include "glwidget.h"
+
+#include <QApplication>
+#include <QKeyEvent>
+#include <iostream>
+
+#define SPEED 1.5
+#define ROTATE_SPEED 0.0025
+
+using namespace std;
+
+GLWidget::GLWidget(QWidget *parent) :
+ QOpenGLWidget(parent),
+ m_deltaTimeProvider(),
+ m_intervalTimer(),
+ m_sim(),
+ m_camera(),
+ m_shader(),
+ m_forward(),
+ m_sideways(),
+ m_vertical(),
+ m_lastX(),
+ m_lastY(),
+ m_capture(false)
+{
+ // GLWidget needs all mouse move events, not just mouse drag events
+ setMouseTracking(true);
+
+ // Hide the cursor since this is a fullscreen app
+ QApplication::setOverrideCursor(Qt::ArrowCursor);
+
+ // GLWidget needs keyboard focus
+ setFocusPolicy(Qt::StrongFocus);
+
+ // Function tick() will be called once per interva
+ connect(&m_intervalTimer, SIGNAL(timeout()), this, SLOT(tick()));
+}
+
+GLWidget::~GLWidget()
+{
+ if (m_shader != nullptr) delete m_shader;
+}
+
+// ================== Basic OpenGL Overrides
+
+void GLWidget::initializeGL()
+{
+ // Initialize GL extension wrangler
+ glewExperimental = GL_TRUE;
+ GLenum err = glewInit();
+ if (err != GLEW_OK) fprintf(stderr, "Error while initializing GLEW: %s\n", glewGetErrorString(err));
+ fprintf(stdout, "Successfully initialized GLEW %s\n", glewGetString(GLEW_VERSION));
+
+ // Set clear color to white
+ glClearColor(1, 1, 1, 1);
+
+ // Enable depth-testing and backface culling
+ glEnable(GL_DEPTH_TEST);
+ glEnable(GL_CULL_FACE);
+ glCullFace(GL_BACK);
+
+ // Initialize the shader and simulation
+ m_shader = new Shader(":/resources/shaders/shader.vert", ":/resources/shaders/shader.frag");
+ m_sim.init();
+
+ // Initialize camera with a reasonable transform
+ Eigen::Vector3f eye = {0, 2, -5};
+ Eigen::Vector3f target = {0, 1, 0};
+ m_camera.lookAt(eye, target);
+ m_camera.setOrbitPoint(target);
+ m_camera.setPerspective(120, width() / static_cast<float>(height()), 0.1, 50);
+
+ m_deltaTimeProvider.start();
+// m_intervalTimer.start(1);
+// m_intervalTimer.start(1000 / 60);
+ m_intervalTimer.start(1000 / 120);
+}
+
+void GLWidget::paintGL()
+{
+ glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
+ m_shader->bind();
+ m_shader->setUniform("proj", m_camera.getProjection());
+ m_shader->setUniform("view", m_camera.getView());
+ m_sim.draw(m_shader);
+ m_shader->unbind();
+}
+
+void GLWidget::resizeGL(int w, int h)
+{
+ glViewport(0, 0, w, h);
+ m_camera.setAspect(static_cast<float>(w) / h);
+}
+
+// ================== Event Listeners
+
+void GLWidget::mousePressEvent(QMouseEvent *event)
+{
+ m_capture = true;
+ m_lastX = event->position().x();
+ m_lastY = event->position().y();
+}
+
+void GLWidget::mouseMoveEvent(QMouseEvent *event)
+{
+ if (!m_capture) return;
+
+ int currX = event->position().x();
+ int currY = event->position().y();
+
+ int deltaX = currX - m_lastX;
+ int deltaY = currY - m_lastY;
+
+ if (deltaX == 0 && deltaY == 0) return;
+
+ m_camera.rotate(deltaY * ROTATE_SPEED,
+ -deltaX * ROTATE_SPEED);
+
+ m_lastX = currX;
+ m_lastY = currY;
+}
+
+void GLWidget::mouseReleaseEvent(QMouseEvent *event)
+{
+ m_capture = false;
+}
+
+void GLWidget::wheelEvent(QWheelEvent *event)
+{
+ float zoom = 1 - event->pixelDelta().y() * 0.1f / 120.f;
+ m_camera.zoom(zoom);
+}
+
+void GLWidget::keyPressEvent(QKeyEvent *event)
+{
+ if (event->isAutoRepeat()) return;
+
+ switch (event->key())
+ {
+ case Qt::Key_W: m_forward += SPEED; break;
+ case Qt::Key_S: m_forward -= SPEED; break;
+ case Qt::Key_A: m_sideways -= SPEED; break;
+ case Qt::Key_D: m_sideways += SPEED; break;
+ case Qt::Key_F: m_vertical -= SPEED; break;
+ case Qt::Key_R: m_vertical += SPEED; break;
+ case Qt::Key_C: m_camera.toggleIsOrbiting(); break;
+ case Qt::Key_T: m_sim.toggleWire(); break;
+ case Qt::Key_O: m_sim.toggleForceRender(); break;
+ case Qt::Key_Escape: QApplication::quit();
+ }
+}
+
+void GLWidget::keyReleaseEvent(QKeyEvent *event)
+{
+ if (event->isAutoRepeat()) return;
+
+ switch (event->key())
+ {
+ case Qt::Key_W: m_forward -= SPEED; break;
+ case Qt::Key_S: m_forward += SPEED; break;
+ case Qt::Key_A: m_sideways += SPEED; break;
+ case Qt::Key_D: m_sideways -= SPEED; break;
+ case Qt::Key_F: m_vertical += SPEED; break;
+ case Qt::Key_R: m_vertical -= SPEED; break;
+ }
+}
+
+// ================== Physics Tick
+
+
+void GLWidget::tick()
+{
+ float deltaSeconds = m_deltaTimeProvider.restart() / 1000.f;
+// deltaSeconds = 0.5f;
+// std::cout << deltaSeconds << std::endl;
+ // .02 is optimal, .021 disappears after 4 for sphere
+ // .015 okay for ellipsoid
+ // .001 okay for cone
+ deltaSeconds = .01;
+ deltaSeconds = .014;
+ m_sim.update(deltaSeconds);
+
+ // Move camera
+ auto look = m_camera.getLook();
+ look.y() = 0;
+ look.normalize();
+ Eigen::Vector3f perp(-look.z(), 0, look.x());
+ Eigen::Vector3f moveVec = m_forward * look.normalized() + m_sideways * perp.normalized() + m_vertical * Eigen::Vector3f::UnitY();
+ moveVec *= deltaSeconds;
+ m_camera.move(moveVec);
+
+ // Flag this view for repainting (Qt will call paintGL() soon after)
+ update();
+}