OpenGL OES Iphone glCopyTexImage2D - iphone

I am new to openGL OES on iPhone and have a memory issue with glCopyTexImage2D. So far i understood, this function should copy the current framebuffer to the binded texture. But for some reason it always allocates new memory, which i can see in instruments checking the allocations.
My goal is to read texture images and draw on it, after drawing i want to save the new texture , so i can scroll through the painting. So here is may code:
1) init opengl and framebuffer:
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!context || ![EAGLContext setCurrentContext:context]) {
[self release];
return nil;
}
glEnable(GL_TEXTURE_2D);
glEnable(GL_BLEND);
glBlendFunc(GL_ONE, GL_SRC_COLOR);
// Setup OpenGL states
glMatrixMode(GL_PROJECTION);
CGRect frame = self.bounds;
CGFloat scale = self.contentScaleFactor;
// Setup the view port in Pixels
glOrthof(0, frame.size.width * scale, 0, frame.size.height * scale, -1, 1);
glViewport(0, 0, frame.size.width, frame.size.height * scale);
glDisable(GL_DEPTH_TEST);
glDisable(GL_DITHER);
glMatrixMode(GL_MODELVIEW);
glEnableClientState(GL_VERTEX_ARRAY);
// Set a blending function appropriate for premultiplied alpha pixel data
glEnable(GL_POINT_SPRITE_OES);
glTexEnvf(GL_POINT_SPRITE_OES, GL_COORD_REPLACE_OES, GL_TRUE);
glPointSize(64 / kBrushScale);
2) now i load the saved images into the framebuffer:
if ([[NSFileManager defaultManager] fileExistsAtPath:path]) {
// load texture
NSData* data = [[NSData alloc] initWithContentsOfFile:path];
glGenTextures(1, &drawBoardTextures[i]);
glBindTexture(GL_TEXTURE_2D, drawBoardTextures[i]);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1024, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, [data bytes]);
// free memory
[data release];
}
3) and finally render the texture:
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glColor4f(1.0f, 1.0f, 1.0f, 1.0f);
int width = 1024;
GLfloat quad[] = {0.0,1024.0,1024.0,1024.0,0.0,0.0,1024.0,0.0};
GLfloat quadTex[] = {0.0,1.0,1.0,1.0,0.0,0.0,1.0,0.0};
for (int i=0; i<10; i++) {
quad[0] = width * i;
quad[2] = quad[0] + width;
quad[4] = quad[0];
quad[6] = quad[2];
glBindTexture(GL_TEXTURE_2D, drawBoardTextures[i]);
glVertexPointer(2, GL_FLOAT, 0, quad);
glTexCoordPointer(2, GL_FLOAT, 0, quadTex);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glBindTexture(GL_TEXTURE_2D, 0);
}
4) for now everything works fine, with gltranslatef i can scroll through the textures and also there is no allocation yet observed in instruments. so now i draw on the current window and want to save the result like followed:
int texIndex = offset.x/1024;
float diff = offset.x - (1024*texIndex);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glBindTexture(GL_TEXTURE_2D, drawBoardTextures[texIndex]);
glBindTexture(GL_TEXTURE_2D, drawBoardTextures[texIndex]);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, diff, 0, 0, 0, 1024-diff, 1024);
glBindTexture(GL_TEXTURE_2D, drawBoardTextures[texIndex + 1]);
glCopyTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, 1024-diff, 0, diff, 1024);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glFlush();
No the problems starts. instead of writing it directly into the generated textures, it writes it into client memory. for every copied texture it uses ~4 MB of Ram, but every recopy doesn't need any memory. i really don't know what i did wrong.
Does anyone know what the problem is? Thanks alot for your help.
cheers
chris

Related

iOS openGL ES 1.0, failed to render Texture2D

I use the openGL ES 1.0. After decoding stream data, it is changed to RGBA bits. And then I transfer RGBA bytes to 'renderer' method with parameter.
the renderer method is called by each frame routines. Because RGBA bytes are changed every times.
But it doesn't draw any picture frames. Just the white rectangle and background gray color are displayed. What is the problem?
[initialize]
- (id <ESRenderer>) init
{
if (self = [super init])
{
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!context || ![EAGLContext setCurrentContext:context])
{
[self release];
return nil;
}
// Create default framebuffer object. The backing will be allocated for the current layer in -resizeFromLayer
glGenFramebuffersOES(1, &defaultFramebuffer);
glGenRenderbuffersOES(1, &colorRenderbuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, defaultFramebuffer);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
glEnable(GL_TEXTURE_2D);
glGenTextures(1, &frameTexture);
glBindTexture(GL_TEXTURE_2D, frameTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, frameTexture, 0);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, colorRenderbuffer);
}
return self;
}
[Renderer method. It is called by outside per each frames]
static const GLfloat verticesForGL_TRIANGLE_STRIP[] = {
-0.8, 0.8, 0.0, //v1
0.0, 1.0, //UV1
-0.8, -0.8, 0.0, //v2
0.0, 0.0, //UV2
0.8, 0.8, 0.0, //v3
1.0, 1.0, //UV3
0.8, -0.8, 0.0, //v4
1.0, 0.0, //UV4
};
- (void)render:(uint8_t*)data
{
if ([EAGLContext currentContext] != context)
[EAGLContext setCurrentContext:context];
glClearColor(0.4f, 0.4f, 0.4f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(-1.1f, 1.1f, -1.1f, 1.1f, -2.0f, 2.0f);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1280, 1024, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, frameTexture);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glVertexPointer(3, GL_FLOAT, sizeof(GLfloat)*5, verticesForGL_TRIANGLE_STRIP);
glTexCoordPointer(2, GL_FLOAT, sizeof(GLfloat)*5, &verticesForGL_TRIANGLE_STRIP[0]+3);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
Seems to me you are attempting to load a non-power-of-two texture. This is not supported on all iOS devices on openGl es 1.0/1.1. You can check if the devices supports such extension
bool npot = strstr(extensions, "GL_APPLE_texture_2D_limited_npot") != 0;
if (! npot)
NSLog("Non power of two textures not supported.");
Also, try loading a power of two square texture and see if that works.
Oh I've solved just now.
I added this line below the glTexImage2D function. (sorry, I'm a beginner about openGL. It seems to make a link frameBuffer with texture.)
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_FRAMEBUFFER_ATTACHMENT_TEXTURE_LEVEL_OES, GL_TEXTURE_2D, frameTexture, 0);
I use the iPhone5(armv7s). It is enough to decode and resize the 1280x1024 30fps pictures. but rendering need to change from using CPU to GPU.
So, now I can make a better performance. (23fps -> 30fps)
thanks.

iPhone OpenGL texture not completely transparent

I tried to paint a transparent texture over a sphere, but the transparent areas are not completely transparent. A vivid shade of gray remains. I tried to load a Photoshop generated PNG then paint it on sphere using the code below:
My code to load textures:
- (void) loadPNGTexture: (int)index Name: (NSString*) name{
CGImageRef imageRef = [UIImage imageNamed:[NSString stringWithFormat:#"%#.png",name]].CGImage;
GLsizei width = CGImageGetWidth(imageRef);
GLsizei height = CGImageGetHeight(imageRef);
GLubyte * data = malloc(width * 4 * height);
if (!data)
NSLog(#"error allocating memory for texture loading!");
else {
NSLog(#"Memory allocated for %#", name);
}
NSLog(#"Width : %d, Height :%d",width,height);
CGContextRef cg_context = CGBitmapContextCreate(data, width, height, 8, 4 * width, CGImageGetColorSpace(imageRef), kCGImageAlphaPremultipliedLast);//kCGImageAlphaPremultipliedLast);
CGContextTranslateCTM(cg_context, 0, height);
CGContextScaleCTM(cg_context, 1, -1);
CGContextDrawImage(cg_context, CGRectMake(0, 0, width, height), imageRef);
CGContextRelease(cg_context);
CGContextSetBlendMode(cg_context, kCGBlendModeCopy); //kCGBlendModeCopy);
glGenTextures(2, m_texture[index]);
glBindTexture(GL_TEXTURE_2D, m_texture[index][0]);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
free(data);
}
Drawing clouds:
glPushMatrix();
glTranslatef(0, 0, 3 );
glScalef(3.1, 3.1, 3.1);
glRotatef(-1, 0, 0, 1);
glRotatef(90, -1, 0, 0);
glDisable(GL_LIGHTING);
//Load Texture for left side of globe
glBindTexture(GL_TEXTURE_2D, m_texture[CLOUD_TEXTURE][0]);
glVertexPointer(3, GL_FLOAT, sizeof(TexturedVertexData3D), &VertexData[0].vertex);
glNormalPointer(GL_FLOAT, sizeof(TexturedVertexData3D), &VertexData[0].normal);
glTexCoordPointer(2, GL_FLOAT, sizeof(TexturedVertexData3D), &VertexData[0].texCoord);
// draw the sphere
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_COPY);
glDrawArrays(GL_TRIANGLES, 0, 11520);
glEnable(GL_LIGHTING);
glPopMatrix();
This first thing that stands out in your code is the line:
glBlendFunc(GL_SRC_ALPHA, GL_COPY);
The second argument (GL_COPY), is not a valid argument for glBlendFunc.
You might want to change that to something along the lines of
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);

Draw a line on top of triangles

I created a new iPhone OpenGL Project in Xcode. I filled my background with triangles and gave them a texture, see below:
CGImageRef spriteImage;
CGContextRef spriteContext;
GLubyte *spriteData;
size_t width, height;
// Sets up matrices and transforms for OpenGL ES
glViewport(0, 0, backingWidth, backingHeight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
//glRotatef(-90,0,0,1);
glOrthof(-1.0f, 1.0f, -1.5f, 1.5f, -1.0f, 1.0f);
glMatrixMode(GL_MODELVIEW);
// Clears the view with black
glClearColor(0.0f, 0.0f, 0.0f, 1.0f);
// Sets up pointers and enables states needed for using vertex arrays and textures
glVertexPointer(2, GL_FLOAT, 0, vertices);
glEnableClientState(GL_VERTEX_ARRAY);
//glColorPointer(4, GL_FLOAT, 0, triangleColors);
//glColor4f(0.0f,1.0f,0.0f,1.0f);
//glEnableClientState(GL_COLOR_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, spriteTexcoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
// Creates a Core Graphics image from an image file
spriteImage = [UIImage imageNamed:#"Bild.png"].CGImage;
// Get the width and height of the image
width = CGImageGetWidth(spriteImage);
height = CGImageGetHeight(spriteImage);
// Texture dimensions must be a power of 2. If you write an application that allows users to supply an image,
// you'll want to add code that checks the dimensions and takes appropriate action if they are not a power of 2.
if(spriteImage) {
// Allocated memory needed for the bitmap context
spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
// Uses the bitmap creation function provided by the Core Graphics framework.
spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width * 4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
// After you create the context, you can draw the sprite image to the context.
CGContextDrawImage(spriteContext, CGRectMake(0.0, 0.0, (CGFloat)width, (CGFloat)height), spriteImage);
// You don't need the context at this point, so you need to release it to avoid memory leaks.
CGContextRelease(spriteContext);
// Use OpenGL ES to generate a name for the texture.
glGenTextures(1, &spriteTexture);
// Bind the texture name.
glBindTexture(GL_TEXTURE_2D, spriteTexture);
// Set the texture parameters to use a minifying filter and a linear filer (weighted average)
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// Specify a 2D texture image, providing the a pointer to the image data in memory
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
// Release the image data
free(spriteData);
// Enable use of the texture
glEnable(GL_TEXTURE_2D);
// Set a blending function to use
glBlendFunc(GL_ONE, GL_ONE_MINUS_SRC_ALPHA);
// Enable blending
glEnable(GL_BLEND);
I have got two questions, bc. I am not so familiar with OpenGL.
I want to write a method, which I give two points as parameters and I want a Line between these two points to be drawn above my triangles (background).
- (void) drawLineFromPoint1:(CGPoint)point1 toPoint2:(CGPoint)point2 {
GLfloat triangle[] = { //Just example points
0.0f, 0.0f,
0.1f, 0.0f,
0.1f, 0.0f,
0.1f, 0.1f
};
GLfloat triangleColors[] = {
0.5f, 0.5f, 0.5f, 1.0f
};
//now draw the triangle
}
Something like that. Now I want to have a 2nd method, which erases this line (and not the background)
My drawing method looks like this:
- (void)drawView
{
// Make sure that you are drawing to the current context
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glClear(GL_COLOR_BUFFER_BIT);
glDrawElements(GL_TRIANGLES, number_vertices, GL_UNSIGNED_SHORT, indices);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
Would be great if you can give e some hints/help,
cheers
The conventional approach would be to redraw everything whenever you move or erase a line.
Well, I got it to work. I just missed to set the Vertex-Pointer in my drawView to my triangles. This here now works:
- (void)drawView
{
[EAGLContext setCurrentContext:context];
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glClear(GL_COLOR_BUFFER_BIT);
glVertexPointer(2, GL_FLOAT, 0, vertices);
glDrawElements(GL_TRIANGLES, number_vertices, GL_UNSIGNED_SHORT, indices);
[self drawLines];
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
- (void) drawLines{
glDisable(GL_TEXTURE_2D);
GLfloat points[4];
for (Dataset *data in buttons) {
CGPoint s = [data screenPosition];
CGPoint p = [data slot];
points[0] = (GLfloat)(768-s.y);
points[1] = (GLfloat)(1024-s.x);
points[2] = (GLfloat)(768-p.y);
points[3] = (GLfloat)(1024-p.x);
glVertexPointer(2, GL_FLOAT, 0, points);
glDrawArrays(GL_LINE_STRIP, 0, 2);
}
glEnable(GL_TEXTURE_2D);
}

Problem with opengles to show an image

I use xcode Opengl App template to create a sample.
I am new to opengles, and having to try re-write the 'render' method in ES1Renderer.m
I try create a texture and show it on the screen, but nothing showed.
Someone can help me ? I have no idea how to fix it:
- (void)render
{
int imageW = 16;
int imageH = 16;
GLubyte *textureData = (GLubyte *) malloc(imageW * imageH << 2);
for (int i = 0; i < imageW * imageH << 2; i++) {
textureData[i]= 0xff & i;
}
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
// when texture area is small, bilinear filter the closest mipmap
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER,
GL_LINEAR );
// when texture area is large, bilinear filter the original
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
// the texture wraps over at the edges (repeat)
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageW, imageH, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);
GLenum err = glGetError();
if (err != GL_NO_ERROR)
NSLog(#"Error uploading texture. glError: 0x%04X", err);
free(textureData);
float x = 10.0f;
float y = 10.0f;
float z = 0.0f;
float scaleX = 1.0f;
float scaleY = 1.0f;
float scaleZ = 1.0f;
int w = imageW /2;
int h = imageH /2;
const GLfloat squareVertices[] = {
-w, -h,
w, -h,
-w, h,
w, h,
};
const GLfloat textureCoords[] = {
0, 0,
1, 0,
0, 1,
1, 1,
};
glEnable(GL_TEXTURE_2D);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnableClientState(GL_VERTEX_ARRAY);
glBindTexture(GL_TEXTURE_2D, textureId);
glVertexPointer(2, GL_FLOAT, 0, squareVertices);
glTexCoordPointer(2, GL_FLOAT, 0, textureCoords);
glPushMatrix();
glTranslatef(x, y, z);
glScalef(scaleX, scaleY, scaleZ);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glPopMatrix();
glDisable(GL_TEXTURE_2D);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
glDisableClientState(GL_VERTEX_ARRAY);
NSLog(#"-->");
glDeleteTextures(1, &textureId);
// This application only creates a single color renderbuffer which is already bound at this point.
// This call is redundant, but needed if dealing with multiple renderbuffers.
glBindRenderbufferOES(GL_RENDERBUFFER_OES, colorRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
Sadly the OpenGL template provided by Xcode has changed at some point — the current code (as of Xcode 3.2.5, creating an iOS Application with the 'OpenGL ES Application' template) no longer supplies a separate ES1Renderer.m and ES2Renderer.m, preferring to provide a single, simplified EAGLView.m and to perform runtime tests within GLTestViewController.m. With that in mind, I modified GLTestViewController.m's awakeFromNib no longer to attempt to get an ES 2 context:
- (void)awakeFromNib
{
EAGLContext *aContext = nil;//[[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
if (!aContext)
{
aContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
}
if (!aContext)
NSLog(#"Failed to create ES context");
else if (![EAGLContext setCurrentContext:aContext])
NSLog(#"Failed to set ES context current");
self.context = aContext;
[aContext release];
[(EAGLView *)self.view setContext:context];
[(EAGLView *)self.view setFramebuffer];
if ([context API] == kEAGLRenderingAPIOpenGLES2)
[self loadShaders];
animating = FALSE;
animationFrameInterval = 1;
self.displayLink = nil;
}
And copied and pasted relevant portions of your code into drawFrame:
- (void)drawFrame
{
[(EAGLView *)self.view setFramebuffer];
// Replace the implementation of this method to do your own custom drawing.
static const GLfloat squareVertices[] = {
-0.5f, -0.33f,
0.5f, -0.33f,
-0.5f, 0.33f,
0.5f, 0.33f,
};
const GLfloat textureCoords[] = {
0, 0,
1, 0,
0, 1,
1, 1,
};
static float transY = 0.0f;
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glClear(GL_COLOR_BUFFER_BIT);
int imageW = 16;
int imageH = 16;
GLubyte *textureData = (GLubyte *) malloc(imageW * imageH << 2);
for (int i = 0; i < imageW * imageH << 2; i++) {
textureData[i]= 0xff & i;
}
GLuint textureId;
glGenTextures(1, &textureId);
glBindTexture(GL_TEXTURE_2D, textureId);
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT );
glTexParameterf( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT );
glTexEnvf(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, imageW, imageH, 0, GL_RGBA, GL_UNSIGNED_BYTE, textureData);
free(textureData);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glTranslatef(0.0f, (GLfloat)(sinf(transY)/2.0f), 0.0f);
transY += 0.075f;
glEnable(GL_TEXTURE_2D);
glVertexPointer(2, GL_FLOAT, 0, squareVertices);
glEnableClientState(GL_VERTEX_ARRAY);
glTexCoordPointer(2, GL_FLOAT, 0, textureCoords);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDeleteTextures(1, &textureId);
[(EAGLView *)self.view presentFramebuffer];
}
The result works entirely as you seem to intend. At a guess, is it possible either that:
you're setting something other than the identity as your projection matrix, causing your geometry to be clipped because it is placed at z = 0?
you've neglected properly to abandon an attempt at ES 2 rendering, causing unexpected results because tasks like textured rendering aren't hardwired in with ES 2 in the same way that they are with ES1?

OpenGL ES Framebuffer weird mirroring when drawing

I really can't wrap my mind around this:
Previously I couldn't get Framebuffers to work, but I've got it going now. However, there is this incredibly weird mirroring going on with the texture generated from the framebuffer, and I have no idea why. Basically, I will try to draw a texture at 0,0 using GL_TRIANGLE_FAN, and the texture appears as normal (more or less) in the top right corner, but also appears in the bottom left corner, mirrored. If I fill up most or all of my viewport area with the same texture, the result is an ugly z-fighting overlap.
Screenshots will do this more justice.
Original image:
Original http://img301.imageshack.us/img301/1518/testsprite.png
Drawn 80x80 at (0,0)
80x80 http://img407.imageshack.us/img407/8339/screenshot20100106at315.png
Drawn 100x180 at (0,0)
100x180 http://img503.imageshack.us/img503/2584/screenshot20100106at316.png
Drawn 320x480 at (0,0)
320x480 http://img85.imageshack.us/img85/9172/screenshot20100106at317.png
And here is my code:
Set up the view:
//Apply the 2D orthographic perspective.
glViewport(0,0,320,480);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0, 320, 480, 0, -10000.0f, 100.0f);
//Disable depth testing.
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glDisable(GL_DEPTH_TEST);
//Enable vertext and texture coordinate arrays.
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glShadeModel(GL_SMOOTH);
glClearColor(0.5f, 0.5f, 0.5f, 1.0f);
glGetError(); // Clear error codes
sprite = [Sprite createSpriteFromImage:#"TestSprite.png"];
[sprite retain];
[self createTextureBuffer];
Create the texture buffer.
- (void) createTextureBuffer
{
// generate texture
glGenTextures(1, &bufferTexture);
glBindTexture(GL_TEXTURE_2D, bufferTexture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 512, 512, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL); // check if this is right
// generate FBO
glGenFramebuffersOES(1, &framebuffer);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
// associate texture with FBO
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, bufferTexture, 0);
// clear texture bind
glBindTexture(GL_TEXTURE_2D,0);
// check if it worked (probably worth doing :) )
GLuint status = glCheckFramebufferStatusOES(GL_FRAMEBUFFER_OES);
if (status != GL_FRAMEBUFFER_COMPLETE_OES)
{
printf("FBO didn't work...");
}
}
Run the render loop.
- (void)drawView
{
[self drawToTextureBuffer];
// Make sure that you are drawing to the current context
[EAGLContext setCurrentContext:context];
//Bind the GLView's buffer.
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer);
glViewport(0, 0, 320, 480);
//Clear the graphics context.
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
//Push the matrix so we can keep it as it was previously.
glPushMatrix();
//Rotate to match landscape mode.
glRotatef(90.0, 0, 0, 1);
glTranslatef(0.0f, -320.0f, 0.0f);
//Store the coordinates/dimensions from the rectangle.
float x = 0.0f;
float y = 0.0f;
float w = 480.0f;
float h = 320.0f;
// Set up an array of values to use as the sprite vertices.
GLfloat vertices[] =
{
x, y,
x, y+h,
x+w, y+h,
x+w, y
};
// Set up an array of values for the texture coordinates.
GLfloat texcoords[] =
{
0, 0,
0, 1,
1, 1,
0, 1
};
//Render the vertices by pointing to the arrays.
glVertexPointer(2, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
// Set the texture parameters to use a linear filter when minifying.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//Enable 2D textures.
glEnable(GL_TEXTURE_2D);
//Bind this texture.
glBindTexture(GL_TEXTURE_2D, bufferTexture);
//Finally draw the arrays.
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
//Restore the model view matrix to prevent contamination.
glPopMatrix();
GLenum err = glGetError();
if (err != GL_NO_ERROR)
{
NSLog(#"Error on draw. glError: 0x%04X", err);
}
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
On the first pass, the render loop will draw the image into the FBO.
- (void)drawToTextureBuffer
{
if (!bufferWasCreated)
{
// render to FBO
glBindFramebufferOES(GL_FRAMEBUFFER_OES, framebuffer);
// set the viewport as the FBO isn't be the same dimension as the screen
glViewport(0, 0, 512, 512);
glPushMatrix();
//Store the coordinates/dimensions from the rectangle.
float x = 0.0f;
float y = 0.0f;
float w = 320.0f;
float h = 480.0f;
// Set up an array of values to use as the sprite vertices.
GLfloat vertices[] =
{
x, y,
x, y+h,
x+w, y+h,
x+w, y
};
// Set up an array of values for the texture coordinates.
GLfloat texcoords[] =
{
0, 0,
0, 1,
1, 1,
1, 0
};
//Render the vertices by pointing to the arrays.
glVertexPointer(2, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texcoords);
// Set the texture parameters to use a linear filter when minifying.
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
//Allow transparency and blending.
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
//Enable 2D textures.
glEnable(GL_TEXTURE_2D);
//Bind this texture.
glBindTexture(GL_TEXTURE_2D, sprite.texture);
//Finally draw the arrays.
glDrawArrays(GL_TRIANGLE_FAN, 0, 4);
//Restore the model view matrix to prevent contamination.
glPopMatrix();
GLenum err = glGetError();
if (err != GL_NO_ERROR)
{
NSLog(#"Error on draw. glError: 0x%04X", err);
}
//Unbind this buffer.
glBindFramebufferOES(GL_FRAMEBUFFER_OES, 0);
bufferWasCreated = YES;
}
}
Your texcoords in - (void)drawView seem to be wrong
GLfloat texcoords[] =
{
0, 0,
0, 1,
1, 1,
0, 1 << HERE should be 1, 0
};