1 /**
2  * ae.ui.video.renderer
3  *
4  * License:
5  *   This Source Code Form is subject to the terms of
6  *   the Mozilla Public License, v. 2.0. If a copy of
7  *   the MPL was not distributed with this file, You
8  *   can obtain one at http://mozilla.org/MPL/2.0/.
9  *
10  * Authors:
11  *   Vladimir Panteleev <ae@cy.md>
12  */
13 
14 module ae.ui.video.renderer;
15 
16 public import ae.utils.graphics.color;
17 public import ae.utils.graphics.image;
18 public import ae.utils.graphics.view;
19 
20 /// Abstract class for a video renderer.
21 class Renderer
22 {
23 	alias COLOR = BGRX; /// The color type we use for all rendering.
24 
25 	/// BGRX/BGRA-only.
26 	struct Bitmap
27 	{
28 		static assert(COLOR.sizeof == uint.sizeof);
29 		/// `ae.utils.graphics.view` implementation.
30 		alias StorageType = PlainStorageUnit!COLOR;
31 
32 		StorageType* pixels; /// ditto
33 		/// ditto
34 		xy_t w, h, stride;
35 
36 		inout(StorageType)[] scanline(xy_t y) inout
37 		{
38 			assert(y>=0 && y<h);
39 			return pixels[stride*y..stride*(y+1)];
40 		} /// ditto
41 
42 		mixin DirectView;
43 	}
44 
45 	/// True when this renderer can lock quickly (usually when it's rendering in software).
46 	/*immutable*/ bool canFastLock;
47 
48 	/// Lock a 32-bit, BGRX/BGRA surface
49 	abstract Bitmap fastLock();
50 
51 	/// ditto
52 	abstract Bitmap lock();
53 
54 	/// Unlock what was previously locked
55 	abstract void unlock();
56 
57 	/// Finalize rendering and present it to the user (flip buffers etc.)
58 	abstract void present();
59 
60 	/// Destroy any bound resources
61 	abstract void shutdown();
62 
63 	// **********************************************************************
64 
65 	/// Get geometry.
66 	abstract @property uint width();
67 	abstract @property uint height(); /// ditto
68 
69 	/// Set a single pixel.
70 	abstract void putPixel(int x, int y, COLOR color);
71 
72 	/// Set some pixels.
73 	struct Pixel { int x, /***/ y; /***/ COLOR color; /***/ }
74 	void putPixels(Pixel[] pixels)
75 	{
76 		foreach (ref pixel; pixels)
77 			putPixel(pixel.tupleof);
78 	} /// ditto
79 
80 	/// Draw a straight line.
81 	abstract void line(float x0, float y0, float x1, float y1, COLOR color);
82 	/// Draw a vertical line.
83 	void vline(int x, int y0, int y1, COLOR color) { line(x, y0, x, y1, color); }
84 	/// Draw a horizontal line.
85 	void hline(int x0, int x1, int y, COLOR color) { line(x0, y, x1, y, color); }
86 
87 	/// Draw a filled rectangle.
88 	abstract void fillRect(int x0, int y0, int x1, int y1, COLOR color);
89 	abstract void fillRect(float x0, float y0, float x1, float y1, COLOR color); /// ditto
90 
91 	/// Clear the entire surface.
92 	abstract void clear();
93 
94 	/// Draw a texture.
95 	abstract void draw(int x, int y, TextureSource source, int u0, int v0, int u1, int v1);
96 
97 	/// Draw a texture with scaling.
98 	abstract void draw(float x0, float y0, float x1, float y1, TextureSource source, int u0, int v0, int u1, int v1);
99 }
100 
101 /// Uniquely identify private data owned by different renderers
102 enum Renderers
103 {
104 	SDLSoftware, ///
105 	SDLOpenGL,	 ///
106 	SDL2,		 ///
107 	max
108 }
109 
110 /// Base class for all renderer-specific texture data
111 class TextureRenderData
112 {
113 	/// If `true`, the `TextureSource` has been destroyed,
114 	/// and so should this instance (in the render thread)>
115 	bool destroyed;
116 
117 	/// Uploaded version number of the texture.
118 	/// If it does not match `TextureSource.textureVersion`,
119 	/// it needs to be updated.
120 	uint textureVersion = 0;
121 
122 	/// Set to `true` when any `TextureRenderData`
123 	/// needs to be destroyed.
124 	static shared bool cleanupNeeded;
125 }
126 
127 /// Base class for logical textures
128 class TextureSource
129 {
130 	// TODO: make this extensible for external renderer implementations.
131 	/// Renderer-specific texture data.
132 	TextureRenderData[Renderers.max] renderData;
133 
134 	/// Source version number of the texture.
135 	uint textureVersion = 1;
136 
137 	/// Common type used by `drawTo` / `getPixels`
138 	alias ImageRef!(Renderer.COLOR) TextureCanvas;
139 
140 	/// Request the contents of this `TextureSource`.
141 	/// Used when the target pixel memory is already allocated
142 	abstract void drawTo(TextureCanvas dest);
143 
144 	/// Request the contents of this `TextureSource`.
145 	/// Used when a pointer is needed to existing pixel memory
146 	abstract TextureCanvas getPixels();
147 
148 	~this()
149 	{
150 		foreach (r; renderData)
151 			if (r)
152 				r.destroyed = true;
153 		TextureRenderData.cleanupNeeded = true;
154 	}
155 }
156 
157 /// Implementation of `TextureSource`
158 /// using an `ae.utils.graphics.image.Image`.
159 class ImageTextureSource : TextureSource
160 {
161 	Image!(Renderer.COLOR) image; /// The image.
162 
163 	override void drawTo(TextureCanvas dest)
164 	{
165 		image.blitTo(dest);
166 	} ///
167 
168 	override TextureCanvas getPixels()
169 	{
170 		return image.toRef();
171 	} ///
172 }
173 
174 /// Base class for `TextureSource` implementations
175 /// where pixel data is calculated on request.
176 class ProceduralTextureSource : TextureSource
177 {
178 	private Image!(Renderer.COLOR) cachedImage;
179 
180 	/// Query the size of the procedural texture
181 	abstract void getSize(out int width, out int height);
182 
183 	/// Implementation of `getPixels` using
184 	/// `drawTo` and a cached copy.
185 	override TextureCanvas getPixels()
186 	{
187 		if (!cachedImage.w)
188 		{
189 			int w, h;
190 			getSize(w, h);
191 			cachedImage.size(w, h);
192 			drawTo(cachedImage.toRef());
193 		}
194 		return cachedImage.toRef();
195 	}
196 }