#include #include #include #define GLEW_STATIC #include #include #include #include #include #include #include "utilities.h" const float pi = 3.14159f; 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() noexcept(false) { setUp(); auto shaderProgram = linkShaderProgram({ {GL_VERTEX_SHADER, "../resources/shader.vertex"}, {GL_FRAGMENT_SHADER, "../resources/shader.fragment"} }); auto planeTexture = loadTexture("../resources/wooden-container.jpg"); GLfloat planeVertices[] = { // position, normal, texture coordinates, color -2048.0f, -2048.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 2048.0f, -2048.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 2048.0f, 2048.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 2048.0f, 2048.0f, 0.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, 1.0f, -2048.0f, 2048.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 1.0f, 1.0f, 1.0f, 1.0f, -2048.0f, -2048.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 1.0f, 1.0f, 1.0f }; GLuint planeVAO; glGenVertexArrays(1, &planeVAO); GLuint planeVBO; glGenBuffers(1, &planeVBO); glBindVertexArray(planeVAO); glBindBuffer(GL_ARRAY_BUFFER, planeVBO); glBufferData(GL_ARRAY_BUFFER, sizeof(planeVertices), planeVertices, 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); // threads auto threadTexture = loadTexture("../resources/fabric.jpg"); setWindowTitle("parsing lines.json"); boost::property_tree::ptree root; boost::property_tree::read_json("../resources/line.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; setWindowTitle(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::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, 100.0f)); glEnable(GL_DEPTH_TEST); // glPolygonMode(GL_FRONT_AND_BACK, GL_LINE); renderCycle([ shaderProgram, planeTexture, planeVAO, threadTexture, threadModelTransform, threadVAO, verticesBuffer ] () { glClearColor(0.5f, 0.5f, 1.0f, 1.0f); glClear(GL_DEPTH_BUFFER_BIT | GL_COLOR_BUFFER_BIT); glUseProgram(shaderProgram); glUniformMatrix4fv(0, 1, GL_FALSE, glm::value_ptr(glm::mat4(1.0f))); glUniformMatrix4fv(1, 1, GL_FALSE, glm::value_ptr(getViewTransform())); glUniformMatrix4fv(2, 1, GL_FALSE, glm::value_ptr(getProjectionTransform())); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, planeTexture); glUniform1i(3, 0); glBindVertexArray(planeVAO); glDrawArrays(GL_TRIANGLES, 0, 6); glBindVertexArray(0); glActiveTexture(GL_TEXTURE0); glBindTexture(GL_TEXTURE_2D, threadTexture); glUniform1i(3, 0); glUniformMatrix4fv(0, 1, GL_FALSE, glm::value_ptr(threadModelTransform)); glBindVertexArray(threadVAO); glDrawArrays(GL_TRIANGLES, 0, verticesBuffer.size()); glBindVertexArray(0); }); tearDown(); return 0; }