From 4d7dfc763dfbe93dd5836daa9812d383b8fa81e5 Mon Sep 17 00:00:00 2001 From: pointer-to-bios Date: Mon, 29 Apr 2024 14:00:58 +0800 Subject: [PATCH] Run ui as thread, add world simulator, currently has one trunk. --- CMakeLists.txt | 4 +- inc/ui.h | 10 + inc/{ => ui}/camera.h | 18 +- inc/{ => ui}/cube_model.h | 37 ++-- inc/{ => ui}/native.h | 0 inc/{ => ui}/shader_m.h | 0 inc/{ => ui}/stb_image.h | 0 inc/world.h | 20 ++ inc/world/block.h | 49 +++++ inc/world/trunk.h | 44 ++++ src/main.cpp | 451 ++------------------------------------ src/ui.cpp | 422 +++++++++++++++++++++++++++++++++++ src/world.cpp | 44 ++++ 13 files changed, 646 insertions(+), 453 deletions(-) create mode 100644 inc/ui.h rename inc/{ => ui}/camera.h (92%) rename inc/{ => ui}/cube_model.h (80%) rename inc/{ => ui}/native.h (100%) rename inc/{ => ui}/shader_m.h (100%) rename inc/{ => ui}/stb_image.h (100%) create mode 100644 inc/world.h create mode 100644 inc/world/block.h create mode 100644 inc/world/trunk.h create mode 100644 src/ui.cpp create mode 100644 src/world.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt index c45bc59..83b49e6 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -13,7 +13,7 @@ add_subdirectory(./deps/glm) ##test target## -add_executable(jungle ./src/main.cpp ./deps/glad/src/glad.c) +add_executable(jungle ./src/main.cpp ./src/ui.cpp ./src/world.cpp ./deps/glad/src/glad.c) target_include_directories(jungle PRIVATE ./inc/) #glfw dep add_dependencies(jungle glfw) @@ -26,4 +26,4 @@ target_link_libraries(jungle Bullet3Common) #glm dep add_dependencies(jungle glm) target_include_directories(jungle PRIVATE ./deps/glm/) -target_link_libraries(jungle glm) \ No newline at end of file +target_link_libraries(jungle glm) diff --git a/inc/ui.h b/inc/ui.h new file mode 100644 index 0000000..e6817e0 --- /dev/null +++ b/inc/ui.h @@ -0,0 +1,10 @@ +#ifndef UI_H +#define UI_H + +#include "world.h" + +int player_ui( + std::vector &require_pipe, std::mutex &require_pipe_lock, + std::vector>> &blocks_pipe, std::mutex &blocks_pipe_lock); + +#endif diff --git a/inc/camera.h b/inc/ui/camera.h similarity index 92% rename from inc/camera.h rename to inc/ui/camera.h index ca2b696..47954c2 100644 --- a/inc/camera.h +++ b/inc/ui/camera.h @@ -21,7 +21,7 @@ const float YAW = -90.0f; const float PITCH = 0.0f; const float SPEED = 4.5f; const float SENSITIVITY = 0.1f; -const float ZOOM = 45.0f; +const float ZOOM = 95.0f; // An abstract camera class that processes input and calculates the corresponding Euler Angles, Vectors and Matrices for use in OpenGL class Camera @@ -71,9 +71,15 @@ public: { float velocity = MovementSpeed * deltaTime; if (direction == FORWARD) - Position += Front * velocity; + { + Position.x += Front.x * velocity; + Position.z += Front.z * velocity; + } if (direction == BACKWARD) - Position -= Front * velocity; + { + Position.x -= Front.x * velocity; + Position.z -= Front.z * velocity; + } if (direction == LEFT) Position -= Right * velocity; if (direction == RIGHT) @@ -111,10 +117,10 @@ public: void ProcessMouseScroll(float yoffset) { Zoom -= (float)yoffset; - if (Zoom < 1.0f) - Zoom = 1.0f; - if (Zoom > 45.0f) + if (Zoom < 45.0f) Zoom = 45.0f; + if (Zoom > ZOOM) + Zoom = ZOOM; } private: diff --git a/inc/cube_model.h b/inc/ui/cube_model.h similarity index 80% rename from inc/cube_model.h rename to inc/ui/cube_model.h index e5f637c..db2a2c8 100644 --- a/inc/cube_model.h +++ b/inc/ui/cube_model.h @@ -56,25 +56,26 @@ float vertices[] = { // world space positions of our cubes glm::ivec3 cubePositions[] = { glm::ivec3(0, 0, 0), - glm::ivec3(2, 5, -15), - glm::ivec3(-1, -2, -2), - glm::ivec3(-3, -2, -12), - glm::ivec3(2, -0, -3), - glm::ivec3(-1, 3, -7), - glm::ivec3(1, -2, -2), - glm::ivec3(1, 2, -2), - glm::ivec3(1, 0, -1), - glm::ivec3(-1, 1, -1)}; + glm::ivec3(0, 0, 1), + glm::ivec3(0, 0, 2), + glm::ivec3(0, 0, 3), + glm::ivec3(0, 0, 4), + + glm::ivec3(0, 0, 5), + glm::ivec3(0, 0, 6), + glm::ivec3(0, 0, 7), + glm::ivec3(0, 0, 8), + glm::ivec3(0, 0, 9)}; glm::ivec2 cubeTextures[] = { - glm::ivec2(1, 14), - glm::ivec2(8, 3), - glm::ivec2(0, 4), glm::ivec2(1, 12), - glm::ivec2(1, 6), + glm::ivec2(1, 11), + glm::ivec2(1, 10), + glm::ivec2(1, 9), + glm::ivec2(1, 8), - glm::ivec2(0, 6), - glm::ivec2(1, 2), - glm::ivec2(0, 14), - glm::ivec2(3, 12), - glm::ivec2(1, 12)}; \ No newline at end of file + glm::ivec2(1, 7), + glm::ivec2(1, 6), + glm::ivec2(1, 5), + glm::ivec2(1, 4), + glm::ivec2(1, 0)}; \ No newline at end of file diff --git a/inc/native.h b/inc/ui/native.h similarity index 100% rename from inc/native.h rename to inc/ui/native.h diff --git a/inc/shader_m.h b/inc/ui/shader_m.h similarity index 100% rename from inc/shader_m.h rename to inc/ui/shader_m.h diff --git a/inc/stb_image.h b/inc/ui/stb_image.h similarity index 100% rename from inc/stb_image.h rename to inc/ui/stb_image.h diff --git a/inc/world.h b/inc/world.h new file mode 100644 index 0000000..9678204 --- /dev/null +++ b/inc/world.h @@ -0,0 +1,20 @@ +#ifndef WORLD_H +#define WORLD_H + +#include "world/trunk.h" +#include "world/block.h" +#include +#include + +enum WorldRequire +{ + NoneReq, + BlockReq, + ExitReq, +}; + + +void world_simulator(std::vector &require_pipe, std::mutex &require_pipe_lock, + std::vector>> &blocks_pipe, std::mutex &blocks_pipe_lock); + +#endif diff --git a/inc/world/block.h b/inc/world/block.h new file mode 100644 index 0000000..2c20e41 --- /dev/null +++ b/inc/world/block.h @@ -0,0 +1,49 @@ +#ifndef BLOCK_H +#define BLOCK_H + +#include +#include + +enum BlockType +{ + Air, + Soil, + Grass, +}; + +enum BlockFacing +{ + FacingNone, + Xpos, + Xneg, + Ypos, + Yneg, + Zpos, + Zneg, +}; + +class Block +{ +public: + Block(BlockType type = BlockType::Air, BlockFacing facing = BlockFacing::FacingNone) : type(type), facing(facing) {} + + void set_type(BlockType type) + { + this->type = type; + } + + BlockType get_type() + { + return this->type; + } + +private: + BlockType type; + BlockFacing facing; +}; + +#ifndef WORLD +extern std::map block_type_texture_table; +#endif + +#endif diff --git a/inc/world/trunk.h b/inc/world/trunk.h new file mode 100644 index 0000000..9351cd9 --- /dev/null +++ b/inc/world/trunk.h @@ -0,0 +1,44 @@ +#ifndef TRUNK_H +#define TRUNK_H + +#include +#include +#include + +#include "world/block.h" + +const int TrunkSizeX = 32; +const int TrunkSizeY = 512; +const int TrunkSizeZ = 32; + +class Trunk +{ +public: + Trunk() + { + for (int i = 0; i < TrunkSizeX; i++) + for (int j = 0; j < 61; j++) + for (int k = 0; k < TrunkSizeZ; k++) + if (j < 60) + blocks[i][j][k].set_type(BlockType::Soil); + else + blocks[i][j][k].set_type(BlockType::Grass); + } + + std::vector> &getBlockList() + { + static std::vector> res; + res.clear(); + for (int i = 0; i < TrunkSizeX; i++) + for (int j = 0; j < TrunkSizeY; j++) + for (int k = 0; k < TrunkSizeZ; k++) + if (blocks[i][j][k].get_type() != BlockType::Air) + res.push_back(std::tuple({i, j, k}, blocks[i][j][k])); + return res; + } + +private: + Block blocks[TrunkSizeX][TrunkSizeY][TrunkSizeZ]; +}; + +#endif diff --git a/src/main.cpp b/src/main.cpp index 51b43d1..e8777c5 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,437 +1,34 @@ -#include -#include -#define STB_IMAGE_IMPLEMENTATION -#include "stb_image.h" - -#include -#include -#include - -#include "shader_m.h" -#include "camera.h" -#include "cube_model.h" -#include "native.h" - +#include +#include #include -#include - -#ifdef __GNUC__ -// #include -// #include -#endif - -#ifdef _MSC_VER - -#endif - -#ifdef __linux__ - -#endif -#ifdef _WIN32 - -#endif - -void framebuffer_size_callback(GLFWwindow *window, int width, int height); -void mouse_callback(GLFWwindow *window, double xpos, double ypos); -void scroll_callback(GLFWwindow *window, double xoffset, double yoffset); -void focus_callback(GLFWwindow *window, int focused); -void processInput(GLFWwindow *window); - -void glfwDump(GLFWwindow *window); - -bool running = true; -bool pausing = false; -bool just_dispaused = false; - -// settings -const unsigned int SCR_WIDTH = 854; -const unsigned int SCR_HEIGHT = 480; - -// camera -Camera camera(glm::vec3(0.0f, 0.0f, 3.0f)); -float lastX = SCR_WIDTH / 2.0f; -float lastY = SCR_HEIGHT / 2.0f; -bool firstMouse = true; - -// timing -volatile double deltaTime = 0; // time between current frame and last frame -volatile double lastFrame = 0; -volatile double timer = 0; -volatile double currentFrame = 0; - -// focuse controlling -bool window_focused = false; - -// window managing -int curr_width; -int curr_height; -int curr_x; -int curr_y; - -// monitors controlling -// int monitor_count; -// GLFWmonitor **monitors; - -GLFWimage icon; +#include +#include "ui.h" +#include "world.h" int main() { -#ifdef __linux__ - nativeSetIcon(); -#endif + std::vector require_pipe; + std::mutex require_pipe_lock; + std::vector>> blocks_pipe; + std::mutex blocks_pipe_lock; - // std::cout << "debug"; - // glfw: initialize and configure - // ------------------------------ - glfwInit(); - glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); - glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); - glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); - glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE); - glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); - -#ifdef __APPLE__ - glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); -#endif - - // glfw window creation - // -------------------- - GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Jungle", NULL, NULL); - if (window == NULL) - { - std::cout << "Failed to create GLFW window" << std::endl; - glfwTerminate(); - return -1; - } - - // monitors = glfwGetMonitors(&monitor_count); - - // pthread_t thr_getting_fps; - // pthread_create(&thr_getting_fps, nullptr, getting_fps, window); - - glfwMakeContextCurrent(window); - glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); - glfwSetCursorPosCallback(window, mouse_callback); - glfwSetScrollCallback(window, scroll_callback); - glfwSetWindowFocusCallback(window, focus_callback); - - // tell GLFW to capture our mouse - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - - // glad: load all OpenGL function pointers - // --------------------------------------- - if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) - { - std::cout << "Failed to initialize GLAD" << std::endl; - return -1; - } - - icon.pixels = stbi_load("./icon.png", &icon.width, &icon.height, 0, STBI_rgb_alpha); - glfwSetWindowIcon(window, 1, &icon); - - // configure global opengl state - // ----------------------------- - // glEnable(GL_DEPTH_TEST); - - // build and compile our shader zprogram - // ------------------------------------ - Shader ourShader("demo.vs", "demo.fs"); - - unsigned int VBO, VAO; - glGenVertexArrays(1, &VAO); - glGenBuffers(1, &VBO); - - glBindVertexArray(VAO); - - glBindBuffer(GL_ARRAY_BUFFER, VBO); - glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); - - // position attribute - glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0); - glEnableVertexAttribArray(0); - // texture coord attribute - glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float))); - glEnableVertexAttribArray(1); - - //////////////////////////////////////////////////////////////////////////////////// - // load and create a texture - // ------------------------- - unsigned int texture1; //, texture2; - // texture 1 - // --------- - glGenTextures(1, &texture1); - glBindTexture(GL_TEXTURE_2D, texture1); - // set the texture wrapping parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); - // set texture filtering parameters - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - // load image, create texture and generate mipmaps - int width, height, nrChannels; - stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. - unsigned char *data = stbi_load("./terrain.png", &width, &height, &nrChannels, STBI_rgb_alpha); - if (data) - { - glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); - glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); - // glGenerateMipmap(GL_TEXTURE_2D); - } - else - { - std::cout << "Failed to load texture" << std::endl; - } - stbi_image_free(data); - - // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) - // ------------------------------------------------------------------------------------------- - ourShader.use(); - ourShader.setInt("texture1", 0); - // ourShader.setInt("texture2", 1); - - // bind textures on corresponding texture units - glActiveTexture(GL_TEXTURE0); - glBindTexture(GL_TEXTURE_2D, texture1); - // glActiveTexture(GL_TEXTURE1); - // glBindTexture(GL_TEXTURE_2D, texture2); - - glEnable(GL_DEPTH_TEST); - glDepthFunc(GL_LESS); - - glfwDump(window); - - // glfwSetCursorPos(window, curr_x + curr_width / 2, curr_y + curr_height / 2); - // render loop - // ----------- - while (!glfwWindowShouldClose(window)) - { - // per-frame time logic - // -------------------- - currentFrame = glfwGetTime(); - deltaTime = currentFrame - lastFrame; - lastFrame = currentFrame; - - // input - // ----- - processInput(window); - - // render - // ------ - glClearColor(0.2f, 0.3f, 0.3f, 1.0f); - glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); - - // activate shader - ourShader.use(); - - // pass projection matrix to shader (note that in this case it could change every frame) - glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), (float)SCR_WIDTH / (float)SCR_HEIGHT, 0.1f, 100.0f); - ourShader.setMat4("projection", projection); - - // camera/view transformation - glm::mat4 view = camera.GetViewMatrix(); - ourShader.setMat4("view", view); - - // glEnable(GL_DEPTH_TEST); - - // glDepthMask(GL_TRUE); - // render opaque objects first - glBindVertexArray(VAO); - - for (unsigned int i = 0; i < 10; i++) + // 启动ui渲染线程 + std::promise ui_prom; + std::future ui_future = ui_prom.get_future(); + std::thread ui( + [&ui_prom, &require_pipe, &require_pipe_lock, &blocks_pipe, &blocks_pipe_lock]() { - ourShader.setIVec2("index", cubeTextures[i]); + int res = player_ui(require_pipe, require_pipe_lock, blocks_pipe, blocks_pipe_lock); + ui_prom.set_value(res); }); - // calculate the model matrix for each object and pass it to shader before drawing - glm::mat4 model = glm::mat4(1.0f); // make sure to initialize matrix to identity matrix first - model = glm::translate(model, glm::vec3(cubePositions[i])); - ourShader.setMat4("model", model); - glDrawArrays(GL_TRIANGLES, 0, 36); - } - // glDepthMask(GL_FALSE); - - // render transparent objects with blending enabled - - // glDisable(GL_DEPTH_TEST); - // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) - // ------------------------------------------------------------------------------- - glfwSwapBuffers(window); - glfwPollEvents(); - - timer += deltaTime; - if (timer > 0.3f) + // 启动世界模拟器线程 + std::thread world_sim( + [&require_pipe, &require_pipe_lock, &blocks_pipe, &blocks_pipe_lock]() { - glfwSetWindowTitle(window, ("fps:" + std::to_string(int(1.0f / deltaTime)) + " X:" + std::to_string(camera.Position.x) + " Y:" + std::to_string(camera.Position.y) + " Z:" + std::to_string(camera.Position.z)).c_str()); - timer -= 0.3f; - } + world_simulator(require_pipe, require_pipe_lock, blocks_pipe, blocks_pipe_lock); + }); - // double renderTime = glfwGetTime() - lastFrame; - // delay_fps(fps, (int)(renderTime * 1000 * 1000)); - } - - running = false; - - glDisable(GL_DEPTH_TEST); - - // optional: de-allocate all resources once they've outlived their purpose: - // ------------------------------------------------------------------------ - glDeleteVertexArrays(1, &VAO); - glDeleteBuffers(1, &VBO); - - // glfw: terminate, clearing all previously allocated GLFW resources. - // ------------------------------------------------------------------ - glfwTerminate(); - return 0; + ui.join(); + world_sim.join(); + return ui_future.get(); } - -// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly -// --------------------------------------------------------------------------------------------------------- -bool ESC_KEY_PRESSED = false; -void processInput(GLFWwindow *window) -{ - int esc_key_evetype = glfwGetKey(window, GLFW_KEY_ESCAPE); - if (!ESC_KEY_PRESSED && esc_key_evetype == GLFW_PRESS) - { - ESC_KEY_PRESSED = true; - pausing = !pausing; - if (!pausing) - just_dispaused = true; - if (!pausing) - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); - else - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - } - else if (esc_key_evetype == GLFW_RELEASE) - { - ESC_KEY_PRESSED = false; - } - - if (pausing) - return; - - if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) - camera.ProcessKeyboard(FORWARD, deltaTime); - if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) - camera.ProcessKeyboard(BACKWARD, deltaTime); - if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) - camera.ProcessKeyboard(LEFT, deltaTime); - if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) - camera.ProcessKeyboard(RIGHT, deltaTime); - - if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) - camera.ProcessKeyboard(UP, deltaTime); - if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) - camera.ProcessKeyboard(DOWN, deltaTime); -} - -// glfw: whenever the window size changed (by OS or user resize) this callback function executes -// --------------------------------------------------------------------------------------------- -void framebuffer_size_callback(GLFWwindow *window, int width, int height) -{ - // make sure the viewport matches the new window dimensions; note that width and - // height will be significantly larger than specified on retina displays. - curr_width = width; - curr_height = height; - if ((double)width / height > (double)SCR_WIDTH / SCR_HEIGHT) - { // When profiled screen size rate less than new size - int vpwidth = width; - int vpheight = width * SCR_HEIGHT / SCR_WIDTH; - glViewport(0, -(vpheight - height) / 2, vpwidth, vpheight); - } - else - { // or more than - int vpheight = height; - int vpwidth = height * SCR_WIDTH / SCR_HEIGHT; - glViewport(-(vpwidth - width) / 2, 0, vpwidth, vpheight); - } -} - -// glfw: whenever the mouse moves, this callback is called -// ------------------------------------------------------- -void mouse_callback(GLFWwindow *window, double xposIn, double yposIn) -{ - if (pausing) - return; - - float xpos = static_cast(xposIn); - float ypos = static_cast(yposIn); - - if (just_dispaused) - { - lastX = xpos; - lastY = ypos; - just_dispaused = false; - } - - if (firstMouse) - { - lastX = xpos; - lastY = ypos; - firstMouse = false; - } - - float xoffset = xpos - lastX; - float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top - - lastX = xpos; - lastY = ypos; - - camera.ProcessMouseMovement(xoffset, yoffset); -} - -// glfw: whenever the mouse scroll wheel scrolls, this callback is called -// ---------------------------------------------------------------------- -void scroll_callback(GLFWwindow *window, double xoffset, double yoffset) -{ - camera.ProcessMouseScroll(static_cast(yoffset)); -} - -void focus_callback(GLFWwindow *window, int focused) -{ - if (focused) - { - window_focused = true; - } - else - { - window_focused = false; - pausing = true; - glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); - } -} - -void glfwDump(GLFWwindow *window) -{ - int clientAPI = glfwGetWindowAttrib(window, GLFW_CLIENT_API); - int contextAPI = glfwGetWindowAttrib(window, GLFW_CONTEXT_CREATION_API); - int contextVersionMajor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR); - int contextVersionMinor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR); - int profile = glfwGetWindowAttrib(window, GLFW_OPENGL_PROFILE); - int robustness = glfwGetWindowAttrib(window, GLFW_CONTEXT_ROBUSTNESS); - int releaseBehavior = glfwGetWindowAttrib(window, GLFW_CONTEXT_RELEASE_BEHAVIOR); - int forwardCompat = glfwGetWindowAttrib(window, GLFW_OPENGL_FORWARD_COMPAT); - int debugContext = glfwGetWindowAttrib(window, GLFW_OPENGL_DEBUG_CONTEXT); - - int windowSizeWidth, windowSizeHeight; - glfwGetWindowSize(window, &windowSizeWidth, &windowSizeHeight); - int bufferSizeWidth, bufferSizeHeight; - glfwGetFramebufferSize(window, &bufferSizeWidth, &bufferSizeHeight); - float windowScaleX, windowScaleY; - glfwGetWindowContentScale(window, &windowScaleX, &windowScaleY); - - std::cout << "Client API: " << clientAPI << std::endl; - std::cout << "Context API: " << contextAPI << std::endl; - std::cout << "OpenGL version: " << contextVersionMajor << "." << contextVersionMinor << std::endl; - std::cout << "OpenGL profile: " << profile << std::endl; - std::cout << "Robustness: " << robustness << std::endl; - std::cout << "Release behavior: " << releaseBehavior << std::endl; - std::cout << "Forward compatibility: " << forwardCompat << std::endl; - std::cout << "Debug context: " << debugContext << std::endl; - - std::cout << "Window size: " - << " width-" << windowSizeWidth << " height-" << windowSizeHeight << std::endl; - std::cout << "FrameBuffer size: " - << " width-" << bufferSizeWidth << " height-" << bufferSizeHeight << std::endl; - std::cout << "Window Scale: " - << " X-" << bufferSizeWidth << " Y-" << bufferSizeHeight << std::endl; -} \ No newline at end of file diff --git a/src/ui.cpp b/src/ui.cpp new file mode 100644 index 0000000..a1d5f78 --- /dev/null +++ b/src/ui.cpp @@ -0,0 +1,422 @@ +#include +#include +#define STB_IMAGE_IMPLEMENTATION +#include "ui/stb_image.h" + +#include +#include +#include + +#include "ui/shader_m.h" +#include "ui/camera.h" +#include "ui/cube_model.h" +#include "ui/native.h" + +#define UI +#include "world.h" + +#include +#include + +void framebuffer_size_callback(GLFWwindow *window, int width, int height); +void mouse_callback(GLFWwindow *window, double xpos, double ypos); +void scroll_callback(GLFWwindow *window, double xoffset, double yoffset); +void focus_callback(GLFWwindow *window, int focused); +void processInput(GLFWwindow *window); + +void glfwDump(GLFWwindow *window); + +bool running = true; +bool pausing = true; +bool just_dispaused = false; + +// settings +const unsigned int SCR_WIDTH = 1920; +const unsigned int SCR_HEIGHT = 1080; + +// camera +Camera camera(glm::vec3(0.0f, 63.0f, 0.0f)); +float lastX = SCR_WIDTH / 2.0f; +float lastY = SCR_HEIGHT / 2.0f; +bool firstMouse = true; + +// timing +volatile double deltaTime = 0; // time between current frame and last frame +volatile double lastFrame = 0; +volatile double timer = 0; +volatile double currentFrame = 0; + +// focuse controlling +bool window_focused = false; + +// window managing +int curr_width; +int curr_height; +int curr_x; +int curr_y; + +GLFWimage icon; + +int player_ui( + std::vector &require_pipe, std::mutex &require_pipe_lock, + std::vector>> &blocks_pipe, std::mutex &blocks_pipe_lock) +{ +#ifdef __linux__ + nativeSetIcon(); +#endif + + // std::cout << "debug"; + // glfw: initialize and configure + // ------------------------------ + glfwInit(); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + glfwWindowHint(GLFW_SCALE_TO_MONITOR, GLFW_FALSE); + glfwWindowHint(GLFW_SCALE_FRAMEBUFFER, GLFW_FALSE); + +#ifdef __APPLE__ + glfwWindowHint(GLFW_OPENGL_FORWARD_COMPAT, GL_TRUE); +#endif + + // glfw window creation + // -------------------- + GLFWwindow *window = glfwCreateWindow(SCR_WIDTH, SCR_HEIGHT, "Jungle", NULL, NULL); + if (window == NULL) + { + std::cout << "Failed to create GLFW window" << std::endl; + glfwTerminate(); + return -1; + } + + glfwMakeContextCurrent(window); + glfwSetFramebufferSizeCallback(window, framebuffer_size_callback); + glfwSetCursorPosCallback(window, mouse_callback); + glfwSetScrollCallback(window, scroll_callback); + glfwSetWindowFocusCallback(window, focus_callback); + + // glad: load all OpenGL function pointers + // --------------------------------------- + if (!gladLoadGLLoader((GLADloadproc)glfwGetProcAddress)) + { + std::cout << "Failed to initialize GLAD" << std::endl; + return -1; + } + + icon.pixels = stbi_load("./icon.png", &icon.width, &icon.height, 0, STBI_rgb_alpha); + glfwSetWindowIcon(window, 1, &icon); + + // configure global opengl state + // ----------------------------- + // glEnable(GL_DEPTH_TEST); + + // build and compile our shader zprogram + // ------------------------------------ + Shader ourShader("demo.vs", "demo.fs"); + + unsigned int VBO, VAO; + glGenVertexArrays(1, &VAO); + glGenBuffers(1, &VBO); + + glBindVertexArray(VAO); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); + + // position attribute + glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)0); + glEnableVertexAttribArray(0); + // texture coord attribute + glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(float), (void *)(3 * sizeof(float))); + glEnableVertexAttribArray(1); + + //////////////////////////////////////////////////////////////////////////////////// + // load and create a texture + // ------------------------- + unsigned int texture1; //, texture2; + // texture 1 + // --------- + glGenTextures(1, &texture1); + glBindTexture(GL_TEXTURE_2D, texture1); + // set the texture wrapping parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT); + // set texture filtering parameters + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); + // load image, create texture and generate mipmaps + int width, height, nrChannels; + stbi_set_flip_vertically_on_load(true); // tell stb_image.h to flip loaded texture's on the y-axis. + unsigned char *data = stbi_load("./terrain.png", &width, &height, &nrChannels, STBI_rgb_alpha); + if (data) + { + glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, data); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST); + glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST); + // glGenerateMipmap(GL_TEXTURE_2D); + } + else + { + std::cout << "Failed to load texture" << std::endl; + } + stbi_image_free(data); + + // tell opengl for each sampler to which texture unit it belongs to (only has to be done once) + // ------------------------------------------------------------------------------------------- + ourShader.use(); + ourShader.setInt("texture1", 0); + + // bind textures on corresponding texture units + glActiveTexture(GL_TEXTURE0); + glBindTexture(GL_TEXTURE_2D, texture1); + + glEnable(GL_DEPTH_TEST); + glDepthFunc(GL_LESS); + + glfwDump(window); + + framebuffer_size_callback(window, SCR_WIDTH, SCR_HEIGHT); + + // glfwSetCursorPos(window, curr_x + curr_width / 2, curr_y + curr_height / 2); + // render loop + // ----------- + while (!glfwWindowShouldClose(window)) + { + // per-frame time logic + // -------------------- + currentFrame = glfwGetTime(); + deltaTime = currentFrame - lastFrame; + lastFrame = currentFrame; + + // input + // ----- + processInput(window); + + // render + // ------ + glClearColor(0.2f, 0.3f, 0.3f, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + // activate shader + ourShader.use(); + + // pass projection matrix to shader (note that in this case it could change every frame) + glm::mat4 projection = glm::perspective(glm::radians(camera.Zoom), 1.0f, 0.1f, 100.0f); + ourShader.setMat4("projection", projection); + + // camera/view transformation + glm::mat4 view = camera.GetViewMatrix(); + ourShader.setMat4("view", view); + + // render opaque objects first + glBindVertexArray(VAO); + + /*for (unsigned int i = 0; i < 10; i++) + { + ourShader.setIVec2("index", cubeTextures[i]); + + // calculate the model matrix for each object and pass it to shader before drawing + glm::mat4 model = glm::mat4(1.0f); // make sure to initialize matrix to identity matrix first + model = glm::translate(model, glm::vec3(cubePositions[i])); + ourShader.setMat4("model", model); + glDrawArrays(GL_TRIANGLES, 0, 36); + }*/ + + require_pipe_lock.lock(); + require_pipe.push_back(WorldRequire::BlockReq); + require_pipe_lock.unlock(); + std::vector> blks; + blocks_pipe_lock.lock(); + if (!blocks_pipe.empty()) + { + blks = blocks_pipe.back(); + blocks_pipe.pop_back(); + } + blocks_pipe_lock.unlock(); + for (auto block : blks) + { + auto loc = std::get<0>(block); + ourShader.setIVec2("index", block_type_texture_table[std::get<1>(block).get_type()]); + glm::mat4 model(1.0f); + model = glm::translate(model, glm::vec3(loc)); + ourShader.setMat4("model", model); + glDrawArrays(GL_TRIANGLES, 0, 36); + } + + // glfw: swap buffers and poll IO events (keys pressed/released, mouse moved etc.) + // ------------------------------------------------------------------------------- + glfwSwapBuffers(window); + glfwPollEvents(); + + timer += deltaTime; + } + + running = false; + require_pipe_lock.lock(); + require_pipe.push_back(WorldRequire::ExitReq); + require_pipe_lock.unlock(); + + glDisable(GL_DEPTH_TEST); + + // optional: de-allocate all resources once they've outlived their purpose: + // ------------------------------------------------------------------------ + glDeleteVertexArrays(1, &VAO); + glDeleteBuffers(1, &VBO); + + // glfw: terminate, clearing all previously allocated GLFW resources. + // ------------------------------------------------------------------ + glfwTerminate(); + return 0; +} + +// process all input: query GLFW whether relevant keys are pressed/released this frame and react accordingly +// --------------------------------------------------------------------------------------------------------- +bool ESC_KEY_PRESSED = false; +void processInput(GLFWwindow *window) +{ + int esc_key_evetype = glfwGetKey(window, GLFW_KEY_ESCAPE); + if (!ESC_KEY_PRESSED && esc_key_evetype == GLFW_PRESS) + { + ESC_KEY_PRESSED = true; + pausing = !pausing; + if (!pausing) + just_dispaused = true; + if (!pausing) + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); + else + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } + else if (esc_key_evetype == GLFW_RELEASE) + { + ESC_KEY_PRESSED = false; + } + + if (pausing) + return; + + if (glfwGetKey(window, GLFW_KEY_W) == GLFW_PRESS) + camera.ProcessKeyboard(FORWARD, deltaTime); + if (glfwGetKey(window, GLFW_KEY_S) == GLFW_PRESS) + camera.ProcessKeyboard(BACKWARD, deltaTime); + if (glfwGetKey(window, GLFW_KEY_A) == GLFW_PRESS) + camera.ProcessKeyboard(LEFT, deltaTime); + if (glfwGetKey(window, GLFW_KEY_D) == GLFW_PRESS) + camera.ProcessKeyboard(RIGHT, deltaTime); + + if (glfwGetKey(window, GLFW_KEY_SPACE) == GLFW_PRESS) + camera.ProcessKeyboard(UP, deltaTime); + if (glfwGetKey(window, GLFW_KEY_LEFT_SHIFT) == GLFW_PRESS) + camera.ProcessKeyboard(DOWN, deltaTime); +} + +// glfw: whenever the window size changed (by OS or user resize) this callback function executes +// --------------------------------------------------------------------------------------------- +void framebuffer_size_callback(GLFWwindow *window, int width, int height) +{ + // make sure the viewport matches the new window dimensions; note that width and + // height will be significantly larger than specified on retina displays. + curr_width = width; + curr_height = height; + if (width > height) + { // When profiled screen size rate less than new size + int vpwidth = width; + int vpheight = width; + glViewport(0, -(vpheight - height) / 2, vpwidth, vpheight); + } + else + { // or more than + int vpheight = height; + int vpwidth = height; + glViewport(-(vpwidth - width) / 2, 0, vpwidth, vpheight); + } +} + +// glfw: whenever the mouse moves, this callback is called +// ------------------------------------------------------- +void mouse_callback(GLFWwindow *window, double xposIn, double yposIn) +{ + if (pausing) + return; + + float xpos = static_cast(xposIn); + float ypos = static_cast(yposIn); + + if (just_dispaused) + { + lastX = xpos; + lastY = ypos; + just_dispaused = false; + } + + if (firstMouse) + { + lastX = xpos; + lastY = ypos; + firstMouse = false; + } + + float xoffset = xpos - lastX; + float yoffset = lastY - ypos; // reversed since y-coordinates go from bottom to top + + lastX = xpos; + lastY = ypos; + + camera.ProcessMouseMovement(xoffset, yoffset); +} + +// glfw: whenever the mouse scroll wheel scrolls, this callback is called +// ---------------------------------------------------------------------- +void scroll_callback(GLFWwindow *window, double xoffset, double yoffset) +{ + camera.ProcessMouseScroll(static_cast(yoffset)); +} + +void focus_callback(GLFWwindow *window, int focused) +{ + if (focused) + { + window_focused = true; + } + else + { + window_focused = false; + pausing = true; + glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_NORMAL); + } +} + +void glfwDump(GLFWwindow *window) +{ + int clientAPI = glfwGetWindowAttrib(window, GLFW_CLIENT_API); + int contextAPI = glfwGetWindowAttrib(window, GLFW_CONTEXT_CREATION_API); + int contextVersionMajor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MAJOR); + int contextVersionMinor = glfwGetWindowAttrib(window, GLFW_CONTEXT_VERSION_MINOR); + int profile = glfwGetWindowAttrib(window, GLFW_OPENGL_PROFILE); + int robustness = glfwGetWindowAttrib(window, GLFW_CONTEXT_ROBUSTNESS); + int releaseBehavior = glfwGetWindowAttrib(window, GLFW_CONTEXT_RELEASE_BEHAVIOR); + int forwardCompat = glfwGetWindowAttrib(window, GLFW_OPENGL_FORWARD_COMPAT); + int debugContext = glfwGetWindowAttrib(window, GLFW_OPENGL_DEBUG_CONTEXT); + + int windowSizeWidth, windowSizeHeight; + glfwGetWindowSize(window, &windowSizeWidth, &windowSizeHeight); + int bufferSizeWidth, bufferSizeHeight; + glfwGetFramebufferSize(window, &bufferSizeWidth, &bufferSizeHeight); + float windowScaleX, windowScaleY; + glfwGetWindowContentScale(window, &windowScaleX, &windowScaleY); + + std::cout << "Client API: " << clientAPI << std::endl; + std::cout << "Context API: " << contextAPI << std::endl; + std::cout << "OpenGL version: " << contextVersionMajor << "." << contextVersionMinor << std::endl; + std::cout << "OpenGL profile: " << profile << std::endl; + std::cout << "Robustness: " << robustness << std::endl; + std::cout << "Release behavior: " << releaseBehavior << std::endl; + std::cout << "Forward compatibility: " << forwardCompat << std::endl; + std::cout << "Debug context: " << debugContext << std::endl; + + std::cout << "Window size: " + << " width-" << windowSizeWidth << " height-" << windowSizeHeight << std::endl; + std::cout << "FrameBuffer size: " + << " width-" << bufferSizeWidth << " height-" << bufferSizeHeight << std::endl; + std::cout << "Window Scale: " + << " X-" << bufferSizeWidth << " Y-" << bufferSizeHeight << std::endl; +} \ No newline at end of file diff --git a/src/world.cpp b/src/world.cpp new file mode 100644 index 0000000..de5a505 --- /dev/null +++ b/src/world.cpp @@ -0,0 +1,44 @@ +#define WORLD +#include "world.h" +#include + +std::map block_type_texture_table{ + std::make_pair(BlockType::Soil, glm::ivec2(2, 15)), + std::make_pair(BlockType::Grass, glm::ivec2(3, 15)), +}; + +void world_simulator( + std::vector &require_pipe, std::mutex &require_pipe_lock, + std::vector>> &blocks_pipe, std::mutex &blocks_pipe_lock) +{ + Trunk trunk000; + bool ends = false; + while (true) + { + WorldRequire wreq = WorldRequire::NoneReq; + require_pipe_lock.lock(); + if (!require_pipe.empty()) + { + wreq = require_pipe.back(); + require_pipe.pop_back(); + } + require_pipe_lock.unlock(); + if (wreq == WorldRequire::NoneReq) + continue; + std::vector> *list; + switch (wreq) + { + case BlockReq: + list = &trunk000.getBlockList(); + blocks_pipe_lock.lock(); + blocks_pipe.push_back(*list); + blocks_pipe_lock.unlock(); + break; + case ExitReq: + ends = true; + break; + } + if (ends) + break; + } +}