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.RendererTexture;
25 
26 private {
27 	debug import std.stdio : writeln;
28 	
29 	import derelict.sdl2.sdl;
30 	
31 	import Dgame.Graphics.Surface;
32 	import Dgame.Graphics.Color;
33 	import Dgame.Graphics.Renderer;
34 	import Dgame.Math.Rect;
35 	import Dgame.Internal.Shared;
36 }
37 
38 ///version = Develop;
39 
40 /**
41  * This is a wrapper for the hardware acceleration of SDL_Surfaces, called SDL_Textures.
42  * That means it is the same as if you use the HW_ACCEL Flag in SDL 1.2.
43  *
44  * Author: rschuett
45  */
46 struct RendererTexture {
47 private:
48 	shared_ptr!(SDL_Texture) _target;
49 	
50 public:
51 	/**
52 	 * Supported Access modes
53 	 */
54 	enum Access {
55 		Static = SDL_TEXTUREACCESS_STATIC,		/** changes rarely, not lockable */
56 		Stream = SDL_TEXTUREACCESS_STREAMING	/** changes frequently, lockable */
57 	}
58 	
59 	const Access access;
60 	
61 	/**
62 	 * CTor
63 	 */
64 	this(SDL_Texture* tex, Access access) {
65 		this._target = make_shared(tex, (SDL_Texture* tex) => SDL_DestroyTexture(tex));
66 		
67 		this.access = access;
68 	}
69 	
70 	version (Develop)
71 	~this() {
72 		debug writeln("DTor RendererTexture");
73 	}
74 	
75 	/**
76 	 * Destroy the RendererTexture <b>and all</b> which are linked to this.
77 	 */
78 	void free() {
79 		this._target.release();
80 	}
81 	
82 	/**
83 	 * Returns a two dimensional array filled with the width and the height
84 	 */
85 	int[2] getSize() {
86 		int w, h;
87 		int access;
88 		uint format;
89 		
90 		SDL_QueryTexture(this._target, &format, &access, &w, &h);
91 		
92 		return [w, h];
93 	}
94 	
95 	/**
96 	 * Returns the width
97 	 */
98 	@property
99 	ushort width() {
100 		int[2] size = this.getSize();
101 		
102 		return cast(ushort) size[0];
103 	}
104 	
105 	/**
106 	 * Returns the width
107 	 */
108 	@property
109 	ushort height() {
110 		int[2] size = this.getSize();
111 		
112 		return cast(ushort) size[1];
113 	}
114 	
115 	/**
116 	 * Checks whether this Surface is lockable and therefore accessable.
117 	 */
118 	bool isLockable() const pure nothrow {
119 		return !(this.access & Access.Static);
120 	}
121 	
122 	/**
123 	 * Use this function to lock a portion of the texture for write-only pixel access.
124 	 * Returns the pixel data of given area.
125 	 * If area is null, the whole pixel data returns.
126 	 */
127 	void* lock(out int pitch, const ShortRect* area = null) {
128 		if (this.access & Access.Static)
129 			return null;
130 
131 		SDL_Rect a = void;
132 		const SDL_Rect* rect_ptr = transfer(area, &a);
133 		
134 		void* pixels;
135 		SDL_LockTexture(this._target, rect_ptr, &pixels, &pitch);
136 		
137 		return pixels;
138 	}
139 	
140 	/**
141 	 * Use this function to unlock a texture, uploading the changes to video memory, if needed.
142 	 */
143 	void unlock() {
144 		SDL_UnlockTexture(this._target);
145 	}
146 	
147 	/**
148 	 * Returns a pointer of the SDL_Texture* struct.
149 	 */
150 	@property
151 	inout(SDL_Texture)* ptr() inout {
152 		return this._target.ptr;
153 	}
154 	
155 	/**
156 	 * Checks whether the RendererTexture is valid.
157 	 */
158 	bool isValid() const pure nothrow {
159 		return this._target.isValid();
160 	}
161 	
162 	/**
163 	 * Use this function to update the given texture rectangle with new pixel data.
164 	 */
165 	void update(const void* pixels, const ShortRect* rect = null, int pitch = -1) {
166 		SDL_Rect a = void;
167 		const SDL_Rect* dst_ptr = transfer(rect, &a);
168 		
169 		SDL_UpdateTexture(this._target, dst_ptr, pixels, !pitch ? this.width * 4 : pitch);
170 	}
171 	
172 	/**
173 	 * Copy hw onto this RendererTexture. rect is the position and size.
174 	 */
175 	void copy(ref RendererTexture hw, const ShortRect* rect) in {
176 		assert(hw.isValid(), "Invalid Surface.");
177 	} body {
178 		int pitch;
179 		void* pixels = hw.lock(pitch);
180 		scope(exit) hw.unlock();
181 		
182 		this.update(pixels, rect, pitch);
183 	}
184 	
185 	/**
186 	 * Copy srfc onto this RendererTexture. rect is the position and size.
187 	 */
188 	void copy(ref Surface srfc, ShortRect* rect) in {
189 		assert(srfc.isValid(), "Invalid Surface.");
190 	} body {
191 		ShortRect clipRect = srfc.getClipRect();
192 		if (rect is null)
193 			rect = &clipRect;
194 		
195 		this.update(srfc.pixels, rect, srfc.ptr.pitch);
196 	}
197 	
198 	/**
199 	 * Use this function to set the blend mode for a texture, used by 'copy'.
200 	 */
201 	void setBlendMode(Renderer.BlendMode bmode) {
202 		SDL_SetTextureBlendMode(this._target, bmode);
203 	}
204 	
205 	/**
206 	 * Use this function to get the blend mode used for texture copy operations.
207 	 */
208 	Renderer.BlendMode getBlendMode() {
209 		SDL_BlendMode blendMode;
210 		SDL_GetTextureBlendMode(this._target, &blendMode);
211 		
212 		return cast(Renderer.BlendMode) blendMode;
213 	}
214 	
215 	/**
216 	 * Use this function to set an additional alpha value multiplied into render copy operations.
217 	 */
218 	void setAlphaMod(ubyte alpha) {
219 		SDL_SetTextureAlphaMod(this._target, alpha);
220 	}
221 	
222 	/**
223 	 * Use this function to get the additional alpha value multiplied into render copy operations.
224 	 */
225 	ubyte getAlphaMod() {
226 		ubyte alpha;
227 		SDL_GetTextureAlphaMod(this._target, &alpha);
228 		
229 		return alpha;
230 	}
231 	
232 	/**
233 	 * Use this function to set an additional color value multiplied into render copy operations.
234 	 */
235 	void setColorMod(ref const Color col) {
236 		this.setColorMod(col.red, col.green, col.blue);
237 	}
238 	
239 	/**
240 	 * Rvalue version
241 	 */
242 	void setColorMod(const Color col) {
243 		this.setColorMod(col);
244 	}
245 	
246 	/**
247 	 * Use this function to set an additional color value multiplied into render copy operations.
248 	 */
249 	void setColorMod(ubyte r, ubyte g, ubyte b) {
250 		SDL_SetTextureColorMod(this._target, r, g, b);
251 	}
252 	
253 	/**
254 	 * Use this function to get the additional color value multiplied into render copy operations
255 	 */
256 	Color getColorMod() {
257 		ubyte r, g, b;
258 		SDL_GetTextureColorMod(this._target, &r, &g, &b);
259 		
260 		return Color(r, g, b);
261 	}
262 }