svn

批量添加 iOS 目录下的文件
1
svn add --force iOS/
提交 iOS 目录
1
svn commit iOS/ -m 'd'
查看 提交历史
1
2
3
4
5
# -l 5 只显示5条记录
# -v 目录信息
# -r 6:9 查看版本号为6到9的信息
# filepath/t.html 查看t.html的信息
svn log
查看 历史修改
1
2
3
4
# 不带参数:工作区与缓存.svn的对比
# -r 3 工作区与版本号为3的对比
# -r 3:4 版本号为3、4的对比
svn diff
查看历史文件
1
2
# 查看版本号为21的 t.html文件内容
svn cat -r 21 t.html
查看远程文件目录
1
svn list https://linlc@csvn.hollycrm.com:8081/hosting/trunk_status/cc/c5-xiaomiapp
hook下面的post-commit
1
2
3
4
5
6
7
8
9
10
11
12
13
14

export LANG=zh_CN.UTF-8

REPOS="$1"
REV="$2"

LOGFILE=/opt/llc/xiaomi/svn.log
exec 1>>"$LOGFILE"
exec 2>&1
# mailer.py commit "$REPOS" "$REV" /path/to/mailer.conf

# echo "11111" >> /opt/llc/xiaomi/svn.log
svn update /opt/xmweb-html/webapp/webapp/ --username loganv --password ****** --no-auth-cache
# echo "2222" >> /opt/llc/xiaomi/svn.log

readme

mac 下

  • 编辑器:xcode, sublime, typora,
  • 连接:Cyberduck, Sequel Pro, Robo 3T, SQLPro for SQLite
  • 其他:chrome, tunnelblick, postman, Charles
  • 开发环境:xampp, nginx, nodejs, redis, mongodb

工具网站


学习类网站


框架


跨平台:Cordova、React Native、Flutter、、、

js: chartjs, vuejs, jquery,velocity,axios

nodejs: hexo,koajs

css: animate.css

内联公式asdf

1
代码块

Metal 第一课(hello)

Metal 苹果面向GPU高速3D图形渲染,


MTKView 实现了Metal图形渲染的UIView

初始化MTKView,设置代理_renderer

1
2
3
4
5
MTKView _view = [[MTKView alloc] initWithFrame:self.view.bounds device: MTLCreateSystemDefaultDevice()];

CCRenderer *_renderer = [[CCRenderer alloc] initWithMetalKitView:_view];
[_renderer mtkView:_view drawableSizeWillChange:_view.drawableSize];
_view.delegate = _renderer;

CCRenderer.h

1
2
3
4
5
6
7
8
9
10
11
//导入MetalKit工具包
@import MetalKit;

//这是一个独立于平台的渲染类
//MTKViewDelegate协议:允许对象呈现在视图中并响应调整大小事件
@interface CCRenderer : NSObject<MTKViewDelegate>

//初始化一个MTKView
- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView;

@end

CCRenderer.m

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177

@import MetalKit;

#import "CCRenderer.h"

//头 在C代码之间共享,这里执行Metal API命令,和.metal文件,这些文件使用这些类型作为着色器的输入。
#import "CCShaderTypes.h"

//执行渲染的类
@implementation CCRenderer
{
//我们用来渲染的设备(又名GPU)
id<MTLDevice> _device;


// 我们的渲染管道有顶点着色器和片元着色器 它们存储在.metal shader 文件中
id<MTLRenderPipelineState> _pipelineState;

//命令队列,从命令缓存区获取
id<MTLCommandQueue> _commandQueue;

//当前视图大小,这样我们才可以在渲染通道使用这个视图
vector_uint2 _viewportSize;
}

//初始化MTKView
- (nonnull instancetype)initWithMetalKitView:(nonnull MTKView *)mtkView
{
self = [super init];
if(self)
{
NSError *error = NULL;

//1.获取GPU 设备
_device = mtkView.device;

//2.在项目中加载所有的(.metal)着色器文件
// 从bundle中获取.metal文件
id<MTLLibrary> defaultLibrary = [_device newDefaultLibrary];
//从库中加载顶点函数
id<MTLFunction> vertexFunction = [defaultLibrary newFunctionWithName:@"vertexShader"];
//从库中加载片元函数
id<MTLFunction> fragmentFunction = [defaultLibrary newFunctionWithName:@"fragmentShader"];

//3.配置用于创建管道状态的管道
MTLRenderPipelineDescriptor *pipelineStateDescriptor = [[MTLRenderPipelineDescriptor alloc] init];
//管道名称
pipelineStateDescriptor.label = @"Simple Pipeline";
//可编程函数,用于处理渲染过程中的各个顶点
pipelineStateDescriptor.vertexFunction = vertexFunction;
//可编程函数,用于处理渲染过程中各个片段/片元
pipelineStateDescriptor.fragmentFunction = fragmentFunction;
//一组存储颜色数据的组件
pipelineStateDescriptor.colorAttachments[0].pixelFormat = mtkView.colorPixelFormat;

//4.同步创建并返回渲染管线状态对象
_pipelineState = [_device newRenderPipelineStateWithDescriptor:pipelineStateDescriptor error:&error];
//判断是否返回了管线状态对象
if (!_pipelineState)
{

//如果我们没有正确设置管道描述符,则管道状态创建可能失败
NSLog(@"Failed to created pipeline state, error %@", error);
return nil;
}

//5.创建命令队列
_commandQueue = [_device newCommandQueue];
}

return self;
}

//每当视图改变方向或调整大小时调用
- (void)mtkView:(nonnull MTKView *)view drawableSizeWillChange:(CGSize)size
{
// 保存可绘制的大小,因为当我们绘制时,我们将把这些值传递给顶点着色器
_viewportSize.x = size.width;
_viewportSize.y = size.height;
}

//每当视图需要渲染帧时调用
- (void)drawInMTKView:(nonnull MTKView *)view
{
//1. 顶点数据/颜色数据
static const CCVertex triangleVertices[] =
{
//顶点, RGBA 颜色值
{ { 0.5, -0.25, 0.0, 1.0 }, { 1, 0, 0, 1 } },
{ { -0.5, -0.25, 0.0, 1.0 }, { 0, 1, 0, 1 } },
{ { -0.0f, 0.25, 0.0, 1.0 }, { 0, 0, 1, 1 } },
};

//2.为当前渲染的每个渲染传递创建一个新的命令缓冲区
id<MTLCommandBuffer> commandBuffer = [_commandQueue commandBuffer];
//指定缓存区名称
commandBuffer.label = @"MyCommand";

//3.
// MTLRenderPassDescriptor:一组渲染目标,用作渲染通道生成的像素的输出目标。
MTLRenderPassDescriptor *renderPassDescriptor = view.currentRenderPassDescriptor;
//判断渲染目标是否为空
if(renderPassDescriptor != nil)
{
//4.创建渲染命令编码器,这样我们才可以渲染到something
id<MTLRenderCommandEncoder> renderEncoder =[commandBuffer renderCommandEncoderWithDescriptor:renderPassDescriptor];
//渲染器名称
renderEncoder.label = @"MyRenderEncoder";

//5.设置我们绘制的可绘制区域
/*
typedef struct {
double originX, originY, width, height, znear, zfar;
} MTLViewport;
*/
//视口指定Metal渲染内容的drawable区域。 视口是具有x和y偏移,宽度和高度以及近和远平面的3D区域
//为管道分配自定义视口需要通过调用setViewport:方法将MTLViewport结构编码为渲染命令编码器。 如果未指定视口,Metal会设置一个默认视口,其大小与用于创建渲染命令编码器的drawable相同。
MTLViewport viewPort = {
0.0,0.0,_viewportSize.x,_viewportSize.y,-1.0,1.0
};
[renderEncoder setViewport:viewPort];
//[renderEncoder setViewport:(MTLViewport){0.0, 0.0, _viewportSize.x, _viewportSize.y, -1.0, 1.0 }];

//6.设置当前渲染管道状态对象
[renderEncoder setRenderPipelineState:_pipelineState];


//7.从应用程序OC 代码 中发送数据给Metal 顶点着色器 函数
//顶点数据+颜色数据
// 1) 指向要传递给着色器的内存的指针
// 2) 我们想要传递的数据的内存大小
// 3)一个整数索引,它对应于我们的“vertexShader”函数中的缓冲区属性限定符的索引。

[renderEncoder setVertexBytes:triangleVertices
length:sizeof(triangleVertices)
atIndex:CCVertexInputIndexVertices];

//viewPortSize 数据
//1) 发送到顶点着色函数中,视图大小
//2) 视图大小内存空间大小
//3) 对应的索引
[renderEncoder setVertexBytes:&_viewportSize
length:sizeof(_viewportSize)
atIndex:CCVertexInputIndexViewportSize];



//8.画出三角形的3个顶点
// @method drawPrimitives:vertexStart:vertexCount:
//@brief 在不使用索引列表的情况下,绘制图元
//@param 绘制图形组装的基元类型
//@param 从哪个位置数据开始绘制,一般为0
//@param 每个图元的顶点个数,绘制的图型顶点数量
/*
MTLPrimitiveTypePoint = 0, 点
MTLPrimitiveTypeLine = 1, 线段
MTLPrimitiveTypeLineStrip = 2, 线环
MTLPrimitiveTypeTriangle = 3, 三角形
MTLPrimitiveTypeTriangleStrip = 4, 三角型扇
*/

[renderEncoder drawPrimitives:MTLPrimitiveTypeTriangle
vertexStart:0
vertexCount:3];

//9.表示已该编码器生成的命令都已完成,并且从NTLCommandBuffer中分离
[renderEncoder endEncoding];

//10.一旦框架缓冲区完成,使用当前可绘制的进度表
[commandBuffer presentDrawable:view.currentDrawable];
}

//11.最后,在这里完成渲染并将命令缓冲区推送到GPU
[commandBuffer commit];
}

@end

CCShaders.metal

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
#include <metal_stdlib>
//使用命名空间 Metal
using namespace metal;

// 导入Metal shader 代码和执行Metal API命令的C代码之间共享的头
#import "CCShaderTypes.h"

// 顶点着色器输出和片段着色器输入
//结构体
typedef struct
{
//处理空间的顶点信息
float4 clipSpacePosition [[position]];

//颜色
float4 color;

} RasterizerData;

//顶点着色函数
vertex RasterizerData
vertexShader(uint vertexID [[vertex_id]],
constant CCVertex *vertices [[buffer(CCVertexInputIndexVertices)]],
constant vector_uint2 *viewportSizePointer [[buffer(CCVertexInputIndexViewportSize)]])
{
/*
处理顶点数据:
1) 执行坐标系转换,将生成的顶点剪辑空间写入到返回值中.
2) 将顶点颜色值传递给返回值
*/

//定义out
RasterizerData out;

// //初始化输出剪辑空间位置
// out.clipSpacePosition = vector_float4(0.0, 0.0, 0.0, 1.0);
//
// // 索引到我们的数组位置以获得当前顶点
// // 我们的位置是在像素维度中指定的.
// float2 pixelSpacePosition = vertices[vertexID].position.xy;
//
// //将vierportSizePointer 从verctor_uint2 转换为vector_float2 类型
// vector_float2 viewportSize = vector_float2(*viewportSizePointer);
//
// //每个顶点着色器的输出位置在剪辑空间中(也称为归一化设备坐标空间,NDC),剪辑空间中的(-1,-1)表示视口的左下角,而(1,1)表示视口的右上角.
// //计算和写入 XY值到我们的剪辑空间的位置.为了从像素空间中的位置转换到剪辑空间的位置,我们将像素坐标除以视口的大小的一半.
// out.clipSpacePosition.xy = pixelSpacePosition / (viewportSize / 2.0);
out.clipSpacePosition = vertices[vertexID].position;

//把我们输入的颜色直接赋值给输出颜色. 这个值将于构成三角形的顶点的其他颜色值插值,从而为我们片段着色器中的每个片段生成颜色值.
out.color = vertices[vertexID].color;

//完成! 将结构体传递到管道中下一个阶段:
return out;
}

//当顶点函数执行3次,三角形的每个顶点执行一次后,则执行管道中的下一个阶段.栅格化/光栅化.


// 片元函数
//[[stage_in]],片元着色函数使用的单个片元输入数据是由顶点着色函数输出.然后经过光栅化生成的.单个片元输入函数数据可以使用"[[stage_in]]"属性修饰符.
//一个顶点着色函数可以读取单个顶点的输入数据,这些输入数据存储于参数传递的缓存中,使用顶点和实例ID在这些缓存中寻址.读取到单个顶点的数据.另外,单个顶点输入数据也可以通过使用"[[stage_in]]"属性修饰符的产生传递给顶点着色函数.
//被stage_in 修饰的结构体的成员不能是如下这些.Packed vectors 紧密填充类型向量,matrices 矩阵,structs 结构体,references or pointers to type 某类型的引用或指针. arrays,vectors,matrices 标量,向量,矩阵数组.
fragment float4 fragmentShader(RasterizerData in [[stage_in]])
{

//返回输入的片元颜色
return in.color;
}

CCShaderTypes.h

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

/*
介绍:
头文件包含了 Metal shaders 与C/OBJC 源之间共享的类型和枚举常数
*/

#ifndef CCShaderTypes_h
#define CCShaderTypes_h

// 缓存区索引值 共享与 shader 和 C 代码 为了确保Metal Shader缓存区索引能够匹配 Metal API Buffer 设置的集合调用
typedef enum CCVertexInputIndex
{
//顶点
CCVertexInputIndexVertices = 0,
//视图大小
CCVertexInputIndexViewportSize = 1,
} CCVertexInputIndex;


//结构体: 顶点/颜色值
typedef struct
{
// 像素空间的位置
// 像素中心点(100,100)
vector_float4 position;

// RGBA颜色
vector_float4 color;
} CCVertex;

#endif

opengl es 第七课(简单滤镜)

滤镜

根据时间进度,处理片源着色器里面的纹理颜色

顶点着色器基本不变

1
2
3
4
5
6
7
8
attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;

void main (void) {
gl_Position = Position;
TextureCoordsVarying = TextureCoords;
}

灵魂出窍

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

void main (void) {
float duration = 0.7;
float maxAlpha = 0.4;
float maxScale = 1.8;

float progress = mod(Time, duration) / duration; // 0~1
float alpha = maxAlpha * (1.0 - progress);
float scale = 1.0 + (maxScale - 1.0) * progress;

float weakX = 0.5 + (TextureCoordsVarying.x - 0.5) / scale;
float weakY = 0.5 + (TextureCoordsVarying.y - 0.5) / scale;
vec2 weakTextureCoords = vec2(weakX, weakY);

vec4 weakMask = texture2D(Texture, weakTextureCoords);

vec4 mask = texture2D(Texture, TextureCoordsVarying);

gl_FragColor = mask * (1.0 - alpha) + weakMask * alpha;
}

放大

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
attribute vec4 Position;
attribute vec2 TextureCoords;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;

void main (void) {
float duration = 0.6;
float maxAmplitude = 0.3;

float time = mod(Time, duration);
float amplitude = 1.0 + maxAmplitude * abs(sin(time * (PI / duration)));

gl_Position = vec4(Position.x * amplitude, Position.y * amplitude, Position.zw);
TextureCoordsVarying = TextureCoords;
}

抖动

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

void main (void) {
float duration = 0.7;
float maxScale = 1.1;
float offset = 0.02;

float progress = mod(Time, duration) / duration; // 0~1
vec2 offsetCoords = vec2(offset, offset) * progress;
float scale = 1.0 + (maxScale - 1.0) * progress;

vec2 ScaleTextureCoords = vec2(0.5, 0.5) + (TextureCoordsVarying - vec2(0.5, 0.5)) / scale;

vec4 maskR = texture2D(Texture, ScaleTextureCoords + offsetCoords);
vec4 maskB = texture2D(Texture, ScaleTextureCoords - offsetCoords);
vec4 mask = texture2D(Texture, ScaleTextureCoords);

gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}

毛刺

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
precision highp float;

uniform sampler2D Texture;
varying vec2 TextureCoordsVarying;

uniform float Time;

const float PI = 3.1415926;

float rand(float n) {
return fract(sin(n) * 43758.5453123);
}

void main (void) {
float maxJitter = 0.06;
float duration = 0.3;
float colorROffset = 0.01;
float colorBOffset = -0.025;

float time = mod(Time, duration * 2.0);
float amplitude = max(sin(time * (PI / duration)), 0.0);

float jitter = rand(TextureCoordsVarying.y) * 2.0 - 1.0; // -1~1
bool needOffset = abs(jitter) < maxJitter * amplitude;

float textureX = TextureCoordsVarying.x + (needOffset ? jitter : (jitter * amplitude * 0.006));
vec2 textureCoords = vec2(textureX, TextureCoordsVarying.y);

vec4 mask = texture2D(Texture, textureCoords);
vec4 maskR = texture2D(Texture, textureCoords + vec2(colorROffset * amplitude, 0.0));
vec4 maskB = texture2D(Texture, textureCoords + vec2(colorBOffset * amplitude, 0.0));

gl_FragColor = vec4(maskR.r, mask.g, maskB.b, mask.a);
}

oc 代码

初始化 上下文 EAGLContext、显示层 CAEAGLLayer、顶点数据 vertices、纹理数据 textureID

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
- (void)filterInit {

//1. 初始化上下文并设置为当前上下文
self.context = [[EAGLContext alloc] initWithAPI:kEAGLRenderingAPIOpenGLES2];
[EAGLContext setCurrentContext:self.context];

//2.开辟顶点数组内存空间
self.vertices = malloc(sizeof(SenceVertex) * 4);

//3.初始化顶点(0,1,2,3)的顶点坐标以及纹理坐标
self.vertices[0] = (SenceVertex){{-1, 1, 0}, {0, 1}};
self.vertices[1] = (SenceVertex){{-1, -1, 0}, {0, 0}};
self.vertices[2] = (SenceVertex){{1, 1, 0}, {1, 1}};
self.vertices[3] = (SenceVertex){{1, -1, 0}, {1, 0}};

//4.创建图层(CAEAGLLayer)
CAEAGLLayer *layer = [[CAEAGLLayer alloc] init];
//设置图层frame
layer.frame = CGRectMake(0, 100, self.view.frame.size.width, self.view.frame.size.width);
//设置图层的scale
layer.contentsScale = [[UIScreen mainScreen] scale];
//给View添加layer
[self.view.layer addSublayer:layer];

//5.绑定渲染缓存区
[self bindRenderLayer:layer];

//6.获取处理的图片路径
NSString *imagePath = [[[NSBundle mainBundle] resourcePath] stringByAppendingPathComponent:@"kunkun.jpg"];
//读取图片
UIImage *image = [UIImage imageWithContentsOfFile:imagePath];
//将JPG图片转换成纹理图片
GLuint textureID = [self createTextureWithImage:image];
//设置纹理ID
self.textureID = textureID; // 将纹理 ID 保存,方便后面切换滤镜的时候重用

//7.设置视口
glViewport(0, 0, self.drawableWidth, self.drawableHeight);

//8.设置顶点缓存区
GLuint vertexBuffer;
glGenBuffers(1, &vertexBuffer);
glBindBuffer(GL_ARRAY_BUFFER, vertexBuffer);
GLsizeiptr bufferSizeBytes = sizeof(SenceVertex) * 4;
glBufferData(GL_ARRAY_BUFFER, bufferSizeBytes, self.vertices, GL_STATIC_DRAW);


//9.设置默认着色器
[self setupNormalShaderProgram]; // 一开始选用默认的着色器

//10.将顶点缓存保存,退出时才释放
self.vertexBuffer = vertexBuffer;
}

绑定帧缓存区、渲染缓存区

1
2
3
4
5
6
7
8
9
10
11
12
//获取渲染缓存区的宽
- (GLint)drawableWidth {
GLint backingWidth;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_WIDTH, &backingWidth);
return backingWidth;
}
//获取渲染缓存区的高
- (GLint)drawableHeight {
GLint backingHeight;
glGetRenderbufferParameteriv(GL_RENDERBUFFER, GL_RENDERBUFFER_HEIGHT, &backingHeight);
return backingHeight;
}

加载纹理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
//从图片中加载纹理
- (GLuint)createTextureWithImage:(UIImage *)image {

//1、将 UIImage 转换为 CGImageRef
CGImageRef cgImageRef = [image CGImage];
//判断图片是否获取成功
if (!cgImageRef) {
NSLog(@"Failed to load image");
exit(1);
}
//2、读取图片的大小,宽和高
GLuint width = (GLuint)CGImageGetWidth(cgImageRef);
GLuint height = (GLuint)CGImageGetHeight(cgImageRef);
//获取图片的rect
CGRect rect = CGRectMake(0, 0, width, height);

//获取图片的颜色空间
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
//3.获取图片字节数 宽*高*4(RGBA)
void *imageData = malloc(width * height * 4);
//4.创建上下文
/*
参数1:data,指向要渲染的绘制图像的内存地址
参数2:width,bitmap的宽度,单位为像素
参数3:height,bitmap的高度,单位为像素
参数4:bitPerComponent,内存中像素的每个组件的位数,比如32位RGBA,就设置为8
参数5:bytesPerRow,bitmap的没一行的内存所占的比特数
参数6:colorSpace,bitmap上使用的颜色空间 kCGImageAlphaPremultipliedLast:RGBA
*/
CGContextRef context = CGBitmapContextCreate(imageData, width, height, 8, width * 4, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big);

//将图片翻转过来(图片默认是倒置的)
CGContextTranslateCTM(context, 0, height);
CGContextScaleCTM(context, 1.0f, -1.0f);
CGColorSpaceRelease(colorSpace);
CGContextClearRect(context, rect);

//对图片进行重新绘制,得到一张新的解压缩后的位图
CGContextDrawImage(context, rect, cgImageRef);

//设置图片纹理属性
//5. 获取纹理ID
GLuint textureID;
glGenTextures(1, &textureID);
glBindTexture(GL_TEXTURE_2D, textureID);

//6.载入纹理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, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, imageData);

//7.设置纹理属性
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);

//8.绑定纹理
/*
参数1:纹理维度
参数2:纹理ID,因为只有一个纹理,给0就可以了。
*/
glBindTexture(GL_TEXTURE_2D, 0);

//9.释放context,imageData
CGContextRelease(context);
free(imageData);

//10.返回纹理ID
return textureID;
}

调用着色器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36

- (void)setupNormalShaderProgram {
//设置着色器程序
[self setupShaderProgramWithName:@"Normal"];
}
// 初始化着色器程序
- (void)setupShaderProgramWithName:(NSString *)name {
//1. 获取着色器program
GLuint program = [self programWithShaderName:name];

//2. use Program
glUseProgram(program);

//3. 获取Position,Texture,TextureCoords 的索引位置
GLuint positionSlot = glGetAttribLocation(program, "Position");
GLuint textureSlot = glGetUniformLocation(program, "Texture");
GLuint textureCoordsSlot = glGetAttribLocation(program, "TextureCoords");

//4.激活纹理,绑定纹理ID
glActiveTexture(GL_TEXTURE0);
glBindTexture(GL_TEXTURE_2D, self.textureID);

//5.纹理sample
glUniform1i(textureSlot, 0);

//6.打开positionSlot 属性并且传递数据到positionSlot中(顶点坐标)
glEnableVertexAttribArray(positionSlot);
glVertexAttribPointer(positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(SenceVertex), NULL + offsetof(SenceVertex, positionCoord));

//7.打开textureCoordsSlot 属性并传递数据到textureCoordsSlot(纹理坐标)
glEnableVertexAttribArray(textureCoordsSlot);
glVertexAttribPointer(textureCoordsSlot, 2, GL_FLOAT, GL_FALSE, sizeof(SenceVertex), NULL + offsetof(SenceVertex, textureCoord));

//8.保存program,界面销毁则释放
self.program = program;
}

编译、链接着色器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
#pragma mark -shader compile and link
//link Program
- (GLuint)programWithShaderName:(NSString *)shaderName {
//1. 编译顶点着色器/片元着色器
GLuint vertexShader = [self compileShaderWithName:shaderName type:GL_VERTEX_SHADER];
GLuint fragmentShader = [self compileShaderWithName:shaderName type:GL_FRAGMENT_SHADER];

//2. 将顶点/片元附着到program
GLuint program = glCreateProgram();
glAttachShader(program, vertexShader);
glAttachShader(program, fragmentShader);

//3.linkProgram
glLinkProgram(program);

//4.检查是否link成功
GLint linkSuccess;
glGetProgramiv(program, GL_LINK_STATUS, &linkSuccess);
if (linkSuccess == GL_FALSE) {
GLchar messages[256];
glGetProgramInfoLog(program, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSAssert(NO, @"program链接失败:%@", messageString);
exit(1);
}
//5.返回program
return program;
}

//编译shader代码
- (GLuint)compileShaderWithName:(NSString *)name type:(GLenum)shaderType {

//1.获取shader 路径
NSString *shaderPath = [[NSBundle mainBundle] pathForResource:name ofType:shaderType == GL_VERTEX_SHADER ? @"vsh" : @"fsh"];
NSError *error;
NSString *shaderString = [NSString stringWithContentsOfFile:shaderPath encoding:NSUTF8StringEncoding error:&error];
if (!shaderString) {
NSAssert(NO, @"读取shader失败");
exit(1);
}

//2. 创建shader->根据shaderType
GLuint shader = glCreateShader(shaderType);

//3.获取shader source
const char *shaderStringUTF8 = [shaderString UTF8String];
int shaderStringLength = (int)[shaderString length];
glShaderSource(shader, 1, &shaderStringUTF8, &shaderStringLength);

//4.编译shader
glCompileShader(shader);

//5.查看编译是否成功
GLint compileSuccess;
glGetShaderiv(shader, GL_COMPILE_STATUS, &compileSuccess);
if (compileSuccess == GL_FALSE) {
GLchar messages[256];
glGetShaderInfoLog(shader, sizeof(messages), 0, &messages[0]);
NSString *messageString = [NSString stringWithUTF8String:messages];
NSAssert(NO, @"shader编译失败:%@", messageString);
exit(1);
}
//6.返回shader
return shader;
}

滤镜动画

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
// 开始一个滤镜动画
- (void)viewWillDisappear:(BOOL)animated {
[super viewWillDisappear:animated];

// 移除 displayLink
if (self.displayLink) {
[self.displayLink invalidate];
self.displayLink = nil;
}
}

- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
//设置背景颜色
self.view.backgroundColor = [UIColor blackColor];
//创建滤镜工具栏
[self setupFilterBar];
//滤镜处理初始化
[self filterInit];
//开始一个滤镜动画
[self startFilerAnimation];
}

- (void)startFilerAnimation {
//1.判断displayLink 是否为空
//CADisplayLink 定时器
if (self.displayLink) {
[self.displayLink invalidate];
self.displayLink = nil;
}
//2. 设置displayLink 的方法
self.startTimeInterval = 0;
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(timeAction)];

//3.将displayLink 添加到runloop 运行循环
[self.displayLink addToRunLoop:[NSRunLoop mainRunLoop]
forMode:NSRunLoopCommonModes];
}

//2. 动画
- (void)timeAction {
//DisplayLink 的当前时间撮
if (self.startTimeInterval == 0) {
self.startTimeInterval = self.displayLink.timestamp;
}
//使用program
glUseProgram(self.program);
//绑定buffer
glBindBuffer(GL_ARRAY_BUFFER, self.vertexBuffer);

// 传入时间
CGFloat currentTime = self.displayLink.timestamp - self.startTimeInterval;
GLuint time = glGetUniformLocation(self.program, "Time");
glUniform1f(time, currentTime);

// 清除画布
glClear(GL_COLOR_BUFFER_BIT);
glClearColor(1, 1, 1, 1);

// 重绘
glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);
//渲染到屏幕上
[self.context presentRenderbuffer:GL_RENDERBUFFER];
}

释放

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
- (void)dealloc {
//1.上下文释放
if ([EAGLContext currentContext] == self.context) {
[EAGLContext setCurrentContext:nil];
}
//顶点缓存区释放
if (_vertexBuffer) {
glDeleteBuffers(1, &_vertexBuffer);
_vertexBuffer = 0;
}
//顶点数组释放
if (_vertices) {
free(_vertices);
_vertices = nil;
}
}