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.Graphics.Transformable;
25 
26 private {
27 	import std.math : isNaN;
28 	
29 	import derelict.opengl3.gl;
30 
31 	import Dgame.Math.Vector2;
32 	import Dgame.Graphics.Moveable;
33 }
34 
35 /**
36  * Basic implementation for transformable objects.
37  * 
38  * Author: rschuett
39  */
40 abstract class Transformable : Moveable {
41 private:
42 	short _rotAngle;
43 	float _zoom = 1f;
44 	Vector2s _rotCenter;
45 
46 protected:
47 	/**
48 	* Apply translation to the object.
49 	*/
50 	override void _applyTranslation() const {
51 		super._applyTranslation();
52 		
53 		if (this._rotAngle != 0) {
54 			if (!this._rotCenter.isEmpty())
55 				glTranslatef(this._rotCenter.x, this._rotCenter.y, 0f);
56 			
57 			glRotatef(this._rotAngle, 0f, 0f, 1f);
58 			
59 			if (!this._rotCenter.isEmpty())
60 				glTranslatef(-this._rotCenter.x, -this._rotCenter.y, 0f);
61 		}
62 		
63 		if (!isNaN(this._zoom) && this._zoom != 1f)
64 			glScalef(this._zoom, this._zoom, 0f);
65 	}
66 
67 public:
68 	/**
69 	 * Calculate, store and return the center point.
70 	 */
71 	abstract ref const(Vector2s) calculateCenter() pure nothrow;
72 
73 	/**
74 	 * Reset the translation.
75 	 */
76 	override void resetTranslation() {
77 		super.resetTranslation();
78 		
79 		this.setRotation(0);
80 		this.setScale(1);
81 	}
82 
83 final:
84 	/**
85 	 * Set the rotation center.
86 	 */
87 	void setCenter(ref const Vector2s center) {
88 		this._rotCenter = center;
89 	}
90 
91 	/**
92 	 * Set the rotation center.
93 	 */
94 	void setCenter(short x, short y) pure nothrow {
95 		this._rotCenter.set(x, y);
96 	}
97 
98 	/**
99 	 * Returns the rotation center.
100 	 */
101 	ref const(Vector2s) getCenter() const pure nothrow {
102 		return this._rotCenter;  
103 	}
104 
105 	/**
106 	 * Set a (new) rotation.
107 	 */
108 	void setRotation(short rotAngle) pure nothrow {
109 		this._rotAngle = rotAngle;
110 		
111 		if (this._rotAngle > 360 || this._rotAngle < -360)
112 			this._rotAngle = 0;
113 	}
114 	
115 	/**
116 	 * Increase/Decrease the rotation.
117 	 */
118 	void rotate(short rotAngle) pure nothrow {
119 		this._rotAngle += rotAngle;
120 	}
121 	
122 	/**
123 	 * Returns the current rotation.
124 	 */
125 	short getRotation() const pure nothrow {
126 		return this._rotAngle;
127 	}
128 	
129 	/**
130 	 * Set a new scale.
131 	 */
132 	void setScale(float zoom) pure nothrow {
133 		this._zoom = zoom;
134 	}
135 	
136 	/**
137 	 * Increase/Decrease the scale/zoom.
138 	 */
139 	void scale(float zoom) pure nothrow {
140 		if (isNaN(this._zoom))
141 			return this.setScale(zoom);
142 		
143 		this._zoom += zoom;
144 	}
145 	
146 	/**
147 	 * Returns the current scale/zoom.
148 	 */
149 	float getScale() const pure nothrow {
150 		return this._zoom;
151 	}
152 }