156 lines
4.4 KiB
C++
156 lines
4.4 KiB
C++
#include "model_offscreen_render.h"
|
|
#include "model_opengl_object.h"
|
|
#include "model_opengl_program.h"
|
|
|
|
ModelOffscreenRender::ModelOffscreenRender(const QSurfaceFormat& format, QScreen* targetScreen)
|
|
: QOffscreenSurface(targetScreen)
|
|
, m_context(nullptr)
|
|
, m_mesh(nullptr)
|
|
{
|
|
setFormat(format);
|
|
create();
|
|
}
|
|
|
|
ModelOffscreenRender::~ModelOffscreenRender()
|
|
{
|
|
// FIXME: If delete m_renderFbo inside toImage,
|
|
// 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;
|
|
|
|
destroy();
|
|
delete m_mesh;
|
|
}
|
|
|
|
void ModelOffscreenRender::setXRotation(int angle)
|
|
{
|
|
m_xRot = angle;
|
|
}
|
|
|
|
void ModelOffscreenRender::setYRotation(int angle)
|
|
{
|
|
m_yRot = angle;
|
|
}
|
|
|
|
void ModelOffscreenRender::setZRotation(int angle)
|
|
{
|
|
m_zRot = angle;
|
|
}
|
|
|
|
void ModelOffscreenRender::setEyePosition(const QVector3D& eyePosition)
|
|
{
|
|
m_eyePosition = eyePosition;
|
|
}
|
|
|
|
void ModelOffscreenRender::setMoveToPosition(const QVector3D& moveToPosition)
|
|
{
|
|
m_moveToPosition = moveToPosition;
|
|
}
|
|
|
|
void ModelOffscreenRender::setRenderThread(QThread* thread)
|
|
{
|
|
moveToThread(thread);
|
|
}
|
|
|
|
void ModelOffscreenRender::updateMesh(ModelMesh* mesh)
|
|
{
|
|
delete m_mesh;
|
|
m_mesh = mesh;
|
|
}
|
|
|
|
QImage ModelOffscreenRender::toImage(const QSize& size)
|
|
{
|
|
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();
|
|
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 colorTextureImage = std::unique_ptr<QImage>(nullptr != m_mesh ? m_mesh->takeTextureImage() : nullptr);
|
|
|
|
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);
|
|
if (nullptr != colorTextureImage)
|
|
program->updateTextureImage(std::move(colorTextureImage));
|
|
program->bind();
|
|
program->bindMaps();
|
|
|
|
program->setUniformValue(program->getUniformLocationByName("eyePosition"), m_eyePosition);
|
|
program->setUniformValue(program->getUniformLocationByName("projectionMatrix"), projection);
|
|
program->setUniformValue(program->getUniformLocationByName("modelMatrix"), world);
|
|
program->setUniformValue(program->getUniformLocationByName("normalMatrix"), world.normalMatrix());
|
|
program->setUniformValue(program->getUniformLocationByName("viewMatrix"), camera);
|
|
|
|
object->draw();
|
|
|
|
program->releaseMaps();
|
|
|
|
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;
|
|
}
|