I'm trying to get data from pixel using glReadPixels.
It was working for some time. But now it stopped working and I don't know why.
I need to make Flood fill algorithm.
glBegin(GL_POINTS);
float target[3] = { 1.0, 1.0, 0.0 }; // target color
float border[3] = { 1.0, 1.0, 1.0 }; // border color
float clearp[3] = { 0.0, 0.0, 0.0 }; // clear color
std::stack<pixel*> colored; // stack with pixels
if (!stack.empty()) // stack contains first pixel
colored.push(stack.top());
while(!colored.empty()) {
pixel *p = colored.top();
glRasterPos2i(p->x, p->y);
glDrawPixels(1, 1, GL_RGB, GL_FLOAT, target);
colored.pop();
//up
float pix[3];
glReadPixels(p->x, p->y + 1, 1, 1, GL_RGB, GL_FLOAT, pix);
if (!compare(pix,border) && compare(pix,clearp)) {
pixel *pn = new pixel();
pn->x = p->x;
pn->y = p->y + 1;
colored.push(pn);
}
//down
glReadPixels(p->x, p->y - 1, 1, 1, GL_RGB, GL_FLOAT, pix);
if (!compare(pix,border) && compare(pix,clearp)) {
pixel *pn = new pixel();
pn->x = p->x;
pn->y = p->y - 1;
colored.push(pn);
}
//left
glReadPixels(p->x - 1, p->y, 1, 1, GL_RGB, GL_FLOAT, pix);
if (!compare(pix,border) && compare(pix,clearp)) {
pixel *pn = new pixel();
pn->x = p->x - 1;
pn->y = p->y;
colored.push(pn);
}
//right
glReadPixels(p->x + 1, p->y, 1, 1, GL_RGB, GL_FLOAT, pix);
if (!compare(pix,border) && compare(pix,clearp)) {
pixel *pn = new pixel();
pn->x = p->x + 1;
pn->y = p->y;
colored.push(pn);
}
}
glEnd();
But array pix does not contain RGB color data. It usually something like this -1.0737418e+008
Where is the problem? It should work fine...
It's an error to call anything but a very limited set of functions between glBegin and glEnd. That list is mostly composed of functions related to specifying attributes of a vertex (e.g., glVertex, glNormal, glColor, glTexCoord, etc.).
So, if your OpenGL implementation is following the OpenGL specification, glReadPixels should return immediately without executing because of being called within a glBegin/glEnd group. Remove those from around your calls, and glReadPixels should work as expected.
Related
So here's the thing. I'm trying to create a Text class using Freetype, which inherits from a Model class, which in turn contains stuff like setting VAO, VBOs, programs, textures, position, rotation and scaling. Here's the code for Model.cpp:
// Model.cpp
#include "Model.h"
using namespace OpenGL::Rendering;
Model::Model() {
model_matrix = glm::mat4(1.0f);
position = glm::vec3(0.0, 0.0, 0.0);
scale = glm::vec3(1.0, 1.0, 1.0);
rotation = glm::vec3(1.0, 0.0, 0.0);
rotation_angle = 0.0;
}
Model::~Model() { destroy(); }
void Model::draw() {}
void Model::set_program(GLuint program) { this->program = program; }
GLuint Model::get_vao() const { return vao; }
const std::vector<GLuint>& Model::get_vbos() const { return vbos; }
GLuint Model::get_texture(std::string texture_name) const {
if (textures.size() > 0) {
return textures.at(texture_name);
} else {
Log()->critical("No textures to get. Requested {}", texture_name);
return 0;
}
}
GLuint Model::get_texture() const {
if (textures.size() > 0) {
return textures.begin()->second;
} else {
Log()->critical("No textures to get.");
return 0;
}
}
void Model::set_texture(std::string texture_name, GLuint texture) {
if (texture == 0) {
Log()->critical("Texture {} is empty.", texture_name);
return;
} else {
textures[texture_name] = texture;
}
}
void Model::destroy() {
glDeleteVertexArrays(1, &vao);
glDeleteBuffers(vbos.size(), &vbos[0]);
vbos.clear();
if (textures.size() > 0) {
for (auto& t : textures) {
glDeleteTextures(1, &t.second);
}
textures.clear();
}
}
const glm::vec3& Model::get_position() const { return position; }
void Model::set_position(float pos_x, float pos_y, float pos_z) {
position = glm::vec3(pos_x, pos_y, pos_z);
update_model_matrix();
}
void Model::set_rotation(float angle_deg, float x, float y, float z) {
rotation_angle = angle_deg * M_PI / 180.0;
rotation = glm::vec3(x, y, z);
update_model_matrix();
}
void Model::set_scale(float sca_x, float sca_y, float sca_z) {
scale = glm::vec3(sca_x, sca_y, sca_z);
update_model_matrix();
}
void Model::update_model_matrix() {
model_matrix = glm::mat4(1.0f);
auto pos = glm::vec3(this->position.x, -this->position.y, this->position.z);
glm::mat4 translate_mat = glm::translate(glm::mat4(1.0f), pos);
glm::mat4 rotate_mat = glm::mat4(1.0f);
if (this->rotation.x != 0.0 || this->rotation.y != 0.0 || this->rotation.z != 0.0) {
rotate_mat = glm::rotate(glm::mat4(1.0f), this->rotation_angle, this->rotation);
} else {
rotate_mat =
glm::rotate(glm::mat4(1.0f), 0.0f, glm::vec3(1.0, 0.0, 0.0));
}
glm::mat4 scale_mat = glm::scale(glm::mat4(1.0f), this->scale);
this->model_matrix = translate_mat * rotate_mat * scale_mat;
glUniformMatrix4fv(glGetUniformLocation(this->program, "model_matrix"), 1,
false, &this->model_matrix[0][0]);
}
Then I have my Text class, which uses Freetype to load fonts and stuff. I know it's not optimised really, so look past that. Note that for Freetype, I'm using GL_DYNAMIC_DRAW, instead of GL_STATIC_DRAW
// Text.cpp
#include "Text.h"
using namespace OpenGL::Rendering::Models;
Text::Text(const std::string& text, OpenGL::Container::Position position,
int font_size, OpenGL::Container::Color color) {
m_font_size = font_size;
m_scale = 1.0;
m_text = text;
float angle = 0;
this->color.r = color.r;
this->color.g = color.g;
this->color.b = color.b;
this->color.a = color.a;
matrix.xx = (FT_Fixed)(cos(angle) * 0x10000L);
matrix.xy = (FT_Fixed)(-sin(angle) * 0x10000L);
matrix.yx = (FT_Fixed)(sin(angle) * 0x10000L);
matrix.yy = (FT_Fixed)(cos(angle) * 0x10000L);
this->position.x = position.x;
this->position.y = position.y;
this->position.z = position.z;
if (FT_Init_FreeType(&font)) {
Log()->critical("Could not initalize Freetype library for fonts.");
}
if (FT_New_Face(font, "/usr/share/fonts/truetype/ubuntu/Ubuntu-R.ttf", 0,
&face)) {
Log()->critical("Could not load font. File is missing maybe?");
}
FT_Set_Char_Size(face, 0, m_font_size * 64, 300, 300);
FT_Set_Pixel_Sizes(face, 0, m_font_size);
if (FT_Load_Char(face, 'X', FT_LOAD_RENDER)) {
Log()->critical(
"Could not load a test glyph. The font is corrupted maybe?");
}
for (GLubyte c = 0; c < 128; ++c) {
FT_Set_Transform(face, &matrix, 0);
if (FT_Load_Char(face, c, FT_LOAD_RENDER)) {
Log()->critical("Could not load glyph \"{}\"", c);
continue;
}
GLuint 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);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
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);
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(std::pair<GLchar, Character>(c, character));
}
FT_Done_Face(face);
FT_Done_FreeType(font);
}
void Text::create() {
GLuint vao;
GLuint vbo;
glGenVertexArrays(1, &vao);
glGenBuffers(1, &vbo);
glBindVertexArray(vao);
glBindBuffer(GL_ARRAY_BUFFER, vbo);
glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 6 * 4, NULL,
GL_DYNAMIC_DRAW);
glEnableVertexAttribArray(0);
glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 4 * sizeof(GLfloat),
(void*)0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
this->vao = vao;
this->vbos.push_back(vbo);
this->set_program(OpenGL::Managers::ShaderManager::get_program("text"));
// this->set_position(position.x, position.y, position.z);
Log()->warn("Pos {0}, {1}, {2}", position.x, position.y, position.z);
}
void Text::draw() {
GLfloat temp_x = 0;
GLfloat temp_y = 0;
glUseProgram(this->program);
glUniform4f(glGetUniformLocation(this->program, "text_color"), color.r,
color.g, color.b, color.a);
glActiveTexture(GL_TEXTURE0);
glBindVertexArray(this->vao);
std::string::const_iterator c;
for (c = m_text.begin(); c != m_text.end(); c++) {
Character ch = characters[*c];
GLfloat xpos = temp_x + ch.bearing.x * m_scale;
GLfloat ypos = temp_y - (ch.size.y - ch.bearing.y) * m_scale;
GLfloat w = ch.size.x * m_scale;
GLfloat h = ch.size.y * m_scale;
GLfloat vertices[6][4] = {
{xpos, ypos + h, 0.0, 0.0}, /**/
{xpos, ypos, 0.0, 1.0}, /**/
{xpos + w, ypos, 1.0, 1.0}, /**/
{xpos, ypos + h, 0.0, 0.0}, /**/
{xpos + w, ypos, 1.0, 1.0}, /**/
{xpos + w, ypos + h, 1.0, 0.0} /**/
};
glBindTexture(GL_TEXTURE_2D, ch.texture_id);
glBindBuffer(GL_ARRAY_BUFFER, this->vbos[0]);
glBufferSubData(GL_ARRAY_BUFFER, 0, sizeof(vertices), vertices);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glDrawArrays(GL_TRIANGLES, 0, 6);
temp_x += (ch.advance >> 6) * m_scale;
}
glUniformMatrix4fv(glGetUniformLocation(this->program, "model_matrix"), 1,
false, &model_matrix[0][0]);
glBindVertexArray(0);
glBindTexture(GL_TEXTURE_2D, 0);
}
void Text::set_text(const std::string& a_text) {
if (!a_text.empty()) {
m_text = a_text;
} else {
Log()->info("Cannot set the text. Input seems to be empty.");
}
}
std::string Text::get_text() { return m_text; }
void Text::set_color(const Container::Color a_color) {
color.r = a_color.r;
color.g = a_color.g;
color.b = a_color.b;
color.a = a_color.a;
}
So the problem is, drawing a text behaves like a pen. So when I try to set the position of text1 object, text2 object moves. text2 affects text3 and so on.
// main.cpp
// This one moves to 200, 100 as defined in text3
auto text1 = new OpenGL::Rendering::Models::Text(
"Text1", Container::Position(pos_x - 5, pos_y - radius, 0), 18,
Container::Color::YELLOW);
text1->create();
text1->set_scale(3, 3, 3);
text1->set_position(500, 500, 0);
// This line actually affects text1, as expected
text1->set_text("Blah");
// This one scales to 3 times bigger, as stated in the previous object
auto text2 = new OpenGL::Rendering::Models::Text(
"Text2", Container::Position(pos_x - radius - 10, pos_y + radius/1.5, 0), 18,
Container::Color::YELLOW);
text2->create();
text2->set_rotation(25, 0, 0, 1);
// And this one gets rotated
auto text3 = new OpenGL::Rendering::Models::Text(
"Text3", Container::Position(0, 0, 0), 125,
Container::Color::YELLOW);
text3->create();
text3->set_position(200, 100, 0);
Here's how it looks like:
Can somebody please explain this weird behaviour? The problem is, all other 2D shapes work just fine with my functions, except this Text class, which kinda affects the next object. Thank you very much in advance. If you need more information to diagnose the problem, I'll add it right away.
As mentioned in comments by #Rabbid76, moving the below line to the beginning of Text::draw() fixed the problem:
glUniformMatrix4fv(glGetUniformLocation(this->program, "model_matrix"), 1,
false, &model_matrix[0][0]);
I have a glitch in my Qt/OpenGL application when I use the Anti-Aliasing MSAA 8x. This is the screenshot with the glitch: black pixels in white lines. It looks a bad strech of the texture but I don't know how to fix it
This is the screenshot:
This is the code:
BackgroundImage.h :
class BackgroundImage
{
public:
explicit BackgroundImage(QOpenGLFunctions * GL);
virtual ~BackgroundImage();
void save(int w, int h);
void restoreToScreen();
private:
// background consts
static const int BACKGROUND_SCREEN_WIDTH_MAX = 8 * 1024;
static const int BACKGROUND_SCREEN_HEIGHT_MAX = 8 * 1024;
static const int BACKGROUND_BUFFER_SIZE_MAX = sizeof(U16) * BACKGROUND_SCREEN_WIDTH_MAX * BACKGROUND_SCREEN_HEIGHT_MAX;
// OpenGL Functions
QOpenGLFunctions * m_gl;
// rgb members
int m_width;
int m_height;
U32 m_colorTextureId;
U16 m_depthBuffer[BACKGROUND_BUFFER_SIZE_MAX / sizeof(U16)];
};
BackgroundImage.cpp :
#include "BackgroundImage.h"
#include "render.h" // glRasterPos
#include "QDebug"
BackgroundImage::BackgroundImage(QOpenGLFunctions * gl):
m_gl(gl),
m_width(0),
m_height(0),
m_colorTextureId(0),
m_multiSampledFBO(nullptr),
m_downSampledFBO(nullptr)
{}
BackgroundImage::~BackgroundImage()
{
m_gl->glDeleteTextures(1, &m_colorTextureId);
if (m_multiSampledFBO)
{
delete m_multiSampledFBO;
}
if (m_downSampledFBO)
{
delete m_downSampledFBO;
}
}
void BackgroundImage::beginSave(int w, int h)
{
if (w!=m_width || h!=m_height)
{
regenerateFBOs(w, h);
m_width = w;
m_height = h;
}
m_multiSampledFBO->bind();
m_gl->glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
}
void BackgroundImage::endSave()
{
QOpenGLFramebufferObject::blitFramebuffer(m_downSampledFBO, m_multiSampledFBO, GL_COLOR_BUFFER_BIT, GL_LINEAR);
QOpenGLFramebufferObject::blitFramebuffer(m_downSampledFBO, m_multiSampledFBO, GL_DEPTH_BUFFER_BIT, GL_NEAREST);
m_downSampledFBO->bind();
m_gl->glPixelStorei(GL_PACK_ALIGNMENT, 1);
// Fill background Image + Generate a texture
m_colorTextureId = m_downSampledFBO->texture();
m_gl->glPixelStorei(GL_PACK_ALIGNMENT, 2);
// Read Depth Buffer
m_gl->glDepthMask(GL_TRUE); // used for enable the zbuffer writing (cf . https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glDepthMask.xml)
//glRasterPos4f(0, 0, 0, 1);
m_gl->glReadPixels(0,0, m_width, m_height, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, (void*)m_depthBuffer);
m_multiSampledFBO->bindDefault();
}
void BackgroundImage::restoreToScreen()
{
m_gl->glEnable(GL_DEPTH_TEST);
m_gl->glDepthFunc(GL_LESS);
m_gl->glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT);
m_gl->glDepthFunc(GL_ALWAYS);
// render background
m_gl->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
Render::RenderImage(m_colorTextureId, 0,0, m_width, m_height);
m_gl->glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
m_gl->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
// Restore Depth Buffer
m_gl->glDepthMask(GL_TRUE); // used for enable the zbuffer writing (cf . https://www.khronos.org/registry/OpenGL-Refpages/gl2.1/xhtml/glDepthMask.xml)
m_gl->glColorMask(GL_FALSE, GL_FALSE, GL_FALSE, GL_FALSE);
m_gl->glDepthFunc(GL_ALWAYS);
m_gl->glPixelStorei(GL_PACK_ALIGNMENT, 2);
glDrawPixels(m_width, m_height, GL_DEPTH_COMPONENT, GL_UNSIGNED_SHORT, (GLvoid*) m_depthBuffer);
m_gl->glDepthFunc(GL_LESS);
m_gl->glColorMask(GL_TRUE, GL_TRUE, GL_TRUE, GL_TRUE);
}
void BackgroundImage::regenerateFBOs(int w, int h)
{
if (m_multiSampledFBO)
{
delete m_multiSampledFBO;
}
if (m_downSampledFBO)
{
delete m_downSampledFBO;
}
//MultiSampling set to 4 now
QOpenGLFramebufferObjectFormat muliSampleFormat;
muliSampleFormat.setAttachment(QOpenGLFramebufferObject::Depth);
muliSampleFormat.setMipmap(true);
muliSampleFormat.setSamples(8);
muliSampleFormat.setTextureTarget(GL_TEXTURE_2D);
muliSampleFormat.setInternalTextureFormat(GL_BGRA_EXT);
m_multiSampledFBO = new QOpenGLFramebufferObject(w,h, muliSampleFormat);
QOpenGLFramebufferObjectFormat downSampledFormat;
downSampledFormat.setAttachment(QOpenGLFramebufferObject::Depth);
downSampledFormat.setMipmap(true);
downSampledFormat.setTextureTarget(GL_TEXTURE_2D);
downSampledFormat.setInternalTextureFormat(GL_BGRA_EXT);
m_downSampledFBO = new QOpenGLFramebufferObject(w, h, downSampledFormat);
}
Render.cpp :
void Render::RenderImage(U32 tex, int x, int y, int w, int h, float anchorX, float anchorY)
{
glClear(GL_DEPTH_BUFFER_BIT);
GLboolean depth = glIsEnabled(GL_DEPTH_TEST);
if (depth)
glDisable(GL_DEPTH_TEST);
glMatrixMode(GL_PROJECTION);
glPushMatrix();
glLoadIdentity();
gluOrtho2D(0, s_width, s_height, 0);
glMatrixMode(GL_MODELVIEW);
glPushMatrix();
glLoadIdentity();
glColor3ub(255, 255, 255);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, tex);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_COLOR_ARRAY);
x -= (int)(anchorX * w);
y -= (int)(anchorY * h);
gVertices[0] = VECTOR3F(x, y, 0);
gVertices[1] = VECTOR3F(x + w - 1, y, 0);
gVertices[2] = VECTOR3F(x + w - 1, y + h - 1, 0);
gVertices[3] = VECTOR3F(x, y + h - 1, 0);
gTexCoords[0] = VECTOR2F(0, 1);
gTexCoords[1] = VECTOR2F(1, 1);
gTexCoords[2] = VECTOR2F(1, 0);
gTexCoords[3] = VECTOR2F(0, 0);
gIndexes[0] = 2;
gIndexes[1] = 1;
gIndexes[2] = 0;
gIndexes[3] = 0;
gIndexes[4] = 3;
gIndexes[5] = 2;
glVertexPointer(3, GL_FLOAT, 0, gVertices);
glTexCoordPointer(2, GL_FLOAT, 0, gTexCoords);
glDrawElements(GL_TRIANGLES, 3 * 2, GL_UNSIGNED_SHORT, gIndexes);
glDisable(GL_TEXTURE_2D);
glPopMatrix();
glMatrixMode(GL_PROJECTION);
glPopMatrix();
glMatrixMode(GL_MODELVIEW);
if (depth)
glEnable(GL_DEPTH_TEST);
}
The error is in Render::RenderImage(...)
This code ...
gVertices[0] = VECTOR3F(x, y, 0);
gVertices[1] = VECTOR3F(x + w - 1, y, 0);
gVertices[2] = VECTOR3F(x + w - 1, y + h - 1, 0);
gVertices[3] = VECTOR3F(x, y + h - 1, 0);
must be replaced by this code
gVertices[0] = VECTOR3F(x, y, 0);
gVertices[1] = VECTOR3F(x + w, y, 0);
gVertices[2] = VECTOR3F(x + w, y + h, 0);
gVertices[3] = VECTOR3F(x, y + h, 0);
I've got code for flood fill algorithm.
void floodFill() {
float target[3] = { 1.0, 1.0, 0.0 };
float border[3] = { 1.0, 1.0, 1.0 };
float clearp[3] = { 0.0, 0.0, 0.0 };
std::stack<pixel*> colored;
if (!stack.empty()) // stack contains first pixel
colored.push(stack.top());
while(!colored.empty()) {
pixel *p = colored.top();
drawPixel(p->x, p->y, target);
colored.pop();
//up
float pix[3];
glReadPixels(p->x, p->y + KOEF, 1, 1, GL_RGB, GL_FLOAT, pix);
if (!compare(pix,border) && compare(pix,clearp)) {
pixel *pn = new pixel();
pn->x = p->x;
pn->y = p->y + KOEF;
colored.push(pn);
}
//down
glReadPixels(p->x, p->y - KOEF, 1, 1, GL_RGB, GL_FLOAT, pix);
if (!compare(pix,border) && compare(pix,clearp)) {
pixel *pn = new pixel();
pn->x = p->x;
pn->y = p->y - KOEF;
colored.push(pn);
}
//left
glReadPixels(p->x - KOEF, p->y, 1, 1, GL_RGB, GL_FLOAT, pix);
if (!compare(pix,border) && compare(pix,clearp)) {
pixel *pn = new pixel();
pn->x = p->x - KOEF;
pn->y = p->y;
colored.push(pn);
}
//right
glReadPixels(p->x + KOEF, p->y, 1, 1, GL_RGB, GL_FLOAT, pix);
if (!compare(pix,border) && compare(pix,clearp)) {
pixel *pn = new pixel();
pn->x = p->x + KOEF;
pn->y = p->y;
colored.push(pn);
}
}
}
I draw pixel using this method
void drawPixel(float x, float y, float *t) {
glRasterPos2i(x, y);
glDrawPixels(1, 1, GL_RGB, GL_FLOAT, t);
for(int i = 0; i < KOEF; i++) {
glRasterPos2i(x, y + i);
glDrawPixels(1, 1, GL_RGB, GL_FLOAT, t);
glRasterPos2i(x + i, y);
glDrawPixels(1, 1, GL_RGB, GL_FLOAT, t);
glRasterPos2i(x + i, y + i);
glDrawPixels(1, 1, GL_RGB, GL_FLOAT, t);
}
};
To fill some area I choose first pixel with mouse click and then call method floodFill.
void mouse(int button, int state, int x, int y) {
if (button == GLUT_LEFT_BUTTON && state == GLUT_DOWN) {
pixel *p = new pixel();
p->x = x;
p->y = HEIGHT - y;
if (!stack.empty())
stack.pop();
stack.push(p); // first pixel
floodFill();
}
};
The result is (for example)
But it works very slow(several seconds. area on the picture - it was drawing it for 11 seconds. area around letter - 43 seconds). And I thought it slowly will draw pixel after pixel but it is waiting for several seconds and then I see the result.
my pc is
intel core 2 duo p8600 2.4 GHz
nvidia 9600m gt 512 mb
windows x86
ram 4 GB(3)`
Should it work so slow or there is a problem?
That's a terrible way to use OpenGL.
Do your flood-fill in host memory, upload the resulting bitmap to an OpenGL texture, and then render a quad with that texture.
Should it work so slow or there is a problem?
No, it should not. Because Photoshop can make it faster :-)
It looks like there are some efficiency-related issues.
You should not use OpenGL calls for single pixel operations. You should better make a buffered copy of the image, process (floodfill) it, then copy back.
Why are you using these strange float coordinates instead of normal integer pixel indices?
And what about not using floats for colors too? Floating point operations are slower than integer ones and float values needs further convesion to internal image format.
Your program seems to be too OOP-ish for its purpose. It is not good idea to use new and stack in the innermost loop of the image processing routine.
I'm writing an Opengl game but I got some problems using Opengl buffers.
My old code thats works (but has a lot of CPU consumption and low fps) looks like this:
void Terrain::drawObject(sf::RenderWindow* window)
{
float scale = 5.0f / max(width_ - 1, length_ - 1);
glScalef(scale, scale, scale);
glTranslatef(-(float) (width_ - 1) / 2, 0.0f, -(float) (length_ - 1) / 2);
bool texture = true;
for (int z = 0; z < width_ - 1; z++) {
//Makes OpenGL draw a triangle at every three consecutive vertices
if (getHeight(0, z) > 15)
{
glBindTexture(GL_TEXTURE_2D, textures_.find(Layer::High)->second);
}
else
{
glBindTexture(GL_TEXTURE_2D, textures_.find(Layer::Mid)->second);
}
glBegin(GL_TRIANGLE_STRIP);
for (int x = 0; x < width_; x++) {
sf::Vector3f normal = getNormal(x, z);
glNormal3f(normal.x, normal.y, normal.z);
if (texture)
{
glTexCoord2f(0, 0);
}
else
{
glTexCoord2f(1, 0);
}
glVertex3f((GLfloat) x, (GLfloat) getHeight(x, z), (GLfloat) z);
normal = getNormal(x, z + 1);
glNormal3f(normal.x, normal.y, normal.z);
if (texture)
{
glTexCoord2f(0, 1);
texture = !texture;
}
else
{
glTexCoord2f(1, 1);
texture = !texture;
}
glVertex3f((GLfloat) x, (GLfloat) getHeight(x, z + 1), (GLfloat) z + 1);
}
glEnd();
}
}
Now I have changed my code to get a higher fps. I use Opengl buffers to get that. But when I use them everything on the screen is corrupted. i use following source code now:
void Terrain::drawObject(sf::RenderWindow* window)
{
if (!buffersCreated_)
{
createBuffers();
buffersCreated_ = true;
}
float scale = 5.0f / max(width_ - 1, length_ - 1);
glScalef(scale, scale, scale);
glTranslatef(-(float) (width_ - 1) / 2, 0.0f, -(float) (length_ - 1) / 2);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_NORMAL_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, textures_.find(Layer::Mid)->second);
glBindBuffer(GL_ARRAY_BUFFER, textCoordBuffer_);
glTexCoordPointer(2, GL_FLOAT, 0, (char *) NULL);
glEnableClientState(GL_NORMAL_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer_);
glNormalPointer(GL_FLOAT, 0, (char *) NULL);
glEnableClientState(GL_VERTEX_ARRAY);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_);
glVertexPointer(3, GL_FLOAT, 0, (char *) NULL);
glDrawArrays(GL_TRIANGLE_STRIP, 0, vhVertexCount);
glDisableClientState(GL_VERTEX_ARRAY);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_NORMAL_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
}
void Terrain::createBuffers()
{
vhVertexCount = (int) (width_ * length_ * 6) / (1 * 1);
sf::Vector3f* vhVertices = new sf::Vector3f[vhVertexCount];
sf::Vector3f* vhNormal = new sf::Vector3f[vhVertexCount];
sf::Vector2i* vhTexCoords = new sf::Vector2i[vhVertexCount];
bool texture = true;
int nIndex = 0;
for (int z = 0; z < length_ - 1; z++) {
for (int x = 0; x < width_; x++) {
sf::Vector3f normal = getNormal(x, z);
if (texture)
{
vhTexCoords[nIndex] = sf::Vector2i(0, 0);
}
else
{
vhTexCoords[nIndex] = sf::Vector2i(1, 0);
}
vhVertices[nIndex] = sf::Vector3f((float) x, getHeight(x, z), (float) z);
vhNormal[nIndex] = sf::Vector3f(normal.x, normal.y, normal.z);
nIndex++;
normal = getNormal(x, z + 1);
if (texture)
{
vhTexCoords[nIndex] = sf::Vector2i(0, 1);
}
else
{
vhTexCoords[nIndex] = sf::Vector2i(1, 1);
}
vhVertices[nIndex] = sf::Vector3f((float) x, getHeight(x, z + 1), (float) z + 1);
vhNormal[nIndex] = sf::Vector3f(normal.x, normal.y, normal.z);
nIndex++;
}
}
glGenBuffers(1, &vertexBuffer_);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer_);
glBufferData(GL_ARRAY_BUFFER, vhVertexCount * sizeof(sf::Vector3f), vhVertices, GL_STATIC_DRAW);
glGenBuffers(1, &normalBuffer_);
glBindBuffer(GL_ARRAY_BUFFER, normalBuffer_);
glBufferData(GL_ARRAY_BUFFER, vhVertexCount * sizeof(sf::Vector3f), vhNormal, GL_STATIC_DRAW);
glGenBuffers(1, &textCoordBuffer_);
glBindBuffer(GL_ARRAY_BUFFER, textCoordBuffer_);
glBufferData(GL_ARRAY_BUFFER, vhVertexCount * sizeof(sf::Vector2i), vhTexCoords, GL_STATIC_DRAW);
delete [] vhVertices;
vhVertices = nullptr;
delete [] vhNormal;
vhNormal = nullptr;
delete [] vhTexCoords;
vhTexCoords = nullptr;
}
I use SFML to create the window and render 2D stuff like the menu in the lower left corner.
The code to render SFML stuff with Opengl stuff looks like:
void GameEngine::gameDraw()
{
// Clear the depth buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glLoadIdentity();
if (camera_ != nullptr)
{
camera_->drawCamera();
}
openglObjectsMutex_.lock();
for (OpenglObject* openglObject : openglObjects_)
{
openglObject->drawObject(window_);
}
openglObjectsMutex_.unlock();
window_->pushGLStates();
sfmlObjectsMutex_.lock();
for (SfmlObject * gameObject : sfmlObjects_)
{
gameObject->drawObject(window_);
}
sfmlObjectsMutex_.unlock();
window_->popGLStates();
}
Can someone find any problems with the buffer code?
The above image is the correct one but with low fps.
After changing the source to using buffers i got the below image.
SFML but it can only saves/restores OpenGL 2.x states. We must disable what we enable in +3.x states. It works adding:
It's fixed adding at the end of own drawing something like:
glBindBuffer( GL_ARRAY_BUFFER, 0 );
glBindBuffer( GL_ELEMENT_ARRAY_BUFFER, 0 );
glBindTexture( GL_TEXTURE_2D, 0 );
glDisableVertexAttribArray( 0 );
glUseProgram( 0 );
I am having an issue with openGL when drawing my sketched line to the screen in that it seems to be adding an extra point at the origin which is not in the point list:
(0,0) is definitely not in the points that are in the array to be drawn, just cant seem to reason it out. I would guess that maybe my array size is too big or something but I can't see it
Here is my code for populating the array and the draw call
void PointArray::repopulateObjectBuffer()
{
//Rebind Appropriate VAO
glBindVertexArray( vertex_array_object_id );
//Recalculate Array Size
vertexArraySize = points.size()*sizeof(glm::vec2);
//Rebind Appropriate VBO
glBindBuffer( GL_ARRAY_BUFFER, buffer_object_id );
glBufferData( GL_ARRAY_BUFFER, vertexArraySize, NULL, GL_STATIC_DRAW );
glBufferSubData( GL_ARRAY_BUFFER, 0, vertexArraySize, (const GLvoid*)(&points[0]) );
//Set up Vertex Arrays
glEnableVertexAttribArray( 0 ); //SimpleShader attrib at position 0 = "vPosition"
glVertexAttribPointer( (GLuint)0, 2, GL_FLOAT, GL_FALSE, 0, BUFFER_OFFSET(0) );
//Unbind
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
void PointArray::draw() {
glBindVertexArray(vertex_array_object_id);
glLineWidth(4);
glDrawArrays( GL_LINE_STRIP, 0, vertexArraySize );
glBindVertexArray(0);
}
and here is where I am adding points in the mouse callback
void mouseMovement(int x, int y)
{
mouseDX = x - lastX ;
mouseDY = y - lastY ;
lastX = x;
lastY = y;
if(mouse_drag)
{
cam->RotateByMouse(glm::vec2(mouseDX*mouseSens, mouseDY * mouseSens));
}
if(sketching)
{
sketchLine.addPoint(glm::vec2((float)x,(float)y));
sketchLine.repopulateObjectBuffer();
updatePickray(x,y);
}
}
Finally my simple ortho vertex shader
in vec2 vPosition;
void main(){
const float right = 800.0;
const float bottom = 600.0;
const float left = 0.0;
const float top = 0.0;
const float far = 1.0;
const float near = -1.0;
mat4 orthoMat = mat4(
vec4(2.0 / (right - left), 0, 0, 0),
vec4(0, 2.0 / (top - bottom), 0, 0),
vec4(0, 0, -2.0 / (far - near), 0),
vec4(-(right + left) / (right - left), -(top + bottom) / (top - bottom), -(far + near) / (far - near), 1)
);
gl_Position = orthoMat * vec4(vPosition, 0.0, 1.0);
}
You seem to be using vertexArraySize as the parameter to glDrawArrays, which is not correct. The count of glDrawArrays should be the number of vertices, not the number of bytes of the vertex array.
In your case I guess it would be glDrawArrays( GL_LINE_STRIP, 0, points.size());.