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 novelate.component; 18 19 /// Wrapepr around an image component. 20 final class ImageComponent : Component 21 { 22 private: 23 /// The image. 24 ExternalImage _image; 25 /// Boolean determining whether the image is full-screen or not. 26 bool _fullScreen; 27 /// The alpha channel. 28 ubyte _alpha; 29 /// The current fade-in amount. 30 ubyte _fadingIn; 31 /// The current fade-out amount. 32 ubyte _fadingOut; 33 34 public: 35 final: 36 /** 37 * Creates a new image component. 38 * Params: 39 * path = The path of the image. 40 */ 41 this(string path) 42 { 43 _image = new ExternalImage(); 44 _image.loadFromFile(path); 45 _image.position = FloatVector(0, 0); 46 47 _alpha = 255; 48 49 auto bounds = _image.bounds; 50 51 super(bounds.x, bounds.y); 52 } 53 54 @property 55 { 56 /// Gets a boolean determining whether the image is full-screen or not. 57 bool fullScreen() { return _fullScreen; } 58 59 /// Sets a boolean determining whether the image is full-screen or not. 60 void fullScreen(bool isFullScreen) 61 { 62 _fullScreen = isFullScreen; 63 } 64 /// Gets the alpha channel. 65 ubyte alpha() { return _alpha; } 66 /// Sets the alpha channel. 67 void alpha(ubyte newAlpha) 68 { 69 _alpha = newAlpha; 70 71 _image.color = Paint(255, 255, 255, _alpha); 72 } 73 } 74 75 /// A handler for when the image has faded out. 76 void delegate() fadedOut; 77 /// A handler for when the image has faded in. 78 void delegate() fadedIn; 79 /// A handler for when the image is fading out. 80 void delegate(ubyte) fadingOut; 81 /// A handler for when the image is fading in. 82 void delegate(ubyte) fadingIn; 83 84 /** 85 * Fades out the image. 86 * Params: 87 * speed = The speed at which the image will fade. 88 */ 89 void fadeOut(ubyte speed) 90 { 91 if (_fadingOut) 92 { 93 return; 94 } 95 96 _fadingIn = 0; 97 _fadingOut = speed; 98 alpha = 255; 99 } 100 101 /** 102 * Fades in the image. 103 * Params: 104 * speed = The speed at which the image will fade. 105 */ 106 void fadeIn(ubyte speed) 107 { 108 if (_fadingIn) 109 { 110 return; 111 } 112 113 _fadingOut = 0; 114 _fadingIn = speed; 115 alpha = 0; 116 } 117 118 /// See: Component.render() 119 override void render(ExternalWindow window) 120 { 121 if (_image) 122 { 123 ptrdiff_t oldAlpha = cast(ptrdiff_t)_alpha; 124 125 if (_fadingIn && oldAlpha < 255) 126 { 127 oldAlpha += _fadingIn; 128 129 if (fadingIn) 130 { 131 fadingIn(cast(ubyte)oldAlpha); 132 } 133 134 if (oldAlpha >= 255) 135 { 136 oldAlpha = 255; 137 138 if (fadedIn) 139 { 140 fadedIn(); 141 } 142 } 143 144 alpha = cast(ubyte)oldAlpha; 145 } 146 else if (_fadingOut && _alpha > 0) 147 { 148 oldAlpha -= _fadingOut; 149 150 if (fadingOut) 151 { 152 fadingOut(cast(ubyte)oldAlpha); 153 } 154 155 if (oldAlpha <= 0) 156 { 157 oldAlpha = 0; 158 159 if (fadedOut) 160 { 161 fadedOut(); 162 } 163 } 164 165 alpha = cast(ubyte)oldAlpha; 166 } 167 168 _image.draw(window); 169 } 170 } 171 172 /// See: Component.refresh() 173 override void refresh(size_t width, size_t height) 174 { 175 if (!_fullScreen) 176 { 177 return; 178 } 179 180 auto bounds = _image.bounds; 181 182 _image.scale = 183 FloatVector 184 ( 185 cast(int)width / bounds.x, 186 cast(int)height / bounds.y 187 ); 188 } 189 190 /// See: Component.updateSize() 191 override void updateSize() 192 { 193 if (_fullScreen) 194 { 195 return; 196 } 197 198 auto bounds = _image.bounds; 199 200 _image.scale = 201 FloatVector 202 ( 203 cast(int)super.width / bounds.x, 204 cast(int)super.height / bounds.y 205 ); 206 } 207 208 /// See: Component.fitToSize() 209 void fitToSize(double maxWidth, double maxHeight, bool enlarge = false) 210 { 211 import std.math : fmin, round; 212 213 auto src = super.size; 214 215 maxWidth = enlarge ? cast(double)maxWidth : fmin(maxWidth, cast(double)src.x); 216 maxHeight = enlarge ? cast(double)maxHeight : fmin(maxHeight, cast(double)src.y); 217 218 double rnd = fmin(maxWidth / cast(double)src.x, maxHeight / cast(double)src.y); 219 220 auto newWidth = round(src.x * rnd); 221 auto newHeight = round(src.y * rnd); 222 223 super.size = FloatVector(newWidth, newHeight); 224 } 225 226 /// See: Component.updatePosition() 227 override void updatePosition() 228 { 229 _image.position = super.position; 230 } 231 }