1 module CPUblit.transform;
2 
3 import CPUblit.colorspaces;
4 import bitleveld.datatypes;
5 
6 /**
7  * Horizontal scaling using nearest integer algorithm for per-line operations.
8  * Works with most datatypes. Use a separate one for 4 bit.
9  * Lenght determines the source's length.
10  * trfmParam describes how the transformation is done. 1024 results in the same exact line. Larger values cause shrinkage, smaller omes growth. Negative values cause reflections.
11  */
12 public void horizontalScaleNearest(T)(T* src, T* dest, sizediff_t length, int trfmParam) @nogc pure nothrow {
13 	int trfmParamA = trfmParam;
14 	sizediff_t offset;
15 	length <<= 10;
16 	if(trfmParam < 0){
17 		offset += length-1024;
18 		trfmParamA *= -1;
19 	}
20 	while(length > 0){
21 		*dest = src[offset>>>10];
22 		offset += trfmParam;
23 		length -= trfmParamA;
24 		dest++;
25 	}
26 }
27 /**
28  * Horizontal scaling and color lookup using nearest integer algorithm for per-line operations.
29  * Works with most datatypes. Use a separate one for 4 bit.
30  * Lenght determines the source's length.
31  * trfmParam describes how the transformation is done. 1024 results in the same exact line. Larger values cause shrinkage, smaller omes growth. Negative values cause reflections.
32  */
33 public void horizontalScaleNearestAndCLU(T, U)(T* src, U* dest, U* palette, sizediff_t length, const int trfmParam)
34 		@nogc pure nothrow {
35 	int trfmParamA = trfmParam;
36 	sizediff_t offset;
37 	length <<= 10;
38 	if(trfmParam < 0){
39 		offset += length-1024;
40 		trfmParamA *= -1;
41 	}
42 	while(length > 0){
43 		*dest = palette[(src[offset>>>10])];
44 		offset += trfmParam;
45 		length -= trfmParamA;
46 		dest++;
47 	}
48 }
49 /**
50  * Horizontal scaling using nearest integer algorithm for per-line operations.
51  * Works with 4 bit datatypes.
52  * Lenght determines the source's length.
53  * trfmParam describes how the transformation is done. 1024 results in the same exact line. Larger values cause shrinkage, smaller omes growth. Negative values cause reflections.
54  */
55 public void horizontalScaleNearest4Bit(ubyte* src, ubyte* dest, sizediff_t length, sizediff_t offset, 
56 		const int trfmParam) @nogc pure nothrow {
57 	int trfmParamA = trfmParam;
58 	length <<= 10;
59 	offset <<= 10;
60 	if(trfmParam < 0){
61 		offset += length-1024;
62 		trfmParamA *= -1;
63 	}
64 	while(length > 0){
65 		const ubyte temp = (offset>>>10) & 1 ?  src[offset>>>11] & 0x0F : src[offset>>>11] >> 4;
66 		*dest |= length & 1 ? temp : temp << 4;
67 		offset += trfmParam;
68 		length -= trfmParamA;
69 		dest++;
70 	}
71 }
72 /**
73  * Horizontal scaling using nearest integer algorithm for per-line operations.
74  * Works with 16, 8, 4, and 2 bit datatypes.
75  * Lenght determines the source's length.
76  * trfmParam describes how the transformation is done. 1024 results in the same exact line. Larger values cause shrinkage, smaller omes growth. Negative values cause reflections.
77  * `ArrayType` should be bitleveld's NibbleArray or QuadArray, but also works with regular D arrays.
78  */
79 public void horizontalScaleNearest(ArrayType)(ArrayType src, ArrayType dest, sizediff_t length, sizediff_t offset, 
80 		const int trfmParam) @nogc pure nothrow {
81 	int trfmParamA = trfmParam;
82 	size_t destPtr;
83 	length <<= 10;
84 	offset <<= 10;
85 	if(trfmParam < 0){
86 		offset += length-1024;
87 		trfmParamA *= -1;
88 	}
89 	while(length > 0){
90 		dest[destPtr] = src[offset>>>10];
91 		offset += trfmParam;
92 		length -= trfmParamA;
93 		destPtr++;
94 	}
95 }
96 /**
97  * Horizontal scaling and color lookup using nearest integer algorithm for per-line operations.
98  * Works with 4 bit datatypes.
99  * Lenght determines the source's length.
100  * trfmParam describes how the transformation is done. 1024 results in the same exact line. Larger values cause shrinkage, smaller omes growth. Negative values cause reflections.
101  */
102 public void horizontalScaleNearest4BitAndCLU(U)(ubyte* src, U* dest, U* palette, sizediff_t length, sizediff_t offset, 
103 		const int trfmParam) @nogc pure nothrow {
104 	int trfmParamA = trfmParam;
105 	length <<= 10;
106 	offset <<= 10;
107 	if(trfmParam < 0){
108 		offset += length-1024;
109 		trfmParamA *= -1;
110 	}
111 	while(length > 0){
112 		const ubyte temp = (offset>>>10) & 1 ?  src[offset>>>11] & 0x0F : src[offset>>>11] >> 4;
113 		*dest = palette[temp];
114 		offset += trfmParam;
115 		length -= trfmParam;
116 		dest++;
117 	}
118 }
119 /**
120  * Horizontal scaling and color lookup using nearest integer algorithm for per-line operations.
121  * Works with 16, 8, 4, and 2 bit datatypes.
122  * Lenght determines the source's length.
123  * trfmParam describes how the transformation is done. 1024 results in the same exact line. Larger values cause shrinkage, smaller omes growth. Negative values cause reflections.
124  * `ArrayType` should be bitleveld's NibbleArray or QuadArray, but also works with regular D arrays.
125  */
126 public void horizontalScaleNearestAndCLU(PaletteType, ArrayType)(ArrayType src, PaletteType* dest, PaletteType* palette, 
127 		sizediff_t length, sizediff_t offset, const int trfmParam) @nogc pure nothrow {
128 	int trfmParamA = trfmParam;
129 	length <<= 10;
130 	offset <<= 10;
131 	if(trfmParam < 0){
132 		offset += length-1024;
133 		trfmParamA *= -1;
134 	}
135 	while(length > 0){
136 		*dest = palette[src[offset>>>10]];
137 		offset += trfmParam;
138 		length -= trfmParamA;
139 		dest++;
140 	}
141 }
142 /**
143  * Returns the needed length of dest for the given trfmParam if the "nearest integer algorithm" used.
144  * Works with both horizontal and vertical algorithms.
145  */
146 public size_t scaleNearestLength(size_t origLen, int trfmParam) @nogc @safe pure nothrow {
147 	if(trfmParam < 0)
148 		trfmParam *= -1;
149 	return cast(size_t)(cast(double)origLen * (1024.0 / cast(double)trfmParam));
150 }
151 pure nothrow unittest{
152 	import std.conv : to;
153 	uint[256] a, b;
154 	ubyte[256] c;
155 	NibbleArray d = NibbleArray(c[0..$], 512);
156 	QuadArray e = QuadArray(c[0..$], 1024);
157 	//force the compiler to check the scalers
158 	horizontalScaleNearest(a.ptr, b.ptr, 16, 2048);
159 	horizontalScaleNearestAndCLU(c.ptr,a.ptr,b.ptr,16,2048);
160 	horizontalScaleNearest4BitAndCLU(c.ptr,a.ptr,b.ptr,16,0,2048);
161 	horizontalScaleNearestAndCLU(d, a.ptr, b.ptr, 256, 0, 2048);
162 	horizontalScaleNearestAndCLU(e, a.ptr, b.ptr, 256, 0, 2048);
163 	assert(20 == scaleNearestLength(10, 512), "Error while testing function `scaleNearestLength`. Expected value: 20 " ~
164 			"Returned value: " ~ to!string(scaleNearestLength(10, 512)));
165 	assert(20 == scaleNearestLength(10, -512), "Error while testing function `scaleNearestLength`. Expected value: 20 " ~
166 			"Returned value: " ~ to!string(scaleNearestLength(10, -512)));
167 }