/* Hugh Fisher Jul 2015 Demo use of attribute divisor for instancing gcc divAttrib.c -o divAttrib -lGL -lglut Expected output: blue window with triangles arranged around a square, not quite centred */ #include #include #include #include void Fail(const char * format, ...) { va_list ap; va_start(ap, format); vfprintf(stderr, format, ap); va_end(ap); exit(-1); } void CheckGL(const char * where) { GLenum err; const char * msg; err = glGetError(); if (err != GL_NO_ERROR) { // no gluGetErrorString in GL3/4. Ridiculous if (err == GL_INVALID_ENUM) msg = "Invalid enum"; else if (err == GL_INVALID_VALUE) msg = "Invalid value"; else if (err == GL_INVALID_OPERATION) msg = "Invalid operation"; else if (err == GL_OUT_OF_MEMORY) msg = "Out of memory"; else if (err == GL_INVALID_FRAMEBUFFER_OPERATION) msg = "Invalid frame buffer operation"; else msg = ""; Fail("%s OpenGL error: %d %s", where, err, msg); } } /* Shaders. */ static const char * vertShaderCode = "\ #version 330\n\ in vec4 vVertex;\n\ in vec2 vOffset;\n\ out vec4 vVaryingColor;\n\ void main ()\n\ {\n\ gl_Position = vVertex + vec4(vOffset.x, vOffset.y, 0, 0);\n\ vVaryingColor = vec4(1, 0, 0, 1);\n\ }\n\ "; static const char * fragShaderCode = "\ #version 330\n\ in vec4 vVaryingColor;\n\ out vec4 vFragColor;\n\ void main ()\n\ {\n\ vFragColor = vVaryingColor;\n\ }\n\ "; static GLint prog; static GLint buildShader(GLint kind, const char * source) { GLuint shader; const GLchar * src[1]; GLint ok; char buf[512]; GLsizei len; shader = glCreateShader(kind); src[0] = source; glShaderSource(shader, 1, src, NULL); /* Now compile and report any errors */ glCompileShader(shader); glGetShaderiv(shader, GL_COMPILE_STATUS, &ok); if (! ok) { glGetShaderInfoLog(shader, sizeof(buf), &len, (GLchar *)buf); buf[len] = 0; Fail("Error in shader kind %d: %s", kind, buf); } return shader; } static void initProgram() { GLint vert, frag; GLint ok; char buf[512]; GLsizei len; const GLchar * src[1]; prog = glCreateProgram(); glBindAttribLocation(prog, 0, "vVertex"); glBindAttribLocation(prog, 1, "vOffset"); vert = buildShader(GL_VERTEX_SHADER, vertShaderCode); frag = buildShader(GL_FRAGMENT_SHADER, fragShaderCode); glAttachShader(prog, vert); glAttachShader(prog, frag); glLinkProgram(prog); glGetProgramiv(prog, GL_LINK_STATUS, &ok); if (! ok) { glGetProgramInfoLog(prog, sizeof(buf), &len, (GLchar *)buf); buf[len] = 0; Fail("Error linking GPU program: %s", buf); } glEnable(GL_PROGRAM_POINT_SIZE); CheckGL("initProgram"); } /* Just drawing one triangle */ static GLint vboA; static GLint vBuf; static GLint oBuf; #define NVERTS 3 static GLfloat vertData[NVERTS * 4] = { -0.25, 0, 0, 1, 0.25, 0, 0, 1, 0, 0.433, 0, 1, }; /* But 8 copies, offset around origin */ #define NTRIS 8 static GLfloat offsetData[NTRIS * 2] = { -0.5, -0.5, 0, -0.5, 0.5, -0.5, -0.5, 0, 0.5, 0, -0.5, 0.5, 0, 0.5, 0.5, 0.5, }; static void initGeo() { glGenVertexArrays(1, &vboA); glBindVertexArray(vboA); // Single attribute, vertex position glGenBuffers(1, &vBuf); glBindBuffer(GL_ARRAY_BUFFER, vBuf); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 4 * NVERTS, vertData, GL_STATIC_DRAW); glEnableVertexAttribArray(0); glVertexAttribPointer(0, 4, GL_FLOAT, GL_FALSE, 0, 0); // Per-triangle attribute, offset glGenBuffers(1, &oBuf); glBindBuffer(GL_ARRAY_BUFFER, oBuf); glBufferData(GL_ARRAY_BUFFER, sizeof(GLfloat) * 2 * NTRIS, offsetData, GL_STATIC_DRAW); glEnableVertexAttribArray(1); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 0, 0); glVertexAttribDivisor(1, 1); // Done glBindVertexArray(0); glBindBuffer(GL_ARRAY_BUFFER, 0); CheckGL("initGeo"); } /* Main program */ void ChangeSize(int w, int h) { printf("Resize %d x %d\n", w, h); glViewport(0, 0, w, h); } void DrawWindow() { printf("Draw!\n"); glClearColor(0, 0, 1, 0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glBindVertexArray(vboA); glUseProgram(prog); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glLineWidth(2); glDrawArraysInstanced(GL_TRIANGLES, 0, 3, NTRIS); glutSwapBuffers(); CheckGL("DrawWindow"); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_DOUBLE | GLUT_RGBA | GLUT_DEPTH); glutInitWindowSize(256, 256); glutInitContextVersion(3,3); glutInitContextProfile(GLUT_CORE_PROFILE); glutCreateWindow("Attribute divisor demo"); glEnable(GL_DEPTH_TEST); initGeo(); initProgram(); glutReshapeFunc(ChangeSize); glutDisplayFunc(DrawWindow); glutMainLoop(); }