1 /* 2 * DSFML - The Simple and Fast Multimedia Library for D 3 * 4 * Copyright (c) 2013 - 2017 Jeremy DeHaan (dehaan.jeremiah@gmail.com) 5 * 6 * This software is provided 'as-is', without any express or implied warranty. 7 * In no event will the authors be held liable for any damages arising from the 8 * use of this software. 9 * 10 * Permission is granted to anyone to use this software for any purpose, 11 * including commercial applications, and to alter it and redistribute it 12 * freely, subject to the following restrictions: 13 * 14 * 1. The origin of this software must not be misrepresented; you must not claim 15 * that you wrote the original software. If you use this software in a product, 16 * an acknowledgment in the product documentation would be appreciated but is 17 * not required. 18 * 19 * 2. Altered source versions must be plainly marked as such, and must not be 20 * misrepresented as being the original software. 21 * 22 * 3. This notice may not be removed or altered from any source distribution 23 */ 24 25 /** 26 * A $(U Transform) specifies how to translate, rotate, scale, shear, project, 27 * whatever things. In mathematical terms, it defines how to transform a 28 * coordinate system into another. 29 * 30 * For example, if you apply a rotation transform to a sprite, the result will 31 * be a rotated sprite. And anything that is transformed by this rotation 32 * transform will be rotated the same way, according to its initial position. 33 * 34 * Transforms are typically used for drawing. But they can also be used for any 35 * computation that requires to transform points between the local and global 36 * coordinate systems of an entity (like collision detection). 37 * 38 * Example: 39 * --- 40 * // define a translation transform 41 * Transform translation; 42 * translation.translate(20, 50); 43 * 44 * // define a rotation transform 45 * Transform rotation; 46 * rotation.rotate(45); 47 * 48 * // combine them 49 * Transform transform = translation * rotation; 50 * 51 * // use the result to transform stuff... 52 * Vector2f point = transform.transformPoint(Vector2f(10, 20)); 53 * FloatRect rect = transform.transformRect(FloatRect(0, 0, 10, 100)); 54 * --- 55 * 56 * See_Also: 57 * $(TRANSFORMABLE_LINK), $(RENDERSTATES_LINK) 58 */ 59 module dsfml.graphics.transform; 60 61 import dsfml.system.vector2; 62 import dsfml.graphics.rect; 63 public import std.math; 64 65 66 /** 67 * Define a 3x3 transform matrix. 68 */ 69 struct Transform 70 { 71 float[9] m_matrix = [1.0f, 0.0f, 0.0f, 0.0f, 1.0f, 0.0f, 0.0f, 0.0f, 1.0f]; 72 73 /** 74 * Construct a 3x3 matrix. 75 * 76 * Params: 77 * a00 = Element (0, 0) of the matrix 78 * a01 = Element (0, 1) of the matrix 79 * a02 = Element (0, 2) of the matrix 80 * a10 = Element (1, 0) of the matrix 81 * a11 = Element (1, 1) of the matrix 82 * a12 = Element (1, 2) of the matrix 83 * a20 = Element (2, 0) of the matrix 84 * a21 = Element (2, 1) of the matrix 85 * a22 = Element (2, 2) of the matrix 86 */ 87 this(float a00, float a01, float a02, float a10, float a11, float a12, float a20, float a21, float a22) 88 { 89 m_matrix = [a00, a01, a02, a10, a11, a12, a20, a21, a22]; 90 } 91 92 /// Construct a 3x3 matrix from a float array. 93 this(float[9] newMatrix) 94 { 95 m_matrix = newMatrix.dup; 96 } 97 98 /** 99 * Return the inverse of the transform. 100 * 101 * If the inverse cannot be computed, an identity transform is returned. 102 * 103 * Returns: A new transform which is the inverse of self. 104 */ 105 Transform getInverse() const 106 { 107 float[9] temp; 108 sfTransform_getInverse(m_matrix.ptr,temp.ptr); 109 return Transform(temp); 110 } 111 112 /** 113 * Return the transform as a 4x4 matrix. 114 * 115 * This function returns a pointer to an array of 16 floats containing the 116 * transform elements as a 4x4 matrix, which is directly compatible with 117 * OpenGL functions. 118 * 119 * Returns: A 4x4 matrix. 120 */ 121 const(float)[] getMatrix() const 122 { 123 static float[16] temp; 124 125 sfTransform_getMatrix(m_matrix.ptr, temp.ptr); 126 127 return temp.dup; 128 } 129 130 /** 131 * Combine the current transform with another one. 132 * 133 * The result is a transform that is equivalent to applying this followed by 134 * transform. Mathematically, it is equivalent to a matrix multiplication. 135 * 136 * Params: 137 * transform = Transform to combine with this one 138 * 139 * Returns: Reference to this. 140 */ 141 void combine(Transform otherTransform) 142 { 143 sfTransform_combine(m_matrix.ptr, otherTransform.m_matrix.ptr); 144 } 145 146 /** 147 * Transform a 2D point. 148 * 149 * Params: 150 * x = X coordinate of the point to transform 151 * y = Y coordinate of the point to transform 152 * 153 * Returns: Transformed point. 154 */ 155 Vector2f transformPoint(Vector2f point) const 156 { 157 Vector2f temp; 158 sfTransform_transformPoint(m_matrix.ptr,point.x, point.y, &temp.x, &temp.y); 159 return temp; 160 } 161 162 /** 163 * Transform a rectangle. 164 * 165 * Since SFML doesn't provide support for oriented rectangles, the result of 166 * this function is always an axis-aligned rectangle. Which means that if 167 * the transform contains a rotation, the bounding rectangle of the 168 * transformed rectangle is returned. 169 * 170 * Params: 171 * rect = Rectangle to transform 172 * 173 * Returns: Transformed rectangle. 174 */ 175 FloatRect transformRect(const(FloatRect) rect)const 176 { 177 FloatRect temp; 178 sfTransform_transformRect(m_matrix.ptr,rect.left, rect.top, rect.width, rect.height, &temp.left, &temp.top, &temp.width, &temp.height); 179 return temp; 180 } 181 182 //TODO: These functions should probably return this; like the documentation states. 183 /** 184 * Combine the current transform with a translation. 185 * 186 * This function returns a reference to this, so that calls can be chained. 187 * 188 * Params: 189 * offset = Translation offset to apply. 190 * 191 * Returns: this 192 */ 193 void translate(float x, float y) 194 { 195 sfTransform_translate(m_matrix.ptr, x, y); 196 } 197 198 /** 199 * Combine the current transform with a rotation. 200 * 201 * This function returns a reference to this, so that calls can be chained. 202 * 203 * Params: 204 * angle = Rotation angle, in degrees 205 * 206 * Returns: this 207 */ 208 void rotate(float angle) 209 { 210 sfTransform_rotate(m_matrix.ptr, angle); 211 } 212 213 /** 214 * Combine the current transform with a rotation. 215 * 216 * The center of rotation is provided for convenience as a second argument, 217 * so that you can build rotations around arbitrary points more easily (and 218 * efficiently) than the usual 219 * translate(-center).rotate(angle).translate(center). 220 * 221 * This function returns a reference to this, so that calls can be chained. 222 * 223 * Params: 224 * angle = Rotation angle, in degrees 225 * center = Center of rotation 226 * 227 * Returns: this 228 */ 229 void rotate(float angle, float centerX, float centerY) 230 { 231 sfTransform_rotateWithCenter(m_matrix.ptr, angle, centerX, centerY); 232 } 233 234 /** 235 * Combine the current transform with a scaling. 236 * 237 * This function returns a reference to this, so that calls can be chained. 238 * 239 * Params: 240 * scaleX = Scaling factor on the X-axis. 241 * scaleY = Scaling factor on the Y-axis. 242 * 243 * Returns: this 244 */ 245 void scale(float scaleX, float scaleY) 246 { 247 sfTransform_scale(m_matrix.ptr, scaleX, scaleY); 248 } 249 250 /** 251 * Combine the current transform with a scaling. 252 * 253 * The center of scaling is provided for convenience as a second argument, 254 * so that you can build scaling around arbitrary points more easily 255 * (and efficiently) than the usual 256 * translate(-center).scale(factors).translate(center). 257 * 258 * This function returns a reference to this, so that calls can be chained. 259 * 260 * Params: 261 * scaleX = Scaling factor on the X-axis 262 * scaleY = Scaling factor on the Y-axis 263 * centerX = X coordinate of the center of scaling 264 * centerY = Y coordinate of the center of scaling 265 * 266 * Returns: this 267 */ 268 void scale(float scaleX, float scaleY, float centerX, float centerY) 269 { 270 sfTransform_scaleWithCenter(m_matrix.ptr, scaleX, scaleY, centerX, centerY); 271 } 272 273 string toString() 274 { 275 return "";//text(InternalsfTransform.matrix); 276 } 277 278 /** 279 * Overload of binary operator `*` to combine two transforms. 280 * 281 * This call is equivalent to: 282 * --- 283 * Transform combined = transform; 284 * combined.combine(rhs); 285 * --- 286 * 287 * Params: 288 * rhs = the second transform to be combined with the first 289 * 290 * Returns: New combined transform. 291 */ 292 Transform opBinary(string op)(Transform rhs) 293 if(op == "*") 294 { 295 Transform temp = this;//Transform(InternalsfTransform); 296 temp.combine(rhs); 297 return temp; 298 } 299 300 /** 301 * Overload of assignment operator `*=` to combine two transforms. 302 * 303 * This call is equivalent to calling `transform.combine(rhs)`. 304 * 305 * Params: 306 * rhs = the second transform to be combined with the first 307 * 308 * Returns: The combined transform. 309 */ 310 ref Transform opOpAssign(string op)(Transform rhs) 311 if(op == "*") 312 { 313 314 this.combine(rhs); 315 return this; 316 } 317 318 /** 319 * Overload of binary operator * to transform a point 320 * 321 * This call is equivalent to calling `transform.transformPoint(vector)`. 322 * 323 * Params: 324 * vector = the point to transform 325 * 326 * Returns: New transformed point. 327 */ 328 Vextor2f opBinary(string op)(Vector2f vector) 329 if(op == "*") 330 { 331 return transformPoint(vector); 332 } 333 334 /// Indentity transform (does nothing). 335 static const(Transform) Identity; 336 } 337 338 private extern(C): 339 340 //Return the 4x4 matrix of a transform 341 void sfTransform_getMatrix(const float* transform, float* matrix); 342 343 //Return the inverse of a transform 344 void sfTransform_getInverse(const float* transform, float* inverse); 345 346 //Apply a transform to a 2D point 347 void sfTransform_transformPoint(const float* transform, float xIn, float yIn, float* xOut, float* yOut); 348 349 //Apply a transform to a rectangle 350 void sfTransform_transformRect(const float* transform, float leftIn, float topIn, float widthIn, float heightIn, float* leftOut, float* topOut, float* widthOut, float* heightOut); 351 352 //Combine two transforms 353 void sfTransform_combine(float* transform, const float* other); 354 355 //Combine a transform with a translation 356 void sfTransform_translate(float* transform, float x, float y); 357 358 //Combine the current transform with a rotation 359 void sfTransform_rotate(float* transform, float angle); 360 361 //Combine the current transform with a rotation 362 void sfTransform_rotateWithCenter(float* transform, float angle, float centerX, float centerY); 363 364 //Combine the current transform with a scaling 365 void sfTransform_scale(float* transform, float scaleX, float scaleY); 366 367 //Combine the current transform with a scaling 368 void sfTransform_scaleWithCenter(float* transform, float scaleX, float scaleY, float centerX, float centerY);