/* Simplified OpenGL 4.5 demo * Seth Long, Fall 2020 * Simple demo, C++ version * Note operator overloading for matrix multiplication! * * Linux build: g++ simple_demo.cpp -lglfw -lGLEW -lGL -lGLU */ #include #include #include #include #include // glad on Windows #include #include #include #include #define TINYOBJLOADER_IMPLEMENTATION #include "tiny_obj_loader.h" #define STB_IMAGE_IMPLEMENTATION #include "stb_image.h" #include using namespace std; using namespace glm; const float height = 800; const float width = 1280; void GLAPIENTRY debug_callback(GLenum, GLenum type, GLuint, GLenum severity, GLsizei, const GLchar* message, const void*){ if(severity != GL_DEBUG_SEVERITY_HIGH && severity != GL_DEBUG_SEVERITY_MEDIUM ) return; fprintf( stderr, "GL ERROR MESSAGE: %s type = 0x%x, severity = 0x%x, message = %s\n", ( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ), type, severity, message ); } int main(int argc, char ** argv){ glfwInit(); GLFWwindow* window = glfwCreateWindow(width, height, "Simple OpenGL 4.0+ Demo", 0, 0); glfwMakeContextCurrent(window); glewInit(); // During init, enable debug output glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(debug_callback, 0); tinyobj::attrib_t attrib; vector shapes; vector materials; string warn, err; if(!tinyobj::LoadObj(&attrib, &shapes, &materials, &err, "cylinder.obj")){ printf("Loading failed! %s\n", err.c_str()); return 1; } vector vertices; vector elements; for(const auto& shape : shapes){ for(const auto& index : shape.mesh.indices){ // Add a vertex to the list vertices.push_back(attrib.vertices[3 * index.vertex_index + 0]); // x coordinate vertices.push_back(attrib.vertices[3 * index.vertex_index + 1]); // y coordinate vertices.push_back(attrib.vertices[3 * index.vertex_index + 2]); // z coordinate vertices.push_back(attrib.texcoords[2 * index.texcoord_index + 0]); // u coordinate vertices.push_back(attrib.texcoords[2 * index.texcoord_index + 1]); // v coordinate elements.push_back(elements.size()); // Until we eliminate duplicates } } printf("Element count: %lu\n", elements.size()); // Format: xyzuv unsigned int vbuf; glGenBuffers(1, &vbuf); glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbuf); glBufferData(GL_SHADER_STORAGE_BUFFER, 20 * vertices.size(), vertices.data(), GL_STATIC_DRAW); unsigned int ebuf; glGenBuffers(1, &ebuf); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf); glBufferData(GL_ELEMENT_ARRAY_BUFFER, 2 * elements.size(), elements.data(), GL_STATIC_DRAW); /* Setup texture here */ int img_width, img_height; unsigned char* image = stbi_load("brick.jpg", &img_width, &img_height, 0, STBI_rgb); if(!image){ printf("image failed to load\n"); return 1; } else { printf("Image size is %d by %d\n", img_width, img_height); } unsigned int tex; glGenTextures(1, &tex); glBindTexture(GL_TEXTURE_2D, tex); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, img_width, img_height, 0, GL_RGB, GL_UNSIGNED_BYTE, image); free(image); int fd = open("vertex_shader.glsl", O_RDONLY); char *source = (char*)malloc(2048); size_t readlen = read(fd, source, 2048); if(2048 == readlen) printf("Warning: vertex shader is probably too long for this read routine\n"); source[readlen] = 0; puts(source); close(fd); unsigned int vs_reference = glCreateShader(GL_VERTEX_SHADER); glShaderSource(vs_reference, 1, (const char**)&source, 0); glCompileShader(vs_reference); glGetShaderInfoLog(vs_reference, 2048, NULL, source); puts(source); int compile_ok; glGetShaderiv(vs_reference, GL_COMPILE_STATUS, &compile_ok); if(!compile_ok){ printf("Vertex shader failed to compile\n"); return 1; } fd = open("fragment_shader.glsl", O_RDONLY); readlen = read(fd, source, 2048); source[readlen] = 0; puts(source); close(fd); unsigned int fs_reference = glCreateShader(GL_FRAGMENT_SHADER); glShaderSource(fs_reference, 1, (const char**)&source, 0); glCompileShader(fs_reference); glGetShaderInfoLog(fs_reference, 2048, NULL, source); puts(source); glGetShaderiv(fs_reference, GL_COMPILE_STATUS, &compile_ok); if(!compile_ok){ printf("Fragment shader failed to compile\n"); return 1; } unsigned int program = glCreateProgram(); glAttachShader(program, vs_reference); glAttachShader(program, fs_reference); glLinkProgram(program); int link_ok; glGetProgramiv(program, GL_LINK_STATUS, &link_ok); glGetProgramInfoLog(program, 2048, NULL, source); puts(source); if(!link_ok){ printf("Link failure\n"); return 1; } free(source); unsigned int v_attrib = glGetAttribLocation(program, "in_vertex"); unsigned int tc_attrib = glGetAttribLocation(program, "in_texcoord"); unsigned int mvp_uniform = glGetUniformLocation(program, "mvp"); int count = 0; glUseProgram(program); glEnableVertexAttribArray(v_attrib); glBindBuffer(GL_ARRAY_BUFFER, vbuf); glVertexAttribPointer(v_attrib, 3, GL_FLOAT, GL_FALSE, 20, 0); glEnableVertexAttribArray(tc_attrib); glBindBuffer(GL_ARRAY_BUFFER, vbuf); glVertexAttribPointer(tc_attrib, 2, GL_FLOAT, GL_FALSE, 20, (const void*)12); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glEnable(GL_DEPTH_TEST); while(!glfwWindowShouldClose(window)){ count++; glfwPollEvents(); glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT); mat4 model = mat4(1.0); model = rotate(model, count / 100.0f, vec3(0, 1, 0)); model = translate(model, vec3(-5, 0, 0)); model = rotate(model, count / 20.0f, vec3(0, 1, 0)); model = rotate(model, radians(45.0f), vec3(0, 0, 1)); // model = scale(model, vec3(sin(count/200.0f) + 1.2, 1.0, 1.0)); mat4 view = lookAt(vec3(0.0f, 5.0f, 15.0f), vec3(0, 0, 0), vec3(0, 1, 0)); mat4 projection = perspective(radians(45.0f), width/height, 0.1f, 1000.0f); mat4 mvp = projection * view * model; glUniformMatrix4fv(mvp_uniform, 1, 0, value_ptr(mvp)); glDrawElementsInstanced(GL_TRIANGLES, elements.size(), GL_UNSIGNED_SHORT, 0, 2); glfwSwapBuffers(window); // usleep(10000); } glDeleteProgram(program); glfwDestroyWindow(window); glfwTerminate(); }