1 /* 2 Copyright (c) 2019-2020 Timur Gafarov 3 4 Boost Software License - Version 1.0 - August 17th, 2003 5 Permission is hereby granted, free of charge, to any person or organization 6 obtaining a copy of the software and accompanying documentation covered by 7 this license (the "Software") to use, reproduce, display, distribute, 8 execute, and transmit the Software, and to prepare derivative works of the 9 Software, and to permit third-parties to whom the Software is furnished to 10 do so, all subject to the following: 11 12 The copyright notices in the Software and this entire statement, including 13 the above license grant, this restriction and the following disclaimer, 14 must be included in all copies of the Software, in whole or in part, and 15 all derivative works of the Software, unless such copies or derivative 16 works are solely in the form of machine-executable object code generated by 17 a source language processor. 18 19 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT 22 SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE 23 FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE, 24 ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER 25 DEALINGS IN THE SOFTWARE. 26 */ 27 28 module dagon.graphics.tween; 29 30 import dlib.math.vector; 31 import dlib.math.quaternion; 32 import dlib.math.interpolation; 33 import dlib.math.utils; 34 import dlib.image.color; 35 import dagon.graphics.entity; 36 37 enum TweenDataType 38 { 39 Float, 40 Vector, 41 Color 42 } 43 44 enum TweenType 45 { 46 Unknown = 0, 47 Position, 48 Rotation, 49 Scaling, 50 Color, 51 Alpha, 52 } 53 54 enum Easing 55 { 56 Linear, 57 QuadIn, 58 QuadOut, 59 QuadInOut, 60 BackIn, 61 BackOut, 62 BackInOut, 63 BounceOut 64 } 65 66 struct Tween 67 { 68 TweenDataType dataType; 69 TweenType type = TweenType.Unknown; 70 Easing easing; 71 bool active = false; 72 Entity entity; 73 double duration; 74 double time = 0.0f; 75 uint repeat = 1; 76 uint repeatCounter; 77 bool isPlaying = true; 78 79 union 80 { 81 Color4f fromColor; 82 Vector3f fromVector; 83 float fromFloat; 84 } 85 86 union 87 { 88 Color4f toColor; 89 Vector3f toVector; 90 float toFloat; 91 } 92 93 this(Entity entity, TweenType type, Vector3f start, Vector3f end, double duration, Easing easing = Easing.Linear) 94 { 95 this.dataType = TweenDataType.Vector; 96 this.type = type; 97 this.easing = easing; 98 this.active = true; 99 this.entity = entity; 100 this.duration = duration; 101 this.time = 0.0f; 102 this.fromVector = start; 103 this.toVector = end; 104 this.repeatCounter = 0; 105 this.isPlaying = true; 106 } 107 108 this(Entity entity, TweenType type, Color4f start, Color4f end, double duration, Easing easing = Easing.Linear) 109 { 110 this.dataType = TweenDataType.Color; 111 this.type = type; 112 this.easing = easing; 113 this.active = true; 114 this.entity = entity; 115 this.duration = duration; 116 this.time = 0.0f; 117 this.fromColor = start; 118 this.toColor = end; 119 this.repeatCounter = 0; 120 this.isPlaying = true; 121 } 122 123 this(Entity entity, TweenType type, float start, float end, double duration, Easing easing = Easing.Linear) 124 { 125 this.dataType = TweenDataType.Float; 126 this.type = type; 127 this.easing = easing; 128 this.active = true; 129 this.entity = entity; 130 this.duration = duration; 131 this.time = 0.0f; 132 this.fromFloat = start; 133 this.toFloat = end; 134 this.repeatCounter = 0; 135 this.isPlaying = true; 136 } 137 138 void pause() 139 { 140 isPlaying = false; 141 } 142 143 void play() 144 { 145 isPlaying = true; 146 } 147 148 void kill() 149 { 150 active = false; 151 time = 0.0; 152 repeatCounter = 0; 153 isPlaying = false; 154 } 155 156 void restart() 157 { 158 time = 0.0; 159 } 160 161 void update(double dt) 162 { 163 if (active && entity && isPlaying) 164 { 165 time += dt; 166 float t; 167 168 if (time > duration) 169 { 170 time = 0.0; 171 t = 0.0f; 172 if (repeat >= 0) 173 { 174 repeatCounter++; 175 if (repeatCounter >= repeat) 176 { 177 repeatCounter = 0; 178 active = false; 179 t = 1.0f; 180 } 181 } 182 } 183 else 184 { 185 t = time / duration; 186 } 187 188 applyTween(t); 189 } 190 } 191 192 void applyTween(float t) 193 { 194 if (type == TweenType.Position) 195 entity.position = lerp(fromVector, toVector, ease(t)); 196 else if (type == TweenType.Rotation) 197 entity.angles = lerp(fromVector, toVector, ease(t)); 198 else if (type == TweenType.Scaling) 199 entity.scaling = lerp(fromVector, toVector, ease(t)); 200 } 201 202 float ease(float t) 203 { 204 if (easing == Easing.Linear) return t; 205 else if (easing == Easing.QuadIn) return easeInQuad(t); 206 else if (easing == Easing.QuadOut) return easeOutQuad(t); 207 else if (easing == Easing.QuadInOut) return easeInOutQuad(t); 208 else if (easing == Easing.BackIn) return easeInBack(t); 209 else if (easing == Easing.BackOut) return easeOutBack(t); 210 else if (easing == Easing.BackInOut) return easeInOutBack(t); 211 else if (easing == Easing.BounceOut) return easeOutBounce(t); 212 else return t; 213 } 214 }