Euphoria
hashgen.sprator.cc
Go to the documentation of this file.
1 #include "core/hashgen.h"
2 
3 
4 
5 #include "core/image.h"
6 #include "base/rgb.h"
7 #include "assert/assert.h"
8 #include "core/rng.h"
9 #include "base/numeric.h"
10 #include "core/image_draw.h"
11 #include "base/cint.h"
12 #include "core/table_bool.h"
13 #include "core/generator_cell.h"
14 
15 
16 namespace
17 {
18  using namespace eu;
19  using namespace eu::core;
20 
21 
22  Rgbai
23  calculate_border_color(const Rgbai& base)
24  {
25  auto h = to_hsl(to_rgb(base));
26  h.h -= Angle::from_degrees(15);
27  h.l *= 0.4f;
28  return {to_rgbi(to_rgb(h)), base.a};
29  }
30 
31 
32  void
33  apply_sprator_algorithm(BoolTable* half_side, int number_of_steps)
34  {
35  generator::Rules rules;
37  (
38  &rules,
39  number_of_steps,
40  [](bool current, const WallCounter& wc) -> std::optional<bool>
41  {
42  const auto c = wc.count
43  (
44  1,
45  false,
47  );
48  if(current)
49  {
50  if(c == 2 || c == 3 ) { return true; }
51  else { return false; }
52  }
53  else
54  {
55  if(c <= 1) { return true; }
56  else { return false; }
57  }
58  }
59  );
60 
61  auto cell = generator::CellularAutomata
62  (
63  &rules,
64  half_side,
66  );
67 
68  while(false == cell.is_done()) { cell.update(); }
69  }
70 
71 
72  BoolTable
73  mirror(const BoolTable& half_side)
74  {
75  const auto height = half_side.get_height();
76  const auto half_width = half_side.get_width();
77  const auto width = half_width * 2;
78 
79  // offset everything by 1 to get a nice border
80  constexpr auto offset = 1;
81  constexpr auto extra_size = 2;
82 
83  auto result_table = BoolTable::from_width_height
84  (
85  width + extra_size,
86  height + extra_size,
87  false
88  );
89 
90  for(int y=0; y<height; y+=1)
91  {
92  for(int x=0; x<half_width; x+=1)
93  {
94  const auto src = half_side[{x, y}];
95  const auto x_mirror = width - (x + 1);
96  result_table[{x + offset, y + offset}] = src;
97  result_table[{x_mirror + offset, y + offset}] = src;
98  }
99  }
100 
101  return result_table;
102  }
103 
104 
105  int
106  calculate_scale(const Image& image, const BoolTable& table)
107  {
108  auto calculate_scale = [](int image_scale, int table_scale) -> int
109  {
110  const auto image_scale_float = static_cast<float>(image_scale);
111  const auto table_scale_float = static_cast<float>(table_scale);
112  const auto scale_factor = image_scale_float / table_scale_float;
113  return std::max(1, floor_to_int(scale_factor));
114  };
115 
116  const auto scale = std::min
117  (
118  calculate_scale(image.width, table.get_width()),
119  calculate_scale(image.height, table.get_height())
120  );
121 
122  return scale;
123  }
124 
125 
126  void
127  draw_image_with_border
128  (
129  Image* image,
130  const BoolTable& result_table,
131  const Rgbai& background_color,
132  const Rgbai& foreground_color,
133  const Rgbai& border_color
134  )
135  {
136  clear(image, background_color);
137  auto img = draw
138  (
139  result_table,
140  foreground_color,
141  background_color,
142  calculate_scale(*image, result_table),
143  BorderSettings{border_color}
144  );
145  paste_image(image, vec2i{0, 0}, img);
146  }
147 
148 
149  template
150  <
151  typename TGenerator
152  >
153  void
154  randomize_world(BoolTable* half_side, TGenerator* generator)
155  {
157  (
158  half_side,
160  [&]() -> bool { return generator->get_next_float01() < 0.5f; }
161  );
162  }
163 
164 
165  template
166  <
167  typename TGenerator,
168  typename I
169  >
170  void
171  render_sprator_impl
172  (
173  Image* image,
174  I code,
175  const Rgbai& foreground_color,
176  const std::optional<Rgbai> border_color_arg,
177  const Rgbai& background_color
178  )
179  {
180  constexpr int half_width = 4;
181  constexpr int height = 8;
182  const int number_of_steps = 3;
183  // todo(Gustav): figure out color (randomly?)
184  const Rgbai border_color = border_color_arg.value_or
185  (
186  calculate_border_color(foreground_color)
187  );
188 
189  auto half_side = BoolTable::from_width_height(half_width, height);
190 
191  auto generator = TGenerator{code};
192 
193  // randomize world
194  randomize_world<TGenerator>(&half_side, &generator);
195 
196  // apply sprator algorithm
197  apply_sprator_algorithm(&half_side, number_of_steps);
198 
199  // flip and copy from small table to big table
200  const auto result_table = mirror(half_side);
201 
202  // draw image with border
203  draw_image_with_border(image, result_table, background_color, foreground_color, border_color);
204  }
205 
206 
207  template
208  <
209  typename TGenerator,
210  typename I
211  >
212  void
213  render_sprator_impl
214  (
215  std::vector<Image>* images,
216  I code,
217  const Rgbai& foreground_color,
218  const std::optional<Rgbai> border_color_arg,
219  const Rgbai& background_color
220  )
221  {
222  constexpr int half_width = 4;
223  constexpr int height = 8;
224  const int number_of_steps = 3;
225  // todo(Gustav): figure out color (randomly?)
226  const Rgbai border_color = border_color_arg.value_or
227  (
228  calculate_border_color(foreground_color)
229  );
230 
231  auto half_side = BoolTable::from_width_height(half_width, height);
232 
233  auto generator = TGenerator{code};
234 
235  // randomize world
236  randomize_world<TGenerator>(&half_side, &generator);
237 
238  // apply sprator algorithm
239  apply_sprator_algorithm(&half_side, number_of_steps - 1);
240 
241  bool first = true;
242 
243  auto orig_half_side = half_side;
244 
245  for(auto& image: *images)
246  {
247  if(first) { first = false; }
248  else
249  {
250  half_side = orig_half_side;
251 
252  // animate...
253  auto hit = BoolTable::from_width_height(half_side.get_width(), half_side.get_height(), false);
254  for(int animation_frame=0; animation_frame<2; animation_frame+=1)
255  {
256  int x = 0;
257  int y = 0;
258  do
259  {
260  x = floor_to_int(generator.get_next_float01() * half_side.get_width());
261  y = floor_to_int(generator.get_next_float01() * half_side.get_height());
262  } while(hit[{x, y}]);
263  hit[{x, y}] = true;
264  half_side[{x, y}] = !half_side[{x, y}];
265  }
266  }
267 
268 
269  apply_sprator_algorithm(&half_side, 1);
270 
271  // flip and copy from small table to big table
272  const auto result_table = mirror(half_side);
273 
274  // draw image with border
275  draw_image_with_border(&image, result_table, background_color, foreground_color, border_color);
276  }
277  }
278 }
279 
280 
281 namespace eu::core
282 {
283  void
285  (
286  Image* image,
287  U32 code,
288  const Rgbai& foreground_color,
289  std::optional<Rgbai> border_color_arg,
290  const Rgbai& background_color
291  )
292  {
293  render_sprator_impl<RandomXorShift32>
294  (
295  image,
296  code,
297  foreground_color,
298  border_color_arg,
299  background_color
300  );
301  }
302 
303 
304  void
306  (
307  std::vector<Image>* images,
308  U32 code,
309  const Rgbai& foreground_color,
310  std::optional<Rgbai> border_color_arg,
311  const Rgbai& background_color
312  )
313  {
314  render_sprator_impl<RandomXorShift32>
315  (
316  images,
317  code,
318  foreground_color,
319  border_color_arg,
320  background_color
321  );
322  }
323 }
324 
ParserBase * base
Definition: argparse.cc:887
void add_complex_rules(Rules *ca, int times, ChangeFunction change)
void clear(Image *image, const Rgbai &color)
Definition: image_draw.cc:32
void set_white_noise(BoolTable *world, Lrud< BorderSetupRule > border_control, std::function< bool()> rng)
Definition: table_bool.cc:11
void render_sprator(Image *image, U32 code, const Rgbai &foreground_color={NamedColor::white}, std::optional< Rgbai > border_color_arg=std::nullopt, const Rgbai &background_color={NamedColor::black, 0})
Image draw(const BoolTable &world, Rgbai wall_color, Rgbai space_color, int scale, std::optional< BorderSettings > border)
Definition: table_bool.cc:459
void paste_image(Image *dest_image, const vec2i &position, const Image &source_image, BlendMode blend_mode, PixelsOutside clip)
Definition: image_draw.cc:553
Definition: assert.h:90
Rgbi to_rgbi(const Rgb &c)
Definition: rgb.cc:352
std::uint32_t U32
Definition: ints.h:13
Rgb to_rgb(const Rgbi &c)
Definition: rgb.cc:229
Hsl to_hsl(const Rgb &c)
Definition: rgb.cc:291
size2f min(const size2f lhs, const size2f rhs)
Definition: size2.cc:140
size2f max(const size2f lhs, const size2f rhs)
Definition: size2.cc:149
int floor_to_int(float v)
Definition: numeric.cc:49
constexpr static Angle from_degrees(float degrees)
Definition: angle.h:16
Generic version of a CSS like padding type.
Definition: lrud.h:20
Definition: rgb.h:45
Idx get_height() const
Definition: table.h:158
Idx get_width() const
Definition: table.h:153
static Table from_width_height(Idx width, Idx height, T d=T())
Definition: table.h:23
int count(int step, bool include_self, NeighborhoodAlgorithm algorithm) const
Definition: table_bool.cc:306
Definition: vec2.h:72