#include #include #include #include #include #include #define GLEW_STATIC #include "GL/glew.h" #include "GLFW/glfw3.h" #include "SOIL/SOIL.h" #include "glm/glm.hpp" #include "glm/gtc/matrix_transform.hpp" #include "glm/gtc/type_ptr.hpp" #include "boost/property_tree/ptree.hpp" #include "boost/property_tree/json_parser.hpp" const int windowWidth = 800; const int windowHeight = 600; const float pi = 3.14159f; std::string readFile(const std::string& filePath) { std::ifstream file(filePath); auto result = std::string( std::istreambuf_iterator(file), std::istreambuf_iterator() ); file.close(); return result; } const GLuint loadShader(const GLenum& shaderType, const std::string& shaderFilePath) { const GLuint shader = glCreateShader(shaderType); auto shaderSource = readFile(shaderFilePath); auto shaderSourceC = shaderSource.c_str(); glShaderSource(shader, 1, &shaderSourceC, nullptr); glCompileShader(shader); GLint success; GLchar infoLog[512]; glGetShaderiv(shader, GL_COMPILE_STATUS, &success); if(!success) { glGetShaderInfoLog(shader, 512, nullptr, infoLog); std::cout << "Failed to compile shader: " << infoLog << std::endl; } return shader; } const GLuint linkShaderProgram(const std::initializer_list>& shadersInfo) { const GLuint shaderProgram = glCreateProgram(); for(const auto& shaderInfo: shadersInfo) { auto shader = loadShader(shaderInfo.first, shaderInfo.second); glAttachShader(shaderProgram, shader); glDeleteShader(shader); } glLinkProgram(shaderProgram); { GLint success; GLchar infoLog[512]; glGetProgramiv(shaderProgram, GL_LINK_STATUS, &success); if(!success) { glGetProgramInfoLog(shaderProgram, 512, nullptr, infoLog); std::cout << "Failed to link shader program: " << infoLog << std::endl; } } return shaderProgram; } GLuint loadTexture(const std::string& textureFilePath) { int imageWidth, imageHeight; unsigned char *imageData = SOIL_load_image( textureFilePath.c_str(), &imageWidth, &imageHeight, nullptr, SOIL_LOAD_RGB ); GLuint texture; glGenTextures(1, &texture); glBindTexture(GL_TEXTURE_2D, texture); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, imageWidth, imageHeight, 0, GL_RGB, GL_UNSIGNED_BYTE, imageData); glGenerateMipmap(GL_TEXTURE_2D); glBindTexture(GL_TEXTURE_2D, 0); SOIL_free_image_data(imageData); return texture; } auto cameraPosition = glm::vec3(0.0f, 0.0f, 512.0f); auto cameraFront = glm::vec3(0.0f, 0.0f, -1.0f); auto cameraUp = glm::vec3(0.0f, 1.0f, 0.0f); bool keyPressed[1024]; void keyCallback(GLFWwindow* /* window */, int key, int /* scanCode */, int action, int /* mode */) { if(key == GLFW_KEY_W) { if(action == GLFW_PRESS) { keyPressed[GLFW_KEY_W] = true; } else if(action == GLFW_RELEASE) { keyPressed[GLFW_KEY_W] = false; } } else if(key == GLFW_KEY_S) { if(action == GLFW_PRESS) { keyPressed[GLFW_KEY_S] = true; } else if(action == GLFW_RELEASE) { keyPressed[GLFW_KEY_S] = false; } } else if(key == GLFW_KEY_A) { if(action == GLFW_PRESS) { keyPressed[GLFW_KEY_A] = true; } else if(action == GLFW_RELEASE) { keyPressed[GLFW_KEY_A] = false; } } else if(key == GLFW_KEY_D) { if(action == GLFW_PRESS) { keyPressed[GLFW_KEY_D] = true; } else if(action == GLFW_RELEASE) { keyPressed[GLFW_KEY_D] = false; } } } void moveCamera(double deltaTime) { float cameraSpeed = 1024.0f * static_cast(deltaTime); if(keyPressed[GLFW_KEY_W]) { cameraPosition = cameraPosition + cameraSpeed * cameraFront; } else if(keyPressed[GLFW_KEY_S]) { cameraPosition = cameraPosition - cameraSpeed * cameraFront; } else if(keyPressed[GLFW_KEY_A]) { cameraPosition = cameraPosition - cameraSpeed * glm::normalize(glm::cross(cameraFront, cameraUp)); } else if(keyPressed[GLFW_KEY_D]) { cameraPosition = cameraPosition + cameraSpeed * glm::normalize(glm::cross(cameraFront, cameraUp)); } } float lastX = windowWidth / 2.0f, lastY = windowHeight / 2.0f; float yaw = -90.0f, pitch = 0.0f; bool firstMouse = false; void mouseCallback(GLFWwindow* /* window */, double x, double y) { auto xf = static_cast(x); auto yf = static_cast(y); if(!firstMouse) { lastX = xf; lastY = yf; firstMouse = true; } auto offsetX = xf - lastX, offsetY = lastY - yf; lastX = xf; lastY = yf; float sensivity = 0.05f; offsetX *= sensivity; offsetY *= sensivity; yaw += offsetX; pitch += offsetY; if(pitch > 89.0f) { pitch = 89.0f; } else if(pitch < -89.0f) { pitch = -89.0f; } glm::vec3 newCameraFront; newCameraFront.x = cosf(glm::radians(pitch)) * cosf(glm::radians(yaw)); newCameraFront.y = sinf(glm::radians(pitch)); newCameraFront.z = cosf(glm::radians(pitch)) * sinf(glm::radians(yaw)); cameraFront = glm::normalize(newCameraFront); } const std::pair findPlaneBasis(const glm::vec3& normal) { std::pair result; glm::vec3 e0, e1; if(normal.z != 0.0f) { e0 = glm::normalize(glm::vec3(1.0f, 0.0f, -normal.x / normal.z)); e1 = glm::vec3(0.0f, 1.0f, -normal.y / normal.z); } else if(normal.y != 0.0f) { e0 = glm::normalize(glm::vec3(1.0f, -normal.x / normal.y, 0.0f)); e1 = glm::vec3(0.0f, -normal.z / normal.y, 1.0f); } else { e0 = glm::normalize(glm::vec3(-normal.y / normal.x, 1.0f, 0.0f)); e1 = glm::vec3(-normal.z / normal.x, 0.0f, 1.0f); } e1 = glm::normalize(e1 - (glm::dot(e1, e0) / glm::dot(e0, e0)) * e0); result.first = e0; result.second = e1; return result; } const float radius = 8.0f; const float step = 100.0f; const float angle = pi / 6.0f; const size_t threadsCount = 3; const size_t verticesCount = 6; void bufferVertices( std::vector& verticesBuffer, const glm::vec3& start, const glm::vec3& end, const glm::vec3& color ) { auto direction = glm::normalize(end - start); size_t iterationsCount = glm::length(end - start) / step; if(iterationsCount == 0) { iterationsCount = 1; } auto adjustedStep = glm::length(end - start) / iterationsCount; auto e = findPlaneBasis(direction); std::vector threadCenters; std::vector> threads; for(size_t i = 0; i < threadsCount; i++) { const auto iPhase = i * 2 * pi / threadsCount; const glm::vec3 threadCenter = radius * (e.first * cosf(iPhase) + e.second * sinf(iPhase)); std::vector vertices; for(size_t j = 0; j < verticesCount; j++) { const auto jPhase = j * 2 * pi / verticesCount; const glm::vec3 vertex = threadCenter + radius * (e.first * cosf(jPhase) + e.second * sinf(jPhase)); vertices.emplace_back(glm::vec4(vertex.x, vertex.y, vertex.z, 1.0f)); } threadCenters.emplace_back(threadCenter); threads.emplace_back(vertices); } auto transform = glm::mat4(1.0f); transform = glm::rotate(transform, angle, direction); transform = glm::translate(transform, adjustedStep * direction); auto p = [&verticesBuffer] (const GLfloat& value) mutable {verticesBuffer.push_back(value);}; auto v = [&p] (const glm::vec3& vector) mutable {p(vector.x); p(vector.y); p(vector.z);}; auto st = [&p] (const GLfloat& s, const GLfloat& t) mutable {p(s); p(t);}; auto n = v; auto c = v; for(size_t i = 0; i < iterationsCount; i++) { std::vector> newThreads; for(size_t j = 0; j < threadsCount; j++) { auto vertices = threads[j]; std::vector newVertices; for(size_t k = 0; k < verticesCount; k++) { newVertices.push_back(transform * vertices[k]); } newThreads.push_back(newVertices); auto threadCenter = threadCenters[j]; auto threadCenter4 = glm::vec4(threadCenter.x, threadCenter.y, threadCenter.z, 1.0f); auto newThreadCenter4 = transform * threadCenter4; auto newThreadCenter = glm::vec3(newThreadCenter4.x, newThreadCenter4.y, newThreadCenter4.z); threadCenters[j] = newThreadCenter; for(size_t k = 0; k < verticesCount; k++) { size_t k1 = (k + 1) % verticesCount; auto vk = glm::vec3(vertices[k].x, vertices[k].y, vertices[k].z); auto vk1 = glm::vec3(vertices[k1].x, vertices[k1].y, vertices[k1].z); auto nvk = glm::vec3(newVertices[k].x, newVertices[k].y, newVertices[k].z); auto nvk1 = glm::vec3(newVertices[k1].x, newVertices[k1].y, newVertices[k1].z); v(start + vk); n(vk - threadCenter); st(0.1f, 0.1f); c(color); v(start + vk1); n(vk1 - threadCenter); st(0.2f, 0.1f); c(color); v(start + nvk); n(nvk - newThreadCenter); st(0.1f, 0.2f); c(color); v(start + vk1); n(vk1 - threadCenter); st(0.2f, 0.1f); c(color); v(start + nvk1); n(nvk1 - newThreadCenter); st(0.2f, 0.2f); c(color); v(start + nvk); n(nvk - newThreadCenter); st(0.1f, 0.2f); c(color); } } threads = newThreads; } }; int main() { if(glfwInit() != GLFW_TRUE) { std::cout << "Failed to initialize glfw." << std::endl; return -1; } glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 4); glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 6); glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); glfwWindowHint(GLFW_RESIZABLE, GLFW_FALSE); GLFWwindow* window = glfwCreateWindow(windowWidth, windowHeight, "gl", nullptr, nullptr); if(window == nullptr) { std::cout << "Failed to create window." << std::endl; glfwTerminate(); return -1; } glfwMakeContextCurrent(window); glfwSetKeyCallback(window, keyCallback); glfwSetInputMode(window, GLFW_CURSOR, GLFW_CURSOR_DISABLED); glfwSetCursorPosCallback(window, mouseCallback); glewExperimental = GL_TRUE; if(glewInit() != GLEW_OK) { std::cout << "Failed to initialize glew." << std::endl; glfwTerminate(); return -1; } int frameBufferWidth, frameBufferHeight; glfwGetFramebufferSize(window, &frameBufferWidth, &frameBufferHeight); glViewport(0, 0, frameBufferWidth, frameBufferHeight); auto shaderProgram = linkShaderProgram({ {GL_VERTEX_SHADER, "../resources/shader.vertex"}, {GL_FRAGMENT_SHADER, "../resources/shader.fragment"} }); auto texture = loadTexture("../resources/wooden-container.jpg"); GLfloat vertices[] = { // position, texture coordinates -2048.0f, -2048.0f, 0.0f, 0.0f, 0.0f, 2048.0f, -2048.0f, 0.0f, 1.0f, 0.0f, 2048.0f, 2048.0f, 0.0f, 1.0f, 1.0f, 2048.0f, 2048.0f, 0.0f, 1.0f, 1.0f, -2048.0f, 2048.0f, 0.0f, 0.0f, 1.0f, -2048.0f, -2048.0f, 0.0f, 0.0f, 0.0f }; GLuint vertexArrayObject; glGenVertexArrays(1, &vertexArrayObject); GLuint vertexBufferObject; glGenBuffers(1, &vertexBufferObject); glBindVertexArray(vertexArrayObject); glBindBuffer(GL_ARRAY_BUFFER, vertexBufferObject); glBufferData(GL_ARRAY_BUFFER, sizeof(vertices), vertices, GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(0 * sizeof(GLfloat))); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 2, GL_FLOAT, GL_FALSE, 5 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); glBindVertexArray(0); // threads auto threadShaderProgram = linkShaderProgram({ {GL_VERTEX_SHADER, "../resources/thread.vertex"}, {GL_FRAGMENT_SHADER, "../resources/thread.fragment"} }); auto threadTexture = loadTexture("../resources/fabric.jpg"); boost::property_tree::ptree root; glfwSetWindowTitle(window, "parsing lines.json..."); boost::property_tree::read_json("../resources/lines100500.json", root); size_t linesCount = 0; for(const auto& line: root.get_child("lines")) { linesCount++; } std::vector verticesBuffer; size_t lineIndex = 0; for(const auto& line: root.get_child("lines")) { std::vector startPosition; std::vector endPosition; std::vector color; for(const auto& value: line.second.get_child("start")) { startPosition.push_back(value.second.get_value()); } for(const auto& value: line.second.get_child("end")) { endPosition.push_back(value.second.get_value()); } for(const auto& value: line.second.get_child("color")) { color.push_back(value.second.get_value()); } if(startPosition[0] != endPosition[0] || startPosition[1] != endPosition[1]) { bufferVertices( verticesBuffer, glm::vec3( static_cast(startPosition[0]) / 2.0f, static_cast(startPosition[1]) / 2.0f, lineIndex * 0.0025f ), glm::vec3( static_cast(endPosition[0]) / 2.0f, static_cast(endPosition[1]) / 2.0f, lineIndex * 0.0025f ), glm::vec3(color[0], color[1], color[2]) ); } lineIndex++; std::stringstream progressString; progressString << "loading " << lineIndex << "/" << linesCount; glfwSetWindowTitle(window, progressString.str().c_str()); } GLuint threadVAO; glGenVertexArrays(1, &threadVAO); GLuint threadVBO; glGenBuffers(1, &threadVBO); glBindVertexArray(threadVAO); glBindBuffer(GL_ARRAY_BUFFER, threadVBO); glBufferData(GL_ARRAY_BUFFER, verticesBuffer.size() * sizeof(GLfloat), verticesBuffer.data(), GL_STATIC_DRAW); glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(GLfloat), (GLvoid*)(0 * sizeof(GLfloat))); glEnableVertexAttribArray(0); glVertexAttribPointer(1, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(GLfloat), (GLvoid*)(3 * sizeof(GLfloat))); glEnableVertexAttribArray(1); glVertexAttribPointer(2, 2, GL_FLOAT, GL_FALSE, 11 * sizeof(GLfloat), (GLvoid*)(6 * sizeof(GLfloat))); glEnableVertexAttribArray(2); glVertexAttribPointer(3, 3, GL_FLOAT, GL_FALSE, 11 * sizeof(GLfloat), (GLvoid*)(8 * sizeof(GLfloat))); glEnableVertexAttribArray(3); glBindVertexArray(0); auto threadModelTransform = glm::mat4(1.0f); threadModelTransform = glm::translate(threadModelTransform, glm::vec3(0.0f, 0.0f, 100.0f)); auto projectionTransform = glm::infinitePerspective( glm::radians(45.0f), static_cast(frameBufferWidth) / static_cast(frameBufferHeight), 0.1f ); double lastTime = 0.0f; glEnable(GL_DEPTH_TEST); // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); while(!glfwWindowShouldClose(window)) { glfwPollEvents(); double currentTime = glfwGetTime(); double deltaTime = currentTime - lastTime; lastTime = currentTime; moveCamera(deltaTime); auto viewTransform = glm::lookAt( cameraPosition, cameraPosition + cameraFront, cameraUp ); glfwSetWindowTitle(window, std::to_string(static_cast(1.0 / deltaTime)).c_str()); glClearColor(0.5f, 0.5f, 1.0f, 1.0f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glUseProgram(shaderProgram); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, texture); glUniform1i(glGetUniformLocation(shaderProgram, "sampler"), 0); glUniformMatrix4fv( glGetUniformLocation(shaderProgram, "modelTransform"), 1, GL_FALSE, glm::value_ptr(glm::mat4(1.0f)) ); glUniformMatrix4fv( glGetUniformLocation(shaderProgram, "viewTransform"), 1, GL_FALSE, glm::value_ptr(viewTransform) ); glUniformMatrix4fv( glGetUniformLocation(shaderProgram, "projectionTransform"), 1, GL_FALSE, glm::value_ptr(projectionTransform) ); glBindVertexArray(vertexArrayObject); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); glUseProgram(threadShaderProgram); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, threadTexture); glUniform1i(glGetUniformLocation(threadShaderProgram, "sampler"), 0); glUniformMatrix4fv( glGetUniformLocation(threadShaderProgram, "modelTransform"), 1, GL_FALSE, glm::value_ptr(threadModelTransform) ); glUniformMatrix4fv( glGetUniformLocation(threadShaderProgram, "viewTransform"), 1, GL_FALSE, glm::value_ptr(viewTransform) ); glUniformMatrix4fv( glGetUniformLocation(threadShaderProgram, "projectionTransform"), 1, GL_FALSE, glm::value_ptr(projectionTransform) ); glBindVertexArray(threadVAO); glDrawArrays(GL_TRIANGLES, 0, verticesBuffer.size()); glBindVertexArray(0); glfwSwapBuffers(window); } glfwTerminate(); return 0; }