polyvox/examples/common/OpenGLWidget.cpp
Matt Williams c26686476d Use Qt's resource system to store the shader source
The shader source is included inside each comipled binary file. The
OpenGL example also provides its own shader files which overrides
the default. Common shader code is in the 'common' directory and
each example's custom shader is alongside the example's C++ code.
2014-05-28 10:29:05 +01:00

196 lines
6.7 KiB
C++

#include "OpenGLWidget.h"
#include <QMouseEvent>
#include <QMatrix4x4>
#include <QCoreApplication>
//#include <QtMath>
using namespace PolyVox;
using namespace std;
////////////////////////////////////////////////////////////////////////////////
// Public functions
////////////////////////////////////////////////////////////////////////////////
OpenGLWidget::OpenGLWidget(QWidget *parent)
:QGLWidget(parent)
,m_viewableRegion(PolyVox::Region(0, 0, 0, 255, 255, 255))
,m_xRotation(0)
,m_yRotation(0)
{
}
void OpenGLWidget::setShader(QSharedPointer<QGLShaderProgram> shader)
{
mShader = shader;
}
void OpenGLWidget::setViewableRegion(PolyVox::Region viewableRegion)
{
m_viewableRegion = viewableRegion;
// The user has specifed a new viewable region
// so we need to regenerate our camera matrix.
setupWorldToCameraMatrix();
}
void OpenGLWidget::mousePressEvent(QMouseEvent* event)
{
// Initialise these variables which will be used when the mouse actually moves.
m_CurrentMousePos = event->pos();
m_LastFrameMousePos = m_CurrentMousePos;
}
void OpenGLWidget::mouseMoveEvent(QMouseEvent* event)
{
// Update the x and y rotations based on the mouse movement.
m_CurrentMousePos = event->pos();
QPoint diff = m_CurrentMousePos - m_LastFrameMousePos;
m_xRotation += diff.x();
m_yRotation += diff.y();
m_LastFrameMousePos = m_CurrentMousePos;
// The camera rotation has changed so we need to regenerate the matrix.
setupWorldToCameraMatrix();
// Re-render.
update();
}
////////////////////////////////////////////////////////////////////////////////
// Protected functions
////////////////////////////////////////////////////////////////////////////////
void OpenGLWidget::initializeGL()
{
GLenum err = glewInit();
if (GLEW_OK != err)
{
/* Problem: glewInit failed, something is seriously wrong. */
std::cout << "GLEW Error: " << glewGetErrorString(err) << std::endl;
}
//Print out some information about the OpenGL implementation.
std::cout << "OpenGL Implementation Details:" << std::endl;
if(glGetString(GL_VENDOR))
std::cout << "\tGL_VENDOR: " << glGetString(GL_VENDOR) << std::endl;
if(glGetString(GL_RENDERER))
std::cout << "\tGL_RENDERER: " << glGetString(GL_RENDERER) << std::endl;
if(glGetString(GL_VERSION))
std::cout << "\tGL_VERSION: " << glGetString(GL_VERSION) << std::endl;
if(glGetString(GL_SHADING_LANGUAGE_VERSION))
std::cout << "\tGL_SHADING_LANGUAGE_VERSION: " << glGetString(GL_SHADING_LANGUAGE_VERSION) << std::endl;
//Set up the clear colour
glClearColor(0.0f, 0.0f, 0.0f, 0.0f);
glClearDepth(1.0f);
glEnable(GL_DEPTH_TEST);
glDepthMask(GL_TRUE);
glDepthFunc(GL_LEQUAL);
glDepthRange(0.0, 1.0);
mShader = QSharedPointer<QGLShaderProgram>(new QGLShaderProgram);
// This is basically a simple fallback vertex shader which does the most basic rendering possible.
// PolyVox examples are able to provide their own shaders to demonstrate certain effects if desired.
if (!mShader->addShaderFromSourceFile(QGLShader::Vertex, ":/example.vert"))
{
std::cerr << mShader->log().toStdString() << std::endl;
exit(EXIT_FAILURE);
}
// This is basically a simple fallback fragment shader which does the most basic rendering possible.
// PolyVox examples are able to provide their own shaders to demonstrate certain effects if desired.
if (!mShader->addShaderFromSourceFile(QGLShader::Fragment, ":/example.frag"))
{
std::cerr << mShader->log().toStdString() << std::endl;
exit(EXIT_FAILURE);
}
// Bind the position semantic - this is defined in the vertex shader above.
mShader->bindAttributeLocation("position", 0);
// Bind the other semantics. Note that these don't actually exist in our example shader above! However, other
// example shaders may choose to provide them and having the binding code here does not seem to cause any problems.
mShader->bindAttributeLocation("normal", 1);
mShader->bindAttributeLocation("material", 2);
if (!mShader->link())
{
std::cerr << mShader->log().toStdString() << std::endl;
exit(EXIT_FAILURE);
}
// Initial setup of camera.
setupWorldToCameraMatrix();
}
void OpenGLWidget::resizeGL(int w, int h)
{
//Setup the viewport
glViewport(0, 0, w, h);
auto aspectRatio = w / (float)h;
float zNear = 1.0;
float zFar = 1000.0;
cameraToClipMatrix.setToIdentity();
cameraToClipMatrix.frustum(-aspectRatio, aspectRatio, -1, 1, zNear, zFar);
}
void OpenGLWidget::paintGL()
{
//Clear the screen
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Our example framework only uses a single shader for the scene (for all meshes).
mShader->bind();
// These two matrices are constant for all meshes.
mShader->setUniformValue("worldToCameraMatrix", worldToCameraMatrix);
mShader->setUniformValue("cameraToClipMatrix", cameraToClipMatrix);
// Iterate over each mesh which the user added to our list, and render it.
for (OpenGLMeshData meshData : mMeshData)
{
//Set up the model matrrix based on provided translation and scale.
QMatrix4x4 modelToWorldMatrix;
modelToWorldMatrix.translate(meshData.translation);
modelToWorldMatrix.scale(meshData.scale);
mShader->setUniformValue("modelToWorldMatrix", modelToWorldMatrix);
// Bind the vertex array for the current mesh
glBindVertexArray(meshData.vertexArrayObject);
// Draw the mesh
glDrawElements(GL_TRIANGLES, meshData.noOfIndices, GL_UNSIGNED_INT, 0);
// Unbind the vertex array.
glBindVertexArray(0);
}
// We're done with the shader for this frame.
mShader->release();
// Check for errors.
GLenum errCode = glGetError();
if(errCode != GL_NO_ERROR)
{
std::cerr << "OpenGL Error: " << errCode << std::endl;
}
}
////////////////////////////////////////////////////////////////////////////////
// Private functions
////////////////////////////////////////////////////////////////////////////////
void OpenGLWidget::setupWorldToCameraMatrix()
{
QVector3D lowerCorner(m_viewableRegion.getLowerX(), m_viewableRegion.getLowerY(), m_viewableRegion.getLowerZ());
QVector3D upperCorner(m_viewableRegion.getUpperX(), m_viewableRegion.getUpperY(), m_viewableRegion.getUpperZ());
QVector3D centerPoint = (lowerCorner + upperCorner) * 0.5;
float fDiagonalLength = (upperCorner - lowerCorner).length();
worldToCameraMatrix.setToIdentity();
worldToCameraMatrix.translate(0, 0, -fDiagonalLength / 2.0f); //Move the camera back by the required amount
worldToCameraMatrix.rotate(m_xRotation, 0, 1, 0); //rotate around y-axis
worldToCameraMatrix.rotate(m_yRotation, 1, 0, 0); //rotate around x-axis
worldToCameraMatrix.translate(-centerPoint); //centre the model on the origin
}