1 /** 2 * Copyright © Novelate 2020 3 * License: MIT (https://github.com/Novelate/NovelateEngine/blob/master/LICENSE) 4 * Author: Jacob Jensen (bausshf) 5 * Website: https://novelate.com/ 6 * ------ 7 * Novelate is a free and open-source visual novel engine and framework written in the D programming language. 8 * It can be used freely for both personal and commercial projects. 9 * ------ 10 * Module Description: 11 * An image component allows for images to be rendered with a set of extra features and flexibility such as fading etc. 12 */ 13 module novelate.imagecomponent; 14 15 import std.conv : to; 16 17 import dsfml.graphics : Sprite, Image, Texture, RenderWindow, Color; 18 import dsfml.system : Vector2f, Vector2u; 19 20 import novelate.component; 21 22 /// Wrapepr around an image component. 23 final class ImageComponent : Component 24 { 25 private: 26 /// The image. 27 Image _image; 28 /// The texture. 29 Texture _texture; 30 /// The sprite. 31 Sprite _sprite; 32 /// Boolean determining whether the image is full-screen or not. 33 bool _fullScreen; 34 /// The alpha channel. 35 ubyte _alpha; 36 /// The current fade-in amount. 37 ubyte _fadingIn; 38 /// The current fade-out amount. 39 ubyte _fadingOut; 40 41 public: 42 final: 43 /** 44 * Creates a new image component. 45 * Params: 46 * path = The path of the image. 47 */ 48 this(string path) 49 { 50 _image = new Image(); 51 _image.loadFromFile(to!string(path)); 52 53 _texture = new Texture(); 54 _texture.loadFromImage(_image); 55 _texture.setSmooth(true); 56 57 _sprite = new Sprite(_texture); 58 _sprite.position = Vector2f(0, 0); 59 _alpha = 255; 60 61 super(_sprite.getLocalBounds().width, _sprite.getLocalBounds().height); 62 } 63 64 @property 65 { 66 /// Gets the raw image size. 67 Vector2u rawImageSize() { return _image.getSize(); } 68 69 /// Gets a boolean determining whether the image is full-screen or not. 70 bool fullScreen() { return _fullScreen; } 71 72 /// Sets a boolean determining whether the image is full-screen or not. 73 void fullScreen(bool isFullScreen) 74 { 75 _fullScreen = isFullScreen; 76 } 77 /// Gets the alpha channel. 78 ubyte alpha() { return _alpha; } 79 /// Sets the alpha channel. 80 void alpha(ubyte newAlpha) 81 { 82 _alpha = newAlpha; 83 84 _sprite.color = Color(255, 255, 255, _alpha); 85 } 86 } 87 88 /// A handler for when the image has faded out. 89 void delegate() fadedOut; 90 /// A handler for when the image has faded in. 91 void delegate() fadedIn; 92 /// A handler for when the image is fading out. 93 void delegate(ubyte) fadingOut; 94 /// A handler for when the image is fading in. 95 void delegate(ubyte) fadingIn; 96 97 /** 98 * Fades out the image. 99 * Params: 100 * speed = The speed at which the image will fade. 101 */ 102 void fadeOut(ubyte speed) 103 { 104 if (_fadingOut) 105 { 106 return; 107 } 108 109 _fadingIn = 0; 110 _fadingOut = speed; 111 alpha = 255; 112 } 113 114 /** 115 * Fades in the image. 116 * Params: 117 * speed = The speed at which the image will fade. 118 */ 119 void fadeIn(ubyte speed) 120 { 121 if (_fadingIn) 122 { 123 return; 124 } 125 126 _fadingOut = 0; 127 _fadingIn = speed; 128 alpha = 0; 129 } 130 131 /// See: Component.render() 132 override void render(RenderWindow window) 133 { 134 if (_sprite) 135 { 136 ptrdiff_t oldAlpha = cast(ptrdiff_t)_alpha; 137 138 if (_fadingIn && oldAlpha < 255) 139 { 140 oldAlpha += _fadingIn; 141 142 if (fadingIn) 143 { 144 fadingIn(cast(ubyte)oldAlpha); 145 } 146 147 if (oldAlpha >= 255) 148 { 149 oldAlpha = 255; 150 151 if (fadedIn) 152 { 153 fadedIn(); 154 } 155 } 156 157 alpha = cast(ubyte)oldAlpha; 158 } 159 else if (_fadingOut && _alpha > 0) 160 { 161 oldAlpha -= _fadingOut; 162 163 if (fadingOut) 164 { 165 fadingOut(cast(ubyte)oldAlpha); 166 } 167 168 if (oldAlpha <= 0) 169 { 170 oldAlpha = 0; 171 172 if (fadedOut) 173 { 174 fadedOut(); 175 } 176 } 177 178 alpha = cast(ubyte)oldAlpha; 179 } 180 181 window.draw(_sprite); 182 } 183 } 184 185 /// See: Component.refresh() 186 override void refresh(size_t width, size_t height) 187 { 188 if (!_fullScreen) 189 { 190 return; 191 } 192 193 _sprite.scale = 194 Vector2f 195 ( 196 cast(int)width / _sprite.getLocalBounds().width, 197 cast(int)height / _sprite.getLocalBounds().height 198 ); 199 } 200 201 /// See: Component.updateSize() 202 override void updateSize() 203 { 204 if (_fullScreen) 205 { 206 return; 207 } 208 209 _sprite.scale = 210 Vector2f 211 ( 212 cast(int)super.width / _sprite.getLocalBounds().width, 213 cast(int)super.height / _sprite.getLocalBounds().height 214 ); 215 } 216 217 /// See: Component.fitToSize() 218 void fitToSize(double maxWidth, double maxHeight, bool enlarge = false) 219 { 220 import std.math : fmin, round; 221 222 auto src = super.size; 223 224 maxWidth = enlarge ? cast(double)maxWidth : fmin(maxWidth, cast(double)src.x); 225 maxHeight = enlarge ? cast(double)maxHeight : fmin(maxHeight, cast(double)src.y); 226 227 double rnd = fmin(maxWidth / cast(double)src.x, maxHeight / cast(double)src.y); 228 229 auto newWidth = round(src.x * rnd); 230 auto newHeight = round(src.y * rnd); 231 232 super.size = Vector2f(newWidth, newHeight); 233 } 234 235 /// See: Component.updatePosition() 236 override void updatePosition() 237 { 238 _sprite.position = super.position; 239 } 240 }