#define MAIN #include "game.h" 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 ); } /* Parameters: * point - point to check * margin - margin around that point (default 0.0f) * blocker - pointer to a variable that will hold a pointer to the thing in that spot * instance - pointer to a variable to hold the instance number */ bool clear_check(vec3 point, float margin = 0.0f, SolidObject **blocker = 0, size_t *instance = 0){ ssize_t c_inst; for(auto &so : solid_objects){ if(-1 != (c_inst = so->is_inside(point, margin))){ if(blocker) *blocker = so; if(instance) *instance = c_inst; return false; } } return true; } void general_management_function(){ while(!g.shutdown) { /* Move the player due to keys, physics, etc */ vec3 step_to_point = vec3(1000000, 1000000, 1000000); if(g.forward) step_to_point = get_lookat_point(0, g.run? g.runspeed : g.walkspeed); if(g.right) step_to_point = get_lookat_point(1, g.run? g.runspeed : g.walkspeed); if(g.backward) step_to_point = get_lookat_point(2, g.run? g.runspeed : g.walkspeed); if(g.left) step_to_point = get_lookat_point(3, g.run? g.runspeed : g.walkspeed); if(step_to_point.y != 1000000){ /* Is anything in the way? If so, we shouldn't keep going! */ bool move_ok = true; if(!clear_check(step_to_point, g.move_margin)){ vec3 no_x = vec3(g.player_position.x, step_to_point.y, step_to_point.z); vec3 no_y = vec3(step_to_point.x, g.player_position.y, step_to_point.z); vec3 no_z = vec3(step_to_point.x, step_to_point.y, g.player_position.z); if(clear_check(no_x, g.move_margin)) step_to_point = no_x; else if(clear_check(no_y, g.move_margin)) step_to_point = no_y; else if(clear_check(no_z, g.move_margin)) step_to_point = no_z; else move_ok = false; } if(move_ok) g.player_position = step_to_point; } /* If we're on something, don't fall */ SolidObject *blocker; size_t block_instance; if(clear_check(g.player_position - vec3(0, g.player_height, 0), g.move_margin, &blocker, &block_instance) || g.vertical_speed > 0.0f){ g.vertical_speed -= g.gravity; g.player_position.y += g.vertical_speed; } else { /* Height Correction */ float floor_height = blocker->get_top(block_instance); g.player_position.y = floor_height + g.player_height; blocker->trigger_action(block_instance, PLAYER_ON_OBJECT); } this_thread::sleep_for(chrono::milliseconds(10)); } } void movement_function() { /* We might need a shutdown procedure that ends this loop */ while(!g.shutdown) { for(auto o : game_objects) o->movement(10); /* TODO: Sleep for 10 ms - the time this iteration took */ this_thread::sleep_for(chrono::milliseconds(10)); } } /* direction: 0 - forward, 1 : right, 2 : backwards, 3 : left */ /* If r is set to 0, elevation is incorporated into the result. * Otherwise, it is ignored, and this function leaves y as 0 */ vec3 get_lookat_point(int direction, float r){ vec3 lap; if(r == 0.0f) { r = cos(g.elevation); lap.y = g.player_position.y + sin(g.elevation); } else { lap.y = g.player_position.y; } if(direction == 0){ lap.x = g.player_position.x + r * cos(g.heading); lap.z = g.player_position.z + r * sin(g.heading); } else if (direction == 1){ lap.x = g.player_position.x + r * cos(g.heading + M_PI / 2); lap.z = g.player_position.z + r * sin(g.heading + M_PI / 2); } else if (direction == 2){ lap.x = g.player_position.x - r * cos(g.heading); lap.z = g.player_position.z - r * sin(g.heading); } else if (direction == 3){ lap.x = g.player_position.x + r * cos(g.heading - M_PI / 2); lap.z = g.player_position.z + r * sin(g.heading - M_PI / 2); } return lap; } void key_callback(GLFWwindow* window, int key, int scancode, int action, int mods){ if(action == GLFW_PRESS) { // down if(key == GLFW_KEY_W) g.forward = true; if(key == GLFW_KEY_S) g.backward = true; if(key == GLFW_KEY_A) g.left = true; if(key == GLFW_KEY_D) g.right = true; if(key == GLFW_KEY_LEFT_CONTROL) g.run = true; if(key == GLFW_KEY_SPACE) if(!clear_check(g.player_position - vec3(0, g.player_height, 0), g.move_margin)) g.vertical_speed = g.jump_speed; if(key == GLFW_KEY_ESCAPE) g.release_cursor = true; } if(action == GLFW_RELEASE) { // UP if(key == GLFW_KEY_W) g.forward = false; if(key == GLFW_KEY_S) g.backward = false; if(key == GLFW_KEY_A) g.left = false; if(key == GLFW_KEY_D) g.right = false; if(key == GLFW_KEY_LEFT_CONTROL) g.run = false; } } void cursor_pos_callback(GLFWwindow* window, double xpos, double ypos){ if(g.release_cursor) return; const double max_move_x = g.width/2 - 100; const double max_move_y = g.height/2 - 100; double dx = g.width/2 - xpos; double dy = g.height/2 - ypos; glfwSetCursorPos(window, g.width / 2, g.height / 2); if(dx > max_move_x || dy > max_move_y) return; g.heading -= (dx / 200.0); g.elevation += (dy / 200.0); if(g.elevation > 3.14f/2) g.elevation = 3.14f/2; if(g.elevation < -3.14f/2) g.elevation = -3.14f/2; } void mouse_button_callback(GLFWwindow* window, int button, int action, int mods) { if(g.release_cursor) g.release_cursor = false; if (button == GLFW_MOUSE_BUTTON_LEFT && action == GLFW_PRESS) { // Code to execute on left mouse click } } void window_size_callback(GLFWwindow* window, int width, int height){ g.width = width; g.height = height; glViewport(0, 0, width, height); } int main(int argc, char ** argv){ glfwInit(); GLFWwindow* window = glfwCreateWindow(g.width, g.height, "Simple OpenGL 4.0+ Demo", 0, 0); glfwMakeContextCurrent(window); // TODO: glad instead of glew #ifdef UNIX glewInit(); #else gladLoadGLLoader((GLADloadproc)glfwGetProcAddress); #endif // During init, enable debug output glEnable(GL_DEBUG_OUTPUT); glDebugMessageCallback(debug_callback, 0); // Set up callback functions for glfw glfwSetKeyCallback(window, key_callback); glfwSetCursorPosCallback(window, cursor_pos_callback); glfwSetMouseButtonCallback(window, mouse_button_callback); glfwSetFramebufferSizeCallback(window, window_size_callback); load_level(); for(auto o : game_objects) if(!o->init()) { printf("Object %s failed to load!\n", o->name.c_str()); return 1; } /* Ready to start! Time to start movement */ thread movement_thread(movement_function); thread general_management_thread(general_management_function); glEnable(GL_DEPTH_TEST); while(!glfwWindowShouldClose(window)){ /* Not for a particular object */ glfwPollEvents(); glClearColor(1.0, 1.0, 1.0, 1.0); glClear(GL_COLOR_BUFFER_BIT); glClear(GL_DEPTH_BUFFER_BIT); /* This sets up the camera location, view angle, etc */ mat4 view = lookAt(g.player_position, get_lookat_point(), vec3(0, 1, 0)); mat4 projection = perspective(radians(45.0f), g.width/g.height, 0.1f, 1000.0f); mat4 vp = projection * view; /* Call draw and give it vp */ for(auto o : game_objects) o->draw(vp); /* Not for a particular object */ glfwSwapBuffers(window); // usleep(10000); } g.shutdown = true; movement_thread.join(); general_management_thread.join(); glfwDestroyWindow(window); glfwTerminate(); return 0; }