1 ///////////////////////////////////////////////////////////////////////////////
2 //            Copyright (C) 2004-2011 by The Allacrost Project
3 //            Copyright (C) 2012-2016 by Bertram (Valyria Tear)
4 //                         All Rights Reserved
5 //
6 // This code is licensed under the GNU GPL version 2. It is free software
7 // and you may modify it and/or redistribute it under the terms of this license.
8 // See http://www.gnu.org/copyleft/gpl.html for details.
9 ///////////////////////////////////////////////////////////////////////////////
10 
11 /** ****************************************************************************
12 *** \file    text.h
13 *** \author  Lindsay Roberts, linds@allacrost.org
14 *** \author  Yohann Ferreira, yohann ferreira orange fr
15 *** \brief   Header file for text rendering
16 ***
17 *** This code makes use of the SDL_ttf font library for representing fonts,
18 *** font glyphs, and text.
19 *** ***************************************************************************/
20 
21 #ifndef __TEXT_HEADER__
22 #define __TEXT_HEADER__
23 
24 #include "engine/video/image.h"
25 
26 #include "utils/singleton.h"
27 #include "utils/ustring.h"
28 
29 #include <map>
30 
31 typedef struct _TTF_Font TTF_Font;
32 
33 namespace vt_video
34 {
35 
36 class TextSupervisor;
37 
38 //! \brief The singleton pointer for the instance of the text supervisor
39 extern TextSupervisor *TextManager;
40 
41 
42 //! \brief Styles for setting the type of text shadows.
43 enum TEXT_SHADOW_STYLE {
44     VIDEO_TEXT_SHADOW_INVALID = -1,
45 
46     //! \brief No text shadow is drawn, even if shadows are enabled.
47     VIDEO_TEXT_SHADOW_NONE = 0,
48     //! \brief Shadowed area is darkened (this is the default).
49     VIDEO_TEXT_SHADOW_DARK = 1,
50     //! \brief Shadowed area is lightened.
51     VIDEO_TEXT_SHADOW_LIGHT = 2,
52     //! \brief Shadowed area is completely black.
53     VIDEO_TEXT_SHADOW_BLACK = 3,
54     //! \brief Shadowed area is the same color of the text, but has less alpha.
55     VIDEO_TEXT_SHADOW_COLOR = 4,
56     //! \brief Shadowed area is the inverse of the text's color (e.g. white text, black shadow).
57     VIDEO_TEXT_SHADOW_INVCOLOR = 5,
58 
59     VIDEO_TEXT_SHADOW_TOTAL = 6
60 };
61 
62 /** ****************************************************************************
63 *** \brief A class which holds properties about fonts
64 *** ***************************************************************************/
65 class FontProperties
66 {
67 public:
68     FontProperties();
69     ~FontProperties();
70 
71     //! \brief Clears out the font object.
72     //! Useful when changing a TextStyle font without deleting
73     //! the font properties object.
74     void ClearFont();
75 
76     //! \brief The maximum height of all of the glyphs for this font.
77     int32_t height;
78 
79     //! \brief SDL_ttf's recommended amount of spacing between lines.
80     int32_t line_skip;
81 
82     //! \brief The height above and below baseline of font
83     int32_t ascent, descent;
84 
85     //! \brief A pointer to SDL_TTF's font structure.
86     TTF_Font* ttf_font;
87 
88     //! \brief Used to know the font currently used.
89     std::string font_filename;
90 
91     //! \brief Used to know the font size currently used.
92     uint32_t font_size;
93 
94 private:
95     //! \brief The copy constructor and assignment operator are hidden by design
96     //! to cause compilation errors when attempting to copy or assign this class.
97     FontProperties(const FontProperties& font_properties);
98     FontProperties& operator=(const FontProperties& font_properties);
99 };
100 
101 /** ****************************************************************************
102 *** \brief A class encompassing all properties that define a text style
103 ***
104 *** The TextSupervisor class maintains a TextStyle object that serves as the
105 *** default style. The various constructors for the TextStyle class will use the
106 *** properties of the default text style when they are not provided with the
107 *** information to initialize all of the class members.
108 *** ***************************************************************************/
109 class TextStyle
110 {
111 public:
112     //! \brief No-arg constructor will set all members to the same value as the current default text style.
113     //! Special empty TextStyle to permit a default initialization in the TextSupervisor.
TextStyle()114     TextStyle():
115         _shadow_style(VIDEO_TEXT_SHADOW_NONE),
116         _shadow_offset_x(0),
117         _shadow_offset_y(0),
118         _font_property(nullptr)
119     {
120     }
121 
122     //! \brief Constructor requiring a font name only.
123     explicit TextStyle(const std::string& font);
124 
125     //! \brief Constructor requiring a text color only.
126     explicit TextStyle(const Color& color);
127 
128     //! \brief Constructor requiring a shadow style only.
129     explicit TextStyle(TEXT_SHADOW_STYLE style);
130 
131     //! \brief Constructor requiring a font name and text color.
132     TextStyle(const std::string& font, const Color& color);
133 
134     //! \brief Constructor requiring a font name and shadow style.
135     TextStyle(const std::string& font, TEXT_SHADOW_STYLE style);
136 
137     //! \brief Constructor requiring a text color and shadow style.
138     TextStyle(const Color& color, TEXT_SHADOW_STYLE style);
139 
140     //! \brief Constructor requiring a font name, color, and shadow style.
141     TextStyle(const std::string& font, const Color& color, TEXT_SHADOW_STYLE style);
142 
143     //! \brief Full constructor requiring initialization data arguments for all class members.
144     TextStyle(const std::string& font, const Color& color, TEXT_SHADOW_STYLE style, int32_t shadow_x, int32_t shadow_y);
145 
146     //! \brief Sets the font name and updates the font properties.
147     void SetFont(const std::string& font);
148 
149     //! \brief Sets the font name and updates the font properties.
SetColor(const Color & color)150     void SetColor(const Color& color) {
151         _color = color;
152         _UpdateTextShadowColor();
153     }
154 
155     //! \brief Sets the shadow style.
SetShadowStyle(TEXT_SHADOW_STYLE shadow_style)156     void SetShadowStyle(TEXT_SHADOW_STYLE shadow_style) {
157         _shadow_style = shadow_style;
158         _UpdateTextShadowColor();
159     }
160 
161     //! \brief Sets the shadow offsets from the given text.
SetShadowOffsets(int32_t xoffset,int32_t yoffset)162     void SetShadowOffsets(int32_t xoffset, int32_t yoffset) {
163         _shadow_offset_x = xoffset;
164         _shadow_offset_y = yoffset;
165     }
166 
167     //! \brief Returns the font property pointer value.
GetFontProperties()168     FontProperties* GetFontProperties() const {
169         return _font_property;
170     }
171 
GetFontName()172     const std::string& GetFontName() const {
173         return _font;
174     }
175 
GetColor()176     const Color& GetColor() const {
177         return _color;
178     }
179 
GetShadowColor()180     const Color& GetShadowColor() const {
181         return _shadow_color;
182     }
183 
GetShadowStyle()184     TEXT_SHADOW_STYLE GetShadowStyle() const {
185         return _shadow_style;
186     }
187 
GetShadowOffsetX()188     int32_t GetShadowOffsetX() const {
189         return _shadow_offset_x;
190     }
191 
GetShadowOffsetY()192     int32_t GetShadowOffsetY() const {
193         return _shadow_offset_y;
194     }
195 
196 private:
197     //! \brief The string font name
198     std::string _font;
199 
200     //! \brief The color of the text
201     Color _color;
202 
203     //! \brief The enum representing the shadow style.
204     TEXT_SHADOW_STYLE _shadow_style;
205     //! \brief The shadow color corresponding to the current color and shadow style.
206     Color _shadow_color;
207 
208     //! \brief The x and y offsets of the shadow.
209     int32_t _shadow_offset_x;
210     int32_t _shadow_offset_y;
211 
212     //! \brief A pointer to the FontProperty object.
213     //! This acts as reference cache, thus it must not be deleted here!
214     FontProperties* _font_property;
215 
216     //! \brief Updates the shadow color to correspond to the current color and shadow style.
217     void _UpdateTextShadowColor();
218 };
219 
220 namespace private_video
221 {
222 
223 /** ****************************************************************************
224 *** \brief Represents an image of rendered text stored in a texture sheet
225 ***
226 *** A text specific class derived from the BaseImage class, it contains a
227 *** unicode string and text style needed to render a piece of text.
228 *** ***************************************************************************/
229 class TextTexture : public private_video::BaseTexture
230 {
231 public:
232     /** \brief Constructor defaults image as the first one in a texture sheet.
233     *** \note The actual sheet where the image is located will be determined later.
234     **/
235     TextTexture(const vt_utils::ustring &string_, const TextStyle &style_);
236 
237     ~TextTexture();
238 
239     // ---------- Public members
240 
241     //! \brief The string represented
242     vt_utils::ustring string;
243 
244     //! \brief The text style of the rendered string
245     TextStyle style;
246 
247     // ---------- Public methods
248 
249     //! \brief Generate a text texture and add to a texture sheet
250     bool Regenerate();
251 
252     //! \brief Reload texture to an already assigned texture sheet
253     bool Reload();
254 
255 private:
256     TextTexture(const TextTexture &copy);
257     TextTexture &operator=(const TextTexture &copy);
258 }; // class TextTexture : public private_video::BaseImage
259 
260 
261 /** ****************************************************************************
262 *** \brief An element used as a portion of a full rendered block of text.
263 ***
264 *** This class represents a block (usually a single line) of rendered text that
265 *** is stored by the TextImage class as a portion, or element, that makes up
266 *** a rendered block of text. This class managed a pointer to a TextTexture
267 *** object that refers to the rendered line of text as it is stored in texture
268 *** memory.
269 *** ***************************************************************************/
270 class TextElement : public ImageDescriptor
271 {
272 public:
273     TextElement();
274 
275     explicit TextElement(TextTexture* texture);
276 
277     virtual ~TextElement() override;
278 
279     // ---------- Public members
280 
281     //! \brief The image that is being referenced by this object.
282     TextTexture *text_texture;
283 
284     // ---------- Public methods
285 
286     void Clear() override;
287 
288     void Draw() const;
289 
290     void Draw(const Color& draw_color) const override;
291 
292     /** \brief Sets the texture used by the class and modifies the width and height members
293     *** \param texture A pointer to the TextTexture object that this class object should manage
294     ***
295     *** Because it is rare that the user needs to define a custom width/height for the text (since
296     *** scaled text looks so poor), this function also automatically sets the _width and _height members
297     *** to the translated value of the width and height of the TextTexture in the current coordinate system
298     *** (current context) in which this function call is made. Passing a nullptr argument will deallocate any
299     *** texture resources and set the width/height to zero.
300     ***
301     *** \note This function will invoke the AddReference() method for the argument object if it is not nullptr.
302     **/
303     void SetTexture(TextTexture *texture);
304 
SetStatic(bool is_static)305     void SetStatic(bool is_static) override {
306         _is_static = is_static;
307     }
308 
SetWidth(float width)309     void SetWidth(float width) override {
310         _width = width;
311     }
312 
SetHeight(float height)313     void SetHeight(float height) override {
314         _height = height;
315     }
316 
SetDimensions(float width,float height)317     void SetDimensions(float width, float height) override {
318         SetWidth(width);
319         SetHeight(height);
320     }
321 
322 private:
_EnableGrayscale()323     void _EnableGrayscale() override
324     {}
325 
_DisableGrayscale()326     void _DisableGrayscale() override
327     {}
328 };
329 
330 } // namespace private_video
331 
332 /** ****************************************************************************
333 *** \brief Represents a rendered text string
334 *** TextImage is a compound image containing each line of a text string.
335 *** ***************************************************************************/
336 class TextImage : public ImageDescriptor
337 {
338     friend class VideoEngine;
339 public:
340     //! \brief Construct empty text object
341     TextImage();
342 
343     //! \brief Constructs rendered string of specified ustring
344     explicit TextImage(const vt_utils::ustring& text, const TextStyle& style = TextStyle());
345 
346     //! \brief Constructs rendered string of specified std::string
347     explicit TextImage(const std::string& text, const TextStyle& style = TextStyle());
348 
349     //! \brief Destructs TextImage, lowering reference counts on all contained timages.
~TextImage()350     virtual ~TextImage() override {
351         Clear();
352     }
353 
354     TextImage(const TextImage &copy);
355     TextImage &operator=(const TextImage &copy);
356 
357     // ---------- Public methods
358 
359     //! \brief Clears the image by resetting its properties
360     void Clear() override;
361 
362     /** \brief Draws the rendered text to the screen with a color modulation
363     *** \param draw_color The color to modulate the text by
364     **/
365     void Draw(const Color &draw_color = vt_video::Color::white) const override;
366 
367     //! \brief Sets image to static/animated
SetStatic(bool is_static)368     virtual void SetStatic(bool is_static) override {
369         _is_static = is_static;
370     }
371 
372     //! \brief Sets width of the image
SetWidth(float width)373     virtual void SetWidth(float width) override {
374         _width = width;
375     }
376 
377     //! \brief Sets height of the image
SetHeight(float height)378     virtual void SetHeight(float height) override {
379         _height = height;
380     }
381 
382     //! \brief Sets the dimensions (width + height) of the image.
SetDimensions(float width,float height)383     virtual void SetDimensions(float width, float height) override {
384         _width  = width;
385         _height = height;
386     }
387 
388     //! \brief Sets the color for the image (for all four verteces).
SetColor(const Color & color)389     void SetColor(const Color &color) override {
390         _color[0] = _color[1] = _color[2] = _color[3] = color;
391     }
392 
393     /** \brief Sets individual vertex colors in the image.
394     *** \param tl top left vertex color
395     *** \param tr top right vertex color
396     *** \param bl bottom left vertex color
397     *** \param br bottom right vertex color
398     **/
SetVertexColors(const Color & tl,const Color & tr,const Color & bl,const Color & br)399     void SetVertexColors(const Color& tl, const Color& tr, const Color& bl, const Color& br) override {
400         _color[0] = tl;
401         _color[1] = tr;
402         _color[2] = bl;
403         _color[3] = br;
404     }
405 
406     //! \brief Sets the text contained
SetText(const vt_utils::ustring & text)407     void SetText(const vt_utils::ustring& text) {
408         // Don't do anything if it's the same text
409         if (_text == text)
410             return;
411 
412         _text = text;
413         _Regenerate();
414     }
415 
SetText(const vt_utils::ustring & text,const TextStyle & text_style)416     void SetText(const vt_utils::ustring& text, const TextStyle& text_style) {
417         _text = text;
418         _style = text_style;
419         _Regenerate();
420     }
421 
422     //! \brief Sets the text (std::string version)
SetText(const std::string & text)423     void SetText(const std::string& text) {
424         SetText(vt_utils::MakeUnicodeString(text));
425     }
426 
427     //! \brief Sets the texts style - regenerating text if present.
SetStyle(const TextStyle & style)428     void SetStyle(const TextStyle& style) {
429         _style = style;
430         _Regenerate();
431     }
432 
SetText(const std::string & text,const TextStyle & text_style)433     void SetText(const std::string& text, const TextStyle& text_style) {
434         SetText(vt_utils::MakeUnicodeString(text), text_style);
435     }
436 
437     //! \brief Set the maximum permitted width to the text image
438     //! It will auto wrap and use more height intead when modified.
439     void SetWordWrapWidth(uint32_t width);
440 
441     //! \name Class Member Access Functions
442     //@{
GetString()443     const vt_utils::ustring& GetString() const {
444         return _text;
445     }
446 
GetStyle()447     TextStyle GetStyle() const {
448         return _style;
449     }
450 
GetWidth()451     virtual float GetWidth() const override {
452         return _width;
453     }
454 
GetWordWrapWidth()455     uint32_t GetWordWrapWidth() const {
456         return _max_width;
457     }
458     //@}
459 
460 private:
461     //! \brief The unicode string of the text to render
462     vt_utils::ustring _text;
463 
464     //! \brief The style to render the text in
465     TextStyle _style;
466 
467     //! \brief The text max width, used for word wrapping
468     uint32_t _max_width;
469 
470     //! \brief The TextTexture elements representing rendered text portions, usually lines.
471     std::vector<private_video::TextElement *> _text_sections;
472 
473     // ---------- Private methods
474 
475     //! \brief Regenerates the texture images for the text
476     void _Regenerate();
477 
478     //! \brief Dervied from ImageDescriptor, this method is not used by TextImage
_EnableGrayscale()479     void _EnableGrayscale() override
480     {}
481 
482     //! \brief Dervied from ImageDescriptor, this method is not used by TextImage
_DisableGrayscale()483     void _DisableGrayscale() override
484     {}
485 };
486 
487 
488 /** ****************************************************************************
489 *** \brief A helper class to the video engine to manage all text rendering
490 ***
491 *** This class is a singleton and it is both created and destroyed by the VideoEngine
492 *** class. TextSupervisor is essentially an extension of the VideoEngine singleton
493 *** class which handles all font and text related operations.
494 ***
495 *** \note The singleton name of this class is "TextManager"
496 ***
497 *** \note When the API user needs to access methods of this class, the recommended
498 *** way for doing so is to call "VideoManager->Text()->MethodName()".
499 *** VideoManager->Text() returns the singleton pointer to this class.
500 *** ***************************************************************************/
501 class TextSupervisor : public vt_utils::Singleton<TextSupervisor>
502 {
503     friend class vt_utils::Singleton<TextSupervisor>;
504     friend class VideoEngine;
505     friend class TextureController;
506     friend class private_video::TextTexture;
507     friend class TextImage;
508     friend class TextStyle;
509 
510 public:
511     ~TextSupervisor();
512 
513     /** \brief Initializes the SDL_ttf library
514     *** \return True if all initializations were successful, or false if there was an error
515     **/
516     bool SingletonInitialize();
517 
518     /** \brief Loads or reloads font needed by the given locale (ex: fr, it, ru, ...)
519     *** using the font script filename: "data/config/fonts.lua"
520     *** \return false in case of an error.
521     **/
522     bool LoadFonts(const std::string& locale_name);
523     //@}
524 
525     //! \name Text methods
526     //@{
527     /** \brief Renders and draws a unicode string of text to the screen in the default text style
528     *** \param text The text string to draw in unicode format
529     **/
Draw(const vt_utils::ustring & text)530     inline void Draw(const vt_utils::ustring &text) {
531         Draw(text, _default_style);
532     }
533 
534     /** \brief Renders and draws a string of text to the screen in a desired text style
535     *** \param text The text string to draw in unicode format
536     *** \param style A reference to the TextStyle to use for drawing the string
537     **/
538     void Draw(const vt_utils::ustring &text, const TextStyle &style);
539 
540     /** \brief Renders and draws a standard string of text to the screen in the default text style
541     *** \param text The text string to draw in standard format
542     **/
Draw(const std::string & text)543     inline void Draw(const std::string &text) {
544         Draw(vt_utils::MakeUnicodeString(text));
545     }
546 
547     /** \brief Renders and draws a standard string of text to the screen in a desired text style
548     *** \param text The text string to draw in standard format
549     *** \param style A reference to the TextStyle to use for drawing the string
550     **/
Draw(const std::string & text,const TextStyle & style)551     inline void Draw(const std::string &text, const TextStyle &style) {
552         Draw(vt_utils::MakeUnicodeString(text), style);
553     }
554 
555     /** \brief Calculates what the width would be for a unicode string of text if it were rendered
556     *** \param ttf_font The True Type SDL font object
557     *** \param text The text string in unicode format
558     *** \return The width of the text as it would be rendered, or -1 if there was an error
559     **/
560     int32_t CalculateTextWidth(TTF_Font* ttf_font, const vt_utils::ustring& text);
561 
562     /** \brief Calculates what the width would be for a standard string of text if it were rendered
563     *** \param ttf_font The True Type SDL font object
564     *** \param text The text string in standard format
565     *** \return The width of the text as it would be rendered, or -1 if there was an error
566     **/
567     int32_t CalculateTextWidth(TTF_Font* ttf_font, const std::string& text);
568 
569     /** \brief Returns the text as a vector of lines which text width is inferior or equal to the given pixel max width.
570     *** \param text The ustring text
571     *** \param ttf_font The True Type SDL font object
572     **/
573     std::vector<vt_utils::ustring> WrapText(const vt_utils::ustring& text, TTF_Font* ttf_font, uint32_t max_width);
574     //@}
575 
576     //! \name Class member access methods
577     //@{
GetDefaultStyle()578     const TextStyle &GetDefaultStyle() const {
579         return _default_style;
580     }
581 
SetDefaultStyle(const TextStyle & style)582     void SetDefaultStyle(const TextStyle& style) {
583         _default_style = style;
584     }
585     //@}
586 
587 private:
588     TextSupervisor();
589 
590     // ---------- Private members
591 
592     //! \brief A texture used to draw text to the screen.
593     GLuint _text_texture;
594 
595     //! \brief The text texture's width.
596     GLuint _text_texture_width;
597 
598     //! \brief The text texture's height.
599     GLuint _text_texture_height;
600 
601     //! \brief The default text style
602     TextStyle _default_style;
603 
604     /** \brief A container for properties for each font which has been loaded
605     *** The key to the map is the font name.
606     **/
607     std::map<std::string, FontProperties *> _font_map;
608 
609     /** \brief Loads or Reloads a font file from disk with a specific size and name
610     *** \param Text style name The name which to refer to the text style after it is loaded
611     *** \param font_filename The filename of the TTF font filename to load
612     *** \param size The point size to set the font after it is loaded
613     *** \return True if the font was successfully loaded, or false if there was an error
614     **/
615     bool _LoadFont(const std::string& textstyle_name, const std::string& font_filename, uint32_t size);
616 
617     /** \brief Removes a loaded font from memory and frees up associated resources
618     *** \param font_name The reference name of the font to unload
619     ***
620     *** If the argument name is invalid (i.e. no font with that reference name exists), this method will do
621     *** nothing more than print out a warning message if running in debug mode.
622     ***
623     *** \todo Implement this function. Its not available yet because of potential problems with lingering references to the
624     *** font (in TextStyle objects, or elswhere)
625     **/
626     void _FreeFont(const std::string &font_name);
627 
628     /** \brief Renders a unicode string to the screen.
629     *** \param text A pointer to a unicode string to draw.
630     *** \param font_properties A pointer to the properties of the font to use in drawing the text.
631     *** \param color The color to render the text in.
632     ***
633     *** This method is intended for drawing only a single line of text.
634     **/
635     void _RenderText(const uint16_t* text, FontProperties* font_properties, const Color& color);
636 
637     /** \brief Renders a unicode, shadowed string to the screen.
638     *** \param text A pointer to a unicode string to draw.
639     *** \param font_properties A pointer to the properties of the font to use in drawing the text.
640     *** \param color The color to render the text in.
641     *** \param shadow_offset_x The X offset for the text's shadow.
642     *** \param shadow_offset_y The Y offset for the text's shadow.
643     *** \param color_shadow The color to render the text's shadow in.
644     ***
645     *** This method is intended for drawing only a single line of text.
646     **/
647     void _RenderText(const uint16_t* text, FontProperties* font_properties,
648                      const Color& color,
649                      float shadow_offset_x, float shadow_offset_y,
650                      const Color& color_shadow);
651 
652     /** \brief Renders a unicode string to a pixel array.
653     *** \param text The unicdoe string to render.
654     *** \param style The text style to render the string in.
655     *** \param buffer A reference to the pixel array where to place the rendered string into.
656     *** \return True if the string was rendered successfully, or false if it was not.
657     **/
658     bool _RenderText(const vt_utils::ustring& text, TextStyle& style, private_video::ImageMemory& buffer);
659 
660     /** \brief Returns true if a font of a certain reference name exists
661     *** \param font_name The reference name of the font to check
662     *** \return True if font name is valid, false if it is not.
663     **/
_IsFontValid(const std::string & font_name)664     bool _IsFontValid(const std::string& font_name) {
665         return (_font_map.find(font_name) != _font_map.end());
666     }
667 
668     /** \brief Get the font properties for a loaded font
669     *** \param font_name The name reference of the loaded font
670     *** \return A pointer to the FontProperties object with the requested data, or nullptr if the properties could not be fetched
671     **/
672     FontProperties* _GetFontProperties(const std::string& font_name);
673 }; // class TextSupervisor : public vt_utils::Singleton
674 
675 }  // namespace vt_video
676 
677 #endif // __TEXT_HEADER__
678