/* 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 * If moving to C++, use GLM instead of cglm g++ load_object.cpp -lGL -lglfw -lGLEW */ #include #include #include #include #include #include #include #include #include #include "scolor.hpp" #include "tiny_obj_loader.h" #include struct key_status_struct { bool w, s, a, d; }; struct key_status_struct key_status = {false, false, false, false}; const float height = 800; const float width = 1280; float player_x = 0, player_y = 0, player_z = 9; float player_heading = 0; float player_elevation = 0; // 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; GLuint make_shader(char *filename, GLenum shaderType){ int fd = open(filename, O_RDONLY); size_t readlen = read(fd, general_buffer, GBLEN); close(fd); if(readlen == GBLEN){ printf(RED("Buffer Length of %d bytes Inadequate for File %s\n").c_str(), GBLEN, filename); 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){ printf(GREEN("Compile Success\n").c_str()); return s_reference; } puts(RED("Compile Failed\n").c_str()); return 0; } void handle_keystrokes(GLFWwindow* window, int key, int scancode, int action, int mods){ if(action == 2) return; if(key == GLFW_KEY_W) key_status.w = action; else if(key == GLFW_KEY_S) key_status.s = action; } void handle_mousemove(GLFWwindow *window, double xpos, double ypos){ static double cpos_x = width/2; static double cpos_y = height/2; double xmove = cpos_x - xpos; double ymove = cpos_y - ypos; cpos_x = xpos; cpos_y = ypos; player_heading += xmove / 100.0; player_elevation += ymove / 100.0; if(player_elevation > 1.0) player_elevation = 1.0; if(player_elevation < -1.0) player_elevation = -1.0; printf("xpos = %lf, ypos = %lf, heading = %f\n", xpos, ypos, player_heading); } 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(); tinyobj::attrib_t attrib; std::vector shapes; std::vector material; std::string warn, err; tinyobj::LoadObj(&attrib, &shapes, &material, &warn, &err, "torus.obj"); // Initialization part unsigned int vbuf; glGenBuffers(1, &vbuf); glBindBuffer(GL_SHADER_STORAGE_BUFFER, vbuf); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(float) * attrib.vertices.size(), attrib.vertices.data(), GL_STATIC_DRAW); std::cout << "Loaded " << attrib.vertices.size() << " Vertices\n"; float colors[] = {1, 0, 0, 0, 1, 0, 0, 0, 1}; unsigned int cbuf; glGenBuffers(1, &cbuf); glBindBuffer(GL_SHADER_STORAGE_BUFFER, cbuf); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(colors), colors, GL_STATIC_DRAW); unsigned int ibuf; std::vector indices; for(const auto &e : shapes[0].mesh.indices) indices.push_back(e.vertex_index); glGenBuffers(1, &ibuf); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf); glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(unsigned short) * indices.size(), indices.data(), GL_STATIC_DRAW); std::cout << "Loaded " << indices.size() << " Indexes\n"; unsigned int vs_reference = make_shader("vertex_shader.glsl", GL_VERTEX_SHADER); unsigned int fs_reference = make_shader("fragment_shader.glsl", GL_FRAGMENT_SHADER); if(!(vs_reference && fs_reference)) return 0; unsigned int program = glCreateProgram(); glAttachShader(program, vs_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); printf(RED("Link Failed\n").c_str()); return 0; } unsigned int v_attrib = glGetAttribLocation(program, "in_vertex"); unsigned int c_attrib = glGetAttribLocation(program, "in_color"); 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, 0, 0); glEnableVertexAttribArray(c_attrib); glBindBuffer(GL_ARRAY_BUFFER, cbuf); glVertexAttribPointer(c_attrib, 3, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf); glEnable(GL_DEPTH_TEST); glfwSetKeyCallback(window, handle_keystrokes); glfwSetCursorPos(window, width/2, height/2); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetCursorPosCallback(window, handle_mousemove); while(!glfwWindowShouldClose(window)){ count++; glfwPollEvents(); glClearColor(0, 0.2, 0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); glm::vec3 axis_y(0, 1, 0); glm::mat4 model = glm::rotate(glm::mat4(1.0f), count/100.0f, axis_y); glm::vec3 lookat; lookat.x = cos(player_elevation) * (player_x + cos(player_heading)); lookat.y = sin(player_elevation); lookat.z = cos(player_elevation) * (player_z + sin(player_heading)); glm::mat4 view = glm::lookAt(glm::vec3(player_x, player_y, player_z), lookat, axis_y); glm::mat4 projection = glm::perspective(45.0f, width/height, 0.1f, 1000.0f); glm::mat4 mvp = projection * view * model; glUniformMatrix4fv(mvp_uniform, 1, 0, glm::value_ptr(mvp)); glDrawElements(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, 0); glfwSwapBuffers(window); // Movement if(key_status.w){ player_x += 0.1 * cos(player_heading); player_z += 0.1 * sin(player_heading); } if(key_status.s) { player_x -= 0.1 * cos(player_heading); player_z -= 0.1 * sin(player_heading); } /* double xpos, ypos; glfwGetCursorPos(window, &xpos, &ypos); glfwSetCursorPos(window, width/2, height/2); double xmove = width/2 - xpos; double ymove = height/2 - ypos; player_heading += xmove / 100.0; player_elevation += ymove / 100.0; if(player_elevation > 1.0) player_elevation = 1.0; if(player_elevation < -1.0) player_elevation = -1.0; */ // End of Movement usleep(10000); } glDeleteProgram(program); glfwDestroyWindow(window); glfwTerminate(); free(general_buffer); }