Loading pictures

To complete the image loading using OpenGL ES, the following steps are probably needed: 1. Create a layer; 2. Create a context. 3. Clear the cache. 4. Set the render buffer; 5. Set the frame buffer. 6. Draw

Write custom shaders

Create two new files shaderv.vsh and shaderf.fsh in your project. They are vertex shaders and slice shaders respectively.

//shaderv.vsh attribute vec4 position; // Attribute Vec2 textCoordinate; // Texture coordinates varying lowp VEC2 varyTextCoord; Void main(){varyTextCoord = textCoordinate; Gl_Position = position; Gl_Position: built-in variable, final result}Copy the code
//shaderf.fsh precision highp float; // Define the precision of the float type varying LOWp VEC2 varyTextCoord; Uniform sampler2D colorMap; Void main(){gl_FragColor = texture2D(colorMap, varyTextCoord); // Texture image, texture coordinates}Copy the code

Create a layer

You need to rewrite the layerClass and replace the layer it returns with CAEAGLLayer instead of CALayer.

-(void)setupLayer {//1. Create special layer self.myeagLayer = (CAEAGLLayer *)self.layer; Set scale [self setContentScaleFactor:[[UIScreen mainScreen]scale]]; //3. Set description properties, Here don't maintain render content and color format for RGBA8 self. MyEagLayer. DrawableProperties = [NSDictionary dictionaryWithObjectsAndKeys:@false,kEAGLDrawablePropertyRetainedBacking, kEAGLColorFormatRGBA8,kEAGLDrawablePropertyColorFormat,nil]; } +(Class)layerClass{ return [CAEAGLLayer class]; }Copy the code

Create context

- (void) setupContext {/ / 1. Specify the OpenGL ES rendering API version, we use 2.0 = kEAGLRenderingAPIOpenGLES2 EAGLRenderingAPI API; EAGLContext *context = [[EAGLContext alloc]initWithAPI: API]; //3. Check whether the command is created successfully. context) { NSLog(@"Create context failed!" ); return; } //4. Set the graphics context if (! [EAGLContext setCurrentContext:context]) { NSLog(@"setCurrentContext failed!" ); return; } //5. Change the local context to the global self.myContext = context; }Copy the code

Clear the cache

-(void)deleteRenderAndFrameBuffer
{
    glDeleteBuffers(1, &_myColorRenderBuffer);
    self.myColorRenderBuffer = 0;
    
    glDeleteBuffers(1, &_myColorFrameBuffer);
    self.myColorFrameBuffer = 0;   
}
Copy the code

Setting the render buffer

-(void)setupRenderBuffer {// Define a buffer ID; // Apply a buffer flag glGenRenderbuffers(1, &buffer); self.myColorRenderBuffer = buffer; // bind the identifier to GL_RENDERBUFFER glBindRenderbuffer(GL_RENDERBUFFER, self.mycolorrenderbuffer); // Bind the store of the drawable object's CAEAGLLayer to the OpenGL ES renderBuffer and the myEagLayer binding [self.myContext] renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEagLayer]; }Copy the code

Setting the frame Buffer

The process for setting up the two buffers is similar, except that after the final setup, the buffers need to be bound and bound to the attachment point.

-(void)setupFrameBuffer { //1. Define a buffer ID GLuint buffer; Buffers (1, &buffer); // buffers(1, &buffer); //3. self.myColorFrameBuffer = buffer; //4. glBindFramebuffer(GL_FRAMEBUFFER, self.myColorFrameBuffer); / * generated after the frame buffer, then need to bind to framebuffer renderbuffer, call glFramebufferRenderbuffer function to bind to the corresponding attachment point, */ /GL_COLOR_ATTACHMENT0 attachment point //5. Will render buffer myColorRenderBuffer by binding to the GL_COLOR_ATTACHMENT0 glFramebufferRenderbuffer function. glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer); }Copy the code

Began to draw

-(void)renderLayer {glClearColor(0.3f, 0.45f, 0.5f, 1.0f); glClear(GL_COLOR_BUFFER_BIT); //1. Set viewport size CGFloat scale = [[UIScreen mainScreen]scale]; glViewport(self.frame.origin.x * scale, self.frame.origin.y * scale, self.frame.size.width * scale, self.frame.size.height * scale); NSString *vertFile = [[NSBundle mainBundle]pathForResource:@"shaderv" ofType:@" VSH "]; NSString *fragFile = [[NSBundle mainBundle]pathForResource:@"shaderf" ofType:@"fsh"]; NSLog(@"vertFile:%@",vertFile); NSLog(@"fragFile:%@",fragFile); MyPrograme = [self loadShaders:vertFile Withfrag:fragFile]; / / 4. Link glLinkProgram (self. MyPrograme); GLint linkStatus; GlGetProgramiv (self.myprograme, GL_LINK_STATUS, &linkStatus); if (linkStatus == GL_FALSE) { GLchar message[512]; glGetProgramInfoLog(self.myPrograme, sizeof(message), 0, &message[0]); NSString *messageString = [NSString stringWithUTF8String:message]; NSLog(@"Program Link Error:%@",messageString); return; } NSLog(@"Program Link Success!" ); glUseProgram(self.myPrograme); / / 5. Set the vertex and texture coordinates GLfloat attrArr [] = {0.5 f to 0.5 f to 1.0 f to 1.0 f to 0.0 f to 0.5 f to 0.5 f to 1.0 f to 0.0 f to 1.0 f to 0.5 f to 0.5 f, 1.0 f, f, 0.0 0.0 f, f 0.5, 0.5 f to 1.0 f, f 1.0, 1.0 f to 0.5 f, 0.5 f to 1.0 f, 0.0 f, f 1.0, 0.5, f - 0.5 f to 1.0 f, f 1.0, 0.0, f}; ----- process vertex data -------- GLuint attrBuffer; glGenBuffers(1, &attrBuffer); glBindBuffer(GL_ARRAY_BUFFER, attrBuffer); glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW); Position = glGetAttribLocation(self.myprograme, "position"); / / set the appropriate format to read data from a buffer glEnableVertexAttribArray (position); GlVertexAttribPointer (position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, NULL); ---- handle texture data ------- GLuint textCoor = glGetAttribLocation(self.myprograme, "textCoordinate"); glEnableVertexAttribArray(textCoor); glVertexAttribPointer(textCoor, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat)*5, (float *)NULL + 3); [self setupTexture:@"touxiang"]; //10. Set the sampler2D glUniform1i(glGetUniformLocation(self.myPrograme, "colorMap"), 0); //11. Say glDrawArrays(GL_TRIANGLES, 0, 6); //12. Display from render cache to screen [self.myContext presentRenderbuffer:GL_RENDERBUFFER]; } // Set UIImage to CGImageRef CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage; if (! spriteImage) { NSLog(@"Failed to load image %@", fileName); 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); CGRect rect = CGRectMake(0, 0, width, height); //6. Draw CGContextDrawImage(spriteContext, rect, spriteImage) using the default method; CGContextRelease(spriteContext); // bind texture to default texture ID (glBindTexture(GL_TEXTURE_2D, 0); 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, spriteData); //11. Free spriteData free(spriteData); return 0; }Copy the code

Texture flip

This is because the origin of the texture coordinates (0,0) is in the lower left corner, while the origin of the screen coordinates (0,0) is in the upper left corner. If we want to display the image correctly, we have the following methods:

GLKTextureLoader loads the texture

When loading GLKTextureLoaderOriginBottomLeft options Settings.

NSDictionary *options = @{GLKTextureLoaderOriginBottomLeft : @(YES)};
GLKTextureInfo *textureInfo = [GLKTextureLoader textureWithContentsOfFile:filePath options:options error:nil];
Copy the code

When you unzip the image, flip it over

CGImageRef spriteImage = [UIImage imageNamed:fileName].CGImage;

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);
  
CGRect rect = CGRectMake(0, 0, width, height);
CGContextTranslateCTM(spriteContext, 0, rect.size.height);
CGContextScaleCTM(spriteContext, 1.0, -1.0);
CGContextDrawImage(spriteContext, rect, spriteImage); 

CGContextRelease(spriteContext);
glBindTexture(GL_TEXTURE_2D, 0);
Copy the code

Set rotation matrix, rotate vertices in shader without flipping texture

GLuint rotate = glGetUniformLocation(self.program, "rotateMatrix"); float radians = M_PI; float sinR = sin(radians); float cosR = cos(radians); GLfloat zRotation[16] = {cosR, -sinr, 0, 0, sinR, cosR, 0, 0, 0, 1.0, 0, 0.0, 0, 0, 1.0}; glUniformMatrix4fv(rotate, 1, GL_FALSE, (GLfloat *)&zRotation[0]);Copy the code

Set the flipped texture coordinate mapping

GLfloat datas [] = {0.5 f to 0.5 f to 0.0 f to 1.0 f to 1.0 f, / / right - 0.5 f, 0.5 f to 0.0 f, f 0.0, 0.0, f / / upper left - 0.5 f, 0.5 f, f 0.0, 0.0, f 1.0 f, / / lower left 0.5 f, f 0.5, 0.0 f, f 1.0, 0.0, f / / upper right - 0.5 f, f 0.5, 0.0 f, f 0.0, 0.0, f / / upper left 0.5 f to 0.5 f, 0.0 f, f 1.0, 1.0, f / / right};Copy the code

Modify the texture coordinates of the vertex shader

attribute vec4 position; attribute vec2 textCoordinate; varying lowp vec2 varyTextCoord; Void main() {varyTextCoord = vec2(textCoordinate. X, 1.0-textcoordinate. Y); gl_Position = position; }Copy the code

Modify the texture coordinates of the slice shader

varying lowp vec2 varyTextCoord; uniform sampler2D colorMap; Void main() {lowp coord = vec2(varyTextCoord.x, 1.0-varyTextcoord.y); gl_FragColor = texture2D(colorMap, coord); }Copy the code