typedef struct
{
GLuint programObject;
} UserData;
//创建着色器程序并返回着色器句柄
GLuint LoadShader ( GLenum type, const char *shaderSrc )
{
GLuint shader;
GLint compiled;
//创建着色器,获得句柄,type = GL_VERTEX_SHADER | GL_FRAGMENT_SHADER
shader = glCreateShader ( type );
//是否创建成功
if ( shader == 0 )
{
return 0;
}
// 将创建的着色器与着色器程序关联,最后一个参数为数组长度,如果为NULL,则自动计算数组长度
glShaderSource ( shader, 1, &shaderSrc, NULL );
//编译着色器字符串源代码,
glCompileShader ( shader );
//编译着色器可能失败, 编译状态将存储为着色器对象的状态的一部分。 如果着色器编译时没有错误并且可以使用,则此值将设置为GL_TRUE,否则将设置为GL_FALSE。
//可以通过使用参数shader和GL_COMPILE_STATUS调用glGetShaderiv来查询状态值。
glGetShaderiv ( shader, GL_COMPILE_STATUS, &compiled );
if ( !compiled )
{
/*
主要为异常情况信息的打印及处理
*/
GLint infoLen = 0;
//获得log的长度
glGetShaderiv ( shader, GL_INFO_LOG_LENGTH, &infoLen );
if ( infoLen > 1 )
{ //申请log长度内存
char *infoLog = malloc ( sizeof ( char ) * infoLen );
//得到log内容
glGetShaderInfoLog ( shader, infoLen, NULL, infoLog );
//输出log内容-宏定义log,基于各平台实现
LOGD( "Error compiling shader:\n%s\n", infoLog );
free ( infoLog );
}
//标记为删除,撤销glCreateShader的调用
//如果要删除的着色器对象附加到程序对象,它将被标记为删除,但它不会被删除,直到它不再附加到任何程序对象,
//对于任何渲染上下文(即,它必须与 它被附加之前的任何地方都将被删除)。shader为0将被忽视。
//要确定对象是否已标记为删除,可以使用参数shader和GL_DELETE_STATUS调用glGetShaderiv。
glDeleteShader ( shader );
return 0;
}
return shader;
}
int Init ( ESContext *esContext )
{
UserData *userData = esContext->userData;
//声明顶点着色器字符串源码
char vShaderStr[] =
"#version 300 es \n"
"layout(location = 0) in vec4 vPosition; \n"
"void main() \n"
"{ \n"
" gl_Position = vPosition; \n"
"} \n";
//声明片段着色器字符串源码
char fShaderStr[] =
"#version 300 es \n"
"precision mediump float; \n"
"out vec4 fragColor; \n"
"void main() \n"
"{ \n"
" fragColor = vec4 ( 1.0, 0.0, 0.0, 1.0 ); \n"
"} \n";
GLuint vertexShader;
GLuint fragmentShader;
GLuint programObject;
GLint linked;
//创建两种着色器
vertexShader = LoadShader ( GL_VERTEX_SHADER, vShaderStr );
fragmentShader = LoadShader ( GL_FRAGMENT_SHADER, fShaderStr );
//创建着色器program,相当于着色器的容器?
programObject = glCreateProgram ( );
//异常情况判断,是否创建成功
if ( programObject == 0 )
{
return 0;
}
//将着色器附加到program中
glAttachShader ( programObject, vertexShader );
glAttachShader ( programObject, fragmentShader );
//连接着色器程序
glLinkProgram ( programObject );
//获取program连接状态,与glGetShaderiv方法类似
glGetProgramiv ( programObject, GL_LINK_STATUS, &linked );
if ( !linked )
{
/*
异常情况处理,与创建着色器时类似
*/
GLint infoLen = 0;
glGetProgramiv ( programObject, GL_INFO_LOG_LENGTH, &infoLen );
if ( infoLen > 1 )
{
char *infoLog = malloc ( sizeof ( char ) * infoLen );
glGetProgramInfoLog ( programObject, infoLen, NULL, infoLog );
LOGE ( "Error linking program:\n%s\n", infoLog );
free ( infoLog );
}
glDeleteProgram ( programObject );
return FALSE;
}
userData->programObject = programObject;
// 为颜色缓冲区指定清除值,取值范围都是0~1.0f,注意,此操作只是指定指,而非渲染,执行此方法,屏幕不会发生变化
// 执行了glClear ( GL_COLOR_BUFFER_BIT ); 之后,glClearColor指定的颜色才会生效
// 四个参数分别为R、G、B、A
glClearColor ( 1.0f, 1.0f, 1.0f, 0.0f );
return TRUE;
}
void Draw ( ESContext *esContext )
{
UserData *userData = esContext->userData;
//opengl 坐标原点默认给在屏幕中间,顶点坐标分别为xyz,可以画出图元形状
GLfloat vVertices[] = { 0.0f, 0.5f, 0.0f,
-0.5f, -0.5f, 0.0f,
0.5f, -0.5f, 0.0f
};
//设置视口,可渲染的区域,指定视口矩形的左下角坐标
glViewport ( 0, 0, esContext->width, esContext->height );
//GL_COLOR_BUFFER_BIT:表示当前启用了颜色写入的缓冲区。
//GL_DEPTH_BUFFER_BIT:深度缓冲区。
//GL_STENCIL_BUFFER_BIT:指示模板缓冲区。
//清除每个缓冲区的值取决于该缓冲区的清除值的设置。
//设置的视口如果为屏幕大小,则其实清除值就是窗口的背景颜色,如果为静态背景,可以只执行一次。
//执行效率比手动涂抹背景画布效率更高,节省资源。
//像素检验、裁剪检验、抖动和缓存的写屏蔽都会影响glClear的操作,其中,裁剪范围限制了清除的区域,而glClear命令还会忽略alpha函数、融合函数、逻辑操作、模板、纹理映射和z缓存;
glClear ( GL_COLOR_BUFFER_BIT );
//使用创建的着色器program
glUseProgram ( userData->programObject );
//指定通用顶点属性数组
/*
*@param index :指定要修改的通用顶点属性的索引。
*@param size :指定每个通用顶点属性的组件数。 必须为1,2,3或4.初始值为4。
*@param type :指定数组中每个组件的数据类型。 接受符号常量GL_BYTE,GL_UNSIGNED_BYTE,GL_SHORT,GL_UNSIGNED_SHORT,GL_FIXED或GL_FLOAT。 初始值为GL_FLOAT。
*@param normalized :指定在访问定点数据值时是应将其标准化(GL_TRUE)还是直接转换为定点值(GL_FALSE)。
*@param stride :指定连续通用顶点属性之间的字节偏移量。 如果stride为0,则通用顶点属性被理解为紧密打包在数组中的。 初始值为0。
*@param pointer :指定指向数组中第一个通用顶点属性的第一个组件的指针。 初始值为0。
*/
glVertexAttribPointer ( 0, 3, GL_FLOAT, GL_FALSE, 0, vVertices );
//启用顶点属性数组
glEnableVertexAttribArray ( 0 );
//从数组数组中渲染图元:图元种类,三角形、线、点精灵
glDrawArrays ( GL_TRIANGLES, 0, 3 );
}
void Shutdown ( ESContext *esContext )
{
UserData *userData = esContext->userData;
//删除释放着色器program
glDeleteProgram ( userData->programObject );
}
int esMain ( ESContext *esContext )
{
esContext->userData = malloc ( sizeof ( UserData ) );
esCreateWindow ( esContext, "Hello Triangle", 320, 240, ES_WINDOW_RGB );
if ( !Init ( esContext ) )
{
return GL_FALSE;
}
esRegisterShutdownFunc ( esContext, Shutdown );
esRegisterDrawFunc ( esContext, Draw );
return GL_TRUE;
}