Gorgon Game Engine
HTMLRenderer.h
Go to the documentation of this file.
1 #pragma once
2 
3 #include <string>
4 #include <cassert>
5 #include <utility>
6 #include <unordered_map>
7 
8 #include "Color.h"
9 #include "Font.h"
10 #include "TextureTargets.h"
11 
12 #include "../Utils/Assert.h"
13 #include "../Utils/Logging.h"
14 
15 #define HR_REQ_SEMICOLON(statement) do { statement; } while(false)
16 #define HR_LOG(string, state) HR_REQ_SEMICOLON(HTMLRendererInternal::Logger.Log(string, state))
17 #define HR_LOG_ERROR(string) HR_LOG(string, Utils::Logger::State::Error)
18 #define HR_LOG_NOTICE(string) HR_LOG(string, Utils::Logger::State::Notice)
19 #define HR_LOG_MESSAGE(string) HR_LOG(string, Utils::Logger::State::Message)
20 
21 #define HR_BTWSOR_TAG_ATTR_PAIR(tag, attribute) \
22  (static_cast<unsigned int>(tag) | static_cast<unsigned int>(attribute))
23 
24 namespace Gorgon { namespace Graphics {
25 
26 namespace HTMLRendererInternal {
27 extern Utils::Logger Logger;
28 }
29 
30 // !!! find a better place?
31 // !!! TODO implement or remove move and copy constructors
32 class FontFamily {
33 public:
34  enum class Style: unsigned int{
35  Normal = 0,
36  Italic,
37  Bold,
38  Large,
39  Custom,
40  End
41  };
42 
43  struct HashType {
44  unsigned int operator()(Style style) const {
45  return static_cast<unsigned int>(style);
46  }
47  };
48 
49  FontFamily(const std::unordered_map<Style, GlyphRenderer*, HashType> fonts): fonts(fonts)
50  {}
51 
53 
54  if(fonts.count(style)) {
55  HR_LOG_NOTICE("font style is found");
56  return fonts[style];
57  }
58 
59  HR_LOG_NOTICE("could not find font style, will use the next available font");
60 
61  // given style does not exist, return the immediate next font style
62  // !!! is it the best course of action?
63  const unsigned int start = static_cast<unsigned int>(Style::Normal);
64  const unsigned int end = static_cast<unsigned int>(Style::End);
65  for(unsigned int i = start; i < end; i++) {
66  if(fonts.count(static_cast<Style>(i))) {
67  return fonts[static_cast<Style>(i)];
68  }
69  }
70 
71  HR_LOG_ERROR("couldn't find any font, about to crash!!!");
72 
73  // couldn't find any font
74  // !!! we do not want to return a nullptr, let it crash
75  ASSERT(false, "empty font family map");
76 
77  // !!! silence compiler warnings
78  return nullptr;
79  }
80 
81  void AddFont(Style style, GlyphRenderer *renderer) {
82  fonts[style] = renderer;
83  }
84 
85  void RemoveFont(Style style) {
86  fonts.erase(style);
87  }
88 
89  bool HasFont(Style style) const {
90  return static_cast<bool>(fonts.count(style));
91  }
92 
93 private:
94  std::unordered_map<Style, GlyphRenderer*, HashType> fonts;
95 
96 }; // end of class FontFamily
97 
98 class HTMLRenderer {
99 public:
100  HTMLRenderer(FontFamily &fontfamily, RGBAf color = 1.f, TextShadow shadow = {}):
101  fontfamily(fontfamily),
102  renderer(*fontfamily.GetGlyphRenderer(FontFamily::Style::Normal)),
103  drawunderlined(false),
104  drawstriked(false),
105  underlinedstart(0),
106  strikedstart(0),
107  baselineoffset(0),
108  ucolor(1.f),
109  scolor(1.f),
110  target(nullptr)
111  {
112  if(!initialized) {
113  initialize();
114  initialized = true;
115  }
116  }
117 
118  void Print(TextureTarget &target, const std::string &text, int x, int y) {
119  parseandprint(target, text, x, y);
120  }
121 
122 private:
123  enum class Tag: unsigned int {
124  Underlined = 0x00000000,
125  Striked = 0x00000001,
126  Bold = 0x00000002,
127  Strong = 0x00000003,
128  Italic = 0x00000004,
129  Emphasized = 0x00000005,
130  H1 = 0x00000006,
131  Break = 0x00000007,
132  End
133  };
134 
135  enum class Attribute: unsigned int {
136  Color = 0x00000000,
137  End
138  };
139 
140  enum class LineType: unsigned int {
141  Underline = 0,
142  Strike,
143  End,
144  };
145 
146  struct HashType {
147  unsigned int operator()(Tag tag) const {
148  return static_cast<unsigned int>(tag);
149  }
150  };
151 
152  FontFamily &fontfamily;
153  StyledRenderer renderer;
154  bool drawunderlined, drawstriked;
155  unsigned int underlinedstart, strikedstart;
156  int baselineoffset, xx, yy, orgx, orgy;
157  RGBAf ucolor; // underlined
158  RGBAf scolor; // strike
159  TextureTarget *target;
160 
161  static bool initialized;
162  static std::unordered_map<unsigned int, bool> attsupportmap;
163  static std::unordered_map<Tag, std::string, HashType> emptytagmap;
164 
165  static void initialize() {
166  // fill attribute support list
167  attsupportmap.emplace(HR_BTWSOR_TAG_ATTR_PAIR(Tag::Underlined, Attribute::Color), true);
168  attsupportmap.emplace(HR_BTWSOR_TAG_ATTR_PAIR(Tag::Striked, Attribute::Color), true);
169 
170  // fill self-closing tags
171  emptytagmap.emplace(Tag::Break, "br");
172  }
173 
174  static Tag string2tag(const std::string &tag) {
175  if(tag == "u") { return Tag::Underlined; }
176  else if(tag == "strike") { return Tag::Striked; }
177  else if(tag == "b") { return Tag::Bold; }
178  else if(tag == "strong") { return Tag::Strong; }
179  else if(tag == "i") { return Tag::Italic; }
180  else if(tag == "em") { return Tag::Emphasized; }
181  else if(tag == "h1") { return Tag::H1; }
182  else if(tag == "br") { return Tag::Break; }
183  else { ASSERT(false, "unsupported tag: " + tag); return Tag::End; }
184  }
185 
186  static Attribute string2attribute(const std::string &attribute) {
187  if(attribute == "color") { return Attribute::Color; }
188  else { ASSERT(false, "unsupported attribute: " + attribute); return Attribute::End; }
189  }
190 
191  static RGBAf extractcolor(const std::string color) {
192  if(color == "white") { return RGBAf(1.f); }
193  else if(color == "black") { return RGBAf(0.f); }
194  else if(color == "green") { return RGBAf(0.f, 1.f, 0.f, 1.f); }
195  else {
196  HR_LOG_NOTICE("could not extract given color, using white");
197  return RGBAf(1.f);
198  }
199  }
200 
201  // private methods
202  void parseandprint(TextureTarget &target, const std::string &str, int x, int y);
203 
204  void applytag(Tag tag) {
205  // !!! TODO tag2string function
206  HR_LOG_NOTICE("applying tag: " + std::to_string(static_cast<unsigned int>(tag)));
207  switch(tag) {
208  case Tag::Underlined:
209  underlinedstart = xx;
210  drawunderlined = true;
211  break;
212  case Tag::Striked:
213  drawstriked = true;
214  strikedstart = xx;
215  break;
216  case Tag::Bold:
217  case Tag::Strong:
218  changeglyphrenderer(FontFamily::Style::Bold);
219  break;
220  case Tag::Italic:
221  case Tag::Emphasized:
222  changeglyphrenderer(FontFamily::Style::Italic);
223  break;
224  case Tag::H1:
225  changeglyphrenderer(FontFamily::Style::Large);
226  break;
227  case Tag::Break:
228  if(drawunderlined) { drawline(LineType::Underline); }
229  if(drawstriked) { drawline(LineType::Strike); }
230  yy += (int)std::round(renderer.GetGlyphRenderer().GetHeight() * 1.2f); // magic number from Font.cpp
231  xx = orgx;
232  break;
233  default:
234  // !!! TODO tag2string function
235  ASSERT(false, "unsupported tag: " + std::to_string(static_cast<unsigned int>(tag)));
236  break;
237  }
238  }
239 
240  void removetag(Tag tag) {
241  // !!! TODO tag2string function
242  HR_LOG_NOTICE("removing tag: " + std::to_string(static_cast<unsigned int>(tag)));
243  switch(tag) {
244  case Tag::Underlined:
245  drawunderlined = false;
246  drawline(LineType::Underline);
247  break;
248  case Tag::Striked:
249  drawstriked = false;
250  drawline(LineType::Strike);
251  break;
252  case Tag::Bold:
253  case Tag::Strong:
254  case Tag::Italic:
255  case Tag::Emphasized:
256  case Tag::H1:
257  changeglyphrenderer(FontFamily::Style::Normal);
258  break;
259  case Tag::Break:
260  // !!! this shouldn't be a case
261  ASSERT(false, "attempting to remove tag Break" + std::to_string(static_cast<unsigned int>(tag)));
262  break;
263  default:
264  // !!! TODO tag2string function
265  ASSERT(false, "unsupported tag: " + std::to_string(static_cast<unsigned int>(tag)));
266  break;
267  }
268  }
269 
270  void applyattributes(Tag tag, const std::vector<std::pair<std::string, std::string>> &attributes) {
271  Attribute attribute;
272  for(const auto &attstr: attributes) {
273  attribute = string2attribute(attstr.first);
274  unsigned int mappedval = HR_BTWSOR_TAG_ATTR_PAIR(tag, attribute);
275  if(attsupportmap.count(mappedval) && attsupportmap.at(mappedval)) {
276  switch(mappedval) {
277  case HR_BTWSOR_TAG_ATTR_PAIR(Tag::Underlined, Attribute::Color):
278  HR_LOG_NOTICE("changing underline color");
279  ucolor = extractcolor(attstr.second);
280  break;
281  case HR_BTWSOR_TAG_ATTR_PAIR(Tag::Striked, Attribute::Color):
282  HR_LOG_NOTICE("changing strike color");
283  scolor = extractcolor(attstr.second);
284  break;
285  default:
286  ASSERT(false, "unsupported attribute: " + attstr.first);
287  break;
288  }
289  }
290  else {
291  // !!! TODO tag2string function
292  HR_LOG_NOTICE("attribute is not part of tag (" + std::to_string(static_cast<unsigned int>(tag)) + ")");
293  }
294  }
295  }
296 
297  // !!! TODO find a way to merge this function with removetag
298  // !!! the problem is underline and strike application is done
299  // !!! after removetag is called
300  void clearattributes(Tag tag) {
301  switch(tag) {
302  case Tag::Underlined:
303  HR_LOG_NOTICE("clearing underline attributes");
304  ucolor = RGBAf(1.f);
305  break;
306  case Tag::Striked:
307  HR_LOG_NOTICE("clearing strike attributes");
308  scolor = RGBAf(1.f);
309  break;
310  default:
311  return;
312  }
313  }
314 
315  void drawline(LineType linetype) {
316  ASSERT(target, "texture target is null");
317 
318  if(linetype == LineType::Underline) {
319  HR_LOG_NOTICE("drawing underline");
320  target->Draw((float)underlinedstart,
321  (float)(yy + renderer.GetGlyphRenderer().GetUnderlineOffset() /*+ baselineoffset*/),
322  (float)(xx - underlinedstart),
323  (float)renderer.GetGlyphRenderer().GetLineThickness(),
324  ucolor);
325  }
326  else if(linetype == LineType::Strike) {
327  HR_LOG_NOTICE("drawing strike");
328  target->Draw((float)strikedstart,
329  (float)(yy + renderer.GetStrikePosition() /*+ baselineoffset*/),
330  (float)(xx - strikedstart),
331  (float)renderer.GetGlyphRenderer().GetLineThickness(),
332  scolor);
333  }
334  else {
335  ASSERT(false, "invalid line type");
336  }
337  }
338 
339  // !!! further cases can ben covered in a switch-case/if-else block
340  void changeglyphrenderer(FontFamily::Style newstyle) {
341  // store previous baseline
342  int prevbaselineoffset = (int)renderer.GetGlyphRenderer().GetBaseLine();
343 
344  renderer.SetGlyphRenderer(*fontfamily.GetGlyphRenderer(newstyle));
345 
346  // calculate the baseline offset if there is a difference in baselines
347  if((prevbaselineoffset - renderer.GetGlyphRenderer().GetBaseLine()) < 0) {
348  baselineoffset = (int)std::round(prevbaselineoffset - renderer.GetGlyphRenderer().GetBaseLine());
349  }
350  else {
351  baselineoffset = 0;
352  }
353  }
354 
355  void print(TextureTarget &target, const std::string &text, int x, int y) {
356  renderer.Print(target, text, x, y + baselineoffset);
357  }
358 
359 }; // end of class HTMLRenderer
360 
361 }} // end of namespace Gorgon::Graphics
Gorgon::Graphics::HTMLRendererInternal::Logger
Utils::Logger Logger
Definition: HTMLRenderer.cpp:10
glGenVertexArrays
PFNGLGENVERTEXARRAYSPROC glGenVertexArrays
Definition: OpenGL.cpp:43
glBindBuffer
PFNGLBINDBUFFERPROC glBindBuffer
Definition: OpenGL.cpp:27
Layer.h
Gorgon::Graphics::FontFamily::RemoveFont
void RemoveFont(Style style)
Definition: HTMLRenderer.h:85
glBindVertexArray
PFNGLBINDVERTEXARRAYPROC glBindVertexArray
Definition: OpenGL.cpp:29
Gorgon::Graphics::HTMLRenderer::HTMLRenderer
HTMLRenderer(FontFamily &fontfamily, RGBAf color=1.f, TextShadow shadow={})
Definition: HTMLRenderer.h:100
HTMLRenderer.h
Gorgon::Graphics::FontFamily::Style::Custom
@ Custom
TextureTargets.h
Gorgon::Graphics::GlyphRenderer::GetCursorAdvance
virtual float GetCursorAdvance(Glyph g) const =0
This function should return the number of pixels the cursor should advance after this glyph.
Gorgon::Graphics::internal::ActivateQuadVertices
void ActivateQuadVertices()
Definition: Graphics.cpp:23
Gorgon::Scripting::Tag
Tag
Tags define behavior of reflection objects.
Definition: Reflection.h:54
Gorgon::Graphics::FontFamily
Definition: HTMLRenderer.h:32
Gorgon::Graphics::HTMLRenderer
Definition: HTMLRenderer.h:98
Gorgon::Geometry::basic_Size::Height
T_ Height
Height of this size object.
Definition: Size.h:261
glVertexAttribIPointer
PFNGLVERTEXATTRIBIPOINTERPROC glVertexAttribIPointer
Definition: OpenGL.cpp:68
Gorgon::Graphics::FontFamily::Style
Style
Definition: HTMLRenderer.h:34
Gorgon::Graphics::FontFamily::FontFamily
FontFamily(const std::unordered_map< Style, GlyphRenderer *, HashType > fonts)
Definition: HTMLRenderer.h:49
Gorgon::Graphics::GlyphRenderer
Should be implemented by the systems aimed to render fonts on the screen.
Definition: Font.h:67
Gorgon::Graphics::RGBAf
Represents a four channel 32 bit float per channel color information.
Definition: Color.h:373
Gorgon::GL::LoadFunctions
void LoadFunctions()
Definition: OpenGL.cpp:281
Gorgon::Graphics::FontFamily::GetGlyphRenderer
GlyphRenderer * GetGlyphRenderer(Style style)
Definition: HTMLRenderer.h:52
Gorgon::Graphics::TextShadow
Describes how a text shadow should be.
Definition: Font.h:432
Gorgon::Geometry::Size
basic_Size< int > Size
Definition: Size.h:385
Font.h
Gorgon::Animation::log
Utils::Logger log
Definition: Animation.cpp:11
Color.h
Gorgon::Graphics::internal::decode
Glyph decode(std::string::const_iterator &it, std::string::const_iterator end)
Decodes a utf-8 character from the given iterator.
Definition: Font.cpp:9
HR_BTWSOR_TAG_ATTR_PAIR
#define HR_BTWSOR_TAG_ATTR_PAIR(tag, attribute)
Definition: HTMLRenderer.h:21
glEnableVertexAttribArray
PFNGLENABLEVERTEXATTRIBARRAYPROC glEnableVertexAttribArray
Definition: OpenGL.cpp:40
glGenBuffers
PFNGLGENBUFFERSPROC glGenBuffers
Definition: OpenGL.cpp:41
Gorgon::Graphics::internal::isspace
bool isspace(Glyph g)
Definition: Font.cpp:96
Gorgon::Graphics::StyledRenderer::GetGlyphRenderer
GlyphRenderer & GetGlyphRenderer()
Definition: Font.h:472
Gorgon::Graphics::FontFamily::Style::End
@ End
HR_LOG_ERROR
#define HR_LOG_ERROR(string)
Definition: HTMLRenderer.h:17
Gorgon
Root namespace for Gorgon Game Engine.
Definition: Any.h:19
Gorgon::Graphics::FontFamily::Style::Normal
@ Normal
ASSERT
#define ASSERT(expression, message,...)
Replaces regular assert to allow messages and backtrace.
Definition: Assert.h:161
Gorgon::Utils::Logger
Eases logging procedure by appending necessary information to the given data and streams to a standar...
Definition: Logging.h:19
Gorgon::Graphics::internal::DrawQuadVertices
void DrawQuadVertices()
Definition: Graphics.cpp:32
Gorgon::Geometry::Point
basic_Point< int > Point
Definition: Point.h:598
Gorgon::Graphics::internal::quadvbo
GLuint quadvbo
Definition: Graphics.cpp:20
Gorgon::Geometry::Pointf
basic_Point< Float > Pointf
Definition: Point.h:601
Gorgon::Geometry::Bounds
basic_Bounds< int > Bounds
Definition: Bounds.h:722
Gorgon::Graphics::TextureTarget
This interface defines a class that can be used as a common target for texture based drawing.
Definition: TextureTargets.h:12
Gorgon::Graphics::internal::LastTexture
GL::Texture LastTexture
Definition: Graphics.cpp:13
Gorgon::Graphics::internal::vaos
std::map< decltype(WindowManager::CurrentContext()), GLuint > vaos
Definition: Graphics.cpp:21
Gorgon::Graphics::FontFamily::Style::Bold
@ Bold
Gorgon::Graphics::FontFamily::HashType
Definition: HTMLRenderer.h:43
Gorgon::Graphics::Initialize
void Initialize()
Initializes Graphics module, should be performed after an OpenGL context is created.
Definition: Graphics.cpp:37
Gorgon::Byte
unsigned char Byte
Represents smallest cell in memory.
Definition: Types.h:9
HR_LOG_NOTICE
#define HR_LOG_NOTICE(string)
Definition: HTMLRenderer.h:18
Gorgon::Graphics::FontFamily::HasFont
bool HasFont(Style style) const
Definition: HTMLRenderer.h:89
Gorgon::UI::Graphics
@ Graphics
Definition: Template.h:164
Gorgon::Geometry::basic_Size::Width
T_ Width
Width of this size object.
Definition: Size.h:258
Gorgon::Graphics::FontFamily::AddFont
void AddFont(Style style, GlyphRenderer *renderer)
Definition: HTMLRenderer.h:81
Gorgon::end
std::vector< T_ >::const_iterator end(enum_type_id< T_ >)
Definition: Enum.h:288
glBufferData
PFNGLBUFFERDATAPROC glBufferData
Definition: OpenGL.cpp:30
Gorgon::Graphics::FontFamily::Style::Italic
@ Italic
Gorgon::Graphics::FontFamily::Style::Large
@ Large
Gorgon::Graphics::FontFamily::HashType::operator()
unsigned int operator()(Style style) const
Definition: HTMLRenderer.h:44
Gorgon::WindowManager::CurrentContext
intptr_t CurrentContext()
Returns an identifier for the current context.
Definition: WindowManager.cpp:34
Gorgon::ScreenSize
Geometry::Size ScreenSize
Definition: Window.cpp:15
Gorgon::Graphics::TextureSource::fullcoordinates
static const Geometry::Pointf fullcoordinates[4]
Coordinates that selects the entire texture to be used.
Definition: Graphics.h:501
Gorgon::Graphics::internal::quadvertexindex
int quadvertexindex[]
Definition: Graphics.cpp:15
Gorgon::Graphics::HTMLRenderer::Print
void Print(TextureTarget &target, const std::string &text, int x, int y)
Definition: HTMLRenderer.h:118