EGL

The OpenGL ES command requires a rendering context and a rendering surface to complete a graph. Rendering context: Stores the relevant OpenGL ES states. Rendering surface: a surface used to draw primitives, which specifies the type of cache required for rendering. Examples are color cache, depth cache, template cache. The OpenGL ES API does not provide information on how to create a render context or how the context is connected to the acoustic window system. EGL is the interface between Khronos rendering apis [such as OpenGL ES] and native window systems. The only platform that supports OpenGL ES but does not support EGL is iOS.

EGL’s main functions are as follows:

  1. Communicate with the local window system
  2. Querying Available Configurations
  3. Create a drawing surface available to OpenGL ES
  4. Synchronize rendering between different classes of apis, such as between OpenGL ES and OpenVG, or between OpenGL and local window drawing commands
  5. Manage rendering resources, such as texture mapping

IOS provides QuartzCore/CAEAGLLayer as the drawing surface

Shaders and programs

Two basic objects need to be created to be rendered by shaders: a shader object and a program object

The general process of obtaining a linked post-shader object consists of six steps:

  1. Create a vertex shader object and a fragment shader object
  2. Link the source code to each shader object
  3. Compile the shader object
  4. Create a program object
  5. Link the compiled shader object to the program object
  6. Linker object

The API is introduced

Shader API

GLuint glCreateShader(GLenum type)

GL_VERTEX_SHADER or GL_FRAGMENT_SHADER RETURN: The return value is a handle to the new shader object and can be called

void glDeleteShader(GLuint shader)

Shader: Handle to the shader object to delete

void glShaderSource(GLuint shader, GLsizei count, const GLchar* const *string, const GLint* length)

Shader: a handle to a shader object count: The number of shader source strings. A shader can consist of multiple source strings, but each shader has only one main function. String: a pointer to an array that holds a shader source string of count: Pointer to an array of integers holding the size of each shader string and the number of elements count

void glCompileShader(GLuint shader)

Shader: Handle to the shader object to compile

void glGetShaderiv(GLuint shader, GLenum pname, GLint* params)

Shader: shader object handle to be compiled pname: name of the obtained parameter params: pointer to the integer storage location of the query result

Pname Optional name
GL_COMPILE_STATUS
GL_DELETE_STATUS
GL_INFO_LOG_LENGTH
GL_SHADER_SOURCE_LENGTH
GL_SHADER_TYPE

void glGetShaderInfoLog(GLuint shader, GLsizei bufsize, GLsizei* length, GLchar* infolog)

Bufsize: the size of the cache where information logs are stored. Length: the length of the log where information is written (minus the null terminator). If you do not need to know the length, you can pass Null infolog: a pointer to the string cache where the information log is stored

Application API

GLuint glCreateProgram(void)

Return: Returns a handle to a new program object

void glDeleteProgram(GLuint program)

Delete program: handle to program object

void glAttachShader(GLuint program, GLuint shader)

Shader: Handle to a shader object pointing to a program link

void glDetachShader(GLuint program, GLuint shader)

Shader: Handle to a shader object pointing to a program link

void glLinkProgram(GLuint program)

Link program: Handle to a program object

void glGetProgramiv(GLuint program, GLenum pname, GLint* params)

Program: handle to the program object. Pname: parameter name to obtain information. Params: pointer to the location where the query result integer is stored

Pname Optional name
GL_ACTIVE_ATTRIBUTES
GL_ACTIVE_ATTRIBUTE_MAX_LENGTH
GL_ACTIVE_UNIFORM_BLOCKS
GL_ACTIVE_UNIFORM_BLOCK_MAX_NAME_LENGTH
GL_ACTIVE_UNIFORMS
GL_ACTIVE_UNIFORM_MAX_LENGTH
GL_ATTACHED_SHADERS
GL_DELETE_STATUS
GL_INFO_LOG_LENGTH
GL_LINK_STATUS
GL_PROGRAM_BINARY_RETRIEVABLE_HINT
GL_TRANSFORM_FEEDBACK_BUFFER_MODE
GL_TRANSFORM_FEEDBACK_VARYINGS
GL_TRANSFORM_FEEDBACK_VARYING_MAX_LENGTH
GL_VALIDATE_STATUS

void glGetProgramInfoLog(GLuint program, GLsizei bufsize, GLsizei* length, GLchar* infolog)

Bufsize: the size of the cache where information logs are stored. Length: the length of the log to which information is written (minus the null terminator). If you do not need to know the length, you can pass Null infolog: a pointer to the string cache where the information log is stored

void glUseProgram(GLuint program)

Set to active program: handle to program object

Relationship between FrmeBuffer and RenderBuffer

Reference documentation

FrameBuffer FrameBuffer

The RenderBuffer is one of the attachments to the frame buffer

The RenderBuffer stores the results of the render operation. The shader can easily manipulate the contents of the RenderBuffer and pass them to the frame buffer for display quickly.

Image to load

Set the shader file

1. Vertex shaders

shaderv.vsh

// Set the image vertex
attribute vec4 position;
// Set texture coordinates
attribute vec2 textCoordinate;
// Pass variables from vertex shader to slice shader (pass texture coordinates)
varying lowp vec2 varyTextCoord;

void main() {
    varyTextCoord = textCoordinate;
    gl_Position = position;
}
Copy the code

2. Chip shader

shaderf.fsh

// Set the float type to high precision
precision highp float;
// Texture coordinates passed from the vertex shader
varying lowp vec2 varyTextCoord;
/ / texture
uniform sampler2D colorMap;

void main() {
    // Pass in the texture and coordinates, return the 4-dimensional vector information of the striene (RGBA)
    gl_FragColor = texture2D(colorMap, varyTextCoord);
}
Copy the code

Texture loading complete code


#import "CustomView.h"
#import <OpenGLES/ES2/gl.h>

/** Create layer 2. Create context 3. 4. Set RenderBuffer 5. Set FrameBuffer 6. Start drawing */

@interface CustomView(a)

// Draw the carrier
@property (nonatomic.strong) CAEAGLLayer *myEAGLLayer;
/ / context
@property (nonatomic.strong) EAGLContext *myContext;

// Render buffer
@property (nonatomic.assign) GLuint myColorRenderBuffer;
// Frame buffer: depth/color/template
@property (nonatomic.assign) GLuint myColorFrameBuffer;

/ / application
@property (nonatomic.assign) GLuint myPrograme;

@end

@implementation CustomView

+ (Class)layerClass {
    return [CAEAGLLayer class];
}

- (void)layoutSubviews {
    [self setupLayer];
    [self setupContext];
    [self deleteBuffer];
    [self setupRenderBuffer];
    [self setupFrameBuffer];
    [self renderLayer];
}

/// Draw layers
- (void)setupLayer {
    // 1. Create layers
    self.myEAGLLayer = (CAEAGLLayer *)self.layer;
    // set the scale
    [self setContentScaleFactor:[UIScreen mainScreen].scale];
    // 3. Set the buffer
    / / kEAGLDrawablePropertyRetainedBacking draw over whether or not to retain
    / / kEAGLDrawablePropertyColorFormat color format
    self.myEAGLLayer.drawableProperties = @{
        kEAGLDrawablePropertyRetainedBacking: @(NO),
        kEAGLDrawablePropertyColorFormat: kEAGLColorFormatRGBA8
    };
}

/// Set the context
- (void)setupContext {
    / / 1. To create
    self.myContext = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
    / / 2. The judgment
    if (!self.myContext) {
        NSLog(@"create context failure");
        return;
    }
    // 3. Set the context
    if(! [EAGLContext setCurrentContext:self.myContext]) {
        NSLog(@"set current context failure");
        return; }}/// delete the buffer
- (void)deleteBuffer {
    glDeleteBuffers(1, &_myColorRenderBuffer);
    self.myColorRenderBuffer = 0;
    glDeleteBuffers(1, &_myColorFrameBuffer);
    self.myColorFrameBuffer = 0;
}

/ / / set the RenderBuffer
- (void)setupRenderBuffer {
    / / 1. Definitions
    GLuint buffer;
    glGenRenderbuffers(1, &buffer);
    self.myColorRenderBuffer = buffer;
    / / 2. Binding
// glBindBuffer(GL_RENDERBUFFER, buffer);
    glBindRenderbuffer(GL_RENDERBUFFER, buffer);
    
    // 3. Set the render context
    [self.myContext renderbufferStorage:GL_RENDERBUFFER fromDrawable:self.myEAGLLayer];
}

/ / / set the FrameBuffer
- (void)setupFrameBuffer {
    / / 1. Definitions
    GLuint buffer;
    glGenFramebuffers(1, &buffer);
    self.myColorFrameBuffer = buffer;
    / / 2. Binding
// glBindBuffer(GL_FRAMEBUFFER, buffer);
    glBindFramebuffer(GL_FRAMEBUFFER, buffer);
    // 3. Bind render buffer and frame buffer
    glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_RENDERBUFFER, self.myColorRenderBuffer);
}

/// start drawing
- (void)renderLayer {
    // 1. Clear the buffer
    glClearColor(0.3.0.45.0.5.1);
    glClear(GL_COLOR_BUFFER_BIT);
    
    // 2. Set the viewport
    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);
    
    // 3. Read the shader file address
    NSString *vertFile = [[NSBundle mainBundle] pathForResource:@"shaderv" ofType:@"vsh"];
    NSString *fragFile = [[NSBundle mainBundle] pathForResource:@"shaderf" ofType:@"fsh"];
    
    // 4. Get program (bind vertex shader and slice shader data)
    self.myPrograme = [self loaderShaders:vertFile withFrag:fragFile];
    
    // 5
    glLinkProgram(self.myPrograme);
    
    GLint linkState;
    // Get the link status
    glGetProgramiv(self.myPrograme, GL_LINK_STATUS, &linkState);
    if (linkState == GL_FALSE) {
        / / link failure
        GLchar message[512];
        glGetProgramInfoLog(self.myPrograme, sizeof(message), 0, &message[0]);
        NSString *messageString = [NSString stringWithUTF8String:message];
        NSLog(@"Programe link failure: %@", messageString);
        return;
    }
    
    // 6
    glUseProgram(self.myPrograme);
    
    // 7. Vertex data, two triangles
    GLfloat attrArr[] =
    {
        0.5f, 0.5f, 1.0f,     1.0f, 0.0f,
        0.5f, 0.5f, 1.0f,     0.0f, 1.0f,
        0.5f, 0.5f, 1.0f,    0.0f, 0.0f,
        
        0.5f, 0.5f, 1.0f,      1.0f, 1.0f,
        0.5f, 0.5f, 1.0f,     0.0f, 1.0f,
        0.5f, 0.5f, 1.0f,     1.0f, 0.0f,
    };
    
    Vertex data -> vertex buffer
    GLuint attrBuffer;
    glGenBuffers(1, &attrBuffer);
    glBindBuffer(GL_ARRAY_BUFFER, attrBuffer);
    glBufferData(GL_ARRAY_BUFFER, sizeof(attrArr), attrArr, GL_DYNAMIC_DRAW);
    
    // 9. Open channel
    // a. Get and open the vertex data channel and set the data
    GLuint position = glGetAttribLocation(self.myPrograme, "position");
    glEnableVertexAttribArray(position);
    glVertexAttribPointer(position, 3, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5.NULL);
    
    // b. Get and open the texture data channel and set the data
    GLuint textCoordinate = glGetAttribLocation(self.myPrograme, "textCoordinate");
    glEnableVertexAttribArray(textCoordinate);
    glVertexAttribPointer(textCoordinate, 2, GL_FLOAT, GL_FALSE, sizeof(GLfloat) * 5, (GLfloat *)NULL + 3);
    
    // load the texture
    [self setupTexture:@"Image"];
    
    // 11. Set the texture sampler
    glUniform1i(glGetUniformLocation(self.myPrograme, "colorMap"), 0);
    
    / / 12. Draw
    glDrawArrays(GL_TRIANGLES, 0.6);
    
    // 13. Display from render buffer to screen
    [self.myContext presentRenderbuffer:GL_RENDERBUFFER];
}

// Get the texture
- (GLuint)setupTexture:(NSString *)fileName {
    // 1
    CGImageRef spriteImage = [UIImage imageNamed:@"Image"].CGImage;
    if(! spriteImage) {NSLog(@"load image failure");
        exit(1);
    }
    / / 2. Wide high
    size_t width = CGImageGetWidth(spriteImage);
    size_t height = CGImageGetHeight(spriteImage);
    
    // 3. Get image bytes width * height *4(RGBA)
    GLubyte *spriteData = (GLubyte *) calloc(width * height * 4.sizeof(GLubyte));
    
    // 4. Set context
    /* Parameter 1: data, pointing to the memory address of the drawn image to be rendered. Parameter 2: width, the bitmap width, in pixels. Parameter 3: height, the bitmap height, in pixels. BitPerComponent, the number of bits per component of pixels in memory, such as 32-bit RGBA, is set to 8. The colorSpace, bitmap using the color space kCGImageAlphaPremultipliedLast: RGBA * /
    CGContextRef spriteContext = CGBitmapContextCreate(spriteData, width, height, 8, width*4.CGImageGetColorSpace(spriteImage), kCGImageAlphaPremultipliedLast);
    // 5. On CGContextRef, draw the picture
    CGRect rect = CGRectMake(0.0, width, height);
    CGContextDrawImage(spriteContext, rect, spriteImage);
    // 6. Finish drawing and release the context
    CGContextRelease(spriteContext);
    // 7. Bind texture to default texture ID. If there is only one texture, the second parameter texture can be set to 0, and texture 0 is activated by default
    glBindTexture(GL_TEXTURE_2D, 0);
    // 8. Set the texture properties
    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);
    
    // 9. Load the texture
    float fw = width, fh = height;
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, fw, fh, 0, GL_RGBA, GL_UNSIGNED_BYTE, spriteData);
    
    / / 10. Release
    free(spriteData);
    return 0;
}


#pragma mark - shader

// create a shader
/// @param vertFilePath Vertex shader string file path
/// @param fragFilePath The string file path of the fragment shader
- (GLuint)loaderShaders:(NSString *)vertFilePath withFrag:(NSString *)fragFilePath {
    // 1. Define vertex shaders and slice shaders
    GLuint verShader, fragShader;
    // 2. Create program
    GLuint program = glCreateProgram();
    
    // 3. Create and compile shaders
    [self compileShader:&verShader type:GL_VERTEX_SHADER filePath:vertFilePath];
    [self compileShader:&fragShader type:GL_FRAGMENT_SHADER filePath:fragFilePath];
    
    // 4. Link shaders and programs
    glAttachShader(program, verShader);
    glAttachShader(program, fragShader);
    
    // 5. Clean up useless objects
    glDeleteShader(verShader);
    glDeleteShader(fragShader);
    
    return program;
}


// create and compile shaders
/// @param shader pointer
/// @param type: vertex/slice
/// @param filePath shader string filePath
- (void)compileShader:(GLuint *)shader type:(GLenum)type filePath:(NSString *)filePath {
    // 1. Read files
    NSString *content = [NSString stringWithContentsOfFile:filePath encoding:NSUTF8StringEncoding error:nil];
    const GLchar *source = (GLchar *)[content UTF8String];
    
    // 2. Create a shader of the corresponding type
    *shader = glCreateShader(type);
    
    // 3. Attach shader source code to shader
    glShaderSource(*shader, 1, &source, NULL);
    
    / / 4. Compilation
    glCompileShader(*shader);
}

@end
Copy the code

Texture flip

1. Rotate matrix without flipping texture

    GLuint rotate = glGetUniformLocation(self.myPrograme, "rotateMatrix");
    float radians = 180 * 3.14159f / 180.0f;
    float s = sin(radians);
    float c = cos(radians);
    
  
    GLfloat zRotation[16] = {
        c, -s, 0.0,
        s, c, 0.0.0.0.1.0.0.0.0.0.0.1.0
    };
    
   glUniformMatrix4fv(rotate, 1, GL_FALSE, (GLfloat *)&zRotation[0]);
Copy the code

2. When decompressing the image, flip the source file (most commonly used ✨✨✨)

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);
CGContextDrawImage(spriteContext, CGRectMake(0.0, width, height), spriteImage);

CGContextTranslateCTM(spriteContext, rect.origin.x, rect.origin.y);
CGContextTranslateCTM(spriteContext, 0, rect.size.height);
CGContextScaleCTM(spriteContext, 1.0.1.0);
CGContextTranslateCTM(spriteContext, -rect.origin.x, -rect.origin.y);
CGContextDrawImage(spriteContext, rect, spriteImage); 

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

3. Modify the slice shader file and texture coordinates

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

4. Modify the vertex shader less than the third method

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

5. Modify texture coordinate data mapping

     GLfloat attrArr[] =
     {
     0.5f, 0.5f, 0.0f,        1.0f, 1.0f, / / right
     0.5f, 0.5f, 0.0f,        0.0f, 0.0f, / / left
     0.5f, 0.5f, 0.0f,       0.0f, 1.0f, / / lower left
     0.5f, 0.5f, 0.0f,         1.0f, 0.0f, / / right
     0.5f, 0.5f, 0.0f,        0.0f, 0.0f, / / left
     0.5f, 0.5f, 0.0f,        1.0f, 1.0f, / / right}; * /Copy the code

See OpenGL 2D Texture Unit & Texture Flip Solutions