使用 iOS OpenGL ES 实现长腿功能

四、实现拉伸逻辑

```/**
根据当前控件的尺寸和纹理的尺寸，计算初始纹理坐标

@param size 原始纹理尺寸
@param startY 中间区域的开始纵坐标位置 0~1
@param endY 中间区域的结束纵坐标位置 0~1
@param newHeight 新的中间区域的高度
*/
- (void)calculateOriginTextureCoordWithTextureSize:(CGSize)size
startY:(CGFloat)startY
endY:(CGFloat)endY
newHeight:(CGFloat)newHeight {
CGFloat ratio = (size.height / size.width) *
(self.bounds.size.width / self.bounds.size.height);
CGFloat textureWidth = self.currentTextureWidth;
CGFloat textureHeight = textureWidth * ratio;

// 拉伸量
CGFloat delta = (newHeight - (endY -  startY)) * textureHeight;

// 判断是否超出最大值
if (textureHeight + delta >= 1) {
delta = 1 - textureHeight;
newHeight = delta / textureHeight + (endY -  startY);
}

// 纹理的顶点
GLKVector3 pointLT = {-textureWidth, textureHeight + delta, 0};  // 左上角
GLKVector3 pointRT = {textureWidth, textureHeight + delta, 0};  // 右上角
GLKVector3 pointLB = {-textureWidth, -textureHeight - delta, 0};  // 左下角
GLKVector3 pointRB = {textureWidth, -textureHeight - delta, 0};  // 右下角

// 中间矩形区域的顶点
CGFloat startYCoord = MIN(-2 * textureHeight * startY + textureHeight, textureHeight);
CGFloat endYCoord = MAX(-2 * textureHeight * endY + textureHeight, -textureHeight);
GLKVector3 centerPointLT = {-textureWidth, startYCoord + delta, 0};  // 左上角
GLKVector3 centerPointRT = {textureWidth, startYCoord + delta, 0};  // 右上角
GLKVector3 centerPointLB = {-textureWidth, endYCoord - delta, 0};  // 左下角
GLKVector3 centerPointRB = {textureWidth, endYCoord - delta, 0};  // 右下角

// 纹理的上面两个顶点
self.vertices[0].positionCoord = pointRT;
self.vertices[0].textureCoord = GLKVector2Make(1, 1);
self.vertices[1].positionCoord = pointLT;
self.vertices[1].textureCoord = GLKVector2Make(0, 1);
// 中间区域的4个顶点
self.vertices[2].positionCoord = centerPointRT;
self.vertices[2].textureCoord = GLKVector2Make(1, 1 - startY);
self.vertices[3].positionCoord = centerPointLT;
self.vertices[3].textureCoord = GLKVector2Make(0, 1 - startY);
self.vertices[4].positionCoord = centerPointRB;
self.vertices[4].textureCoord = GLKVector2Make(1, 1 - endY);
self.vertices[5].positionCoord = centerPointLB;
self.vertices[5].textureCoord = GLKVector2Make(0, 1 - endY);
// 纹理的下面两个顶点
self.vertices[6].positionCoord = pointRB;
self.vertices[6].textureCoord = GLKVector2Make(1, 0);
self.vertices[7].positionCoord = pointLB;
self.vertices[7].textureCoord = GLKVector2Make(0, 0);
}
```

五、渲染到纹理

```GLuint renderBuffer; // 渲染缓存
GLuint frameBuffer;  // 帧缓存

// 绑定渲染缓存要输出的 layer
glGenRenderbuffers(1, &renderBuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderBuffer);
[self.context renderbufferStorage:GL_RENDERBUFFER fromDrawable:layer];

// 将渲染缓存绑定到帧缓存上
glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);
glFramebufferRenderbuffer(GL_FRAMEBUFFER,
GL_COLOR_ATTACHMENT0,
GL_RENDERBUFFER,
renderBuffer);
```

```// 生成帧缓存，挂载渲染缓存
GLuint frameBuffer;
GLuint texture;

glGenFramebuffers(1, &frameBuffer);
glBindFramebuffer(GL_FRAMEBUFFER, frameBuffer);

glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, newTextureWidth, newTextureHeight, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);

glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, texture, 0);
```

六、保存结果

```// 返回某个纹理对应的 UIImage，调用前先绑定对应的帧缓存
- (UIImage *)imageFromTextureWithWidth:(int)width height:(int)height {
int size = width * height * 4;
GLubyte *buffer = malloc(size);
glReadPixels(0, 0, width, height, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, buffer, size, NULL);
int bitsPerComponent = 8;
int bitsPerPixel = 32;
int bytesPerRow = 4 * width;
CGColorSpaceRef colorSpaceRef = CGColorSpaceCreateDeviceRGB();
CGBitmapInfo bitmapInfo = kCGBitmapByteOrderDefault;
CGColorRenderingIntent renderingIntent = kCGRenderingIntentDefault;
CGImageRef imageRef = CGImageCreate(width, height, bitsPerComponent, bitsPerPixel, bytesPerRow, colorSpaceRef, bitmapInfo, provider, NULL, NO, renderingIntent);

// 此时的 imageRef 是上下颠倒的，调用 CG 的方法重新绘制一遍，刚好翻转过来
UIGraphicsBeginImageContext(CGSizeMake(width, height));
CGContextRef context = UIGraphicsGetCurrentContext();
CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef);
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();
UIGraphicsEndImageContext();

free(buffer);
return image;
}
```