1 /**
2  * Retrograde Engine
3  *
4  * Authors:
5  *  Mike Bierlee, m.bierlee@lostmoment.com
6  * Copyright: 2014-2021 Mike Bierlee
7  * License:
8  *  This software is licensed under the terms of the MIT license.
9  *  The full terms of the license can be found in the LICENSE.txt file.
10  */
11 
12 module retrograde.graphics.twodee.sdl2.text;
13 
14 version(Have_derelict_sdl2) {
15 
16 import retrograde.entity;
17 import retrograde.font;
18 import retrograde.graphics.twodee.sdl2.rendering;
19 import retrograde.file;
20 import retrograde.graphics.core;
21 import retrograde.stringid;
22 
23 import derelict.sdl2.ttf;
24 import derelict.sdl2.sdl;
25 
26 import poodinis;
27 
28 import std.typecons;
29 import std.string;
30 import std.conv;
31 import std.exception;
32 
33 class Sdl2TextProcessor : EntityProcessor {
34 
35     @Autowire
36     private Sdl2RenderSystem renderer;
37 
38     public override bool acceptsEntity(Entity entity) {
39         return entity.hasComponent!RenderableTextComponent
40             && entity.hasComponent!FontComponent
41             && entity.hasComponent!TextComponent
42             && entity.hasComponent!TextureComponent;
43     }
44 
45     public override void update() {
46         foreach(entity; _entities.getAll()) {
47             renderEntityText(entity);
48         }
49     }
50 
51     private void renderEntityText(Entity entity) {
52         entity.withComponent!TextComponent((component) {
53             if (component.isChanged()) {
54                 auto fontComponent = entity.getComponent!FontComponent;
55                 auto font = cast(Sdl2Font) fontComponent.font;
56                 if (font is null) {
57                     return;
58                 }
59 
60                 TTF_Font* ttfFont = font.ttfFont;
61                 SDL_Surface* surface = TTF_RenderUTF8_Blended(ttfFont, component.text.toStringz(), SDL_Color(255, 255, 255, 255));
62                 SDL_Texture* texture = renderer.createTextureFromSurface(surface);
63                 SDL_FreeSurface(surface);
64                 auto textureComponent = entity.getComponent!TextureComponent;
65                 // TODO: Free old texture?
66                 textureComponent.texture = new Sdl2Texture(texture, font.fontName);
67                 component.clearChanged();
68             }
69         });
70     }
71 
72 }
73 
74 class Sdl2Font : Font {
75     private TTF_Font* _ttfFont;
76 
77     public TTF_Font* ttfFont() {
78         return _ttfFont;
79     }
80 
81     this(TTF_Font* ttfFont, string fontName, uint pointSize, ulong index) {
82         super(fontName, pointSize, index);
83         this._ttfFont = ttfFont;
84     }
85 }
86 
87 class FontLoadException : Exception {
88     mixin basicExceptionCtors;
89 }
90 
91 class Sdl2FontComponentFactory : FontComponentFactory {
92     private FontComponent[Tuple!(string, uint, ulong)] fontComponentCache;
93 
94     public override FontComponent create(File fontFile, uint pointSize, ulong index = 0) {
95         auto key = tuple(fontFile.fileName, pointSize, index);
96         auto cachedComponent = key in fontComponentCache;
97         if (cachedComponent) {
98             return *cachedComponent;
99         }
100 
101         auto loadedFont = TTF_OpenFontIndex(fontFile.fileName.toStringz(), cast(int) pointSize, cast(int) index);
102         if (!loadedFont) {
103             throw new FontLoadException(format("Cannot load %s: %s", fontFile.fileName, to!string(TTF_GetError())));
104         }
105 
106         auto newComponent = new FontComponent(new Sdl2Font(loadedFont, fontFile.fileName, pointSize, index));
107         fontComponentCache[key] = newComponent;
108         return newComponent;
109     }
110 }
111 
112 }