1 /*
2  * Copyright (C) 2015-2020, by Laszlo Szeremi under the Boost license.
3  *
4  * Pixel Perfect Engine, graphics.layers.base module
5  */
6 
7 module pixelperfectengine.graphics.layers.base;
8 
9 public import pixelperfectengine.graphics.bitmap;
10 public import pixelperfectengine.graphics.common;
11 public import pixelperfectengine.graphics.layers.interfaces;
12 package import pixelperfectengine.graphics.transformfunctions;
13 package import pixelperfectengine.system.etc;
14 //package import pixelperfectengine.system.platform;
15 
16 package import std.bitmanip : bitfields;
17 public import pixelperfectengine.system.exc;
18 package import bindbc.sdl;
19 package import core.stdc.stdlib;
20 package import CPUblit.composing;
21 package import CPUblit.composing.specblt : xorBlitter;
22 package import CPUblit.colorlookup;
23 package import CPUblit.transform;
24 
25 import inteli.emmintrin;
26 alias RenderFunc = @nogc pure nothrow void function(uint* src, uint* dest, size_t length, ubyte value);
27 /// For generating a blitter function with value modifier
28 @nogc pure nothrow void localBlt(uint* src, uint* dest, size_t length, ubyte value) {
29 	blitter!uint(src, dest, length);
30 }
31 /// For generating a copy function with value modifier
32 @nogc pure nothrow void localCpy(uint* src, uint* dest, size_t length, ubyte value) {
33 	copy!uint(src, dest, length);
34 }
35 /// For generating a XOR blitter function with value modifier
36 @nogc pure nothrow void localXOR(uint* src, uint* dest, size_t length, ubyte value) {
37 	xorBlitter!uint(src, dest, length);
38 }
39 /**
40  * The basis of all layer classes, containing function pointers for rendering.
41  * Can be overloaded for user defined layers.
42  */
43 abstract class Layer {
44 	protected RenderFunc mainRenderingFunction;		///Used to implement changeable renderers for each layers
45 	/+protected @nogc pure nothrow void function(ushort* src, uint* dest, uint* palette, size_t length) 
46 			mainColorLookupFunction;+/
47 	//protected @nogc void function(uint* src, int length) mainHorizontalMirroringFunction;
48 	/+protected @nogc pure nothrow void function(ubyte* src, uint* dest, uint* palette, size_t length) 
49 			main8BitColorLookupFunction;+/
50 	/+protected @nogc pure nothrow void function(ubyte* src, uint* dest, uint* palette, size_t length, int offset) 
51 			main4BitColorLookupFunction;+/
52 	alias mainColorLookupFunction = colorLookup!(ushort,uint);
53 	alias main8BitColorLookupFunction = colorLookup!(ubyte,uint);
54 	alias main4BitColorLookupFunction = colorLookup4Bit!uint;
55 	protected RenderingMode renderMode;
56 
57 	// scrolling position
58 	//protected int sX, sY, rasterX, rasterY;
59 	protected int		sX;		///Horizontal scroll position
60 	protected int       sY;		///Vertical scroll position
61 	protected int		rasterX;///Raster width (visible)
62 	protected int		rasterY;///Haster height
63 
64 	/**
65 	 * Sets up the layer for the current rasterizer.
66 	 * Params:
67 	 *   rX = Width of the raster.
68 	 *   rY = Height of the raster.
69 	 * Note: These values define the visible area that need to be worked with. Some overscan can be defined,
70 	 * and `updateRaster`'s `pitch` parameter defines the per-line stepping. Note that too much overscan can
71 	 * negatively impact performance.
72 	 */
73 	public void setRasterizer(int rX, int rY) @safe pure nothrow {
74 		rasterX=rX;
75 		rasterY=rY;
76 	}
77 	/**
78 	 * Sets the global rendering mode for this layer.
79 	 * Params:
80 	 *   mode = The enumerator that describes built-in rendering functions.
81 	 */
82 	public void setRenderingMode(RenderingMode mode) @nogc @safe pure nothrow {
83 		renderMode = mode;
84 		mainRenderingFunction = getRenderingFunc(mode);
85 		//mainColorLookupFunction = &colorLookup!(ushort,uint);
86 		//mainHorizontalMirroringFunction = &flipHorizontal;
87 		//main8BitColorLookupFunction = &colorLookup!(ubyte,uint);
88 		//main4BitColorLookupFunction = &colorLookup4Bit!uint;
89 	}
90 	/**
91 	 * Scrolls the layer to the given position.
92 	 * Params:
93 	 *   x = Horizontal coordinate.
94 	 *   y = Vertical coordinate.
95 	 */
96 	public void scroll(int x, int y) @safe nothrow {
97 		sX = x;
98 		sY = y;
99 	}
100 	/**
101 	 * Relatively scrolls the layer by the given amount.
102 	 * Formula is:
103 	 * `[sX,sY] = [sX,sY] + [x,y]`
104 	 * Params:
105 	 *   x = Horizontal amount.
106 	 *   y = Vertical amount.
107 	 */
108 	public void relScroll(int x, int y) @safe nothrow {
109 		sX += x;
110 		sY += y;
111 	}
112 	///Getter for the X scroll position.
113 	public int getSX() @nogc @safe pure nothrow const {
114 		return sX;
115 	}
116 	///Getter for the Y scroll position.
117 	public int getSY() @nogc @safe pure nothrow const {
118 		return sY;
119 	}
120 	/**
121 	 * Renders the layer's output to the raster. Function is called sequentially for all layers. Layers with higher
122 	 * priority number will render to the raster in a later time. Function is marked as @nogc, as render-time 
123 	 * allocation has negative impact on performance. For errors, either use asserts for unrecoverable errors, or 
124 	 * errorcodes for less severe cases.
125 	 * Params:
126 	 *   workpad = The pointer to the workpad's first pixel to be shown. Does not have to be equal with the actual
127 	 * first pixel of the workpad.
128 	 *   pitch = The difference between lines in the amount of bytes. Must also contain any padding bytes, e.g.
129 	 * pixels, etc.
130 	 *   palette = Pointer to the first element on the palette.
131 	 * Note: Due to the nature of how rendering functions work on vector extensions, arrays are not as feasible as
132 	 * in other places, so that's why pointers are used instead.
133 	 */
134 	public abstract void updateRaster(void* workpad, int pitch, Color* palette) @nogc ;
135 	///Returns the type of the layer.
136 	///Useful with certain scripting languages.
137 	public abstract LayerType getLayerType() @nogc @safe pure nothrow const;
138 	///Standard algorithm for horizontal mirroring, used for tile mirroring
139 	protected void flipHorizontal(T)(T[] target) @nogc pure nothrow {
140 		//sizediff_t j = target.length - 1;
141 		for (sizediff_t i, j = target.length - 1 ; i < j ; i++, j--) {
142 			const T s = target[i];
143 			target[i] = target[j];
144 			target[j] = s;
145 			//j--;
146 		}
147 	}
148 }
149 /**
150  * Mostly used for internal communication and scripting.
151  */
152 public enum LayerType {
153 	init,
154 	Tile,
155 	TransformableTile,
156 	Sprite,
157 	Effects,
158 }
159 /**
160  * Defines how the layer or sprite will be rendered.
161  * See each value's documentation individually for more information on each mode.
162  */
163 public enum RenderingMode : ubyte {
164 	init,			///Rendering mode is not set
165 	Copy,			///Copies the pixels without any transparencies. The fastest as it only reads once. Best use is either GUI or lowest-layer.
166 	Blitter,		///Copies the pixels to the target using simple transparency. No effect from master-alpha values. Can be faster on less memory-bound machines.
167 	AlphaBlend,		///Blends the source onto the target, using both per-pixel alpha and master alpha. 
168 	Multiply,		///Multiplies pixel channel values, then stores it in the destination.
169 	MultiplyBl,		///Multiply with alpha used as a blend between the original and target value.
170 	Screen,			///Composes the source to the destination using the following formula: 1 - (1 - dest) * (1 - src)
171 	ScreenBl,		///Screen with alpha used as a blend between the original and target value.
172 	Add,			///Adds with saturation the source to the destination.
173 	AddBl,			///Add with alpha used as a blend between the original and target value.
174 	Subtract,		///Subtracts with saturation the source from the destination.
175 	SubtractBl,		///Subtracts with saturation the source from the destination. Alpha determines how much of the source's other channels is used.
176 	Diff,			///Calculates the difference between the source and destination.
177 	DiffBl,			///Calculates the difference between the source and destination. Alpha determines how much of the source's other channels is used.
178 	AND,			///Logically ANDs the source to the destination. Alpha value is ignored.
179 	OR,				///Logically ORs the source to the destination. Alpha value is ignored.
180 	XOR,			///Logically XORs the source to the destination. Alpha value is ignored.
181 }
182 /**
183  * Returns the rendering function that belongs to the enumeration value.
184  */
185 public RenderFunc getRenderingFunc (RenderingMode mode) @nogc @safe pure nothrow {
186 	final switch (mode) with (RenderingMode) {
187 		case init:
188 			return null;
189 		case Copy:
190 			return &localCpy;
191 		case Blitter:
192 			return &localBlt;
193 		case AlphaBlend:
194 			return (uint* src, uint* dest, size_t length, ubyte value) {alphaBlendMV(src, dest, length, value);};
195 		case Multiply:
196 			return (uint* src, uint* dest, size_t length, ubyte value) {multMV(src, dest, length, value);};
197 		case MultiplyBl:
198 			return (uint* src, uint* dest, size_t length, ubyte value) {multMVBl(src, dest, length, value);};
199 		case Screen:
200 			return (uint* src, uint* dest, size_t length, ubyte value) {screenMV(src, dest, length, value);};
201 		case ScreenBl:
202 			return (uint* src, uint* dest, size_t length, ubyte value) {screenMVBl(src, dest, length, value);};
203 		case Add:
204 			return (uint* src, uint* dest, size_t length, ubyte value) {addMV!(false)(src, dest, length, value);};
205 		case AddBl:
206 			return (uint* src, uint* dest, size_t length, ubyte value) {addMV!(true)(src, dest, length, value);};
207 		case Subtract:
208 			return (uint* src, uint* dest, size_t length, ubyte value) {subMV!(false)(src, dest, length, value);};
209 		case SubtractBl:
210 			return (uint* src, uint* dest, size_t length, ubyte value) {subMV!(true)(src, dest, length, value);};
211 		case Diff:
212 			return (uint* src, uint* dest, size_t length, ubyte value) {diffMV(src, dest, length, value);};
213 		case DiffBl:
214 			return (uint* src, uint* dest, size_t length, ubyte value) {diffMVBl(src, dest, length, value);};
215 		case AND:
216 			return null;
217 		case OR:
218 			return null;
219 		case XOR:
220 			return &localXOR;
221 	}
222 }
223 /**
224  * Sets the WarpMode for any tile layer.
225  */
226 public enum WarpMode : ubyte {
227 	Off,				/// Content shown only once.
228 	MapRepeat,			/// Tilemap is repeated on the layer.
229 	TileRepeat			/// Out of bounds areas repeat tile 0x0000. Tile 0xFFFF is still reserved as transparency.
230 }
231 /**
232  * Mapping element, that is used on most if not all layers in this engine.
233  * It reserves:
234  * * 16 bits for tile selection.
235  * * 6 bits for extra purposes (can be user defined if the layer doesn't use it for anything else).
236  * * 1 bit for vertical mirroring.
237  * * 1 bit for horizontal mirroring.
238  * * 8 bits for palette selection (can be used for user-defined purposes if tiles are either 16 or 32 bit).
239  * User defined purposes may include marking tiles with special purpose for the game logic.
240  */
241 public struct MappingElement {
242 	wchar tileID;				///Determines which tile is being used for the given instance. 0xFFFF is reserved for transparency.
243 	BitmapAttrib attributes;	///General attributes, such as vertical and horizontal mirroring. The extra 6 bits can be used for various purposes
244 	ubyte paletteSel;			///Selects the palette for the bitmap if supported
245 	///Default constructor
246 	this(wchar tileID, BitmapAttrib attributes = BitmapAttrib(false, false), ubyte paletteSel = 0) @nogc @safe pure nothrow {
247 		this.tileID = tileID;
248 		this.attributes = attributes;
249 		this.paletteSel = paletteSel;
250 	}
251 	public string toString() const {
252 		import std.conv : to;
253 		return "[tileID:" ~ to!string(cast(int)tileID) ~ "; attributes:" ~ attributes.toString ~ "; paletteSel:" ~
254 				to!string(paletteSel) ~ "]";
255 	}
256 }