/* 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 #include #include #include "scolor.hpp" #include "tiny_obj_loader.h" using namespace glm; using namespace std; 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; float player_yvel = 0.0f; const float gravity = 0.20f; GLFWwindow* window; // 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){ puts(GREEN("Compile Success").c_str()); return s_reference; } puts(RED("Compile Failed\n").c_str()); return 0; } #include "stone.h" int count = 0; void print_fps(){ int last_count = 0; while(1){ int new_frames = count - last_count; last_count = count; printf("FPS: %d\n", new_frames); sleep(1); } } 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; if(key == GLFW_KEY_SPACE && action == 0) player_yvel = 5.0; } void movement(){ while(1){ // 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); } player_yvel -= gravity; player_y += player_yvel/100.0; if(player_y <= -0.0f) { player_y = -0.0f; player_yvel = 0.0f; } // Mouse Movement 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 > 2.0) player_elevation = 2.0; if(player_elevation < -2.0) player_elevation = -2.0; usleep(10000); } } int main(int argc, char ** argv){ general_buffer = (char*)malloc(GBLEN); glfwInit(); 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 floor[] = {0, 0, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 0, 1, 1, 0, 0}; unsigned int floorbuf; glGenBuffers(1, &floorbuf); glBindBuffer(GL_SHADER_STORAGE_BUFFER, floorbuf); glBufferData(GL_SHADER_STORAGE_BUFFER, sizeof(floor), floor, 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"; int texwidth, texheight; unsigned int tex; unsigned char *image_data = SOIL_load_image("brick_2.png", &texwidth, &texheight, 0, SOIL_LOAD_RGB); printf("Loaded texture %d by %d\n", texwidth, texheight); 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, texwidth, texheight, 0, GL_RGB, GL_UNSIGNED_BYTE, image_data); 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 floor_vertex = make_shader("vertex_floor.glsl", GL_VERTEX_SHADER); unsigned int floor_frag = make_shader("fragment_floor.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 floor_program = glCreateProgram(); glAttachShader(floor_program, floor_vertex); glAttachShader(floor_program, floor_frag); glLinkProgram(floor_program); glGetProgramiv(floor_program, GL_LINK_STATUS, &link_ok); if(!link_ok){ glGetProgramInfoLog(floor_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 mvp_uniform = glGetUniformLocation(program, "mvp"); unsigned int v_attrib_floor = glGetAttribLocation(floor_program, "in_vertex"); unsigned int mvp_uniform_floor = glGetUniformLocation(floor_program, "mvp"); unsigned int tex_uniform = glGetUniformLocation(floor_program, "tex"); thread fps_printer(print_fps); thread run_movement(movement); StoneBlock sb; sb.locations.push_back(vec4(0, 1, 3, 0)); sb.locations.push_back(vec4(2, 1, 3, 0)); for(int i = 0; i < 20; i++) sb.locations.push_back(vec4(-2, -1.0 + i/0.5, 2, 0)); sb.init(); glEnable(GL_DEPTH_TEST); glfwSetKeyCallback(window, handle_keystrokes); glfwSetCursorPos(window, width/2, height/2); while(!glfwWindowShouldClose(window)){ count++; glfwPollEvents(); glClearColor(0, 0.2, 0, 1.0); glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); double time = glfwGetTime(); glm::vec3 axis_y(0, 1, 0); glm::mat4 model = glm::rotate(glm::mat4(1.0f), (float)time, vec3(1, 0, 0)); glm::vec3 lookat; lookat.x = player_x + cos(player_elevation) * cos(player_heading); lookat.y = player_y + sin(player_elevation); lookat.z = player_z + cos(player_elevation) * 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; mat4 vp = projection * view; // Draw the object we loaded glUseProgram(program); glUniformMatrix4fv(mvp_uniform, 1, 0, glm::value_ptr(mvp)); glEnableVertexAttribArray(v_attrib); glBindBuffer(GL_ARRAY_BUFFER, vbuf); glVertexAttribPointer(v_attrib, 3, GL_FLOAT, GL_FALSE, 0, 0); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, ibuf); glDrawElementsInstanced(GL_TRIANGLES, indices.size(), GL_UNSIGNED_SHORT, 0, 20); // Draw the floor glUseProgram(floor_program); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, tex); glUniform1i(tex_uniform, 0); glUniformMatrix4fv(mvp_uniform_floor, 1, 0, glm::value_ptr(vp)); glEnableVertexAttribArray(v_attrib_floor); glBindBuffer(GL_ARRAY_BUFFER, floorbuf); glVertexAttribPointer(v_attrib_floor, 3, GL_FLOAT, GL_FALSE, 0, 0); glDrawArraysInstanced(GL_TRIANGLES, 0, 18, 400); sb.draw(vp); glfwSwapBuffers(window); } glDeleteProgram(program); glfwDestroyWindow(window); glfwTerminate(); free(general_buffer); }