2010-11-07 21 views

Respuesta

19

Puede usar la propiedad de capa de la vista para obtener el CALayer y usar renderInContext: para dibujar en un contexto CoreGraphics. Puede configurar un contexto CoreGraphics con la memoria que se asigna para recibir un búfer de píxeles. A continuación, puede cargarlo en OpenGL por el método normal.

Así que: hay un medio para obtener el contenido de píxeles de un UIView y OpenGL aceptará los búferes de píxeles. No hay un vínculo específico entre los dos.

Codificación de manera extemporánea, el proceso sería algo así como:

UIView *view = ... something ...; 

// make space for an RGBA image of the view 
GLubyte *pixelBuffer = (GLubyte *)malloc(
           4 * 
           view.bounds.size.width * 
           view.bounds.size.height); 

// create a suitable CoreGraphics context 
CGColorSpaceRef colourSpace = CGColorSpaceCreateDeviceRGB(); 
CGContextRef context = 
    CGBitmapContextCreate(pixelBuffer, 
          view.bounds.size.width, view.bounds.size.height, 
          8, 4*view.bounds.size.width, 
          colourSpace, 
          kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); 
CGColorSpaceRelease(colourSpace); 

// draw the view to the buffer 
[view.layer renderInContext:context]; 

// upload to OpenGL 
glTexImage2D(GL_TEXTURE_2D, 0, 
      GL_RGBA, 
      view.bounds.size.width, view.bounds.size.height, 0, 
      GL_RGBA, GL_UNSIGNED_BYTE, pixelBuffer); 

// clean up 
CGContextRelease(context); 
free(pixelBuffer); 

Eso no se ocupa de cuestiones relacionadas con la no-poder-de-dos vistas de tamaño en hardware sin el no-poder-de-dos textura extensión y supone que ya se ha generado y enlazado un nombre de textura GL adecuado. Compruébalo tú mismo, pero creo que el hardware SGX no es compatible con el poder-de-dos (es decir, iPhone 3GS en adelante, el iPad y todos excepto el iPod Touch de tercera generación de 8g en adelante) pero no en MBX.

La forma más fácil de tratar las texturas que no son de potencia de dos aquí es probablemente crear una potencia lo suficientemente grande de dos texturas y usar glTexSubImage2D para cargar solo la parte de su UIView de origen.

+0

Usando CVOpenGLESTextureCacheCreateTextureForImage debería ser más eficiente que usar glTexImage2D directamente. El buffer de píxeles debe tener definidas las claves 'IOSurfaceProperties' y' OpenGLESCompatibility'. – OrangeDog

5

Aquí hay otro método de agarrar una Capa OpenGL, que es usar glReadPixels. Esto agarrará las capas visibles DETRÁS de su capa openGL, también (básicamente, su pantalla visible). Mira esta pregunta: How do I grab an image form my EAGLLayer ?

Una vez que tengas tu imagen, se debe cambiar el tamaño a la potencia de dos. Puede intentar estirar la imagen, pero eso causará problemas de calidad cuando la reduzca nuevamente, o si lo hace una y otra vez. La mejor manera es dibujar el tamaño normal de su imagen en una textura de base 2 con píxeles adicionales para formar un buffer. Aquí está el código (he modificado esto desde código de otra persona, pero no puedo encontrar el código original, por lo que si alguien ve el código original, por favor hágamelo saber de dónde vino para dar crédito):

-(UIImage*)base2Image:(UIImage *) srcImg { 
    int frame2Base = 512; 

    CGSize srcSize = [srcImg size]; 
    CGRect rec = CGRectMake(0, 0, frame2Base, frame2Base); 

    [srcImg drawInRect:rec blendMode:kCGBlendModeNormal alpha:1.0]; 

    //create a context to do our clipping in 
    UIGraphicsBeginImageContext(CGSizeMake(frame2Base, frame2Base)); 
    CGContextRef currentContext = UIGraphicsGetCurrentContext(); 

    //create a rect with the size we want to crop the image to 
    CGRect clippedRect = CGRectMake(0, 0, frame2Base, frame2Base); 
    CGContextClipToRect(currentContext, clippedRect); 

    //create a rect equivalent to the full size of the image 
    CGRect drawRect = CGRectMake(0, 0, srcSize.width, srcSize.height); 

    //draw the image to our clipped context using our offset rect 
    CGContextDrawImage(currentContext, drawRect, srcImg.CGImage); 

    UIImage *dstImg = UIGraphicsGetImageFromCurrentImageContext(); 
    UIGraphicsEndImageContext(); 
    return dstImg; 
} 

Ahora, una vez hecho esto, usa una matriz de coordenadas de textura para SOLAMENTE extraer la sección de tamaño correcto de su imagen. Tal como este:

GLfloat texCoords[] = { 
    0.0, (float)frameHeight/2BaseHeight, 
    0.0, 0.0, 
    (float)frameWidth/2BaseWidth, (float)frameHeight/2BaseHeight, 
    (float)frameWidth/2BaseWidth, 0.0 
}; 

Y ya lo tienes. Una captura de pantalla de su pantalla visible que ahora es una textura.

+0

¡Esta es una gran técnica! De hecho, necesito obtener el contenido de una parte de la jerarquía de mi vista, pero aun así, +1. –