1 /* 2 ******************************************************************************************* 3 * Dgame (a D game framework) - Copyright (c) Randy Schütt 4 * 5 * This software is provided 'as-is', without any express or implied warranty. 6 * In no event will the authors be held liable for any damages arising from 7 * the use of this software. 8 * 9 * Permission is granted to anyone to use this software for any purpose, 10 * including commercial applications, and to alter it and redistribute it 11 * freely, subject to the following restrictions: 12 * 13 * 1. The origin of this software must not be misrepresented; you must not claim 14 * that you wrote the original software. If you use this software in a product, 15 * an acknowledgment in the product documentation would be appreciated but is 16 * not required. 17 * 18 * 2. Altered source versions must be plainly marked as such, and must not be 19 * misrepresented as being the original software. 20 * 21 * 3. This notice may not be removed or altered from any source distribution. 22 ******************************************************************************************* 23 */ 24 module Dgame.Graphic.Transformable; 25 26 private: 27 28 import Dgame.Math.Vector2; 29 import Dgame.Math.Matrix4x4; 30 31 public: 32 33 /** 34 * Transformable is an abstract class which enables his child classes to be transformable 35 * which means that they have a position, can be scaled and can be rotated. 36 * For that purpose an additional Matrix is used (besides the Vector2f and float components) which maps the transformations. 37 * 38 * See: Matrix4 39 * See: Vector2f 40 * 41 * Author: Randy Schuett (rswhite4@googlemail.com) 42 */ 43 class Transformable { 44 private: 45 Vector2f _position; 46 Vector2f _rotationCenter; 47 Vector2f _origin; 48 Vector2f _scale = Vector2f(1, 1); 49 50 float _rotationAngle = 0; 51 52 Matrix4x4 _matrix; 53 bool _was_transformed = true; 54 55 protected: 56 @nogc 57 final void _notifyTransform() pure nothrow { 58 _was_transformed = true; 59 } 60 61 public: 62 final: 63 /** 64 * Returns the current matrix. 65 * If any transformations was made, the matrix is updated before 66 */ 67 @nogc 68 ref const(Matrix4x4) getMatrix() pure nothrow { 69 if (_was_transformed) { 70 const Vector2f* center = _origin.isEmpty() ? &_rotationCenter : &_origin; 71 _matrix.loadIdentity() 72 .translate(_position - _origin) 73 .rotate(_rotationAngle, *center) 74 .scale(_scale, *center); 75 _was_transformed = false; 76 } 77 78 return _matrix; 79 } 80 81 /** 82 * Sets the position 83 */ 84 @nogc 85 void setPosition(float x, float y) pure nothrow { 86 _position.x = x; 87 _position.y = y; 88 _notifyTransform(); 89 } 90 91 /** 92 * Sets the position 93 */ 94 @nogc 95 void setPosition(const Vector2f pos) pure nothrow { 96 _position = pos; 97 _notifyTransform(); 98 } 99 100 /** 101 * Move the position by offset (x, y) 102 */ 103 @nogc 104 void move(float x, float y) pure nothrow { 105 _position.x += x; 106 _position.y += y; 107 _notifyTransform(); 108 } 109 110 /** 111 * Move the position by offset (x, y) 112 */ 113 @nogc 114 void move(const Vector2f offset) pure nothrow { 115 _position += offset; 116 _notifyTransform(); 117 } 118 119 /** 120 * Returns the current position 121 */ 122 @nogc 123 ref const(Vector2f) getPosition() const pure nothrow{ 124 return _position; 125 } 126 127 /** 128 * Returns the x coordinate <b>by value</b> 129 * 130 * Note: if you want to change the coordinate, use either move or setPosition 131 */ 132 @nogc 133 @property 134 float x() const pure nothrow { 135 return _position.x; 136 } 137 138 /** 139 * Sets a new x coordinate 140 */ 141 @nogc 142 @property 143 void x(float cx) pure nothrow { 144 _position.x = cx; 145 _notifyTransform(); 146 } 147 148 /** 149 * Returns the y coordinate <b>by value</b> 150 * 151 * Note: if you want to change the coordinate, use either move or setPosition 152 */ 153 @nogc 154 @property 155 float y() const pure nothrow { 156 return _position.y; 157 } 158 159 /** 160 * Sets a new y coordinate 161 */ 162 @nogc 163 @property 164 void y(float cy) pure nothrow { 165 _position.y = cy; 166 _notifyTransform(); 167 } 168 169 /** 170 * Sets the center position 171 * 172 * Note: if you use this function with setOrigin, 173 * the origin takes the place of the rotation center. 174 */ 175 @nogc 176 void setRotationCenter(float x, float y) pure nothrow { 177 _rotationCenter.x = x; 178 _rotationCenter.y = y; 179 _notifyTransform(); 180 } 181 182 /** 183 * Sets the center of the rotation 184 * 185 * Note: if you use this function with setOrigin, 186 * the origin takes the place of the rotation center. 187 */ 188 @nogc 189 void setRotationCenter(const Vector2f center) pure nothrow { 190 _rotationCenter = center; 191 _notifyTransform(); 192 } 193 194 /** 195 * Returns the current rotation center 196 */ 197 @nogc 198 ref const(Vector2f) getRotationCenter() const pure nothrow { 199 return _rotationCenter; 200 } 201 202 /** 203 * Sets the origin. The origin is a offset which is added to the position 204 * and serves as center position for scaling and rotation. 205 * 206 * Note: If you use this with setRotationCenter 207 * the origin will suppress the rotation center and takes it's place. 208 */ 209 @nogc 210 void setOrigin(float x, float y) pure nothrow { 211 _origin.x = x; 212 _origin.y = y; 213 _notifyTransform(); 214 } 215 216 /** 217 * Sets the origin. The origin is a offset which is added to the position 218 * and serves as center position for scaling and rotation. 219 * 220 * Note: If you use this with setRotationCenter 221 * the origin will suppress the rotation center and takes it's place. 222 */ 223 @nogc 224 void setOrigin(const Vector2f origin) pure nothrow { 225 _origin = origin; 226 _notifyTransform(); 227 } 228 229 /** 230 * Returns the current origin 231 */ 232 @nogc 233 ref const(Vector2f) getOrigin() const pure nothrow { 234 return _origin; 235 } 236 237 /** 238 * Sets the scaling (for both, x and y) 239 */ 240 @nogc 241 void setScale(float x, float y) pure nothrow { 242 _scale.x = x; 243 _scale.y = y; 244 _notifyTransform(); 245 } 246 247 /** 248 * Sets the scaling (for both, x and y) 249 */ 250 @nogc 251 void setScale(const Vector2f offset) pure nothrow { 252 _scale = offset; 253 _notifyTransform(); 254 } 255 256 /** 257 * Inc-/Decrease the scaling 258 */ 259 @nogc 260 void scale(const Vector2f offset) pure nothrow { 261 _scale += offset; 262 _notifyTransform(); 263 } 264 265 /** 266 * Inc-/Decrease the scaling 267 */ 268 @nogc 269 void scale(float offset) pure nothrow { 270 _scale += offset; 271 _notifyTransform(); 272 } 273 274 /** 275 * Returns the current scaling 276 */ 277 @nogc 278 ref const(Vector2f) getScale() const pure nothrow { 279 return _scale; 280 } 281 282 /** 283 * Set the rotation angle. If not in range of 0 .. 360 it will be set to 0. 284 */ 285 @nogc 286 void setRotation(float rotation) pure nothrow { 287 _rotationAngle = rotation; 288 if (_rotationAngle < 0 || _rotationAngle > 360) 289 _rotationAngle = 0; 290 _notifyTransform(); 291 } 292 293 /** 294 * Inc-/Decrease the rotation. 295 * If the rotation is <b>after</b> that not in range of 0 .. 360 it will be set to 0. 296 */ 297 @nogc 298 void rotate(float rotation) pure nothrow { 299 _rotationAngle += rotation; 300 if (_rotationAngle > 360 || _rotationAngle < -360) 301 _rotationAngle %= 360; 302 _notifyTransform(); 303 } 304 305 /** 306 * Returns the current rotation 307 */ 308 @nogc 309 float getRotation() const pure nothrow { 310 return _rotationAngle; 311 } 312 }