/* Simplified OpenGL 4.5 demo * Seth Long, Fall 2020 * This is a *very* short demo which displays a triangle * Many of these functions can fail, and return error values * I doubt it can be done much shorter without leaving vertices in only main memory or some such */ #include #include #include #include #include #include #include #include #include #include "scolor.hpp" using namespace std; const float height = 800; const float width = 1280; // Will be used for a lot of stuff throughout the demo // NOTE: general_buffer is NOT thread safe. Don't try to load shaders in parallel! // NOTE on the NOTE: You probably shouldn't do that anyway! #define GBLEN (1024*32) char* general_buffer; int count = 0; GLuint make_program(const char* v_file, const char* tcs_file, const char* tes_file, const char* g_file, const char* f_file); GLuint make_shader(const char* filename, GLenum shaderType); class gameobject { public: virtual int init() { return 0; } virtual void deinit() {}; virtual void draw(glm::mat4) {} }; vector objects; class lightbox : public gameobject { public: unsigned int mvp_uniform, anim_uniform, v_attrib, c_attrib, program, vbuf, cbuf, ebuf; int init() override { // Initialization part float vertices[] = { // front -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, // back -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, }; glGenBuffers(1, &vbuf); glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbuf); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); float colors[] = { // front colors 1.0, 0.0, 1.0, 1.0, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, // back colors 0.5, 1.0, 0.5, 0.5, 1.0, 0.5, 1.0, 1.0, 1.0, 1.0, 1.0, 1.0, }; glGenBuffers(1, &cbuf); glBindBuffer(GL_SHADER_STORAGE_BUFFER, cbuf); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(colors), 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, &ebuf); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cube_elements), cube_elements, GL_STATIC_DRAW); program = make_program("other_vertex_shader.glsl",0, 0, 0, "fragment_shader.glsl"); if (!program) return 1; v_attrib = glGetAttribLocation(program, "in_vertex"); c_attrib = glGetAttribLocation(program, "in_color"); mvp_uniform = glGetUniformLocation(program, "mvp"); return 0; } void draw(glm::mat4 vp) override { glUseProgram(program); glEnableVertexAttribArray(v_attrib); glBindBuffer(GL_ARRAY_BUFFER, vbuf); glVertexAttribPointer(v_attrib, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(c_attrib); glBindBuffer(GL_ARRAY_BUFFER, cbuf); glVertexAttribPointer(c_attrib, 3, GL_FLOAT, GL_FALSE, 0, 0); int size; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf); glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size); glUniformMatrix4fv(mvp_uniform, 1, 0, glm::value_ptr(vp)); glDrawElementsInstanced(GL_TRIANGLES, size / sizeof(GLushort), GL_UNSIGNED_SHORT, 0, 1); } }; class weirdbox : public gameobject { public: unsigned int mvp_uniform, anim_uniform, v_attrib, c_attrib, program, vbuf, cbuf, ebuf; int init() override { // Initialization part float vertices[] = { // front -1.0, -1.0, 1.0, 1.0, -1.0, 1.0, 1.0, 1.0, 1.0, -1.0, 1.0, 1.0, // back -1.0, -1.0, -1.0, 1.0, -1.0, -1.0, 1.0, 1.0, -1.0, -1.0, 1.0, -1.0, }; glGenBuffers(1, &vbuf); glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbuf); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); float 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, &cbuf); glBindBuffer(GL_SHADER_STORAGE_BUFFER, cbuf); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(colors), 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, &ebuf); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(cube_elements), cube_elements, GL_STATIC_DRAW); program = make_program("vertex_shader.glsl",0, 0, 0, "fragment_shader.glsl"); if (!program) return 1; v_attrib = glGetAttribLocation(program, "in_vertex"); c_attrib = glGetAttribLocation(program, "in_color"); mvp_uniform = glGetUniformLocation(program, "mvp"); anim_uniform = glGetUniformLocation(program, "animation"); return 0; } void draw(glm::mat4 vp) override { glUseProgram(program); glEnableVertexAttribArray(v_attrib); glBindBuffer(GL_ARRAY_BUFFER, vbuf); glVertexAttribPointer(v_attrib, 3, GL_FLOAT, GL_FALSE, 0, 0); glEnableVertexAttribArray(c_attrib); glBindBuffer(GL_ARRAY_BUFFER, cbuf); glVertexAttribPointer(c_attrib, 3, GL_FLOAT, GL_FALSE, 0, 0); int size; glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf); glGetBufferParameteriv(GL_ELEMENT_ARRAY_BUFFER, GL_BUFFER_SIZE, &size); glm::mat4 anim = glm::rotate(glm::mat4(1.0f), count / 20.0f, glm::vec3(0, 1, 0)); anim = glm::scale(anim, glm::vec3(1 - .5f*sinf(count/10.0f), 3 + 2*sinf(count / 10.0f), 1 - 0.5*sinf(count/10.0f))); glUniformMatrix4fv(mvp_uniform, 1, 0, glm::value_ptr(vp)); glUniformMatrix4fv(anim_uniform, 1, 0, (float*)&anim); glDrawElementsInstanced(GL_TRIANGLES, size / sizeof(GLushort), GL_UNSIGNED_SHORT, 0, 10); } void deinit(){ glDeleteProgram(program); // And the vertex, color, and element buffers // And the shaders } }; GLuint make_shader(const char* filename, GLenum shaderType) { FILE* fd = fopen(filename, "r"); if (fd == 0) { printf("File not found: %s\n", filename); return 0; } size_t readlen = fread(general_buffer, 1, GBLEN, fd); fclose(fd); if (readlen == GBLEN) { printf(RED("Buffer Length of %d bytes Inadequate for File %s\n").c_str(), GBLEN, filename); return 0; } if (readlen == 0) { puts(RED("File read problem, read 0 bytes").c_str()); return 0; } general_buffer[readlen] = 0; printf(DGREEN("Read shader in file %s (%d bytes)\n").c_str(), filename, readlen); puts(general_buffer); unsigned int s_reference = glCreateShader(shaderType); glShaderSource(s_reference, 1, (const char**)&general_buffer, 0); glCompileShader(s_reference); glGetShaderInfoLog(s_reference, GBLEN, NULL, general_buffer); puts(general_buffer); GLint compile_ok; glGetShaderiv(s_reference, GL_COMPILE_STATUS, &compile_ok); if (compile_ok) { puts(GREEN("Compile Success").c_str()); return s_reference; } puts(RED("Compile Failed\n").c_str()); return 0; } GLuint make_program(const char* v_file, const char* tcs_file, const char* tes_file, const char* g_file, const char* f_file) { unsigned int vs_reference = make_shader(v_file, GL_VERTEX_SHADER); unsigned int tcs_reference = 0, tes_reference = 0; if (tcs_file) if (!(tcs_reference = make_shader(tcs_file, GL_TESS_CONTROL_SHADER))) return 0; if (tes_file) if (!(tes_reference = make_shader(tes_file, GL_TESS_EVALUATION_SHADER))) return 0; unsigned int gs_reference = 0; if (g_file) gs_reference = make_shader(g_file, GL_GEOMETRY_SHADER); unsigned int fs_reference = make_shader(f_file, GL_FRAGMENT_SHADER); if (!(vs_reference && fs_reference)) return 0; if (g_file && !gs_reference) return 0; unsigned int program = glCreateProgram(); glAttachShader(program, vs_reference); if (g_file) glAttachShader(program, gs_reference); if (tcs_file) glAttachShader(program, tcs_reference); if (tes_file) glAttachShader(program, tes_reference); glAttachShader(program, fs_reference); glLinkProgram(program); GLint link_ok; glGetProgramiv(program, GL_LINK_STATUS, &link_ok); if (!link_ok) { glGetProgramInfoLog(program, GBLEN, NULL, general_buffer); puts(general_buffer); puts(RED("Link Failed").c_str()); return 0; } return program; } int main(int argc, char** argv) { general_buffer = (char*)malloc(GBLEN); glfwInit(); GLFWwindow* window = glfwCreateWindow(width, height, "Simple OpenGL 4.0+ Demo", 0, 0); glfwMakeContextCurrent(window); glewInit(); weirdbox wb; lightbox lb; objects.push_back(&wb); objects.push_back(&lb); for(gameobject* o : objects){ if(o->init()){ puts(RED("Compile Failed, giving up!").c_str()); return 1; } } glEnable(GL_DEPTH_TEST); while (!glfwWindowShouldClose(window)) { count++; glfwPollEvents(); glClearColor(0, 0, 0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT); glm::vec3 axis_y(0, 1, 0); glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 0.0f, 50.0f), glm::vec3(0, 0, 0), axis_y); glm::mat4 projection = glm::perspective(45.0f, width / height, 0.1f, 1000.0f); glm::mat4 vp = projection * view; for(gameobject* o : objects) o->draw(vp); glfwSwapBuffers(window); } glfwDestroyWindow(window); glfwTerminate(); free(general_buffer); }