2021-09-03 16:56:57 +00:00
|
|
|
/*##############################################################################
|
|
|
|
## Author: Shaun Reed ##
|
2022-03-06 16:54:05 +00:00
|
|
|
## Legal: All Content (c) 2022 Shaun Reed, all rights reserved ##
|
|
|
|
## About: Main window for Qt6 OpenGL widget application ##
|
2021-09-03 16:56:57 +00:00
|
|
|
## ##
|
|
|
|
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
|
|
|
##############################################################################*/
|
|
|
|
|
|
|
|
#include <QKeyEvent>
|
|
|
|
|
|
|
|
#include <input.h>
|
2022-08-21 19:37:42 +00:00
|
|
|
#include <qtkwidget.h>
|
2022-08-07 17:12:12 +00:00
|
|
|
#include <mesh.h>
|
|
|
|
#include <abstractscene.h>
|
2021-09-03 16:56:57 +00:00
|
|
|
|
2022-08-07 17:12:12 +00:00
|
|
|
using namespace Qtk;
|
2021-09-03 16:56:57 +00:00
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* Constructors, Destructors
|
|
|
|
******************************************************************************/
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
QtkWidget::QtkWidget() : mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR)
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
2022-03-13 22:00:00 +00:00
|
|
|
initializeWidget();
|
|
|
|
}
|
|
|
|
|
|
|
|
// Constructor for using this widget in QtDesigner
|
2022-08-21 19:37:42 +00:00
|
|
|
QtkWidget::QtkWidget(QWidget *parent) : QOpenGLWidget(parent),
|
2022-08-07 17:12:12 +00:00
|
|
|
mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR)
|
2022-03-13 22:00:00 +00:00
|
|
|
{
|
|
|
|
initializeWidget();
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
QtkWidget::QtkWidget(const QSurfaceFormat &format)
|
2022-08-07 17:12:12 +00:00
|
|
|
: mScene(Q_NULLPTR), mDebugLogger(Q_NULLPTR)
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
setFormat(format);
|
2022-03-13 22:00:00 +00:00
|
|
|
setFocusPolicy(Qt::ClickFocus);
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
QtkWidget::~QtkWidget()
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
makeCurrent();
|
|
|
|
teardownGL();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* Private Member Functions
|
|
|
|
******************************************************************************/
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::teardownGL()
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
// Nothing to teardown yet...
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* Inherited Virtual Member Functions
|
|
|
|
******************************************************************************/
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::paintGL()
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
// Clear buffers
|
|
|
|
glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
|
|
|
|
|
2021-09-19 18:06:41 +00:00
|
|
|
// Draw the scene first, since it handles drawing our skybox
|
2022-08-14 21:02:50 +00:00
|
|
|
if (mScene != Q_NULLPTR) mScene->draw();
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::initializeGL()
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
initializeOpenGLFunctions();
|
|
|
|
// Connect the frameSwapped signal to call the update() function
|
|
|
|
connect(this, SIGNAL(frameSwapped()), this, SLOT(update()));
|
|
|
|
|
|
|
|
// Initialize OpenGL debug context
|
|
|
|
#ifdef QTK_DEBUG
|
|
|
|
mDebugLogger = new QOpenGLDebugLogger(this);
|
|
|
|
if (mDebugLogger->initialize()) {
|
|
|
|
qDebug() << "GL_DEBUG Debug Logger" << mDebugLogger << "\n";
|
|
|
|
connect(mDebugLogger, SIGNAL(messageLogged(QOpenGLDebugMessage)),
|
|
|
|
this, SLOT(messageLogged(QOpenGLDebugMessage)));
|
|
|
|
mDebugLogger->startLogging();
|
|
|
|
}
|
|
|
|
#endif // QTK_DEBUG
|
|
|
|
|
|
|
|
printContextInformation();
|
|
|
|
|
|
|
|
// Initialize opengl settings
|
|
|
|
glEnable(GL_MULTISAMPLE);
|
|
|
|
glEnable(GL_DEPTH_TEST);
|
|
|
|
glDepthMask(GL_TRUE);
|
|
|
|
glDepthFunc(GL_LEQUAL);
|
|
|
|
glDepthRange(0.1f, 1.0f);
|
|
|
|
glClearDepth(1.0f);
|
|
|
|
glClearColor(0.0f, 0.25f, 0.0f, 0.0f);
|
|
|
|
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
|
|
|
|
}
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::resizeGL(int width, int height)
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
2021-09-19 18:06:41 +00:00
|
|
|
Scene::Projection().setToIdentity();
|
|
|
|
Scene::Projection().perspective(45.0f,
|
2021-09-03 16:56:57 +00:00
|
|
|
float(width) / float(height),
|
|
|
|
0.1f, 1000.0f);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* Protected Slots
|
|
|
|
******************************************************************************/
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::update()
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
updateCameraInput();
|
|
|
|
|
2022-08-07 17:12:12 +00:00
|
|
|
if (mScene != Q_NULLPTR) mScene->update();
|
2021-09-03 16:56:57 +00:00
|
|
|
|
|
|
|
QWidget::update();
|
|
|
|
}
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::messageLogged(const QOpenGLDebugMessage &msg)
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
QString error;
|
|
|
|
|
|
|
|
// Format based on severity
|
|
|
|
switch (msg.severity())
|
|
|
|
{
|
|
|
|
case QOpenGLDebugMessage::NotificationSeverity:
|
|
|
|
error += "--";
|
|
|
|
break;
|
|
|
|
case QOpenGLDebugMessage::HighSeverity:
|
|
|
|
error += "!!";
|
|
|
|
break;
|
|
|
|
case QOpenGLDebugMessage::MediumSeverity:
|
|
|
|
error += "!~";
|
|
|
|
break;
|
|
|
|
case QOpenGLDebugMessage::LowSeverity:
|
|
|
|
error += "~~";
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
error += " (";
|
|
|
|
|
|
|
|
// Format based on source
|
|
|
|
#define CASE(c) case QOpenGLDebugMessage::c: error += #c; break
|
|
|
|
switch (msg.source())
|
|
|
|
{
|
|
|
|
CASE(APISource);
|
|
|
|
CASE(WindowSystemSource);
|
|
|
|
CASE(ShaderCompilerSource);
|
|
|
|
CASE(ThirdPartySource);
|
|
|
|
CASE(ApplicationSource);
|
|
|
|
CASE(OtherSource);
|
|
|
|
CASE(InvalidSource);
|
|
|
|
}
|
|
|
|
#undef CASE
|
|
|
|
|
|
|
|
error += " : ";
|
|
|
|
|
|
|
|
// Format based on type
|
|
|
|
#define CASE(c) case QOpenGLDebugMessage::c: error += #c; break
|
|
|
|
switch (msg.type())
|
|
|
|
{
|
|
|
|
CASE(InvalidType);
|
|
|
|
CASE(ErrorType);
|
|
|
|
CASE(DeprecatedBehaviorType);
|
|
|
|
CASE(UndefinedBehaviorType);
|
|
|
|
CASE(PortabilityType);
|
|
|
|
CASE(PerformanceType);
|
|
|
|
CASE(OtherType);
|
|
|
|
CASE(MarkerType);
|
|
|
|
CASE(GroupPushType);
|
|
|
|
CASE(GroupPopType);
|
|
|
|
}
|
|
|
|
#undef CASE
|
|
|
|
|
|
|
|
error += ")";
|
|
|
|
qDebug() << qPrintable(error) << "\n" << qPrintable(msg.message()) << "\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* Protected Helpers
|
|
|
|
******************************************************************************/
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::keyPressEvent(QKeyEvent *event)
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
if (event->isAutoRepeat()) {
|
2022-03-13 22:00:00 +00:00
|
|
|
// Do not repeat input while a key is held down
|
2021-09-03 16:56:57 +00:00
|
|
|
event->ignore();
|
|
|
|
} else {
|
|
|
|
Input::registerKeyPress(event->key());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::keyReleaseEvent(QKeyEvent *event)
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
if (event->isAutoRepeat()) {
|
|
|
|
event->ignore();
|
|
|
|
} else {
|
|
|
|
Input::registerKeyRelease(event->key());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::mousePressEvent(QMouseEvent *event)
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
Input::registerMousePress(event->button());
|
|
|
|
}
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::mouseReleaseEvent(QMouseEvent *event)
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
Input::registerMouseRelease(event->button());
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* Private Helpers
|
|
|
|
******************************************************************************/
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::initializeWidget()
|
2022-03-13 22:00:00 +00:00
|
|
|
{
|
|
|
|
QSurfaceFormat format;
|
|
|
|
format.setRenderableType(QSurfaceFormat::OpenGL);
|
|
|
|
format.setProfile(QSurfaceFormat::CoreProfile);
|
|
|
|
format.setVersion(4, 6);
|
|
|
|
// Set the number of samples used for glEnable(GL_MULTISAMPLING)
|
|
|
|
format.setSamples(4);
|
|
|
|
// Set the size of the depth bufer for glEnable(GL_DEPTH_TEST)
|
|
|
|
format.setDepthBufferSize(16);
|
|
|
|
// If QTK_DEBUG is set, enable debug context
|
|
|
|
#ifdef QTK_DEBUG
|
|
|
|
format.setOption(QSurfaceFormat::DebugContext);
|
|
|
|
#endif
|
|
|
|
setFormat(format);
|
|
|
|
setFocusPolicy(Qt::ClickFocus);
|
|
|
|
}
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::printContextInformation()
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
QString glType;
|
|
|
|
QString glVersion;
|
|
|
|
QString glProfile;
|
|
|
|
|
|
|
|
QString glVendor;
|
|
|
|
QString glRenderer;
|
|
|
|
|
|
|
|
|
|
|
|
// Get Version Information
|
|
|
|
glType = (context()->isOpenGLES()) ? "OpenGL ES" : "OpenGL";
|
|
|
|
glVersion = reinterpret_cast<const char *>(glGetString(GL_VERSION));
|
|
|
|
glVendor =
|
|
|
|
reinterpret_cast<const char *>(glGetString(GL_VENDOR));
|
|
|
|
glRenderer =
|
|
|
|
reinterpret_cast<const char *>(glGetString(GL_RENDERER));
|
|
|
|
|
|
|
|
// Get Profile Information
|
|
|
|
#define CASE(c) case QSurfaceFormat::c: glProfile = #c; break
|
|
|
|
switch (format().profile()) {
|
|
|
|
CASE(NoProfile);
|
|
|
|
CASE(CoreProfile);
|
|
|
|
CASE(CompatibilityProfile);
|
|
|
|
}
|
|
|
|
#undef CASE
|
|
|
|
|
|
|
|
// qPrintable() will print our QString w/o quotes around it.
|
|
|
|
qDebug() << qPrintable(glType) << qPrintable(glVersion) << "("
|
|
|
|
<< qPrintable(glProfile) << ")"
|
|
|
|
<< "\nOpenGL Vendor: " << qPrintable(glVendor)
|
|
|
|
<< "\nRendering Device: " << qPrintable(glRenderer) << "\n";
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
2022-08-21 19:37:42 +00:00
|
|
|
void QtkWidget::updateCameraInput()
|
2021-09-03 16:56:57 +00:00
|
|
|
{
|
|
|
|
Input::update();
|
|
|
|
// Camera Transformation
|
|
|
|
if (Input::buttonPressed(Qt::RightButton)) {
|
|
|
|
static const float transSpeed = 0.1f;
|
|
|
|
static const float rotSpeed = 0.5f;
|
|
|
|
|
|
|
|
// Handle rotations
|
2021-09-19 18:06:41 +00:00
|
|
|
Scene::Camera().transform().rotate(-rotSpeed * Input::mouseDelta().x(),
|
2021-09-03 16:56:57 +00:00
|
|
|
Camera3D::LocalUp);
|
2021-09-19 18:06:41 +00:00
|
|
|
Scene::Camera().transform().rotate(-rotSpeed * Input::mouseDelta().y(),
|
|
|
|
Scene::Camera().right());
|
2021-09-03 16:56:57 +00:00
|
|
|
|
|
|
|
// Handle translations
|
|
|
|
QVector3D translation;
|
|
|
|
if (Input::keyPressed(Qt::Key_W)) {
|
2021-09-19 18:06:41 +00:00
|
|
|
translation += Scene::Camera().forward();
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
if (Input::keyPressed(Qt::Key_S)) {
|
2021-09-19 18:06:41 +00:00
|
|
|
translation -= Scene::Camera().forward();
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
if (Input::keyPressed(Qt::Key_A)) {
|
2021-09-19 18:06:41 +00:00
|
|
|
translation -= Scene::Camera().right();
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
if (Input::keyPressed(Qt::Key_D)) {
|
2021-09-19 18:06:41 +00:00
|
|
|
translation += Scene::Camera().right();
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
if (Input::keyPressed(Qt::Key_Q)) {
|
2021-09-19 18:06:41 +00:00
|
|
|
translation -= Scene::Camera().up() / 2.0f;
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
if (Input::keyPressed(Qt::Key_E)) {
|
2021-09-19 18:06:41 +00:00
|
|
|
translation += Scene::Camera().up() / 2.0f;
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
2021-09-19 18:06:41 +00:00
|
|
|
Scene::Camera().transform().translate(transSpeed * translation);
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
}
|