/** * From the OpenGL Programming wikibook: http://en.wikibooks.org/wiki/OpenGL_Programming * This file is in the public domain. * Contributors: Sylvain Beucler */ #include #include /* Use glew.h instead of gl.h to get all the GL prototypes declared */ #include /* Using the GLUT library for the base windowing setup */ #include /** * Store all the file's contents in memory, useful to pass shaders * source code to OpenGL */ char* file_read(const char* filename) { FILE* in = fopen(filename, "rb"); if (in == NULL) return NULL; int res_size = BUFSIZ; char* res = (char*)malloc(res_size); int nb_read_total = 0; while (!feof(in) && !ferror(in)) { if (nb_read_total + BUFSIZ > res_size) { if (res_size > 10*1024*1024) break; res_size = res_size * 2; res = (char*)realloc(res, res_size); } char* p_res = res + nb_read_total; nb_read_total += fread(p_res, 1, BUFSIZ, in); } fclose(in); res = (char*)realloc(res, nb_read_total + 1); res[nb_read_total] = '\0'; return res; } /** * Display compilation errors from the OpenGL shader compiler */ void print_log(GLuint object) { GLint log_length = 0; if (glIsShader(object)) glGetShaderiv(object, GL_INFO_LOG_LENGTH, &log_length); else if (glIsProgram(object)) glGetProgramiv(object, GL_INFO_LOG_LENGTH, &log_length); else { fprintf(stderr, "printlog: Not a shader or a program\n"); return; } char* log = (char*)malloc(log_length); if (glIsShader(object)) glGetShaderInfoLog(object, log_length, NULL, log); else if (glIsProgram(object)) glGetProgramInfoLog(object, log_length, NULL, log); fprintf(stderr, "%s", log); free(log); } /** * Compile the shader from file 'filename', with error handling */ GLuint create_shader(const char* filename, GLenum type) { const GLchar* source = file_read(filename); if (source == NULL) { fprintf(stderr, "Error opening %s: ", filename); perror(""); return 0; } GLuint res = glCreateShader(type); const GLchar* sources[] = { source }; glShaderSource(res, 1, sources, NULL); free((void*)source); glCompileShader(res); GLint compile_ok = GL_FALSE; glGetShaderiv(res, GL_COMPILE_STATUS, &compile_ok); if (compile_ok == GL_FALSE) { fprintf(stderr, "%s:", filename); print_log(res); glDeleteShader(res); return 0; } return res; } GLuint create_program(const char *vertexfile, const char *fragmentfile) { GLuint program = glCreateProgram(); GLuint shader; if(vertexfile) { shader = create_shader(vertexfile, GL_VERTEX_SHADER); if(!shader) return 0; glAttachShader(program, shader); } if(fragmentfile) { shader = create_shader(fragmentfile, GL_FRAGMENT_SHADER); if(!shader) return 0; glAttachShader(program, shader); } glLinkProgram(program); GLint link_ok = GL_FALSE; glGetProgramiv(program, GL_LINK_STATUS, &link_ok); if (!link_ok) { fprintf(stderr, "glLinkProgram:"); print_log(program); glDeleteProgram(program); return 0; } return program; } GLint get_attrib(GLuint program, const char *name) { GLint attribute = glGetAttribLocation(program, name); if(attribute == -1) fprintf(stderr, "Could not bind attribute %s\n", name); return attribute; } GLint get_uniform(GLuint program, const char *name) { GLint uniform = glGetUniformLocation(program, name); if(uniform == -1) fprintf(stderr, "Could not bind uniform %s\n", name); return uniform; } GLuint vbo_triangle; GLuint program; GLuint vao; GLint attribute_coord2d; GLuint buf; GLuint tex; GLuint pos; int init_resources() { GLuint octree [] = { 0x80000001, 0x80000001, 0x80000001, 0x80000001, 0x80000001, 0x80000001, 0x80000001, 0x80000001, }; GLfloat vertices[] = { 0, 0, 1, 0, 0, 1, 1, 1, }; GLuint indices[] = { 0, 1, 2, 1, 3, 2, }; glGenBuffers(1, &buf); glBindBuffer(GL_TEXTURE_BUFFER, buf); glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_BUFFER, tex); glTexBuffer(GL_TEXTURE_BUFFER, GL_R32UI, buf); GLint link_ok = GL_FALSE; GLuint vs, fs; if ((vs = create_shader("raycast.vert", GL_VERTEX_SHADER)) == 0) return 0; if ((fs = create_shader("raycast.frag", GL_FRAGMENT_SHADER)) == 0) return 0; program = glCreateProgram(); glAttachShader(program, vs); glAttachShader(program, fs); glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, &link_ok); if (!link_ok) { fprintf(stderr, "glLinkProgram:"); print_log(program); return 0; } glUseProgram(program); GLuint root = get_uniform(program, "root"); if (root == -1) { return 0; } pos = get_uniform(program, "p"); if (pos == -1) { return 0; } glGenVertexArrays(1, &vao); glBindVertexArray(vao); glEnableVertexAttribArray(0); glEnableVertexAttribArray(1); GLuint bufs[3]; glGenBuffers(3, bufs); GLuint vtxbuf = bufs[0]; GLuint wldbuf = bufs[1]; GLuint idxbuf = bufs[2]; glBindBuffer(GL_ARRAY_BUFFER, vtxbuf); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer(0, vtxbuf, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ARRAY_BUFFER, wldbuf); glVertexAttribPointer(1, wldbuf, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, idxbuf); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(indices), indices, GL_STATIC_DRAW); glBufferData(GL_TEXTURE_BUFFER, sizeof(octree), octree, GL_STATIC_DRAW); glUniform1ui(root, 0); return 1; } void checkError(void) { GLenum err; while ((err = glGetError()) != GL_NO_ERROR) { printf("OpenGL error: %d\n", err); } printf("Finished error check\n"); } void onDisplay() { printf("Frame\n"); glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); checkError(); glUniform3f(pos, 1.2249755859375f, 1.017822265625f, 1.3031005859375f); float a = 0.25; float b = a * 1280.0f / 1024.0f; GLfloat corners[] = { 1, a, -b, 1, a, b, 1, -a, -b, 1, -a, b, }; glBufferData(GL_ARRAY_BUFFER, sizeof(corners), corners, GL_STREAM_DRAW); glDrawElements(GL_TRIANGLES, 6, GL_UNSIGNED_INT, NULL); checkError(); glutSwapBuffers(); checkError(); } void free_resources() { glDeleteProgram(program); glDeleteBuffers(1, &vbo_triangle); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitContextVersion(3,3); glutInitContextProfile(GLUT_CORE_PROFILE); glutInitDisplayMode(GLUT_RGBA|GLUT_ALPHA|GLUT_DOUBLE|GLUT_DEPTH); glutInitWindowSize(1280, 1024); glutCreateWindow("My Second Triangle"); if (init_resources()) { glutDisplayFunc(onDisplay); glutMainLoop(); } free_resources(); return 0; }