Euphoria
hashgen.identicon.cc
Go to the documentation of this file.
1 #include "core/hashgen.h"
2 
3 #include "core/image.h"
4 #include "base/rgb.h"
5 #include "assert/assert.h"
6 #include "base/numeric.h"
7 #include "base/range.h"
8 #include "base/vec2.h"
9 #include "base/mat2.h"
10 #include "base/mat3.h"
11 #include "core/image_draw.h"
12 #include "core/image_canvas.h"
13 #include "base/cint.h"
14 #include "log/log.h"
15 
16 
17 namespace
18 {
19  using namespace eu;
20  using namespace eu::core;
21 
22  const auto patch0 = std::vector<int>{0, 4, 24, 20 };
23  const auto patch1 = std::vector<int>{0, 4, 20 };
24  const auto patch2 = std::vector<int>{2, 24, 20 };
25  const auto patch3 = std::vector<int>{0, 2, 20, 22 };
26  const auto patch4 = std::vector<int>{2, 14, 22, 10 };
27  const auto patch5 = std::vector<int>{0, 14, 24, 22 };
28  const auto patch6 = std::vector<int>{2, 24, 22, 13, 11, 22, 20 };
29  const auto patch7 = std::vector<int>{0, 14, 22 };
30  const auto patch8 = std::vector<int>{6, 8, 18, 16 };
31  const auto patch9 = std::vector<int>{4, 20, 10, 12, 2 };
32  const auto patch10 = std::vector<int>{0, 2, 12, 10 };
33  const auto patch11 = std::vector<int>{10, 14, 22 };
34  const auto patch12 = std::vector<int>{20, 12, 24 };
35  const auto patch13 = std::vector<int>{10, 2, 12 };
36  const auto patch14 = std::vector<int>{0, 2, 10 };
37  const auto patch_types = std::vector<std::vector<int>>
38  {
39  patch0,
40  patch1,
41  patch2,
42  patch3,
43  patch4,
44  patch5,
45  patch6,
46  patch7,
47  patch8,
48  patch9,
49  patch10,
50  patch11,
51  patch12,
52  patch13,
53  patch14,
54  patch0
55  };
56  const auto center_patch_types = std::vector<int>{0, 4, 8, 15};
57 
58  void render_identicon_patch
59  (
60  Image* image,
61  int x,
62  int y,
63  int size,
64  int overflowing_patch_type,
65  int turn,
66  bool invert,
67  const Rgbi& foreground_color,
68  const Rgbi& background_color
69  ) {
70  const auto patch = overflowing_patch_type % eu::c_sizet_to_int(patch_types.size());
71  turn %= 4;
72  if (patch == 15)
73  {
74  invert = !invert;
75  }
76 
77  auto vertices = patch_types[patch];
78  auto offset = static_cast<float>(size) / 2.0f;
79  auto scale = static_cast<float>(size) / 4.0f;
80 
81  auto ctx = Canvas{image};
82 
83  // paint background
84  ctx.fill_style = invert ? foreground_color : background_color;
85  ctx.fill_rect(x, y, size, size);
86 
87  // build patch path
88  ctx.translate(static_cast<float>(x) + offset, static_cast<float>(y) + offset);
89  ctx.rotate(static_cast<float>(turn) * eu::pi / 2);
90  ctx.begin_path();
91  ctx.move_to
92  (
93  static_cast<float>(vertices[0] % 5) * scale - offset,
94  std::floor(static_cast<float>(vertices[0]) / 5.0f) * scale - offset
95  );
96  for (std::size_t vertex_index = 1; vertex_index < vertices.size(); vertex_index++)
97  {
98  ctx.draw_line_to
99  (
100  static_cast<float>(vertices[vertex_index] % 5) * scale - offset,
101  std::floor(static_cast<float>(vertices[vertex_index]) / 5.0f) * scale - offset
102  );
103  }
104  ctx.close_path();
105 
106  // offset and rotate coordinate space by patch position (x, y) and
107  // 'turn' before rendering patch shape
108 
109  // render rotated patch using fore color (back color if inverted)
110  ctx.fill_style = invert ? background_color : foreground_color;
111  ctx.fill();
112  }
113 }
114 
115 namespace eu::core
116 {
117  void render_identicon(Image* image, U32 code)
118  {
119  ASSERT(image);
120  ASSERT(image->width == image->height);
121  const auto patch_size = image->height / 3;
122  const auto middle_type = center_patch_types[code & 3];
123  const bool middle_invert = ((code >> 2) & 1) != 0;
124  const bool corner_invert = ((code >> 7) & 1) != 0;
125  const bool side_invert = ((code >> 14) & 1) != 0;
126  const int corner_type = c_unsigned_int_to_int((code >> 3) & 15);
127  const int side_type = c_unsigned_int_to_int((code >> 10) & 15);
128  const int blue = c_unsigned_int_to_int((code >> 16) & 31);
129  const int green = c_unsigned_int_to_int((code >> 21) & 31);
130  const int red = c_unsigned_int_to_int((code >> 27) & 31);
131 
132  int corner_turn = c_unsigned_int_to_int((code >> 8) & 3);
133  int side_turn = c_unsigned_int_to_int((code >> 15) & 3);
134 
135  const auto con = [](int i) -> U8 { return c_int_to_u8(keep_within(Range<int>{0, 255}, i)); };
136  const auto foreground_color = Rgbi{con(red << 3), con(green << 3), con(blue << 3)};
137  const auto background_color = Rgbi{255, 255, 255};
138 
139  // middle patch
140  render_identicon_patch(image, patch_size, patch_size, patch_size, middle_type, 0, middle_invert, foreground_color, background_color);
141  // side patchs, starting from top and moving clock-wise
142  render_identicon_patch(image, patch_size, 0, patch_size, side_type, side_turn++, side_invert, foreground_color, background_color);
143  render_identicon_patch(image, patch_size * 2, patch_size, patch_size, side_type, side_turn++, side_invert, foreground_color, background_color);
144  render_identicon_patch(image, patch_size, patch_size * 2, patch_size, side_type, side_turn++, side_invert, foreground_color, background_color);
145  render_identicon_patch(image, 0, patch_size, patch_size, side_type, side_turn++, side_invert, foreground_color, background_color);
146  // corner patchs, starting from top left and moving clock-wise
147  render_identicon_patch(image, 0, 0, patch_size, corner_type, corner_turn++, corner_invert, foreground_color, background_color);
148  render_identicon_patch(image, patch_size * 2, 0, patch_size, corner_type, corner_turn++, corner_invert, foreground_color, background_color);
149  render_identicon_patch(image, patch_size * 2, patch_size * 2, patch_size, corner_type, corner_turn++, corner_invert, foreground_color, background_color);
150  render_identicon_patch(image, 0, patch_size * 2, patch_size, corner_type, corner_turn++, corner_invert, foreground_color, background_color);
151  }
152 }
#define ASSERT(x)
Definition: assert.h:29
constexpr Rgbi con(unsigned char r, unsigned char g, unsigned char b)
void render_identicon(Image *image, U32 code)
Definition: assert.h:90
T keep_within(const Range< T > &range, T value)
Definition: range.h:115
int c_sizet_to_int(size_t t)
Definition: cint.cc:11
constexpr float pi
Definition: numeric.h:127
std::uint32_t U32
Definition: ints.h:13
U8 c_int_to_u8(unsigned int i)
Definition: cint.cc:42
std::uint8_t U8
Definition: ints.h:15
int c_unsigned_int_to_int(unsigned int i)
Definition: cint.cc:19
float floor(float v)
Definition: numeric.cc:35
Definition: rgb.h:26
hacky layer between something that looks like the html 'canvas rendering context 2d' and the euphoria...
Definition: image_canvas.h:16