I've run into what originally seemed should be a very simple problem, but have spent many many hours trying to figure out and have gotten nowhere.
I'm working with Apple's GLImageProcessing sample code and have simplified it to display one EAGLView with a UISlider that adjusts the hue of an image. I've modified EAGLView to inherit from UIImageView so that I can have a little more control over the image displayed. This works fine. The problem comes when I try to add a second image to the screen. Ideally I'd like to have a background image and several other images displayed and have the hue slider simultaneously change the hue of all of them. However, when I try to add a second image to the screen, the first image becomes just a plain black view and actually turns a shade of purple when I move the slider, but is otherwise unresponsive. The new view does function as expected. If I were to add a third, the first 2 would be nonfunctional, and the third would function correctly.
I think what I want to do is have one EAGLView and add textures for new images, but nothing seems to work. Any help to point me in the right direction would be much appreciated. Thanks!
From ViewController.h. Code to add a new EAGLView subview in the viewDidLoad method. There's already another view loaded in the nib:
- (void)viewDidLoad
{
UIImage *img = [UIImage imageNamed:@"Image.png"];
EAGLView *newView = [[EAGLView alloc] initWithImage:img texID:0];
self.view2 = newView;
self.view2.frame = CGRectMake(110, 110, 100, 100);
[self.view addSubview:self.view2];
[newView release];
}
And a simple IBAction fired on Value Changed:
- (void)sliderAction:(id)sender
{
[self.imageView drawViewWithSliderValue:self.slider.value];
[self.view2 drawViewWithSliderValue:self.slider.value];
}
From EAGLView.h, this is the EAGLView init code and the draw code. It's almost the same as the sample code, except it lets you pass an image into your initGL:
-(id) initializeEAGLwithTexID:(int)texID{
// Get the layer
CAEAGLLayer *eaglLayer = (CAEAGLLayer *)self.layer;
eaglLayer.opaque = YES;
eaglLayer.drawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithBool:NO], kEAGLDrawablePropertyRetainedBacking,
kEAGLColorFormatRGBA8, kEAGLDrawablePropertyColorFormat,
nil];
context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES1];
if (!context || ![EAGLContext setCurrentContext:context])
{
[self release];
return nil;
}
// Create system framebuffer object. The backing will be allocated in -reshapeFramebuffer
glGenFramebuffersOES(1, &viewFramebuffer[texID]);
glGenRenderbuffersOES(1, &viewRenderbuffer[texID]);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, viewFramebuffer[texID]);
glBindRenderbufferOES(GL_RENDERBUFFER_OES, viewRenderbuffer[texID]);
glFramebufferRenderbufferOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_RENDERBUFFER_OES, viewRenderbuffer[texID]);
// Perform additional one-time GL initialization
UIImage *myImage = self.image;
NSLog(@"holding image of width: %f height %f", myImage.size.width, myImage.size.height);
CGImageRef imageRef = myImage.CGImage;
initGL(imageRef, texID);
return self;
}
-(id) initWithImage:(UIImage *)image texID:(int)texID{
if((self = [super initWithImage:image])){
self.opaque = YES;
self.contentMode = UIViewContentModeScaleToFill;
[self initializeEAGLwithTexID:texID];
}
return self;
}
- (void)drawViewWithSliderValue:(float)value;
{
drawGL(backingWidth, backingHeight, value, currentID);
[context presentRenderbuffer:GL_RENDERBUFFER_OES];
}
From Imaging.c, the initGL code and drawGL. I modified the code to handle arrays for dealing with multiple textures. I'm relatively sure a bunch of the arrays created here are unnecessary, but since they aren't hurting anything, haven't tried removing any yet:
void initGL(CGImageRef myImage, int currID)
{
int i;
// Query renderer capabilities that affect this app's rendering paths
renderer[currID].extension[APPLE_texture_2D_limited_npot] =
(0 != strstr((char *)glGetString(GL_EXTENSIONS), "GL_APPLE_texture_2D_limited_npot"));
renderer[currID].extension[IMG_texture_format_BGRA8888] =
(0 != strstr((char *)glGetString(GL_EXTENSIONS), "GL_IMG_texture_format_BGRA8888"));
glGetIntegerv(GL_MAX_TEXTURE_SIZE, &renderer[currID].maxTextureSize);
// Constant state for the lifetime of the app-- position and unit0 are always used
glEnableClientState(GL_VERTEX_ARRAY);
glEnableClientState(GL_TEXTURE_COORD_ARRAY);
glEnable(GL_TEXTURE_2D);
glPixelStorei(GL_UNPACK_ALIGNMENT, 1);
// Load image into texture
loadTexture(myImage, &Input[currID], &renderer[currID], currID);
// Modify quad texcoords to match (possibly padded) image
for (i = 0; i < 4; i++)
{
fullquad[i].s *= Input[currID].s;
fullquad[i].t *= Input[currID].t;
flipquad[i].s *= Input[currID].s;
flipquad[i].t *= Input[currID].t;
}
// Create 1x1 for default constant texture
// To enable a texture unit, a valid texture has to be bound even if the combine modes do not access it
GLubyte half[3][4] = {{ 0x80, 0x80, 0x80, 0x80 },{ 0x80, 0x80, 0x80, 0x80 },{ 0x80, 0x80, 0x80, 0x80 }};
glActiveTexture(GL_TEXTURE1);
glGenTextures(1, &Half[currID].texID);
Half[currID].wide = Half[currID].high = 1;
Half[currID].s = Half[currID].t = 1.0;
glBindTexture(GL_TEXTURE_2D, Half[currID].texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, 1, 1, 0, GL_RGBA, GL_UNSIGNED_BYTE, half[currID]);
glActiveTexture(GL_TEXTURE0);
// Remember the FBO being used for the display framebuffer
glGetIntegerv(GL_FRAMEBUFFER_BINDING_OES, (GLint *)&SystemFBO[currID]);
// Create scratch textures and FBOs
glGenTextures(1, &Degen[currID].texID);
Degen[currID].wide = Input[currID].wide;
Degen[currID].high = Input[currID].high;
Degen[currID].s = Input[currID].s;
Degen[currID].t = Input[currID].t;
glBindTexture(GL_TEXTURE_2D, Degen[currID].texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Degen[currID].wide, Degen[currID].high, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glGenFramebuffersOES(1, &DegenFBO[currID]);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, DegenFBO[currID]);
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, Degen[currID].texID, 0);
glGenTextures(1, &Scratch[currID].texID);
Scratch[currID].wide = Input[currID].wide;
Scratch[currID].high = Input[currID].high;
Scratch[currID].s = Input[currID].s;
Scratch[currID].t = Input[currID].t;
glBindTexture(GL_TEXTURE_2D, Scratch[currID].texID);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
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);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, Scratch[currID].wide, Scratch[currID].high, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
glGenFramebuffersOES(1, &ScratchFBO[currID]);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, ScratchFBO[currID]);
glFramebufferTexture2DOES(GL_FRAMEBUFFER_OES, GL_COLOR_ATTACHMENT0_OES, GL_TEXTURE_2D, Scratch[currID].texID, 0);
glBindFramebufferOES(GL_FRAMEBUFFER_OES, SystemFBO[currID]);
}
void drawGL(int wide, int high, float val, int currID)
{
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
glOrthof(0, wide, 0, high, -1, 1);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
glScalef(wide, high, 1);
glBindTexture(GL_TEXTURE_2D, Input[currID].texID);
// Render filtered image to system framebuffer
glViewport(0, 0, wide, high);
hue(flipquad, val);
}