#include <stdio.h>#include <string.h>#include <assert.h>#include <math.h>#include <GL/glew.h>#include <GL/freeglut.h>#include "math_3d.h"GLuint VBO;GLuint gWorldLocation;/*在管线之间传输的变量,都要被声明为out,out是一个shader保留关键字在片元shader中,定义输入颜色,该输入颜色是顶点属性插值后像素的颜色。我们用该插值颜色,做为片元shader最终的输出颜色。*/static const char *pVS = " \n\#version 330 \n\ \n\layout (location = 0) in vec3 Position; \n\ \n\uniform mat4 gWorld; \n\ \n\out vec4 Color; \n\ \n\void main() \n\{ \n\ gl_Position = gWorld * vec4(Position, 1.0); \n\ Color = vec4(clamp(Position, 0.0, 1.0), 1.0); \n\}";static const char *pFS = " \n\#version 330 \n\ \n\in vec4 Color; \n\ \n\out vec4 FragColor; \n\ \n\void main() \n\{ \n\ FragColor = Color; \n\}";static void RenderSceneCB(){ glClear(GL_COLOR_BUFFER_BIT); static float Scale = 0.0f; Scale += 0.001f; Matrix4f World; World.m[0][0] = sinf(Scale) ; World.m[0][1] = 0.0f ; World.m[0][2] = 0.0f; World.m[0][3] = 0.0f; World.m[1][0] = 0.0f ; World.m[1][1] = sinf(Scale); World.m[1][2] = 0.0f; World.m[1][3] = 0.0f; World.m[2][0] = 0.0f; ; World.m[2][1] = 0.0f; ; World.m[2][2] = sinf(Scale); World.m[2][3] = 0.0f; World.m[3][0] = 0.0f; ; World.m[3][1] = 0.0f; ; World.m[3][2] = 0.0f; World.m[3][3] = 1.0f; glUniformMatrix4fv(gWorldLocation, 1, GL_TRUE, &World.m[0][0]); glEnableVertexAttribArray(0); glBindBuffer(GL_ARRAY_BUFFER, VBO); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 0, 0); glDrawArrays(GL_TRIANGLES, 0, 3); glDisableVertexAttribArray(0); glutSwapBuffers();}static void InitializeGlutCallbacks(){ glutDisplayFunc(RenderSceneCB); glutIdleFunc(RenderSceneCB);}static void CreateVertexBuffer(){ Vector3f Vertices[3]; Vertices[0] = Vector3f(-1.0f, -1.0f, 0.0f); Vertices[1] = Vector3f(1.0f, -1.0f, 0.0f); Vertices[2] = Vector3f(0.0f, 1.0f, 0.0f); glGenBuffers(1, &VBO); glBindBuffer(GL_ARRAY_BUFFER, VBO); glBufferData(GL_ARRAY_BUFFER, sizeof(Vertices), Vertices, GL_STATIC_DRAW);}static void AddShader(GLuint ShaderProgram, const char *pShaderText, GLenum ShaderType){ GLuint ShaderObj = glCreateShader(ShaderType); if (ShaderObj == 0) { fprintf(stderr, "Error creating shader type %d\n", ShaderType); exit(0); } const GLchar *p[1]; p[0] = pShaderText; GLint Lengths[1]; Lengths[0] = strlen(pShaderText); glShaderSource(ShaderObj, 1, p, Lengths); glCompileShader(ShaderObj); GLint success; glGetShaderiv(ShaderObj, GL_COMPILE_STATUS, &success); if (!success) { GLchar InfoLog[1024]; glGetShaderInfoLog(ShaderObj, 1024, NULL, InfoLog); fprintf(stderr, "Error compiling shader type %d: '%s'\n", ShaderType, InfoLog); exit(1); } glAttachShader(ShaderProgram, ShaderObj);}static void CompileShaders(){ GLuint ShaderProgram = glCreateProgram(); if (ShaderProgram == 0) { fprintf(stderr, "Error creating shader program\n"); exit(1); } AddShader(ShaderProgram, pVS, GL_VERTEX_SHADER); AddShader(ShaderProgram, pFS, GL_FRAGMENT_SHADER); GLint Success = 0; GLchar ErrorLog[1024] = { 0 }; glLinkProgram(ShaderProgram); glGetProgramiv(ShaderProgram, GL_LINK_STATUS, &Success); if (Success == 0) { glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog); fprintf(stderr, "Error linking shader program: '%s'\n", ErrorLog); exit(1); } glValidateProgram(ShaderProgram); glGetProgramiv(ShaderProgram, GL_VALIDATE_STATUS, &Success); if (!Success) { glGetProgramInfoLog(ShaderProgram, sizeof(ErrorLog), NULL, ErrorLog); fprintf(stderr, "Invalid shader program: '%s'\n", ErrorLog); exit(1); } glUseProgram(ShaderProgram); /*通过查询shader程序对象,我们能够得到uniform变量的位置,该位置和该uniform变量在shader代码中的位置一致。 通常情况下,我们不能直接访问和更新uniform变量。在glsl compiler编译shader代码时候,它会给每个uniform变量 分配一个索引,在shader内部访问uniform变量都是通过这个索引来实现的,应用程序则是通过glGetUniformLocation 函数来访问相应的uniform变量,函数的参数为shader程序句柄以及uniform变量名字。函数调用成功, 则会返回索引值,失败的话返回-1,对返回值进行错误检测也非常重要,这样可以保证shader值被正确更新。 */ gWorldLocation = glGetUniformLocation(ShaderProgram, "gWorld"); assert(gWorldLocation != 0xFFFFFFFF);}int main(int argc, char **argv){ glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA); glutInitWindowSize(1024, 768); glutInitWindowPosition(100, 100); glutCreateWindow("Tutorial 09"); InitializeGlutCallbacks(); // Must be done after glut is initialized! GLenum res = glewInit(); if (res != GLEW_OK) { fprintf(stderr, "Error: '%s'\n", glewGetErrorString(res)); return 1; } glClearColor(0.0f, 0.0f, 0.0f, 0.0f); CreateVertexBuffer(); CompileShaders(); glutMainLoop(); return 0;}