diff --git a/cmake_modules/VCMI_lib.cmake b/cmake_modules/VCMI_lib.cmake index 39b8044f5..62218f98b 100644 --- a/cmake_modules/VCMI_lib.cmake +++ b/cmake_modules/VCMI_lib.cmake @@ -151,6 +151,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) ${MAIN_LIB_DIR}/rmg/Zone.cpp ${MAIN_LIB_DIR}/rmg/Functions.cpp ${MAIN_LIB_DIR}/rmg/RmgMap.cpp + ${MAIN_LIB_DIR}/rmg/PenroseTiling.cpp ${MAIN_LIB_DIR}/rmg/modificators/Modificator.cpp ${MAIN_LIB_DIR}/rmg/modificators/ObjectManager.cpp ${MAIN_LIB_DIR}/rmg/modificators/ObjectDistributor.cpp @@ -522,6 +523,7 @@ macro(add_main_lib TARGET_NAME LIBRARY_TYPE) ${MAIN_LIB_DIR}/rmg/RmgMap.h ${MAIN_LIB_DIR}/rmg/float3.h ${MAIN_LIB_DIR}/rmg/Functions.h + ${MAIN_LIB_DIR}/rmg/PenroseTiling.h ${MAIN_LIB_DIR}/rmg/modificators/Modificator.h ${MAIN_LIB_DIR}/rmg/modificators/ObjectManager.h ${MAIN_LIB_DIR}/rmg/modificators/ObjectDistributor.h diff --git a/lib/rmg/PenroseTiling.cpp b/lib/rmg/PenroseTiling.cpp new file mode 100644 index 000000000..2af1d7b71 --- /dev/null +++ b/lib/rmg/PenroseTiling.cpp @@ -0,0 +1,227 @@ +/* + * © 2020 Michael Percival + * See LICENSE file for copyright and license details. + */ + +// Adapted from https://github.com/mpizzzle/penrose + +// FIXME: Find library for geometry representation +//https://www.boost.org/doc/libs/1_72_0/libs/geometry/doc/html/geometry/reference/adapted/boost_polygon/point_data.html + +//#include +//#include + +//#include +//#include + +#include "StdInc.h" + +#include +#include +#include +#include + +#include +//https://www.boost.org/doc/libs/1_72_0/libs/geometry/doc/html/geometry/reference/strategies/strategy_transform_rotate_transformer.html + +//#include "shader.hpp" +//#include "png_writer.hpp" + +#include "PenroseTiling.h" + +VCMI_LIB_NAMESPACE_BEGIN + +//static const std::string file_name = "penrose.png"; + +Triangle::Triangle(bool t_123, const TIndices & inds): + tiling(t_123), + indices(inds) +{} + +void PenroseTiling::split(Triangle& p, std::vector& points, + std::array, 5>& indices, uint32_t depth) +{ + uint32_t s = points.size(); + TIndices& i = p.indices; + + const auto p2 = P2; + + if (depth > 0) + { + if (p.tiling ^ !p2) + { + points.push_back(glm::vec2(((1.0f - PHI) * points[i[0]]) + (PHI * points[i[2]]))); + points.push_back(glm::vec2(((1.0f - PHI) * points[i[p2]]) + (PHI * points[i[!p2]]))); + + Triangle t1(p2, TIndices({ i[(!p2) + 1], p2 ? i[2] : s, p2 ? s : i[1] })); + Triangle t2(true, TIndices({ p2 ? i[1] : s, s + 1, p2 ? s : i[1] })); + Triangle t3(false, TIndices({ s, s + 1, i[0] })); + + // FIXME: Make sure these are not destroyed when we leave the scope + p.subTriangles = { &t1, &t2, &t3 }; + } + else + { + points.push_back(glm::vec2(((1.0f - PHI) * points[i[p2 * 2]]) + (PHI * points[i[!p2]]))); + + Triangle t1(true, TIndices({ i[2], s, i[1] })); + Triangle t2(false, TIndices({ i[(!p2) + 1], s, i[0] })); + + p.subTriangles = { &t1, &t2 }; + } + + for (auto& t : p.subTriangles) + { + if (depth == 1) + { + for (uint32_t k = 0; k < 3; ++k) + { + if (k != (t->tiling ^ !p2 ? 2 : 1)) + { + indices[indices.size() - 1].push_back(t->indices[k]); + indices[indices.size() - 1].push_back(t->indices[((k + 1) % 3)]); + } + } + + indices[t->tiling + (p.tiling ? 0 : 2)].insert(indices[t->tiling + (p.tiling ? 0 : 2)].end(), t->indices.begin(), t->indices.end()); + } + + // Split recursively + split(*t, points, indices, depth - 1); + } + } + + return; +} + +// TODO: Return something +void generatePenroseTiling(size_t numZones, CRandomGenerator * rand); +{ + float scale = 100.f / (numZones + 20); //TODO: Use it to initialize the large tile + + //static std::default_random_engine e(std::random_device{}()); + static std::uniform_real_distribution<> d(0, 1); + + /* + std::vector colours = { glm::vec3(d(e), d(e), d(e)), glm::vec3(d(e), d(e), d(e)), + glm::vec3(d(e), d(e), d(e)), glm::vec3(d(e), d(e), d(e)), + glm::vec3(d(e), d(e), d(e)), glm::vec3(d(e), d(e), d(e)) }; + */ + + float polyAngle = glm::radians(360.0f / POLY); + + std::vector points = { glm::vec2(0.0f, 0.0f), glm::vec2(0.0f, 1.0f) }; + std::array, 5> indices; + + for (uint32_t i = 1; i < POLY; ++i) + { + //TODO: Use boost to rotate + glm::vec2 next = glm::rotate(points[i], polyAngle); + points.push_back(next); + } + + // TODO: Scale to unit square + for (auto& p : points) + { + p.x = (p.x / window_w) * window_h; + } + + for (uint32_t i = 0; i < POLY; i++) + { + std::array p = { (i % (POLY + 1)) + 1, ((i + 1) % POLY) + 1 }; + + triangle t(true, TIndices({ 0, p[i & 1], p[!(i & 1)] })); + + split(t, points, indices, DEPTH); + } + + // TODO: Return collection of triangles + // TODO: Get center point of the triangle + + // Do not draw anything + /* + if(!glfwInit()) + { + return -1; + } + + glfwWindowHint(GLFW_SAMPLES, 4); + glfwWindowHint(GLFW_CONTEXT_VERSION_MAJOR, 3); + glfwWindowHint(GLFW_CONTEXT_VERSION_MINOR, 3); + glfwWindowHint(GLFW_OPENGL_PROFILE, GLFW_OPENGL_CORE_PROFILE); + + GLFWwindow* window = glfwCreateWindow(window_w, window_h, "penrose", NULL, NULL); + + if(window == NULL) { + glfwTerminate(); + return -1; + } + + glfwMakeContextCurrent(window); + glewExperimental=true; + + if (glewInit() != GLEW_OK) { + return -1; + } + + glfwSetInputMode(window, GLFW_STICKY_KEYS, GL_TRUE); + + uint32_t VAOs[5], VBO, EBOs[5]; + + glGenVertexArrays(5, VAOs); + glGenBuffers(1, &VBO); + glGenBuffers(5, EBOs); + glLineWidth(line_w); + + for (uint32_t i = 0; i < indices.size(); ++i) { + glBindVertexArray(VAOs[i]); + + glBindBuffer(GL_ARRAY_BUFFER, VBO); + glBufferData(GL_ARRAY_BUFFER, points.size() * 4 * 2, &points[0], GL_STATIC_DRAW); + + glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBOs[i]); + glBufferData(GL_ELEMENT_ARRAY_BUFFER, indices[i].size() * 4, &indices[i][0], GL_STATIC_DRAW); + + glVertexAttribPointer(0, 2, GL_FLOAT, GL_FALSE, 2 * sizeof(float), (void*)0); + glEnableVertexAttribArray(0); + } + + uint32_t programID = Shader::loadShaders("vertex.vert", "fragment.frag"); + GLint paint = glGetUniformLocation(programID, "paint"); + + while (glfwGetKey(window, GLFW_KEY_ESCAPE) != GLFW_PRESS && glfwWindowShouldClose(window) == 0 && paint != -1) { + glViewport(-1.0 * (window_w / scale) * ((0.5 * scale) - 0.5), -1.0 * (window_h / scale) * ((0.5 * scale) - 0.5), window_w, window_h); + glClearColor(colours.back().x, colours.back().y, colours.back().z, 1.0f); + glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT); + + glUseProgram(programID); + glPolygonMode(GL_FRONT_AND_BACK, GL_FILL); + + for (uint32_t i = 0; i < indices.size(); ++i) { + glPolygonMode(GL_FRONT_AND_BACK, i < indices.size() - 1 ? GL_FILL : GL_LINE); + glUniform3fv(paint, 1, &colours[i][0]); + glBindVertexArray(VAOs[i]); + glDrawElements(i < indices.size() - 1 ? GL_TRIANGLES : GL_LINES, indices[i].size(), GL_UNSIGNED_INT, 0); + } + + glfwSwapBuffers(window); + glfwPollEvents(); + } + + int frame_w, frame_h; + glfwGetFramebufferSize(window, &frame_w, &frame_h); + + png_bytep* row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * frame_h); + + for (int y = 0; y < frame_h; ++y) { + row_pointers[y] = (png_byte*) malloc((4 * sizeof(png_byte)) * frame_w); + glReadPixels(0, y, frame_w, 1, GL_RGBA, GL_UNSIGNED_BYTE, row_pointers[y]); + } + + PngWriter::write_png_file(file_name, frame_w, frame_h, row_pointers); + + return 0; + */ +} + +VCMI_LIB_NAMESPACE_END \ No newline at end of file diff --git a/lib/rmg/PenroseTiling.h b/lib/rmg/PenroseTiling.h new file mode 100644 index 000000000..cc3060a8a --- /dev/null +++ b/lib/rmg/PenroseTiling.h @@ -0,0 +1,57 @@ +/* + * PenroseTiling.h, part of VCMI engine + * + * Authors: listed in file AUTHORS in main folder + * + * License: GNU General Public License v2.0 or later + * Full text of license available in license.txt file, in main folder + * + */ + +#pragma once + +#include "../GameConstants.h" +#include "../CRandomGenerator.h" +#include +#include + + +VCMI_LIB_NAMESPACE_BEGIN + +typedef std::array TIndices; + +class Triangle +{ +public: + const bool tiling; + TIndices indices; + + std::vector subTriangles; + + Triangle(bool t_123, const TIndices & inds); +}; + +class PenroseTiling +{ + +public: + const float PHI = 1.0 / ((1.0 + std::sqrt(5.0)) / 2); + // TODO: Is that the number of symmetries? + const uint32_t POLY = 10; + + const float scale = 4.0f; + //const uint32_t window_w = 1920 * scale; + //const uint32_t window_h = 1080 * scale; + const uint32_t DEPTH = 10; //recursion depth + + const bool P2 = false; // Tiling type + //const float line_w = 2.0f; //line width + + void generatePenroseTiling(size_t numZones, CRandomGenerator * rand); + +private: + void split(Triangle& p, std::vector& points, std::array, 5>& indices, uint32_t depth); + +}; + +VCMI_LIB_NAMESPACE_END \ No newline at end of file