/** * From the OpenGL Programming wikibook: http://en.wikibooks.org/wiki/OpenGL_Programming * This file is in the public domain. * Contributors: Sylvain Beucler */ #include #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 /* GLM */ // #define GLM_MESSAGES #define GLM_FORCE_RADIANS #include #include #include #include "../common/shader_utils.h" #include "cube.h" extern "C" struct shrub shrubmaker(float x, float y, float z, int level, float scale); int screen_width=1200, screen_height=1600; GLuint vbo_cube_vertices, vbo_cube_colors; GLuint vbo_vertex_velocity, vbo_cube_positions, vbo_tree_vertices; GLuint ibo_cube_elements; GLuint program, cprogram, tprogram; GLint attribute_coord3d, attribute_v_color, attribute_tv; GLint cattribute_coord3d; GLint uniform_mvp, uniform_tmvp, uniform_twind, uniform_fwind; int fruitfall = 0; struct shrub bush; int init_resources() { bush = shrubmaker(0, 0, 0, 8, 20); glGenBuffers(1, &vbo_cube_positions); glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_cube_positions); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * bush.fn, bush.fruit_vertices, GL_STATIC_DRAW); GLfloat cube_vertices[] = { // front -.10, -.10, .10, 1.0, .10, -.10, .10, 1.0, .10, .10, .10, 1.0, -.10, .10, .10, 1.0, // back -.10, -.10, -.10, 1.0, .10, -.10, -.10, 1.0, .10, .10, -.10, 1.0, -.10, .10, -.10, 1.0, }; glGenBuffers(1, &vbo_cube_vertices); glBindBuffer(GL_ARRAY_BUFFER, vbo_cube_vertices); glBufferData(GL_ARRAY_BUFFER, sizeof(cube_vertices), cube_vertices, GL_STATIC_DRAW); float *vertex_velocity = (float*)calloc(sizeof(float), bush.fn); glGenBuffers(1, &vbo_vertex_velocity); glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbo_vertex_velocity); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * bush.fn, vertex_velocity, GL_STATIC_DRAW); GLfloat cube_colors[] = { // front colors 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, // back colors 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 0.0, 1.0, 1.0, 1.0, 1.0, }; glGenBuffers(1, &vbo_cube_colors); glBindBuffer(GL_ARRAY_BUFFER, vbo_cube_colors); glBufferData(GL_ARRAY_BUFFER, sizeof(cube_colors), cube_colors, GL_STATIC_DRAW); GLushort cube_elements[] = { // front 0, 1, 2, 2, 3, 0, // top 1, 5, 6, 6, 2, 1, // back 7, 6, 5, 5, 4, 7, // bottom 4, 0, 3, 3, 7, 4, // left 4, 5, 1, 1, 0, 4, // right 3, 2, 6, 6, 7, 3, }; glGenBuffers(1, &ibo_cube_elements); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_cube_elements); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cube_elements), cube_elements, GL_STATIC_DRAW); glGenBuffers(1, &vbo_tree_vertices); glBindBuffer(GL_ARRAY_BUFFER, vbo_tree_vertices); glBufferData(GL_ARRAY_BUFFER, sizeof(float) * bush.n, bush.line_vertices, GL_STATIC_DRAW); // Enable once everything works // free(bush.line_vertices); // free(bush.fruit_vertices); GLint link_ok = GL_FALSE; GLuint vs, fs, cs, tes, tcs, tvs, tfs; if ((vs = create_shader("cube.v.glsl", GL_VERTEX_SHADER)) == 0) return 0; if ((fs = create_shader("cube.f.glsl", GL_FRAGMENT_SHADER)) == 0) return 0; if ((cs = create_shader("cube.c.glsl", GL_COMPUTE_SHADER)) == 0) return 0; if ((tcs = create_shader("cube.tcs.glsl", GL_TESS_CONTROL_SHADER)) == 0) return 0; if ((tes = create_shader("cube.tes.glsl", GL_TESS_EVALUATION_SHADER)) == 0) return 0; program = glCreateProgram(); glAttachShader(program, vs); glAttachShader(program, tcs); glAttachShader(program, tes); glAttachShader(program, fs); glLinkProgram(program); glGetProgramiv(program, GL_LINK_STATUS, &link_ok); if (!link_ok) { fprintf(stderr, "glLinkProgram:"); print_log(program); return 0; } const char* attribute_name; attribute_name = "coord3d"; attribute_coord3d = glGetAttribLocation(program, attribute_name); if (attribute_coord3d == -1) { fprintf(stderr, "Could not bind attribute %s\n", attribute_name); return 0; } attribute_name = "v_color"; attribute_v_color = glGetAttribLocation(program, attribute_name); if (attribute_v_color == -1) { fprintf(stderr, "Could not bind attribute %s\n", attribute_name); return 0; } const char* uniform_name; uniform_name = "mvp"; uniform_mvp = glGetUniformLocation(program, uniform_name); if (uniform_mvp == -1) { fprintf(stderr, "Could not bind uniform %s\n", uniform_name); return 0; } uniform_name = "wind"; uniform_fwind = glGetUniformLocation(program, uniform_name); if (uniform_fwind == -1) { fprintf(stderr, "Fruit: Could not bind uniform %s\n", uniform_name); return 0; } cprogram = glCreateProgram(); glAttachShader(cprogram, cs); glLinkProgram(cprogram); glGetProgramiv(cprogram, GL_LINK_STATUS, &link_ok); if (!link_ok) { fprintf(stderr, "Compute glLinkProgram:"); print_log(cprogram); return 0; } if ((tvs = create_shader("tree.v.glsl", GL_VERTEX_SHADER)) == 0) return 0; if ((tfs = create_shader("tree.f.glsl", GL_FRAGMENT_SHADER)) == 0) return 0; tprogram = glCreateProgram(); glAttachShader(tprogram, tvs); glAttachShader(tprogram, tfs); glLinkProgram(tprogram); glGetProgramiv(tprogram, GL_LINK_STATUS, &link_ok); if (!link_ok) { fprintf(stderr, "Tree glLinkProgram:"); print_log(tprogram); return 0; } attribute_tv = glGetAttribLocation(tprogram, "coord3d"); if (attribute_tv == -1) { fprintf(stderr, "Could not bind attribute coord3d\n"); return 0; } uniform_name = "mvp"; uniform_tmvp = glGetUniformLocation(tprogram, uniform_name); if (uniform_tmvp == -1) { fprintf(stderr, "Could not bind uniform %s\n", uniform_name); return 0; } uniform_name = "wind"; uniform_twind = glGetUniformLocation(tprogram, uniform_name); if (uniform_twind == -1) { fprintf(stderr, "Tree: Could not bind uniform %s\n", uniform_name); return 0; } return 1; } void onIdle() { float angle = glutGet(GLUT_ELAPSED_TIME) / 1000.0 * 45; // 45° per second if(!fruitfall && glutGet(GLUT_ELAPSED_TIME) > 5000) fruitfall = 1; glm::vec3 axis_y(0, 1, 0); glm::mat4 anim = glm::rotate(glm::mat4(1.0f), glm::radians(angle), axis_y); glm::mat4 model = glm::translate(glm::mat4(1.0f), glm::vec3(0.0, 0.0, -4.0)); glm::mat4 view = glm::lookAt(glm::vec3(0.0, 100.0, 400.0), glm::vec3(0.0, 100.0, -4.0), glm::vec3(0.0, 1.0, 0.0)); glm::mat4 projection = glm::perspective(45.0f, 1.0f*screen_width/screen_height, 0.1f, 10000.0f); glm::mat4 mvp = projection * view * model * anim; glUseProgram(program); glUniformMatrix4fv(uniform_mvp, 1, GL_FALSE, glm::value_ptr(mvp)); if(fruitfall) glUniform1f(uniform_fwind, 0); else glUniform1f(uniform_fwind, sinf(angle/10)); glUseProgram(tprogram); glUniformMatrix4fv(uniform_tmvp, 1, GL_FALSE, glm::value_ptr(mvp)); glUniform1f(uniform_twind, sinf(angle/10)); glutPostRedisplay(); } void onDisplay() { glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT); if(fruitfall){ glUseProgram(cprogram); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, vbo_cube_positions); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 1, vbo_vertex_velocity); glDispatchCompute(bush.fn, 1, 1); glMemoryBarrier(GL_SHADER_STORAGE_BARRIER_BIT); } //*/ /* GLfloat feedback[10]; glGetBufferSubData(GL_SHADER_STORAGE_BUFFER, 0, sizeof(feedback), feedback); for(float *i = feedback; i < sizeof(feedback)/sizeof(float) + feedback; i++) printf("%f ", *i); printf("\n"); // */ glUseProgram(program); glEnableVertexAttribArray(attribute_coord3d); // Describe our vertices array to OpenGL (it can't guess its format automatically) glBindBuffer(GL_ARRAY_BUFFER, vbo_cube_vertices); glVertexAttribPointer( attribute_coord3d, // attribute 4, // number of elements per vertex, here (x,y,z,o) GL_FLOAT, // the type of each element GL_FALSE, // take our values as-is 0, // no extra data between each position 0 // offset of first element ); glEnableVertexAttribArray(attribute_v_color); glBindBuffer(GL_ARRAY_BUFFER, vbo_cube_colors); glVertexAttribPointer( attribute_v_color, // attribute 3, // number of elements per vertex, here (R,G,B) GL_FLOAT, // the type of each element GL_FALSE, // take our values as-is 0, // no extra data between each position 0 // offset of first element ); glBindBufferBase(GL_SHADER_STORAGE_BUFFER, 0, vbo_cube_positions); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibo_cube_elements); int size; glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size); glPatchParameteri(GL_PATCH_VERTICES, 3); glDrawElementsInstanced(GL_PATCHES, size/sizeof(GLushort), GL_UNSIGNED_SHORT, 0, bush.fn); glDisableVertexAttribArray(attribute_coord3d); glDisableVertexAttribArray(attribute_v_color); //*/ glUseProgram(tprogram); glEnableVertexAttribArray(attribute_tv); glBindBuffer(GL_ARRAY_BUFFER, vbo_tree_vertices); glVertexAttribPointer( attribute_tv, // attribute 4, // number of elements per vertex, here (x,y,z,o) GL_FLOAT, // the type of each element GL_FALSE, // take our values as-is 0, // no extra data between each position 0 // offset of first element ); glDrawArrays(GL_LINES, 0, bush.n / 4); glutSwapBuffers(); } void onReshape(int width, int height) { screen_width = width; screen_height = height; glViewport(0, 0, screen_width, screen_height); } void free_resources() { glDeleteProgram(program); glDeleteBuffers(1, &vbo_cube_vertices); glDeleteBuffers(1, &vbo_cube_colors); glDeleteBuffers(1, &ibo_cube_elements); } int main(int argc, char* argv[]) { glutInit(&argc, argv); glutInitDisplayMode(GLUT_RGBA|GLUT_ALPHA|GLUT_DOUBLE|GLUT_DEPTH); glutInitWindowSize(screen_width, screen_height); glutCreateWindow("My Rotating Cube"); GLenum glew_status = glewInit(); if (glew_status != GLEW_OK) { fprintf(stderr, "Error: %s\n", glewGetErrorString(glew_status)); return 1; } if (!GLEW_VERSION_2_0) { fprintf(stderr, "Error: your graphic card does not support OpenGL 2.0\n"); return 1; } if (init_resources()) { glutDisplayFunc(onDisplay); glutReshapeFunc(onReshape); glutIdleFunc(onIdle); onDisplay(); glEnable(GL_BLEND); glEnable(GL_DEPTH_TEST); //glDepthFunc(GL_LESS); glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); glutMainLoop(); } free_resources(); return 0; }