How to render Image from file using the Qt OpenGL API - image

I'm trying to render an image from a *.png file on to screen using the Qt OpenGL API. My implement method creates the OpenGLWindow class, which is subclass of QOpenGLWindow and QOpenGLFunctions, then overrides 2 methods: initializeGL() and paintGL().
I have code, as below:
class OpenGLWindow : public QOpenGLWindow, protected QOpenGLFunctions
{
Q_OBJECT
public:
OpenGLWindow();
protected:
void initializeGL();
void paintGL() Q_DECL_OVERRIDE;
};
OpenGLWindow::OpenGLWindow()
: QOpenGLWindow(QOpenGLWindow::NoPartialUpdate)
{
}
void OpenGLWindow::initializeGL()
{
initializeOpenGLFunctions();
}
void OpenGLWindow::paintGL()
{
// Clear buffer with blue color
glClearColor(0, 0, 1, 0);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Load image from file
QImage image;
if(!image.load(":/side1.png"))
{
qDebug() << "load image fail";
return;
}
// Draw Texture
glEnable(GL_TEXTURE_2D); // Enable texturing
glActiveTexture(GL_TEXTURE1);
GLuint textureID;
glGenTextures(1, &textureID); // Obtain an id for the texture
glBindTexture(GL_TEXTURE_2D, textureID); // Set as the current texture
QImage tex = QGLWidget::convertToGLFormat(image);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, tex.width(), tex.height(), 0, GL_RGBA, GL_UNSIGNED_BYTE, tex.bits());
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glDisable(GL_TEXTURE_2D);
}
The result is the window only displays a blue screen, with an error that the image could not be displayed. I saw that the image was loaded successfully to QImage. Have I don't something wrong or am I missing something or not? Can somebody help me?
Result screen:

Related

Puzzels about glteximage2d using gl_luminance

I met some problem about using gl_luminance to define FBO. Here is the code i used,
generateRenderToTexture(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, _maskTexture, _imageWidth, _imageHeight, false);
related code is as follows,
TextureBuffer _maskTexture;
class TextureBuffer {
public:
GLuint texture;
GLuint frameBuffer;
GLenum internalformat;
GLenum format;
GLenum type;
int w,h;
TextureBuffer() : texture(0), frameBuffer(0) {}
void release()
{
if(texture)
{
glDeleteTextures(1, &texture);
texture = 0;
}
if(frameBuffer)
{
glDeleteFramebuffers(1, &frameBuffer);
frameBuffer = 0;
}
}
};
void generateRenderToTexture(GLint internalformat, GLenum format, GLenum type,
TextureBuffer &tb, int w, int h, bool linearInterp)
{
glGenTextures(1, &tb.texture);
glBindTexture(GL_TEXTURE_2D, tb.texture);
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, linearInterp ? GL_LINEAR : GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, linearInterp ? GL_LINEAR : GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, internalformat, w, h, 0, format, type, NULL);
glGenFramebuffers(1, &tb.frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, tb.frameBuffer);
glClear(_glClearBits);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, tb.texture, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if(status != GL_FRAMEBUFFER_COMPLETE)
printf("Framebuffer status: %x", (int)status);
tb.internalformat = internalformat;
tb.format = format;
tb.type = type;
tb.w = w;
tb.h = h;
}
The question is when I use,
generateRenderToTexture(GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE, _maskTexture, _imageWidth, _imageHeight, false);
The code went well. But if use gl_luminance instead,
generateRenderToTexture(GL_LUMINANCE, GL_LUMINANCE, GL_UNSIGNED_BYTE, _maskTexture, _imageWidthOriginal,
I don't know why i could not use GL_LUMINANCE to define the FBO. Anyone have some useful suggestions to solve this?
The only formats that are guaranteed to work as color FBO attachments in ES 2.0 are, according to table 4.5 in the spec document:
GL_RGBA4
GL_RGB5_A1
GL_RGB565
Support for rendering to GL_RGBA, which works for you, is not required by the standard. Many implementations support it, though. The OES_rgb8_rgba8 extension adds support for GL_RGB8 and GL_RGBA8 formats as render targets.
GL_LUMINANCE is not supported as a color-renderable format by the standard, and I can't find an extension for it either. It's possible that some implementations could support it, but you certainly can't count on it.
ES 3.0 lists GL_R8 as a color-renderable format. In ES 3.0, the RED/R formats replace the LUMINANCE/ALPHA formats from ES 2.0. So if you can move to ES 3.0, you have support to render to 1-component texture formats.
You're using non-extension FBO functions, which were introduced only with OpenGL-3. So unlike FBO extension functions (ending with ARB) those functions are available only with a OpenGL-3 context. In OpenGL-3 the GL_LUMINANCE and GL_ALPHA texture internal formats are deprecated, are not available in core profile. They have been replaced by the GL_RED texture format. You can use an appropriately written shader or texture swizzle parameters to make a GL_RED texture work just like GL_LUMINANCE (swizzle dst.rgb = texture.r) or GL_ALPHA (swizzle dst.a = texture.r).
I have solved by using GL_RG_EXT, or GL_RED_EXT, instead.

OpenGL FBO performance issue

i'm working on a school project and I've come across an issue with my FBO.
game is rendered in 2 passes:
1) I render to the shadow map texture using an FBO.
2) I render scene normally to the default FBO.
Issue is, for some reason, binding the FBO when i do the first pass slows down my game by roughly 200+ fps, I really don't know what could be wrong with the FBO since it's as barebones as possible.
If i were to render the shadow map without binding, so directly to the screen, it'd be 200 fps faster, so it's not an issue of rendering, it's an issue of binding the FBO I believe.
Anyways, here's the first pass function.
//renders to the depth buffer texture.
void firstPass()
{
static GLuint shadowID = Resources::getInstance().shadowShader;
shadowBuffer->bindForWriting();//make active frame buffer the shadow buffer
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, shadowBuffer->TEXTURE_WIDTH, shadowBuffer->TEXTURE_HEIGHT);
//render to the shadow map from the point of view of the sunlight.
glUseProgram(shadowID);
... set some uniforms
scene->render(shadowID);
shadowBuffer->unBindForWriting();//set frame buffer to default
glUseProgram(0);
}
And here is my FBO class in its entirety.
ShadowMapFBO()
{
init();
}
void bindForWriting()
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, FBO);
}
void unBindForWriting()
{
glBindFramebuffer(GL_DRAW_FRAMEBUFFER, 0);
}
void bindForReading(GLenum TextureUnit, GLuint texture)
{
glActiveTexture(TextureUnit);
glBindTexture(GL_TEXTURE_2D, texture);
}
void BindTexture(GLuint textureID, GLuint location)
{
glUniform1i(textureID, location);
}
void unBindForReading()
{
glBindTexture(GL_TEXTURE_2D, 0);
}
GLuint shadowTexture;
int TEXTURE_WIDTH = 2048;
int TEXTURE_HEIGHT = 2048;
GLuint FBO;
void init()
{
glGenFramebuffers(1, &FBO);
glBindFramebuffer(GL_FRAMEBUFFER, FBO);
shadowTexture = Util::createTexture(TEXTURE_WIDTH, TEXTURE_HEIGHT, true);
glFramebufferTexture(GL_FRAMEBUFFER, GL_DEPTH_ATTACHMENT, shadowTexture, 0);
glDrawBuffer(GL_NONE);
glReadBuffer(GL_NONE);
GLenum Status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (Status != GL_FRAMEBUFFER_COMPLETE)
printf("FB error, status: 0x%x\n", Status);
else
printf("Shadow Buffer created successfully.\n");
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
Here's how I create my depth buffer texture.
static GLuint createTexture(int width, int height)
{
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexImage2D(GL_TEXTURE_2D, 0, GL_DEPTH_COMPONENT, width, height, 0, GL_DEPTH_COMPONENT, GL_FLOAT, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
int i;
i = glGetError();
if (i != 0)
{
std::cout << "Error happened while loading the texture: " << i << std::endl;
}
glBindTexture(GL_TEXTURE_2D, 0);
return textureId;
}

Issues drawing multiple image textures with some disapearing

I'm looking to use OpenGl to blend 4 images to the screen. The first image contains the background and the other 3 are images contain some cartoon with transparency. My goal is to render those 4 images at once. At every call to render I'm updating the top 3 images with new images to compose the new frame.
I'm new to OpenGL and so far I'm able to achieve blending those images however I'm noticing some horrible issues when I render. I'm seeing some of the top 3 images are missing sometimes or some are rendered but look like they where cropped by the invisible man...
Each lines represents a different image.
Image cropped issue:
Image cropped and one image missing:
How it should look like:
Any help figuring out the issue I would greatly appreciate it! Below the code I'm using.
Here is the code I use to render the images.
void MoviePreview::prepareTexture (GLuint texture, GLint format, int w, int h)
{
// Bind to generated texture
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glShadeModel(GL_FLAT);
//glShadeModel(GL_SMOOTH);
glTexImage2D(GL_TEXTURE_2D, 0, format, w, h, 0, format, GL_UNSIGNED_BYTE, 0);
if (GL_RGBA == format)
{
//glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
}
// Crop the texture rectangle
GLint rect[] = {0, h, w, -h};
glTexParameteriv(GL_TEXTURE_2D, GL_TEXTURE_CROP_RECT_OES, rect);
glDrawTexiOES(0, 0, 0, w, h);
}
void MoviePreview::resize (int w, int h)
{
LOGI("native_gl_resize %d %d", w, h);
// init open gl
//glClearColor(1.0, 1.0, 1.0, 1.0);
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glDisable(GL_DITHER);
glDisable(GL_LIGHTING);
glDisable(GL_DEPTH_TEST);
glDisable(GL_COLOR_MATERIAL);
glDisable(GL_FOG);
glDisable(GL_CULL_FACE);
glDisable(GL_STENCIL_TEST);
glDisable(GL_COLOR_LOGIC_OP);
glDisable(GL_ALPHA_TEST);
//glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);//NEW
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);//NEW
//glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_DST_ALPHA);
// Generate one texture object
glGenTextures(MAX_TEXTURES, mTexture);
check_gl_error("glGenTextures");
int frameHeight = h;//image.rows;
int frameWidth = w;//image.cols;
// first texture is our background texture
prepareTexture(mTexture[0], GL_RGBA, mBg.cols, mBg.rows);
prepareTexture(mTexture[1], GL_RGBA, frameWidth, frameHeight);
prepareTexture(mTexture[2], GL_RGBA, frameWidth, frameHeight);
prepareTexture(mTexture[3], GL_RGBA, frameWidth, frameHeight);
mSurfaceWidth = w;
mSurfaceHeight = h;
}
void MoviePreview::render (int64_t* imageIds, const int images)
{
int i = 0;
double sleepDuration = 0;
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// TODO try to see if we can just get away from always loading the bg
// since it doesn't change often might be worth loading it once and that
// is it...
//glBindTexture(GL_TEXTURE_2D, mTexture[0]);
//glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, mBg.cols, mBg.rows, GL_RGBA, GL_UNSIGNED_BYTE, mBg.ptr());
//glDrawTexiOES(0, 0, 0, mSurfaceWidth, mSurfaceHeight);
// TODO pass the image batch loader
// load images
for (i=0; i<images; i++)
{
if (0 < imageIds[i])
{
sprintf(mTempPath, "%s/f1_%lld.png",mProjectPath.c_str(), imageIds[i]);
mImageLoader[i].loadImage(mTempPath);
}
}
if (0 < mFrameDuration)
{
// here we try to control the suggested frame rate
// set. We calculate since the last show image time
// if we should sleep or not...
if (0 < mLastDrawTimestamp) {
sleepDuration = mFrameDuration - (now_ms() - mLastDrawTimestamp);
}
if (0 < sleepDuration) {
usleep((long)sleepDuration*NANO_IN_MS);
}
}
// draw images
i = 0;
for (i=0; i<images; i++)
{
if (0 < imageIds[i])
{
cv::Mat img = mImageLoader[i].getImage();
if (!img.empty())
{
glBindTexture(GL_TEXTURE_2D, mTexture[i+1]);
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, img.cols, img.rows, GL_RGBA, GL_UNSIGNED_BYTE, img.ptr());
glDrawTexiOES(0, 0, 0, img.cols, img.rows);
}
}
}
mLastDrawTimestamp = now_ms();
}
The issue ended up being with my image sources getting modified by another thread while OpenGl was trying to draw them...

Opengl ES 2.0, FBOs, and Fragment Shaders

Here's my render loop:
Bind a custom FBO
Bind a texture (previously associated with the FBO as COLOR_ATTACHMENT0)
Render using a custom fragment shader which chooses fragment colors on the basis of a fractal algorithm. (If a fragment is not used by the algorithm, it is assigned the color black)
Rebind the window-provided framebuffer and renderbuffer. (on ios 5, this is the [view bindDrawable] method.
Clear the screen to white.
Render the fbo texture into a frame that is substantially smaller than the window itself.
Expected result:
The fractal should appear in the smaller frame. The frame should have a black background. The rest of the screen should be white.
Current result:
The entire screen is taken up by the fractal, as if I were rendering to the window provided fbo, and to my custom fbo/texture.
I don't really know what I'm doing wrong, so I'd be grateful for any help.
EDIT:
Fragment Shader:
void main()
{
highp vec2 pix = gl_FragCoord.xy;
lowp vec4 color = vec4(0.0,0.0,0.0,0.0);
//determine if fragment is part of the fractal using the algorithm
//if yes, change the value of the color vec4
gl_FragColor = color;
}
FBO Initialization:
//First create and bind the frame buffer
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
//Create a texture
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, 0);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//Attach the texture to the framebuffer
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
GLenum status = glCheckFramebufferStatus(GL_FRAMEBUFFER);
if (status != GL_FRAMEBUFFER_COMPLETE) {
printf("\n Incomplete Frame Buffer!");
}
Render Loop:
{
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, texture);
glViewport(0, 0, width, height);
//Call the fractal render, basically a plane of 4 vertices happening through GL_TRIANGLE_STRIP, but that calls the fragment shader above.
[self.view bindDrawable];
glClearColor(1.0,1.0,1.0,1.0);
matrix4x4 mvp = multiplyMatrices(projectionMatrix, modelView);
glUseProgram(shaderId);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
glVertexAttribPointer(positionLocation, 4, GL_FLOAT, GL_FALSE, 0, NULL);
glBindBuffer(GL_ARRAY_BUFFER, texelBuffer);
glVertexAttribPointer(texelLocation, 2, GL_FLOAT, GL_FALSE, 0, NULL);
glUniformMatrix4fv(mvpLocation, 1, 0, mvp.val);
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, textureId);
glUniform1i(textureLocation, 0);
glDrawArrays(GL_TRIANGLE_STRIP, 0, tVertices);
}
I hope this helps. Please let me know if you'd like any more information on what I'm doing.
I also noticed something very strange happening.
If, after binding the FBO, I try
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1.0,0.0,0.0,0.5);
...it is the window-provided framebuffer on which the clear actually happens.
Thank you guys for helping.

How to force 24 bit color depth in OpenGL ES

I am trying to load and display a texture in OpenGL ES. The problem I am having is that even though my image is in ARGB_8888 format, the texture seems to be drawn in RGB_565 format. Without dithering, my image looks pretty terrible.
I am running my program on a phone which supports 16m colors, therefore, the texture should be view-able in all it's original glory.
EDIT code:
loading bitmap:
background = BitmapFactory.decodeResource(getResources(), R.drawable.background, null);
generating texture:
public void loadBackground(GL10 gl) {
gl.glGenTextures(1, textures, 0);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MIN_FILTER, GL10.GL_LINEAR);
gl.glTexParameterf(GL10.GL_TEXTURE_2D, GL10.GL_TEXTURE_MAG_FILTER, GL10.GL_LINEAR);
GLUtils.texImage2D(GL10.GL_TEXTURE_2D,0, background,0);
background.recycle();
}
drawing:
gl.glEnableClientState(GL10.GL_VERTEX_ARRAY);
gl.glEnableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
gl.glClear(GL10.GL_COLOR_BUFFER_BIT | GL10.GL_DEPTH_BUFFER_BIT);
gl.glBindTexture(GL10.GL_TEXTURE_2D, textures[0]);
gl.glVertexPointer(3, GL10.GL_FLOAT, 0, backgroundVertexBuffer);
gl.glTexCoordPointer(2, GL10.GL_FLOAT, 0, textureBuffer);
gl.glDrawArrays(GL10.GL_TRIANGLE_STRIP, 0,4);
gl.glDisableClientState(GL10.GL_VERTEX_ARRAY);
gl.glDisableClientState(GL10.GL_TEXTURE_COORD_ARRAY);
onSurfaceCreated:
public void onSurfaceCreated(GL10 gl, EGLConfig config) {
gl.glEnable(GL10.GL_TEXTURE_2D);
}
onSurfaceChanged
public void onSurfaceChanged(GL10 gl, int width, int height) {
gl.glViewport(0, 0, width, height);
gl.glLoadIdentity();
gl.glOrthof(0, width, height, 0, -1, 1);
By default the GLSurfaceView is using RGB_565 for its pixel format, so you need to specify that you want a 32 bit surface before you bind the renderer. More info at http://developer.android.com/reference/android/opengl/GLSurfaceView.html , look at one of the setEGLConfigChooser methods.

Resources