2021-09-03 16:56:57 +00:00
|
|
|
/*##############################################################################
|
|
|
|
## Author: Shaun Reed ##
|
2023-03-12 02:02:26 +00:00
|
|
|
## Legal: All Content (c) 2023 Shaun Reed, all rights reserved ##
|
2021-09-03 16:56:57 +00:00
|
|
|
## About: MeshRenderer class for quick object creation and drawing ##
|
|
|
|
## ##
|
|
|
|
## Contact: shaunrd0@gmail.com | URL: www.shaunreed.com | GitHub: shaunrd0 ##
|
|
|
|
##############################################################################*/
|
|
|
|
|
|
|
|
#include <QImageReader>
|
|
|
|
|
2023-03-12 02:02:26 +00:00
|
|
|
#include "meshrenderer.h"
|
|
|
|
#include "scene.h"
|
|
|
|
#include "texture.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
|
|
|
|
|
|
|
// Static QHash that holds all MeshRenderer instances using their mName as keys
|
2022-08-07 17:12:12 +00:00
|
|
|
Qtk::MeshRenderer::MeshManager Qtk::MeshRenderer::sInstances;
|
2021-09-03 16:56:57 +00:00
|
|
|
|
2023-03-12 02:02:26 +00:00
|
|
|
/*******************************************************************************
|
|
|
|
* Constructors / Destructors
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
MeshRenderer::MeshRenderer(
|
|
|
|
const char * name, Vertices vertices, Indices indices, DrawMode mode) :
|
|
|
|
MeshRenderer(
|
|
|
|
name, ShapeBase(mode, std::move(vertices), std::move(indices))) {}
|
|
|
|
|
|
|
|
MeshRenderer::MeshRenderer(const char * name) :
|
|
|
|
MeshRenderer(name, Cube(QTK_DRAW_ELEMENTS)) {}
|
|
|
|
|
2022-11-24 22:26:53 +00:00
|
|
|
MeshRenderer::MeshRenderer(const char * name, const ShapeBase & shape) :
|
2023-03-12 02:02:26 +00:00
|
|
|
Object(name, shape, QTK_MESH), mVertexShader(":/shaders/multi-color.vert"),
|
|
|
|
mFragmentShader(":/shaders/multi-color.frag"), mDrawType(GL_TRIANGLES) {
|
2021-09-03 16:56:57 +00:00
|
|
|
mShape = Shape(shape);
|
|
|
|
init();
|
|
|
|
sInstances.insert(name, this);
|
|
|
|
}
|
|
|
|
|
2022-11-24 22:26:53 +00:00
|
|
|
MeshRenderer::~MeshRenderer() {
|
2023-03-12 02:02:26 +00:00
|
|
|
sInstances.remove(mName.c_str());
|
2022-11-24 22:26:53 +00:00
|
|
|
}
|
2021-09-03 16:56:57 +00:00
|
|
|
|
|
|
|
/*******************************************************************************
|
2023-03-12 02:02:26 +00:00
|
|
|
* Public Methods
|
2021-09-03 16:56:57 +00:00
|
|
|
******************************************************************************/
|
|
|
|
|
2022-11-24 22:26:53 +00:00
|
|
|
void MeshRenderer::init() {
|
|
|
|
if(mVAO.isCreated()) {
|
|
|
|
mVAO.destroy();
|
|
|
|
}
|
|
|
|
if(mProgram.isLinked()) {
|
|
|
|
mProgram.removeAllShaders();
|
|
|
|
}
|
|
|
|
if(mVBO.isCreated()) {
|
|
|
|
mVBO.destroy();
|
|
|
|
}
|
2021-09-03 16:56:57 +00:00
|
|
|
|
|
|
|
mVAO.create();
|
|
|
|
mVAO.bind();
|
|
|
|
|
|
|
|
mProgram.create();
|
2022-11-24 22:26:53 +00:00
|
|
|
mProgram.addShaderFromSourceFile(
|
|
|
|
QOpenGLShader::Vertex, mVertexShader.c_str());
|
|
|
|
mProgram.addShaderFromSourceFile(
|
|
|
|
QOpenGLShader::Fragment, mFragmentShader.c_str());
|
2021-09-03 16:56:57 +00:00
|
|
|
mProgram.link();
|
|
|
|
mProgram.bind();
|
|
|
|
|
|
|
|
mVBO.create();
|
|
|
|
mVBO.setUsagePattern(QOpenGLBuffer::StaticDraw);
|
|
|
|
mVBO.bind();
|
|
|
|
|
|
|
|
// Combine position and color data into one vector, allowing us to use one VBO
|
|
|
|
Vertices combined;
|
2022-11-24 22:26:53 +00:00
|
|
|
combined.reserve(getVertices().size() + getColors().size());
|
|
|
|
combined.insert(combined.end(), getVertices().begin(), getVertices().end());
|
|
|
|
combined.insert(combined.end(), getColors().begin(), getColors().end());
|
2021-09-03 16:56:57 +00:00
|
|
|
|
2022-11-24 22:26:53 +00:00
|
|
|
mVBO.allocate(combined.data(), combined.size() * sizeof(combined[0]));
|
2021-09-03 16:56:57 +00:00
|
|
|
|
|
|
|
// Enable position attribute
|
|
|
|
mProgram.enableAttributeArray(0);
|
2022-11-24 22:26:53 +00:00
|
|
|
mProgram.setAttributeBuffer(0, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
2021-09-03 16:56:57 +00:00
|
|
|
// Enable color attribute, setting offset to total size of vertices()
|
|
|
|
mProgram.enableAttributeArray(1);
|
2022-11-24 22:26:53 +00:00
|
|
|
mProgram.setAttributeBuffer(
|
|
|
|
1, GL_FLOAT, getVertices().size() * sizeof(getVertices()[0]), 3,
|
|
|
|
sizeof(QVector3D));
|
2021-09-03 16:56:57 +00:00
|
|
|
|
|
|
|
mVBO.release();
|
|
|
|
|
|
|
|
mProgram.release();
|
|
|
|
mVAO.release();
|
|
|
|
}
|
|
|
|
|
2022-11-24 22:26:53 +00:00
|
|
|
void MeshRenderer::draw() {
|
|
|
|
bindShaders();
|
2021-09-03 16:56:57 +00:00
|
|
|
mVAO.bind();
|
|
|
|
|
2022-11-24 22:26:53 +00:00
|
|
|
if(mTexture.hasTexture()) {
|
|
|
|
mTexture.getOpenGLTexture().bind();
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// TODO: Automate uniforms some other way
|
|
|
|
setUniformMVP();
|
|
|
|
|
2022-11-24 22:26:53 +00:00
|
|
|
if(mShape.mDrawMode == QTK_DRAW_ARRAYS) {
|
|
|
|
glDrawArrays(mDrawType, 0, getVertices().size());
|
|
|
|
} else if(
|
|
|
|
mShape.mDrawMode == QTK_DRAW_ELEMENTS
|
|
|
|
|| mShape.mDrawMode == QTK_DRAW_ELEMENTS_NORMALS) {
|
|
|
|
glDrawElements(
|
|
|
|
mDrawType, mShape.mIndices.size(), GL_UNSIGNED_INT,
|
|
|
|
mShape.mIndices.data());
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
|
2022-11-24 22:26:53 +00:00
|
|
|
if(mTexture.hasTexture()) {
|
|
|
|
mTexture.getOpenGLTexture().release();
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
mVAO.release();
|
2022-11-24 22:26:53 +00:00
|
|
|
releaseShaders();
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
|
2023-03-12 02:02:26 +00:00
|
|
|
void MeshRenderer::enableAttributeArray(int location) {
|
2022-11-24 22:26:53 +00:00
|
|
|
ShaderBindScope lock(&mProgram, mBound);
|
2023-03-12 02:02:26 +00:00
|
|
|
mVAO.bind();
|
|
|
|
mProgram.enableAttributeArray(location);
|
|
|
|
mVAO.release();
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
|
2022-11-24 22:26:53 +00:00
|
|
|
void MeshRenderer::reallocateTexCoords(const TexCoords & t, unsigned dims) {
|
|
|
|
mVAO.bind();
|
|
|
|
mNBO.destroy();
|
|
|
|
mNBO.create();
|
|
|
|
mNBO.bind();
|
|
|
|
mNBO.allocate(t.data(), t.size() * sizeof(t[0]));
|
|
|
|
enableAttributeArray(1);
|
|
|
|
if(dims == 2) {
|
|
|
|
setAttributeBuffer(1, GL_FLOAT, 0, 2, sizeof(QVector2D));
|
|
|
|
} else if(dims == 3) {
|
|
|
|
setAttributeBuffer(1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
|
|
|
}
|
|
|
|
mNBO.release();
|
|
|
|
mVAO.release();
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
|
2022-11-24 22:26:53 +00:00
|
|
|
void MeshRenderer::reallocateNormals(const Normals & n, unsigned dims) {
|
|
|
|
// TODO: Store state to track if buffer objects are bound
|
|
|
|
mVAO.bind();
|
|
|
|
mNBO.destroy();
|
|
|
|
mNBO.create();
|
|
|
|
mNBO.bind();
|
|
|
|
mNBO.allocate(n.data(), n.size() * sizeof(n[0]));
|
|
|
|
enableAttributeArray(1);
|
|
|
|
if(dims == 2) {
|
|
|
|
setAttributeBuffer(1, GL_FLOAT, 0, 2, sizeof(QVector2D));
|
|
|
|
} else if(dims == 3) {
|
|
|
|
setAttributeBuffer(1, GL_FLOAT, 0, 3, sizeof(QVector3D));
|
|
|
|
}
|
|
|
|
mNBO.release();
|
|
|
|
mVAO.release();
|
2021-09-03 16:56:57 +00:00
|
|
|
}
|
|
|
|
|
2023-03-12 02:02:26 +00:00
|
|
|
void MeshRenderer::setShaders(
|
|
|
|
const std::string & vert, const std::string & frag) {
|
|
|
|
mVertexShader = vert;
|
|
|
|
mFragmentShader = frag;
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MeshRenderer::setUniformMVP(
|
|
|
|
const char * model, const char * view, const char * projection) {
|
|
|
|
ShaderBindScope lock(&mProgram, mBound);
|
|
|
|
mProgram.setUniformValue(projection, Scene::getProjectionMatrix());
|
|
|
|
mProgram.setUniformValue(view, Scene::getViewMatrix());
|
|
|
|
mProgram.setUniformValue(model, mTransform.toMatrix());
|
|
|
|
}
|
2021-09-03 16:56:57 +00:00
|
|
|
|
2022-11-24 22:26:53 +00:00
|
|
|
void MeshRenderer::setShape(const Shape & value) {
|
2021-09-03 16:56:57 +00:00
|
|
|
Object::setShape(value);
|
|
|
|
init();
|
|
|
|
}
|
2023-03-12 02:02:26 +00:00
|
|
|
|
|
|
|
void MeshRenderer::setColor(const QVector3D & color) {
|
|
|
|
if(mShape.mColors.empty()) {
|
|
|
|
for(const auto & vertex : mShape.getVertices()) {
|
|
|
|
mShape.mColors.push_back(color);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for(int i = 0; i < mShape.getColors().size(); i++) {
|
|
|
|
mShape.mColors[i] = color;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// TODO: Factor this out so we don't need to reinitialize
|
|
|
|
init();
|
|
|
|
}
|
|
|
|
|
|
|
|
void MeshRenderer::setAttributeBuffer(
|
|
|
|
int location, GLenum type, int offset, int tupleSize, int stride) {
|
|
|
|
ShaderBindScope lock(&mProgram, mBound);
|
|
|
|
mVAO.bind();
|
|
|
|
mProgram.setAttributeBuffer(location, type, offset, tupleSize, stride);
|
|
|
|
mVAO.release();
|
|
|
|
}
|
|
|
|
|
|
|
|
/*******************************************************************************
|
|
|
|
* Static Public Methods
|
|
|
|
******************************************************************************/
|
|
|
|
|
|
|
|
// Static member function to retrieve instances of MeshRenderers
|
|
|
|
MeshRenderer * MeshRenderer::getInstance(const QString & name) {
|
|
|
|
if(!sInstances.contains(name)) {
|
|
|
|
#if QTK_DEBUG
|
|
|
|
qDebug() << "Attempt to access MeshRenderer instance that does not exist! ("
|
|
|
|
<< qPrintable(name) << ")\n";
|
|
|
|
#endif
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return sInstances[name];
|
|
|
|
}
|