1 /* stb_image_resize - v0.96 - public domain image resizing
2    by Jorge L Rodriguez (@VinoBS) - 2014
3    http://github.com/nothings/stb
4 
5    Written with emphasis on usability, portability, and efficiency. (No
6    SIMD or threads, so it be easily outperformed by libs that use those.)
7    Only scaling and translation is supported, no rotations or shears.
8    Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation.
9 
10    QUICKSTART
11       stbir_resize_uint8(      input_pixels , in_w , in_h , 0,
12                                output_pixels, out_w, out_h, 0, num_channels)
13 
14       stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0,
15                                output_pixels, out_w, out_h, 0,
16                                num_channels , alpha_chan  , 0)
17       stbir_resize_uint8_srgb_edgemode(
18                                input_pixels , in_w , in_h , 0,
19                                output_pixels, out_w, out_h, 0,
20                                num_channels , alpha_chan  , 0, STBIR_EDGE_CLAMP)
21                                                             // WRAP/REFLECT/ZERO
22 
23    FULL API
24       See the "header file" section of the source for API documentation.
25 
26    ADDITIONAL DOCUMENTATION
27 
28       SRGB & FLOATING POINT REPRESENTATION
29          The sRGB functions presume IEEE floating point. If you do not have
30          IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use
31          a slower implementation.
32 
33       MEMORY ALLOCATION
34          The resize functions here perform a single memory allocation using
35          malloc. To control the memory allocation, before the #include that
36          triggers the implementation, do:
37 
38             #define STBIR_MALLOC(size,context) ...
39             #define STBIR_FREE(ptr,context)   ...
40 
41          Each resize function makes exactly one call to malloc/free, so to use
42          temp memory, store the temp memory in the context and return that.
43 
44       DEFAULT FILTERS
45          For functions which don't provide explicit control over what filters
46          to use, you can change the compile-time defaults with
47 
48             #define STBIR_DEFAULT_FILTER_UPSAMPLE     STBIR_FILTER_something
49             #define STBIR_DEFAULT_FILTER_DOWNSAMPLE   STBIR_FILTER_something
50 
51          See stbir_filter in the header-file section for the list of filters.
52 
53       NEW FILTERS
54          A number of 1D filter kernels are used. For a list of
55          supported filters see the stbir_filter enum. To add a new filter,
56          write a filter function and add it to stbir__filter_info_table.
57 
58       MAX CHANNELS
59          If your image has more than 64 channels, define STBIR_MAX_CHANNELS
60          to the max you'll have.
61 
62       ALPHA CHANNEL
63          Most of the resizing functions provide the ability to control how
64          the alpha channel of an image is processed. The important things
65          to know about this:
66 
67          1. The best mathematically-behaved version of alpha to use is
68          called "premultiplied alpha", in which the other color channels
69          have had the alpha value multiplied in. If you use premultiplied
70          alpha, linear filtering (such as image resampling done by this
71          library, or performed in texture units on GPUs) does the "right
72          thing". While premultiplied alpha is standard in the movie CGI
73          industry, it is still uncommon in the videogame/real-time world.
74 
75          If you linearly filter non-premultiplied alpha, strange effects
76          occur. (For example, the 50/50 average of 99% transparent bright green
77          and 1% transparent black produces 50% transparent dark green when
78          non-premultiplied, whereas premultiplied it produces 50%
79          transparent near-black. The former introduces green energy
80          that doesn't exist in the source image.)
81 
82          2. Artists should not edit premultiplied-alpha images; artists
83          want non-premultiplied alpha images. Thus, art tools generally output
84          non-premultiplied alpha images.
85 
86          3. You will get best results in most cases by converting images
87          to premultiplied alpha before processing them mathematically.
88 
89          4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the
90          resizer does not do anything special for the alpha channel;
91          it is resampled identically to other channels. This produces
92          the correct results for premultiplied-alpha images, but produces
93          less-than-ideal results for non-premultiplied-alpha images.
94 
95          5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED,
96          then the resizer weights the contribution of input pixels
97          based on their alpha values, or, equivalently, it multiplies
98          the alpha value into the color channels, resamples, then divides
99          by the resultant alpha value. Input pixels which have alpha=0 do
100          not contribute at all to output pixels unless _all_ of the input
101          pixels affecting that output pixel have alpha=0, in which case
102          the result for that pixel is the same as it would be without
103          STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for
104          input images in integer formats. For input images in float format,
105          input pixels with alpha=0 have no effect, and output pixels
106          which have alpha=0 will be 0 in all channels. (For float images,
107          you can manually achieve the same result by adding a tiny epsilon
108          value to the alpha channel of every image, and then subtracting
109          or clamping it at the end.)
110 
111          6. You can suppress the behavior described in #5 and make
112          all-0-alpha pixels have 0 in all channels by #defining
113          STBIR_NO_ALPHA_EPSILON.
114 
115          7. You can separately control whether the alpha channel is
116          interpreted as linear or affected by the colorspace. By default
117          it is linear; you almost never want to apply the colorspace.
118          (For example, graphics hardware does not apply sRGB conversion
119          to the alpha channel.)
120 
121    CONTRIBUTORS
122       Jorge L Rodriguez: Implementation
123       Sean Barrett: API design, optimizations
124       Aras Pranckevicius: bugfix
125       Nathan Reed: warning fixes
126 
127    REVISIONS
128       0.97 (2020-02-02) fixed warning
129       0.96 (2019-03-04) fixed warnings
130       0.95 (2017-07-23) fixed warnings
131       0.94 (2017-03-18) fixed warnings
132       0.93 (2017-03-03) fixed bug with certain combinations of heights
133       0.92 (2017-01-02) fix integer overflow on large (>2GB) images
134       0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
135       0.90 (2014-09-17) first released version
136 
137    LICENSE
138      See end of file for license information.
139 
140    TODO
141       Don't decode all of the image data when only processing a partial tile
142       Don't use full-width decode buffers when only processing a partial tile
143       When processing wide images, break processing into tiles so data fits in L1 cache
144       Installable filters?
145       Resize that respects alpha test coverage
146          (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
147          https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
148 */
149 /**
150 Resizer ported to D from C. Removed a few features that did'nt make sense in Dplug.
151 Added Ryhor Spivak work on Lanczos filter... also added a few more lanczos kernels.
152 Copyright: (c) Guillaume Piolat (2021)
153 */
154 module dplug.graphics.stb_image_resize;
155 
156 
157 import core.stdc.stdlib: malloc, free;
158 import core.stdc.string: memset;
159 
160 import inteli.smmintrin;
161 import inteli.math;
162 
163 import dplug.core.math : fast_fabs, fast_pow, fast_ceil, fast_floor, fast_sin;
164 import dplug.core.vec;
165 
166 
167 nothrow:
168 @nogc:
169 
170 
171 //////////////////////////////////////////////////////////////////////////////
172 //
173 // Easy-to-use API:
174 //
175 //     * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4)
176 //     * input_w is input image width (x-axis), input_h is input image height (y-axis)
177 //     * stride is the offset between successive rows of image data in memory, in bytes. you can
178 //       specify 0 to mean packed continuously in memory
179 //     * alpha channel is treated identically to other channels.
180 //     * colorspace is linear or sRGB as specified by function name
181 //     * returned result is 1 for success or 0 in case of an error.
182 //       #define assert() to trigger an assert on parameter validation errors.
183 //     * Memory required grows approximately linearly with input and output size, but with
184 //       discontinuities at input_w == output_w and input_h == output_h.
185 //     * These functions use a "default" resampling filter defined at compile time. To change the filter,
186 //       you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE
187 //       and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API.
188 
189 int stbir_resize_uint8(const(ubyte)* input_pixels , int input_w , int input_h , int input_stride_in_bytes,
190                        ubyte* output_pixels, int output_w, int output_h, int output_stride_in_bytes,
191                        int num_channels, int filter, void *alloc_context)
192 {
193     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
194                                    output_pixels, output_w, output_h, output_stride_in_bytes,
195                                    0,0,1,1,null,num_channels,-1,0, STBIR_TYPE_UINT8, filter, filter,
196                                    STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
197 }
198 
199 int stbir_resize_uint16(const(ushort)* input_pixels , int input_w , int input_h , int input_stride_in_bytes,
200                        ushort* output_pixels, int output_w, int output_h, int output_stride_in_bytes,
201                        int num_channels, int filter, void *alloc_context)
202 {
203     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
204                                    output_pixels, output_w, output_h, output_stride_in_bytes,
205                                    0,0,1,1,null,num_channels,-1,0, STBIR_TYPE_UINT16, filter, filter,
206                                    STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
207 }
208 
209 
210 // The following functions interpret image data as gamma-corrected sRGB.
211 // Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
212 // or otherwise provide the index of the alpha channel. Flags value
213 // of 0 will probably do the right thing if you're not sure what
214 // the flags mean.
215 
216 enum STBIR_ALPHA_CHANNEL_NONE      = -1;
217 
218 // Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
219 // use alpha-weighted resampling (effectively premultiplying, resampling,
220 // then unpremultiplying).
221 enum STBIR_FLAG_ALPHA_PREMULTIPLIED = (1 << 0);
222 
223 // The specified alpha channel should be handled as gamma-corrected value even
224 // when doing sRGB operations.
225 enum STBIR_FLAG_ALPHA_USES_COLORSPACE = (1 << 1);
226 
227 int stbir_resize_uint8_srgb(const(ubyte)*input_pixels , int input_w , int input_h , int input_stride_in_bytes,
228                             ubyte*output_pixels, int output_w, int output_h, int output_stride_in_bytes,
229                             int num_channels, int alpha_channel, int flags, void* alloc_context, int filter)
230 {
231     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
232                                    output_pixels, output_w, output_h, output_stride_in_bytes,
233                                    0,0,1,1,null,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter,
234                                    STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB);
235 }
236 
237 alias stbir_edge = int;
238 enum : stbir_edge
239 {
240     STBIR_EDGE_CLAMP   = 1,
241     STBIR_EDGE_REFLECT = 2,
242     STBIR_EDGE_WRAP    = 3,
243     STBIR_EDGE_ZERO    = 4,
244 }
245 
246 
247 //////////////////////////////////////////////////////////////////////////////
248 //
249 // Medium-complexity API
250 //
251 // This extends the easy-to-use API as follows:
252 //
253 //     * Alpha-channel can be processed separately
254 //       * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
255 //         * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
256 //         * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
257 //     * Filter can be selected explicitly
258 //     * uint16 image type
259 //     * sRGB colorspace available for all types
260 //     * context parameter for passing to STBIR_MALLOC
261 
262 alias stbir_filter = int;
263 enum : stbir_filter
264 {
265     STBIR_FILTER_DEFAULT      = 0,  // use same filter type that easy-to-use API chooses
266     STBIR_FILTER_BOX          = 1,  // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
267     STBIR_FILTER_TRIANGLE     = 2,  // On upsampling, produces same results as bilinear texture filtering
268     STBIR_FILTER_CUBICBSPLINE = 3,  // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
269     STBIR_FILTER_CATMULLROM   = 4,  // An interpolating cubic spline
270     STBIR_FILTER_MITCHELL     = 5,  // Mitchell-Netrevalli filter with B=1/3, C=1/3
271     STBIR_FILTER_LANCZOS2     = 6,  // Lanczos 2
272     STBIR_FILTER_LANCZOS2_5   = 7,  // Lanczos 2.5
273     STBIR_FILTER_LANCZOS3     = 8,  // Lanczos 3
274     STBIR_FILTER_LANCZOS4     = 9,  // Lanczos 4
275     STBIR_FILTER_MK_2013      = 10, // Magic Kernel, without sharpening
276     STBIR_FILTER_MKS_2013_86  = 11, // Magic Kernel + Sharp 2013, but with only 86% sharpening (Dplug Issue #729)
277     STBIR_FILTER_MKS_2013     = 12, // Magic Kernel + Sharp 2013 (the one recommended by John Costella in 2013)
278     STBIR_FILTER_MKS_2021     = 13, // Magic Kernel + Sharp 2021 (the one recommended to us by John Costella in 2022)
279 
280     // To be continued, as John Costella has other kernels...
281 }
282 
283 alias stbir_colorspace = int;
284 enum : stbir_colorspace 
285 {
286     STBIR_COLORSPACE_LINEAR,
287     STBIR_COLORSPACE_SRGB,
288 
289     STBIR_MAX_COLORSPACES,
290 }
291 
292 
293 //////////////////////////////////////////////////////////////////////////////
294 //
295 // Full-complexity API
296 //
297 // This extends the medium API as follows:
298 //
299 //     * uint32 image type
300 //     * not typesafe
301 //     * separate filter types for each axis
302 //     * separate edge modes for each axis
303 //     * can specify scale explicitly for subpixel correctness
304 //     * can specify image source tile using texture coordinates
305 
306 alias stbir_datatype = int;
307 enum : stbir_datatype
308 {
309     STBIR_TYPE_UINT8 ,
310     STBIR_TYPE_UINT16,
311     STBIR_TYPE_UINT32,
312     STBIR_TYPE_FLOAT ,
313 
314     STBIR_MAX_TYPES
315 }
316 
317 // (s0, t0) & (s1, t1) are the top-left and bottom right corner (uv addressing style: [0, 1]x[0, 1]) of a region of the input image to use.
318 
319 struct STBAllocatorContext
320 {
321 nothrow:
322 @nogc:
323     void* buf = null;
324     size_t length = 0;
325 
326     @disable this(this);
327 
328     ~this()
329     {
330         alignedFree(buf, 1);
331     }
332 
333     void* reallocDiscard(size_t numBytes)
334     {
335         if (length < numBytes)
336         {         
337             buf = alignedReallocDiscard(buf, numBytes, 1);
338             length = numBytes;
339         }
340         return buf;
341     }
342 }
343 
344 void* STBIR_MALLOC(size_t size, void* context)
345 {
346     assert(context !is null);
347     STBAllocatorContext* alloc = cast(STBAllocatorContext*)context;
348     return alloc.reallocDiscard(size);
349 }
350 
351 void STBIR_FREE(void* p, void* context)
352 {
353     assert(context !is null);
354     // will be freed when resizer is freed, because it's relatively small and shared.
355 }
356 
357 enum STBIR_DEFAULT_FILTER_UPSAMPLE = STBIR_FILTER_CATMULLROM;
358 
359 enum STBIR_DEFAULT_FILTER_DOWNSAMPLE = STBIR_FILTER_MITCHELL;
360 
361 enum STBIR_MAX_CHANNELS = 4;
362 
363 // This value is added to alpha just before premultiplication to avoid
364 // zeroing out color values. It is equivalent to 2^-80. If you don't want
365 // that behavior (it may interfere if you have floating point images with
366 // very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
367 // disable it.
368 enum float STBIR_ALPHA_EPSILON = (cast(float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20));
369 
370 // must match stbir_datatype
371 static immutable ubyte[4] stbir__type_size = 
372 [
373     1, // STBIR_TYPE_UINT8
374     2, // STBIR_TYPE_UINT16
375     4, // STBIR_TYPE_UINT32
376     4, // STBIR_TYPE_FLOAT
377 ];
378 
379 // Kernel function centered at 0
380 alias stbir__kernel_fn = float function(float x, float scale);
381 alias stbir__support_fn = float function(float scale);
382 
383 struct stbir__filter_info
384 {
385     stbir__kernel_fn kernel;
386     stbir__support_fn support;
387 }
388 
389 // When upsampling, the contributors are which source pixels contribute.
390 // When downsampling, the contributors are which destination pixels are contributed to.
391 struct stbir__contributors
392 {
393     int n0; // First contributing pixel
394     int n1; // Last contributing pixel
395 }
396 
397 struct stbir__info
398 {
399     const(void)* input_data;
400     int input_w;
401     int input_h;
402     int input_stride_bytes;
403 
404     void* output_data;
405     int output_w;
406     int output_h;
407     int output_stride_bytes;
408 
409     float s0, t0, s1, t1;
410 
411     float horizontal_shift; // Units: output pixels
412     float vertical_shift;   // Units: output pixels
413     float horizontal_scale;
414     float vertical_scale;
415 
416     int channels;
417     int alpha_channel;
418     uint flags;
419     stbir_datatype type;
420     stbir_filter horizontal_filter;
421     stbir_filter vertical_filter;
422     stbir_edge edge_horizontal;
423     stbir_edge edge_vertical;
424     stbir_colorspace colorspace;
425 
426     stbir__contributors* horizontal_contributors;
427     float* horizontal_coefficients;
428 
429     stbir__contributors* vertical_contributors;
430     float* vertical_coefficients;
431 
432     int decode_buffer_pixels;
433     float* decode_buffer;
434 
435     float* horizontal_buffer;
436 
437     // cache these because ceil/floor are inexplicably showing up in profile
438     int horizontal_coefficient_width;
439     int vertical_coefficient_width;
440     int horizontal_filter_pixel_width;
441     int vertical_filter_pixel_width;
442     int horizontal_filter_pixel_margin;
443     int vertical_filter_pixel_margin;
444     int horizontal_num_contributors;
445     int vertical_num_contributors;
446 
447     int ring_buffer_length_bytes;   // The length of an individual entry in the ring buffer. The total number of ring buffers is stbir__get_filter_pixel_width(filter)
448     int ring_buffer_num_entries;    // Total number of entries in the ring buffer.
449     int ring_buffer_first_scanline;
450     int ring_buffer_last_scanline;
451     int ring_buffer_begin_index;    // first_scanline is at this index in the ring buffer
452     float* ring_buffer;
453 
454     float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
455 
456     int horizontal_contributors_size;
457     int horizontal_coefficients_size;
458     int vertical_contributors_size;
459     int vertical_coefficients_size;
460     int decode_buffer_size;
461     int horizontal_buffer_size;
462     int ring_buffer_size;
463     int encode_buffer_size;
464 }
465 
466 
467 static immutable float stbir__max_uint8_as_float  = 255.0f;
468 static immutable float stbir__max_uint16_as_float = 65535.0f;
469 static immutable double stbir__max_uint32_as_float = 4294967295.0;
470 
471 
472 int stbir__min(int a, int b)
473 {
474     return a < b ? a : b;
475 }
476 
477 float stbir__saturate(float x)
478 {
479     if (x < 0)
480         return 0;
481 
482     if (x > 1)
483         return 1;
484 
485     return x;
486 }
487 
488 static immutable float[256] stbir__srgb_uchar_to_linear_float = 
489 [
490     0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
491     0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,
492     0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,
493     0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,
494     0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,
495     0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,
496     0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,
497     0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
498     0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,
499     0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,
500     0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,
501     0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,
502     0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,
503     0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,
504     0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
505     0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,
506     0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,
507     0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,
508     0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,
509     0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,
510     0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,
511     0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
512     0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,
513     0.982251f, 0.991102f, 1.0f
514 ];
515 
516 float stbir__srgb_to_linear(float f)
517 {
518     if (f <= 0.04045f)
519         return f / 12.92f;
520     else
521         return cast(float)fast_pow((f + 0.055f) / 1.055f, 2.4f);
522 }
523 
524 float stbir__linear_to_srgb(float f)
525 {
526     if (f <= 0.0031308f)
527         return f * 12.92f;
528     else
529         return 1.055f * _mm_pow_ss(f, 0.4166666666f) - 0.055f;
530 }
531 /*
532 __m128 stbir__linear_to_srgb(__m128 f)
533 {
534     __m128 below = f * _mm_set1_ps(12.92f);
535     __m128 exponentiated = _mm_set1_ps(1.055f) * _mm_pow_ps(f, 0.4166666666f) - _mm_set1_ps(0.055f);
536     __m128 mask  =_mm_cmplt_ps(f, _mm_set1_ps(0.0031308f));
537     __m128i result = (cast(__m128i)below & cast(__m128i)mask) | (cast(__m128i)exponentiated & ~cast(__m128i)mask);
538     return cast(__m128)result;
539 }*/
540 
541 union stbir__FP32
542 {
543     uint u;
544     float f;
545 }
546 
547 static immutable uint[104] fp32_to_srgb8_tab4 = 
548 [
549     0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
550     0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
551     0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
552     0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
553     0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
554     0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
555     0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
556     0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
557     0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
558     0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
559     0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
560     0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
561     0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
562 ];
563 
564 ubyte stbir__linear_to_srgb_uchar(float in_)
565 {
566     static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
567     static const stbir__FP32 minval = { (127-13) << 23 };
568     uint tab,bias,scale,t;
569     stbir__FP32 f;
570 
571     // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
572     // The tests are carefully written so that NaNs map to 0, same as in the reference
573     // implementation.
574     if (!(in_ > minval.f)) // written this way to trap NaNs
575         in_ = minval.f;
576     if (in_ > almostone.f)
577         in_ = almostone.f;
578 
579     // Do the table lookup and unpack bias, scale
580     f.f = in_;
581     tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
582     bias = (tab >> 16) << 9;
583     scale = tab & 0xffff;
584 
585     // Grab next-highest mantissa bits and perform linear interpolation
586     t = (f.u >> 12) & 0xff;
587     return cast(ubyte) ((bias + scale*t) >> 16);
588 }
589 
590 // same but 4 float at once
591 __m128i stbir__linear_to_srgb_uchar(__m128 in_)
592 {
593     static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
594     static const stbir__FP32 minval = { (127-13) << 23 };
595     in_ = _mm_max_ps(in_, _mm_set1_ps(minval.f));
596     in_ = _mm_min_ps(in_, _mm_set1_ps(almostone.f));
597 
598     __m128i f = cast(__m128i) in_;
599     __m128i tblIndex = _mm_srli_epi32(f - _mm_set1_epi32(minval.u), 20);
600 
601     __m128i tab = _mm_setr_epi32(fp32_to_srgb8_tab4[ tblIndex.array[0] ], 
602                                  fp32_to_srgb8_tab4[ tblIndex.array[1] ],
603                                  fp32_to_srgb8_tab4[ tblIndex.array[2] ],
604                                  fp32_to_srgb8_tab4[ tblIndex.array[3] ]);
605     __m128i bias = _mm_slli_epi32(_mm_srli_epi32(tab, 16), 9);
606     __m128i scale = _mm_and_si128(tab, _mm_set1_epi32(0xffff));
607 
608     __m128i t = _mm_srli_epi32(f, 12) &  _mm_set1_epi32(0xff);
609     __m128i r = _mm_srli_epi32(bias + _mm_mullo_epi32(scale, t), 16);
610     __m128i zero = _mm_setzero_si128();
611     r = _mm_packs_epi32(r, zero);
612     r = _mm_packus_epi16(r, zero);
613     return r;
614 }
615 
616 float stbir__filter_trapezoid(float x, float scale)
617 {
618     float halfscale = scale / 2;
619     float t = 0.5f + halfscale;
620     assert(scale <= 1);
621 
622     x = cast(float)fast_fabs(x);
623 
624     if (x >= t)
625         return 0;
626     else
627     {
628         float r = 0.5f - halfscale;
629         if (x <= r)
630             return 1;
631         else
632             return (t - x) / scale;
633     }
634 }
635 
636 float stbir__support_trapezoid(float scale)
637 {
638     assert(scale <= 1);
639     return 0.5f + scale / 2;
640 }
641 
642 float stbir__filter_triangle(float x, float s)
643 {
644     x = cast(float)fast_fabs(x);
645 
646     if (x <= 1.0f)
647         return 1 - x;
648     else
649         return 0;
650 }
651 
652 float stbir__filter_cubic(float x, float s)
653 {
654     x = cast(float)fast_fabs(x);
655 
656     if (x < 1.0f)
657         return (4 + x*x*(3*x - 6))/6;
658     else if (x < 2.0f)
659         return (8 + x*(-12 + x*(6 - x)))/6;
660 
661     return (0.0f);
662 }
663 
664 float stbir__filter_catmullrom(float x, float s)
665 {
666     x = cast(float)fast_fabs(x);
667 
668     if (x < 1.0f)
669         return 1 - x*x*(2.5f - 1.5f*x);
670     else if (x < 2.0f)
671         return 2 - x*(4 + x*(0.5f*x - 2.5f));
672 
673     return (0.0f);
674 }
675 
676 float stbir__filter_mitchell(float x, float s)
677 {
678     x = cast(float)fast_fabs(x);
679 
680     if (x < 1.0f)
681         return (16 + x*x*(21 * x - 36))/18;
682     else if (x < 2.0f)
683         return (32 + x*(-60 + x*(36 - 7*x)))/18;
684 
685     return (0.0f);
686 }
687 
688 float stbir__filter_lanczos(float A)(float x, float s)
689 {
690     x = cast(float)fast_fabs(x);
691 
692     if (x <= float.min_normal)
693         return 1.0f;
694 
695     if (x < A)
696     {
697         float pix = 3.14159265358979323846f*x;
698         return A*fast_sin(pix)*fast_sin(pix/A)/(pix*pix);
699     }
700 
701     return 0.0f;
702 }
703 
704 float stbir__filter_mk2013(float x, float s) nothrow @nogc
705 {
706     x = fast_fabs(x);
707     if (x < 0.5)
708         return 0.75 - x * x;
709 
710     if (x < 1.5)
711         return 0.5 * (x - 1.5)*(x - 1.5);
712 
713     return 0.0f;
714 }
715 
716 float stbir__filter_mks2013_hs(float x, float s) nothrow @nogc
717 {
718     // Perhaps possible to do better with "MKS 2021".
719     return 0.14f * stbir__filter_mk2013(x, s)
720          + 0.86f * stbir__filter_mks2013(x, s);
721 }
722 
723 float stbir__filter_mks2013(float x, float s) nothrow @nogc
724 {
725     x = fast_fabs(x);
726 
727     if (x <= float.min_normal)
728         return 17.0f / 16.0f;
729 
730     if (x < 0.5)
731         return 17.0 / 16.0 - 7.0 * x * x / 4.0;
732 
733     if (x < 1.5)
734     {
735         double x2 = x * x;
736         return 0.25 * (4 * x2 - 11.0 * x + 7.0);
737     }
738 
739     if (x < 2.5)
740     {
741         return -0.125 * (x - 5.0 / 2.0)*(x - 5.0 / 2.0);
742     }
743     return 0.0f;
744 }
745 
746 float stbir__filter_mks2021(float x, float s) nothrow @nogc
747 {
748     x = fast_fabs(x);
749     float x2 = x * x;
750 
751     if (x < 0.5)
752         return 577.0f / 576.0f - (239.0f / 144.0f) * x2;
753 
754     if (x < 1.5)
755         return (140 * x2 - 379 * x + 239) / 144.0f;
756 
757     if (x < 2.5)
758         return -(24 * x2 - 113 * x + 130) / 144.0f;
759 
760     if (x < 3.5)
761         return (4 * x2 - 27 * x + 45) / 144.0f;
762 
763     if (x < 4.5)
764         return -(4 * x2 - 36 * x + 81) / 1152.0f;
765 
766     return 0.0f;
767 }
768 
769 float stbir__support_zero(float s)
770 {
771     return 0;
772 }
773 
774 float stbir__support_one(float s)
775 {
776     return 1;
777 }
778 
779 float stbir__support_two(float s)
780 {
781     return 2;
782 }
783 
784 float stbir__support_three(float s)
785 {
786     return 3;
787 }
788 
789 float stbir__support_four(float s)
790 {
791     return 4;
792 }
793 
794 float stbir__support_five(float s)
795 {
796     return 5;
797 }
798 
799 static immutable stbir__filter_info[14] stbir__filter_info_table = 
800 [
801         { null,                      &stbir__support_zero },
802         { &stbir__filter_trapezoid,  &stbir__support_trapezoid },
803         { &stbir__filter_triangle,   &stbir__support_one },
804         { &stbir__filter_cubic,      &stbir__support_two },
805         { &stbir__filter_catmullrom, &stbir__support_two },
806         { &stbir__filter_mitchell,   &stbir__support_two },
807         { &stbir__filter_lanczos!2.0f, &stbir__support_two },
808         { &stbir__filter_lanczos!2.5f, &stbir__support_three },
809         { &stbir__filter_lanczos!3.0f, &stbir__support_three },
810         { &stbir__filter_lanczos!4.0f, &stbir__support_four },
811         { &stbir__filter_mk2013,       &stbir__support_three },
812         { &stbir__filter_mks2013_hs,   &stbir__support_three },
813         { &stbir__filter_mks2013,      &stbir__support_three },
814         { &stbir__filter_mks2021,      &stbir__support_five },
815         ];
816 
817 
818 static int stbir__use_upsampling(float ratio)
819 {
820     return ratio > 1;
821 }
822 
823 static int stbir__use_width_upsampling(stbir__info* stbir_info)
824 {
825     return stbir__use_upsampling(stbir_info.horizontal_scale);
826 }
827 
828 static int stbir__use_height_upsampling(stbir__info* stbir_info)
829 {
830     return stbir__use_upsampling(stbir_info.vertical_scale);
831 }
832 
833 // This is the maximum number of input samples that can affect an output sample
834 // with the given filter
835 static int stbir__get_filter_pixel_width(stbir_filter filter, float scale)
836 {
837     assert(filter != 0);
838     assert(filter < stbir__filter_info_table.length);
839 
840     if (stbir__use_upsampling(scale))
841         return cast(int)fast_ceil(stbir__filter_info_table[filter].support(1/scale) * 2);
842     else
843         return cast(int)fast_ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale);
844 }
845 
846 // This is how much to expand buffers to account for filters seeking outside
847 // the image boundaries.
848 static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale)
849 {
850     return stbir__get_filter_pixel_width(filter, scale) / 2;
851 }
852 
853 static int stbir__get_coefficient_width(stbir_filter filter, float scale)
854 {
855     if (stbir__use_upsampling(scale))
856         return cast(int)fast_ceil(stbir__filter_info_table[filter].support(1 / scale) * 2);
857     else
858         return cast(int)fast_ceil(stbir__filter_info_table[filter].support(scale) * 2);
859 }
860 
861 static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size)
862 {
863     if (stbir__use_upsampling(scale))
864         return output_size;
865     else
866         return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2);
867 }
868 
869 static int stbir__get_total_horizontal_coefficients(stbir__info* info)
870 {
871     return info.horizontal_num_contributors
872          * stbir__get_coefficient_width      (info.horizontal_filter, info.horizontal_scale);
873 }
874 
875 static int stbir__get_total_vertical_coefficients(stbir__info* info)
876 {
877     return info.vertical_num_contributors
878          * stbir__get_coefficient_width      (info.vertical_filter, info.vertical_scale);
879 }
880 
881 static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n)
882 {
883     return &contributors[n];
884 }
885 
886 // For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample,
887 // if you change it here change it there too.
888 static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c)
889 {
890     int width = stbir__get_coefficient_width(filter, scale);
891     return &coefficients[width*n + c];
892 }
893 
894 static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
895 {
896     switch (edge)
897     {
898     case STBIR_EDGE_ZERO:
899         return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later
900 
901     case STBIR_EDGE_CLAMP:
902         if (n < 0)
903             return 0;
904 
905         if (n >= max)
906             return max - 1;
907 
908         return n; // NOTREACHED
909 
910     case STBIR_EDGE_REFLECT:
911     {
912         if (n < 0)
913         {
914             if (n < max)
915                 return -n;
916             else
917                 return max - 1;
918         }
919 
920         if (n >= max)
921         {
922             int max2 = max * 2;
923             if (n >= max2)
924                 return 0;
925             else
926                 return max2 - n - 1;
927         }
928 
929         return n; // NOTREACHED
930     }
931 
932     case STBIR_EDGE_WRAP:
933         if (n >= 0)
934             return (n % max);
935         else
936         {
937             int m = (-n) % max;
938 
939             if (m != 0)
940                 m = max - m;
941 
942             return (m);
943         }
944         // NOTREACHED
945 
946     default:
947         assert(false, "Unimplemented edge type");
948     }
949 }
950 
951 static int stbir__edge_wrap(stbir_edge edge, int n, int max)
952 {
953     // avoid per-pixel switch
954     if (n >= 0 && n < max)
955         return n;
956     return stbir__edge_wrap_slow(edge, n, max);
957 }
958 
959 // What input pixels contribute to this output pixel?
960 static void stbir__calculate_sample_range_upsample(int n, float out_filter_radius, float scale_ratio, float out_shift, int* in_first_pixel, int* in_last_pixel, float* in_center_of_out)
961 {
962     float out_pixel_center = cast(float)n + 0.5f;
963     float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius;
964     float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius;
965 
966     float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio;
967     float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio;
968 
969     *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio;
970     *in_first_pixel = cast(int)(fast_floor(in_pixel_influence_lowerbound + 0.5));
971     *in_last_pixel = cast(int)(fast_floor(in_pixel_influence_upperbound - 0.5));
972 }
973 
974 // What output pixels does this input pixel contribute to?
975 static void stbir__calculate_sample_range_downsample(int n, float in_pixels_radius, float scale_ratio, float out_shift, int* out_first_pixel, int* out_last_pixel, float* out_center_of_in)
976 {
977     float in_pixel_center = cast(float)n + 0.5f;
978     float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;
979     float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;
980 
981     float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift;
982     float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift;
983 
984     *out_center_of_in = in_pixel_center * scale_ratio - out_shift;
985     *out_first_pixel = cast(int)(fast_floor(out_pixel_influence_lowerbound + 0.5));
986     *out_last_pixel = cast(int)(fast_floor(out_pixel_influence_upperbound - 0.5));
987 }
988 
989 static void stbir__calculate_coefficients_upsample(stbir_filter filter, float scale, int in_first_pixel, int in_last_pixel, float in_center_of_out, stbir__contributors* contributor, float* coefficient_group)
990 {
991     int i;
992     float total_filter = 0;
993     float filter_scale;
994 
995     assert(in_last_pixel - in_first_pixel <= cast(int)fast_ceil(stbir__filter_info_table[filter].support(1/scale) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
996 
997     contributor.n0 = in_first_pixel;
998     contributor.n1 = in_last_pixel;
999 
1000     assert(contributor.n1 >= contributor.n0);
1001 
1002     for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
1003     {
1004         float in_pixel_center = cast(float)(i + in_first_pixel) + 0.5f;
1005         coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale);
1006 
1007         // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.)
1008         if (i == 0 && !coefficient_group[i])
1009         {
1010             contributor.n0 = ++in_first_pixel;
1011             i--;
1012             continue;
1013         }
1014 
1015         total_filter += coefficient_group[i];
1016     }
1017 
1018     assert(stbir__filter_info_table[filter].kernel(cast(float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
1019 
1020     assert(total_filter > 0.9);
1021     assert(total_filter < 1.1f); // Make sure it's not way off.
1022 
1023     // Make sure the sum of all coefficients is 1.
1024     filter_scale = 1 / total_filter;
1025 
1026     for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
1027         coefficient_group[i] *= filter_scale;
1028 
1029     for (i = in_last_pixel - in_first_pixel; i >= 0; i--)
1030     {
1031         if (coefficient_group[i])
1032             break;
1033 
1034         // This line has no weight. We can skip it.
1035         contributor.n1 = contributor.n0 + i - 1;
1036     }
1037 }
1038 
1039 static void stbir__calculate_coefficients_downsample(stbir_filter filter, float scale_ratio, int out_first_pixel, int out_last_pixel, float out_center_of_in, stbir__contributors* contributor, float* coefficient_group)
1040 {
1041     int i;
1042 
1043      assert(out_last_pixel - out_first_pixel <= cast(int)fast_ceil(stbir__filter_info_table[filter].support(scale_ratio) * 2)); // Taken directly from stbir__get_coefficient_width() which we can't call because we don't know if we're horizontal or vertical.
1044 
1045     contributor.n0 = out_first_pixel;
1046     contributor.n1 = out_last_pixel;
1047 
1048     assert(contributor.n1 >= contributor.n0);
1049 
1050     for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
1051     {
1052         float out_pixel_center = cast(float)(i + out_first_pixel) + 0.5f;
1053         float x = out_pixel_center - out_center_of_in;
1054         coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
1055     }
1056 
1057     assert(stbir__filter_info_table[filter].kernel(cast(float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
1058 
1059     for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
1060     {
1061         if (coefficient_group[i])
1062             break;
1063 
1064         // This line has no weight. We can skip it.
1065         contributor.n1 = contributor.n0 + i - 1;
1066     }
1067 }
1068 
1069 static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size)
1070 {
1071     int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
1072     int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
1073     int i, j;
1074     int skip;
1075 
1076     for (i = 0; i < output_size; i++)
1077     {
1078         float scale;
1079         float total = 0;
1080 
1081         for (j = 0; j < num_contributors; j++)
1082         {
1083             if (i >= contributors[j].n0 && i <= contributors[j].n1)
1084             {
1085                 float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0);
1086                 total += coefficient;
1087             }
1088             else if (i < contributors[j].n0)
1089                 break;
1090         }
1091 
1092         assert(total > 0.9f);
1093         assert(total < 1.1f);
1094 
1095         scale = 1 / total;
1096 
1097         for (j = 0; j < num_contributors; j++)
1098         {
1099             if (i >= contributors[j].n0 && i <= contributors[j].n1)
1100                 *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale;
1101             else if (i < contributors[j].n0)
1102                 break;
1103         }
1104     }
1105 
1106     // Optimize: Skip zero coefficients and contributions outside of image bounds.
1107     // Do this after normalizing because normalization depends on the n0/n1 values.
1108     for (j = 0; j < num_contributors; j++)
1109     {
1110         int range, max, width;
1111 
1112         skip = 0;
1113         while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0)
1114             skip++;
1115 
1116         contributors[j].n0 += skip;
1117 
1118         while (contributors[j].n0 < 0)
1119         {
1120             contributors[j].n0++;
1121             skip++;
1122         }
1123 
1124         range = contributors[j].n1 - contributors[j].n0 + 1;
1125         max = stbir__min(num_coefficients, range);
1126 
1127         width = stbir__get_coefficient_width(filter, scale_ratio);
1128         for (i = 0; i < max; i++)
1129         {
1130             if (i + skip >= width)
1131                 break;
1132 
1133             *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip);
1134         }
1135 
1136         continue;
1137     }
1138 
1139     // Using min to avoid writing into invalid pixels.
1140     for (i = 0; i < num_contributors; i++)
1141         contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1);
1142 }
1143 
1144 // Each scan line uses the same kernel values so we should calculate the kernel
1145 // values once and then we can use them for every scan line.
1146 static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
1147 {
1148     int n;
1149     int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
1150 
1151     if (stbir__use_upsampling(scale_ratio))
1152     {
1153         float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio;
1154 
1155         // Looping through out pixels
1156         for (n = 0; n < total_contributors; n++)
1157         {
1158             float in_center_of_out; // Center of the current out pixel in the in pixel space
1159             int in_first_pixel, in_last_pixel;
1160 
1161             stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
1162 
1163             stbir__calculate_coefficients_upsample(filter, scale_ratio, in_first_pixel, in_last_pixel, in_center_of_out, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
1164         }
1165     }
1166     else
1167     {
1168         float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio;
1169 
1170         // Looping through in pixels
1171         for (n = 0; n < total_contributors; n++)
1172         {
1173             float out_center_of_in; // Center of the current out pixel in the in pixel space
1174             int out_first_pixel, out_last_pixel;
1175             int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio);
1176 
1177             stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
1178 
1179             stbir__calculate_coefficients_downsample(filter, scale_ratio, out_first_pixel, out_last_pixel, out_center_of_in, stbir__get_contributor(contributors, n), stbir__get_coefficient(coefficients, filter, scale_ratio, n, 0));
1180         }
1181 
1182         stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
1183     }
1184 }
1185 
1186 static float* stbir__get_decode_buffer(stbir__info* stbir_info)
1187 {
1188     // The 0 index of the decode buffer starts after the margin. This makes
1189     // it okay to use negative indexes on the decode buffer.
1190     return &stbir_info.decode_buffer[stbir_info.horizontal_filter_pixel_margin * stbir_info.channels];
1191 }
1192 
1193 int STBIR__DECODE(int type, int colorspace)
1194 {
1195     return type * STBIR_MAX_COLORSPACES + colorspace;
1196 }
1197 
1198 static void stbir__decode_scanline(stbir__info* stbir_info, int n)
1199 {
1200     int c;
1201     int channels = stbir_info.channels;
1202     int alpha_channel = stbir_info.alpha_channel;
1203     int type = stbir_info.type;
1204     int colorspace = stbir_info.colorspace;
1205     int input_w = stbir_info.input_w;
1206     size_t input_stride_bytes = stbir_info.input_stride_bytes;
1207     float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1208     stbir_edge edge_horizontal = stbir_info.edge_horizontal;
1209     stbir_edge edge_vertical = stbir_info.edge_vertical;
1210     size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info.input_h) * input_stride_bytes;
1211     const void* input_data = cast(char *) stbir_info.input_data + in_buffer_row_offset;
1212     int max_x = input_w + stbir_info.horizontal_filter_pixel_margin;
1213     int decode = STBIR__DECODE(type, colorspace);
1214 
1215     int x = -stbir_info.horizontal_filter_pixel_margin;
1216 
1217     // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input,
1218     // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO
1219     if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info.input_h))
1220     {
1221         for (; x < max_x; x++)
1222             for (c = 0; c < channels; c++)
1223                 decode_buffer[x*channels + c] = 0;
1224         return;
1225     }
1226 
1227     switch (decode)
1228     {
1229     case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
1230         for (; x < max_x; x++)
1231         {
1232             int decode_pixel_index = x * channels;
1233             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1234             for (c = 0; c < channels; c++)
1235                 decode_buffer[decode_pixel_index + c] = (cast(float)(cast(const(ubyte)*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
1236         }
1237         break;
1238 
1239     case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
1240         if (channels == 4 && alpha_channel == 3 && !(stbir_info.flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1241         {
1242             // This avoids one table lookup, but the table is the fastest way to onvet from sRGB to linear float
1243             for (; x < max_x; x++)
1244             {
1245                 int decode_pixel_index = x * channels;
1246                 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1247                 for (c = 0; c < 3; c++)
1248                     decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[(cast(const(ubyte)*)input_data)[input_pixel_index + c]];
1249                 ubyte alpha = (cast(const(ubyte)*)input_data)[input_pixel_index + 3];
1250                 decode_buffer[decode_pixel_index + 3] = cast(float)(alpha * 0.00392156862f);
1251             }
1252         }
1253 
1254         for (; x < max_x; x++)
1255         {
1256             int decode_pixel_index = x * channels;
1257             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1258             for (c = 0; c < channels; c++)
1259                 decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[(cast(const(ubyte)*)input_data)[input_pixel_index + c]];
1260 
1261             if (!(stbir_info.flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1262                 decode_buffer[decode_pixel_index + alpha_channel] = (cast(float)(cast(const(ubyte)*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
1263         }
1264         break;
1265 
1266     case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
1267     {
1268         if (channels == 1 && edge_horizontal == STBIR_EDGE_CLAMP)
1269         {
1270             for (; x < max_x; x++)
1271             {
1272                 int decode_pixel_index = x;
1273                 int input_pixel_index = stbir__edge_wrap(STBIR_EDGE_CLAMP, x, input_w) * channels;
1274                 ushort depth = (cast(const(ushort)*)input_data)[input_pixel_index];
1275                 decode_buffer[decode_pixel_index] = depth / stbir__max_uint16_as_float;
1276             }
1277         }
1278         else if (channels == 4 && edge_horizontal == STBIR_EDGE_CLAMP)
1279         {
1280             __m128i zero = _mm_setzero_si128();
1281             __m128 normalizingFactor = _mm_set1_ps(1 / 65535.0f);
1282 
1283             for (; x < max_x; x++)
1284             {
1285                 int decode_pixel_index = x * channels;
1286                 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1287 
1288                 // load four values at once
1289                 __m128i mmPixel = _mm_loadu_si64( (cast(const(ushort)*)input_data) + input_pixel_index );
1290                 mmPixel = _mm_unpacklo_epi16(mmPixel, zero); // convert to 32-bit
1291                 __m128 fPixel = _mm_cvtepi32_ps(mmPixel) * normalizingFactor;
1292                 _mm_storeu_ps(&decode_buffer[decode_pixel_index], fPixel);
1293             }
1294         }
1295         else
1296         {
1297             for (; x < max_x; x++)
1298             {
1299                 int decode_pixel_index = x * channels;
1300                 int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1301                 for (c = 0; c < channels; c++)
1302                 {
1303                     ushort depth = (cast(const(ushort)*)input_data)[input_pixel_index + c];
1304                     decode_buffer[decode_pixel_index + c] = depth / stbir__max_uint16_as_float;
1305                 }
1306             }
1307         }
1308         break;
1309     }
1310 
1311     case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
1312         for (; x < max_x; x++)
1313         {
1314             int decode_pixel_index = x * channels;
1315             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1316             for (c = 0; c < channels; c++)
1317                 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((cast(float)(cast(const(ushort)*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float);
1318 
1319             if (!(stbir_info.flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1320                 decode_buffer[decode_pixel_index + alpha_channel] = (cast(float)(cast(const(ushort)*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
1321         }
1322         break;
1323 
1324     case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
1325         for (; x < max_x; x++)
1326         {
1327             int decode_pixel_index = x * channels;
1328             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1329             for (c = 0; c < channels; c++)
1330                 decode_buffer[decode_pixel_index + c] = cast(float)((cast(double)(cast(const uint*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
1331         }
1332         break;
1333 
1334     case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
1335         for (; x < max_x; x++)
1336         {
1337             int decode_pixel_index = x * channels;
1338             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1339             for (c = 0; c < channels; c++)
1340                 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(cast(float)((cast(double)(cast(const uint*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float));
1341 
1342             if (!(stbir_info.flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1343                 decode_buffer[decode_pixel_index + alpha_channel] = cast(float)((cast(double)(cast(const uint*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
1344         }
1345         break;
1346 
1347     case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
1348         for (; x < max_x; x++)
1349         {
1350             int decode_pixel_index = x * channels;
1351             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1352             for (c = 0; c < channels; c++)
1353                 decode_buffer[decode_pixel_index + c] = (cast(const(float)*)input_data)[input_pixel_index + c];
1354         }
1355         break;
1356 
1357     case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
1358         for (; x < max_x; x++)
1359         {
1360             int decode_pixel_index = x * channels;
1361             int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
1362             for (c = 0; c < channels; c++)
1363                 decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((cast(const(float)*)input_data)[input_pixel_index + c]);
1364 
1365             if (!(stbir_info.flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1366                 decode_buffer[decode_pixel_index + alpha_channel] = (cast(const(float)*)input_data)[input_pixel_index + alpha_channel];
1367         }
1368 
1369         break;
1370 
1371     default:
1372         assert(!"Unknown type/colorspace/channels combination.");
1373         break;
1374     }
1375 
1376     if (!(stbir_info.flags & STBIR_FLAG_ALPHA_PREMULTIPLIED))
1377     {
1378         for (x = -stbir_info.horizontal_filter_pixel_margin; x < max_x; x++)
1379         {
1380             int decode_pixel_index = x * channels;
1381 
1382             // If the alpha value is 0 it will clobber the color values. Make sure it's not.
1383             float alpha = decode_buffer[decode_pixel_index + alpha_channel];
1384 
1385             version(STBIR_NO_ALPHA_EPSILON)
1386             {}
1387             else
1388             {
1389                 if (stbir_info.type != STBIR_TYPE_FLOAT) {
1390                     alpha += STBIR_ALPHA_EPSILON;
1391                     decode_buffer[decode_pixel_index + alpha_channel] = alpha;
1392                 }
1393             }
1394 
1395             for (c = 0; c < channels; c++)
1396             {
1397                 if (c == alpha_channel)
1398                     continue;
1399 
1400                 decode_buffer[decode_pixel_index + c] *= alpha;
1401             }
1402         }
1403     }
1404 
1405     if (edge_horizontal == STBIR_EDGE_ZERO)
1406     {
1407         for (x = -stbir_info.horizontal_filter_pixel_margin; x < 0; x++)
1408         {
1409             for (c = 0; c < channels; c++)
1410                 decode_buffer[x*channels + c] = 0;
1411         }
1412         for (x = input_w; x < max_x; x++)
1413         {
1414             for (c = 0; c < channels; c++)
1415                 decode_buffer[x*channels + c] = 0;
1416         }
1417     }
1418 }
1419 
1420 static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length)
1421 {
1422     return &ring_buffer[index * ring_buffer_length];
1423 }
1424 
1425 static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
1426 {
1427     int ring_buffer_index;
1428     float* ring_buffer;
1429 
1430     stbir_info.ring_buffer_last_scanline = n;
1431 
1432     if (stbir_info.ring_buffer_begin_index < 0)
1433     {
1434         ring_buffer_index = stbir_info.ring_buffer_begin_index = 0;
1435         stbir_info.ring_buffer_first_scanline = n;
1436     }
1437     else
1438     {
1439         ring_buffer_index = (stbir_info.ring_buffer_begin_index + (stbir_info.ring_buffer_last_scanline - stbir_info.ring_buffer_first_scanline)) % stbir_info.ring_buffer_num_entries;
1440         assert(ring_buffer_index != stbir_info.ring_buffer_begin_index);
1441     }
1442 
1443     ring_buffer = stbir__get_ring_buffer_entry(stbir_info.ring_buffer, ring_buffer_index, stbir_info.ring_buffer_length_bytes / cast(int)(float.sizeof));
1444     memset(ring_buffer, 0, stbir_info.ring_buffer_length_bytes);
1445 
1446     return ring_buffer;
1447 }
1448 
1449 
1450 static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer)
1451 {
1452     int x, k;
1453     int output_w = stbir_info.output_w;
1454     int channels = stbir_info.channels;
1455     float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1456     stbir__contributors* horizontal_contributors = stbir_info.horizontal_contributors;
1457     float* horizontal_coefficients = stbir_info.horizontal_coefficients;
1458     int coefficient_width = stbir_info.horizontal_coefficient_width;
1459 
1460     for (x = 0; x < output_w; x++)
1461     {
1462         int n0 = horizontal_contributors[x].n0;
1463         int n1 = horizontal_contributors[x].n1;
1464 
1465         int out_pixel_index = x * channels;
1466         int coefficient_group = coefficient_width * x;
1467         int coefficient_counter = 0;
1468 
1469         assert(n1 >= n0);
1470         assert(n0 >= -stbir_info.horizontal_filter_pixel_margin);
1471         assert(n1 >= -stbir_info.horizontal_filter_pixel_margin);
1472         assert(n0 < stbir_info.input_w + stbir_info.horizontal_filter_pixel_margin);
1473         assert(n1 < stbir_info.input_w + stbir_info.horizontal_filter_pixel_margin);
1474 
1475         switch (channels) {
1476             case 1:
1477                 for (k = n0; k <= n1; k++)
1478                 {
1479                     int in_pixel_index = k * 1;
1480                     float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1481                     //assert(coefficient != 0);
1482                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1483                 }
1484                 break;
1485             case 2:
1486                 for (k = n0; k <= n1; k++)
1487                 {
1488                     int in_pixel_index = k * 2;
1489                     float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1490                     //assert(coefficient != 0);
1491                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1492                     output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1493                 }
1494                 break;
1495             case 3:
1496                 for (k = n0; k <= n1; k++)
1497                 {
1498                     int in_pixel_index = k * 3;
1499                     float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1500                     //assert(coefficient != 0);
1501                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1502                     output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1503                     output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1504                 }
1505                 break;
1506             case 4:
1507                 for (k = n0; k <= n1; k++)
1508                 {
1509                     int in_pixel_index = k * 4;
1510                     float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1511                     //assert(coefficient != 0);
1512                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1513                     output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1514                     output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1515                     output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
1516                 }
1517                 break;
1518             default:
1519                 for (k = n0; k <= n1; k++)
1520                 {
1521                     int in_pixel_index = k * channels;
1522                     float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
1523                     int c;
1524                     //assert(coefficient != 0);
1525                     for (c = 0; c < channels; c++)
1526                         output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
1527                 }
1528                 break;
1529         }
1530     }
1531 }
1532 
1533 static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer)
1534 {
1535     int x, k;
1536     int input_w = stbir_info.input_w;
1537     int channels = stbir_info.channels;
1538     float* decode_buffer = stbir__get_decode_buffer(stbir_info);
1539     stbir__contributors* horizontal_contributors = stbir_info.horizontal_contributors;
1540     float* horizontal_coefficients = stbir_info.horizontal_coefficients;
1541     int coefficient_width = stbir_info.horizontal_coefficient_width;
1542     int filter_pixel_margin = stbir_info.horizontal_filter_pixel_margin;
1543     int max_x = input_w + filter_pixel_margin * 2;
1544 
1545     assert(!stbir__use_width_upsampling(stbir_info));
1546 
1547     switch (channels) {
1548         case 1:
1549             for (x = 0; x < max_x; x++)
1550             {
1551                 int n0 = horizontal_contributors[x].n0;
1552                 int n1 = horizontal_contributors[x].n1;
1553 
1554                 int in_x = x - filter_pixel_margin;
1555                 int in_pixel_index = in_x * 1;
1556                 int max_n = n1;
1557                 int coefficient_group = coefficient_width * x;
1558 
1559                 for (k = n0; k <= max_n; k++)
1560                 {
1561                     int out_pixel_index = k * 1;
1562                     float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1563                     //assert(coefficient != 0); // Note: this makes MKS 2021 crash
1564                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1565                 }
1566             }
1567             break;
1568 
1569         case 2:
1570             for (x = 0; x < max_x; x++)
1571             {
1572                 int n0 = horizontal_contributors[x].n0;
1573                 int n1 = horizontal_contributors[x].n1;
1574 
1575                 int in_x = x - filter_pixel_margin;
1576                 int in_pixel_index = in_x * 2;
1577                 int max_n = n1;
1578                 int coefficient_group = coefficient_width * x;
1579 
1580                 for (k = n0; k <= max_n; k++)
1581                 {
1582                     int out_pixel_index = k * 2;
1583                     float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1584                     //assert(coefficient != 0); // Note: this makes MKS 2021 crash
1585                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1586                     output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1587                 }
1588             }
1589             break;
1590 
1591         case 3:
1592             for (x = 0; x < max_x; x++)
1593             {
1594                 int n0 = horizontal_contributors[x].n0;
1595                 int n1 = horizontal_contributors[x].n1;
1596 
1597                 int in_x = x - filter_pixel_margin;
1598                 int in_pixel_index = in_x * 3;
1599                 int max_n = n1;
1600                 int coefficient_group = coefficient_width * x;
1601 
1602                 for (k = n0; k <= max_n; k++)
1603                 {
1604                     int out_pixel_index = k * 3;
1605                     float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1606                     //assert(coefficient != 0); // Note: this makes MKS 2021 crash
1607                     output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1608                     output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1609                     output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1610                 }
1611             }
1612             break;
1613 
1614         case 4:
1615             for (x = 0; x < max_x; x++)
1616             {
1617                 int n0 = horizontal_contributors[x].n0;
1618                 int n1 = horizontal_contributors[x].n1;
1619 
1620                 int in_x = x - filter_pixel_margin;
1621                 int in_pixel_index = in_x * 4;
1622                 int max_n = n1;
1623                 int coefficient_group = coefficient_width * x;
1624 
1625                 for (k = n0; k <= max_n; k++)
1626                 {
1627                     int out_pixel_index = k * 4;
1628                     float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1629                     //assert(coefficient != 0); // Note: this makes MKS 2021 crash
1630 
1631                     version(DigitalMars)
1632                     {
1633                         output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
1634                         output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
1635                         output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
1636                         output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
1637                     }
1638                     else
1639                     {
1640                         __m128 A = _mm_loadu_ps(&decode_buffer[in_pixel_index]);
1641                         __m128 B = _mm_loadu_ps(&output_buffer[out_pixel_index]);
1642                         B = B + A * _mm_set1_ps(coefficient);
1643                         _mm_storeu_ps(&output_buffer[out_pixel_index], B);
1644                     }
1645                 }
1646             }
1647             break;
1648 
1649         default:
1650             for (x = 0; x < max_x; x++)
1651             {
1652                 int n0 = horizontal_contributors[x].n0;
1653                 int n1 = horizontal_contributors[x].n1;
1654 
1655                 int in_x = x - filter_pixel_margin;
1656                 int in_pixel_index = in_x * channels;
1657                 int max_n = n1;
1658                 int coefficient_group = coefficient_width * x;
1659 
1660                 for (k = n0; k <= max_n; k++)
1661                 {
1662                     int c;
1663                     int out_pixel_index = k * channels;
1664                     float coefficient = horizontal_coefficients[coefficient_group + k - n0];
1665                     //assert(coefficient != 0); // Note: this makes MKS 2021 crash
1666                     for (c = 0; c < channels; c++)
1667                         output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
1668                 }
1669             }
1670             break;
1671     }
1672 }
1673 
1674 static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n)
1675 {
1676     // Decode the nth scanline from the source image into the decode buffer.
1677     stbir__decode_scanline(stbir_info, n);
1678 
1679     // Now resample it into the ring buffer.
1680     if (stbir__use_width_upsampling(stbir_info))
1681         stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
1682     else
1683         stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
1684 
1685     // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
1686 }
1687 
1688 static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n)
1689 {
1690     // Decode the nth scanline from the source image into the decode buffer.
1691     stbir__decode_scanline(stbir_info, n);
1692 
1693     memset(stbir_info.horizontal_buffer, 0, stbir_info.output_w * stbir_info.channels * float.sizeof);
1694 
1695     // Now resample it into the horizontal buffer.
1696     if (stbir__use_width_upsampling(stbir_info))
1697         stbir__resample_horizontal_upsample(stbir_info, stbir_info.horizontal_buffer);
1698     else
1699         stbir__resample_horizontal_downsample(stbir_info, stbir_info.horizontal_buffer);
1700 
1701     // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
1702 }
1703 
1704 // Get the specified scan line from the ring buffer.
1705 static float* stbir__get_ring_buffer_scanline(int get_scanline, float* ring_buffer, int begin_index, int first_scanline, int ring_buffer_num_entries, int ring_buffer_length)
1706 {
1707     int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
1708     return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
1709 }
1710 
1711 
1712 static void stbir__encode_scanline(stbir__info* stbir_info, int num_pixels, void *output_buffer, float *encode_buffer, int channels, int alpha_channel, int decode)
1713 {
1714     int x;
1715     int n;
1716     int num_nonalpha;
1717     ushort[STBIR_MAX_CHANNELS] nonalpha;
1718 
1719     if (!(stbir_info.flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
1720     {
1721         for (x=0; x < num_pixels; ++x)
1722         {
1723             int pixel_index = x*channels;
1724 
1725             float alpha = encode_buffer[pixel_index + alpha_channel];
1726             float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
1727 
1728             // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb
1729             for (n = 0; n < channels; n++)
1730                 if (n != alpha_channel)
1731                     encode_buffer[pixel_index + n] *= reciprocal_alpha;
1732 
1733             // We added in a small epsilon to prevent the color channel from being deleted with zero alpha.
1734             // Because we only add it for integer types, it will automatically be discarded on integer
1735             // conversion, so we don't need to subtract it back out (which would be problematic for
1736             // numeric precision reasons).
1737         }
1738     }
1739 
1740     // build a table of all channels that need colorspace correction, so
1741     // we don't perform colorspace correction on channels that don't need it.
1742     for (x = 0, num_nonalpha = 0; x < channels; ++x)
1743     {
1744         if (x != alpha_channel || (stbir_info.flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
1745         {
1746             nonalpha[num_nonalpha++] = cast(ushort)x;
1747         }
1748     }
1749 
1750     static int STBIR__ROUND_INT_f(float f)
1751     {
1752         return cast(int)(f + 0.5f);
1753     }
1754     static int STBIR__ROUND_INT_d(double f)
1755     {
1756         return cast(int)(f + 0.5);
1757     }
1758     static int STBIR__ROUND_UINT_f(float f)
1759     {
1760         return cast(uint)(f + 0.5f);
1761     }
1762     static int STBIR__ROUND_UINT_d(double f)
1763     {
1764         return cast(uint)(f + 0.5);
1765     }
1766 
1767     static ubyte STBIR__ENCODE_LINEAR8(float f)
1768     {
1769         return cast(ubyte) STBIR__ROUND_INT_f(stbir__saturate(f) * stbir__max_uint8_as_float );
1770     }
1771 
1772     static ushort STBIR__ENCODE_LINEAR16(float f)
1773     {
1774         return cast(ushort) STBIR__ROUND_INT_f(stbir__saturate(f) * stbir__max_uint16_as_float );
1775     }
1776 
1777     switch (decode)
1778     {
1779         case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
1780             for (x=0; x < num_pixels; ++x)
1781             {
1782                 int pixel_index = x*channels;
1783 
1784                 for (n = 0; n < channels; n++)
1785                 {
1786                     int index = pixel_index + n;
1787                     (cast(ubyte*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]);
1788                 }
1789             }
1790             break;
1791 
1792         case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
1793         {
1794             // Special case because of how slow it is in normal stb_image_resize.
1795             if (channels == 4 && alpha_channel == -1 && (stbir_info.flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
1796             {
1797                 for (x = 0; x < num_pixels; ++x)
1798                 {
1799                     __m128i zero = _mm_setzero_si128();
1800 
1801                     __m128 fpixels = _mm_loadu_ps( &encode_buffer[4*x] );
1802                     __m128i fpixels_desrgb = stbir__linear_to_srgb_uchar(fpixels);
1803                     _mm_storeu_si32( (cast(ubyte*)output_buffer) + 4*x, fpixels_desrgb);
1804                 }
1805             }
1806             else
1807             {
1808                 for (x = 0; x < num_pixels; ++x)
1809                 {
1810                     int pixel_index = x*channels;
1811 
1812                     for (n = 0; n < num_nonalpha; n++)
1813                     {
1814                         int index = pixel_index + nonalpha[n];
1815                         (cast(ubyte*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]);
1816                     }
1817 
1818                     if (!(stbir_info.flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
1819                         (cast(ubyte*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]);
1820                 }
1821             }
1822             break;
1823         }
1824 
1825         case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
1826             for (x=0; x < num_pixels; ++x)
1827             {
1828                 int pixel_index = x*channels;
1829 
1830                 for (n = 0; n < channels; n++)
1831                 {
1832                     int index = pixel_index + n;
1833                     (cast(ushort*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]);
1834                 }
1835             }
1836             break;
1837 
1838         case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
1839             for (x=0; x < num_pixels; ++x)
1840             {
1841                 int pixel_index = x*channels;
1842 
1843                 for (n = 0; n < num_nonalpha; n++)
1844                 {
1845                     int index = pixel_index + nonalpha[n];
1846                     (cast(ushort*)output_buffer)[index] = cast(ushort)STBIR__ROUND_INT_f(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
1847                 }
1848 
1849                 if (!(stbir_info.flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1850                     (cast(ushort*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]);
1851             }
1852 
1853             break;
1854 
1855         case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
1856             for (x=0; x < num_pixels; ++x)
1857             {
1858                 int pixel_index = x*channels;
1859 
1860                 for (n = 0; n < channels; n++)
1861                 {
1862                     int index = pixel_index + n;
1863                     (cast(uint*)output_buffer)[index] = cast(uint)STBIR__ROUND_UINT_d((cast(double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
1864                 }
1865             }
1866             break;
1867 
1868         case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
1869             for (x=0; x < num_pixels; ++x)
1870             {
1871                 int pixel_index = x*channels;
1872 
1873                 for (n = 0; n < num_nonalpha; n++)
1874                 {
1875                     int index = pixel_index + nonalpha[n];
1876                     (cast(uint*)output_buffer)[index] = cast(uint)STBIR__ROUND_UINT_d((cast(double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float);
1877                 }
1878 
1879                 if (!(stbir_info.flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1880                     (cast(uint*)output_buffer)[pixel_index + alpha_channel] = cast(uint) STBIR__ROUND_INT_d((cast(double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float);
1881             }
1882             break;
1883 
1884         case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
1885             for (x=0; x < num_pixels; ++x)
1886             {
1887                 int pixel_index = x*channels;
1888 
1889                 for (n = 0; n < channels; n++)
1890                 {
1891                     int index = pixel_index + n;
1892                     (cast(float*)output_buffer)[index] = encode_buffer[index];
1893                 }
1894             }
1895             break;
1896 
1897         case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
1898             for (x=0; x < num_pixels; ++x)
1899             {
1900                 int pixel_index = x*channels;
1901 
1902                 for (n = 0; n < num_nonalpha; n++)
1903                 {
1904                     int index = pixel_index + nonalpha[n];
1905                     (cast(float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]);
1906                 }
1907 
1908                 if (!(stbir_info.flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
1909                     (cast(float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel];
1910             }
1911             break;
1912 
1913         default:
1914             assert(!"Unknown type/colorspace/channels combination.");
1915             break;
1916     }
1917 }
1918 
1919 static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n)
1920 {
1921     int x, k;
1922     int output_w = stbir_info.output_w;
1923     stbir__contributors* vertical_contributors = stbir_info.vertical_contributors;
1924     float* vertical_coefficients = stbir_info.vertical_coefficients;
1925     int channels = stbir_info.channels;
1926     int alpha_channel = stbir_info.alpha_channel;
1927     int type = stbir_info.type;
1928     int colorspace = stbir_info.colorspace;
1929     int ring_buffer_entries = stbir_info.ring_buffer_num_entries;
1930     void* output_data = stbir_info.output_data;
1931     float* encode_buffer = stbir_info.encode_buffer;
1932     int decode = STBIR__DECODE(type, colorspace);
1933     int coefficient_width = stbir_info.vertical_coefficient_width;
1934     int coefficient_counter;
1935     int contributor = n;
1936 
1937     float* ring_buffer = stbir_info.ring_buffer;
1938     int ring_buffer_begin_index = stbir_info.ring_buffer_begin_index;
1939     int ring_buffer_first_scanline = stbir_info.ring_buffer_first_scanline;
1940     int ring_buffer_length = stbir_info.ring_buffer_length_bytes / cast(int)(float.sizeof);
1941 
1942     int n0,n1, output_row_start;
1943     int coefficient_group = coefficient_width * contributor;
1944 
1945     n0 = vertical_contributors[contributor].n0;
1946     n1 = vertical_contributors[contributor].n1;
1947 
1948     output_row_start = n * stbir_info.output_stride_bytes;
1949 
1950     assert(stbir__use_height_upsampling(stbir_info));
1951 
1952     memset(encode_buffer, 0, output_w * float.sizeof * channels);
1953 
1954     // I tried reblocking this for better cache usage of encode_buffer
1955     // (using x_outer, k, x_inner), but it lost speed. -- stb
1956 
1957     coefficient_counter = 0;
1958     switch (channels) {
1959         case 1:
1960             for (k = n0; k <= n1; k++)
1961             {
1962                 int coefficient_index = coefficient_counter++;
1963                 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1964                 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1965                 for (x = 0; x < output_w; ++x)
1966                 {
1967                     int in_pixel_index = x * 1;
1968                     encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1969                 }
1970             }
1971             break;
1972         case 2:
1973             for (k = n0; k <= n1; k++)
1974             {
1975                 int coefficient_index = coefficient_counter++;
1976                 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1977                 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1978                 for (x = 0; x < output_w; ++x)
1979                 {
1980                     int in_pixel_index = x * 2;
1981                     encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1982                     encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1983                 }
1984             }
1985             break;
1986         case 3:
1987             for (k = n0; k <= n1; k++)
1988             {
1989                 int coefficient_index = coefficient_counter++;
1990                 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
1991                 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
1992                 for (x = 0; x < output_w; ++x)
1993                 {
1994                     int in_pixel_index = x * 3;
1995                     encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
1996                     encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
1997                     encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
1998                 }
1999             }
2000             break;
2001         case 4:
2002             for (k = n0; k <= n1; k++)
2003             {
2004                 int coefficient_index = coefficient_counter++;
2005                 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
2006                 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
2007                 for (x = 0; x < output_w; ++x)
2008                 {
2009                     int in_pixel_index = x * 4;
2010                     encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
2011                     encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
2012                     encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
2013                     encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient;
2014                 }
2015             }
2016             break;
2017         default:
2018             for (k = n0; k <= n1; k++)
2019             {
2020                 int coefficient_index = coefficient_counter++;
2021                 float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
2022                 float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
2023                 for (x = 0; x < output_w; ++x)
2024                 {
2025                     int in_pixel_index = x * channels;
2026                     int c;
2027                     for (c = 0; c < channels; c++)
2028                         encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient;
2029                 }
2030             }
2031             break;
2032     }
2033     stbir__encode_scanline(stbir_info, output_w, cast(char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
2034 }
2035 
2036 static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n)
2037 {
2038     int x, k;
2039     int output_w = stbir_info.output_w;
2040     stbir__contributors* vertical_contributors = stbir_info.vertical_contributors;
2041     float* vertical_coefficients = stbir_info.vertical_coefficients;
2042     int channels = stbir_info.channels;
2043     int ring_buffer_entries = stbir_info.ring_buffer_num_entries;
2044     float* horizontal_buffer = stbir_info.horizontal_buffer;
2045     int coefficient_width = stbir_info.vertical_coefficient_width;
2046     int contributor = n + stbir_info.vertical_filter_pixel_margin;
2047 
2048     float* ring_buffer = stbir_info.ring_buffer;
2049     int ring_buffer_begin_index = stbir_info.ring_buffer_begin_index;
2050     int ring_buffer_first_scanline = stbir_info.ring_buffer_first_scanline;
2051     int ring_buffer_length = stbir_info.ring_buffer_length_bytes / cast(int)(float.sizeof);
2052     int n0,n1;
2053 
2054     n0 = vertical_contributors[contributor].n0;
2055     n1 = vertical_contributors[contributor].n1;
2056 
2057     assert(!stbir__use_height_upsampling(stbir_info));
2058 
2059     for (k = n0; k <= n1; k++)
2060     {
2061         int coefficient_index = k - n0;
2062         int coefficient_group = coefficient_width * contributor;
2063         float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
2064 
2065         float* ring_buffer_entry = stbir__get_ring_buffer_scanline(k, ring_buffer, ring_buffer_begin_index, ring_buffer_first_scanline, ring_buffer_entries, ring_buffer_length);
2066 
2067         switch (channels) {
2068             case 1:
2069                 for (x = 0; x < output_w; x++)
2070                 {
2071                     int in_pixel_index = x * 1;
2072                     ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2073                 }
2074                 break;
2075             case 2:
2076                 for (x = 0; x < output_w; x++)
2077                 {
2078                     int in_pixel_index = x * 2;
2079                     ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2080                     ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2081                 }
2082                 break;
2083             case 3:
2084                 for (x = 0; x < output_w; x++)
2085                 {
2086                     int in_pixel_index = x * 3;
2087                     ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
2088                     ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
2089                     ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
2090                 }
2091                 break;
2092             case 4:
2093 
2094                 __m128 vCoefficients = _mm_set1_ps(coefficient);
2095 
2096                 for (x = 0; x < output_w; x++)
2097                 {
2098                     int in_pixel_index = x * 4;
2099                     __m128 A = _mm_loadu_ps(&horizontal_buffer[in_pixel_index]);
2100                     __m128 B = _mm_loadu_ps(&ring_buffer_entry[in_pixel_index]);
2101                     _mm_storeu_ps( &ring_buffer_entry[in_pixel_index], B + A * vCoefficients);
2102                 }
2103                 break;
2104             default:
2105                 for (x = 0; x < output_w; x++)
2106                 {
2107                     int in_pixel_index = x * channels;
2108 
2109                     int c;
2110                     for (c = 0; c < channels; c++)
2111                         ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient;
2112                 }
2113                 break;
2114         }
2115     }
2116 }
2117 
2118 static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
2119 {
2120     int y;
2121     float scale_ratio = stbir_info.vertical_scale;
2122     float out_scanlines_radius = stbir__filter_info_table[stbir_info.vertical_filter].support(1/scale_ratio) * scale_ratio;
2123 
2124     assert(stbir__use_height_upsampling(stbir_info));
2125 
2126     for (y = 0; y < stbir_info.output_h; y++)
2127     {
2128         float in_center_of_out = 0; // Center of the current out scanline in the in scanline space
2129         int in_first_scanline = 0, in_last_scanline = 0;
2130 
2131         stbir__calculate_sample_range_upsample(y, out_scanlines_radius, scale_ratio, stbir_info.vertical_shift, &in_first_scanline, &in_last_scanline, &in_center_of_out);
2132 
2133         assert(in_last_scanline - in_first_scanline + 1 <= stbir_info.ring_buffer_num_entries);
2134 
2135         if (stbir_info.ring_buffer_begin_index >= 0)
2136         {
2137             // Get rid of whatever we don't need anymore.
2138             while (in_first_scanline > stbir_info.ring_buffer_first_scanline)
2139             {
2140                 if (stbir_info.ring_buffer_first_scanline == stbir_info.ring_buffer_last_scanline)
2141                 {
2142                     // We just popped the last scanline off the ring buffer.
2143                     // Reset it to the empty state.
2144                     stbir_info.ring_buffer_begin_index = -1;
2145                     stbir_info.ring_buffer_first_scanline = 0;
2146                     stbir_info.ring_buffer_last_scanline = 0;
2147                     break;
2148                 }
2149                 else
2150                 {
2151                     stbir_info.ring_buffer_first_scanline++;
2152                     stbir_info.ring_buffer_begin_index = (stbir_info.ring_buffer_begin_index + 1) % stbir_info.ring_buffer_num_entries;
2153                 }
2154             }
2155         }
2156 
2157         // Load in new ones.
2158         if (stbir_info.ring_buffer_begin_index < 0)
2159             stbir__decode_and_resample_upsample(stbir_info, in_first_scanline);
2160 
2161         while (in_last_scanline > stbir_info.ring_buffer_last_scanline)
2162             stbir__decode_and_resample_upsample(stbir_info, stbir_info.ring_buffer_last_scanline + 1);
2163 
2164         // Now all buffers should be ready to write a row of vertical sampling.
2165         stbir__resample_vertical_upsample(stbir_info, y);
2166     }
2167 }
2168 
2169 static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline)
2170 {
2171     int output_stride_bytes = stbir_info.output_stride_bytes;
2172     int channels = stbir_info.channels;
2173     int alpha_channel = stbir_info.alpha_channel;
2174     int type = stbir_info.type;
2175     int colorspace = stbir_info.colorspace;
2176     int output_w = stbir_info.output_w;
2177     void* output_data = stbir_info.output_data;
2178     int decode = STBIR__DECODE(type, colorspace);
2179 
2180     float* ring_buffer = stbir_info.ring_buffer;
2181     int ring_buffer_length = stbir_info.ring_buffer_length_bytes / cast(int)(float.sizeof);
2182 
2183     if (stbir_info.ring_buffer_begin_index >= 0)
2184     {
2185         // Get rid of whatever we don't need anymore.
2186         while (first_necessary_scanline > stbir_info.ring_buffer_first_scanline)
2187         {
2188             if (stbir_info.ring_buffer_first_scanline >= 0 && stbir_info.ring_buffer_first_scanline < stbir_info.output_h)
2189             {
2190                 int output_row_start = stbir_info.ring_buffer_first_scanline * output_stride_bytes;
2191                 float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info.ring_buffer_begin_index, ring_buffer_length);
2192                 stbir__encode_scanline(stbir_info, output_w, cast(char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode);
2193             }
2194 
2195             if (stbir_info.ring_buffer_first_scanline == stbir_info.ring_buffer_last_scanline)
2196             {
2197                 // We just popped the last scanline off the ring buffer.
2198                 // Reset it to the empty state.
2199                 stbir_info.ring_buffer_begin_index = -1;
2200                 stbir_info.ring_buffer_first_scanline = 0;
2201                 stbir_info.ring_buffer_last_scanline = 0;
2202                 break;
2203             }
2204             else
2205             {
2206                 stbir_info.ring_buffer_first_scanline++;
2207                 stbir_info.ring_buffer_begin_index = (stbir_info.ring_buffer_begin_index + 1) % stbir_info.ring_buffer_num_entries;
2208             }
2209         }
2210     }
2211 }
2212 
2213 static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
2214 {
2215     int y;
2216     float scale_ratio = stbir_info.vertical_scale;
2217     int output_h = stbir_info.output_h;
2218     float in_pixels_radius = stbir__filter_info_table[stbir_info.vertical_filter].support(scale_ratio) / scale_ratio;
2219     int pixel_margin = stbir_info.vertical_filter_pixel_margin;
2220     int max_y = stbir_info.input_h + pixel_margin;
2221 
2222     assert(!stbir__use_height_upsampling(stbir_info));
2223 
2224     for (y = -pixel_margin; y < max_y; y++)
2225     {
2226         float out_center_of_in; // Center of the current out scanline in the in scanline space
2227         int out_first_scanline, out_last_scanline;
2228 
2229         stbir__calculate_sample_range_downsample(y, in_pixels_radius, scale_ratio, stbir_info.vertical_shift, &out_first_scanline, &out_last_scanline, &out_center_of_in);
2230 
2231         assert(out_last_scanline - out_first_scanline + 1 <= stbir_info.ring_buffer_num_entries);
2232 
2233         if (out_last_scanline < 0 || out_first_scanline >= output_h)
2234             continue;
2235 
2236         stbir__empty_ring_buffer(stbir_info, out_first_scanline);
2237 
2238         stbir__decode_and_resample_downsample(stbir_info, y);
2239 
2240         // Load in new ones.
2241         if (stbir_info.ring_buffer_begin_index < 0)
2242             stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline);
2243 
2244         while (out_last_scanline > stbir_info.ring_buffer_last_scanline)
2245             stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info.ring_buffer_last_scanline + 1);
2246 
2247         // Now the horizontal buffer is ready to write to all ring buffer rows.
2248         stbir__resample_vertical_downsample(stbir_info, y);
2249     }
2250 
2251     stbir__empty_ring_buffer(stbir_info, stbir_info.output_h);
2252 }
2253 
2254 static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels)
2255 {
2256     info.input_w = input_w;
2257     info.input_h = input_h;
2258     info.output_w = output_w;
2259     info.output_h = output_h;
2260     info.channels = channels;
2261 }
2262 
2263 static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform)
2264 {
2265     info.s0 = s0;
2266     info.t0 = t0;
2267     info.s1 = s1;
2268     info.t1 = t1;
2269 
2270     if (transform)
2271     {
2272         info.horizontal_scale = transform[0];
2273         info.vertical_scale   = transform[1];
2274         info.horizontal_shift = transform[2];
2275         info.vertical_shift   = transform[3];
2276     }
2277     else
2278     {
2279         info.horizontal_scale = (cast(float)info.output_w / info.input_w) / (s1 - s0);
2280         info.vertical_scale = (cast(float)info.output_h / info.input_h) / (t1 - t0);
2281 
2282         info.horizontal_shift = s0 * info.output_w / (s1 - s0);
2283         info.vertical_shift = t0 * info.output_h / (t1 - t0);
2284     }
2285 }
2286 
2287 static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter)
2288 {
2289     if (h_filter == 0)
2290         h_filter = stbir__use_upsampling(info.horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
2291     if (v_filter == 0)
2292         v_filter = stbir__use_upsampling(info.vertical_scale)   ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
2293     info.horizontal_filter = h_filter;
2294     info.vertical_filter = v_filter;
2295 }
2296 
2297 static uint stbir__calculate_memory(stbir__info *info)
2298 {
2299     int pixel_margin = stbir__get_filter_pixel_margin(info.horizontal_filter, info.horizontal_scale);
2300     int filter_height = stbir__get_filter_pixel_width(info.vertical_filter, info.vertical_scale);
2301 
2302     info.horizontal_num_contributors = stbir__get_contributors(info.horizontal_scale, info.horizontal_filter, info.input_w, info.output_w);
2303     info.vertical_num_contributors   = stbir__get_contributors(info.vertical_scale  , info.vertical_filter  , info.input_h, info.output_h);
2304 
2305     // One extra entry because floating point precision problems sometimes cause an extra to be necessary.
2306     info.ring_buffer_num_entries = filter_height + 1;
2307 
2308     info.horizontal_contributors_size = info.horizontal_num_contributors                  * cast(int)(stbir__contributors.sizeof);
2309     info.horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info)    * cast(int)(float.sizeof);
2310     info.vertical_contributors_size   = info.vertical_num_contributors                    * cast(int)(stbir__contributors.sizeof);
2311     info.vertical_coefficients_size   = stbir__get_total_vertical_coefficients(info)      * cast(int)(float.sizeof);
2312     info.decode_buffer_size           = (info.input_w + pixel_margin * 2) * info.channels * cast(int)(float.sizeof);
2313     info.horizontal_buffer_size       = info.output_w * info.channels                     * cast(int)(float.sizeof);
2314     info.ring_buffer_size             = info.output_w * info.channels                     * info.ring_buffer_num_entries * cast(int)(float.sizeof);
2315     info.encode_buffer_size           = info.output_w * info.channels                     * cast(int)(float.sizeof);
2316 
2317     assert(info.horizontal_filter != 0);
2318     assert(info.horizontal_filter < stbir__filter_info_table.length); // this now happens too late
2319     assert(info.vertical_filter != 0);
2320     assert(info.vertical_filter < stbir__filter_info_table.length); // this now happens too late
2321 
2322     if (stbir__use_height_upsampling(info))
2323         // The horizontal buffer is for when we're downsampling the height and we
2324         // can't output the result of sampling the decode buffer directly into the
2325         // ring buffers.
2326         info.horizontal_buffer_size = 0;
2327     else
2328         // The encode buffer is to retain precision in the height upsampling method
2329         // and isn't used when height downsampling.
2330         info.encode_buffer_size = 0;
2331 
2332     return info.horizontal_contributors_size + info.horizontal_coefficients_size
2333         + info.vertical_contributors_size + info.vertical_coefficients_size
2334         + info.decode_buffer_size + info.horizontal_buffer_size
2335         + info.ring_buffer_size + info.encode_buffer_size;
2336 }
2337 
2338 static int stbir__resize_allocated(stbir__info *info,
2339     const void* input_data, int input_stride_in_bytes,
2340     void* output_data, int output_stride_in_bytes,
2341     int alpha_channel, uint flags, stbir_datatype type,
2342     stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace,
2343     void* tempmem, size_t tempmem_size_in_bytes)
2344 {
2345     size_t memory_required = stbir__calculate_memory(info);
2346 
2347     int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info.channels * info.input_w * stbir__type_size[type];
2348     int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info.channels * info.output_w * stbir__type_size[type];
2349 
2350     assert(info.channels >= 0);
2351     assert(info.channels <= STBIR_MAX_CHANNELS);
2352 
2353     if (info.channels < 0 || info.channels > STBIR_MAX_CHANNELS)
2354         return 0;
2355 
2356     assert(info.horizontal_filter < stbir__filter_info_table.length);
2357     assert(info.vertical_filter < stbir__filter_info_table.length);
2358 
2359     if (info.horizontal_filter >= stbir__filter_info_table.length)
2360         return 0;
2361     if (info.vertical_filter >= stbir__filter_info_table.length)
2362         return 0;
2363 
2364     if (alpha_channel < 0)
2365         flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED;
2366 
2367     if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) {
2368         assert(alpha_channel >= 0 && alpha_channel < info.channels);
2369     }
2370 
2371     if (alpha_channel >= info.channels)
2372         return 0;
2373 
2374     assert(tempmem);
2375 
2376     if (!tempmem)
2377         return 0;
2378 
2379     assert(tempmem_size_in_bytes >= memory_required);
2380 
2381     if (tempmem_size_in_bytes < memory_required)
2382         return 0;
2383 
2384     memset(tempmem, 0, tempmem_size_in_bytes);
2385 
2386     info.input_data = input_data;
2387     info.input_stride_bytes = width_stride_input;
2388 
2389     info.output_data = output_data;
2390     info.output_stride_bytes = width_stride_output;
2391 
2392     info.alpha_channel = alpha_channel;
2393     info.flags = flags;
2394     info.type = type;
2395     info.edge_horizontal = edge_horizontal;
2396     info.edge_vertical = edge_vertical;
2397     info.colorspace = colorspace;
2398 
2399     info.horizontal_coefficient_width   = stbir__get_coefficient_width  (info.horizontal_filter, info.horizontal_scale);
2400     info.vertical_coefficient_width     = stbir__get_coefficient_width  (info.vertical_filter  , info.vertical_scale  );
2401     info.horizontal_filter_pixel_width  = stbir__get_filter_pixel_width (info.horizontal_filter, info.horizontal_scale);
2402     info.vertical_filter_pixel_width    = stbir__get_filter_pixel_width (info.vertical_filter  , info.vertical_scale  );
2403     info.horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info.horizontal_filter, info.horizontal_scale);
2404     info.vertical_filter_pixel_margin   = stbir__get_filter_pixel_margin(info.vertical_filter  , info.vertical_scale  );
2405 
2406     info.ring_buffer_length_bytes = info.output_w * info.channels * cast(int)(float.sizeof);
2407     info.decode_buffer_pixels = info.input_w + info.horizontal_filter_pixel_margin * 2;
2408 
2409     static newtype* STBIR__NEXT_MEMPTR(newtype)(void* current, size_t current_size)
2410     {
2411         return cast(newtype*)( (cast(ubyte*)current) + current_size );
2412     }
2413 
2414     info.horizontal_contributors = cast(stbir__contributors *) tempmem;
2415     info.horizontal_coefficients = STBIR__NEXT_MEMPTR!float              (info.horizontal_contributors, info.horizontal_contributors_size);
2416     info.vertical_contributors   = STBIR__NEXT_MEMPTR!stbir__contributors(info.horizontal_coefficients, info.horizontal_coefficients_size);
2417     info.vertical_coefficients   = STBIR__NEXT_MEMPTR!float              (info.vertical_contributors,   info.vertical_contributors_size);
2418     info.decode_buffer           = STBIR__NEXT_MEMPTR!float              (info.vertical_coefficients,   info.vertical_coefficients_size);
2419 
2420     if (stbir__use_height_upsampling(info))
2421     {
2422         info.horizontal_buffer   = null;
2423         info.ring_buffer         = STBIR__NEXT_MEMPTR!float              (info.decode_buffer,           info.decode_buffer_size);
2424         info.encode_buffer       = STBIR__NEXT_MEMPTR!float              (info.ring_buffer,             info.ring_buffer_size);
2425 
2426         assert(cast(size_t)STBIR__NEXT_MEMPTR!ubyte(info.encode_buffer, info.encode_buffer_size) == cast(size_t)tempmem + tempmem_size_in_bytes);
2427     }
2428     else
2429     {
2430         info.horizontal_buffer   = STBIR__NEXT_MEMPTR!float              (info.decode_buffer,           info.decode_buffer_size);
2431         info.ring_buffer         = STBIR__NEXT_MEMPTR!float              (info.horizontal_buffer,       info.horizontal_buffer_size);
2432         info.encode_buffer = null;
2433 
2434         assert(cast(size_t)STBIR__NEXT_MEMPTR!ubyte(info.ring_buffer, info.ring_buffer_size) == cast(size_t)tempmem + tempmem_size_in_bytes);
2435     }
2436 
2437     // This signals that the ring buffer is empty
2438     info.ring_buffer_begin_index = -1;
2439 
2440     stbir__calculate_filters(info.horizontal_contributors, info.horizontal_coefficients, info.horizontal_filter, info.horizontal_scale, info.horizontal_shift, info.input_w, info.output_w);
2441     stbir__calculate_filters(info.vertical_contributors, info.vertical_coefficients, info.vertical_filter, info.vertical_scale, info.vertical_shift, info.input_h, info.output_h);
2442 
2443     if (stbir__use_height_upsampling(info))
2444         stbir__buffer_loop_upsample(info);
2445     else
2446         stbir__buffer_loop_downsample(info);
2447 
2448     return 1;
2449 }
2450 
2451 
2452 static int stbir__resize_arbitrary(
2453     void *alloc_context,
2454     const void* input_data, int input_w, int input_h, int input_stride_in_bytes,
2455     void* output_data, int output_w, int output_h, int output_stride_in_bytes,
2456     float s0, float t0, float s1, float t1, float *transform,
2457     int channels, int alpha_channel, uint flags, stbir_datatype type,
2458     stbir_filter h_filter, stbir_filter v_filter,
2459     stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace)
2460 {
2461     stbir__info info;
2462     int result;
2463     size_t memory_required;
2464     void* extra_memory;
2465 
2466     stbir__setup(&info, input_w, input_h, output_w, output_h, channels);
2467     stbir__calculate_transform(&info, s0,t0,s1,t1,transform);
2468     stbir__choose_filter(&info, h_filter, v_filter);
2469     memory_required = stbir__calculate_memory(&info);
2470     extra_memory = STBIR_MALLOC(memory_required, alloc_context);
2471 
2472     if (!extra_memory)
2473         return 0;
2474 
2475     result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes,
2476                                             output_data, output_stride_in_bytes,
2477                                             alpha_channel, flags, type,
2478                                             edge_horizontal, edge_vertical,
2479                                             colorspace, extra_memory, memory_required);
2480 
2481     STBIR_FREE(extra_memory, alloc_context);
2482 
2483     return result;
2484 }
2485 
2486 
2487 
2488 int stbir_resize_uint8_srgb_edgemode(const(ubyte)*input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2489                                                     ubyte*output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2490                                               int num_channels, int alpha_channel, int flags,
2491                                               stbir_edge edge_wrap_mode)
2492 {
2493     return stbir__resize_arbitrary(null, input_pixels, input_w, input_h, input_stride_in_bytes,
2494         output_pixels, output_w, output_h, output_stride_in_bytes,
2495         0,0,1,1,null,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
2496         edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB);
2497 }
2498 
2499 int stbir_resize_uint8_generic( const(ubyte)*input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2500                                                ubyte*output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2501                                          int num_channels, int alpha_channel, int flags,
2502                                          stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
2503                                          void *alloc_context)
2504 {
2505     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2506         output_pixels, output_w, output_h, output_stride_in_bytes,
2507         0,0,1,1,null,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter,
2508         edge_wrap_mode, edge_wrap_mode, space);
2509 }
2510 
2511 int stbir_resize_uint16_generic(const ushort *input_pixels  , int input_w , int input_h , int input_stride_in_bytes,
2512                                                ushort *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
2513                                          int num_channels, int alpha_channel, int flags,
2514                                          stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
2515                                          void *alloc_context)
2516 {
2517     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2518         output_pixels, output_w, output_h, output_stride_in_bytes,
2519         0,0,1,1,null,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter,
2520         edge_wrap_mode, edge_wrap_mode, space);
2521 }
2522 
2523 
2524 int stbir_resize(         const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2525                                          void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2526                                    stbir_datatype datatype,
2527                                    int num_channels, int alpha_channel, int flags,
2528                                    stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
2529                                    stbir_filter filter_horizontal,  stbir_filter filter_vertical,
2530                                    stbir_colorspace space, void *alloc_context)
2531 {
2532     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2533         output_pixels, output_w, output_h, output_stride_in_bytes,
2534         0,0,1,1,null,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2535         edge_mode_horizontal, edge_mode_vertical, space);
2536 }
2537 
2538 
2539 int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2540                                          void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2541                                    stbir_datatype datatype,
2542                                    int num_channels, int alpha_channel, int flags,
2543                                    stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
2544                                    stbir_filter filter_horizontal,  stbir_filter filter_vertical,
2545                                    stbir_colorspace space, void *alloc_context,
2546                                    float x_scale, float y_scale,
2547                                    float x_offset, float y_offset)
2548 {
2549     float[4] transform;
2550     transform[0] = x_scale;
2551     transform[1] = y_scale;
2552     transform[2] = x_offset;
2553     transform[3] = y_offset;
2554     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2555         output_pixels, output_w, output_h, output_stride_in_bytes,
2556         0,0,1,1,transform.ptr,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2557         edge_mode_horizontal, edge_mode_vertical, space);
2558 }
2559 
2560 int stbir_resize_region(  const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
2561                                          void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
2562                                    stbir_datatype datatype,
2563                                    int num_channels, int alpha_channel, int flags,
2564                                    stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
2565                                    stbir_filter filter_horizontal,  stbir_filter filter_vertical,
2566                                    stbir_colorspace space, void *alloc_context,
2567                                    float s0, float t0, float s1, float t1)
2568 {
2569     return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
2570         output_pixels, output_w, output_h, output_stride_in_bytes,
2571         s0,t0,s1,t1,null,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
2572         edge_mode_horizontal, edge_mode_vertical, space);
2573 }
2574 
2575 /*
2576 ------------------------------------------------------------------------------
2577 This software is available under 2 licenses -- choose whichever you prefer.
2578 ------------------------------------------------------------------------------
2579 ALTERNATIVE A - MIT License
2580 Copyright (c) 2017 Sean Barrett
2581 Permission is hereby granted, free of charge, to any person obtaining a copy of
2582 this software and associated documentation files (the "Software"), to deal in
2583 the Software without restriction, including without limitation the rights to
2584 use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
2585 of the Software, and to permit persons to whom the Software is furnished to do
2586 so, subject to the following conditions:
2587 The above copyright notice and this permission notice shall be included in all
2588 copies or substantial portions of the Software.
2589 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2590 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2591 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2592 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
2593 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
2594 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
2595 SOFTWARE.
2596 ------------------------------------------------------------------------------
2597 ALTERNATIVE B - Public Domain (www.unlicense.org)
2598 This is free and unencumbered software released into the public domain.
2599 Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
2600 software, either in source code form or as a compiled binary, for any purpose,
2601 commercial or non-commercial, and by any means.
2602 In jurisdictions that recognize copyright laws, the author or authors of this
2603 software dedicate any and all copyright interest in the software to the public
2604 domain. We make this dedication for the benefit of the public at large and to
2605 the detriment of our heirs and successors. We intend this dedication to be an
2606 overt act of relinquishment in perpetuity of all present and future rights to
2607 this software under copyright law.
2608 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
2609 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
2610 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
2611 AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
2612 ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
2613 WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
2614 ------------------------------------------------------------------------------
2615 */