| #include <stdlib.h> | |
| #include <stdio.h> | |
| #include <sstream> | |
| #include <poly/Glad.h> | |
| #include <GLFW/glfw3.h> | |
| #include <poly/Log.h> | |
| #include <poly/CommandLineOptions.h> | |
| #include <poly/MiniTrace.h> | |
| #include <poly/Pointer.h> | |
| #include <poly/Math.h> | |
| #include <poly/Shaders.h> | |
| #include <poly/TurnTableSmooth.h> | |
| #include <poly/Grid.h> | |
| using namespace poly; | |
| /* -------------------------------------------- */ | |
| void button_callback(GLFWwindow* win, int bt, int action, int mods); | |
| void cursor_callback(GLFWwindow* win, double x, double y); | |
| void key_callback(GLFWwindow* win, int key, int scancode, int action, int mods); | |
| void char_callback(GLFWwindow* win, unsigned int key); | |
| void error_callback(int err, const char* desc); | |
| void resize_callback(GLFWwindow* window, int width, int height); | |
| void scroll_callback(GLFWwindow* window, double xoffset, double yoffset); | |
| /* -------------------------------------------- */ | |
| int win_h = 0; | |
| int win_w = 0; | |
| TurnTableSmooth table; | |
| class Cam { | |
| public: | |
| void init(const vec3& pos, const vec3& target, const vec3& up, float winWidth, float winHeight); | |
| void update(); | |
| void onMouseDown(float x, float y); | |
| void onMouseMove(float x, float y); | |
| void onMouseUp(); | |
| vec4 screenToWorld(float x, float y); | |
| public: | |
| float win_width = 0.0f; | |
| float win_height = 0.0f; | |
| float zoom = 1.0f; | |
| vec3 pos; | |
| vec3 target; | |
| vec3 up; | |
| vec3 dir; | |
| vec2 pan; | |
| mat4 pm; /* Projection Matrix. */ | |
| mat4 lm; /* Lookat matrix */ | |
| mat4 vm; /* View matrix. */ | |
| float yaw = 0.0f; /* Around Y-axis. */ | |
| float pitch = 0.0f; /* Around X-axis. */ | |
| mat4 screen_to_world; /* Inverted projection matrix. */ | |
| vec4 mouse_down_pos; | |
| bool is_down = false; | |
| }; | |
| Cam cam; | |
| /* -------------------------------------------- */ | |
| int main(int argc, char* argv[]) { | |
| glfwSetErrorCallback(error_callback); | |
| CommandLineOptions cmd; | |
| cmd.addU32("width", false, 1920, "Window width"); | |
| cmd.addU32("height", false, 1080, "Window height"); | |
| cmd.addU32("x", false, 0, "Window X position"); | |
| cmd.addU32("y", false, 0, "Window Y position"); | |
| cmd.addFlag("decorated", "Draw window title, min/max buttons and border."); | |
| if (0 != cmd.init(argc, argv)) { | |
| SX_ERROR("Failed to initialize."); | |
| exit(EXIT_FAILURE); | |
| } | |
| if(!glfwInit()) { | |
| printf("Error: cannot setup glfw.\n"); | |
| exit(EXIT_FAILURE); | |
| } | |
| glfwWindowHint(GLFW_SAMPLES, 4); | |
| glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); | |
| glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); | |
| glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); | |
| glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); | |
| glfwWindowHint(GLFW_COCOA_RETINA_FRAMEBUFFER, GL_FALSE); | |
| glfwWindowHint(GLFW_RESIZABLE, GL_FALSE); | |
| glfwWindowHint(GLFW_DECORATED, (true == cmd.hasFlag("decorated")) ? GL_TRUE : GL_FALSE); | |
| GLFWwindow* win = NULL; | |
| int w = cmd.getU32("width"); | |
| int h = cmd.getU32("height"); | |
| int x = cmd.getU32("x"); | |
| int y = cmd.getU32("y"); | |
| win_w = w; | |
| win_h = h; | |
| win = glfwCreateWindow(w, h, "TURN TABLE", NULL, NULL); | |
| if(!win) { | |
| glfwTerminate(); | |
| exit(EXIT_FAILURE); | |
| } | |
| glfwSetFramebufferSizeCallback(win, resize_callback); | |
| glfwSetKeyCallback(win, key_callback); | |
| glfwSetCharCallback(win, char_callback); | |
| glfwSetCursorPosCallback(win, cursor_callback); | |
| glfwSetMouseButtonCallback(win, button_callback); | |
| glfwSetScrollCallback(win, scroll_callback); | |
| glfwMakeContextCurrent(win); | |
| glfwSwapInterval(1); | |
| if (cmd.getU32("x") && cmd.getU32("y")) { | |
| glfwSetWindowPos(win, x, y); | |
| } | |
| if (!gladLoadGL()) { | |
| printf("Cannot load GL.\n"); | |
| exit(1); | |
| } | |
| // ---------------------------------------------------------------- | |
| // THIS IS WHERE YOU START CALLING OPENGL FUNCTIONS, NOT EARLIER!! | |
| // ---------------------------------------------------------------- | |
| mtr_init("turntable.json"); | |
| MTR_META_PROCESS_NAME("turntable"); | |
| MTR_META_THREAD_NAME("main"); | |
| poly_log_init(1024, argc, argv); | |
| poly_log_add_sink_stdout(); | |
| glDisable(GL_DEPTH_TEST); | |
| glDisable(GL_DITHER); | |
| glEnable(GL_BLEND); | |
| glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); | |
| /* -------------------------------------------------------------------- */ | |
| mat4 pm; | |
| pm.perspective(60.0f, win_w / win_h, 0.1f, 100.0f); | |
| mat4 vm; | |
| vm.lookat(vec3(0, 3, 3), vec3(0, 0, 0), vec3(0, 1, 0)); | |
| vm.print(); | |
| ShaderP3C4 shader_pc; | |
| if (0 != shader_pc.init()) { | |
| exit(EXIT_FAILURE); | |
| } | |
| Grid grid; | |
| grid.init(50, 50, 0.1, 0.1); | |
| table.lookat(vec3(0, 3, 3), vec3(0,0,0), vec3(0,1,0)); | |
| cam.init(vec3(0, 5, 5), vec3(0,0,0), vec3(0,1,0), win_w, win_h); | |
| /* -------------------------------------------------------------------- */ | |
| /* Our main render loop. */ | |
| while(!glfwWindowShouldClose(win)) { | |
| glBindFramebuffer(GL_FRAMEBUFFER, 0); | |
| glViewport(0, 0, w, h); | |
| glClearColor(0.13f, 0.13f, 0.13f, 1.0f); | |
| glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); | |
| MTR_SCOPE("main", "update()"); | |
| cam.update(); | |
| shader_pc.use(); | |
| shader_pc.setProjectionMatrix(pm.ptr()); | |
| shader_pc.setViewMatrix(cam.vm.ptr()); | |
| grid.draw(); | |
| glfwSwapBuffers(win); | |
| glfwPollEvents(); | |
| } | |
| mtr_flush(); | |
| mtr_shutdown(); | |
| glfwTerminate(); | |
| return EXIT_SUCCESS; | |
| } | |
| void char_callback(GLFWwindow* win, unsigned int key) { | |
| } | |
| void key_callback(GLFWwindow* win, int key, int scancode, int action, int mods) { | |
| if (GLFW_RELEASE == action) { | |
| return; | |
| } | |
| switch(key) { | |
| case GLFW_KEY_A: { | |
| /* left */ | |
| cam.pan.x -= 1; | |
| break; | |
| } | |
| case GLFW_KEY_D: { | |
| /* right */ | |
| cam.pan.x += 1; | |
| break; | |
| } | |
| case GLFW_KEY_EQUAL: { | |
| cam.zoom += 0.1; | |
| break; | |
| } | |
| case GLFW_KEY_MINUS: { | |
| cam.zoom -= 0.1; | |
| break; | |
| } | |
| case GLFW_KEY_UP: { | |
| cam.pitch -= 1 * DEG_TO_RAD; | |
| break; | |
| } | |
| case GLFW_KEY_DOWN: { | |
| cam.pitch += 1 * DEG_TO_RAD; | |
| break; | |
| } | |
| case GLFW_KEY_LEFT: { | |
| cam.yaw -= 1 * DEG_TO_RAD; | |
| break; | |
| } | |
| case GLFW_KEY_RIGHT: { | |
| cam.yaw += 1 * DEG_TO_RAD; | |
| break; | |
| } | |
| case GLFW_KEY_SPACE: { | |
| break; | |
| } | |
| case GLFW_KEY_ESCAPE: { | |
| glfwSetWindowShouldClose(win, GL_TRUE); | |
| break; | |
| } | |
| }; | |
| } | |
| void resize_callback(GLFWwindow* window, int width, int height) { | |
| } | |
| void cursor_callback(GLFWwindow* win, double x, double y) { | |
| Pointer p; | |
| p.id = 666; | |
| p.x = x; | |
| p.y = y; | |
| p.type = POINTER_TYPE_MOUSE; | |
| p.button = POINTER_BUTTON_LEFT; | |
| p.state = POINTER_STATE_MOVE; | |
| table.onMouseMove(x, y); | |
| cam.onMouseMove(x, y); | |
| } | |
| void scroll_callback(GLFWwindow* window, double xoffset, double yoffset) { | |
| table.onScroll(yoffset); | |
| } | |
| void button_callback(GLFWwindow* win, int bt, int action, int mods) { | |
| double mx = 0.0f; | |
| double my = 0.0f; | |
| glfwGetCursorPos(win, &mx, &my); | |
| SX_VERBOSE("mouse: %2.2f, %2.2f", mx, my); | |
| Pointer p; | |
| p.id = 666; | |
| p.x = mx; | |
| p.y = my; | |
| p.type = POINTER_TYPE_MOUSE; | |
| p.button = POINTER_BUTTON_LEFT; | |
| if (GLFW_PRESS == action) { | |
| p.state = POINTER_STATE_DOWN; | |
| table.onMouseDown(mx, my, bt); | |
| cam.onMouseDown(mx, my); | |
| } | |
| else if (GLFW_RELEASE == action) { | |
| p.state = POINTER_STATE_UP; | |
| table.onMouseUp(bt); | |
| cam.onMouseUp(); | |
| } | |
| } | |
| void error_callback(int err, const char* desc) { | |
| printf("GLFW error: %s (%d)\n", desc, err); | |
| } | |
| /* -------------------------------------------------------------------- */ | |
| void Cam::init(const vec3& p, const vec3& t, const vec3& u, float winWidth, float winHeight) { | |
| win_width = winWidth; | |
| win_height = winHeight; | |
| dir = t - p; | |
| pos = p; | |
| target = t; | |
| up = u; | |
| pm.perspective(60.0f, win_w / win_h, 0.1f, 100.0f); | |
| } | |
| void Cam::update() { | |
| lm.lookat(target - (dir * zoom), target, up); | |
| mat4 inv = lm; | |
| inv.invert(); | |
| mat4 trans; | |
| trans.translate(pan.x, pan.y, 0.0); | |
| mat4 rot; | |
| rot.rotateY(yaw); | |
| rot.rotateX(pitch); | |
| vm = lm * rot; | |
| /* experiment for panning */ | |
| screen_to_world = pm * vm; | |
| screen_to_world.invert(); | |
| } | |
| void Cam::onMouseDown(float x, float y) { | |
| mouse_down_pos = screenToWorld(x, y); | |
| is_down = true; | |
| } | |
| void Cam::onMouseMove(float x, float y) { | |
| if (false == is_down) { | |
| return; | |
| } | |
| } | |
| void Cam::onMouseUp() { | |
| is_down = false; | |
| } | |
| vec4 Cam::screenToWorld(float x, float y) { | |
| float nx = 2.0 * x / win_width - 1.0; | |
| float ny = -2.0 * y / win_height + 1.0; | |
| vec4 world_pos(x, y, 0.0f, 1.0f); | |
| return screen_to_world * world_pos; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment