You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

481 lines
14 KiB

#include <QImageReader>
#include <QOpenGLFunctions>
#include <QOpenGLBuffer>
#include "OpenGLHandler.h"
OpenGLHandler::OpenGLHandler() : _texture(QOpenGLTexture::Target2D)
{
if(!_context.create())
{
qDebug() << "Can't create GL _context.";
return;
}
_surface.setFormat(_context.format());
_surface.create();
if(!_surface.isValid())
{
qDebug() << "_surface not valid.";
return;
}
if(!_context.makeCurrent(&_surface))
{
qDebug() << "Can't make _context current.";
return;
}
_image = new QImage("/home/mmt/Desktop/Projects/OpenGLOffscreen/sono.jpg");
_fbo = new QOpenGLFramebufferObject(_image->size());
_context.functions()->glViewport(0, 0, _image->width(), _image->height());
fun = new QOpenGLFunctions_3_3_Core();
if(!fun->initializeOpenGLFunctions())
{
qDebug() << "Can't init GL functions.";
return;
}
_shader = new QOpenGLShaderProgram(&_context);
loadChars();
}
bool OpenGLHandler::prepareShader(QString vertexShader, QString fragmentShader)
{
if(!_shader->addCacheableShaderFromSourceCode(QOpenGLShader::Vertex, vertexShader))
{
qDebug() << "Can't add vertex shader.";
return false;
}
if(!_shader->addCacheableShaderFromSourceCode(QOpenGLShader::Fragment, fragmentShader))
{
qDebug() << "Can't add fragment shader.";
return {};
}
if(!_shader->link())
{
qDebug() << "Can't link program.";
return false;
}
if(!_shader->bind())
{
qDebug() << "Can't bind program.";
return false;
}
return true;
}
bool OpenGLHandler::prepareTexture(const QImage& image)
{
_texture.setData(image);
_texture.bind();
if(!_texture.isBound())
{
qDebug() << "Texture not bound.";
return false;
}
return true;
}
bool OpenGLHandler::prepareCoords(QOpenGLBuffer vertexBuf, QOpenGLBuffer indexBuf)
{
VertexData vertices[] =
{
{{ -0.5f, +0.5f }, { 0.0f, 0.0f }}, //top-left
{{ +0.5f, +0.5f }, { 1.0f, 0.0f }}, //top-right
{{ -0.5f, -0.5f }, { 0.0f, 1.0f }}, //bottom-left
{{ +0.5f, -0.5f }, { 1.0f, 1.0f }} //bottom-right
//{{ -0.5f, +0.5f }, { 0.0f, 0.0f }}, //top-left
//{{ +0.5f, +0.5f }, { 1.0f, 0.0f }}, //top-right
//{{ -0.5f, -0.5f }, { 0.0f, 1.0f }}, //bottom-left
//{{ +0.5f, -0.5f }, { 1.0f, 1.0f }} //bottom-right
};
GLuint indices[] =
{
0, 1, 2, 3
};
if(!vertexBuf.create())
{
qDebug() << "Can't create vertex buffer.";
return {};
}
if(!indexBuf.create())
{
qDebug() << "Can't create index buffer.";
return {};
}
if(!vertexBuf.bind())
{
qDebug() << "Can't bind vertex buffer.";
return {};
}
vertexBuf.allocate(vertices, 4 * sizeof(VertexData));
if(!indexBuf.bind())
{
qDebug() << "Can't bind index buffer.";
return {};
}
indexBuf.allocate(indices, 4 * sizeof(GLuint));
return true;
}
void OpenGLHandler::loadChars()
{
if(FT_Init_FreeType(&_ft))
{
qDebug() << "ERROR::FREETYPE: Could not init FreeType Library";
}
if(FT_New_Face(_ft, "/home/mmt/.fonts/Roboto-Black.ttf", 0, &_face))
{
qDebug() << "ERROR::FREETYPE: Failed to load font";
}
FT_Set_Pixel_Sizes(_face, 0, 48);
if(FT_Load_Char(_face, 'X', FT_LOAD_RENDER))
{
qDebug() << "ERROR::FREETYTPE: Failed to load Glyph";
}
glPixelStorei(GL_UNPACK_ALIGNMENT, 1); //disable byte-alignment restriction
int i = 0;
for(unsigned char c = 0; c < 128; c++)
{
//load character glyph
if(FT_Load_Char(_face, c, FT_LOAD_RENDER))
{
qDebug() << "ERROR::FREETYTPE: Failed to load Glyph\n";
continue;
}
//// generate texture
unsigned int texture;
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RED,
_face->glyph->bitmap.width,
_face->glyph->bitmap.rows,
0,
GL_RED,
GL_UNSIGNED_BYTE,
_face->glyph->bitmap.buffer
);
//qDebug() << _face->glyph->bitmap.palette_mode;
//QImage chImage(_face->glyph->bitmap.buffer, _face->glyph->bitmap.width,
//_face->glyph->bitmap.rows,
//QImage::Format::Format_Grayscale8);
//chImage.save("/home/mmt/Desktop/chr/" + static_cast<QString>(i++) + ".png");
//// set texture options
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
//now store character for later use
Character character = {
texture,
glm::ivec2(_face->glyph->bitmap.width, _face->glyph->bitmap.rows),
glm::ivec2(_face->glyph->bitmap_left, _face->glyph->bitmap_top),
_face->glyph->advance.x
};
_characters.insert(c, character);
}
glBindTexture(GL_TEXTURE_2D, 0);
FT_Done_Face(_face);
FT_Done_FreeType(_ft);
}
void OpenGLHandler::processText()
{
QString vertexShadre =
"#version 330 core\n"
"layout (location = 4) in vec4 vertex;"
"out vec2 TexCoords;"
"uniform mat4 projection;"
"void main()"
"{"
" gl_Position = projection * vec4(vertex.xy, 0.0, 1.0);"
" TexCoords.x = vertex.z;"
" TexCoords.y = vertex.w;"
"}";
QString fragShadre =
"#version 330 core\n"
"in vec2 TexCoords;"
"out vec4 color;"
"uniform sampler2D text;"
"uniform vec3 textColor;"
"void main()"
"{"
" vec4 sampled = vec4(1.0, 1.0, 1.0, texture(text, TexCoords).r);"
" color = vec4(textColor, 1.00) * sampled;"
"}";
prepareShader(vertexShadre, fragShadre);
//_shader->link();
//_shader->bind();
//fun->glEnable(GL_CULL_FACE);
fun->glEnable(GL_BLEND);
//glBlendFunc(GL_ONE, GL_ZERO);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
QMatrix4x4 qProjection;
QRect temp(0.0f, static_cast<float>(320), 0.0f, static_cast<float>(480));
qProjection.ortho(temp);
_shader->setUniformValueArray(_shader->uniformLocation("projection"), &qProjection, 1);
fun->glGenVertexArrays(1, &chVAO);
fun->glGenBuffers(1, &chVBO);
fun->glBindVertexArray(chVAO);
fun->glBindBuffer(GL_ARRAY_BUFFER, chVBO);
fun->glBufferData(GL_ARRAY_BUFFER, sizeof(float) * 6 * 4, NULL, GL_DYNAMIC_DRAW);
fun->glEnableVertexAttribArray(4);
fun->glVertexAttribPointer(4, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(float), 0);
fun->glBindBuffer(GL_ARRAY_BUFFER, 0);
fun->glBindVertexArray(0);
RenderText("This is sample text", -0.8f, -.8f, .003f, glm::vec3(0.5, 0.8f, 0.2f));
RenderText("(C) LearnOpenGL.com", -0.5f, 0.00f, 0.005f, glm::vec3(0.3, 0.7f, 0.9f));
//glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.)
//-------------------------------------------------------------------------------
//glfwSwapBuffers(_window);
//glfwPollEvents();
auto log = _shader->log();
if(log != "")
{
qDebug() << "log : " << log;
}
fun->glDeleteVertexArrays(1, &chVAO);
fun->glDeleteBuffers(1, &chVBO);
_shader->removeAllShaders();
fun->glDisable(GL_BLEND);
glDisable(GL_CULL_FACE);
}
void OpenGLHandler::RenderText(std::string text, float x, float y, float scale, glm::vec3 color)
{
//activate corresponding render state
_shader->setUniformValue(_shader->uniformLocation("textColor"), color.x, color.y, color.z);
glActiveTexture(GL_TEXTURE0);
fun->glBindVertexArray(chVAO);
//iterate through all characters
std::string::const_iterator c;
for(c = text.begin(); c != text.end(); c++)
{
//qDebug() << "here";
Character ch = _characters[*c];
float xpos = x + ch.Bearing.x * scale;
float ypos = y - (ch.Size.y - ch.Bearing.y) * scale;
//qDebug() << "xpos = " << xpos;
float w = ch.Size.x * scale;
float h = ch.Size.y * scale;
//qDebug() << ypos + h;
//update VBO for each character
float vertices[6][4] = {
{ xpos, ypos + h, 0.0f, 0.0f },
{ xpos, ypos, 0.0f, 1.0f },
{ xpos + w, ypos, 1.0f, 1.0f },
{ xpos, ypos + h, 0.0f, 0.0f },
{ xpos + w, ypos, 1.0f, 1.0f },
{ xpos + w, ypos + h, 1.0f, 0.0f }
};
//render glyph texture over quad
glBindTexture(GL_TEXTURE_2D, ch.TextureID);
//update content of VBO memory
fun->glBindBuffer(GL_ARRAY_BUFFER, chVBO);
fun->glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices); //be sure to use
//glBufferSubData and not
//glBufferData
fun->glBindBuffer(GL_ARRAY_BUFFER, 0);
//render quad
glDrawArrays(GL_TRIANGLES, 0, 6);
//now advance cursors for next glyph (note that advance is number of 1/64 pixels)
x += (ch.Advance >> 6) * scale; //bitshift by 6 to get value in pixels (2^6 = 64 (divide
//amount of 1/64th pixels by 64 to get amount of pixels))
}
fun->glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
bool OpenGLHandler::prepareCoords2(QOpenGLBuffer vertexBuf, QOpenGLBuffer indexBuf)
{
VertexData vertices[] =
{
{{ -1.0f, +1.0f }, { 0.0f, 1.0f }}, //top-left
{{ +1.0f, +1.0f }, { 1.0f, 1.0f }}, //top-right
{{ -1.0f, -1.0f }, { 0.0f, 0.0f }}, //bottom-left
{{ +1.0f, -1.0f }, { 1.0f, 0.0f }} //bottom-right
};
GLuint indices[] =
{
0, 1, 2, 3
};
if(!vertexBuf.create())
{
qDebug() << "Can't create vertex buffer.";
return {};
}
if(!indexBuf.create())
{
qDebug() << "Can't create index buffer.";
return {};
}
if(!vertexBuf.bind())
{
qDebug() << "Can't bind vertex buffer.";
return {};
}
vertexBuf.allocate(vertices, 4 * sizeof(VertexData));
if(!indexBuf.bind())
{
qDebug() << "Can't bind index buffer.";
return {};
}
indexBuf.allocate(indices, 4 * sizeof(GLuint));
return true;
}
QString OpenGLHandler::getImage(QImage img)
{
QByteArray byteArray;
QBuffer buffer(&byteArray);
buffer.open(QIODevice::WriteOnly);
img.save(&buffer, "png");
//save image data in string
QString image("data:image/png;base64,");
image.append(QString::fromLatin1(byteArray.toBase64().data()));
return image;
}
OpenGLHandler::~OpenGLHandler()
{
delete _image;
delete _fbo;
delete _shader;
}
void OpenGLHandler::processImage(const QImage& image,
const QString& vertexShader,
const QString& fragmentShader,
const QString& textureVar,
const QString& vertexPosVar,
const QString& textureCoordVar)
{
//fun->glEnable(GL_BLEND);
bool a;
QOpenGLBuffer vertexBuf(QOpenGLBuffer::VertexBuffer);
QOpenGLBuffer indexBuf(QOpenGLBuffer::IndexBuffer);
a = prepareShader(vertexShader, fragmentShader);
a = prepareTexture(image);
a = prepareCoords(vertexBuf, indexBuf);
int offset = 0;
_shader->enableAttributeArray(vertexPosVar.toLatin1().data());
_shader->setAttributeBuffer(vertexPosVar.toLatin1().data(), GL_FLOAT, offset, 2,
sizeof(VertexData));
offset += sizeof(QVector2D);
_shader->enableAttributeArray(textureCoordVar.toLatin1().data());
_shader->setAttributeBuffer(textureCoordVar.toLatin1().data(), GL_FLOAT, offset, 2,
sizeof(VertexData));
_shader->setUniformValue(textureVar.toLatin1().data(), 0);
fun->glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, Q_NULLPTR);
_shader->disableAttributeArray(vertexPosVar.toLatin1().data());
_shader->disableAttributeArray(textureCoordVar.toLatin1().data());
_shader->disableAttributeArray(textureVar.toLatin1().data());
_shader->removeAllShaders();
}
void OpenGLHandler::flipImage()
{
QString textureVar = "texture";
QString vertexPosVar = "aPosition";
QString textureCoordVar = "aTexCoord";
QString flipVertexShader =
"attribute vec4 aPosition;\n"
"attribute vec2 aTexCoord;\n"
"varying vec2 vTexCoord;\n"
"void main()\n"
"{\n"
" gl_Position = aPosition;\n"
" vTexCoord.x = -aTexCoord.x;\n"
" vTexCoord.y = aTexCoord.y;\n"
"}";
QString flipFragmentShader =
"uniform sampler2D texture;\n"
"varying vec2 vTexCoord;\n"
"void main()\n"
"{\n"
" gl_FragColor = texture2D(texture, vTexCoord);\n"
"}";
prepareShader(flipVertexShader, "");
QOpenGLBuffer vertexBuf(QOpenGLBuffer::VertexBuffer);
QOpenGLBuffer indexBuf(QOpenGLBuffer::IndexBuffer);
prepareCoords2(vertexBuf, indexBuf);
int offset = 0;
_shader->enableAttributeArray(vertexPosVar.toLatin1().data());
_shader->setAttributeBuffer(vertexPosVar.toLatin1().data(), GL_FLOAT, offset, 2,
sizeof(VertexData));
offset += sizeof(QVector2D);
_shader->enableAttributeArray(textureCoordVar.toLatin1().data());
_shader->setAttributeBuffer(textureCoordVar.toLatin1().data(), GL_FLOAT, offset, 2,
sizeof(VertexData));
_shader->setUniformValue(textureVar.toLatin1().data(), 0);
fun->glDrawElements(GL_TRIANGLE_STRIP, 4, GL_UNSIGNED_INT, Q_NULLPTR);
_shader->disableAttributeArray(vertexPosVar.toLatin1().data());
_shader->disableAttributeArray(textureCoordVar.toLatin1().data());
_shader->disableAttributeArray(textureVar.toLatin1().data());
_shader->removeAllShaders();
}
void OpenGLHandler::run()
{
//fun->glClearColor(0, 1, 1, 1);
//fun->glClear(GL_COLOR_BUFFER_BIT);
processImage(*_image, vertexShader, fragmentShader, "texture", "aPosition",
"aTexCoord");
processText();
//flipImage();
auto ret = _fbo->toImage(true);
//auto address = getImage(ret);
ret.save("/home/mmt/Desktop/test.png");
}