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. Mainly created to solve problems in 8 * PixelPerfectEngine with sprite scaling 9 * Params: 10 * src = Source of the line to be transformed. Must be large enough to support the destination output with the given 11 * transformation params. 12 * dest = Destination of the transformed line. 13 * length = Length of the output. Must be less or eaqual than the dest buffer. Use function "scaleNearestLength" to 14 * calculate the needed output length. 15 * trfmParam = Transformation parameter. 16 * offset = Offset in the source line. This allows the source line to be offset by the given amount of fractional 17 * pixels. Default value is zero. 18 */ 19 public void horizontalScaleNearest(T)(T* src, T* dest, sizediff_t length, int trfmParam, size_t offset = 0) 20 @nogc pure nothrow { 21 if(trfmParam < 0){ 22 offset = (length<<10) - 1024 - offset; 23 } 24 while (length > 0) { 25 *dest = src[offset>>>10]; 26 offset += trfmParam; 27 length--; 28 dest++; 29 } 30 }+/ 31 /** 32 * Horizontal scaling using nearest integer algorithm for per-line operations. Intended to use with arrays that might 33 * contain elements less than 8 bit in length. 34 * Params: 35 * src = Source of the line to be transformed. Must be large enough to support the destination output with the given 36 * transformation params. 37 * dest = Destination of the transformed line. 38 * length = Length of the output. Must be less or eaqual than the dest buffer. Use function "scaleNearestLength" to 39 * calculate the needed output length. 40 * trfmParam = Transformation parameter. 41 * offset = Offset in the source line. This allows the source line to be offset by the given amount of fractional 42 * pixels. Default value is zero. 43 */ 44 public void horizontalScaleNearest(ArrayType)(ArrayType src, ArrayType dest, sizediff_t length, int trfmParam, 45 sizediff_t offset = 0) @nogc pure nothrow { 46 if(trfmParam < 0) { 47 trfmParam *= -1; 48 for (sizediff_t i ; i < length ; i++) { 49 dest[i] = src[src.length - (offset>>>10) - 1]; 50 offset += trfmParam; 51 } 52 } else { 53 for (sizediff_t i ; i < length ; i++) { 54 dest[i] = src[offset>>>10]; 55 offset += trfmParam; 56 } 57 } 58 } 59 /+/** 60 * Horizontal scaling using nearest integer algorithm for per-line operations. Uses pointers for both the palette and 61 * source. Intended for 8 bit or larger data. 62 * Params: 63 * src = Source of the line to be transformed. Must be large enough to support the destination output with the given 64 * transformation params. 65 * dest = Destination of the transformed line. 66 * palette = Palette. Should have enough elements for every index, or ensure that source wouldn't point that far. 67 * length = Length of the output. Must be less or eaqual than the dest buffer. Use function "scaleNearestLength" to 68 * calculate the needed output length. 69 * trfmParam = Transformation parameter. 70 * offset = Offset in the source line. This allows the source line to be offset by the given amount of fractional 71 * pixels. Default value is zero. 72 */ 73 public void horizontalScaleNearestAndCLU(T, U)(T* src, U* dest, U* palette, sizediff_t length, int trfmParam, 74 size_t offset = 0) @nogc pure nothrow { 75 if(trfmParam < 0){ 76 offset += (length<<10) - 1024 - offset; 77 } 78 while (length > 0) { 79 *dest = palette[src[offset>>>10]]; 80 offset += trfmParam; 81 length--; 82 dest++; 83 } 84 }+/ 85 /** 86 * Horizontal scaling using nearest integer algorithm for per-line operations. Uses arrays for source (compatible with 87 * data types smaller than 8 bit) 88 * Params: 89 * src = Source of the line to be transformed. Must be large enough to support the destination output with the given 90 * transformation params. 91 * dest = Destination of the transformed line. 92 * palette = Palette. Should have enough elements for every index, or ensure that source wouldn't point that far. 93 * length = Length of the output. Must be less or eaqual than the dest buffer. Use function "scaleNearestLength" to 94 * calculate the needed output length. 95 * trfmParam = Transformation parameter. 96 * offset = Offset in the source line. This allows the source line to be offset by the given amount of fractional 97 * pixels. Default value is zero. 98 */ 99 public void horizontalScaleNearestAndCLU(ArrayType, U)(ArrayType src, U* dest, U* palette, sizediff_t length, 100 int trfmParam, sizediff_t offset = 0) @nogc pure nothrow { 101 if(trfmParam < 0) { 102 trfmParam *= -1; 103 for (sizediff_t i ; i < length ; i++) { 104 dest[i] = palette[src[src.length - (offset>>>10) - 1]]; 105 offset += trfmParam; 106 } 107 } else { 108 for (sizediff_t i ; i < length ; i++) { 109 dest[i] = palette[src[offset>>>10]]; 110 offset += trfmParam; 111 } 112 } 113 } 114 /** 115 * Horizontal scaling using nearest integer algorithm for per-line operations. (Old, might get deprecated later on) 116 * Works with most datatypes. Use a separate one for 4 bit. 117 * Lenght determines the source's length. 118 * 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. 119 */ 120 public void _horizontalScaleNearest(T)(T* src, T* dest, sizediff_t length, int trfmParam) @nogc pure nothrow { 121 int trfmParamA = trfmParam; 122 sizediff_t offset; 123 length <<= 10; 124 if(trfmParam < 0){ 125 offset += length-1024; 126 trfmParamA *= -1; 127 } 128 while(length > 0){ 129 *dest = src[offset>>>10]; 130 offset += trfmParam; 131 length -= trfmParamA; 132 dest++; 133 } 134 } 135 /** 136 * Horizontal scaling and color lookup using nearest integer algorithm for per-line operations. (Old, might get deprecated later on) 137 * Works with most datatypes. Use a separate one for 4 bit. 138 * Lenght determines the source's length. 139 * 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. 140 */ 141 public void _horizontalScaleNearestAndCLU(T, U)(T* src, U* dest, U* palette, sizediff_t length, const int trfmParam) 142 @nogc pure nothrow { 143 int trfmParamA = trfmParam; 144 sizediff_t offset; 145 length <<= 10; 146 if(trfmParam < 0){ 147 offset += length-1024; 148 trfmParamA *= -1; 149 } 150 while(length > 0){ 151 *dest = palette[(src[offset>>>10])]; 152 offset += trfmParam; 153 length -= trfmParamA; 154 dest++; 155 } 156 } 157 /** 158 * Horizontal scaling using nearest integer algorithm for per-line operations. (Old, might get deprecated later on) 159 * Works with 4 bit datatypes. 160 * Lenght determines the source's length. 161 * 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. 162 */ 163 public void _horizontalScaleNearest4Bit(ubyte* src, ubyte* dest, sizediff_t length, sizediff_t offset, 164 const int trfmParam) @nogc pure nothrow { 165 int trfmParamA = trfmParam; 166 length <<= 10; 167 offset <<= 10; 168 if(trfmParam < 0){ 169 offset += length-1024; 170 trfmParamA *= -1; 171 } 172 while(length > 0){ 173 const ubyte temp = (offset>>>10) & 1 ? src[offset>>>11] & 0x0F : src[offset>>>11] >> 4; 174 *dest |= length & 1 ? temp : temp << 4; 175 offset += trfmParam; 176 length -= trfmParamA; 177 dest++; 178 } 179 } 180 /** 181 * Horizontal scaling using nearest integer algorithm for per-line operations. (Old, might get deprecated later on) 182 * Works with 16, 8, 4, and 2 bit datatypes. 183 * Lenght determines the source's length. 184 * 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. 185 * `ArrayType` should be bitleveld's NibbleArray or QuadArray, but also works with regular D arrays. 186 */ 187 public void _horizontalScaleNearest(ArrayType)(ArrayType src, ArrayType dest, sizediff_t length, sizediff_t offset, 188 const int trfmParam) @nogc pure nothrow { 189 int trfmParamA = trfmParam; 190 size_t destPtr; 191 length <<= 10; 192 offset <<= 10; 193 if(trfmParam < 0){ 194 offset += length-1024; 195 trfmParamA *= -1; 196 } 197 while(length > 0){ 198 dest[destPtr] = src[offset>>>10]; 199 offset += trfmParam; 200 length -= trfmParamA; 201 destPtr++; 202 } 203 } 204 /** 205 * Horizontal scaling and color lookup using nearest integer algorithm for per-line operations. (Old, might get deprecated later on) 206 * Works with 4 bit datatypes. 207 * Lenght determines the source's length. 208 * 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. 209 */ 210 public void _horizontalScaleNearest4BitAndCLU(U)(ubyte* src, U* dest, U* palette, sizediff_t length, sizediff_t offset, 211 const int trfmParam) @nogc pure nothrow { 212 int trfmParamA = trfmParam; 213 length <<= 10; 214 offset <<= 10; 215 if(trfmParam < 0){ 216 offset += length-1024; 217 trfmParamA *= -1; 218 } 219 while(length > 0){ 220 const ubyte temp = (offset>>>10) & 1 ? src[offset>>>11] & 0x0F : src[offset>>>11] >> 4; 221 *dest = palette[temp]; 222 offset += trfmParam; 223 length -= trfmParam; 224 dest++; 225 } 226 } 227 /** 228 * Horizontal scaling and color lookup using nearest integer algorithm for per-line operations. (Old, might get deprecated later on) 229 * Works with 16, 8, 4, and 2 bit datatypes. 230 * Lenght determines the source's length. 231 * 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. 232 * `ArrayType` should be bitleveld's NibbleArray or QuadArray, but also works with regular D arrays. 233 */ 234 public void _horizontalScaleNearestAndCLU(PaletteType, ArrayType)(ArrayType src, PaletteType* dest, PaletteType* palette, 235 sizediff_t length, sizediff_t offset, const int trfmParam) @nogc pure nothrow { 236 int trfmParamA = trfmParam; 237 length <<= 10; 238 offset <<= 10; 239 if(trfmParam < 0){ 240 offset += length-1024; 241 trfmParamA *= -1; 242 } 243 while(length > 0){ 244 *dest = palette[src[offset>>>10]]; 245 offset += trfmParam; 246 length -= trfmParamA; 247 dest++; 248 } 249 } 250 /** 251 * Returns the needed length of dest for the given trfmParam if the "nearest integer algorithm" used. (Old, might get deprecated later on) 252 * Works with both horizontal and vertical algorithms. 253 */ 254 public size_t scaleNearestLength(size_t origLen, int trfmParam) @nogc @safe pure nothrow { 255 if(trfmParam < 0) 256 trfmParam *= -1; 257 return cast(size_t)(cast(double)origLen * (1024.0 / cast(double)trfmParam)); 258 } 259 pure nothrow unittest{ 260 import std.conv : to; 261 uint[256] a, b; 262 ubyte[256] c; 263 NibbleArray d = NibbleArray(c[0..$], 512), f = NibbleArray(c[0..$], 512); 264 QuadArray e = QuadArray(c[0..$], 1024), g = QuadArray(c[0..$], 1024); 265 //old scalers 266 _horizontalScaleNearest(a.ptr, b.ptr, 16, 2048); 267 _horizontalScaleNearestAndCLU(c.ptr,a.ptr,b.ptr,16,2048); 268 _horizontalScaleNearest4BitAndCLU(c.ptr,a.ptr,b.ptr,16,0,2048); 269 _horizontalScaleNearestAndCLU(d, a.ptr, b.ptr, 256, 0, 2048); 270 _horizontalScaleNearestAndCLU(e, a.ptr, b.ptr, 256, 0, 2048); 271 272 horizontalScaleNearest(a, b, scaleNearestLength(100, 1000), 1000, 20); 273 horizontalScaleNearest(a, b, scaleNearestLength(100, -1000), -1000, 20); 274 horizontalScaleNearest(d, f, scaleNearestLength(200, 1000), 1000, 56); 275 horizontalScaleNearest(d, f, scaleNearestLength(200, -1000), -1000, 58); 276 horizontalScaleNearest(e, g, scaleNearestLength(200, 1100), 1100, 53); 277 horizontalScaleNearest(e, g, scaleNearestLength(200, -1100), -1100, 53); 278 279 horizontalScaleNearestAndCLU(c, a.ptr, b.ptr, scaleNearestLength(130, 1200), 1200, 94); 280 horizontalScaleNearestAndCLU(c, a.ptr, b.ptr, scaleNearestLength(130, -1200), -1200, 0); 281 horizontalScaleNearestAndCLU(d, a.ptr, b.ptr, scaleNearestLength(130, 1200), 1200, 94); 282 horizontalScaleNearestAndCLU(d, a.ptr, b.ptr, scaleNearestLength(130, -1200), -1200, 94); 283 horizontalScaleNearestAndCLU(e, a.ptr, b.ptr, scaleNearestLength(130, 1200), 1200, 94); 284 horizontalScaleNearestAndCLU(e, a.ptr, b.ptr, scaleNearestLength(130, -1200), -1200, 94); 285 assert(20 == scaleNearestLength(10, 512), "Error while testing function `scaleNearestLength`. Expected value: 20 " ~ 286 "Returned value: " ~ to!string(scaleNearestLength(10, 512))); 287 assert(20 == scaleNearestLength(10, -512), "Error while testing function `scaleNearestLength`. Expected value: 20 " ~ 288 "Returned value: " ~ to!string(scaleNearestLength(10, -512))); 289 }