Symphony Of Empires
font_sdf.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 // font_sdf.cpp
20 //
21 // Abstract:
22 // Does important stuff.
23 // ----------------------------------------------------------------------------
24 
25 #include <iostream>
26 #include <fstream>
27 #include <string>
28 #include <codecvt>
29 #include <locale>
30 #include <sstream>
31 
32 #include "eng3d/font_sdf.hpp"
33 #include "eng3d/state.hpp"
34 #include "eng3d/texture.hpp"
35 #include "eng3d/primitive.hpp"
36 #include "eng3d/shader.hpp"
37 #include "eng3d/state.hpp"
38 #include "eng3d/camera.hpp"
39 #include "eng3d/log.hpp"
40 
41 Eng3D::Glyph::Glyph(float _advance, Eng3D::Rectangle _atlas_bounds, Eng3D::Rectangle _plane_bounds)
42  : advance{ _advance },
43  atlas_bounds{ _atlas_bounds },
44  plane_bounds{ _plane_bounds }
45 {
46 
47 }
48 
49 Eng3D::FontSDF::FontSDF(const std::string& filename) {
50  auto& s = Eng3D::State::get_instance();
51  sphere_shader = std::make_unique<Eng3D::OpenGL::Program>();
52  {
53  auto vs_shader = Eng3D::OpenGL::VertexShader(s.package_man.get_unique("shaders/sphere_mapping.vs")->read_all());
54  sphere_shader->attach_shader(vs_shader);
55  sphere_shader->attach_shader(*s.builtin_shaders["fs_font_sdf"].get());
56  sphere_shader->link();
57  }
58  flat_shader = std::make_unique<Eng3D::OpenGL::Program>();
59  {
60  flat_shader->attach_shader(*s.builtin_shaders["vs_font_sdf"].get());
61  flat_shader->attach_shader(*s.builtin_shaders["fs_font_sdf"].get());
62  flat_shader->link();
63  }
64 
65  Eng3D::TextureOptions mipmap_options;
66  mipmap_options.min_filter = Eng3D::TextureOptions::Filter::LINEAR;
67  mipmap_options.mag_filter = Eng3D::TextureOptions::Filter::LINEAR;
68  mipmap_options.wrap_s = Eng3D::TextureOptions::Wrap::CLAMP_TO_EDGE;
69  mipmap_options.wrap_t = Eng3D::TextureOptions::Wrap::CLAMP_TO_EDGE;
70  mipmap_options.compressed = false;
71 
72  auto asset = s.package_man.get_unique(filename + ".png");
73  atlas = s.tex_man.load(asset->abs_path, mipmap_options);
74 
75  char buff;
76  uint32_t unicode;
77  float advance, top, bottom, left, right;
78  std::string line;
79  std::ifstream glyph_data(s.package_man.get_unique(filename + ".csv")->abs_path);
80  if(glyph_data.is_open()) {
81  while(std::getline(glyph_data, line)) {
82  std::istringstream data(line);
83  data >> unicode >> buff;
84  data >> advance >> buff;
85  data >> left >> buff >> bottom >> buff >> right >> buff >> top >> buff;
86  Eng3D::Rectangle plane_bounds(left, top, right - left, bottom - top);
87  data >> left >> buff >> bottom >> buff >> right >> buff >> top;
88  left /= atlas->width;
89  right /= atlas->width;
90  top /= atlas->height;
91  bottom /= atlas->height;
92  Eng3D::Rectangle atlas_bounds(left, top, right - left, bottom - top);
93  Eng3D::Glyph glyph(advance, atlas_bounds, plane_bounds);
94  unicode_map.insert({ unicode, glyph });
95  }
96  }
97 }
98 
100 template<typename T>
101 constexpr T bezier(float t, const T p0, const T p1, const T p2) {
102  return (1 - t) * ((1 - t) * p0 + t * p1) + t * ((1 - t) * p1 + t * p2);
103 }
104 
105 std::unique_ptr<Eng3D::Label3D> Eng3D::FontSDF::gen_text(const std::string& text, glm::vec2 pmin, glm::vec2 pmax, glm::vec2 p0, float width) {
106  assert(width > 0.f && width < 1.f);
107  std::wstring_convert<std::codecvt_utf8<char32_t>, char32_t> conv_utf8_utf32;
108  std::u32string unicode_text = conv_utf8_utf32.from_bytes(text);
109 
110  auto text_width = 0.f;
111  for(const auto& character : unicode_text) {
112  if(!unicode_map.count(character)) continue;
113  const auto& glyph = unicode_map[character];
114  text_width += glyph.advance;
115  }
116  assert(text_width != 0.f);
117 
118  glm::vec2 diff = (pmax - pmin) * (1.f - width);
119  pmin += diff;
120  pmax -= diff;
121  float scale = glm::length(pmax - pmin) / text_width;
122 
123  std::vector<glm::vec3> positions;
124  std::vector<glm::vec2> tex_coords;
125  float advance = 0.f;
126  for(const auto& character : unicode_text) {
127  if(!unicode_map.count(character)) continue;
128  const auto& glyph = unicode_map.at(character);
129  //glm::vec2 atlas_tl(glyph.atlas_bounds.left, glyph.atlas_bounds.top);
130  //glm::vec2 atlas_bl(glyph.atlas_bounds.left, glyph.atlas_bounds.bottom);
131  //glm::vec2 atlas_tr(glyph.atlas_bounds.right, glyph.atlas_bounds.top);
132  //glm::vec2 atlas_br(glyph.atlas_bounds.right, glyph.atlas_bounds.bottom);
133  glm::vec2 atlas_tl(glyph.atlas_bounds.left, glyph.atlas_bounds.bottom);
134  glm::vec2 atlas_bl(glyph.atlas_bounds.left, glyph.atlas_bounds.top);
135  glm::vec2 atlas_tr(glyph.atlas_bounds.right, glyph.atlas_bounds.bottom);
136  glm::vec2 atlas_br(glyph.atlas_bounds.right, glyph.atlas_bounds.top);
137  tex_coords.push_back(atlas_tl);
138  tex_coords.push_back(atlas_br);
139  tex_coords.push_back(atlas_bl);
140  tex_coords.push_back(atlas_tr);
141  tex_coords.push_back(atlas_br);
142  tex_coords.push_back(atlas_tl);
143 
144  glm::vec2 plane_tl(glyph.plane_bounds.left, glyph.plane_bounds.top);
145  glm::vec2 plane_bl(glyph.plane_bounds.left, glyph.plane_bounds.bottom);
146  glm::vec2 plane_tr(glyph.plane_bounds.right, glyph.plane_bounds.top);
147  glm::vec2 plane_br(glyph.plane_bounds.right, glyph.plane_bounds.bottom);
148 
149  const auto t0 = advance / text_width;
150  advance += glyph.advance;
151  glm::vec2 char_tl = bezier(t0, pmin, p0, pmax) + plane_tl * scale;
152  glm::vec2 char_bl = bezier(t0, pmin, p0, pmax) + plane_bl * scale;
153  glm::vec2 char_tr = bezier(t0, pmin, p0, pmax) + plane_tr * scale;
154  glm::vec2 char_br = bezier(t0, pmin, p0, pmax) + plane_br * scale;
155 
156  positions.emplace_back(char_tl, 0.f);
157  positions.emplace_back(char_br, 0.f);
158  positions.emplace_back(char_bl, 0.f);
159  positions.emplace_back(char_tr, 0.f);
160  positions.emplace_back(char_br, 0.f);
161  positions.emplace_back(char_tl, 0.f);
162  }
163  return std::make_unique<Eng3D::Label3D>(new Eng3D::TriangleList(positions, tex_coords), scale, glm::vec3(p0, 0.f));
164 }
165 
166 #include "eng3d/map.hpp"
167 void Eng3D::FontSDF::draw(const std::vector<std::unique_ptr<Label3D>>& labels, const Eng3D::Camera& camera, bool sphere) {
168  auto& shader = sphere ? *sphere_shader : *flat_shader;
169  shader.use();
170  shader.set_uniform("projection", camera.get_projection());
171  shader.set_uniform("view", camera.get_view());
172  shader.set_uniform("map_size", camera.get_map_size());
173  shader.set_uniform("model", glm::mat4(1));
174  shader.set_texture(0, "atlas", *atlas);
175  for(auto& label : labels) {
176  if(label.get() == nullptr) continue;
177  const auto size = label->size * (sphere ? 0.1f : 1.f);
178  shader.set_uniform("center", label->center.x, label->center.y);
179  shader.set_uniform("radius", Eng3D::GLOBE_RADIUS + 0.01f * size);
180  shader.set_uniform("px_range", size * 0.3f);
181  label->draw();
182  }
183 }
184 
185 Eng3D::Label3D::Label3D(Eng3D::TriangleList* _triangles, float _size, glm::vec3 _center)
186  : size{ _size },
187  center{ _center },
188  triangles{ _triangles }
189 {
190 
191 }
192 
194  triangles->draw();
195 }
glm::vec2 get_map_size() const
Get the size of the map.
Definition: camera.hpp:83
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
static State & get_instance()
Definition: state.cpp:514
enum Eng3D::TextureOptions::Filter min_filter
enum Eng3D::TextureOptions::Wrap wrap_s
constexpr T bezier(float t, const T p0, const T p1, const T p2)
Quadratic bezier curve, p1 is control.
Definition: font_sdf.cpp:101
void draw(const std::vector< std::unique_ptr< Label3D >> &labels, const Eng3D::Camera &camera, bool sphere)
Definition: font_sdf.cpp:167
FontSDF(const std::string &filename)
Definition: font_sdf.cpp:49
std::unique_ptr< Eng3D::Label3D > gen_text(const std::string &text, glm::vec2 pmin, glm::vec2 pmax, glm::vec2 p0, float width)
Definition: font_sdf.cpp:105
Glyph()=default
Label3D(Eng3D::TriangleList *triangles, float size, glm::vec3 center)
Definition: font_sdf.cpp:185