拆分Cocos2dx渲染部分代码

纹理实现

思想

这个是Cocos2dx的渲染部分的最基本的实现,被我拆分到mac上,但是并不是用的EGLContext,而是搭配glfw,还有soil第三方图形库。

实现

//
//  main.cpp
//  Moni
//
//  Created by staff on 17/1/10.
//  Copyright © 2017年 staff. All rights reserved.
//

#include <iostream>
#include <string>
#include <cassert>
#include <GL/glew.h>
#include <GLUT/glut.h>
#include <GLFW/glfw3.h>
#include "png.h"
#include "SOIL.h"
#include "CCOPGL.h"

#include <unordered_map>
#include "CCVector2.h"
#include "CCVector3.h"
#include "CCVector4.h"
#include "CCMatrix.h"
#include "CCType.h"

#define STRINGIFY(A)  #A
#include "CCPositionTextureColor.frag"
#include "CCPositionTextureColor.vert"

using namespace std;

#define MAX_VERTICES_SIZE 65536 //Buffer中一次存储进顶点数据的最大数目
#define MAX_INDICES_SIZE MAX_VERTICES_SIZE * 6 / 4 //前者的索引

#define MATIRIAL_ID_NOT_BATCH 0
#define UNIFORM_MAX_SIZE 7

// Attribute顶点属性变量名字(需要和shader中的对应起来,否则无法传值)
typedef enum {
    VERTEX_ATTRIB_POSITION = 0, // 位置
    VERTEX_ATTRIB_COLOR,        // 颜色
    VERTEX_ATTRIB_TEXCOOD       // 纹理坐标
} VERTEX_ATTRIB_TYPE;


typedef enum {
    UNIFORM_P_MATRIX = 0,
    UNIFORM_MV_MATRIX,
    UNIFORM_MVP_MATRIX,
    
    UNIFORM_SAMPLER0,
    UNIFORM_SAMPLER1,
    UNIFORM_SAMPLER2,
    UNIFORM_SAMPLER3,
}VERTEX_UNIFORM_TYPE;

// shader中的vertexAttrib
struct VertexAttrib
{
    GLuint index; //属性下标,从0开始
    GLint size; //数据个数
    GLenum type; //数据类型
    string name; //顶点着色器的名字
};

// shader中的uniform
struct Uniform
{
    GLint location; //属性位置,从0开始
    GLint size;
    GLenum type;
    string name;
};

// 封装Uniform
class UniformValue {
public:
    UniformValue();
    ~UniformValue();
    
protected:
    Uniform _uniform;
};

// 封装VertexAttrib
class VertexAttribValue {
public:
    VertexAttribValue();
    ~VertexAttribValue();
    
protected:
    VertexAttrib _attrib;
};

struct Triangles //三角形
{
    V3F_C4B_T2F *verts; //顶点数据
    unsigned int* indices;
    ssize_t vertCount;
    ssize_t indexCount;
    
    void outVerts() {
        for (ssize_t i = 0; i < vertCount; i++) {
            cout << "第" << i + 1 << "个顶点信息" << endl;
            cout << "坐标:" << verts[i].vertices.x << "," << verts[i].vertices.y << "," << verts[i].vertices.z << endl;
            cout << "颜色:" << verts[i].colors.r << "," << verts[i].colors.g << "," << verts[i].colors.b << endl;
            cout << "纹理:" << verts[i].texCoords.u << "," << verts[i].texCoords.v << endl;
        }
    }
    
    void outIndics() {
        for (ssize_t i = 0; i < indexCount; i++) {
            cout << "第" << i + 1 << "个纹理信息" << endl;
            cout << indices[i] << endl;
        }
    }
};

// 用流读取图片数据的回调函数
typedef struct
{
    const unsigned char * data;
    ssize_t size;
    int offset;
}tImageSource;

// 设定attribute值
static const char* ATTRIBUTE_NAME_POSITION = "a_position";
static const char* ATTRIBUTE_NAME_COLOR    = "a_color";
static const char* ATTRIBUTE_NAME_TEXCOOD    = "a_texCoord";

// 设置统一变量值
static const char* UNIFORM_NAME_P_MATRIX = "CC_PMatrix";
static const char* UNIFORM_NAME_MV_MATRIX = "CC_MVMatrix";
static const char* UNIFORM_NAME_MVP_MATRIX = "CC_MVPMatrix";
static const char* UNIFORM_NAME_SAMPLER0 = "CC_Texture0";
static const char* UNIFORM_NAME_SAMPLER1 = "CC_Texture1";
static const char* UNIFORM_NAME_SAMPLER2 = "CC_Texture2";
static const char* UNIFORM_NAME_SAMPLER3 = "CC_Texture3";

// 用作缓存,暂时不用
const char* SHADER_NAME_POSITION_TEXTURE_COLOR = "ShaderPositionTextureColor";

static const char* DEFAULT_SHADER_UNIFORMS =
"uniform mat4 CC_PMatrix;
"
"uniform mat4 CC_MVMatrix;
"
"uniform mat4 CC_MVPMatrix;
"
"uniform sampler2D CC_Texture0;
"
"uniform sampler2D CC_Texture1;
"
"uniform sampler2D CC_Texture2;
"
"uniform sampler2D CC_Texture3;
"
"//CC INCLUDES END

";

static unsigned int quadIndices[] = {
    0, 1, 2,
    1, 2, 3
};


class CCData {
public:
    CCData() {
        
    }
    
    CCData(unsigned char* bytes, ssize_t size) {
        _bytes = bytes;
        _size = size;
    }
    
    ~CCData() {
        _bytes = NULL;
        _size = 0;
    }
    
    
    CCData& operator=(const CCData& other) {
        copy(other._bytes, other._size);
        return *this;
    }
    
    CCData& operator=(CCData&& other) {
        move(other);
        return *this;
    }
    
    // 移动构造函数
    void move(CCData& data) {
        _bytes = data._bytes;
        _size = data._size;
        
        data._bytes = NULL;
        data._size = 0;
    }
    
    // 拷贝构造函数
    void copy(const unsigned char* bytes, const ssize_t size) {
        if (size > 0) {
            _size = size;
            _bytes = (unsigned char*)malloc(sizeof(unsigned char*) * size);
            memcpy(_bytes, bytes, _size);
        }
    }
    
    void fastSet(unsigned char* bytes, const ssize_t size)
    {
        _bytes = bytes;
        _size = size;
    }
    
    
    unsigned char* getBytes() {
        return _bytes;
    }
    
    ssize_t getSize() {
        return _size;
    }
    
protected:
    unsigned char* _bytes;
    ssize_t _size;
};

class CCSize {
public:
    CCSize() {
        
        
    }
    
    CCSize(float x, float y) {
        _x = x;
        _y = y;
    }
    
    ~CCSize() {
        
    }
    
    void fastSet(float x, float y) {
        _x = x;
        _y = y;
    }
    
    float getX() const {
        return _x;
    }
    
    float getY() const {
        return _y;
    }
private:
    float _x;
    float _y;
};



GLuint _triangleVAO;
GLuint _triangleVBO[2]; //默认支持VBO
V3F_C4B_T2F Vertexs[MAX_VERTICES_SIZE]; //绘制的节点信息
GLuint Indices[MAX_INDICES_SIZE]; // 绘制所需的索引信息

unsigned int _filledVertex = 0; //填充的顶点偏移
unsigned int _filledIndex = 0; //填充的索引偏移

Color4F _clearColor; //默认的颜色

GLuint _program; //渲染程序
GLuint _vertexShader; //顶点着色器
GLuint _fragShader; //片元着色器
GLint _uniforms[UNIFORM_MAX_SIZE]; //统一变量
unordered_map<string, Uniform> _uniformsMap; //建立通过名字找到的统一变量
unordered_map<string, VertexAttrib> _verAttribsMap; //建立通过名字找到的顶点属性

// 精灵的属性
GLuint _sp_textureID;
BlendFunc _sp_blend;
Triangles _sp_triangles;
V3F_C4B_T2F_Quad _sp_quad;
Matrix _sp_modelView;

CCData _sp_image_data;
CCSize _sp_image_size;

Vector2 _sp_position(0, 0);

bool _sp_transformUpdated = false;

void pngReadCallback(png_structp png_ptr, png_bytep data, png_size_t length)
{
    tImageSource* isource = (tImageSource*)png_get_io_ptr(png_ptr);
    
    if((int)(isource->offset + length) <= isource->size)
    {
        memcpy(data, isource->data+isource->offset, length);
        isource->offset += length;
    }
    else
    {
        png_error(png_ptr, "pngReaderCallback failed");
    }
}

void reset() {
    _clearColor = Color4F::WHITE;
    // 清除深度缓存和颜色缓存
    glClearColor(_clearColor.r, _clearColor.g, _clearColor.b, _clearColor.a);
    glClear(GL_COLOR_BUFFER_BIT);
}

void clearShader() {
    if (_vertexShader) {
        glDeleteShader(_vertexShader);
    }
    
    if (_fragShader) {
        glDeleteShader(_fragShader);
    }
    
    _vertexShader = _fragShader = 0;
}

void handleUniforms() {
    // 对uniforms进行初始化
    _uniforms[UNIFORM_P_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_P_MATRIX);
    _uniforms[UNIFORM_MV_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MV_MATRIX);
    _uniforms[UNIFORM_MVP_MATRIX] = glGetUniformLocation(_program, UNIFORM_NAME_MVP_MATRIX);
    _uniforms[UNIFORM_SAMPLER0] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER0);
    _uniforms[UNIFORM_SAMPLER1] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER1);
    _uniforms[UNIFORM_SAMPLER2] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER2);
    _uniforms[UNIFORM_SAMPLER3] = glGetUniformLocation(_program, UNIFORM_NAME_SAMPLER3);
}

void handleVertexAttrib() {
    
    GLint active_attrib_count;
    GLint length;
    // 获取已经激活的属性数量
    glGetProgramiv(_program, GL_ACTIVE_ATTRIBUTES, &active_attrib_count);
    if (active_attrib_count > 0) {
        glGetProgramiv(_program, GL_ACTIVE_ATTRIBUTE_MAX_LENGTH, &length);
        VertexAttrib attribute;
        if (length > 0) {
            GLchar *attribName = (GLchar*) alloca(length + 1);
            for (GLint i = 0; i < active_attrib_count; i++) {
                glGetActiveAttrib(_program, i, length, nullptr, &attribute.size, &attribute.type, attribName);
            }
        }
    }
    else {
        GLchar ErrorLog[1024];
        glGetProgramInfoLog(_program, sizeof(ErrorLog), NULL, ErrorLog);
        cout << "vertex attrib." << ErrorLog << endl;
    }
}

// 创建program和shader
void initProgramShader(const GLchar* vertexArr, const GLchar* fragArr) {
    _program = glCreateProgram();
    _vertexShader = _fragShader = 0;
    
    _vertexShader = glCreateShader(GL_VERTEX_SHADER);
    if (vertexArr != NULL) {
        const GLchar *sources[] = {
            DEFAULT_SHADER_UNIFORMS,
            vertexArr
        };
        glShaderSource(_vertexShader, sizeof(sources)/sizeof(*sources), sources, NULL);
        glCompileShader(_vertexShader);
        GLint status;
        glGetShaderiv(_vertexShader, GL_COMPILE_STATUS, &status);
        if (!status) {
            GLint infoLen = 0;
            glGetShaderiv(_vertexShader, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen) {
                char* infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
                glGetShaderInfoLog(_vertexShader, infoLen, NULL, infoLog);
                cout << "compile vertex shader wrong..." << infoLog << endl;
            }
        }
        else {
            cout << "compile vertex shader success..." << endl;
        }
    }
    
    _fragShader = glCreateShader(GL_FRAGMENT_SHADER);
    // 片元着色器中没有指定的精度,所以必须要指定一个精度
    if (fragArr != NULL) {
        const GLchar *sources[] = {
            DEFAULT_SHADER_UNIFORMS,
            fragArr
        };
        glShaderSource(_fragShader, sizeof(sources)/sizeof(*sources), sources, NULL);
        glCompileShader(_fragShader);
        GLint status;
        glGetShaderiv(_fragShader, GL_COMPILE_STATUS, &status);
        if (!status) {
            GLint infoLen = 0;
            glGetShaderiv(_fragShader, GL_INFO_LOG_LENGTH, &infoLen);
            if (infoLen) {
                char* infoLog = static_cast<char *>(malloc(sizeof(char) * infoLen));
                glGetShaderInfoLog(_fragShader, infoLen, NULL, infoLog);
                cout << "compile fragment shader wrong..." << infoLog << endl;
            }
        }
        else {
            cout << "compile fragment shader success..." << endl;
        }
    }
    
    // 创建和链接程序
    if (_vertexShader) {
        glAttachShader(_program, _vertexShader);
    }
    
    if (_fragShader) {
        glAttachShader(_program, _fragShader);
    }
    
    // 验证程序对象(比较慢,不推荐使用)
    //glValidateProgram(_program);
    
    // 将通用顶点属性索引和指定的属性变量关联起来
    // 用来将Program指定的程序对象中的一个用户定义的属性变量和一个通用的顶点属性索引绑定
    // 属性数组
    static const struct {
        const char* attributeName;
        VERTEX_ATTRIB_TYPE type;
    }
    attribute_locations[] = {
        {ATTRIBUTE_NAME_POSITION, VERTEX_ATTRIB_POSITION}, //顶点位置
        {ATTRIBUTE_NAME_COLOR, VERTEX_ATTRIB_COLOR}, //顶点颜色
        {ATTRIBUTE_NAME_TEXCOOD, VERTEX_ATTRIB_TEXCOOD}, //顶点纹理坐标
    };
    
    // 把顶点属性索引绑定属性名
    for (int i = 0; i < sizeof(attribute_locations)/sizeof(attribute_locations[0]); i++) {
        glBindAttribLocation(_program, attribute_locations[i].type, attribute_locations[i].attributeName);
    }
    
    glLinkProgram(_program);
    
    //需要在program创建了以后才可以获取
    handleUniforms();
    
    // 已经使用完shader以后,则重置shader
    clearShader();
    
    GLint status = GL_TRUE;
    glGetProgramiv(_program, GL_LINK_STATUS, &status);
    if (status == GL_FALSE) {
        cout << "the program link failed." << endl;
        glDeleteProgram(_program);
        _program = 0;
        assert(status == GL_FALSE);
    }
    else {
        cout << "the program link success..." << endl;
    }
    
    handleVertexAttrib();
    
}

// 初始化图片的数据
bool initWithImageData(const unsigned char * data, ssize_t dataLen) {
#define PNGSIGSIZE  8
    bool ret = false;
    png_byte        header[PNGSIGSIZE]   = {0};
    png_structp     png_ptr     =   0;
    png_infop       info_ptr    = 0;
    do
    {
        memcpy(header, data, PNGSIGSIZE);
        
        png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, 0, 0, 0);
        info_ptr = png_create_info_struct(png_ptr);
        
        //png_set_read_fn(png_ptr, &imageSource, pngReadCallback);
        
        // read png header info
        tImageSource imageSource;
        imageSource.data    = (unsigned char*)data;
        imageSource.size    = dataLen;
        imageSource.offset  = 0;
        png_set_read_fn(png_ptr, &imageSource, pngReadCallback);
        
        // read png file info
        png_read_info(png_ptr, info_ptr);
        size_t _img_width = png_get_image_width(png_ptr, info_ptr);
        size_t _img_height = png_get_image_height(png_ptr, info_ptr);
        
        _sp_image_size.fastSet((float)_img_width, (float)_img_height);
        
        png_byte bit_depth = png_get_bit_depth(png_ptr, info_ptr);
        png_uint_32 color_type = png_get_color_type(png_ptr, info_ptr);
        
        if (color_type == PNG_COLOR_TYPE_PALETTE)
        {
            png_set_palette_to_rgb(png_ptr);
        }
        if (color_type == PNG_COLOR_TYPE_GRAY && bit_depth < 8)
        {
            bit_depth = 8;
            png_set_expand_gray_1_2_4_to_8(png_ptr);
        }
        // reduce images with 16-bit samples to 8 bits
        if (bit_depth == 16)
        {
            png_set_strip_16(png_ptr);
        }
        // Expanded earlier for grayscale, now take care of palette and rgb
        if (bit_depth < 8)
        {
            png_set_packing(png_ptr);
        }
        
        png_read_update_info(png_ptr, info_ptr);
        bit_depth = png_get_bit_depth(png_ptr, info_ptr);
        color_type = png_get_color_type(png_ptr, info_ptr);
        
        // read png data
        png_size_t rowbytes;
        png_bytep* row_pointers = (png_bytep*)malloc( sizeof(png_bytep) * _img_height );
        
        rowbytes = png_get_rowbytes(png_ptr, info_ptr);
        
        size_t _datalen = rowbytes * _img_height;
        unsigned char* _data = static_cast<unsigned char*>(malloc(_datalen * sizeof(unsigned char)));
        if (!_data)
        {
            if (row_pointers != nullptr)
            {
                free(row_pointers);
            }
            break;
        }
        
        for (unsigned short i = 0; i < _img_height; ++i)
        {
            row_pointers[i] = _data + i*rowbytes;
        }
        png_read_image(png_ptr, row_pointers);
        
        png_read_end(png_ptr, nullptr);
        
        ret = true;
    } while (0);
    
    if (png_ptr)
    {
        png_destroy_read_struct(&png_ptr, (info_ptr) ? &info_ptr : 0, 0);
    }
    
    return ret;
}

// 第一种方法:获取图片数据,这种方法,可以获取到图片真正的数据,还可以通过fwrite生成新的图片
// cocos2dx使用的是这个方法,但是我不太懂为什么我这边搞错了
bool getImageData(const char* path) {
    // 根据路径获取图片数据
    bool ret = false;
    size_t size = 0;
    size_t readsize;
    
    unsigned char* buffer = nullptr;
    do
    {
        FILE* file = fopen(path, "rb");
        if(file == NULL) {
            std::cout << "Failed to open Image." << std::endl;
            return NULL;
        }
        
        fseek(file,0,SEEK_END);
        size = ftell(file);
        fseek(file,0,SEEK_SET);
        
        buffer = (unsigned char*)malloc(sizeof(unsigned char) * size);
        
        readsize = fread(buffer, sizeof(unsigned char), size, file);
        fclose(file);
    } while (0);
    
    if (nullptr == buffer || 0 == readsize)
    {
        printf("Get data from file %s failed", path);
    }
    else
    {
        _sp_image_data.fastSet(buffer, readsize);
    }
    
    // 对图片数据进行初始化
    unsigned char* unpackedData = nullptr;
    ssize_t unpackedLen = 0;
    
    unpackedData = const_cast<unsigned char*>(_sp_image_data.getBytes());
    unpackedLen = _sp_image_data.getSize();
    ret = initWithImageData(unpackedData, unpackedLen);
    
    return ret;
}

// 第二种方法:获取图片数据,这个方法非常简单,但是只获得了rgb数据,并不能根据这个数据去生成新的图片
// 因为不是学习的重点,所以暂时先使用这个方法
bool getImageData2(const char* path) {
    // 根据路径获取图片数据
    bool ret = true;
    int width, height;
    unsigned char* image_data = SOIL_load_image(path, &width, &height, 0, SOIL_LOAD_RGB);
    const ssize_t size = strlen((const char*)image_data);
    _sp_image_data.fastSet(image_data, size);
    _sp_image_size.fastSet(width, height);
    
    SOIL_free_image_data(image_data);
    
    return ret;
}

void initSpriteData(const char* path) {
    bool ret = getImageData2(path);
    if (!ret) {
        cout << "get iamge data is failed." << endl;
        return ;
    }
    else {
        cout << "get iamge data is success." << endl;
        
        //测试图片数据
        FILE * file;
        file = fopen("/Users/staff/Desktop/abc.png","wb");
        if (file)
        {
            fwrite(_sp_image_data.getBytes(),1,_sp_image_data.getSize(), file);
        }
        fclose(file);
        
    }
    
    glEnable(GL_TEXTURE_2D);
    OPGL::activeTexture(GL_TEXTURE0);
    
    //绑定
    glGenTextures(1, &_sp_textureID);
    glBindTexture(GL_TEXTURE_2D, _sp_textureID);
    
    //纹理过滤函数,纹理图像空间映射到帧缓冲图像空间
    //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);
    
    //生成2d纹理
    glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, _sp_image_size.getX(), _sp_image_size.getY(), 0, GL_RGB, GL_UNSIGNED_BYTE, _sp_image_data.getBytes());
    glGenerateMipmap(GL_TEXTURE_2D);
    
    glBindTexture(GL_TEXTURE_2D, 0);
}

void setSpritePosition(float x, float y) {
    _sp_position.x = x;
    _sp_position.y = y;
    
    if (_sp_position.x == x && _sp_position.y == y)
        return;
    
    _sp_position.x = x;
    _sp_position.y = y;
    
    _sp_transformUpdated = true;
}

// 将精灵的顶点数据填充到绘制的数组中
void filledVertexData() {
    // 分配顶点属性数据
    memcpy(Vertexs + _filledVertex, _sp_triangles.verts, sizeof(V3F_C4B_T2F) * _sp_triangles.vertCount);
    
    // 更新每一个顶点的模型矩阵,根据这个去设置顶点着色器的值
    for (ssize_t i = 0; i < _sp_triangles.vertCount; ++i) {
        V3F_C4B_T2F *v_i = &Vertexs[i + _filledVertex];
        Vector3 *v_p = (Vector3 *)&v_i->vertices;
        _sp_modelView.transformPoint(v_p);
    }
    
    // 获取索引信息
    const unsigned int* indices = _sp_triangles.indices;
    for (ssize_t i = 0; i < _sp_triangles.indexCount; ++i) {
        Indices[i + _filledIndex] = _filledVertex + indices[i];
    }
    
    // 已处理的顶点下标
    _filledVertex += _sp_triangles.vertCount;
    _filledIndex += _sp_triangles.indexCount;
}

void drawDrawCommand() {
    if (_sp_triangles.indexCount % 3 != 0) {
        ssize_t count = _sp_triangles.indexCount;
        _sp_triangles.indexCount = count / 3 * 3;
    }
    
    int indexToDraw = 0;
    
    //Upload buffer to VBO
    if(_filledVertex <= 0 || _filledIndex <= 0)
    {
        cout << "image data is null" << endl;
        return;
    }
    // 设置默认的顶点对象数组
    OPGL::bindVAO(_triangleVAO);
    
    glBindBuffer(GL_ARRAY_BUFFER, _triangleVBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(Vertexs[0]) * _filledVertex, nullptr, GL_DYNAMIC_DRAW);
    void *buf = glMapBuffer(GL_ARRAY_BUFFER, GL_WRITE_ONLY);
    memcpy(buf, Vertexs, sizeof(Vertexs[0])* _filledVertex);
    // 映射缓存
    glUnmapBuffer(GL_ARRAY_BUFFER);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
    
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triangleVBO[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Indices[0]) * _filledIndex, Indices, GL_STATIC_DRAW);
    
    OPGL::bindVAO(0);

    indexToDraw += _sp_triangles.indexCount;
    
    if (indexToDraw > 0) {
        glUseProgram(_program);
        
        glEnable(GL_BLEND);
        glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
        OPGL::activeTexture(GL_TEXTURE0);
        glBindTexture(GL_TEXTURE_2D, _sp_textureID); // 绑定,即可从_textureID中取出图像数据
        glUniform1i(_uniforms[UNIFORM_SAMPLER0], 0);
        
        OPGL::bindVAO(_triangleVAO);
        glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, 0);
        cout << "drawing..." << endl;
        OPGL::bindVAO(0);
    }
    
    // 恢复默认的顶点对象数组
    _filledVertex = 0;
    _filledIndex = 0;
}

void setSpriteVertexAttribInfo() {
    memset(&_sp_quad, 0, sizeof(_sp_quad));
    
    _sp_quad.bl.colors = Color4B::BLUE;
    _sp_quad.br.colors = Color4B::WHITE;
    _sp_quad.tl.colors = Color4B::BLACK;
    _sp_quad.tr.colors = Color4B::RED;
    
    // 1.指的是要处理纹理的部分
    float left = 0.0f;
    float right = 1.0f;
    float top = 1.0f;
    float bottom = 0.0f;
    
    // 左下角
    _sp_quad.bl.texCoords.u = left;
    _sp_quad.bl.texCoords.v = bottom;
    
    // 右下角
    _sp_quad.br.texCoords.u = bottom;
    _sp_quad.br.texCoords.v = right;
    
    // 左上角
    _sp_quad.tl.texCoords.u = top;
    _sp_quad.tl.texCoords.v = left;
    
    // 右上角
    _sp_quad.tr.texCoords.u = top;
    _sp_quad.tr.texCoords.v = right;
    
    // 2.处理四边形的顶点坐标
    float x1 = -0.5f;
    float y1 = -0.5f;
    float x2 = 0.5f;
    float y2 = 0.5f;
    
    // 左下角
    _sp_quad.bl.vertices.set(x1,  y1, 0.0f);
    // 右下角
    _sp_quad.br.vertices.set(x2, y1, 0.0f);
    // 左上角
    _sp_quad.tl.vertices.set(x1, y2, 0.0f);
    // 右上角
    _sp_quad.tr.vertices.set(x2, y2, 0.0f);
    
    // 3.更新到三角形上
    _sp_triangles.vertCount = 4; //顶点个数
    _sp_triangles.verts = (V3F_C4B_T2F*)&_sp_quad; //顶点数据
    _sp_triangles.indexCount = 6; //索引个数
    _sp_triangles.indices = quadIndices;
}

//设置VAO
void setVAOAndVBO() {
    
    _sp_triangles.outVerts();
    _sp_triangles.outIndics();
    
    glGenVertexArrays(1, &_triangleVAO);
    // 绑定VAO
    OPGL::bindVAO(_triangleVAO);
    // 创建生成两个VBO
    glGenBuffers(2, &_triangleVBO[0]);
    // 顶点Buffer
    glBindBuffer(GL_ARRAY_BUFFER, _triangleVBO[0]);
    glBufferData(GL_ARRAY_BUFFER, sizeof(V3F_C4B_T2F) * _sp_triangles.vertCount, _sp_triangles.verts, GL_STATIC_DRAW);
    
    GLuint _positionSlot = glGetAttribLocation(_program, ATTRIBUTE_NAME_POSITION);
    GLuint _colorSlot = glGetAttribLocation(_program, ATTRIBUTE_NAME_COLOR);
    GLuint _textureCoordsSlot = glGetAttribLocation(_program, ATTRIBUTE_NAME_TEXCOOD);
    
    // vertices
    // 位置
    glEnableVertexAttribArray(_positionSlot);
    glVertexAttribPointer(_positionSlot, 3, GL_FLOAT, GL_FALSE, sizeof(V3F_C4B_T2F), (GLvoid*) offsetof( V3F_C4B_T2F, vertices));
    
    // colors
    // 颜色
    glEnableVertexAttribArray(_colorSlot);
    glVertexAttribPointer(_colorSlot, 4, GL_UNSIGNED_BYTE, GL_TRUE, sizeof(V3F_C4B_T2F), (GLvoid*) offsetof( V3F_C4B_T2F, colors));
    
    // tex coords
    // 纹理坐标数据
    glEnableVertexAttribArray(_textureCoordsSlot);
    glVertexAttribPointer(_textureCoordsSlot, 2, GL_FLOAT, GL_FALSE, sizeof(V3F_C4B_T2F), (GLvoid*) offsetof( V3F_C4B_T2F, texCoords));
    
    // 索引Buffer
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, _triangleVBO[1]);
    glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * _sp_triangles.indexCount, _sp_triangles.indices, GL_STATIC_DRAW);
    
    OPGL::bindVAO(0);

    glBindVertexArray(0);
    glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
    glBindBuffer(GL_ARRAY_BUFFER, 0);
}

void init() {
    // 只有源
    reset();
    glViewport(0, 0, 800, 600);
    
    glBlendFunc(GL_ONE, GL_ZERO);
    glEnable(GL_TEXTURE_2D);
    glDisable(GL_DEPTH_TEST); //2d没用
    // Enable texturing
//    glEnable(GL_CULL_FACE); //启用剔除功能
    glEnable(GL_BLEND); //启用混合方式
    glDisable(GL_DITHER); //启用抖动功能
    glDepthMask(GL_FALSE); //将深度缓冲区设置成只读形式
    glDepthFunc(GL_LESS); //指定深度缓冲比较函数,如果输入的深度值小于参考值,则通过
    glDepthRange(0.0f, 1.0f); //用于决定窗口坐标的z值
    glClearDepth(1.0f); //用指定值来清除指定的深度缓冲区值
    glCullFace (GL_BACK); //表示剔除多边形的哪种面
    glFrontFace(GL_CCW); //设置点序列逆时针方向围成的多边形为正面
    glClearStencil(0);//用指定值来清除指定的模版缓冲区值
    glStencilMask( 0xFFFFFFFF ); //指定模版的掩码
    glEnable(GL_VERTEX_PROGRAM_POINT_SIZE);
}

int main(int argc, const char * argv[]) {
    GLFWwindow* window;
    /* Initialize the library */
    if (!glfwInit())
        return -1;

    /* Create a windowed mode window and its OpenGL context */
    window = glfwCreateWindow(800, 600, "First OpenGL", NULL, NULL);
    if (!window)
    {
        glfwTerminate();
        return -1;
    }
    
    /* Make the window's context current */
    glfwMakeContextCurrent(window);
    glewExperimental = GL_TRUE;
    glewInit();
    glfwSwapInterval(1);
    
    // 开启功能
    init();
    // 创建program和shader
    initProgramShader(CCPositionTextureColorVert, CCPositionTextureColorFrag);
    // 对texture进行绘制
    initSpriteData("/Users/staff/Desktop/fgh/fgh/wall.jpg");
    // 设置精灵的顶点属性数据
    setSpriteVertexAttribInfo();
    // 设置顶点数组缓冲区
    setVAOAndVBO();
    
    
    /* Loop until the user closes the window */
    while (!glfwWindowShouldClose(window))
    {
        glfwPollEvents();
        
        int width, height;
        glfwGetFramebufferSize(window, &width, &height);
        glViewport(0, 0, width, height);
        glClearColor(0.2f, 0.3f, 0.3f, 1.0f);
        glClear(GL_COLOR_BUFFER_BIT);
        
        // 填充数据
        filledVertexData();
        // 根据的到的数据进行绘制
        drawDrawCommand();

        
        glfwSwapBuffers(window);
    }
    
    glfwTerminate();
    glDeleteVertexArrays(1, &_triangleVAO);
    glDeleteBuffers(1, &_triangleVBO[0]);
    glDeleteBuffers(1, &_triangleVBO[1]);

    return 0;
}

这里面有个很坑的地方,也是因为自己的基础不扎实,导致找了一天的bug。sizeof()我直接用一个对象指针作为参数,以为是个对象数组应该可以,但是应该是不行的,应该将其类型作为参数,并且乘以对象个数才能得到数组的大小。

还有一个注意的地方,因为只是作为测试使用,所以没有进行封装,只有一个triangleCommand,也就是只会绘制一个指令,后续同样以这个工程作为测试工程。

先是顶点shader:

const char* CCPositionTextureColorVert = STRINGIFY(
attribute vec4 a_position;
attribute vec4 a_color;
attribute vec2 a_texCoord;
                                                   
varying vec4 ourColor;
varying vec2 TexCoord;
                                                   
void main() {
    gl_Position = a_position;
    ourColor = a_color;
    TexCoord = a_texCoord;
}
);

接下来的是片元shader

const char* CCPositionTextureColorFrag = STRINGIFY(
varying vec4 ourColor;
varying vec2 TexCoord;
                                                   
//varying vec4 color;

//uniform float mixValue;
                                                   
void main() {
    //gl_FragColor = mix(texture2D(CC_Texture0, TexCoord) * vec4(ourColor, 1.0), texture2D(CC_Texture1, vec2(-TexCoord.x, TexCoord.y)), mixValue);
    gl_FragColor = ourColor * texture2D(CC_Texture0, TexCoord);
}
);
原文地址:https://www.cnblogs.com/George1994/p/6306505.html