From 47cd8a592ecad52c1b01f27d23476c0a5afeb7f1 Mon Sep 17 00:00:00 2001 From: Sebastian Park Date: Wed, 10 Apr 2024 02:45:04 -0400 Subject: initial --- wave-sim/src/glwidget.cpp | 194 ++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 194 insertions(+) create mode 100755 wave-sim/src/glwidget.cpp (limited to 'wave-sim/src/glwidget.cpp') 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 +#include +#include + +#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(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(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(); +} -- cgit v1.2.3-70-g09d2