当前位置: 移动技术网 > 移动技术>移动开发>IOS > OpenGL ES画板

OpenGL ES画板

2018年12月10日  | 移动技术网移动技术  | 我要评论

一、概述

利用自定义顶点和片元着色器渲染,并且设置图片纹理颜色为画笔颜色

二、核心代码

 

- (void)renderlinefrompoint:(cgpoint)start topoint:(cgpoint)end
{
    //顶点缓存区
    static glfloat *vertexbuffer = null;
    //顶点max
    static nsuinteger vertexmax = 64;
    //顶点个数
    nsuinteger vertexcount = 0,count;
    cgfloat scale = self.contentscalefactor;
    
    //点到像素转换:乘以比例因子
    start.x *= scale;
    start.y *= scale;
    end.x *= scale;
    end.y *= scale;
    
    //开辟顶点缓存区
    if (vertexbuffer == null) {
        vertexbuffer = malloc(vertexmax*2*sizeof(glfloat));
    }
    
    //求得两点之间的距离
    float seq = sqrtf((end.x-start.x)*(end.x-start.x)+(end.y-start.y)*(end.y-start.y));
    /*向上取整:求得距离要产生多少个点
     kbrushpixelstep值越大,笔触越细;值越小,笔触越粗
     */
    nsinteger pointcount = ceil(seq/kbrushpixelstep);
    count = max(pointcount, 1);
    
    for (int i = 0; i < count; i++) {
        if (vertexcount == vertexmax) {
            //修改2倍增长
            vertexmax = 2*vertexmax;
            vertexbuffer = realloc(vertexbuffer, vertexmax*2*sizeof(glfloat));
        }
        
        //计算两个之间的距离有多少个点,并存储在顶点缓存区中
        vertexbuffer[2*vertexcount+0] = start.x+(end.x-start.x)*((glfloat)i/(glfloat)count);
        vertexbuffer[2*vertexcount+1] = start.y+(end.y-start.y)*((glfloat)i/(glfloat)count);
        
        vertexcount++;
    }
    
    //绑定顶点数据
    glbindbuffer(gl_array_buffer, vboid);
    //将数据从cpu中复制到gpu中提供给opengl使用
    glbufferdata(gl_array_buffer, vertexcount*2*sizeof(glfloat), vertexbuffer, gl_dynamic_draw);
    
    //启用指定属性
    glenablevertexattribarray(attrib_vertex);
    //链接顶点属性
    glvertexattribpointer(attrib_vertex, 2, gl_float, gl_false, 2*sizeof(glfloat), 0);
    
    //使用数据总线:传递顶点数据到顶点着色器
    gluseprogram(program[programe_point].id);
    //绘制顶点:绘制模型、起始点、顶点个数
    gldrawarrays(gl_points, 0, (int)vertexcount);
    //绑定渲染缓存区到特定标志符上
    glbindrenderbuffer(gl_renderbuffer, viewrenderbuffer);
    //开始渲染
    [context presentrenderbuffer:gl_renderbuffer];
    
}

 

- (textureinfo_t)texturefromname:(nsstring *)name
{
    cgimageref brushimage;
    cgcontextref brushcontext;
    glubyte *brushdata;
    size_t width, height;
    gluint texid;
    textureinfo_t texture;
    
    brushimage = [uiimage imagenamed:name].cgimage;
    width = cgimagegetwidth(brushimage);
    height = cgimagegetheight(brushimage);
    //开辟纹理图片内存
    brushdata = (glubyte *)calloc(width*height*4, sizeof(glubyte));
    
    /*创建位图上下文
     参数:图片内存地址、图片宽、图片高、像素组件位数(一般设置8),每一行所占比特数、颜色空间、颜色通道
     */
    brushcontext = cgbitmapcontextcreate(brushdata, width, height, 8, width*4, cgimagegetcolorspace(brushimage), kcgimagealphapremultipliedlast);
    
    //绘图
    cgcontextdrawimage(brushcontext, cgrectmake(0, 0, (cgfloat)width, (cgfloat)height), brushimage);
    //释放上下文
    cgcontextrelease(brushcontext);
    
    //申请纹理标志符
    glgentextures(1, &texid);
    //绑定纹理
    glbindtexture(gl_texture_2d, texid);
    //设置纹理属性:缩小滤波器、线性滤波器
    gltexparameteri(gl_texture_2d, gl_texture_min_filter, gl_linear);
    /*生成2d纹理图片
     参数:纹理目标、图像级别(0为基本级别)、颜色组件(gl_rgba、gl_alpha)、图像宽、图像高、边框宽度(一般为0)、像素数据颜色格式、像素数据类型、内存中指向图像数据指针
     */
    glteximage2d(gl_texture_2d, 0, gl_rgba, (int)width, (int)height, 0, gl_rgba, gl_unsigned_byte, brushdata);
    
    free(brushdata);
    
    //配置纹理属性
    texture.id = texid;
    texture.width = (int)width;
    texture.height = (int)height;
    
    return texture;
}
- (void)setupshaders
{
    for (int i = 0; i < num_programs; i++) {
        
        //读取顶点着色器程序
        char *vsrc = readfile(pathforresource(program[i].vert));
        //读取片元着色器程序
        char *fsrc = readfile(pathforresource(program[i].frag));
        nsstring *vsrcstr = [[nsstring alloc] initwithbytes:vsrc length:strlen(vsrc)-1 encoding:nsutf8stringencoding];
        nsstring *fsrcstr = [[nsstring alloc] initwithbytes:fsrc length:strlen(fsrc)-1 encoding:nsutf8stringencoding];
        nslog(@"vsrcstr------%@", vsrcstr);
        nslog(@"fsrcstr------%@", fsrcstr);
        
        glsizei attribct = 0;
        glchar *attribused[num_attribs];
        glint attrib[num_attribs];
        glchar *attribname[num_attribs] = {
            "invertex"
        };
        
        const char *uniformname[num_uniforms] = {
            "mvp","pointsize","vertexcolor", "texture"
        };
        
        for (int j = 0; j < num_attribs; j++) {
            if (strstr(vsrc, attribname[j])) {
                attrib[attribct] = j;
                attribused[attribct++] = attribname[j];
            }
        }
        
        //program处理:创建、链接、生成
        gluecreateprogram(vsrc, fsrc, attribct, (const char **)&attribused[0], attrib, num_uniforms, &uniformname[0], program[i].uniform, &program[i].id);
        
        free(vsrc);
        free(fsrc);
        
        if (i == programe_point) {
            gluseprogram(program[programe_point].id);
           //为当前程序指定uniform变量
            gluniform1i(program[programe_point].uniform[uniform_texture], 0);
            
            //设置正射投影矩阵
            glkmatrix4 projectionmatrix = glkmatrix4makeortho(0, backingwidth, 0, backingheight, -1, 1);
            //创建模型视图矩阵:单元矩阵
            glkmatrix4 modelviewmatrix = glkmatrix4identity;
            //正射投影矩阵与模型视图矩阵相乘,结果保存在mvpmatrix矩阵中
            glkmatrix4 mvpmatrix = glkmatrix4multiply(projectionmatrix, modelviewmatrix);
           
           /*为当前程序指定uniform变量值
            参数:指明要更改的uniform变量的位置、将要被修改的矩阵的数量、矩阵值被载入变量时是否要对举证进行变换(如转置)、将要用于更新uniform变量mvp的数组指针
            */
            gluniformmatrix4fv(program[programe_point].uniform[uniform_mvp], 1, gl_false, mvpmatrix.m);
           //为当前程序对象uniform变量的pointsize赋值
            gluniform1f(program[programe_point].uniform[uniform_point_size], brushtexture.width/kbrushscale);
            //为当前程序对象uniform变量顶点颜色赋值
            gluniform4fv(program[programe_point].uniform[uniform_vertex_color], 1, brushcolor);
            
        }
    }
    
    glerror();
}

三、效果图

 

 

github

 

如对本文有疑问, 点击进行留言回复!!

相关文章:

验证码:
移动技术网