25 #include <unordered_set>
27 #include <glm/mat4x4.hpp>
29 #include "eng3d/borders.hpp"
30 #include "eng3d/texture.hpp"
31 #include "eng3d/state.hpp"
32 #include "eng3d/curve.hpp"
33 #include "eng3d/shader.hpp"
34 #include "eng3d/camera.hpp"
44 mipmap_options.
wrap_s = Eng3D::TextureOptions::Wrap::REPEAT;
45 mipmap_options.wrap_t = Eng3D::TextureOptions::Wrap::REPEAT;
46 mipmap_options.min_filter = Eng3D::TextureOptions::Filter::LINEAR_MIPMAP;
47 mipmap_options.mag_filter = Eng3D::TextureOptions::Filter::LINEAR;
48 mipmap_options.internal_format = Eng3D::TextureOptions::Format::SRGB;
50 line_shader = std::make_unique<Eng3D::OpenGL::Program>();
52 auto vs_shader = *s.builtin_shaders[
"vs_3d"];
53 line_shader->attach_shader(vs_shader);
55 line_shader->attach_shader(fs_shader);
60 this->build_borders();
64 std::unordered_set<int> walked_positions;
65 std::unordered_set<int> walked_paths;
66 std::stack<int> unexplored_paths;
67 std::stack<int> current_paths;
68 std::vector<std::vector<glm::vec3>>& borders;
69 const uint32_t* pixels;
72 BorderGenerator(std::vector<std::vector<glm::vec3>>& _borders,
const uint32_t* _pixels,
int _width,
int _height)
73 : borders{ _borders },
81 bool check_neighbor(
int new_x,
int new_y) {
82 if(new_x < 0 || new_y < 0 || new_x >= width - 1 || new_y >= height - 1)
84 int new_index = new_x + new_y * width;
85 const auto color_ul = pixels[new_index];
86 const auto color_dl = pixels[new_index + width];
87 const auto color_ur = pixels[new_index + 1];
88 const auto color_dr = pixels[new_index + width + 1];
90 if(color_ul != color_ur || color_ur != color_dr || color_dr != color_dl || color_dl != color_ul)
95 void add_neighbor(
int prev_x,
int prev_y,
int new_x,
int new_y,
int& connections) {
96 if(check_neighbor(new_x, new_y)) {
97 int old_index = prev_x + prev_y * width;
98 int new_index = new_x + new_y * width;
99 int index = 2 * glm::min<int>(old_index, new_index) + std::abs(prev_x - new_x);
100 if(walked_paths.count(index))
return;
101 walked_positions.insert(new_index);
102 if(connections++ > 1) {
103 unexplored_paths.push(old_index);
105 current_paths.push(new_index);
106 walked_paths.insert(index);
111 void get_border(
int current_index,
int connections) {
112 int x = current_index % width;
113 int y = current_index / width;
114 auto& current_river = borders.back();
115 current_river.push_back(glm::vec3(x + 1.f, y + 1.f, -0.05));
117 add_neighbor(x, y, x - 1, y + 0, connections);
118 add_neighbor(x, y, x + 1, y + 0, connections);
119 add_neighbor(x, y, x + 0, y + 1, connections);
120 add_neighbor(x, y, x + 0, y - 1, connections);
124 while(!current_paths.empty() || !unexplored_paths.empty()) {
125 while(!current_paths.empty()) {
126 auto current_path = current_paths.top();
128 get_border(current_path, 1);
131 if(!unexplored_paths.empty()) {
132 current_paths.push(unexplored_paths.top());
133 unexplored_paths.pop();
134 borders.push_back(std::vector<glm::vec3>());
137 borders.push_back(std::vector<glm::vec3>());
142 static void build_borders(std::vector<std::vector<glm::vec3>>& borders,
const uint32_t* pixels,
int width,
int height) {
144 borders.push_back(std::vector<glm::vec3>());
145 for(
int y = 0; y < height; y++) {
146 for(
int x = 0; x < width; x++) {
147 int curr_index = x + y * width;
148 if(generator.check_neighbor(x, y) && !generator.walked_positions.count(curr_index)) {
149 generator.get_border(curr_index, 1);
150 generator.clear_stack();
157 void Eng3D::Borders::build_borders() {
158 auto border_tex = std::make_unique<Eng3D::BinaryImage>(s.package_man.get_unique(
"map/provinces.png")->get_abs_path());
159 int height = border_tex->height;
160 int width = border_tex->width;
161 auto pixels = border_tex->buffer.get();
162 std::vector<std::vector<glm::vec3>> borders;
166 auto curve = std::make_unique<Eng3D::Curve>();
167 for(
size_t i = 0; i < borders.size(); i++) {
168 std::vector<glm::vec3> river = borders[i];
169 auto length = river.size();
170 if(length < 2)
continue;
172 std::vector<glm::vec3> mid_points(length + 3);
173 mid_points[0] = river[0];
174 mid_points[1] = river[0];
175 for(
size_t j = 0; j < length - 1; j++)
176 mid_points[j + 2] = 0.5f * (river[j] + river[j + 1]);
177 mid_points[length + 1] = river[length - 1];
178 mid_points[length + 2] = river[length - 1];
180 std::vector<glm::vec3> curve_points;
184 glm::vec3 p0, p1, p2, p3;
185 for(
size_t j = 1; j < mid_points.size() - 2; j++) {
186 p0 = mid_points[j - 1];
188 p2 = mid_points[j + 1];
189 p3 = mid_points[j + 2];
191 for(
float t = 1.f; t > 0.f; t -= step) {
196 glm::vec3 pt(0, 0, 0);
197 pt += p0 * (+1.f / 6.f * glm::pow(t0, 3.f) + 2.f * t0 + 4.f / 3.f + glm::pow(t0, 2.f));
198 pt += p3 * (-1.f / 6.f * glm::pow(t3, 3.f) - 2.f * t3 + 4.f / 3.f + glm::pow(t3, 2.f));
199 pt += p1 * (-1.f / 2.f * glm::pow(t1, 3.f) - glm::pow(t1, 2.f) + 2.f / 3.f);
200 pt += p2 * (+1.f / 2.f * glm::pow(t2, 3.f) - glm::pow(t2, 2.f) + 2.f / 3.f);
201 curve_points.push_back(pt);
205 std::vector<glm::vec3> normals(curve_points.size() - 1, glm::vec3(0, 0, 1));
206 curve->add_line(curve_points, normals, 1.0f);
209 this->curves.push_back(std::move(curve));
214 glm::mat4 model(1.f);
215 line_shader->set_uniform(
"model", model);
217 line_shader->set_uniform(
"view", camera.
get_view());
218 line_shader->set_texture(0,
"water_texture", *water_tex);
219 for(
auto& curve : curves)
static void build_borders(std::vector< std::vector< glm::vec3 >> &borders, const uint32_t *pixels, int width, int height)
void draw(const Eng3D::Camera &camera)
Borders(Eng3D::State &s, bool lazy_init=true)
Construct a new Eng 3D::Borders object.
virtual glm::mat4 get_view() const =0
Get the view matrix.
virtual glm::mat4 get_projection() const
Get the projection matrix.
std::shared_ptr< Eng3D::IO::Asset::Base > get_unique(const Eng3D::IO::Path &path)
Obtaining an unique asset means the "first-found" policy applies.
Eng3D::TextureManager tex_man
Eng3D::IO::PackageManager package_man
std::shared_ptr< Eng3D::Texture > load(const std::string &path, TextureOptions options=default_options)
Finds a texture in the list of a texture manager if the texture is already in the list we load the sa...
enum Eng3D::TextureOptions::Wrap wrap_s