OpenGL ES 图片到纹理读取方式

1.使用CoreGraphics

//从图片中加载纹理
- (GLuint)setupTexture:(NSString *)fileName {
    
    //1、将 UIImage 转换为 CGImageRef
    CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
    
    //判断图片是否获取成功
    if (!spriteImage) {
        NSLog(@"Failed to load image %@", fileName);
        exit(1);
    }
    
    //2、读取图片的大小,宽和高
    size_t width = CGImageGetWidth(spriteImage);
    size_t height = CGImageGetHeight(spriteImage);
    
    //3.获取图片字节数 宽*高*4(RGBA)
    GLubyte * spriteData = (GLubyte *) calloc(width * height * 4, sizeof(GLubyte));
    
    //4.创建上下文
    /*
     参数1:data,指向要渲染的绘制图像的内存地址
     参数2:width,bitmap的宽度,单位为像素
     参数3:height,bitmap的高度,单位为像素
     参数4:bitPerComponent,内存中像素的每个组件的位数,比如32位RGBA,就设置为8
     参数5:bytesPerRow,bitmap的没一行的内存所占的比特数
     参数6:colorSpace,bitmap上使用的颜色空间  kCGImageAlphaPremultipliedLast:RGBA
     */
    CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4,CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
    
    
    //5、在CGContextRef上--> 将图片绘制出来
    /*
     CGContextDrawImage 使用的是Core Graphics框架,坐标系与UIKit 不一样。UIKit框架的原点在屏幕的左上角,Core Graphics框架的原点在屏幕的左下角。
     CGContextDrawImage
     参数1:绘图上下文
     参数2:rect坐标
     参数3:绘制的图片
     */
    CGRect rect = CGRectMake(0, 0, width, height);
    
    // 图片正向-否则绘制出来的图片上下是反的
    CGContextTranslateCTM(spriteContext, 0, rect.size.height);
    CGContextScaleCTM(spriteContext, 1.0, -1.0);
    
    //6.使用默认方式绘制
    CGContextDrawImage(spriteContext, rect, spriteImage);
    
    //7、画图完毕就释放上下文
    CGContextRelease(spriteContext);
    
    //8、绑定纹理到默认的纹理ID(
    glBindTexture(GL_TEXTURE_2D, 0);
    
    //9.设置纹理属性
    /*
     参数1:纹理维度
     参数2:线性过滤、为s,t坐标设置模式
     参数3:wrapMode,环绕模式
     */
    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);
    
    float fw = width, fh = height;
    
    //10.载入纹理2D数据
    /*
     参数1:纹理模式,GL_TEXTURE_1D、GL_TEXTURE_2D、GL_TEXTURE_3D
     参数2:加载的层次,一般设置为0
     参数3:纹理的颜色值GL_RGBA
     参数4:宽
     参数5:高
     参数6:border,边界宽度
     参数7:format
     参数8:type
     参数9:纹理数据
     */
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);

    //11.释放spriteData
    free(spriteData);
    return 0;
}

2.不使用CoreGraphics

- (GLuint)setupTextureNoneUsingCoreGraphics:(NSString *)fileName {
    CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;
    
    //判断图片是否获取成功
    if (!spriteImage) {
        NSLog(@"Failed to load image %@", fileName);
        exit(1);
    }
    
    //2、读取图片的大小,宽和高
    size_t width = CGImageGetWidth(spriteImage);
    size_t height = CGImageGetHeight(spriteImage);
    
    GLubyte *imageData = NULL;
    CFDataRef dataFromImageDataProvider = NULL;
    dataFromImageDataProvider = CGDataProviderCopyData(CGImageGetDataProvider(spriteImage));
    imageData = (GLubyte *)CFDataGetBytePtr(dataFromImageDataProvider);
    
    //8、绑定纹理到默认的纹理ID(
    glBindTexture(GL_TEXTURE_2D, 0);
    
    //9.设置纹理属性
    /*
     参数1:纹理维度
     参数2:线性过滤、为s,t坐标设置模式
     参数3:wrapMode,环绕模式
     */
    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);
    
    float fw = width, fh = height;
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);
    
    if (dataFromImageDataProvider) {
        CFRelease(dataFromImageDataProvider);
    }
    
    return 0;
}

3.动态判断是否使用CoreGraphics

shouldRedrawUsingCoreGraphics == YES 还有一种情况是图片尺寸大于屏幕的时候,下面没有实现,自行查阅GPUImage
- (void)setUpTextureWithImageName:(NSString *)imageName andIsGenerateMipmap:(BOOL)isCreate{
    // 默认不使用CoreGraphics
    BOOL shouldRedrawUsingCoreGraphics = NO;
    
    //1、将 UIImage 转换为 CGImageRef
    CGImageRef newImageSource = [UIImage imageNamed:imageName].CGImage;
    
    if (CGImageGetBytesPerRow(newImageSource) != CGImageGetWidth(newImageSource) * 4 || CGImageGetBitsPerPixel(newImageSource) != 32 ||
        CGImageGetBitsPerComponent(newImageSource) != 8)
    {
        shouldRedrawUsingCoreGraphics = YES;
    } else {
        /* Check that the bitmap pixel format is compatible with GL */
        CGBitmapInfo bitmapInfo = CGImageGetBitmapInfo(newImageSource);
        if ((bitmapInfo & kCGBitmapFloatComponents) != 0) {
            /* We don't support float components for use directly in GL */
            shouldRedrawUsingCoreGraphics = YES;
        } else {
            CGBitmapInfo byteOrderInfo = bitmapInfo & kCGBitmapByteOrderMask;
            if (byteOrderInfo == kCGBitmapByteOrder32Little) {
                /* Little endian, for alpha-first we can use this bitmap directly in GL */
                CGImageAlphaInfo alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask;
                if (alphaInfo != kCGImageAlphaPremultipliedFirst && alphaInfo != kCGImageAlphaFirst &&
                    alphaInfo != kCGImageAlphaNoneSkipFirst) {
                    shouldRedrawUsingCoreGraphics = YES;
                }
            } else if (byteOrderInfo == kCGBitmapByteOrderDefault || byteOrderInfo == kCGBitmapByteOrder32Big) {
                /* Big endian, for alpha-last we can use this bitmap directly in GL */
                CGImageAlphaInfo alphaInfo = bitmapInfo & kCGBitmapAlphaInfoMask;
                if (alphaInfo != kCGImageAlphaPremultipliedLast && alphaInfo != kCGImageAlphaLast &&
                    alphaInfo != kCGImageAlphaNoneSkipLast) {
                    shouldRedrawUsingCoreGraphics = YES;
                }
            }
        }
    }
    
    if (isCreate) {
        shouldRedrawUsingCoreGraphics = YES;
    }
    
    if (shouldRedrawUsingCoreGraphics) {
        [self setupTexture:imageName];
    } else {
        [self setupTextureNoneUsingCoreGraphics:imageName];
    }
}

4.OpenGL ES 渲染图片自适应

纹理坐标是不变的,相对改变顶点坐标
1.默认渲染区域
2.基于UIView(layer)比例 屏幕内按照图片尺寸最大限度渲染
3.基于图片比例  按照图片比例采集渲染
 GLuint fillMode = 2;
    
    CGImageRef spriteImage = [UIImage imageNamed:@"kunkun.jpg"].CGImage;
    
    //判断图片是否获取成功
    if (!spriteImage) {
        NSLog(@"Failed to load image");
        exit(1);
    }
    
    //2、读取图片的大小,宽和高
    GLfloat width = CGImageGetWidth(spriteImage);
    GLfloat height = CGImageGetHeight(spriteImage);
    CGSize inputImageSize = CGSizeMake(width, height);
    
    CGFloat heightScaling = 0.0, widthScaling = 0.0;
    CGSize currentViewSize = self.bounds.size;
    CGRect insetRect = AVMakeRectWithAspectRatioInsideRect(inputImageSize, self.layer.bounds);
    switch(fillMode)
    {
        case 1:
        {
            widthScaling = 1.0;
            heightScaling = 1.0;
        };
        break;
            
        case 2:
        {
            widthScaling = insetRect.size.width / currentViewSize.width;
            heightScaling = insetRect.size.height / currentViewSize.height;
        }; break;
            
        case 3:
        {
            widthScaling = currentViewSize.height / insetRect.size.height;
            heightScaling = currentViewSize.width / insetRect.size.width;
        };
        break;
    }
    NSLog(@"widthScaling == %lf", widthScaling);
    NSLog(@"heightScaling == %lf", heightScaling);

  //动态调整顶点数组
    GLfloat attrArr[] =
    {
        -widthScaling, -heightScaling, 0.0f,     0.0f, 0.0f,
        widthScaling, -heightScaling, 0.0f,     1.0f, 0.0f,
        -widthScaling,  heightScaling, 0.0f,    0.0f, 1.0f,
        widthScaling,  heightScaling, 0.0f,     1.0f, 1.0f,
    };

你可能感兴趣的:(OpenGL ES 图片到纹理读取方式)