I'm drawing text with OpenGL ES 2.0, but the result doesn't look good (especially the bottom of "t"):
(It looks kinda pixelized and blurred)
I don't know exactly why since I load the font in high res (200px or 400px) for example.
I draw each char in an image, that compose the texture atlas. So all the chars can be displayed at any time without loading. I scale the texture with openGL (MVP matrix), but it shouldn't look as bad anyway.
Here's an UIImage of the char "t" that I retrieve with the method below, before it's processed with openGL :
(You can see it look way better without OpenGL)
Here's the code I use to create an image from a char :
- (id)initWithString:(NSString *)string dimensions:(CGSize)dimensions alignment:(NSTextAlignment)alignment fontName:(NSString *)name fontSize:(CGFloat)size {
NSUInteger width, height, i;
CGContextRef context;
void *data;
CGColorSpaceRef colorSpace;
UIFont *font;
font = [UIFont fontWithName:name size:size];
width = (NSUInteger)dimensions.width;
height = (NSUInteger)dimensions.height;
while(dimensions.width > kMaxTextureSize && size > 0) {
font = [UIFont fontWithName:name size: --size];
dimensions = [string sizeWithAttributes:#{NSFontAttributeName: font}];
width = (GLuint)NextPowerOfTwo((int)dimensions.width);
height = (GLuint)NextPowerOfTwo((int)dimensions.height);
}
colorSpace = CGColorSpaceCreateDeviceRGB();
data = calloc(1, width * height * 4);
context = CGBitmapContextCreate(data,
width, height,
8,
4 * width,
colorSpace,
kCGImageAlphaPremultipliedFirst | kCGBitmapByteOrder32Big);
CGColorSpaceRelease(colorSpace);
CGContextSetRGBFillColor(context, 0.f, 0.f, 0.f, 1);
CGContextTranslateCTM(context, 0.0, height);
CGContextScaleCTM(context, 1.0f, -1.0f); //NOTE: NSString draws in UIKit referential i.e. renders upside-down compared to CGBitmapContext referential
UIGraphicsPushContext(context);
NSMutableParagraphStyle *style = [[NSParagraphStyle defaultParagraphStyle] mutableCopy];
[style setLineBreakMode:NSLineBreakByWordWrapping];
UIColor *whiteColor = [UIColor whiteColor];
NSDictionary *attrsDictionary = #{
NSFontAttributeName: font,
NSBaselineOffsetAttributeName: #1.0F,
NSParagraphStyleAttributeName: style,
NSForegroundColorAttributeName: whiteColor
};
CGRect destRect = CGRectMake(0, 0, dimensions.width, dimensions.height);
CGContextSetTextDrawingMode(context, kCGTextFill);
CGContextSetAllowsAntialiasing(context, YES);
CGContextSetShouldAntialias(context, YES);
CGContextSetShouldSmoothFonts(context, YES);
[string drawInRect:destRect
withAttributes:attrsDictionary];
CGImageRef cgImageFinal = CGBitmapContextCreateImage(context);
UIGraphicsPopContext();
self = [self initWithData:data pixelFormat:GL_RGBA
pixelsWide:width pixelsHigh:height];
CGContextRelease(context);
free(data);
return self;
}
And here's the code to retrieve a openGL texture from it :
- (id)initWithData:(const void *)data
pixelFormat:(GLenum)pixelFormat
pixelsWide:(NSUInteger)width
pixelsHigh:(NSUInteger)height {
if ((self = [super init])) {
glActiveTexture(GL_TEXTURE0);
glGenTextures(1, &_texture);
glBindTexture(GL_TEXTURE_2D, _texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
switch (pixelFormat) {
case GL_RGBA:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data);
break;
case GL_RGB:
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_SHORT_5_6_5, data);
break;
case GL_ALPHA:
glTexImage2D(GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
break;
default:
[NSException raise:NSInternalInconsistencyException format:#""];
}
self.width = width;
self.height = height;
}
return self;
}
Any help would be really much appreciated !
Related
I copied this code straight out of a book and I don't know what the problem is. I am getting an EXC BAD ACCESS runtime error on the very last line where glTexImage2d is called. I think it's coming from the pixelData pointer. But I don't know what the problem is. If any geniuses out there could help i'd greatly appreciate it. I am using Xcode 6.
#import "TextureHelper.h"
#implementation TextureHelper
-(void) createTextureFromImage: (NSString *) picName{
UIImage *pic = [UIImage imageNamed:picName];
int scaleFactor = 1;
float iOSVersion = [[[UIDevice currentDevice] systemVersion] floatValue];
if(iOSVersion >= 4.0){
if(pic.scale >= 2){
scaleFactor = pic.scale;
}
}
if(pic){
//set texture dimentions
width = pic.size.width * scaleFactor;
height = pic.size.height * scaleFactor;
/*
if ((width & (width-1)) !=0 || (height & height-1)) != 0 || width> 2048 || height > 2048) {
NSLog(#"ERROR:%# width and/or height is not power of 2 or is > 2048!", picName);
}
*/
GLubyte *pixelData = [self generatePixelDataFromImage:pic];
[self generateTexture:pixelData];
int memory = width*height*4;
NSLog(#"%#, Size:%i KB, ID:%i", picName, memory/1024, textureID);
free(pixelData);
}else{
NSLog(#"ERROR:%# not found, texture not created.",picName);
}
}
-(GLubyte *) generatePixelDataFromImage: (UIImage *) pic{
GLubyte *pixelData = (GLubyte *) calloc(width * height *4, sizeof(GLubyte));
CGColorSpaceRef imageCS = CGImageGetColorSpace(pic.CGImage);
CGBitmapInfo bitmapInfo = (CGBitmapInfo) kCGImageAlphaPremultipliedLast;
CGContextRef gc = CGBitmapContextCreate(pixelData, width, height, 8, width*4, imageCS, bitmapInfo);
CGContextDrawImage(gc, CGRectMake(0, 0, width, height), pic.CGImage);
CGContextRelease(gc);
return pixelData;
}
-(void) generateTexture: (GLubyte * ) pixelData{
//Create GL Texture
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, &pixelData);
}
#end
I fixed this because I stupidly included the & symbol in pixelData.
I'm trying to load a screenshot into an OpenGLES Texture, but when i display it, it is just black.
Here is how I get the screenshot:
UIGraphicsBeginImageContext(self.bounds.size);
[self.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage* image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
and here is how I'm trying to load the image into the Texture:
GLuint setupTextureFromImage(UIImage* image) {
CGImageRef spriteImage = image.CGImage;
if (!spriteImage) {
NSLog(#"Failed to load image");
exit(1);
}
size_t width = CGImageGetWidth(spriteImage);
size_t height = CGImageGetHeight(spriteImage);
GLubyte * spriteData = (GLubyte *) calloc(width*height*4, sizeof(GLubyte));
CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4, CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Host);
CGContextDrawImage(spriteContext, CGRectMake(0, 0, width, height), spriteImage);
CGContextRelease(spriteContext);
GLuint texName;
glGenTextures(1, &texName);
glBindTexture(GL_TEXTURE_2D, texName);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, (int) width, (int) height, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
free(spriteData);
return texName;
}
if I load an image from the resources with [UIImage imageNamed: #"FileName.png"] it works and if I'm setting the screenshot as the background color it also works, so both parts work separately
I'm using vuforia for Augmented Reality applciation. When i detect image i can able display or render 3D object and UIImageView then i can take the screenshot of 3D object but i can't save the normal image. I'm just displaying normal UIImageview holding of images. Do i need to render 2D image instead of normal UIImageView?
Render 3D:
- (void)renderFrameQCAR
{
[self setFramebuffer];
// Clear colour and depth buffers
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
// Render video background and retrieve tracking state
QCAR::State state = QCAR::Renderer::getInstance().begin();
QCAR::Renderer::getInstance().drawVideoBackground();
glEnable(GL_DEPTH_TEST);
// We must detect if background reflection is active and adjust the culling direction.
// If the reflection is active, this means the pose matrix has been reflected as well,
// therefore standard counter clockwise face culling will result in "inside out" models.
if (offTargetTrackingEnabled) {
glDisable(GL_CULL_FACE);
} else {
glEnable(GL_CULL_FACE);
}
glCullFace(GL_BACK);
if(QCAR::Renderer::getInstance().getVideoBackgroundConfig().mReflection == QCAR::VIDEO_BACKGROUND_REFLECTION_ON)
glFrontFace(GL_CW); //Front camera
else
glFrontFace(GL_CCW); //Back camera
for (int i = 0; i < state.getNumTrackableResults(); ++i) {
// Get the trackable
// _numResults = state.getNumTrackableResults();
[self performSelectorOnMainThread:#selector(DisplayPhotoButton
) withObject:nil waitUntilDone:YES];
const QCAR::TrackableResult* result = state.getTrackableResult(i);
const QCAR::Trackable& trackable = result->getTrackable();
//const QCAR::Trackable& trackable = result->getTrackable();
QCAR::Matrix44F modelViewMatrix = QCAR::Tool::convertPose2GLMatrix(result->getPose());
// OpenGL 2
QCAR::Matrix44F modelViewProjection;
if (offTargetTrackingEnabled) {
SampleApplicationUtils::rotatePoseMatrix(90, 1, 0, 0,&modelViewMatrix.data[0]);
SampleApplicationUtils::scalePoseMatrix(kObjectScaleOffTargetTracking, kObjectScaleOffTargetTracking, kObjectScaleOffTargetTracking, &modelViewMatrix.data[0]);
} else {
SampleApplicationUtils::translatePoseMatrix(0.0f, 0.0f, kObjectScaleNormal, &modelViewMatrix.data[0]);
SampleApplicationUtils::scalePoseMatrix(kObjectScaleNormal, kObjectScaleNormal, kObjectScaleNormal, &modelViewMatrix.data[0]);
}
SampleApplicationUtils::multiplyMatrix(&vapp.projectionMatrix.data[0], &modelViewMatrix.data[0], &modelViewProjection.data[0]);
glUseProgram(shaderProgramID);
if (offTargetTrackingEnabled) {
glVertexAttribPointer(vertexHandle, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)buildingModel.vertices);
glVertexAttribPointer(normalHandle, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)buildingModel.normals);
glVertexAttribPointer(textureCoordHandle, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)buildingModel.texCoords);
} else {
glVertexAttribPointer(vertexHandle, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)teapotVertices);
glVertexAttribPointer(normalHandle, 3, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)teapotNormals);
glVertexAttribPointer(textureCoordHandle, 2, GL_FLOAT, GL_FALSE, 0, (const GLvoid*)teapotTexCoords);
}
glEnableVertexAttribArray(vertexHandle);
glEnableVertexAttribArray(normalHandle);
glEnableVertexAttribArray(textureCoordHandle);
// Choose the texture based on the target name
int targetIndex = 0; // "stones"
if (!strcmp(trackable.getName(), "chips"))
targetIndex = 1;
else if (!strcmp(trackable.getName(), "tarmac"))
targetIndex = 2;
glActiveTexture(GL_TEXTURE0);
if (offTargetTrackingEnabled) {
glBindTexture(GL_TEXTURE_2D, augmentationTexture[3].textureID);
} else {
glBindTexture(GL_TEXTURE_2D, augmentationTexture[targetIndex].textureID);
}
glUniformMatrix4fv(mvpMatrixHandle, 1, GL_FALSE, (const GLfloat*)&modelViewProjection.data[0]);
glUniform1i(texSampler2DHandle, 0 /*GL_TEXTURE0*/);
if (offTargetTrackingEnabled) {
glDrawArrays(GL_TRIANGLES, 0, buildingModel.numVertices);
} else {
glDrawElements(GL_TRIANGLES, NUM_TEAPOT_OBJECT_INDEX, GL_UNSIGNED_SHORT, (const GLvoid*)teapotIndices);
}
SampleApplicationUtils::checkGlError("EAGLView renderFrameQCAR");
}
glDisable(GL_DEPTH_TEST);
glDisable(GL_CULL_FACE);
glDisableVertexAttribArray(vertexHandle);
glDisableVertexAttribArray(normalHandle);
glDisableVertexAttribArray(textureCoordHandle);
QCAR::Renderer::getInstance().end();
[self presentFramebuffer];
}
Display UIImageView when cameraview open:
- (id)initWithFrame:(CGRect)frame appSession:(SampleApplicationSession *) app
{
self = [super initWithFrame:frame];
if (self) {
vapp = app;
// takePhotoFlag = NO;
// [self DisplayPhotoButton];
// Enable retina mode if available on this device
if (YES == [vapp isRetinaDisplay]) {
[self setContentScaleFactor:2.0f];
}
// Load the augmentation textures
for (int i = 0; i < NUM_AUGMENTATION_TEXTURES; ++i) {
augmentationTexture[i] = [[Texture alloc] initWithImageFile:[NSString stringWithCString:textureFilenames[i] encoding:NSASCIIStringEncoding]];
}
// Create the OpenGL ES context
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
// The EAGLContext must be set for each thread that wishes to use it.
// Set it the first time this method is called (on the main thread)
if (context != [EAGLContext currentContext]) {
[EAGLContext setCurrentContext:context];
}
// Generate the OpenGL ES texture and upload the texture data for use
// when rendering the augmentation
for (int i = 0; i < NUM_AUGMENTATION_TEXTURES; ++i) {
GLuint textureID;
glGenTextures(1, &textureID);
[augmentationTexture[i] setTextureID: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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, [augmentationTexture[i] width], [augmentationTexture[i] height], 0, GL_RGBA, GL_UNSIGNED_BYTE, (GLvoid*)[augmentationTexture[i] pngData]);
}
offTargetTrackingEnabled = NO;
[self loadBuildingsModel];
[self initShaders];
_takePhotoFlag = NO;
[self DisplayPhotoButton];
}
return self;
}
- (void)DisplayPhotoButton
{
UIImage *closeButtonImage = [UIImage imageNamed:#"back.png"];
// UIImage *closeButtonTappedImage = [UIImage imageNamed:#"button_close_pressed.png"];
CGRect aRect = CGRectMake(20,20,
closeButtonImage.size.width,
closeButtonImage.size.height);
photo = [UIButton buttonWithType:UIButtonTypeCustom];
photo.frame = aRect;
photo.userInteractionEnabled=YES;
[photo setImage:closeButtonImage forState:UIControlStateNormal];
// photo.autoresizingMask = UIViewAutoresizingFlexibleLeftMargin;
[photo addTarget:self action:#selector(takePhoto) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:photo];
UIButton *arrowButton = [UIButton buttonWithType:UIButtonTypeCustom];
[arrowButton setImage:[UIImage imageNamed:#"back_btn.png"] forState:UIControlStateNormal];
// [overlayButton setFrame:CGRectMake(80, 420, 60, 30)];
[arrowButton setFrame:CGRectMake(100, 10, 40, 40)];
[arrowButton addTarget:self action:#selector(showActionSheet:forEvent:) forControlEvents:UIControlEventTouchUpInside];
[self addSubview:arrowButton];
}
OpenGL screenshot:
- (UIImage*) glToUIImage
{
UIImage *outputImage = nil;
CGFloat scale = [[UIScreen mainScreen] scale];
CGRect s = CGRectMake(0, 0, 320.0f * scale, 480.0f * scale);
uint8_t *buffer = (uint8_t *) malloc(s.size.width * s.size.height * 4);
glReadPixels(0, 0, s.size.width, s.size.height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
UIImage *imageFromRawData(uint8_t *data, int width, int height) {
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL,data,width*height*4,NULL);
CGImageRef imageRef = CGImageCreate(width, height, 8, 32, width*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaLast, provider, NULL, NO, kCGRenderingIntentDefault);
UIImage *newImage = [UIImage imageWithCGImage:imageRef];
return newImage;
}
CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, buffer, s.size.width * s.size.height * 4, NULL);
CGImageRef iref = CGImageCreate(s.size.width, s.size.height, 8, 32, s.size.width * 4, CGColorSpaceCreateDeviceRGB(), kCGBitmapByteOrderDefault, ref, NULL, true, kCGRenderingIntentDefault);
size_t width = CGImageGetWidth(iref);
size_t height = CGImageGetHeight(iref);
size_t length = width * height * 4;
uint32_t *pixels = (uint32_t *)malloc(length);
CGContextRef context1 = CGBitmapContextCreate(pixels, width, height, 8, width * 4,
CGImageGetColorSpace(iref), kCGImageAlphaNoneSkipFirst | kCGBitmapByteOrder32Big);
CGAffineTransform transform = CGAffineTransformIdentity;
transform = CGAffineTransformMakeTranslation(0.0f, height);
transform = CGAffineTransformScale(transform, 1.0, -1.0);
CGContextConcatCTM(context1, transform);
CGContextDrawImage(context1, CGRectMake(0.0f, 0.0f, width, height), iref);
CGImageRef outputRef = CGBitmapContextCreateImage(context1);
outputImage = [UIImage imageWithCGImage: outputRef];
CGDataProviderRelease(ref);
CGImageRelease(iref);
CGContextRelease(context1);
CGImageRelease(outputRef);
free(pixels);
free(buffer);
UIImageWriteToSavedPhotosAlbum(outputImage, nil, nil, nil);
return outputImage;
}
Save from present frame buffer:
- (BOOL)presentFramebuffer
{
if (_takePhotoFlag)
{
[self glToUIImage];
_takePhotoFlag = NO;
}
// setFramebuffer must have been called before presentFramebuffer, therefore
// we know the context is valid and has been set for this (render) thread
// Bind the colour render buffer and present it
glBindRenderbuffer(GL_RENDERBUFFER, colorRenderbuffer);
return [context presentRenderbuffer:GL_RENDERBUFFER];
}
You can either have an openGL screenshot or UI screenshot. To combine the 2 I suggest you to do both images. This will sound silly but it is probably the fastest and most powerful way to do this:
Take a screenshot from openGL (as you already do)
Create an image view from that screenshot
Insert that image view on your main view
Take an UI screenshot* of the main view
Remove the image view
*By UI screenshot I mean something like this:
+ (UIImage *)imageFromView:(UIView *)view {
UIGraphicsBeginImageContextWithOptions(view.bounds.size, view.opaque, .0);
[view.layer renderInContext:UIGraphicsGetCurrentContext()];
UIImage * img = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
return img;
}
If you will have an issue such as seeing black background instead of the background image there is probably an issue generating the CGImage somewhere in the pipeline where it is skipping or premultiplying the alpha channel. (a very common mistake)
EDIT: Getting image from read pixels RGBA data:
This is what I used for getting an UIImage from raw RGBA data. Note this procedure will not handle any orientation but you can modify it a bit take the orientation as an argument as well and then use imageWithCGImage:scale:orientation:
UIImage *imageFromRawData(uint8_t *data, int width, int height) {
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL,data,width*height*4,NULL);
CGImageRef imageRef = CGImageCreate(width, height, 8, 32, width*4, CGColorSpaceCreateDeviceRGB(), kCGImageAlphaLast, provider, NULL, NO, kCGRenderingIntentDefault);
UIImage *newImage = [UIImage imageWithCGImage:imageRef];
return newImage;
}
I am using OpenGL to do my drawing on screen and want to draw a portion of the screen to a UIImage. This is code I've cobbled together looking at examples, which works, but produces a memory leak every time it's called. I've tested this on device and the leak still persists and eventually causes a crash. The returned UIImage is saved to an instance variable and is later definitely set to nil again. What is causing the memory leak here?
- (UIImage *)renderToImageWithContentFrame:(CGRect)contentFrame
exportFrame:(CGRect)exportFrame
scale:(float)scale {
float screenWidth = contentFrame.size.width * scale;
float screenHeight = contentFrame.size.height * scale;
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
GLuint renderTex;
glGenTextures(1, &renderTex);
glBindTexture(GL_TEXTURE_2D, renderTex);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, screenWidth, screenHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, renderTex, 0);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
glViewport(0, 0, screenWidth, screenHeight);
[self _renderImageGL];
// grabbing image from FBO
NSInteger dataLength = screenWidth * screenHeight * 4;
GLubyte *data = (GLubyte*)malloc(dataLength * sizeof(GLubyte));
glPixelStorei(GL_PACK_ALIGNMENT, 4);
glReadPixels(0, 0, screenWidth, screenHeight, GL_RGBA, GL_UNSIGNED_BYTE, data);
glDeleteFramebuffers(1, &framebuffer);
CGDataProviderRef ref = CGDataProviderCreateWithData(NULL, data, dataLength, NULL);
CGColorSpaceRef colorspace = CGColorSpaceCreateDeviceRGB();
CGImageRef iref = CGImageCreate(screenWidth, screenHeight, 8, 32, screenWidth * 4, colorspace,
kCGBitmapByteOrder32Big | kCGImageAlphaPremultipliedLast,
ref, NULL, true, kCGRenderingIntentDefault);
float x = (exportFrame.origin.x - contentFrame.origin.x) * scale;
float y = (exportFrame.origin.y - contentFrame.origin.y) * scale;
float width = exportFrame.size.width * scale;
float height = exportFrame.size.height * scale;
CGImageRef cropped = CGImageCreateWithImageInRect(iref, (CGRect){x, y, width, height});
UIGraphicsBeginImageContext((CGSize){width, height});
CGContextRef cgcontext = UIGraphicsGetCurrentContext();
CGContextSetBlendMode(cgcontext, kCGBlendModeCopy);
CGContextDrawImage(cgcontext, (CGRect){0, 0, width, height}, cropped);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();
free(data);
CFRelease(ref);
CFRelease(colorspace);
CGImageRelease(iref);
CGImageRelease(cropped);
return image;
}
The variable renderTex is not being freed (via a call to glDeleteTextures(1, &renderTex);). My guess is that Instruments may not know about OpenGL-allocated memory because that memory may reside on a graphics card and may be harder (or impossible) to track. (Though that's mainly a guess.)
I have 6 squares made up of 2 trangles, each of which is supposed to have a different texture mapped onto it. Instead, each texture is having the last binded texture on it instead of its own. Heres my drawView and setView:
- (void)drawView:(GLView*)view
{
glBindTexture(GL_TEXTURE_2D, texture[0]);
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
static const Vertex3D vertices[] = {
{0,0, 1}, //TL
{ 1024,0, 1}, //TR
{0,-1024, 1}, //BL
{ 1024.0f, -1024.0f, 1} //BR
};
static const GLfloat texCoords[] = {
0.0, 1.0,
1.0, 1.0,
0.0, 0.0,
1.0, 0.0
};
glVertexPointer(3, GL_FLOAT, 0, vertices);
glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
glDisableClientState(GL_VERTEX_ARRAY);
glDisableClientState(GL_TEXTURE_COORD_ARRAY);
}
- (void)setupView:(GLView*)view {
// Bind the number of textures we need.
glGenTextures(1, &texture[0]);
glBindTexture(GL_TEXTURE_2D, texture[0]);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_NEAREST);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameterf(GL_TEXTURE_2D, GL_GENERATE_MIPMAP,GL_TRUE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glLoadIdentity();
NSString *path = [[NSBundle mainBundle] pathForResource:filename ofType:#"jpg"];
NSData *texData = [[NSData alloc] initWithContentsOfFile:path];
UIImage *image = [[UIImage alloc] initWithData:texData];
if (image == nil)
NSLog(#"Do real error checking here");
GLuint width = CGImageGetWidth(image.CGImage);
GLuint height = CGImageGetHeight(image.CGImage);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
void *imageData = malloc( height * width * 4 );
CGContextRef context = CGBitmapContextCreate( imageData, width, height, 8, 4 * width, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big );
// Flip the Y-axis
CGContextTranslateCTM (context, 0, height);
CGContextScaleCTM (context, 1.0, -1.0);
CGColorSpaceRelease( colorSpace );
CGContextClearRect( context, CGRectMake( 0, 0, width, height ) );
CGContextDrawImage( context, CGRectMake( 0, 0, width, height ), image.CGImage );
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
CGContextRelease(context);
free(imageData);
}
You're always using texture[0], so you will indeed get the same texture every time. You need to pass the id of the texture you want to glBindTexture ().
I think the problem is related to the texture binding and in particular to this line:
glBindTexture(GL_TEXTURE_2D, texture[0]);
Double check that you use the right value of the gluint required for the texture binding.
Are you using shaders? In case double check it as well though it is most probably not the case.
I suggest to use texture atlas in order to not kill the overall engine's performances by binding every time a different texture in the GPU.