/* 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 #include #include #define GLM_ENABLE_EXPERIMENTAL #include #include #include #include #include #include "tiny_obj_loader.h" #include "scolor.hpp" #include "util.h" using namespace std; using namespace glm; char general_buffer[GBLEN]; float height = 1200; float width = 100; void GLAPIENTRY MessageCallback( GLenum , GLenum type, GLuint , GLenum severity, GLsizei , const GLchar* message, const void* ) { fprintf( stderr, "GL CALLBACK: %s type = 0x%x, severity = 0x%x, message = %s\n", ( type == GL_DEBUG_TYPE_ERROR ? "** GL ERROR **" : "" ), type, severity, message ); } void resize(GLFWwindow*, int new_width, int new_height){ width = new_width; height = new_height; printf("Window resized, now %f by %f\n", width, height); glViewport(0, 0, width, height); } struct Vertex { vec3 pos; vec3 normal; vec2 texCoord; bool operator==(const Vertex& other) const { return pos == other.pos && texCoord == other.texCoord && normal == other.normal; } };// Can't use __attribute__((packed)) due to non-POD vec2 and vec3 namespace std { template<> struct hash { size_t operator()(Vertex const& vertex) const { return hash()(vertex.pos) ^ (hash()(vertex.texCoord) << 1) ^ (hash()(vertex.normal) << 2); } }; } class LoadedObject { public: GLuint ebuf, tvnbuf; size_t element_count; void load_object(const char* filename){ tinyobj::attrib_t attrib; std::vector shapes; std::vector materials; std::string warn, err; vector vertices; vector indices; if(!tinyobj::LoadObj(&attrib, &shapes, &materials, &warn, &err, filename)) throw std::runtime_error(err); unordered_map uniqueVertices = {}; for(const auto& shape : shapes){ for(const auto& index : shape.mesh.indices){ Vertex vertex = {}; vertex.pos = { attrib.vertices[3 * index.vertex_index + 0], attrib.vertices[3 * index.vertex_index + 1], attrib.vertices[3 * index.vertex_index + 2] }; vertex.texCoord = { attrib.texcoords[2 * index.texcoord_index + 0], 1.0 - attrib.texcoords[2 * index.texcoord_index + 1] }; vertex.normal = { attrib.normals[3 * index.normal_index], attrib.normals[3 * index.normal_index + 1], attrib.normals[3 * index.normal_index + 2] }; if(uniqueVertices.count(vertex) == 0){ uniqueVertices[vertex] = (uint32_t)vertices.size(); vertices.push_back(vertex); } indices.push_back(uniqueVertices[vertex]); } } glGenBuffers(1, &tvnbuf); glBindBuffer(GL_SHADER_STORAGE_BUFFER, tvnbuf); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(struct Vertex) * vertices.size(), vertices.data(), GL_STATIC_DRAW); std::cout << "Loaded " << vertices.size() << " Vertices\n"; glGenBuffers(1, &ebuf); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ebuf); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned int) * indices.size(), indices.data(), GL_STATIC_DRAW); element_count = indices.size(); std::cout << "Loaded " << indices.size() << " Indexes\n"; } }; int main(int , char ** ){ glfwInit(); GLFWwindow* window = glfwCreateWindow(width, height, "Simple OpenGL 4.0+ Demo", 0, 0); glfwSetFramebufferSizeCallback(window, resize); glfwMakeContextCurrent(window); glewInit(); // During init, enable debug output glEnable ( GL_DEBUG_OUTPUT ); glDebugMessageCallback( MessageCallback, 0 ); // Load object LoadedObject torus; torus.load_object("monkey.obj"); GLuint visual_program = make_program("vertex_shader.glsl", 0, 0, 0, "fragment_shader.glsl"); if(!visual_program) return 1; unsigned int v_attrib = glGetAttribLocation(visual_program, "in_vertex"); unsigned int n_attrib = glGetAttribLocation(visual_program, "in_normal"); unsigned int t_attrib = glGetAttribLocation(visual_program, "in_texcoord"); unsigned int mvp_uniform = glGetUniformLocation(visual_program, "mvp"); unsigned int model_uniform = glGetUniformLocation(visual_program, "model"); unsigned int factor_uniform = glGetUniformLocation(visual_program, "factor"); int img_width, img_height; // Coming back to this soon unsigned char* image = SOIL_load_image("brick.jpg", &img_width, &img_height, 0, SOIL_LOAD_RGB); if(!image){ puts(RED("No image, giving up!").c_str()); puts(SOIL_last_result()); return 1; } else printf(PURPLE("Image size: %d by %d\n").c_str(), img_width, img_height); GLuint 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 count = 0; glEnable(GL_DEPTH_TEST); while(!glfwWindowShouldClose(window)){ count++; // Do the visual rendering bit 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 model = glm::rotate(glm::mat4(1.0f), count/100.0f, glm::vec3(0, 1, 0)); model = glm::rotate(model, count/100.0f, glm::vec3(1, 0, 0)); glm::mat4 view = glm::lookAt(glm::vec3(0.0f, 0.0f, 4.0f), glm::vec3(0, 0, 0), axis_y); glm::mat4 projection = glm::perspective(45.0f, width/height, 0.1f, 1000.0f); glm::mat4 mvp = projection * view * model; glUseProgram(visual_program); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); // vertices glEnableVertexAttribArray(v_attrib); glBindBuffer(GL_ARRAY_BUFFER, torus.tvnbuf); glVertexAttribPointer(v_attrib, 3, GL_FLOAT, GL_FALSE, 32, 0); // texture coordinates glEnableVertexAttribArray(t_attrib); glBindBuffer(GL_ARRAY_BUFFER, torus.tvnbuf); glVertexAttribPointer(t_attrib, 2, GL_FLOAT, GL_FALSE, 32, (void*)24); // normal vectors glEnableVertexAttribArray(n_attrib); glBindBuffer(GL_ARRAY_BUFFER, torus.tvnbuf); glVertexAttribPointer(n_attrib, 3, GL_FLOAT, GL_FALSE, 32, (void*)12); // Edges3 glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, torus.ebuf); glUniformMatrix4fv(mvp_uniform, 1, 0, glm::value_ptr(mvp)); glUniformMatrix4fv(model_uniform, 1, 0, glm::value_ptr(model)); glUniform1f(factor_uniform, -cos(count/100.0f)); glDrawElementsInstanced(GL_TRIANGLES, torus.element_count, GL_UNSIGNED_INT, 0, 1); glfwSwapBuffers(window); } glDeleteProgram(visual_program); glfwDestroyWindow(window); glfwTerminate(); } // g++ load_object.cpp -lGL -lglfw -lGLEW