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