dust3d/application/sources/model_offscreen_render.cc

152 lines
4.2 KiB
C++
Raw Normal View History

2022-09-19 13:30:03 +00:00
#include "model_offscreen_render.h"
2022-09-23 17:33:55 +00:00
#include "model_opengl_object.h"
#include "model_opengl_program.h"
2022-09-19 13:30:03 +00:00
ModelOffscreenRender::ModelOffscreenRender(const QSurfaceFormat& format, QScreen* targetScreen)
: QOffscreenSurface(targetScreen)
, m_context(nullptr)
, m_mesh(nullptr)
2022-09-19 13:30:03 +00:00
{
2022-09-23 17:33:55 +00:00
setFormat(format);
create();
2022-09-19 13:30:03 +00:00
}
ModelOffscreenRender::~ModelOffscreenRender()
{
// FIXME: If delete m_renderFbo inside toImage,
2022-09-23 17:33:55 +00:00
// sometimes, the application will freeze, maybe there are dead locks inside the destruction call
// move it here can make sure it will be deleted on the main GUI thread to avoid dead locks
delete m_renderFbo;
2022-09-23 17:33:55 +00:00
destroy();
delete m_mesh;
2022-09-19 13:30:03 +00:00
}
void ModelOffscreenRender::setXRotation(int angle)
{
2022-09-23 17:33:55 +00:00
m_xRot = angle;
2022-09-19 13:30:03 +00:00
}
void ModelOffscreenRender::setYRotation(int angle)
{
2022-09-23 17:33:55 +00:00
m_yRot = angle;
2022-09-19 13:30:03 +00:00
}
void ModelOffscreenRender::setZRotation(int angle)
{
2022-09-23 17:33:55 +00:00
m_zRot = angle;
2022-09-19 13:30:03 +00:00
}
void ModelOffscreenRender::setEyePosition(const QVector3D& eyePosition)
2022-09-19 13:30:03 +00:00
{
2022-09-23 17:33:55 +00:00
m_eyePosition = eyePosition;
2022-09-19 13:30:03 +00:00
}
void ModelOffscreenRender::setMoveToPosition(const QVector3D& moveToPosition)
2022-09-19 13:30:03 +00:00
{
2022-09-23 17:33:55 +00:00
m_moveToPosition = moveToPosition;
2022-09-19 13:30:03 +00:00
}
void ModelOffscreenRender::setRenderThread(QThread* thread)
2022-09-19 13:30:03 +00:00
{
2022-09-23 17:33:55 +00:00
moveToThread(thread);
2022-09-19 13:30:03 +00:00
}
void ModelOffscreenRender::updateMesh(ModelMesh* mesh)
2022-09-19 13:30:03 +00:00
{
2022-09-23 17:33:55 +00:00
delete m_mesh;
m_mesh = mesh;
2022-09-19 13:30:03 +00:00
}
QImage ModelOffscreenRender::toImage(const QSize& size)
2022-09-19 13:30:03 +00:00
{
2022-09-23 17:33:55 +00:00
QImage image;
if (nullptr == m_mesh)
return image;
QMatrix4x4 projection;
QMatrix4x4 world;
QMatrix4x4 camera;
world.setToIdentity();
world.rotate(m_xRot / 16.0f, 1, 0, 0);
world.rotate(m_yRot / 16.0f, 0, 1, 0);
world.rotate(m_zRot / 16.0f, 0, 0, 1);
projection.setToIdentity();
projection.translate(m_moveToPosition.x(), m_moveToPosition.y(), m_moveToPosition.z());
projection.perspective(45.0f, GLfloat(size.width()) / size.height(), 0.01f, 100.0f);
camera.setToIdentity();
camera.translate(m_eyePosition);
m_context = new QOpenGLContext();
m_context->setFormat(format());
if (!m_context->create()) {
delete m_context;
m_context = nullptr;
qDebug() << "QOpenGLContext create failed";
return image;
}
if (!m_context->makeCurrent(this)) {
delete m_context;
m_context = nullptr;
qDebug() << "QOpenGLContext makeCurrent failed";
return image;
}
QOpenGLFramebufferObjectFormat format;
format.setAttachment(QOpenGLFramebufferObject::CombinedDepthStencil);
format.setSamples(4);
format.setTextureTarget(GL_TEXTURE_2D);
format.setInternalTextureFormat(GL_RGBA32F_ARB);
m_renderFbo = new QOpenGLFramebufferObject(size, format);
m_renderFbo->bind();
QOpenGLFunctions* f = m_context->functions();
2022-09-23 17:33:55 +00:00
f->glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
f->glEnable(GL_BLEND);
f->glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
f->glEnable(GL_DEPTH_TEST);
f->glEnable(GL_CULL_FACE);
f->glViewport(0, 0, size.width(), size.height());
auto object = std::make_unique<ModelOpenGLObject>();
object->update(std::unique_ptr<ModelMesh>(m_mesh));
m_mesh = nullptr;
auto program = std::make_unique<ModelOpenGLProgram>();
program->load(m_context->format().profile() == QSurfaceFormat::CoreProfile);
program->bind();
2022-09-24 13:31:49 +00:00
program->bindMaps();
2022-09-23 17:33:55 +00:00
program->setUniformValue(program->getUniformLocationByName("eyePosition"), m_eyePosition);
program->setUniformValue(program->getUniformLocationByName("projectionMatrix"), projection);
program->setUniformValue(program->getUniformLocationByName("modelMatrix"), world);
2022-09-24 13:31:49 +00:00
program->setUniformValue(program->getUniformLocationByName("normalMatrix"), world.normalMatrix());
2022-09-23 17:33:55 +00:00
program->setUniformValue(program->getUniformLocationByName("viewMatrix"), camera);
object->draw();
2022-09-24 13:31:49 +00:00
program->releaseMaps();
2022-09-23 17:33:55 +00:00
program->release();
f->glFlush();
image = m_renderFbo->toImage();
program.reset();
object.reset();
m_renderFbo->release();
m_context->doneCurrent();
delete m_context;
m_context = nullptr;
return image;
2022-09-19 13:30:03 +00:00
}