Symphony Of Empires
rivers.cpp
Go to the documentation of this file.
1 // Eng3D - General purpouse game engine
2 // Copyright (C) 2021, Eng3D contributors
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU General Public License as published by
6 // the Free Software Foundation, either version 3 of the License, or
7 // (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with this program. If not, see <https://www.gnu.org/licenses/>.
16 //
17 // ----------------------------------------------------------------------------
18 // Name:
19 // rivers.cpp
20 //
21 // Abstract:
22 // Does some important stuff.
23 // ----------------------------------------------------------------------------
24 
25 #include <glm/mat4x4.hpp>
26 
27 #include "eng3d/rivers.hpp"
28 #include "eng3d/texture.hpp"
29 #include "eng3d/state.hpp"
30 #include "eng3d/curve.hpp"
31 #include "eng3d/shader.hpp"
32 #include "eng3d/camera.hpp"
33 
37 Eng3D::Rivers::Rivers(Eng3D::State& _s, bool lazy_init)
38  : s{ _s }
39 {
40  Eng3D::TextureOptions mipmap_options{};
41  mipmap_options.wrap_s = Eng3D::TextureOptions::Wrap::REPEAT;
42  mipmap_options.wrap_t = Eng3D::TextureOptions::Wrap::REPEAT;
43  mipmap_options.min_filter = Eng3D::TextureOptions::Filter::LINEAR_MIPMAP;
44  mipmap_options.mag_filter = Eng3D::TextureOptions::Filter::LINEAR;
45  mipmap_options.internal_format = Eng3D::TextureOptions::Format::SRGB;
46 
47  water_tex = s.tex_man.load(s.package_man.get_unique("gfx/water_tex.png"), mipmap_options);
48  line_shader = std::make_unique<Eng3D::OpenGL::Program>();
49  {
50  auto vs_shader = *s.builtin_shaders["vs_3d"].get();
51  line_shader->attach_shader(vs_shader);
52  auto fs_shader = Eng3D::OpenGL::FragmentShader(s.package_man.get_unique("shaders/curve.fs")->read_all(), true);
53  line_shader->attach_shader(fs_shader);
54  line_shader->link();
55  }
56 
57  if(!lazy_init)
58  this->build_rivers();
59 }
60 
62 public:
63  ConnectedNode* node = nullptr;
64  std::unique_ptr<std::vector<glm::vec3>> river;
66  : river{ new std::vector<glm::vec3> }
67  {
68 
69  }
70 
71  ConnectedNode(const std::vector<glm::vec3>& _river)
72  : river{ std::make_unique<std::vector<glm::vec3>>(_river) }
73  {
74 
75  }
76 
77  ~ConnectedNode() = default;
78 };
79 
80 void Eng3D::Rivers::get_river(std::vector<glm::vec3>& river, int current_index, int prev_index, uint32_t* pixels, int width, int height) {
81  int x = current_index % width;
82  int y = current_index / width;
83  river.push_back(glm::vec3(x, y, -0.05));
84 
85  const auto check_neighbor = [this, current_index, prev_index, pixels, width, height](std::vector<glm::vec3>& _river, int new_x, int new_y) {
86  if(new_x < 0 || new_y < 0 || new_x >= width || new_y >= height)
87  return;
88  int new_index = new_x + new_y * width;
89  if(new_index == prev_index) return;
90 
91  uint32_t neighbor_color = pixels[new_index];
92  if(neighbor_color == 0xFFFF0000) {
93  this->get_river(_river, new_index, current_index, pixels, width, height);
94  return;
95  }
96  };
97  check_neighbor(river, x - 1, y + 0);
98  check_neighbor(river, x + 1, y + 0);
99  check_neighbor(river, x + 0, y + 1);
100  check_neighbor(river, x + 0, y - 1);
101 }
102 
103 
104 void Eng3D::Rivers::build_rivers() {
105  Eng3D::TextureOptions no_drop_options{};
106  no_drop_options.editable = true;
107  auto river_tex = s.tex_man.load(s.package_man.get_unique("map/river.png"), no_drop_options);
108 
109  std::vector<int> rivers_starts;
110  auto pixels = river_tex->buffer.get();
111  for(size_t y = 0; y < river_tex->height; y++)
112  for(size_t x = 0; x < river_tex->width; x++)
113  if(pixels[x + y * river_tex->width] == 0xff0000ff)
114  rivers_starts.push_back(x + y * river_tex->width);
115 
116  // TODO FIX THIS NOT INFINITE LOOP
117  for(size_t i = 0; i < rivers_starts.size(); i++) {
118  std::vector<glm::vec3> river;
119  this->get_river(river, rivers_starts[i], -1, pixels, river_tex->width, river_tex->height);
120 
121  const size_t length = river.size();
122  if(length < 2) continue;
123 
124  std::vector<glm::vec3> mid_points(length + 3);
125  mid_points[0] = river[0];
126  mid_points[1] = river[0];
127  for(size_t j = 0; j < length - 1; j++)
128  mid_points[j + 2] = 0.5f * (river[j] + river[j + 1]);
129  mid_points[length + 1] = river[length - 1];
130  mid_points[length + 2] = river[length - 1];
131 
132  std::vector<glm::vec3> curve_points;
133 
134  // p0 = 2.f * river[0] - river[1];
135  // p3 = 2.f * river[length - 1] - river[length - 2];
136  glm::vec3 p0, p1, p2, p3;
137  for(size_t j = 1; j < mid_points.size() - 2; j++) {
138  p0 = mid_points[j - 1];
139  p1 = mid_points[j];
140  p2 = mid_points[j + 1];
141  p3 = mid_points[j + 2];
142 
143  float step = 1 / 10.;
144  for(float t = 1.f; t > 0.f; t -= step) {
145  float t0 = t - 2;
146  float t1 = t - 1;
147  float t2 = t + 0;
148  float t3 = t + 1;
149 
150  glm::vec3 pt(0, 0, 0);
151  pt += p0 * (+1.f / 6.f * glm::pow(t0, 3.f) + 2.f * t0 + 4.f / 3.f + glm::pow(t0, 2.f));
152  pt += p3 * (-1.f / 6.f * glm::pow(t3, 3.f) - 2.f * t3 + 4.f / 3.f + glm::pow(t3, 2.f));
153  pt += p1 * (-1.f / 2.f * glm::pow(t1, 3.f) - glm::pow(t1, 2.f) + 2.f / 3.f);
154  pt += p2 * (+1.f / 2.f * glm::pow(t2, 3.f) - glm::pow(t2, 2.f) + 2.f / 3.f);
155  curve_points.push_back(pt);
156  }
157  }
158 
159  std::vector<glm::vec3> normals(curve_points.size() - 1, glm::vec3(0, 0, 1));
160  auto curve = std::make_unique<Eng3D::Curve>(curve_points, normals, 1.0f);
161  this->curves.push_back(std::move(curve));
162  }
163 }
164 
165 void Eng3D::Rivers::draw(const Eng3D::Camera& camera) {
166  line_shader->use();
167 
168  glm::mat4 model(1.f);
169  line_shader->set_uniform("model", model);
170  line_shader->set_uniform("projection", camera.get_projection());
171  line_shader->set_uniform("view", camera.get_view());
172  line_shader->set_texture(0, "water_texture", *water_tex);
173  for(auto& curve : curves)
174  curve->draw();
175 }
std::unique_ptr< std::vector< glm::vec3 > > river
Definition: rivers.cpp:64
~ConnectedNode()=default
ConnectedNode(const std::vector< glm::vec3 > &_river)
Definition: rivers.cpp:71
virtual glm::mat4 get_view() const =0
Get the view matrix.
virtual glm::mat4 get_projection() const
Get the projection matrix.
Definition: camera.hpp:91
std::shared_ptr< Eng3D::IO::Asset::Base > get_unique(const Eng3D::IO::Path &path)
Obtaining an unique asset means the "first-found" policy applies.
Definition: io.cpp:146
Rivers(Eng3D::State &s, bool lazy_init=true)
Construct a new Eng3D::Rivers object.
Definition: rivers.cpp:37
void draw(const Eng3D::Camera &camera)
Definition: rivers.cpp:165
Eng3D::TextureManager tex_man
Definition: state.hpp:124
Eng3D::IO::PackageManager package_man
Definition: state.hpp:122
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...
Definition: texture.cpp:432
enum Eng3D::TextureOptions::Wrap wrap_s
Definition: utils.hpp:35