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 <vladimir@thecybershadow.net>
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;
24 
25 	/// BGRX/BGRA-only.
26 	struct Bitmap
27 	{
28 		static assert(COLOR.sizeof == uint.sizeof);
29 		alias StorageType = PlainStorageUnit!COLOR;
30 
31 		StorageType* pixels;
32 		xy_t w, h, stride;
33 
34 		inout(StorageType)[] scanline(xy_t y) inout
35 		{
36 			assert(y>=0 && y<h);
37 			return pixels[stride*y..stride*(y+1)];
38 		}
39 
40 		mixin DirectView;
41 	}
42 
43 	/// True when this renderer can lock quickly (usually when it's rendering in software).
44 	/*immutable*/ bool canFastLock;
45 
46 	/// Lock a 32-bit, BGRX/BGRA surface
47 	abstract Bitmap fastLock();
48 
49 	/// ditto
50 	abstract Bitmap lock();
51 
52 	/// Unlock what was previously locked
53 	abstract void unlock();
54 
55 	/// Finalize rendering and present it to the user (flip buffers etc.)
56 	abstract void present();
57 
58 	/// Destroy any bound resources
59 	abstract void shutdown();
60 
61 	// **********************************************************************
62 
63 	abstract @property uint width();
64 	abstract @property uint height();
65 
66 	abstract void putPixel(int x, int y, COLOR color);
67 
68 	struct Pixel { int x, y; COLOR color; }
69 	void putPixels(Pixel[] pixels)
70 	{
71 		foreach (ref pixel; pixels)
72 			putPixel(pixel.tupleof);
73 	}
74 
75 	abstract void line(float x0, float y0, float x1, float y1, COLOR color);
76 	void vline(int x, int y0, int y1, COLOR color) { line(x, y0, x, y1, color); }
77 	void hline(int x0, int x1, int y, COLOR color) { line(x0, y, x1, y, color); }
78 
79 	abstract void fillRect(int x0, int y0, int x1, int y1, COLOR color);
80 	abstract void fillRect(float x0, float y0, float x1, float y1, COLOR color);
81 
82 	abstract void clear();
83 
84 	abstract void draw(int x, int y, TextureSource source, int u0, int v0, int u1, int v1);
85 	abstract void draw(float x0, float y0, float x1, float y1, TextureSource source, int u0, int v0, int u1, int v1);
86 }
87 
88 /// Uniquely identify private data owned by different renderers
89 enum Renderers
90 {
91 	SDLSoftware,
92 	SDLOpenGL,
93 	SDL2,
94 	max
95 }
96 
97 /// Base class for all renderer-specific texture data
98 class TextureRenderData
99 {
100 	bool destroyed;
101 	uint textureVersion = 0;
102 
103 	static shared bool cleanupNeeded;
104 }
105 
106 /// Base class for logical textures
107 class TextureSource
108 {
109 	TextureRenderData[Renderers.max] renderData;
110 
111 	uint textureVersion = 1;
112 
113 	alias ImageRef!(Renderer.COLOR) TextureCanvas;
114 
115 	/// Used when the target pixel memory is already allocated
116 	abstract void drawTo(TextureCanvas dest);
117 
118 	/// Used when a pointer is needed to existing pixel memory
119 	abstract TextureCanvas getPixels();
120 
121 	~this()
122 	{
123 		foreach (r; renderData)
124 			if (r)
125 				r.destroyed = true;
126 		TextureRenderData.cleanupNeeded = true;
127 	}
128 }
129 
130 class ImageTextureSource : TextureSource
131 {
132 	Image!(Renderer.COLOR) image;
133 
134 	override void drawTo(TextureCanvas dest)
135 	{
136 		image.blitTo(dest);
137 	}
138 
139 	override TextureCanvas getPixels()
140 	{
141 		return image.toRef();
142 	}
143 }
144 
145 class ProceduralTextureSource : TextureSource
146 {
147 	private Image!(Renderer.COLOR) cachedImage;
148 
149 	abstract void getSize(out int width, out int height);
150 
151 	override TextureCanvas getPixels()
152 	{
153 		if (!cachedImage.w)
154 		{
155 			int w, h;
156 			getSize(w, h);
157 			cachedImage.size(w, h);
158 			drawTo(cachedImage.toRef());
159 		}
160 		return cachedImage.toRef();
161 	}
162 }