sites

public wiki contents of suckless.org
git clone git://git.suckless.org/sites
Log | Files | Refs

dwm-winicon-6.2-v1.1.diff (127991B)


      1 diff --git a/config.def.h b/config.def.h
      2 index 1c0b587..5385e27 100644
      3 --- a/config.def.h
      4 +++ b/config.def.h
      5 @@ -5,6 +5,8 @@ static const unsigned int borderpx  = 1;        /* border pixel of windows */
      6  static const unsigned int snap      = 32;       /* snap pixel */
      7  static const int showbar            = 1;        /* 0 means no bar */
      8  static const int topbar             = 1;        /* 0 means bottom bar */
      9 +#define ICONSIZE 20   /* icon size */
     10 +#define ICONSPACING 5 /* space between icon and title */
     11  static const char *fonts[]          = { "monospace:size=10" };
     12  static const char dmenufont[]       = "monospace:size=10";
     13  static const char col_gray1[]       = "#222222";
     14 diff --git a/config.mk b/config.mk
     15 index 6d36cb7..39edf93 100644
     16 --- a/config.mk
     17 +++ b/config.mk
     18 @@ -22,7 +22,7 @@ FREETYPEINC = /usr/include/freetype2
     19  
     20  # includes and libs
     21  INCS = -I${X11INC} -I${FREETYPEINC}
     22 -LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS}
     23 +LIBS = -L${X11LIB} -lX11 ${XINERAMALIBS} ${FREETYPELIBS} -lm
     24  
     25  # flags
     26  CPPFLAGS = -D_DEFAULT_SOURCE -D_BSD_SOURCE -D_POSIX_C_SOURCE=2 -DVERSION=\"${VERSION}\" ${XINERAMAFLAGS}
     27 diff --git a/drw.c b/drw.c
     28 index 8fd1ca4..91454e1 100644
     29 --- a/drw.c
     30 +++ b/drw.c
     31 @@ -2,6 +2,7 @@
     32  #include <stdio.h>
     33  #include <stdlib.h>
     34  #include <string.h>
     35 +#include <stdint.h>
     36  #include <X11/Xlib.h>
     37  #include <X11/Xft/Xft.h>
     38  
     39 @@ -378,6 +379,27 @@ drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lp
     40  	return x + (render ? w : 0);
     41  }
     42  
     43 +static uint32_t blend32(uint32_t p1, uint32_t p2) {
     44 +    uint32_t a = p2 >> 24;
     45 +    uint32_t na = 255 - a;
     46 +    uint32_t rb = ((na * (p1 & 0x00ff00ffu)) + (a * (p2 & 0x00ff00ffu))) >> 8;
     47 +    uint32_t ag = (na * ((p1 & 0xff00ff00u) >> 8)) + (a * (0x01000000u | ((p2 & 0x0000ff00u) >> 8)));
     48 +    return ((rb & 0x00ff00ffu) | (ag & 0xff00ff00u));
     49 +}
     50 +
     51 +void
     52 +drw_img(Drw *drw, int x, int y, XImage *img, uint32_t *tmp) 
     53 +{
     54 +	if (!drw || !drw->scheme)
     55 +		return;
     56 +	uint32_t *data = (uint32_t *)img->data, bt = drw->scheme[ColBg].pixel;
     57 +	int icsz = img->width * img->height, i;
     58 +	for (i = 0; i < icsz; ++i) tmp[i] = blend32(bt, data[i]);
     59 +	img->data = (char *)tmp;
     60 +	XPutImage(drw->dpy, drw->drawable, drw->gc, img, 0, 0, x, y, img->width, img->height);
     61 +	img->data = (char *)data;
     62 +}
     63 +
     64  void
     65  drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h)
     66  {
     67 diff --git a/drw.h b/drw.h
     68 index 4bcd5ad..07b6433 100644
     69 --- a/drw.h
     70 +++ b/drw.h
     71 @@ -52,6 +52,7 @@ void drw_setscheme(Drw *drw, Clr *scm);
     72  /* Drawing functions */
     73  void drw_rect(Drw *drw, int x, int y, unsigned int w, unsigned int h, int filled, int invert);
     74  int drw_text(Drw *drw, int x, int y, unsigned int w, unsigned int h, unsigned int lpad, const char *text, int invert);
     75 +void drw_img(Drw *drw, int x, int y, XImage *img, uint32_t *tmp);
     76  
     77  /* Map functions */
     78  void drw_map(Drw *drw, Window win, int x, int y, unsigned int w, unsigned int h);
     79 diff --git a/dwm.c b/dwm.c
     80 index 4465af1..a1c879e 100644
     81 --- a/dwm.c
     82 +++ b/dwm.c
     83 @@ -28,6 +28,8 @@
     84  #include <stdlib.h>
     85  #include <string.h>
     86  #include <unistd.h>
     87 +#include <limits.h>
     88 +#include <stdint.h>
     89  #include <sys/types.h>
     90  #include <sys/wait.h>
     91  #include <X11/cursorfont.h>
     92 @@ -60,7 +62,7 @@
     93  /* enums */
     94  enum { CurNormal, CurResize, CurMove, CurLast }; /* cursor */
     95  enum { SchemeNorm, SchemeSel }; /* color schemes */
     96 -enum { NetSupported, NetWMName, NetWMState, NetWMCheck,
     97 +enum { NetSupported, NetWMName, NetWMIcon, NetWMState, NetWMCheck,
     98         NetWMFullscreen, NetActiveWindow, NetWMWindowType,
     99         NetWMWindowTypeDialog, NetClientList, NetLast }; /* EWMH atoms */
    100  enum { WMProtocols, WMDelete, WMState, WMTakeFocus, WMLast }; /* default atoms */
    101 @@ -93,6 +95,7 @@ struct Client {
    102  	int bw, oldbw;
    103  	unsigned int tags;
    104  	int isfixed, isfloating, isurgent, neverfocus, oldstate, isfullscreen;
    105 +	XImage *icon;
    106  	Client *next;
    107  	Client *snext;
    108  	Monitor *mon;
    109 @@ -171,6 +174,7 @@ static void focusmon(const Arg *arg);
    110  static void focusstack(const Arg *arg);
    111  static int getrootptr(int *x, int *y);
    112  static long getstate(Window w);
    113 +static XImage *geticonprop(Window win);
    114  static int gettextprop(Window w, Atom atom, char *text, unsigned int size);
    115  static void grabbuttons(Client *c, int focused);
    116  static void grabkeys(void);
    117 @@ -213,6 +217,7 @@ static void togglebar(const Arg *arg);
    118  static void togglefloating(const Arg *arg);
    119  static void toggletag(const Arg *arg);
    120  static void toggleview(const Arg *arg);
    121 +static void freeicon(Client *c);
    122  static void unfocus(Client *c, int setfocus);
    123  static void unmanage(Client *c, int destroyed);
    124  static void unmapnotify(XEvent *e);
    125 @@ -224,6 +229,7 @@ static void updatenumlockmask(void);
    126  static void updatesizehints(Client *c);
    127  static void updatestatus(void);
    128  static void updatetitle(Client *c);
    129 +static void updateicon(Client *c);
    130  static void updatewindowtype(Client *c);
    131  static void updatewmhints(Client *c);
    132  static void view(const Arg *arg);
    133 @@ -731,7 +737,9 @@ drawbar(Monitor *m)
    134  	if ((w = m->ww - sw - x) > bh) {
    135  		if (m->sel) {
    136  			drw_setscheme(drw, scheme[m == selmon ? SchemeSel : SchemeNorm]);
    137 -			drw_text(drw, x, 0, w, bh, lrpad / 2, m->sel->name, 0);
    138 +			drw_text(drw, x, 0, w, bh, lrpad / 2 + (m->sel->icon ? m->sel->icon->width + ICONSPACING : 0), m->sel->name, 0);
    139 +			static uint32_t tmp[ICONSIZE * ICONSIZE];
    140 +			if (m->sel->icon) drw_img(drw, x + lrpad / 2, (bh - m->sel->icon->height) / 2, m->sel->icon, tmp);
    141  			if (m->sel->isfloating)
    142  				drw_rect(drw, x + boxs, boxs, boxw, boxw, m->sel->isfixed, 0);
    143  		} else {
    144 @@ -899,6 +907,70 @@ getstate(Window w)
    145  	return result;
    146  }
    147  
    148 +#define STB_IMAGE_RESIZE_IMPLEMENTATION
    149 +#define STBIR_DEFAULT_FILTER_DOWNSAMPLE STBIR_FILTER_BOX
    150 +#include "stb_image_resize.h"
    151 +
    152 +XImage *
    153 +geticonprop(Window win)
    154 +{
    155 +	int format;
    156 +	unsigned long n, extra, *p = NULL;
    157 +	Atom real;
    158 +
    159 +	if (XGetWindowProperty(dpy, win, netatom[NetWMIcon], 0L, LONG_MAX, False, AnyPropertyType, 
    160 +						   &real, &format, &n, &extra, (unsigned char **)&p) != Success)
    161 +		return NULL; 
    162 +	if (n == 0) { XFree(p); return NULL; }
    163 +
    164 +	unsigned long *bstp = NULL, w, h;
    165 +
    166 +	{
    167 +		const unsigned long *end = p + n;
    168 +		unsigned long *i;
    169 +		int bstd = INT_MAX, d, m;
    170 +		for (i = p; i < end; ) {
    171 +			w = *i++; h = *i++;
    172 +			m = w > h ? w : h;
    173 +			if (m >= ICONSIZE && (d = m - ICONSIZE) < bstd) { bstd = d; bstp = i; }
    174 +			i += (w * h);
    175 +		}
    176 +		if (!bstp) {
    177 +			for (i = p; i < end; ) {
    178 +				w = *i++; h = *i++;
    179 +				m = w > h ? w : h;
    180 +				if ((d = ICONSIZE - m) < bstd) { bstd = d; bstp = i; }
    181 +				i += (w * h);
    182 +			}
    183 +		}
    184 +		if (!bstp) { XFree(p); return NULL; }
    185 +	}
    186 +
    187 +	w = *(bstp - 2); h = *(bstp - 1);
    188 +
    189 +	int icw, ich;
    190 +	if (w <= h) {
    191 +		ich = ICONSIZE; icw = w * ICONSIZE / h;
    192 +		if (icw < 1) icw = 1;
    193 +	}
    194 +	else {
    195 +		icw = ICONSIZE; ich = h * ICONSIZE / w;
    196 +		if (ich < 1) ich = 1;
    197 +	}
    198 +
    199 +	unsigned char *icbuf = malloc(icw * ich << 2); if(!icbuf) { XFree(p); return NULL; }
    200 +#if ULONG_MAX > UINT32_MAX
    201 +	int i, sz = w * h;
    202 +	uint32_t *bstp32 = (uint32_t *)bstp;
    203 +	for (i = 0; i < sz; ++i) bstp32[i] = bstp[i];
    204 +#endif
    205 +	if (w == icw && h == ich) memcpy(icbuf, bstp, icw * ich << 2);
    206 +	else stbir_resize_uint8((unsigned char *)bstp, w, h, 0, icbuf, icw, ich, 0, 4);
    207 +	XFree(p);
    208 +
    209 +	return XCreateImage(dpy, DefaultVisual(dpy, screen), DefaultDepth(dpy, screen), ZPixmap, 0, (char *)icbuf, icw, ich, 32, 0);
    210 +}
    211 +
    212  int
    213  gettextprop(Window w, Atom atom, char *text, unsigned int size)
    214  {
    215 @@ -1030,6 +1102,8 @@ manage(Window w, XWindowAttributes *wa)
    216  	c->h = c->oldh = wa->height;
    217  	c->oldbw = wa->border_width;
    218  
    219 +	c->icon = NULL;
    220 +	updateicon(c);
    221  	updatetitle(c);
    222  	if (XGetTransientForHint(dpy, w, &trans) && (t = wintoclient(trans))) {
    223  		c->mon = t->mon;
    224 @@ -1240,6 +1314,11 @@ propertynotify(XEvent *e)
    225  			if (c == c->mon->sel)
    226  				drawbar(c->mon);
    227  		}
    228 +		else if (ev->atom == netatom[NetWMIcon]) {
    229 +			updateicon(c);
    230 +			if (c == c->mon->sel)
    231 +				drawbar(c->mon);
    232 +		}
    233  		if (ev->atom == netatom[NetWMWindowType])
    234  			updatewindowtype(c);
    235  	}
    236 @@ -1556,6 +1635,7 @@ setup(void)
    237  	netatom[NetActiveWindow] = XInternAtom(dpy, "_NET_ACTIVE_WINDOW", False);
    238  	netatom[NetSupported] = XInternAtom(dpy, "_NET_SUPPORTED", False);
    239  	netatom[NetWMName] = XInternAtom(dpy, "_NET_WM_NAME", False);
    240 +	netatom[NetWMIcon] = XInternAtom(dpy, "_NET_WM_ICON", False);
    241  	netatom[NetWMState] = XInternAtom(dpy, "_NET_WM_STATE", False);
    242  	netatom[NetWMCheck] = XInternAtom(dpy, "_NET_SUPPORTING_WM_CHECK", False);
    243  	netatom[NetWMFullscreen] = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
    244 @@ -1746,6 +1826,15 @@ toggleview(const Arg *arg)
    245  	}
    246  }
    247  
    248 +void
    249 +freeicon(Client *c)
    250 +{
    251 +	if (c->icon) {
    252 +		XDestroyImage(c->icon);
    253 +		c->icon = NULL;
    254 +	}
    255 +}
    256 +
    257  void
    258  unfocus(Client *c, int setfocus)
    259  {
    260 @@ -1767,6 +1856,7 @@ unmanage(Client *c, int destroyed)
    261  
    262  	detach(c);
    263  	detachstack(c);
    264 +	freeicon(c);
    265  	if (!destroyed) {
    266  		wc.border_width = c->oldbw;
    267  		XGrabServer(dpy); /* avoid race conditions */
    268 @@ -2001,6 +2091,13 @@ updatetitle(Client *c)
    269  		strcpy(c->name, broken);
    270  }
    271  
    272 +void
    273 +updateicon(Client *c)
    274 +{
    275 +	freeicon(c);
    276 +	c->icon = geticonprop(c->win);
    277 +}
    278 +
    279  void
    280  updatewindowtype(Client *c)
    281  {
    282 diff --git a/stb_image_resize.h b/stb_image_resize.h
    283 new file mode 100644
    284 index 0000000..42a8efb
    285 --- /dev/null
    286 +++ b/stb_image_resize.h
    287 @@ -0,0 +1,2631 @@
    288 +/* stb_image_resize - v0.96 - public domain image resizing
    289 +   by Jorge L Rodriguez (@VinoBS) - 2014
    290 +   http://github.com/nothings/stb
    291 +
    292 +   Written with emphasis on usability, portability, and efficiency. (No
    293 +   SIMD or threads, so it be easily outperformed by libs that use those.)
    294 +   Only scaling and translation is supported, no rotations or shears.
    295 +   Easy API downsamples w/Mitchell filter, upsamples w/cubic interpolation.
    296 +
    297 +   COMPILING & LINKING
    298 +      In one C/C++ file that #includes this file, do this:
    299 +         #define STB_IMAGE_RESIZE_IMPLEMENTATION
    300 +      before the #include. That will create the implementation in that file.
    301 +
    302 +   QUICKSTART
    303 +      stbir_resize_uint8(      input_pixels , in_w , in_h , 0,
    304 +                               output_pixels, out_w, out_h, 0, num_channels)
    305 +      stbir_resize_float(...)
    306 +      stbir_resize_uint8_srgb( input_pixels , in_w , in_h , 0,
    307 +                               output_pixels, out_w, out_h, 0,
    308 +                               num_channels , alpha_chan  , 0)
    309 +      stbir_resize_uint8_srgb_edgemode(
    310 +                               input_pixels , in_w , in_h , 0,
    311 +                               output_pixels, out_w, out_h, 0,
    312 +                               num_channels , alpha_chan  , 0, STBIR_EDGE_CLAMP)
    313 +                                                            // WRAP/REFLECT/ZERO
    314 +
    315 +   FULL API
    316 +      See the "header file" section of the source for API documentation.
    317 +
    318 +   ADDITIONAL DOCUMENTATION
    319 +
    320 +      SRGB & FLOATING POINT REPRESENTATION
    321 +         The sRGB functions presume IEEE floating point. If you do not have
    322 +         IEEE floating point, define STBIR_NON_IEEE_FLOAT. This will use
    323 +         a slower implementation.
    324 +
    325 +      MEMORY ALLOCATION
    326 +         The resize functions here perform a single memory allocation using
    327 +         malloc. To control the memory allocation, before the #include that
    328 +         triggers the implementation, do:
    329 +
    330 +            #define STBIR_MALLOC(size,context) ...
    331 +            #define STBIR_FREE(ptr,context)   ...
    332 +
    333 +         Each resize function makes exactly one call to malloc/free, so to use
    334 +         temp memory, store the temp memory in the context and return that.
    335 +
    336 +      ASSERT
    337 +         Define STBIR_ASSERT(boolval) to override assert() and not use assert.h
    338 +
    339 +      OPTIMIZATION
    340 +         Define STBIR_SATURATE_INT to compute clamp values in-range using
    341 +         integer operations instead of float operations. This may be faster
    342 +         on some platforms.
    343 +
    344 +      DEFAULT FILTERS
    345 +         For functions which don't provide explicit control over what filters
    346 +         to use, you can change the compile-time defaults with
    347 +
    348 +            #define STBIR_DEFAULT_FILTER_UPSAMPLE     STBIR_FILTER_something
    349 +            #define STBIR_DEFAULT_FILTER_DOWNSAMPLE   STBIR_FILTER_something
    350 +
    351 +         See stbir_filter in the header-file section for the list of filters.
    352 +
    353 +      NEW FILTERS
    354 +         A number of 1D filter kernels are used. For a list of
    355 +         supported filters see the stbir_filter enum. To add a new filter,
    356 +         write a filter function and add it to stbir__filter_info_table.
    357 +
    358 +      PROGRESS
    359 +         For interactive use with slow resize operations, you can install
    360 +         a progress-report callback:
    361 +
    362 +            #define STBIR_PROGRESS_REPORT(val)   some_func(val)
    363 +
    364 +         The parameter val is a float which goes from 0 to 1 as progress is made.
    365 +
    366 +         For example:
    367 +
    368 +            static void my_progress_report(float progress);
    369 +            #define STBIR_PROGRESS_REPORT(val) my_progress_report(val)
    370 +
    371 +            #define STB_IMAGE_RESIZE_IMPLEMENTATION
    372 +            #include "stb_image_resize.h"
    373 +
    374 +            static void my_progress_report(float progress)
    375 +            {
    376 +               printf("Progress: %f%%\n", progress*100);
    377 +            }
    378 +
    379 +      MAX CHANNELS
    380 +         If your image has more than 64 channels, define STBIR_MAX_CHANNELS
    381 +         to the max you'll have.
    382 +
    383 +      ALPHA CHANNEL
    384 +         Most of the resizing functions provide the ability to control how
    385 +         the alpha channel of an image is processed. The important things
    386 +         to know about this:
    387 +
    388 +         1. The best mathematically-behaved version of alpha to use is
    389 +         called "premultiplied alpha", in which the other color channels
    390 +         have had the alpha value multiplied in. If you use premultiplied
    391 +         alpha, linear filtering (such as image resampling done by this
    392 +         library, or performed in texture units on GPUs) does the "right
    393 +         thing". While premultiplied alpha is standard in the movie CGI
    394 +         industry, it is still uncommon in the videogame/real-time world.
    395 +
    396 +         If you linearly filter non-premultiplied alpha, strange effects
    397 +         occur. (For example, the 50/50 average of 99% transparent bright green
    398 +         and 1% transparent black produces 50% transparent dark green when
    399 +         non-premultiplied, whereas premultiplied it produces 50%
    400 +         transparent near-black. The former introduces green energy
    401 +         that doesn't exist in the source image.)
    402 +
    403 +         2. Artists should not edit premultiplied-alpha images; artists
    404 +         want non-premultiplied alpha images. Thus, art tools generally output
    405 +         non-premultiplied alpha images.
    406 +
    407 +         3. You will get best results in most cases by converting images
    408 +         to premultiplied alpha before processing them mathematically.
    409 +
    410 +         4. If you pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED, the
    411 +         resizer does not do anything special for the alpha channel;
    412 +         it is resampled identically to other channels. This produces
    413 +         the correct results for premultiplied-alpha images, but produces
    414 +         less-than-ideal results for non-premultiplied-alpha images.
    415 +
    416 +         5. If you do not pass the flag STBIR_FLAG_ALPHA_PREMULTIPLIED,
    417 +         then the resizer weights the contribution of input pixels
    418 +         based on their alpha values, or, equivalently, it multiplies
    419 +         the alpha value into the color channels, resamples, then divides
    420 +         by the resultant alpha value. Input pixels which have alpha=0 do
    421 +         not contribute at all to output pixels unless _all_ of the input
    422 +         pixels affecting that output pixel have alpha=0, in which case
    423 +         the result for that pixel is the same as it would be without
    424 +         STBIR_FLAG_ALPHA_PREMULTIPLIED. However, this is only true for
    425 +         input images in integer formats. For input images in float format,
    426 +         input pixels with alpha=0 have no effect, and output pixels
    427 +         which have alpha=0 will be 0 in all channels. (For float images,
    428 +         you can manually achieve the same result by adding a tiny epsilon
    429 +         value to the alpha channel of every image, and then subtracting
    430 +         or clamping it at the end.)
    431 +
    432 +         6. You can suppress the behavior described in #5 and make
    433 +         all-0-alpha pixels have 0 in all channels by #defining
    434 +         STBIR_NO_ALPHA_EPSILON.
    435 +
    436 +         7. You can separately control whether the alpha channel is
    437 +         interpreted as linear or affected by the colorspace. By default
    438 +         it is linear; you almost never want to apply the colorspace.
    439 +         (For example, graphics hardware does not apply sRGB conversion
    440 +         to the alpha channel.)
    441 +
    442 +   CONTRIBUTORS
    443 +      Jorge L Rodriguez: Implementation
    444 +      Sean Barrett: API design, optimizations
    445 +      Aras Pranckevicius: bugfix
    446 +      Nathan Reed: warning fixes
    447 +
    448 +   REVISIONS
    449 +      0.97 (2020-02-02) fixed warning
    450 +      0.96 (2019-03-04) fixed warnings
    451 +      0.95 (2017-07-23) fixed warnings
    452 +      0.94 (2017-03-18) fixed warnings
    453 +      0.93 (2017-03-03) fixed bug with certain combinations of heights
    454 +      0.92 (2017-01-02) fix integer overflow on large (>2GB) images
    455 +      0.91 (2016-04-02) fix warnings; fix handling of subpixel regions
    456 +      0.90 (2014-09-17) first released version
    457 +
    458 +   LICENSE
    459 +     See end of file for license information.
    460 +
    461 +   TODO
    462 +      Don't decode all of the image data when only processing a partial tile
    463 +      Don't use full-width decode buffers when only processing a partial tile
    464 +      When processing wide images, break processing into tiles so data fits in L1 cache
    465 +      Installable filters?
    466 +      Resize that respects alpha test coverage
    467 +         (Reference code: FloatImage::alphaTestCoverage and FloatImage::scaleAlphaToCoverage:
    468 +         https://code.google.com/p/nvidia-texture-tools/source/browse/trunk/src/nvimage/FloatImage.cpp )
    469 +*/
    470 +
    471 +#ifndef STBIR_INCLUDE_STB_IMAGE_RESIZE_H
    472 +#define STBIR_INCLUDE_STB_IMAGE_RESIZE_H
    473 +
    474 +#ifdef _MSC_VER
    475 +typedef unsigned char  stbir_uint8;
    476 +typedef unsigned short stbir_uint16;
    477 +typedef unsigned int   stbir_uint32;
    478 +#else
    479 +#include <stdint.h>
    480 +typedef uint8_t  stbir_uint8;
    481 +typedef uint16_t stbir_uint16;
    482 +typedef uint32_t stbir_uint32;
    483 +#endif
    484 +
    485 +#ifndef STBIRDEF
    486 +#ifdef STB_IMAGE_RESIZE_STATIC
    487 +#define STBIRDEF static
    488 +#else
    489 +#ifdef __cplusplus
    490 +#define STBIRDEF extern "C"
    491 +#else
    492 +#define STBIRDEF extern
    493 +#endif
    494 +#endif
    495 +#endif
    496 +
    497 +//////////////////////////////////////////////////////////////////////////////
    498 +//
    499 +// Easy-to-use API:
    500 +//
    501 +//     * "input pixels" points to an array of image data with 'num_channels' channels (e.g. RGB=3, RGBA=4)
    502 +//     * input_w is input image width (x-axis), input_h is input image height (y-axis)
    503 +//     * stride is the offset between successive rows of image data in memory, in bytes. you can
    504 +//       specify 0 to mean packed continuously in memory
    505 +//     * alpha channel is treated identically to other channels.
    506 +//     * colorspace is linear or sRGB as specified by function name
    507 +//     * returned result is 1 for success or 0 in case of an error.
    508 +//       #define STBIR_ASSERT() to trigger an assert on parameter validation errors.
    509 +//     * Memory required grows approximately linearly with input and output size, but with
    510 +//       discontinuities at input_w == output_w and input_h == output_h.
    511 +//     * These functions use a "default" resampling filter defined at compile time. To change the filter,
    512 +//       you can change the compile-time defaults by #defining STBIR_DEFAULT_FILTER_UPSAMPLE
    513 +//       and STBIR_DEFAULT_FILTER_DOWNSAMPLE, or you can use the medium-complexity API.
    514 +
    515 +STBIRDEF int stbir_resize_uint8(     const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    516 +                                           unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    517 +                                     int num_channels);
    518 +
    519 +STBIRDEF int stbir_resize_float(     const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    520 +                                           float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    521 +                                     int num_channels);
    522 +
    523 +
    524 +// The following functions interpret image data as gamma-corrected sRGB.
    525 +// Specify STBIR_ALPHA_CHANNEL_NONE if you have no alpha channel,
    526 +// or otherwise provide the index of the alpha channel. Flags value
    527 +// of 0 will probably do the right thing if you're not sure what
    528 +// the flags mean.
    529 +
    530 +#define STBIR_ALPHA_CHANNEL_NONE       -1
    531 +
    532 +// Set this flag if your texture has premultiplied alpha. Otherwise, stbir will
    533 +// use alpha-weighted resampling (effectively premultiplying, resampling,
    534 +// then unpremultiplying).
    535 +#define STBIR_FLAG_ALPHA_PREMULTIPLIED    (1 << 0)
    536 +// The specified alpha channel should be handled as gamma-corrected value even
    537 +// when doing sRGB operations.
    538 +#define STBIR_FLAG_ALPHA_USES_COLORSPACE  (1 << 1)
    539 +
    540 +STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    541 +                                           unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    542 +                                     int num_channels, int alpha_channel, int flags);
    543 +
    544 +
    545 +typedef enum
    546 +{
    547 +    STBIR_EDGE_CLAMP   = 1,
    548 +    STBIR_EDGE_REFLECT = 2,
    549 +    STBIR_EDGE_WRAP    = 3,
    550 +    STBIR_EDGE_ZERO    = 4,
    551 +} stbir_edge;
    552 +
    553 +// This function adds the ability to specify how requests to sample off the edge of the image are handled.
    554 +STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    555 +                                                    unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    556 +                                              int num_channels, int alpha_channel, int flags,
    557 +                                              stbir_edge edge_wrap_mode);
    558 +
    559 +//////////////////////////////////////////////////////////////////////////////
    560 +//
    561 +// Medium-complexity API
    562 +//
    563 +// This extends the easy-to-use API as follows:
    564 +//
    565 +//     * Alpha-channel can be processed separately
    566 +//       * If alpha_channel is not STBIR_ALPHA_CHANNEL_NONE
    567 +//         * Alpha channel will not be gamma corrected (unless flags&STBIR_FLAG_GAMMA_CORRECT)
    568 +//         * Filters will be weighted by alpha channel (unless flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)
    569 +//     * Filter can be selected explicitly
    570 +//     * uint16 image type
    571 +//     * sRGB colorspace available for all types
    572 +//     * context parameter for passing to STBIR_MALLOC
    573 +
    574 +typedef enum
    575 +{
    576 +    STBIR_FILTER_DEFAULT      = 0,  // use same filter type that easy-to-use API chooses
    577 +    STBIR_FILTER_BOX          = 1,  // A trapezoid w/1-pixel wide ramps, same result as box for integer scale ratios
    578 +    STBIR_FILTER_TRIANGLE     = 2,  // On upsampling, produces same results as bilinear texture filtering
    579 +    STBIR_FILTER_CUBICBSPLINE = 3,  // The cubic b-spline (aka Mitchell-Netrevalli with B=1,C=0), gaussian-esque
    580 +    STBIR_FILTER_CATMULLROM   = 4,  // An interpolating cubic spline
    581 +    STBIR_FILTER_MITCHELL     = 5,  // Mitchell-Netrevalli filter with B=1/3, C=1/3
    582 +} stbir_filter;
    583 +
    584 +typedef enum
    585 +{
    586 +    STBIR_COLORSPACE_LINEAR,
    587 +    STBIR_COLORSPACE_SRGB,
    588 +
    589 +    STBIR_MAX_COLORSPACES,
    590 +} stbir_colorspace;
    591 +
    592 +// The following functions are all identical except for the type of the image data
    593 +
    594 +STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    595 +                                               unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    596 +                                         int num_channels, int alpha_channel, int flags,
    597 +                                         stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
    598 +                                         void *alloc_context);
    599 +
    600 +STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels  , int input_w , int input_h , int input_stride_in_bytes,
    601 +                                               stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
    602 +                                         int num_channels, int alpha_channel, int flags,
    603 +                                         stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
    604 +                                         void *alloc_context);
    605 +
    606 +STBIRDEF int stbir_resize_float_generic( const float *input_pixels         , int input_w , int input_h , int input_stride_in_bytes,
    607 +                                               float *output_pixels        , int output_w, int output_h, int output_stride_in_bytes,
    608 +                                         int num_channels, int alpha_channel, int flags,
    609 +                                         stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
    610 +                                         void *alloc_context);
    611 +
    612 +
    613 +
    614 +//////////////////////////////////////////////////////////////////////////////
    615 +//
    616 +// Full-complexity API
    617 +//
    618 +// This extends the medium API as follows:
    619 +//
    620 +//       * uint32 image type
    621 +//     * not typesafe
    622 +//     * separate filter types for each axis
    623 +//     * separate edge modes for each axis
    624 +//     * can specify scale explicitly for subpixel correctness
    625 +//     * can specify image source tile using texture coordinates
    626 +
    627 +typedef enum
    628 +{
    629 +    STBIR_TYPE_UINT8 ,
    630 +    STBIR_TYPE_UINT16,
    631 +    STBIR_TYPE_UINT32,
    632 +    STBIR_TYPE_FLOAT ,
    633 +
    634 +    STBIR_MAX_TYPES
    635 +} stbir_datatype;
    636 +
    637 +STBIRDEF int stbir_resize(         const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    638 +                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    639 +                                   stbir_datatype datatype,
    640 +                                   int num_channels, int alpha_channel, int flags,
    641 +                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
    642 +                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
    643 +                                   stbir_colorspace space, void *alloc_context);
    644 +
    645 +STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    646 +                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    647 +                                   stbir_datatype datatype,
    648 +                                   int num_channels, int alpha_channel, int flags,
    649 +                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
    650 +                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
    651 +                                   stbir_colorspace space, void *alloc_context,
    652 +                                   float x_scale, float y_scale,
    653 +                                   float x_offset, float y_offset);
    654 +
    655 +STBIRDEF int stbir_resize_region(  const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
    656 +                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
    657 +                                   stbir_datatype datatype,
    658 +                                   int num_channels, int alpha_channel, int flags,
    659 +                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
    660 +                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
    661 +                                   stbir_colorspace space, void *alloc_context,
    662 +                                   float s0, float t0, float s1, float t1);
    663 +// (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.
    664 +
    665 +//
    666 +//
    667 +////   end header file   /////////////////////////////////////////////////////
    668 +#endif // STBIR_INCLUDE_STB_IMAGE_RESIZE_H
    669 +
    670 +
    671 +
    672 +
    673 +
    674 +#ifdef STB_IMAGE_RESIZE_IMPLEMENTATION
    675 +
    676 +#ifndef STBIR_ASSERT
    677 +#include <assert.h>
    678 +#define STBIR_ASSERT(x) assert(x)
    679 +#endif
    680 +
    681 +// For memset
    682 +#include <string.h>
    683 +
    684 +#include <math.h>
    685 +
    686 +#ifndef STBIR_MALLOC
    687 +#include <stdlib.h>
    688 +// use comma operator to evaluate c, to avoid "unused parameter" warnings
    689 +#define STBIR_MALLOC(size,c) ((void)(c), malloc(size))
    690 +#define STBIR_FREE(ptr,c)    ((void)(c), free(ptr))
    691 +#endif
    692 +
    693 +#ifndef _MSC_VER
    694 +#ifdef __cplusplus
    695 +#define stbir__inline inline
    696 +#else
    697 +#define stbir__inline
    698 +#endif
    699 +#else
    700 +#define stbir__inline __forceinline
    701 +#endif
    702 +
    703 +
    704 +// should produce compiler error if size is wrong
    705 +typedef unsigned char stbir__validate_uint32[sizeof(stbir_uint32) == 4 ? 1 : -1];
    706 +
    707 +#ifdef _MSC_VER
    708 +#define STBIR__NOTUSED(v)  (void)(v)
    709 +#else
    710 +#define STBIR__NOTUSED(v)  (void)sizeof(v)
    711 +#endif
    712 +
    713 +#define STBIR__ARRAY_SIZE(a) (sizeof((a))/sizeof((a)[0]))
    714 +
    715 +#ifndef STBIR_DEFAULT_FILTER_UPSAMPLE
    716 +#define STBIR_DEFAULT_FILTER_UPSAMPLE    STBIR_FILTER_CATMULLROM
    717 +#endif
    718 +
    719 +#ifndef STBIR_DEFAULT_FILTER_DOWNSAMPLE
    720 +#define STBIR_DEFAULT_FILTER_DOWNSAMPLE  STBIR_FILTER_MITCHELL
    721 +#endif
    722 +
    723 +#ifndef STBIR_PROGRESS_REPORT
    724 +#define STBIR_PROGRESS_REPORT(float_0_to_1)
    725 +#endif
    726 +
    727 +#ifndef STBIR_MAX_CHANNELS
    728 +#define STBIR_MAX_CHANNELS 64
    729 +#endif
    730 +
    731 +#if STBIR_MAX_CHANNELS > 65536
    732 +#error "Too many channels; STBIR_MAX_CHANNELS must be no more than 65536."
    733 +// because we store the indices in 16-bit variables
    734 +#endif
    735 +
    736 +// This value is added to alpha just before premultiplication to avoid
    737 +// zeroing out color values. It is equivalent to 2^-80. If you don't want
    738 +// that behavior (it may interfere if you have floating point images with
    739 +// very small alpha values) then you can define STBIR_NO_ALPHA_EPSILON to
    740 +// disable it.
    741 +#ifndef STBIR_ALPHA_EPSILON
    742 +#define STBIR_ALPHA_EPSILON ((float)1 / (1 << 20) / (1 << 20) / (1 << 20) / (1 << 20))
    743 +#endif
    744 +
    745 +
    746 +
    747 +#ifdef _MSC_VER
    748 +#define STBIR__UNUSED_PARAM(v)  (void)(v)
    749 +#else
    750 +#define STBIR__UNUSED_PARAM(v)  (void)sizeof(v)
    751 +#endif
    752 +
    753 +// must match stbir_datatype
    754 +static unsigned char stbir__type_size[] = {
    755 +    1, // STBIR_TYPE_UINT8
    756 +    2, // STBIR_TYPE_UINT16
    757 +    4, // STBIR_TYPE_UINT32
    758 +    4, // STBIR_TYPE_FLOAT
    759 +};
    760 +
    761 +// Kernel function centered at 0
    762 +typedef float (stbir__kernel_fn)(float x, float scale);
    763 +typedef float (stbir__support_fn)(float scale);
    764 +
    765 +typedef struct
    766 +{
    767 +    stbir__kernel_fn* kernel;
    768 +    stbir__support_fn* support;
    769 +} stbir__filter_info;
    770 +
    771 +// When upsampling, the contributors are which source pixels contribute.
    772 +// When downsampling, the contributors are which destination pixels are contributed to.
    773 +typedef struct
    774 +{
    775 +    int n0; // First contributing pixel
    776 +    int n1; // Last contributing pixel
    777 +} stbir__contributors;
    778 +
    779 +typedef struct
    780 +{
    781 +    const void* input_data;
    782 +    int input_w;
    783 +    int input_h;
    784 +    int input_stride_bytes;
    785 +
    786 +    void* output_data;
    787 +    int output_w;
    788 +    int output_h;
    789 +    int output_stride_bytes;
    790 +
    791 +    float s0, t0, s1, t1;
    792 +
    793 +    float horizontal_shift; // Units: output pixels
    794 +    float vertical_shift;   // Units: output pixels
    795 +    float horizontal_scale;
    796 +    float vertical_scale;
    797 +
    798 +    int channels;
    799 +    int alpha_channel;
    800 +    stbir_uint32 flags;
    801 +    stbir_datatype type;
    802 +    stbir_filter horizontal_filter;
    803 +    stbir_filter vertical_filter;
    804 +    stbir_edge edge_horizontal;
    805 +    stbir_edge edge_vertical;
    806 +    stbir_colorspace colorspace;
    807 +
    808 +    stbir__contributors* horizontal_contributors;
    809 +    float* horizontal_coefficients;
    810 +
    811 +    stbir__contributors* vertical_contributors;
    812 +    float* vertical_coefficients;
    813 +
    814 +    int decode_buffer_pixels;
    815 +    float* decode_buffer;
    816 +
    817 +    float* horizontal_buffer;
    818 +
    819 +    // cache these because ceil/floor are inexplicably showing up in profile
    820 +    int horizontal_coefficient_width;
    821 +    int vertical_coefficient_width;
    822 +    int horizontal_filter_pixel_width;
    823 +    int vertical_filter_pixel_width;
    824 +    int horizontal_filter_pixel_margin;
    825 +    int vertical_filter_pixel_margin;
    826 +    int horizontal_num_contributors;
    827 +    int vertical_num_contributors;
    828 +
    829 +    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)
    830 +    int ring_buffer_num_entries;    // Total number of entries in the ring buffer.
    831 +    int ring_buffer_first_scanline;
    832 +    int ring_buffer_last_scanline;
    833 +    int ring_buffer_begin_index;    // first_scanline is at this index in the ring buffer
    834 +    float* ring_buffer;
    835 +
    836 +    float* encode_buffer; // A temporary buffer to store floats so we don't lose precision while we do multiply-adds.
    837 +
    838 +    int horizontal_contributors_size;
    839 +    int horizontal_coefficients_size;
    840 +    int vertical_contributors_size;
    841 +    int vertical_coefficients_size;
    842 +    int decode_buffer_size;
    843 +    int horizontal_buffer_size;
    844 +    int ring_buffer_size;
    845 +    int encode_buffer_size;
    846 +} stbir__info;
    847 +
    848 +
    849 +static const float stbir__max_uint8_as_float  = 255.0f;
    850 +static const float stbir__max_uint16_as_float = 65535.0f;
    851 +static const double stbir__max_uint32_as_float = 4294967295.0;
    852 +
    853 +
    854 +static stbir__inline int stbir__min(int a, int b)
    855 +{
    856 +    return a < b ? a : b;
    857 +}
    858 +
    859 +static stbir__inline float stbir__saturate(float x)
    860 +{
    861 +    if (x < 0)
    862 +        return 0;
    863 +
    864 +    if (x > 1)
    865 +        return 1;
    866 +
    867 +    return x;
    868 +}
    869 +
    870 +#ifdef STBIR_SATURATE_INT
    871 +static stbir__inline stbir_uint8 stbir__saturate8(int x)
    872 +{
    873 +    if ((unsigned int) x <= 255)
    874 +        return x;
    875 +
    876 +    if (x < 0)
    877 +        return 0;
    878 +
    879 +    return 255;
    880 +}
    881 +
    882 +static stbir__inline stbir_uint16 stbir__saturate16(int x)
    883 +{
    884 +    if ((unsigned int) x <= 65535)
    885 +        return x;
    886 +
    887 +    if (x < 0)
    888 +        return 0;
    889 +
    890 +    return 65535;
    891 +}
    892 +#endif
    893 +
    894 +static float stbir__srgb_uchar_to_linear_float[256] = {
    895 +    0.000000f, 0.000304f, 0.000607f, 0.000911f, 0.001214f, 0.001518f, 0.001821f, 0.002125f, 0.002428f, 0.002732f, 0.003035f,
    896 +    0.003347f, 0.003677f, 0.004025f, 0.004391f, 0.004777f, 0.005182f, 0.005605f, 0.006049f, 0.006512f, 0.006995f, 0.007499f,
    897 +    0.008023f, 0.008568f, 0.009134f, 0.009721f, 0.010330f, 0.010960f, 0.011612f, 0.012286f, 0.012983f, 0.013702f, 0.014444f,
    898 +    0.015209f, 0.015996f, 0.016807f, 0.017642f, 0.018500f, 0.019382f, 0.020289f, 0.021219f, 0.022174f, 0.023153f, 0.024158f,
    899 +    0.025187f, 0.026241f, 0.027321f, 0.028426f, 0.029557f, 0.030713f, 0.031896f, 0.033105f, 0.034340f, 0.035601f, 0.036889f,
    900 +    0.038204f, 0.039546f, 0.040915f, 0.042311f, 0.043735f, 0.045186f, 0.046665f, 0.048172f, 0.049707f, 0.051269f, 0.052861f,
    901 +    0.054480f, 0.056128f, 0.057805f, 0.059511f, 0.061246f, 0.063010f, 0.064803f, 0.066626f, 0.068478f, 0.070360f, 0.072272f,
    902 +    0.074214f, 0.076185f, 0.078187f, 0.080220f, 0.082283f, 0.084376f, 0.086500f, 0.088656f, 0.090842f, 0.093059f, 0.095307f,
    903 +    0.097587f, 0.099899f, 0.102242f, 0.104616f, 0.107023f, 0.109462f, 0.111932f, 0.114435f, 0.116971f, 0.119538f, 0.122139f,
    904 +    0.124772f, 0.127438f, 0.130136f, 0.132868f, 0.135633f, 0.138432f, 0.141263f, 0.144128f, 0.147027f, 0.149960f, 0.152926f,
    905 +    0.155926f, 0.158961f, 0.162029f, 0.165132f, 0.168269f, 0.171441f, 0.174647f, 0.177888f, 0.181164f, 0.184475f, 0.187821f,
    906 +    0.191202f, 0.194618f, 0.198069f, 0.201556f, 0.205079f, 0.208637f, 0.212231f, 0.215861f, 0.219526f, 0.223228f, 0.226966f,
    907 +    0.230740f, 0.234551f, 0.238398f, 0.242281f, 0.246201f, 0.250158f, 0.254152f, 0.258183f, 0.262251f, 0.266356f, 0.270498f,
    908 +    0.274677f, 0.278894f, 0.283149f, 0.287441f, 0.291771f, 0.296138f, 0.300544f, 0.304987f, 0.309469f, 0.313989f, 0.318547f,
    909 +    0.323143f, 0.327778f, 0.332452f, 0.337164f, 0.341914f, 0.346704f, 0.351533f, 0.356400f, 0.361307f, 0.366253f, 0.371238f,
    910 +    0.376262f, 0.381326f, 0.386430f, 0.391573f, 0.396755f, 0.401978f, 0.407240f, 0.412543f, 0.417885f, 0.423268f, 0.428691f,
    911 +    0.434154f, 0.439657f, 0.445201f, 0.450786f, 0.456411f, 0.462077f, 0.467784f, 0.473532f, 0.479320f, 0.485150f, 0.491021f,
    912 +    0.496933f, 0.502887f, 0.508881f, 0.514918f, 0.520996f, 0.527115f, 0.533276f, 0.539480f, 0.545725f, 0.552011f, 0.558340f,
    913 +    0.564712f, 0.571125f, 0.577581f, 0.584078f, 0.590619f, 0.597202f, 0.603827f, 0.610496f, 0.617207f, 0.623960f, 0.630757f,
    914 +    0.637597f, 0.644480f, 0.651406f, 0.658375f, 0.665387f, 0.672443f, 0.679543f, 0.686685f, 0.693872f, 0.701102f, 0.708376f,
    915 +    0.715694f, 0.723055f, 0.730461f, 0.737911f, 0.745404f, 0.752942f, 0.760525f, 0.768151f, 0.775822f, 0.783538f, 0.791298f,
    916 +    0.799103f, 0.806952f, 0.814847f, 0.822786f, 0.830770f, 0.838799f, 0.846873f, 0.854993f, 0.863157f, 0.871367f, 0.879622f,
    917 +    0.887923f, 0.896269f, 0.904661f, 0.913099f, 0.921582f, 0.930111f, 0.938686f, 0.947307f, 0.955974f, 0.964686f, 0.973445f,
    918 +    0.982251f, 0.991102f, 1.0f
    919 +};
    920 +
    921 +static float stbir__srgb_to_linear(float f)
    922 +{
    923 +    if (f <= 0.04045f)
    924 +        return f / 12.92f;
    925 +    else
    926 +        return (float)pow((f + 0.055f) / 1.055f, 2.4f);
    927 +}
    928 +
    929 +static float stbir__linear_to_srgb(float f)
    930 +{
    931 +    if (f <= 0.0031308f)
    932 +        return f * 12.92f;
    933 +    else
    934 +        return 1.055f * (float)pow(f, 1 / 2.4f) - 0.055f;
    935 +}
    936 +
    937 +#ifndef STBIR_NON_IEEE_FLOAT
    938 +// From https://gist.github.com/rygorous/2203834
    939 +
    940 +typedef union
    941 +{
    942 +    stbir_uint32 u;
    943 +    float f;
    944 +} stbir__FP32;
    945 +
    946 +static const stbir_uint32 fp32_to_srgb8_tab4[104] = {
    947 +    0x0073000d, 0x007a000d, 0x0080000d, 0x0087000d, 0x008d000d, 0x0094000d, 0x009a000d, 0x00a1000d,
    948 +    0x00a7001a, 0x00b4001a, 0x00c1001a, 0x00ce001a, 0x00da001a, 0x00e7001a, 0x00f4001a, 0x0101001a,
    949 +    0x010e0033, 0x01280033, 0x01410033, 0x015b0033, 0x01750033, 0x018f0033, 0x01a80033, 0x01c20033,
    950 +    0x01dc0067, 0x020f0067, 0x02430067, 0x02760067, 0x02aa0067, 0x02dd0067, 0x03110067, 0x03440067,
    951 +    0x037800ce, 0x03df00ce, 0x044600ce, 0x04ad00ce, 0x051400ce, 0x057b00c5, 0x05dd00bc, 0x063b00b5,
    952 +    0x06970158, 0x07420142, 0x07e30130, 0x087b0120, 0x090b0112, 0x09940106, 0x0a1700fc, 0x0a9500f2,
    953 +    0x0b0f01cb, 0x0bf401ae, 0x0ccb0195, 0x0d950180, 0x0e56016e, 0x0f0d015e, 0x0fbc0150, 0x10630143,
    954 +    0x11070264, 0x1238023e, 0x1357021d, 0x14660201, 0x156601e9, 0x165a01d3, 0x174401c0, 0x182401af,
    955 +    0x18fe0331, 0x1a9602fe, 0x1c1502d2, 0x1d7e02ad, 0x1ed4028d, 0x201a0270, 0x21520256, 0x227d0240,
    956 +    0x239f0443, 0x25c003fe, 0x27bf03c4, 0x29a10392, 0x2b6a0367, 0x2d1d0341, 0x2ebe031f, 0x304d0300,
    957 +    0x31d105b0, 0x34a80555, 0x37520507, 0x39d504c5, 0x3c37048b, 0x3e7c0458, 0x40a8042a, 0x42bd0401,
    958 +    0x44c20798, 0x488e071e, 0x4c1c06b6, 0x4f76065d, 0x52a50610, 0x55ac05cc, 0x5892058f, 0x5b590559,
    959 +    0x5e0c0a23, 0x631c0980, 0x67db08f6, 0x6c55087f, 0x70940818, 0x74a007bd, 0x787d076c, 0x7c330723,
    960 +};
    961 +
    962 +static stbir_uint8 stbir__linear_to_srgb_uchar(float in)
    963 +{
    964 +    static const stbir__FP32 almostone = { 0x3f7fffff }; // 1-eps
    965 +    static const stbir__FP32 minval = { (127-13) << 23 };
    966 +    stbir_uint32 tab,bias,scale,t;
    967 +    stbir__FP32 f;
    968 +
    969 +    // Clamp to [2^(-13), 1-eps]; these two values map to 0 and 1, respectively.
    970 +    // The tests are carefully written so that NaNs map to 0, same as in the reference
    971 +    // implementation.
    972 +    if (!(in > minval.f)) // written this way to catch NaNs
    973 +        in = minval.f;
    974 +    if (in > almostone.f)
    975 +        in = almostone.f;
    976 +
    977 +    // Do the table lookup and unpack bias, scale
    978 +    f.f = in;
    979 +    tab = fp32_to_srgb8_tab4[(f.u - minval.u) >> 20];
    980 +    bias = (tab >> 16) << 9;
    981 +    scale = tab & 0xffff;
    982 +
    983 +    // Grab next-highest mantissa bits and perform linear interpolation
    984 +    t = (f.u >> 12) & 0xff;
    985 +    return (unsigned char) ((bias + scale*t) >> 16);
    986 +}
    987 +
    988 +#else
    989 +// sRGB transition values, scaled by 1<<28
    990 +static int stbir__srgb_offset_to_linear_scaled[256] =
    991 +{
    992 +            0,     40738,    122216,    203693,    285170,    366648,    448125,    529603,
    993 +       611080,    692557,    774035,    855852,    942009,   1033024,   1128971,   1229926,
    994 +      1335959,   1447142,   1563542,   1685229,   1812268,   1944725,   2082664,   2226148,
    995 +      2375238,   2529996,   2690481,   2856753,   3028870,   3206888,   3390865,   3580856,
    996 +      3776916,   3979100,   4187460,   4402049,   4622919,   4850123,   5083710,   5323731,
    997 +      5570236,   5823273,   6082892,   6349140,   6622065,   6901714,   7188133,   7481369,
    998 +      7781466,   8088471,   8402427,   8723380,   9051372,   9386448,   9728650,  10078021,
    999 +     10434603,  10798439,  11169569,  11548036,  11933879,  12327139,  12727857,  13136073,
   1000 +     13551826,  13975156,  14406100,  14844697,  15290987,  15745007,  16206795,  16676389,
   1001 +     17153826,  17639142,  18132374,  18633560,  19142734,  19659934,  20185196,  20718552,
   1002 +     21260042,  21809696,  22367554,  22933648,  23508010,  24090680,  24681686,  25281066,
   1003 +     25888850,  26505076,  27129772,  27762974,  28404716,  29055026,  29713942,  30381490,
   1004 +     31057708,  31742624,  32436272,  33138682,  33849884,  34569912,  35298800,  36036568,
   1005 +     36783260,  37538896,  38303512,  39077136,  39859796,  40651528,  41452360,  42262316,
   1006 +     43081432,  43909732,  44747252,  45594016,  46450052,  47315392,  48190064,  49074096,
   1007 +     49967516,  50870356,  51782636,  52704392,  53635648,  54576432,  55526772,  56486700,
   1008 +     57456236,  58435408,  59424248,  60422780,  61431036,  62449032,  63476804,  64514376,
   1009 +     65561776,  66619028,  67686160,  68763192,  69850160,  70947088,  72053992,  73170912,
   1010 +     74297864,  75434880,  76581976,  77739184,  78906536,  80084040,  81271736,  82469648,
   1011 +     83677792,  84896192,  86124888,  87363888,  88613232,  89872928,  91143016,  92423512,
   1012 +     93714432,  95015816,  96327688,  97650056,  98982952, 100326408, 101680440, 103045072,
   1013 +    104420320, 105806224, 107202800, 108610064, 110028048, 111456776, 112896264, 114346544,
   1014 +    115807632, 117279552, 118762328, 120255976, 121760536, 123276016, 124802440, 126339832,
   1015 +    127888216, 129447616, 131018048, 132599544, 134192112, 135795792, 137410592, 139036528,
   1016 +    140673648, 142321952, 143981456, 145652208, 147334208, 149027488, 150732064, 152447968,
   1017 +    154175200, 155913792, 157663776, 159425168, 161197984, 162982240, 164777968, 166585184,
   1018 +    168403904, 170234160, 172075968, 173929344, 175794320, 177670896, 179559120, 181458992,
   1019 +    183370528, 185293776, 187228736, 189175424, 191133888, 193104112, 195086128, 197079968,
   1020 +    199085648, 201103184, 203132592, 205173888, 207227120, 209292272, 211369392, 213458480,
   1021 +    215559568, 217672656, 219797792, 221934976, 224084240, 226245600, 228419056, 230604656,
   1022 +    232802400, 235012320, 237234432, 239468736, 241715280, 243974080, 246245120, 248528464,
   1023 +    250824112, 253132064, 255452368, 257785040, 260130080, 262487520, 264857376, 267239664,
   1024 +};
   1025 +
   1026 +static stbir_uint8 stbir__linear_to_srgb_uchar(float f)
   1027 +{
   1028 +    int x = (int) (f * (1 << 28)); // has headroom so you don't need to clamp
   1029 +    int v = 0;
   1030 +    int i;
   1031 +
   1032 +    // Refine the guess with a short binary search.
   1033 +    i = v + 128; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
   1034 +    i = v +  64; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
   1035 +    i = v +  32; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
   1036 +    i = v +  16; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
   1037 +    i = v +   8; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
   1038 +    i = v +   4; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
   1039 +    i = v +   2; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
   1040 +    i = v +   1; if (x >= stbir__srgb_offset_to_linear_scaled[i]) v = i;
   1041 +
   1042 +    return (stbir_uint8) v;
   1043 +}
   1044 +#endif
   1045 +
   1046 +static float stbir__filter_trapezoid(float x, float scale)
   1047 +{
   1048 +    float halfscale = scale / 2;
   1049 +    float t = 0.5f + halfscale;
   1050 +    STBIR_ASSERT(scale <= 1);
   1051 +
   1052 +    x = (float)fabs(x);
   1053 +
   1054 +    if (x >= t)
   1055 +        return 0;
   1056 +    else
   1057 +    {
   1058 +        float r = 0.5f - halfscale;
   1059 +        if (x <= r)
   1060 +            return 1;
   1061 +        else
   1062 +            return (t - x) / scale;
   1063 +    }
   1064 +}
   1065 +
   1066 +static float stbir__support_trapezoid(float scale)
   1067 +{
   1068 +    STBIR_ASSERT(scale <= 1);
   1069 +    return 0.5f + scale / 2;
   1070 +}
   1071 +
   1072 +static float stbir__filter_triangle(float x, float s)
   1073 +{
   1074 +    STBIR__UNUSED_PARAM(s);
   1075 +
   1076 +    x = (float)fabs(x);
   1077 +
   1078 +    if (x <= 1.0f)
   1079 +        return 1 - x;
   1080 +    else
   1081 +        return 0;
   1082 +}
   1083 +
   1084 +static float stbir__filter_cubic(float x, float s)
   1085 +{
   1086 +    STBIR__UNUSED_PARAM(s);
   1087 +
   1088 +    x = (float)fabs(x);
   1089 +
   1090 +    if (x < 1.0f)
   1091 +        return (4 + x*x*(3*x - 6))/6;
   1092 +    else if (x < 2.0f)
   1093 +        return (8 + x*(-12 + x*(6 - x)))/6;
   1094 +
   1095 +    return (0.0f);
   1096 +}
   1097 +
   1098 +static float stbir__filter_catmullrom(float x, float s)
   1099 +{
   1100 +    STBIR__UNUSED_PARAM(s);
   1101 +
   1102 +    x = (float)fabs(x);
   1103 +
   1104 +    if (x < 1.0f)
   1105 +        return 1 - x*x*(2.5f - 1.5f*x);
   1106 +    else if (x < 2.0f)
   1107 +        return 2 - x*(4 + x*(0.5f*x - 2.5f));
   1108 +
   1109 +    return (0.0f);
   1110 +}
   1111 +
   1112 +static float stbir__filter_mitchell(float x, float s)
   1113 +{
   1114 +    STBIR__UNUSED_PARAM(s);
   1115 +
   1116 +    x = (float)fabs(x);
   1117 +
   1118 +    if (x < 1.0f)
   1119 +        return (16 + x*x*(21 * x - 36))/18;
   1120 +    else if (x < 2.0f)
   1121 +        return (32 + x*(-60 + x*(36 - 7*x)))/18;
   1122 +
   1123 +    return (0.0f);
   1124 +}
   1125 +
   1126 +static float stbir__support_zero(float s)
   1127 +{
   1128 +    STBIR__UNUSED_PARAM(s);
   1129 +    return 0;
   1130 +}
   1131 +
   1132 +static float stbir__support_one(float s)
   1133 +{
   1134 +    STBIR__UNUSED_PARAM(s);
   1135 +    return 1;
   1136 +}
   1137 +
   1138 +static float stbir__support_two(float s)
   1139 +{
   1140 +    STBIR__UNUSED_PARAM(s);
   1141 +    return 2;
   1142 +}
   1143 +
   1144 +static stbir__filter_info stbir__filter_info_table[] = {
   1145 +        { NULL,                     stbir__support_zero },
   1146 +        { stbir__filter_trapezoid,  stbir__support_trapezoid },
   1147 +        { stbir__filter_triangle,   stbir__support_one },
   1148 +        { stbir__filter_cubic,      stbir__support_two },
   1149 +        { stbir__filter_catmullrom, stbir__support_two },
   1150 +        { stbir__filter_mitchell,   stbir__support_two },
   1151 +};
   1152 +
   1153 +stbir__inline static int stbir__use_upsampling(float ratio)
   1154 +{
   1155 +    return ratio > 1;
   1156 +}
   1157 +
   1158 +stbir__inline static int stbir__use_width_upsampling(stbir__info* stbir_info)
   1159 +{
   1160 +    return stbir__use_upsampling(stbir_info->horizontal_scale);
   1161 +}
   1162 +
   1163 +stbir__inline static int stbir__use_height_upsampling(stbir__info* stbir_info)
   1164 +{
   1165 +    return stbir__use_upsampling(stbir_info->vertical_scale);
   1166 +}
   1167 +
   1168 +// This is the maximum number of input samples that can affect an output sample
   1169 +// with the given filter
   1170 +static int stbir__get_filter_pixel_width(stbir_filter filter, float scale)
   1171 +{
   1172 +    STBIR_ASSERT(filter != 0);
   1173 +    STBIR_ASSERT(filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
   1174 +
   1175 +    if (stbir__use_upsampling(scale))
   1176 +        return (int)ceil(stbir__filter_info_table[filter].support(1/scale) * 2);
   1177 +    else
   1178 +        return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2 / scale);
   1179 +}
   1180 +
   1181 +// This is how much to expand buffers to account for filters seeking outside
   1182 +// the image boundaries.
   1183 +static int stbir__get_filter_pixel_margin(stbir_filter filter, float scale)
   1184 +{
   1185 +    return stbir__get_filter_pixel_width(filter, scale) / 2;
   1186 +}
   1187 +
   1188 +static int stbir__get_coefficient_width(stbir_filter filter, float scale)
   1189 +{
   1190 +    if (stbir__use_upsampling(scale))
   1191 +        return (int)ceil(stbir__filter_info_table[filter].support(1 / scale) * 2);
   1192 +    else
   1193 +        return (int)ceil(stbir__filter_info_table[filter].support(scale) * 2);
   1194 +}
   1195 +
   1196 +static int stbir__get_contributors(float scale, stbir_filter filter, int input_size, int output_size)
   1197 +{
   1198 +    if (stbir__use_upsampling(scale))
   1199 +        return output_size;
   1200 +    else
   1201 +        return (input_size + stbir__get_filter_pixel_margin(filter, scale) * 2);
   1202 +}
   1203 +
   1204 +static int stbir__get_total_horizontal_coefficients(stbir__info* info)
   1205 +{
   1206 +    return info->horizontal_num_contributors
   1207 +         * stbir__get_coefficient_width      (info->horizontal_filter, info->horizontal_scale);
   1208 +}
   1209 +
   1210 +static int stbir__get_total_vertical_coefficients(stbir__info* info)
   1211 +{
   1212 +    return info->vertical_num_contributors
   1213 +         * stbir__get_coefficient_width      (info->vertical_filter, info->vertical_scale);
   1214 +}
   1215 +
   1216 +static stbir__contributors* stbir__get_contributor(stbir__contributors* contributors, int n)
   1217 +{
   1218 +    return &contributors[n];
   1219 +}
   1220 +
   1221 +// For perf reasons this code is duplicated in stbir__resample_horizontal_upsample/downsample,
   1222 +// if you change it here change it there too.
   1223 +static float* stbir__get_coefficient(float* coefficients, stbir_filter filter, float scale, int n, int c)
   1224 +{
   1225 +    int width = stbir__get_coefficient_width(filter, scale);
   1226 +    return &coefficients[width*n + c];
   1227 +}
   1228 +
   1229 +static int stbir__edge_wrap_slow(stbir_edge edge, int n, int max)
   1230 +{
   1231 +    switch (edge)
   1232 +    {
   1233 +    case STBIR_EDGE_ZERO:
   1234 +        return 0; // we'll decode the wrong pixel here, and then overwrite with 0s later
   1235 +
   1236 +    case STBIR_EDGE_CLAMP:
   1237 +        if (n < 0)
   1238 +            return 0;
   1239 +
   1240 +        if (n >= max)
   1241 +            return max - 1;
   1242 +
   1243 +        return n; // NOTREACHED
   1244 +
   1245 +    case STBIR_EDGE_REFLECT:
   1246 +    {
   1247 +        if (n < 0)
   1248 +        {
   1249 +            if (n < max)
   1250 +                return -n;
   1251 +            else
   1252 +                return max - 1;
   1253 +        }
   1254 +
   1255 +        if (n >= max)
   1256 +        {
   1257 +            int max2 = max * 2;
   1258 +            if (n >= max2)
   1259 +                return 0;
   1260 +            else
   1261 +                return max2 - n - 1;
   1262 +        }
   1263 +
   1264 +        return n; // NOTREACHED
   1265 +    }
   1266 +
   1267 +    case STBIR_EDGE_WRAP:
   1268 +        if (n >= 0)
   1269 +            return (n % max);
   1270 +        else
   1271 +        {
   1272 +            int m = (-n) % max;
   1273 +
   1274 +            if (m != 0)
   1275 +                m = max - m;
   1276 +
   1277 +            return (m);
   1278 +        }
   1279 +        // NOTREACHED
   1280 +
   1281 +    default:
   1282 +        STBIR_ASSERT(!"Unimplemented edge type");
   1283 +        return 0;
   1284 +    }
   1285 +}
   1286 +
   1287 +stbir__inline static int stbir__edge_wrap(stbir_edge edge, int n, int max)
   1288 +{
   1289 +    // avoid per-pixel switch
   1290 +    if (n >= 0 && n < max)
   1291 +        return n;
   1292 +    return stbir__edge_wrap_slow(edge, n, max);
   1293 +}
   1294 +
   1295 +// What input pixels contribute to this output pixel?
   1296 +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)
   1297 +{
   1298 +    float out_pixel_center = (float)n + 0.5f;
   1299 +    float out_pixel_influence_lowerbound = out_pixel_center - out_filter_radius;
   1300 +    float out_pixel_influence_upperbound = out_pixel_center + out_filter_radius;
   1301 +
   1302 +    float in_pixel_influence_lowerbound = (out_pixel_influence_lowerbound + out_shift) / scale_ratio;
   1303 +    float in_pixel_influence_upperbound = (out_pixel_influence_upperbound + out_shift) / scale_ratio;
   1304 +
   1305 +    *in_center_of_out = (out_pixel_center + out_shift) / scale_ratio;
   1306 +    *in_first_pixel = (int)(floor(in_pixel_influence_lowerbound + 0.5));
   1307 +    *in_last_pixel = (int)(floor(in_pixel_influence_upperbound - 0.5));
   1308 +}
   1309 +
   1310 +// What output pixels does this input pixel contribute to?
   1311 +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)
   1312 +{
   1313 +    float in_pixel_center = (float)n + 0.5f;
   1314 +    float in_pixel_influence_lowerbound = in_pixel_center - in_pixels_radius;
   1315 +    float in_pixel_influence_upperbound = in_pixel_center + in_pixels_radius;
   1316 +
   1317 +    float out_pixel_influence_lowerbound = in_pixel_influence_lowerbound * scale_ratio - out_shift;
   1318 +    float out_pixel_influence_upperbound = in_pixel_influence_upperbound * scale_ratio - out_shift;
   1319 +
   1320 +    *out_center_of_in = in_pixel_center * scale_ratio - out_shift;
   1321 +    *out_first_pixel = (int)(floor(out_pixel_influence_lowerbound + 0.5));
   1322 +    *out_last_pixel = (int)(floor(out_pixel_influence_upperbound - 0.5));
   1323 +}
   1324 +
   1325 +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)
   1326 +{
   1327 +    int i;
   1328 +    float total_filter = 0;
   1329 +    float filter_scale;
   1330 +
   1331 +    STBIR_ASSERT(in_last_pixel - in_first_pixel <= (int)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.
   1332 +
   1333 +    contributor->n0 = in_first_pixel;
   1334 +    contributor->n1 = in_last_pixel;
   1335 +
   1336 +    STBIR_ASSERT(contributor->n1 >= contributor->n0);
   1337 +
   1338 +    for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
   1339 +    {
   1340 +        float in_pixel_center = (float)(i + in_first_pixel) + 0.5f;
   1341 +        coefficient_group[i] = stbir__filter_info_table[filter].kernel(in_center_of_out - in_pixel_center, 1 / scale);
   1342 +
   1343 +        // If the coefficient is zero, skip it. (Don't do the <0 check here, we want the influence of those outside pixels.)
   1344 +        if (i == 0 && !coefficient_group[i])
   1345 +        {
   1346 +            contributor->n0 = ++in_first_pixel;
   1347 +            i--;
   1348 +            continue;
   1349 +        }
   1350 +
   1351 +        total_filter += coefficient_group[i];
   1352 +    }
   1353 +
   1354 +    STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(in_last_pixel + 1) + 0.5f - in_center_of_out, 1/scale) == 0);
   1355 +
   1356 +    STBIR_ASSERT(total_filter > 0.9);
   1357 +    STBIR_ASSERT(total_filter < 1.1f); // Make sure it's not way off.
   1358 +
   1359 +    // Make sure the sum of all coefficients is 1.
   1360 +    filter_scale = 1 / total_filter;
   1361 +
   1362 +    for (i = 0; i <= in_last_pixel - in_first_pixel; i++)
   1363 +        coefficient_group[i] *= filter_scale;
   1364 +
   1365 +    for (i = in_last_pixel - in_first_pixel; i >= 0; i--)
   1366 +    {
   1367 +        if (coefficient_group[i])
   1368 +            break;
   1369 +
   1370 +        // This line has no weight. We can skip it.
   1371 +        contributor->n1 = contributor->n0 + i - 1;
   1372 +    }
   1373 +}
   1374 +
   1375 +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)
   1376 +{
   1377 +    int i;
   1378 +
   1379 +     STBIR_ASSERT(out_last_pixel - out_first_pixel <= (int)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.
   1380 +
   1381 +    contributor->n0 = out_first_pixel;
   1382 +    contributor->n1 = out_last_pixel;
   1383 +
   1384 +    STBIR_ASSERT(contributor->n1 >= contributor->n0);
   1385 +
   1386 +    for (i = 0; i <= out_last_pixel - out_first_pixel; i++)
   1387 +    {
   1388 +        float out_pixel_center = (float)(i + out_first_pixel) + 0.5f;
   1389 +        float x = out_pixel_center - out_center_of_in;
   1390 +        coefficient_group[i] = stbir__filter_info_table[filter].kernel(x, scale_ratio) * scale_ratio;
   1391 +    }
   1392 +
   1393 +    STBIR_ASSERT(stbir__filter_info_table[filter].kernel((float)(out_last_pixel + 1) + 0.5f - out_center_of_in, scale_ratio) == 0);
   1394 +
   1395 +    for (i = out_last_pixel - out_first_pixel; i >= 0; i--)
   1396 +    {
   1397 +        if (coefficient_group[i])
   1398 +            break;
   1399 +
   1400 +        // This line has no weight. We can skip it.
   1401 +        contributor->n1 = contributor->n0 + i - 1;
   1402 +    }
   1403 +}
   1404 +
   1405 +static void stbir__normalize_downsample_coefficients(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, int input_size, int output_size)
   1406 +{
   1407 +    int num_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
   1408 +    int num_coefficients = stbir__get_coefficient_width(filter, scale_ratio);
   1409 +    int i, j;
   1410 +    int skip;
   1411 +
   1412 +    for (i = 0; i < output_size; i++)
   1413 +    {
   1414 +        float scale;
   1415 +        float total = 0;
   1416 +
   1417 +        for (j = 0; j < num_contributors; j++)
   1418 +        {
   1419 +            if (i >= contributors[j].n0 && i <= contributors[j].n1)
   1420 +            {
   1421 +                float coefficient = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0);
   1422 +                total += coefficient;
   1423 +            }
   1424 +            else if (i < contributors[j].n0)
   1425 +                break;
   1426 +        }
   1427 +
   1428 +        STBIR_ASSERT(total > 0.9f);
   1429 +        STBIR_ASSERT(total < 1.1f);
   1430 +
   1431 +        scale = 1 / total;
   1432 +
   1433 +        for (j = 0; j < num_contributors; j++)
   1434 +        {
   1435 +            if (i >= contributors[j].n0 && i <= contributors[j].n1)
   1436 +                *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i - contributors[j].n0) *= scale;
   1437 +            else if (i < contributors[j].n0)
   1438 +                break;
   1439 +        }
   1440 +    }
   1441 +
   1442 +    // Optimize: Skip zero coefficients and contributions outside of image bounds.
   1443 +    // Do this after normalizing because normalization depends on the n0/n1 values.
   1444 +    for (j = 0; j < num_contributors; j++)
   1445 +    {
   1446 +        int range, max, width;
   1447 +
   1448 +        skip = 0;
   1449 +        while (*stbir__get_coefficient(coefficients, filter, scale_ratio, j, skip) == 0)
   1450 +            skip++;
   1451 +
   1452 +        contributors[j].n0 += skip;
   1453 +
   1454 +        while (contributors[j].n0 < 0)
   1455 +        {
   1456 +            contributors[j].n0++;
   1457 +            skip++;
   1458 +        }
   1459 +
   1460 +        range = contributors[j].n1 - contributors[j].n0 + 1;
   1461 +        max = stbir__min(num_coefficients, range);
   1462 +
   1463 +        width = stbir__get_coefficient_width(filter, scale_ratio);
   1464 +        for (i = 0; i < max; i++)
   1465 +        {
   1466 +            if (i + skip >= width)
   1467 +                break;
   1468 +
   1469 +            *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i) = *stbir__get_coefficient(coefficients, filter, scale_ratio, j, i + skip);
   1470 +        }
   1471 +
   1472 +        continue;
   1473 +    }
   1474 +
   1475 +    // Using min to avoid writing into invalid pixels.
   1476 +    for (i = 0; i < num_contributors; i++)
   1477 +        contributors[i].n1 = stbir__min(contributors[i].n1, output_size - 1);
   1478 +}
   1479 +
   1480 +// Each scan line uses the same kernel values so we should calculate the kernel
   1481 +// values once and then we can use them for every scan line.
   1482 +static void stbir__calculate_filters(stbir__contributors* contributors, float* coefficients, stbir_filter filter, float scale_ratio, float shift, int input_size, int output_size)
   1483 +{
   1484 +    int n;
   1485 +    int total_contributors = stbir__get_contributors(scale_ratio, filter, input_size, output_size);
   1486 +
   1487 +    if (stbir__use_upsampling(scale_ratio))
   1488 +    {
   1489 +        float out_pixels_radius = stbir__filter_info_table[filter].support(1 / scale_ratio) * scale_ratio;
   1490 +
   1491 +        // Looping through out pixels
   1492 +        for (n = 0; n < total_contributors; n++)
   1493 +        {
   1494 +            float in_center_of_out; // Center of the current out pixel in the in pixel space
   1495 +            int in_first_pixel, in_last_pixel;
   1496 +
   1497 +            stbir__calculate_sample_range_upsample(n, out_pixels_radius, scale_ratio, shift, &in_first_pixel, &in_last_pixel, &in_center_of_out);
   1498 +
   1499 +            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));
   1500 +        }
   1501 +    }
   1502 +    else
   1503 +    {
   1504 +        float in_pixels_radius = stbir__filter_info_table[filter].support(scale_ratio) / scale_ratio;
   1505 +
   1506 +        // Looping through in pixels
   1507 +        for (n = 0; n < total_contributors; n++)
   1508 +        {
   1509 +            float out_center_of_in; // Center of the current out pixel in the in pixel space
   1510 +            int out_first_pixel, out_last_pixel;
   1511 +            int n_adjusted = n - stbir__get_filter_pixel_margin(filter, scale_ratio);
   1512 +
   1513 +            stbir__calculate_sample_range_downsample(n_adjusted, in_pixels_radius, scale_ratio, shift, &out_first_pixel, &out_last_pixel, &out_center_of_in);
   1514 +
   1515 +            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));
   1516 +        }
   1517 +
   1518 +        stbir__normalize_downsample_coefficients(contributors, coefficients, filter, scale_ratio, input_size, output_size);
   1519 +    }
   1520 +}
   1521 +
   1522 +static float* stbir__get_decode_buffer(stbir__info* stbir_info)
   1523 +{
   1524 +    // The 0 index of the decode buffer starts after the margin. This makes
   1525 +    // it okay to use negative indexes on the decode buffer.
   1526 +    return &stbir_info->decode_buffer[stbir_info->horizontal_filter_pixel_margin * stbir_info->channels];
   1527 +}
   1528 +
   1529 +#define STBIR__DECODE(type, colorspace) ((int)(type) * (STBIR_MAX_COLORSPACES) + (int)(colorspace))
   1530 +
   1531 +static void stbir__decode_scanline(stbir__info* stbir_info, int n)
   1532 +{
   1533 +    int c;
   1534 +    int channels = stbir_info->channels;
   1535 +    int alpha_channel = stbir_info->alpha_channel;
   1536 +    int type = stbir_info->type;
   1537 +    int colorspace = stbir_info->colorspace;
   1538 +    int input_w = stbir_info->input_w;
   1539 +    size_t input_stride_bytes = stbir_info->input_stride_bytes;
   1540 +    float* decode_buffer = stbir__get_decode_buffer(stbir_info);
   1541 +    stbir_edge edge_horizontal = stbir_info->edge_horizontal;
   1542 +    stbir_edge edge_vertical = stbir_info->edge_vertical;
   1543 +    size_t in_buffer_row_offset = stbir__edge_wrap(edge_vertical, n, stbir_info->input_h) * input_stride_bytes;
   1544 +    const void* input_data = (char *) stbir_info->input_data + in_buffer_row_offset;
   1545 +    int max_x = input_w + stbir_info->horizontal_filter_pixel_margin;
   1546 +    int decode = STBIR__DECODE(type, colorspace);
   1547 +
   1548 +    int x = -stbir_info->horizontal_filter_pixel_margin;
   1549 +
   1550 +    // special handling for STBIR_EDGE_ZERO because it needs to return an item that doesn't appear in the input,
   1551 +    // and we want to avoid paying overhead on every pixel if not STBIR_EDGE_ZERO
   1552 +    if (edge_vertical == STBIR_EDGE_ZERO && (n < 0 || n >= stbir_info->input_h))
   1553 +    {
   1554 +        for (; x < max_x; x++)
   1555 +            for (c = 0; c < channels; c++)
   1556 +                decode_buffer[x*channels + c] = 0;
   1557 +        return;
   1558 +    }
   1559 +
   1560 +    switch (decode)
   1561 +    {
   1562 +    case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
   1563 +        for (; x < max_x; x++)
   1564 +        {
   1565 +            int decode_pixel_index = x * channels;
   1566 +            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1567 +            for (c = 0; c < channels; c++)
   1568 +                decode_buffer[decode_pixel_index + c] = ((float)((const unsigned char*)input_data)[input_pixel_index + c]) / stbir__max_uint8_as_float;
   1569 +        }
   1570 +        break;
   1571 +
   1572 +    case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
   1573 +        for (; x < max_x; x++)
   1574 +        {
   1575 +            int decode_pixel_index = x * channels;
   1576 +            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1577 +            for (c = 0; c < channels; c++)
   1578 +                decode_buffer[decode_pixel_index + c] = stbir__srgb_uchar_to_linear_float[((const unsigned char*)input_data)[input_pixel_index + c]];
   1579 +
   1580 +            if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1581 +                decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned char*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint8_as_float;
   1582 +        }
   1583 +        break;
   1584 +
   1585 +    case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
   1586 +        for (; x < max_x; x++)
   1587 +        {
   1588 +            int decode_pixel_index = x * channels;
   1589 +            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1590 +            for (c = 0; c < channels; c++)
   1591 +                decode_buffer[decode_pixel_index + c] = ((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float;
   1592 +        }
   1593 +        break;
   1594 +
   1595 +    case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
   1596 +        for (; x < max_x; x++)
   1597 +        {
   1598 +            int decode_pixel_index = x * channels;
   1599 +            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1600 +            for (c = 0; c < channels; c++)
   1601 +                decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((float)((const unsigned short*)input_data)[input_pixel_index + c]) / stbir__max_uint16_as_float);
   1602 +
   1603 +            if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1604 +                decode_buffer[decode_pixel_index + alpha_channel] = ((float)((const unsigned short*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint16_as_float;
   1605 +        }
   1606 +        break;
   1607 +
   1608 +    case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
   1609 +        for (; x < max_x; x++)
   1610 +        {
   1611 +            int decode_pixel_index = x * channels;
   1612 +            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1613 +            for (c = 0; c < channels; c++)
   1614 +                decode_buffer[decode_pixel_index + c] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float);
   1615 +        }
   1616 +        break;
   1617 +
   1618 +    case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
   1619 +        for (; x < max_x; x++)
   1620 +        {
   1621 +            int decode_pixel_index = x * channels;
   1622 +            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1623 +            for (c = 0; c < channels; c++)
   1624 +                decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear((float)(((double)((const unsigned int*)input_data)[input_pixel_index + c]) / stbir__max_uint32_as_float));
   1625 +
   1626 +            if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1627 +                decode_buffer[decode_pixel_index + alpha_channel] = (float)(((double)((const unsigned int*)input_data)[input_pixel_index + alpha_channel]) / stbir__max_uint32_as_float);
   1628 +        }
   1629 +        break;
   1630 +
   1631 +    case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
   1632 +        for (; x < max_x; x++)
   1633 +        {
   1634 +            int decode_pixel_index = x * channels;
   1635 +            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1636 +            for (c = 0; c < channels; c++)
   1637 +                decode_buffer[decode_pixel_index + c] = ((const float*)input_data)[input_pixel_index + c];
   1638 +        }
   1639 +        break;
   1640 +
   1641 +    case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
   1642 +        for (; x < max_x; x++)
   1643 +        {
   1644 +            int decode_pixel_index = x * channels;
   1645 +            int input_pixel_index = stbir__edge_wrap(edge_horizontal, x, input_w) * channels;
   1646 +            for (c = 0; c < channels; c++)
   1647 +                decode_buffer[decode_pixel_index + c] = stbir__srgb_to_linear(((const float*)input_data)[input_pixel_index + c]);
   1648 +
   1649 +            if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   1650 +                decode_buffer[decode_pixel_index + alpha_channel] = ((const float*)input_data)[input_pixel_index + alpha_channel];
   1651 +        }
   1652 +
   1653 +        break;
   1654 +
   1655 +    default:
   1656 +        STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
   1657 +        break;
   1658 +    }
   1659 +
   1660 +    if (!(stbir_info->flags & STBIR_FLAG_ALPHA_PREMULTIPLIED))
   1661 +    {
   1662 +        for (x = -stbir_info->horizontal_filter_pixel_margin; x < max_x; x++)
   1663 +        {
   1664 +            int decode_pixel_index = x * channels;
   1665 +
   1666 +            // If the alpha value is 0 it will clobber the color values. Make sure it's not.
   1667 +            float alpha = decode_buffer[decode_pixel_index + alpha_channel];
   1668 +#ifndef STBIR_NO_ALPHA_EPSILON
   1669 +            if (stbir_info->type != STBIR_TYPE_FLOAT) {
   1670 +                alpha += STBIR_ALPHA_EPSILON;
   1671 +                decode_buffer[decode_pixel_index + alpha_channel] = alpha;
   1672 +            }
   1673 +#endif
   1674 +            for (c = 0; c < channels; c++)
   1675 +            {
   1676 +                if (c == alpha_channel)
   1677 +                    continue;
   1678 +
   1679 +                decode_buffer[decode_pixel_index + c] *= alpha;
   1680 +            }
   1681 +        }
   1682 +    }
   1683 +
   1684 +    if (edge_horizontal == STBIR_EDGE_ZERO)
   1685 +    {
   1686 +        for (x = -stbir_info->horizontal_filter_pixel_margin; x < 0; x++)
   1687 +        {
   1688 +            for (c = 0; c < channels; c++)
   1689 +                decode_buffer[x*channels + c] = 0;
   1690 +        }
   1691 +        for (x = input_w; x < max_x; x++)
   1692 +        {
   1693 +            for (c = 0; c < channels; c++)
   1694 +                decode_buffer[x*channels + c] = 0;
   1695 +        }
   1696 +    }
   1697 +}
   1698 +
   1699 +static float* stbir__get_ring_buffer_entry(float* ring_buffer, int index, int ring_buffer_length)
   1700 +{
   1701 +    return &ring_buffer[index * ring_buffer_length];
   1702 +}
   1703 +
   1704 +static float* stbir__add_empty_ring_buffer_entry(stbir__info* stbir_info, int n)
   1705 +{
   1706 +    int ring_buffer_index;
   1707 +    float* ring_buffer;
   1708 +
   1709 +    stbir_info->ring_buffer_last_scanline = n;
   1710 +
   1711 +    if (stbir_info->ring_buffer_begin_index < 0)
   1712 +    {
   1713 +        ring_buffer_index = stbir_info->ring_buffer_begin_index = 0;
   1714 +        stbir_info->ring_buffer_first_scanline = n;
   1715 +    }
   1716 +    else
   1717 +    {
   1718 +        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;
   1719 +        STBIR_ASSERT(ring_buffer_index != stbir_info->ring_buffer_begin_index);
   1720 +    }
   1721 +
   1722 +    ring_buffer = stbir__get_ring_buffer_entry(stbir_info->ring_buffer, ring_buffer_index, stbir_info->ring_buffer_length_bytes / sizeof(float));
   1723 +    memset(ring_buffer, 0, stbir_info->ring_buffer_length_bytes);
   1724 +
   1725 +    return ring_buffer;
   1726 +}
   1727 +
   1728 +
   1729 +static void stbir__resample_horizontal_upsample(stbir__info* stbir_info, float* output_buffer)
   1730 +{
   1731 +    int x, k;
   1732 +    int output_w = stbir_info->output_w;
   1733 +    int channels = stbir_info->channels;
   1734 +    float* decode_buffer = stbir__get_decode_buffer(stbir_info);
   1735 +    stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
   1736 +    float* horizontal_coefficients = stbir_info->horizontal_coefficients;
   1737 +    int coefficient_width = stbir_info->horizontal_coefficient_width;
   1738 +
   1739 +    for (x = 0; x < output_w; x++)
   1740 +    {
   1741 +        int n0 = horizontal_contributors[x].n0;
   1742 +        int n1 = horizontal_contributors[x].n1;
   1743 +
   1744 +        int out_pixel_index = x * channels;
   1745 +        int coefficient_group = coefficient_width * x;
   1746 +        int coefficient_counter = 0;
   1747 +
   1748 +        STBIR_ASSERT(n1 >= n0);
   1749 +        STBIR_ASSERT(n0 >= -stbir_info->horizontal_filter_pixel_margin);
   1750 +        STBIR_ASSERT(n1 >= -stbir_info->horizontal_filter_pixel_margin);
   1751 +        STBIR_ASSERT(n0 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
   1752 +        STBIR_ASSERT(n1 < stbir_info->input_w + stbir_info->horizontal_filter_pixel_margin);
   1753 +
   1754 +        switch (channels) {
   1755 +            case 1:
   1756 +                for (k = n0; k <= n1; k++)
   1757 +                {
   1758 +                    int in_pixel_index = k * 1;
   1759 +                    float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
   1760 +                    STBIR_ASSERT(coefficient != 0);
   1761 +                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1762 +                }
   1763 +                break;
   1764 +            case 2:
   1765 +                for (k = n0; k <= n1; k++)
   1766 +                {
   1767 +                    int in_pixel_index = k * 2;
   1768 +                    float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
   1769 +                    STBIR_ASSERT(coefficient != 0);
   1770 +                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1771 +                    output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
   1772 +                }
   1773 +                break;
   1774 +            case 3:
   1775 +                for (k = n0; k <= n1; k++)
   1776 +                {
   1777 +                    int in_pixel_index = k * 3;
   1778 +                    float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
   1779 +                    STBIR_ASSERT(coefficient != 0);
   1780 +                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1781 +                    output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
   1782 +                    output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
   1783 +                }
   1784 +                break;
   1785 +            case 4:
   1786 +                for (k = n0; k <= n1; k++)
   1787 +                {
   1788 +                    int in_pixel_index = k * 4;
   1789 +                    float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
   1790 +                    STBIR_ASSERT(coefficient != 0);
   1791 +                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1792 +                    output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
   1793 +                    output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
   1794 +                    output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
   1795 +                }
   1796 +                break;
   1797 +            default:
   1798 +                for (k = n0; k <= n1; k++)
   1799 +                {
   1800 +                    int in_pixel_index = k * channels;
   1801 +                    float coefficient = horizontal_coefficients[coefficient_group + coefficient_counter++];
   1802 +                    int c;
   1803 +                    STBIR_ASSERT(coefficient != 0);
   1804 +                    for (c = 0; c < channels; c++)
   1805 +                        output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
   1806 +                }
   1807 +                break;
   1808 +        }
   1809 +    }
   1810 +}
   1811 +
   1812 +static void stbir__resample_horizontal_downsample(stbir__info* stbir_info, float* output_buffer)
   1813 +{
   1814 +    int x, k;
   1815 +    int input_w = stbir_info->input_w;
   1816 +    int channels = stbir_info->channels;
   1817 +    float* decode_buffer = stbir__get_decode_buffer(stbir_info);
   1818 +    stbir__contributors* horizontal_contributors = stbir_info->horizontal_contributors;
   1819 +    float* horizontal_coefficients = stbir_info->horizontal_coefficients;
   1820 +    int coefficient_width = stbir_info->horizontal_coefficient_width;
   1821 +    int filter_pixel_margin = stbir_info->horizontal_filter_pixel_margin;
   1822 +    int max_x = input_w + filter_pixel_margin * 2;
   1823 +
   1824 +    STBIR_ASSERT(!stbir__use_width_upsampling(stbir_info));
   1825 +
   1826 +    switch (channels) {
   1827 +        case 1:
   1828 +            for (x = 0; x < max_x; x++)
   1829 +            {
   1830 +                int n0 = horizontal_contributors[x].n0;
   1831 +                int n1 = horizontal_contributors[x].n1;
   1832 +
   1833 +                int in_x = x - filter_pixel_margin;
   1834 +                int in_pixel_index = in_x * 1;
   1835 +                int max_n = n1;
   1836 +                int coefficient_group = coefficient_width * x;
   1837 +
   1838 +                for (k = n0; k <= max_n; k++)
   1839 +                {
   1840 +                    int out_pixel_index = k * 1;
   1841 +                    float coefficient = horizontal_coefficients[coefficient_group + k - n0];
   1842 +                    STBIR_ASSERT(coefficient != 0);
   1843 +                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1844 +                }
   1845 +            }
   1846 +            break;
   1847 +
   1848 +        case 2:
   1849 +            for (x = 0; x < max_x; x++)
   1850 +            {
   1851 +                int n0 = horizontal_contributors[x].n0;
   1852 +                int n1 = horizontal_contributors[x].n1;
   1853 +
   1854 +                int in_x = x - filter_pixel_margin;
   1855 +                int in_pixel_index = in_x * 2;
   1856 +                int max_n = n1;
   1857 +                int coefficient_group = coefficient_width * x;
   1858 +
   1859 +                for (k = n0; k <= max_n; k++)
   1860 +                {
   1861 +                    int out_pixel_index = k * 2;
   1862 +                    float coefficient = horizontal_coefficients[coefficient_group + k - n0];
   1863 +                    STBIR_ASSERT(coefficient != 0);
   1864 +                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1865 +                    output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
   1866 +                }
   1867 +            }
   1868 +            break;
   1869 +
   1870 +        case 3:
   1871 +            for (x = 0; x < max_x; x++)
   1872 +            {
   1873 +                int n0 = horizontal_contributors[x].n0;
   1874 +                int n1 = horizontal_contributors[x].n1;
   1875 +
   1876 +                int in_x = x - filter_pixel_margin;
   1877 +                int in_pixel_index = in_x * 3;
   1878 +                int max_n = n1;
   1879 +                int coefficient_group = coefficient_width * x;
   1880 +
   1881 +                for (k = n0; k <= max_n; k++)
   1882 +                {
   1883 +                    int out_pixel_index = k * 3;
   1884 +                    float coefficient = horizontal_coefficients[coefficient_group + k - n0];
   1885 +                    STBIR_ASSERT(coefficient != 0);
   1886 +                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1887 +                    output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
   1888 +                    output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
   1889 +                }
   1890 +            }
   1891 +            break;
   1892 +
   1893 +        case 4:
   1894 +            for (x = 0; x < max_x; x++)
   1895 +            {
   1896 +                int n0 = horizontal_contributors[x].n0;
   1897 +                int n1 = horizontal_contributors[x].n1;
   1898 +
   1899 +                int in_x = x - filter_pixel_margin;
   1900 +                int in_pixel_index = in_x * 4;
   1901 +                int max_n = n1;
   1902 +                int coefficient_group = coefficient_width * x;
   1903 +
   1904 +                for (k = n0; k <= max_n; k++)
   1905 +                {
   1906 +                    int out_pixel_index = k * 4;
   1907 +                    float coefficient = horizontal_coefficients[coefficient_group + k - n0];
   1908 +                    STBIR_ASSERT(coefficient != 0);
   1909 +                    output_buffer[out_pixel_index + 0] += decode_buffer[in_pixel_index + 0] * coefficient;
   1910 +                    output_buffer[out_pixel_index + 1] += decode_buffer[in_pixel_index + 1] * coefficient;
   1911 +                    output_buffer[out_pixel_index + 2] += decode_buffer[in_pixel_index + 2] * coefficient;
   1912 +                    output_buffer[out_pixel_index + 3] += decode_buffer[in_pixel_index + 3] * coefficient;
   1913 +                }
   1914 +            }
   1915 +            break;
   1916 +
   1917 +        default:
   1918 +            for (x = 0; x < max_x; x++)
   1919 +            {
   1920 +                int n0 = horizontal_contributors[x].n0;
   1921 +                int n1 = horizontal_contributors[x].n1;
   1922 +
   1923 +                int in_x = x - filter_pixel_margin;
   1924 +                int in_pixel_index = in_x * channels;
   1925 +                int max_n = n1;
   1926 +                int coefficient_group = coefficient_width * x;
   1927 +
   1928 +                for (k = n0; k <= max_n; k++)
   1929 +                {
   1930 +                    int c;
   1931 +                    int out_pixel_index = k * channels;
   1932 +                    float coefficient = horizontal_coefficients[coefficient_group + k - n0];
   1933 +                    STBIR_ASSERT(coefficient != 0);
   1934 +                    for (c = 0; c < channels; c++)
   1935 +                        output_buffer[out_pixel_index + c] += decode_buffer[in_pixel_index + c] * coefficient;
   1936 +                }
   1937 +            }
   1938 +            break;
   1939 +    }
   1940 +}
   1941 +
   1942 +static void stbir__decode_and_resample_upsample(stbir__info* stbir_info, int n)
   1943 +{
   1944 +    // Decode the nth scanline from the source image into the decode buffer.
   1945 +    stbir__decode_scanline(stbir_info, n);
   1946 +
   1947 +    // Now resample it into the ring buffer.
   1948 +    if (stbir__use_width_upsampling(stbir_info))
   1949 +        stbir__resample_horizontal_upsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
   1950 +    else
   1951 +        stbir__resample_horizontal_downsample(stbir_info, stbir__add_empty_ring_buffer_entry(stbir_info, n));
   1952 +
   1953 +    // Now it's sitting in the ring buffer ready to be used as source for the vertical sampling.
   1954 +}
   1955 +
   1956 +static void stbir__decode_and_resample_downsample(stbir__info* stbir_info, int n)
   1957 +{
   1958 +    // Decode the nth scanline from the source image into the decode buffer.
   1959 +    stbir__decode_scanline(stbir_info, n);
   1960 +
   1961 +    memset(stbir_info->horizontal_buffer, 0, stbir_info->output_w * stbir_info->channels * sizeof(float));
   1962 +
   1963 +    // Now resample it into the horizontal buffer.
   1964 +    if (stbir__use_width_upsampling(stbir_info))
   1965 +        stbir__resample_horizontal_upsample(stbir_info, stbir_info->horizontal_buffer);
   1966 +    else
   1967 +        stbir__resample_horizontal_downsample(stbir_info, stbir_info->horizontal_buffer);
   1968 +
   1969 +    // Now it's sitting in the horizontal buffer ready to be distributed into the ring buffers.
   1970 +}
   1971 +
   1972 +// Get the specified scan line from the ring buffer.
   1973 +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)
   1974 +{
   1975 +    int ring_buffer_index = (begin_index + (get_scanline - first_scanline)) % ring_buffer_num_entries;
   1976 +    return stbir__get_ring_buffer_entry(ring_buffer, ring_buffer_index, ring_buffer_length);
   1977 +}
   1978 +
   1979 +
   1980 +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)
   1981 +{
   1982 +    int x;
   1983 +    int n;
   1984 +    int num_nonalpha;
   1985 +    stbir_uint16 nonalpha[STBIR_MAX_CHANNELS];
   1986 +
   1987 +    if (!(stbir_info->flags&STBIR_FLAG_ALPHA_PREMULTIPLIED))
   1988 +    {
   1989 +        for (x=0; x < num_pixels; ++x)
   1990 +        {
   1991 +            int pixel_index = x*channels;
   1992 +
   1993 +            float alpha = encode_buffer[pixel_index + alpha_channel];
   1994 +            float reciprocal_alpha = alpha ? 1.0f / alpha : 0;
   1995 +
   1996 +            // unrolling this produced a 1% slowdown upscaling a large RGBA linear-space image on my machine - stb
   1997 +            for (n = 0; n < channels; n++)
   1998 +                if (n != alpha_channel)
   1999 +                    encode_buffer[pixel_index + n] *= reciprocal_alpha;
   2000 +
   2001 +            // We added in a small epsilon to prevent the color channel from being deleted with zero alpha.
   2002 +            // Because we only add it for integer types, it will automatically be discarded on integer
   2003 +            // conversion, so we don't need to subtract it back out (which would be problematic for
   2004 +            // numeric precision reasons).
   2005 +        }
   2006 +    }
   2007 +
   2008 +    // build a table of all channels that need colorspace correction, so
   2009 +    // we don't perform colorspace correction on channels that don't need it.
   2010 +    for (x = 0, num_nonalpha = 0; x < channels; ++x)
   2011 +    {
   2012 +        if (x != alpha_channel || (stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
   2013 +        {
   2014 +            nonalpha[num_nonalpha++] = (stbir_uint16)x;
   2015 +        }
   2016 +    }
   2017 +
   2018 +    #define STBIR__ROUND_INT(f)    ((int)          ((f)+0.5))
   2019 +    #define STBIR__ROUND_UINT(f)   ((stbir_uint32) ((f)+0.5))
   2020 +
   2021 +    #ifdef STBIR__SATURATE_INT
   2022 +    #define STBIR__ENCODE_LINEAR8(f)   stbir__saturate8 (STBIR__ROUND_INT((f) * stbir__max_uint8_as_float ))
   2023 +    #define STBIR__ENCODE_LINEAR16(f)  stbir__saturate16(STBIR__ROUND_INT((f) * stbir__max_uint16_as_float))
   2024 +    #else
   2025 +    #define STBIR__ENCODE_LINEAR8(f)   (unsigned char ) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint8_as_float )
   2026 +    #define STBIR__ENCODE_LINEAR16(f)  (unsigned short) STBIR__ROUND_INT(stbir__saturate(f) * stbir__max_uint16_as_float)
   2027 +    #endif
   2028 +
   2029 +    switch (decode)
   2030 +    {
   2031 +        case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_LINEAR):
   2032 +            for (x=0; x < num_pixels; ++x)
   2033 +            {
   2034 +                int pixel_index = x*channels;
   2035 +
   2036 +                for (n = 0; n < channels; n++)
   2037 +                {
   2038 +                    int index = pixel_index + n;
   2039 +                    ((unsigned char*)output_buffer)[index] = STBIR__ENCODE_LINEAR8(encode_buffer[index]);
   2040 +                }
   2041 +            }
   2042 +            break;
   2043 +
   2044 +        case STBIR__DECODE(STBIR_TYPE_UINT8, STBIR_COLORSPACE_SRGB):
   2045 +            for (x=0; x < num_pixels; ++x)
   2046 +            {
   2047 +                int pixel_index = x*channels;
   2048 +
   2049 +                for (n = 0; n < num_nonalpha; n++)
   2050 +                {
   2051 +                    int index = pixel_index + nonalpha[n];
   2052 +                    ((unsigned char*)output_buffer)[index] = stbir__linear_to_srgb_uchar(encode_buffer[index]);
   2053 +                }
   2054 +
   2055 +                if (!(stbir_info->flags & STBIR_FLAG_ALPHA_USES_COLORSPACE))
   2056 +                    ((unsigned char *)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR8(encode_buffer[pixel_index+alpha_channel]);
   2057 +            }
   2058 +            break;
   2059 +
   2060 +        case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_LINEAR):
   2061 +            for (x=0; x < num_pixels; ++x)
   2062 +            {
   2063 +                int pixel_index = x*channels;
   2064 +
   2065 +                for (n = 0; n < channels; n++)
   2066 +                {
   2067 +                    int index = pixel_index + n;
   2068 +                    ((unsigned short*)output_buffer)[index] = STBIR__ENCODE_LINEAR16(encode_buffer[index]);
   2069 +                }
   2070 +            }
   2071 +            break;
   2072 +
   2073 +        case STBIR__DECODE(STBIR_TYPE_UINT16, STBIR_COLORSPACE_SRGB):
   2074 +            for (x=0; x < num_pixels; ++x)
   2075 +            {
   2076 +                int pixel_index = x*channels;
   2077 +
   2078 +                for (n = 0; n < num_nonalpha; n++)
   2079 +                {
   2080 +                    int index = pixel_index + nonalpha[n];
   2081 +                    ((unsigned short*)output_buffer)[index] = (unsigned short)STBIR__ROUND_INT(stbir__linear_to_srgb(stbir__saturate(encode_buffer[index])) * stbir__max_uint16_as_float);
   2082 +                }
   2083 +
   2084 +                if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   2085 +                    ((unsigned short*)output_buffer)[pixel_index + alpha_channel] = STBIR__ENCODE_LINEAR16(encode_buffer[pixel_index + alpha_channel]);
   2086 +            }
   2087 +
   2088 +            break;
   2089 +
   2090 +        case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_LINEAR):
   2091 +            for (x=0; x < num_pixels; ++x)
   2092 +            {
   2093 +                int pixel_index = x*channels;
   2094 +
   2095 +                for (n = 0; n < channels; n++)
   2096 +                {
   2097 +                    int index = pixel_index + n;
   2098 +                    ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__saturate(encode_buffer[index])) * stbir__max_uint32_as_float);
   2099 +                }
   2100 +            }
   2101 +            break;
   2102 +
   2103 +        case STBIR__DECODE(STBIR_TYPE_UINT32, STBIR_COLORSPACE_SRGB):
   2104 +            for (x=0; x < num_pixels; ++x)
   2105 +            {
   2106 +                int pixel_index = x*channels;
   2107 +
   2108 +                for (n = 0; n < num_nonalpha; n++)
   2109 +                {
   2110 +                    int index = pixel_index + nonalpha[n];
   2111 +                    ((unsigned int*)output_buffer)[index] = (unsigned int)STBIR__ROUND_UINT(((double)stbir__linear_to_srgb(stbir__saturate(encode_buffer[index]))) * stbir__max_uint32_as_float);
   2112 +                }
   2113 +
   2114 +                if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   2115 +                    ((unsigned int*)output_buffer)[pixel_index + alpha_channel] = (unsigned int)STBIR__ROUND_INT(((double)stbir__saturate(encode_buffer[pixel_index + alpha_channel])) * stbir__max_uint32_as_float);
   2116 +            }
   2117 +            break;
   2118 +
   2119 +        case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_LINEAR):
   2120 +            for (x=0; x < num_pixels; ++x)
   2121 +            {
   2122 +                int pixel_index = x*channels;
   2123 +
   2124 +                for (n = 0; n < channels; n++)
   2125 +                {
   2126 +                    int index = pixel_index + n;
   2127 +                    ((float*)output_buffer)[index] = encode_buffer[index];
   2128 +                }
   2129 +            }
   2130 +            break;
   2131 +
   2132 +        case STBIR__DECODE(STBIR_TYPE_FLOAT, STBIR_COLORSPACE_SRGB):
   2133 +            for (x=0; x < num_pixels; ++x)
   2134 +            {
   2135 +                int pixel_index = x*channels;
   2136 +
   2137 +                for (n = 0; n < num_nonalpha; n++)
   2138 +                {
   2139 +                    int index = pixel_index + nonalpha[n];
   2140 +                    ((float*)output_buffer)[index] = stbir__linear_to_srgb(encode_buffer[index]);
   2141 +                }
   2142 +
   2143 +                if (!(stbir_info->flags&STBIR_FLAG_ALPHA_USES_COLORSPACE))
   2144 +                    ((float*)output_buffer)[pixel_index + alpha_channel] = encode_buffer[pixel_index + alpha_channel];
   2145 +            }
   2146 +            break;
   2147 +
   2148 +        default:
   2149 +            STBIR_ASSERT(!"Unknown type/colorspace/channels combination.");
   2150 +            break;
   2151 +    }
   2152 +}
   2153 +
   2154 +static void stbir__resample_vertical_upsample(stbir__info* stbir_info, int n)
   2155 +{
   2156 +    int x, k;
   2157 +    int output_w = stbir_info->output_w;
   2158 +    stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
   2159 +    float* vertical_coefficients = stbir_info->vertical_coefficients;
   2160 +    int channels = stbir_info->channels;
   2161 +    int alpha_channel = stbir_info->alpha_channel;
   2162 +    int type = stbir_info->type;
   2163 +    int colorspace = stbir_info->colorspace;
   2164 +    int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
   2165 +    void* output_data = stbir_info->output_data;
   2166 +    float* encode_buffer = stbir_info->encode_buffer;
   2167 +    int decode = STBIR__DECODE(type, colorspace);
   2168 +    int coefficient_width = stbir_info->vertical_coefficient_width;
   2169 +    int coefficient_counter;
   2170 +    int contributor = n;
   2171 +
   2172 +    float* ring_buffer = stbir_info->ring_buffer;
   2173 +    int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
   2174 +    int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
   2175 +    int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
   2176 +
   2177 +    int n0,n1, output_row_start;
   2178 +    int coefficient_group = coefficient_width * contributor;
   2179 +
   2180 +    n0 = vertical_contributors[contributor].n0;
   2181 +    n1 = vertical_contributors[contributor].n1;
   2182 +
   2183 +    output_row_start = n * stbir_info->output_stride_bytes;
   2184 +
   2185 +    STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
   2186 +
   2187 +    memset(encode_buffer, 0, output_w * sizeof(float) * channels);
   2188 +
   2189 +    // I tried reblocking this for better cache usage of encode_buffer
   2190 +    // (using x_outer, k, x_inner), but it lost speed. -- stb
   2191 +
   2192 +    coefficient_counter = 0;
   2193 +    switch (channels) {
   2194 +        case 1:
   2195 +            for (k = n0; k <= n1; k++)
   2196 +            {
   2197 +                int coefficient_index = coefficient_counter++;
   2198 +                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);
   2199 +                float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
   2200 +                for (x = 0; x < output_w; ++x)
   2201 +                {
   2202 +                    int in_pixel_index = x * 1;
   2203 +                    encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
   2204 +                }
   2205 +            }
   2206 +            break;
   2207 +        case 2:
   2208 +            for (k = n0; k <= n1; k++)
   2209 +            {
   2210 +                int coefficient_index = coefficient_counter++;
   2211 +                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);
   2212 +                float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
   2213 +                for (x = 0; x < output_w; ++x)
   2214 +                {
   2215 +                    int in_pixel_index = x * 2;
   2216 +                    encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
   2217 +                    encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
   2218 +                }
   2219 +            }
   2220 +            break;
   2221 +        case 3:
   2222 +            for (k = n0; k <= n1; k++)
   2223 +            {
   2224 +                int coefficient_index = coefficient_counter++;
   2225 +                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);
   2226 +                float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
   2227 +                for (x = 0; x < output_w; ++x)
   2228 +                {
   2229 +                    int in_pixel_index = x * 3;
   2230 +                    encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
   2231 +                    encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
   2232 +                    encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
   2233 +                }
   2234 +            }
   2235 +            break;
   2236 +        case 4:
   2237 +            for (k = n0; k <= n1; k++)
   2238 +            {
   2239 +                int coefficient_index = coefficient_counter++;
   2240 +                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);
   2241 +                float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
   2242 +                for (x = 0; x < output_w; ++x)
   2243 +                {
   2244 +                    int in_pixel_index = x * 4;
   2245 +                    encode_buffer[in_pixel_index + 0] += ring_buffer_entry[in_pixel_index + 0] * coefficient;
   2246 +                    encode_buffer[in_pixel_index + 1] += ring_buffer_entry[in_pixel_index + 1] * coefficient;
   2247 +                    encode_buffer[in_pixel_index + 2] += ring_buffer_entry[in_pixel_index + 2] * coefficient;
   2248 +                    encode_buffer[in_pixel_index + 3] += ring_buffer_entry[in_pixel_index + 3] * coefficient;
   2249 +                }
   2250 +            }
   2251 +            break;
   2252 +        default:
   2253 +            for (k = n0; k <= n1; k++)
   2254 +            {
   2255 +                int coefficient_index = coefficient_counter++;
   2256 +                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);
   2257 +                float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
   2258 +                for (x = 0; x < output_w; ++x)
   2259 +                {
   2260 +                    int in_pixel_index = x * channels;
   2261 +                    int c;
   2262 +                    for (c = 0; c < channels; c++)
   2263 +                        encode_buffer[in_pixel_index + c] += ring_buffer_entry[in_pixel_index + c] * coefficient;
   2264 +                }
   2265 +            }
   2266 +            break;
   2267 +    }
   2268 +    stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, encode_buffer, channels, alpha_channel, decode);
   2269 +}
   2270 +
   2271 +static void stbir__resample_vertical_downsample(stbir__info* stbir_info, int n)
   2272 +{
   2273 +    int x, k;
   2274 +    int output_w = stbir_info->output_w;
   2275 +    stbir__contributors* vertical_contributors = stbir_info->vertical_contributors;
   2276 +    float* vertical_coefficients = stbir_info->vertical_coefficients;
   2277 +    int channels = stbir_info->channels;
   2278 +    int ring_buffer_entries = stbir_info->ring_buffer_num_entries;
   2279 +    float* horizontal_buffer = stbir_info->horizontal_buffer;
   2280 +    int coefficient_width = stbir_info->vertical_coefficient_width;
   2281 +    int contributor = n + stbir_info->vertical_filter_pixel_margin;
   2282 +
   2283 +    float* ring_buffer = stbir_info->ring_buffer;
   2284 +    int ring_buffer_begin_index = stbir_info->ring_buffer_begin_index;
   2285 +    int ring_buffer_first_scanline = stbir_info->ring_buffer_first_scanline;
   2286 +    int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
   2287 +    int n0,n1;
   2288 +
   2289 +    n0 = vertical_contributors[contributor].n0;
   2290 +    n1 = vertical_contributors[contributor].n1;
   2291 +
   2292 +    STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
   2293 +
   2294 +    for (k = n0; k <= n1; k++)
   2295 +    {
   2296 +        int coefficient_index = k - n0;
   2297 +        int coefficient_group = coefficient_width * contributor;
   2298 +        float coefficient = vertical_coefficients[coefficient_group + coefficient_index];
   2299 +
   2300 +        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);
   2301 +
   2302 +        switch (channels) {
   2303 +            case 1:
   2304 +                for (x = 0; x < output_w; x++)
   2305 +                {
   2306 +                    int in_pixel_index = x * 1;
   2307 +                    ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
   2308 +                }
   2309 +                break;
   2310 +            case 2:
   2311 +                for (x = 0; x < output_w; x++)
   2312 +                {
   2313 +                    int in_pixel_index = x * 2;
   2314 +                    ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
   2315 +                    ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
   2316 +                }
   2317 +                break;
   2318 +            case 3:
   2319 +                for (x = 0; x < output_w; x++)
   2320 +                {
   2321 +                    int in_pixel_index = x * 3;
   2322 +                    ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
   2323 +                    ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
   2324 +                    ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
   2325 +                }
   2326 +                break;
   2327 +            case 4:
   2328 +                for (x = 0; x < output_w; x++)
   2329 +                {
   2330 +                    int in_pixel_index = x * 4;
   2331 +                    ring_buffer_entry[in_pixel_index + 0] += horizontal_buffer[in_pixel_index + 0] * coefficient;
   2332 +                    ring_buffer_entry[in_pixel_index + 1] += horizontal_buffer[in_pixel_index + 1] * coefficient;
   2333 +                    ring_buffer_entry[in_pixel_index + 2] += horizontal_buffer[in_pixel_index + 2] * coefficient;
   2334 +                    ring_buffer_entry[in_pixel_index + 3] += horizontal_buffer[in_pixel_index + 3] * coefficient;
   2335 +                }
   2336 +                break;
   2337 +            default:
   2338 +                for (x = 0; x < output_w; x++)
   2339 +                {
   2340 +                    int in_pixel_index = x * channels;
   2341 +
   2342 +                    int c;
   2343 +                    for (c = 0; c < channels; c++)
   2344 +                        ring_buffer_entry[in_pixel_index + c] += horizontal_buffer[in_pixel_index + c] * coefficient;
   2345 +                }
   2346 +                break;
   2347 +        }
   2348 +    }
   2349 +}
   2350 +
   2351 +static void stbir__buffer_loop_upsample(stbir__info* stbir_info)
   2352 +{
   2353 +    int y;
   2354 +    float scale_ratio = stbir_info->vertical_scale;
   2355 +    float out_scanlines_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(1/scale_ratio) * scale_ratio;
   2356 +
   2357 +    STBIR_ASSERT(stbir__use_height_upsampling(stbir_info));
   2358 +
   2359 +    for (y = 0; y < stbir_info->output_h; y++)
   2360 +    {
   2361 +        float in_center_of_out = 0; // Center of the current out scanline in the in scanline space
   2362 +        int in_first_scanline = 0, in_last_scanline = 0;
   2363 +
   2364 +        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);
   2365 +
   2366 +        STBIR_ASSERT(in_last_scanline - in_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
   2367 +
   2368 +        if (stbir_info->ring_buffer_begin_index >= 0)
   2369 +        {
   2370 +            // Get rid of whatever we don't need anymore.
   2371 +            while (in_first_scanline > stbir_info->ring_buffer_first_scanline)
   2372 +            {
   2373 +                if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
   2374 +                {
   2375 +                    // We just popped the last scanline off the ring buffer.
   2376 +                    // Reset it to the empty state.
   2377 +                    stbir_info->ring_buffer_begin_index = -1;
   2378 +                    stbir_info->ring_buffer_first_scanline = 0;
   2379 +                    stbir_info->ring_buffer_last_scanline = 0;
   2380 +                    break;
   2381 +                }
   2382 +                else
   2383 +                {
   2384 +                    stbir_info->ring_buffer_first_scanline++;
   2385 +                    stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
   2386 +                }
   2387 +            }
   2388 +        }
   2389 +
   2390 +        // Load in new ones.
   2391 +        if (stbir_info->ring_buffer_begin_index < 0)
   2392 +            stbir__decode_and_resample_upsample(stbir_info, in_first_scanline);
   2393 +
   2394 +        while (in_last_scanline > stbir_info->ring_buffer_last_scanline)
   2395 +            stbir__decode_and_resample_upsample(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
   2396 +
   2397 +        // Now all buffers should be ready to write a row of vertical sampling.
   2398 +        stbir__resample_vertical_upsample(stbir_info, y);
   2399 +
   2400 +        STBIR_PROGRESS_REPORT((float)y / stbir_info->output_h);
   2401 +    }
   2402 +}
   2403 +
   2404 +static void stbir__empty_ring_buffer(stbir__info* stbir_info, int first_necessary_scanline)
   2405 +{
   2406 +    int output_stride_bytes = stbir_info->output_stride_bytes;
   2407 +    int channels = stbir_info->channels;
   2408 +    int alpha_channel = stbir_info->alpha_channel;
   2409 +    int type = stbir_info->type;
   2410 +    int colorspace = stbir_info->colorspace;
   2411 +    int output_w = stbir_info->output_w;
   2412 +    void* output_data = stbir_info->output_data;
   2413 +    int decode = STBIR__DECODE(type, colorspace);
   2414 +
   2415 +    float* ring_buffer = stbir_info->ring_buffer;
   2416 +    int ring_buffer_length = stbir_info->ring_buffer_length_bytes/sizeof(float);
   2417 +
   2418 +    if (stbir_info->ring_buffer_begin_index >= 0)
   2419 +    {
   2420 +        // Get rid of whatever we don't need anymore.
   2421 +        while (first_necessary_scanline > stbir_info->ring_buffer_first_scanline)
   2422 +        {
   2423 +            if (stbir_info->ring_buffer_first_scanline >= 0 && stbir_info->ring_buffer_first_scanline < stbir_info->output_h)
   2424 +            {
   2425 +                int output_row_start = stbir_info->ring_buffer_first_scanline * output_stride_bytes;
   2426 +                float* ring_buffer_entry = stbir__get_ring_buffer_entry(ring_buffer, stbir_info->ring_buffer_begin_index, ring_buffer_length);
   2427 +                stbir__encode_scanline(stbir_info, output_w, (char *) output_data + output_row_start, ring_buffer_entry, channels, alpha_channel, decode);
   2428 +                STBIR_PROGRESS_REPORT((float)stbir_info->ring_buffer_first_scanline / stbir_info->output_h);
   2429 +            }
   2430 +
   2431 +            if (stbir_info->ring_buffer_first_scanline == stbir_info->ring_buffer_last_scanline)
   2432 +            {
   2433 +                // We just popped the last scanline off the ring buffer.
   2434 +                // Reset it to the empty state.
   2435 +                stbir_info->ring_buffer_begin_index = -1;
   2436 +                stbir_info->ring_buffer_first_scanline = 0;
   2437 +                stbir_info->ring_buffer_last_scanline = 0;
   2438 +                break;
   2439 +            }
   2440 +            else
   2441 +            {
   2442 +                stbir_info->ring_buffer_first_scanline++;
   2443 +                stbir_info->ring_buffer_begin_index = (stbir_info->ring_buffer_begin_index + 1) % stbir_info->ring_buffer_num_entries;
   2444 +            }
   2445 +        }
   2446 +    }
   2447 +}
   2448 +
   2449 +static void stbir__buffer_loop_downsample(stbir__info* stbir_info)
   2450 +{
   2451 +    int y;
   2452 +    float scale_ratio = stbir_info->vertical_scale;
   2453 +    int output_h = stbir_info->output_h;
   2454 +    float in_pixels_radius = stbir__filter_info_table[stbir_info->vertical_filter].support(scale_ratio) / scale_ratio;
   2455 +    int pixel_margin = stbir_info->vertical_filter_pixel_margin;
   2456 +    int max_y = stbir_info->input_h + pixel_margin;
   2457 +
   2458 +    STBIR_ASSERT(!stbir__use_height_upsampling(stbir_info));
   2459 +
   2460 +    for (y = -pixel_margin; y < max_y; y++)
   2461 +    {
   2462 +        float out_center_of_in; // Center of the current out scanline in the in scanline space
   2463 +        int out_first_scanline, out_last_scanline;
   2464 +
   2465 +        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);
   2466 +
   2467 +        STBIR_ASSERT(out_last_scanline - out_first_scanline + 1 <= stbir_info->ring_buffer_num_entries);
   2468 +
   2469 +        if (out_last_scanline < 0 || out_first_scanline >= output_h)
   2470 +            continue;
   2471 +
   2472 +        stbir__empty_ring_buffer(stbir_info, out_first_scanline);
   2473 +
   2474 +        stbir__decode_and_resample_downsample(stbir_info, y);
   2475 +
   2476 +        // Load in new ones.
   2477 +        if (stbir_info->ring_buffer_begin_index < 0)
   2478 +            stbir__add_empty_ring_buffer_entry(stbir_info, out_first_scanline);
   2479 +
   2480 +        while (out_last_scanline > stbir_info->ring_buffer_last_scanline)
   2481 +            stbir__add_empty_ring_buffer_entry(stbir_info, stbir_info->ring_buffer_last_scanline + 1);
   2482 +
   2483 +        // Now the horizontal buffer is ready to write to all ring buffer rows.
   2484 +        stbir__resample_vertical_downsample(stbir_info, y);
   2485 +    }
   2486 +
   2487 +    stbir__empty_ring_buffer(stbir_info, stbir_info->output_h);
   2488 +}
   2489 +
   2490 +static void stbir__setup(stbir__info *info, int input_w, int input_h, int output_w, int output_h, int channels)
   2491 +{
   2492 +    info->input_w = input_w;
   2493 +    info->input_h = input_h;
   2494 +    info->output_w = output_w;
   2495 +    info->output_h = output_h;
   2496 +    info->channels = channels;
   2497 +}
   2498 +
   2499 +static void stbir__calculate_transform(stbir__info *info, float s0, float t0, float s1, float t1, float *transform)
   2500 +{
   2501 +    info->s0 = s0;
   2502 +    info->t0 = t0;
   2503 +    info->s1 = s1;
   2504 +    info->t1 = t1;
   2505 +
   2506 +    if (transform)
   2507 +    {
   2508 +        info->horizontal_scale = transform[0];
   2509 +        info->vertical_scale   = transform[1];
   2510 +        info->horizontal_shift = transform[2];
   2511 +        info->vertical_shift   = transform[3];
   2512 +    }
   2513 +    else
   2514 +    {
   2515 +        info->horizontal_scale = ((float)info->output_w / info->input_w) / (s1 - s0);
   2516 +        info->vertical_scale = ((float)info->output_h / info->input_h) / (t1 - t0);
   2517 +
   2518 +        info->horizontal_shift = s0 * info->output_w / (s1 - s0);
   2519 +        info->vertical_shift = t0 * info->output_h / (t1 - t0);
   2520 +    }
   2521 +}
   2522 +
   2523 +static void stbir__choose_filter(stbir__info *info, stbir_filter h_filter, stbir_filter v_filter)
   2524 +{
   2525 +    if (h_filter == 0)
   2526 +        h_filter = stbir__use_upsampling(info->horizontal_scale) ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
   2527 +    if (v_filter == 0)
   2528 +        v_filter = stbir__use_upsampling(info->vertical_scale)   ? STBIR_DEFAULT_FILTER_UPSAMPLE : STBIR_DEFAULT_FILTER_DOWNSAMPLE;
   2529 +    info->horizontal_filter = h_filter;
   2530 +    info->vertical_filter = v_filter;
   2531 +}
   2532 +
   2533 +static stbir_uint32 stbir__calculate_memory(stbir__info *info)
   2534 +{
   2535 +    int pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
   2536 +    int filter_height = stbir__get_filter_pixel_width(info->vertical_filter, info->vertical_scale);
   2537 +
   2538 +    info->horizontal_num_contributors = stbir__get_contributors(info->horizontal_scale, info->horizontal_filter, info->input_w, info->output_w);
   2539 +    info->vertical_num_contributors   = stbir__get_contributors(info->vertical_scale  , info->vertical_filter  , info->input_h, info->output_h);
   2540 +
   2541 +    // One extra entry because floating point precision problems sometimes cause an extra to be necessary.
   2542 +    info->ring_buffer_num_entries = filter_height + 1;
   2543 +
   2544 +    info->horizontal_contributors_size = info->horizontal_num_contributors * sizeof(stbir__contributors);
   2545 +    info->horizontal_coefficients_size = stbir__get_total_horizontal_coefficients(info) * sizeof(float);
   2546 +    info->vertical_contributors_size = info->vertical_num_contributors * sizeof(stbir__contributors);
   2547 +    info->vertical_coefficients_size = stbir__get_total_vertical_coefficients(info) * sizeof(float);
   2548 +    info->decode_buffer_size = (info->input_w + pixel_margin * 2) * info->channels * sizeof(float);
   2549 +    info->horizontal_buffer_size = info->output_w * info->channels * sizeof(float);
   2550 +    info->ring_buffer_size = info->output_w * info->channels * info->ring_buffer_num_entries * sizeof(float);
   2551 +    info->encode_buffer_size = info->output_w * info->channels * sizeof(float);
   2552 +
   2553 +    STBIR_ASSERT(info->horizontal_filter != 0);
   2554 +    STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
   2555 +    STBIR_ASSERT(info->vertical_filter != 0);
   2556 +    STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table)); // this now happens too late
   2557 +
   2558 +    if (stbir__use_height_upsampling(info))
   2559 +        // The horizontal buffer is for when we're downsampling the height and we
   2560 +        // can't output the result of sampling the decode buffer directly into the
   2561 +        // ring buffers.
   2562 +        info->horizontal_buffer_size = 0;
   2563 +    else
   2564 +        // The encode buffer is to retain precision in the height upsampling method
   2565 +        // and isn't used when height downsampling.
   2566 +        info->encode_buffer_size = 0;
   2567 +
   2568 +    return info->horizontal_contributors_size + info->horizontal_coefficients_size
   2569 +        + info->vertical_contributors_size + info->vertical_coefficients_size
   2570 +        + info->decode_buffer_size + info->horizontal_buffer_size
   2571 +        + info->ring_buffer_size + info->encode_buffer_size;
   2572 +}
   2573 +
   2574 +static int stbir__resize_allocated(stbir__info *info,
   2575 +    const void* input_data, int input_stride_in_bytes,
   2576 +    void* output_data, int output_stride_in_bytes,
   2577 +    int alpha_channel, stbir_uint32 flags, stbir_datatype type,
   2578 +    stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace,
   2579 +    void* tempmem, size_t tempmem_size_in_bytes)
   2580 +{
   2581 +    size_t memory_required = stbir__calculate_memory(info);
   2582 +
   2583 +    int width_stride_input = input_stride_in_bytes ? input_stride_in_bytes : info->channels * info->input_w * stbir__type_size[type];
   2584 +    int width_stride_output = output_stride_in_bytes ? output_stride_in_bytes : info->channels * info->output_w * stbir__type_size[type];
   2585 +
   2586 +#ifdef STBIR_DEBUG_OVERWRITE_TEST
   2587 +#define OVERWRITE_ARRAY_SIZE 8
   2588 +    unsigned char overwrite_output_before_pre[OVERWRITE_ARRAY_SIZE];
   2589 +    unsigned char overwrite_tempmem_before_pre[OVERWRITE_ARRAY_SIZE];
   2590 +    unsigned char overwrite_output_after_pre[OVERWRITE_ARRAY_SIZE];
   2591 +    unsigned char overwrite_tempmem_after_pre[OVERWRITE_ARRAY_SIZE];
   2592 +
   2593 +    size_t begin_forbidden = width_stride_output * (info->output_h - 1) + info->output_w * info->channels * stbir__type_size[type];
   2594 +    memcpy(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
   2595 +    memcpy(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE);
   2596 +    memcpy(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE);
   2597 +    memcpy(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE);
   2598 +#endif
   2599 +
   2600 +    STBIR_ASSERT(info->channels >= 0);
   2601 +    STBIR_ASSERT(info->channels <= STBIR_MAX_CHANNELS);
   2602 +
   2603 +    if (info->channels < 0 || info->channels > STBIR_MAX_CHANNELS)
   2604 +        return 0;
   2605 +
   2606 +    STBIR_ASSERT(info->horizontal_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
   2607 +    STBIR_ASSERT(info->vertical_filter < STBIR__ARRAY_SIZE(stbir__filter_info_table));
   2608 +
   2609 +    if (info->horizontal_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
   2610 +        return 0;
   2611 +    if (info->vertical_filter >= STBIR__ARRAY_SIZE(stbir__filter_info_table))
   2612 +        return 0;
   2613 +
   2614 +    if (alpha_channel < 0)
   2615 +        flags |= STBIR_FLAG_ALPHA_USES_COLORSPACE | STBIR_FLAG_ALPHA_PREMULTIPLIED;
   2616 +
   2617 +    if (!(flags&STBIR_FLAG_ALPHA_USES_COLORSPACE) || !(flags&STBIR_FLAG_ALPHA_PREMULTIPLIED)) {
   2618 +        STBIR_ASSERT(alpha_channel >= 0 && alpha_channel < info->channels);
   2619 +    }
   2620 +
   2621 +    if (alpha_channel >= info->channels)
   2622 +        return 0;
   2623 +
   2624 +    STBIR_ASSERT(tempmem);
   2625 +
   2626 +    if (!tempmem)
   2627 +        return 0;
   2628 +
   2629 +    STBIR_ASSERT(tempmem_size_in_bytes >= memory_required);
   2630 +
   2631 +    if (tempmem_size_in_bytes < memory_required)
   2632 +        return 0;
   2633 +
   2634 +    memset(tempmem, 0, tempmem_size_in_bytes);
   2635 +
   2636 +    info->input_data = input_data;
   2637 +    info->input_stride_bytes = width_stride_input;
   2638 +
   2639 +    info->output_data = output_data;
   2640 +    info->output_stride_bytes = width_stride_output;
   2641 +
   2642 +    info->alpha_channel = alpha_channel;
   2643 +    info->flags = flags;
   2644 +    info->type = type;
   2645 +    info->edge_horizontal = edge_horizontal;
   2646 +    info->edge_vertical = edge_vertical;
   2647 +    info->colorspace = colorspace;
   2648 +
   2649 +    info->horizontal_coefficient_width   = stbir__get_coefficient_width  (info->horizontal_filter, info->horizontal_scale);
   2650 +    info->vertical_coefficient_width     = stbir__get_coefficient_width  (info->vertical_filter  , info->vertical_scale  );
   2651 +    info->horizontal_filter_pixel_width  = stbir__get_filter_pixel_width (info->horizontal_filter, info->horizontal_scale);
   2652 +    info->vertical_filter_pixel_width    = stbir__get_filter_pixel_width (info->vertical_filter  , info->vertical_scale  );
   2653 +    info->horizontal_filter_pixel_margin = stbir__get_filter_pixel_margin(info->horizontal_filter, info->horizontal_scale);
   2654 +    info->vertical_filter_pixel_margin   = stbir__get_filter_pixel_margin(info->vertical_filter  , info->vertical_scale  );
   2655 +
   2656 +    info->ring_buffer_length_bytes = info->output_w * info->channels * sizeof(float);
   2657 +    info->decode_buffer_pixels = info->input_w + info->horizontal_filter_pixel_margin * 2;
   2658 +
   2659 +#define STBIR__NEXT_MEMPTR(current, newtype) (newtype*)(((unsigned char*)current) + current##_size)
   2660 +
   2661 +    info->horizontal_contributors = (stbir__contributors *) tempmem;
   2662 +    info->horizontal_coefficients = STBIR__NEXT_MEMPTR(info->horizontal_contributors, float);
   2663 +    info->vertical_contributors = STBIR__NEXT_MEMPTR(info->horizontal_coefficients, stbir__contributors);
   2664 +    info->vertical_coefficients = STBIR__NEXT_MEMPTR(info->vertical_contributors, float);
   2665 +    info->decode_buffer = STBIR__NEXT_MEMPTR(info->vertical_coefficients, float);
   2666 +
   2667 +    if (stbir__use_height_upsampling(info))
   2668 +    {
   2669 +        info->horizontal_buffer = NULL;
   2670 +        info->ring_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
   2671 +        info->encode_buffer = STBIR__NEXT_MEMPTR(info->ring_buffer, float);
   2672 +
   2673 +        STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->encode_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
   2674 +    }
   2675 +    else
   2676 +    {
   2677 +        info->horizontal_buffer = STBIR__NEXT_MEMPTR(info->decode_buffer, float);
   2678 +        info->ring_buffer = STBIR__NEXT_MEMPTR(info->horizontal_buffer, float);
   2679 +        info->encode_buffer = NULL;
   2680 +
   2681 +        STBIR_ASSERT((size_t)STBIR__NEXT_MEMPTR(info->ring_buffer, unsigned char) == (size_t)tempmem + tempmem_size_in_bytes);
   2682 +    }
   2683 +
   2684 +#undef STBIR__NEXT_MEMPTR
   2685 +
   2686 +    // This signals that the ring buffer is empty
   2687 +    info->ring_buffer_begin_index = -1;
   2688 +
   2689 +    stbir__calculate_filters(info->horizontal_contributors, info->horizontal_coefficients, info->horizontal_filter, info->horizontal_scale, info->horizontal_shift, info->input_w, info->output_w);
   2690 +    stbir__calculate_filters(info->vertical_contributors, info->vertical_coefficients, info->vertical_filter, info->vertical_scale, info->vertical_shift, info->input_h, info->output_h);
   2691 +
   2692 +    STBIR_PROGRESS_REPORT(0);
   2693 +
   2694 +    if (stbir__use_height_upsampling(info))
   2695 +        stbir__buffer_loop_upsample(info);
   2696 +    else
   2697 +        stbir__buffer_loop_downsample(info);
   2698 +
   2699 +    STBIR_PROGRESS_REPORT(1);
   2700 +
   2701 +#ifdef STBIR_DEBUG_OVERWRITE_TEST
   2702 +    STBIR_ASSERT(memcmp(overwrite_output_before_pre, &((unsigned char*)output_data)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
   2703 +    STBIR_ASSERT(memcmp(overwrite_output_after_pre, &((unsigned char*)output_data)[begin_forbidden], OVERWRITE_ARRAY_SIZE) == 0);
   2704 +    STBIR_ASSERT(memcmp(overwrite_tempmem_before_pre, &((unsigned char*)tempmem)[-OVERWRITE_ARRAY_SIZE], OVERWRITE_ARRAY_SIZE) == 0);
   2705 +    STBIR_ASSERT(memcmp(overwrite_tempmem_after_pre, &((unsigned char*)tempmem)[tempmem_size_in_bytes], OVERWRITE_ARRAY_SIZE) == 0);
   2706 +#endif
   2707 +
   2708 +    return 1;
   2709 +}
   2710 +
   2711 +
   2712 +static int stbir__resize_arbitrary(
   2713 +    void *alloc_context,
   2714 +    const void* input_data, int input_w, int input_h, int input_stride_in_bytes,
   2715 +    void* output_data, int output_w, int output_h, int output_stride_in_bytes,
   2716 +    float s0, float t0, float s1, float t1, float *transform,
   2717 +    int channels, int alpha_channel, stbir_uint32 flags, stbir_datatype type,
   2718 +    stbir_filter h_filter, stbir_filter v_filter,
   2719 +    stbir_edge edge_horizontal, stbir_edge edge_vertical, stbir_colorspace colorspace)
   2720 +{
   2721 +    stbir__info info;
   2722 +    int result;
   2723 +    size_t memory_required;
   2724 +    void* extra_memory;
   2725 +
   2726 +    stbir__setup(&info, input_w, input_h, output_w, output_h, channels);
   2727 +    stbir__calculate_transform(&info, s0,t0,s1,t1,transform);
   2728 +    stbir__choose_filter(&info, h_filter, v_filter);
   2729 +    memory_required = stbir__calculate_memory(&info);
   2730 +    extra_memory = STBIR_MALLOC(memory_required, alloc_context);
   2731 +
   2732 +    if (!extra_memory)
   2733 +        return 0;
   2734 +
   2735 +    result = stbir__resize_allocated(&info, input_data, input_stride_in_bytes,
   2736 +                                            output_data, output_stride_in_bytes,
   2737 +                                            alpha_channel, flags, type,
   2738 +                                            edge_horizontal, edge_vertical,
   2739 +                                            colorspace, extra_memory, memory_required);
   2740 +
   2741 +    STBIR_FREE(extra_memory, alloc_context);
   2742 +
   2743 +    return result;
   2744 +}
   2745 +
   2746 +STBIRDEF int stbir_resize_uint8(     const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2747 +                                           unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2748 +                                     int num_channels)
   2749 +{
   2750 +    return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
   2751 +        output_pixels, output_w, output_h, output_stride_in_bytes,
   2752 +        0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
   2753 +        STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
   2754 +}
   2755 +
   2756 +STBIRDEF int stbir_resize_float(     const float *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2757 +                                           float *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2758 +                                     int num_channels)
   2759 +{
   2760 +    return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
   2761 +        output_pixels, output_w, output_h, output_stride_in_bytes,
   2762 +        0,0,1,1,NULL,num_channels,-1,0, STBIR_TYPE_FLOAT, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
   2763 +        STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_LINEAR);
   2764 +}
   2765 +
   2766 +STBIRDEF int stbir_resize_uint8_srgb(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2767 +                                           unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2768 +                                     int num_channels, int alpha_channel, int flags)
   2769 +{
   2770 +    return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
   2771 +        output_pixels, output_w, output_h, output_stride_in_bytes,
   2772 +        0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
   2773 +        STBIR_EDGE_CLAMP, STBIR_EDGE_CLAMP, STBIR_COLORSPACE_SRGB);
   2774 +}
   2775 +
   2776 +STBIRDEF int stbir_resize_uint8_srgb_edgemode(const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2777 +                                                    unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2778 +                                              int num_channels, int alpha_channel, int flags,
   2779 +                                              stbir_edge edge_wrap_mode)
   2780 +{
   2781 +    return stbir__resize_arbitrary(NULL, input_pixels, input_w, input_h, input_stride_in_bytes,
   2782 +        output_pixels, output_w, output_h, output_stride_in_bytes,
   2783 +        0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, STBIR_FILTER_DEFAULT, STBIR_FILTER_DEFAULT,
   2784 +        edge_wrap_mode, edge_wrap_mode, STBIR_COLORSPACE_SRGB);
   2785 +}
   2786 +
   2787 +STBIRDEF int stbir_resize_uint8_generic( const unsigned char *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2788 +                                               unsigned char *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2789 +                                         int num_channels, int alpha_channel, int flags,
   2790 +                                         stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
   2791 +                                         void *alloc_context)
   2792 +{
   2793 +    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
   2794 +        output_pixels, output_w, output_h, output_stride_in_bytes,
   2795 +        0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT8, filter, filter,
   2796 +        edge_wrap_mode, edge_wrap_mode, space);
   2797 +}
   2798 +
   2799 +STBIRDEF int stbir_resize_uint16_generic(const stbir_uint16 *input_pixels  , int input_w , int input_h , int input_stride_in_bytes,
   2800 +                                               stbir_uint16 *output_pixels , int output_w, int output_h, int output_stride_in_bytes,
   2801 +                                         int num_channels, int alpha_channel, int flags,
   2802 +                                         stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
   2803 +                                         void *alloc_context)
   2804 +{
   2805 +    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
   2806 +        output_pixels, output_w, output_h, output_stride_in_bytes,
   2807 +        0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_UINT16, filter, filter,
   2808 +        edge_wrap_mode, edge_wrap_mode, space);
   2809 +}
   2810 +
   2811 +
   2812 +STBIRDEF int stbir_resize_float_generic( const float *input_pixels         , int input_w , int input_h , int input_stride_in_bytes,
   2813 +                                               float *output_pixels        , int output_w, int output_h, int output_stride_in_bytes,
   2814 +                                         int num_channels, int alpha_channel, int flags,
   2815 +                                         stbir_edge edge_wrap_mode, stbir_filter filter, stbir_colorspace space,
   2816 +                                         void *alloc_context)
   2817 +{
   2818 +    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
   2819 +        output_pixels, output_w, output_h, output_stride_in_bytes,
   2820 +        0,0,1,1,NULL,num_channels,alpha_channel,flags, STBIR_TYPE_FLOAT, filter, filter,
   2821 +        edge_wrap_mode, edge_wrap_mode, space);
   2822 +}
   2823 +
   2824 +
   2825 +STBIRDEF int stbir_resize(         const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2826 +                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2827 +                                   stbir_datatype datatype,
   2828 +                                   int num_channels, int alpha_channel, int flags,
   2829 +                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
   2830 +                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
   2831 +                                   stbir_colorspace space, void *alloc_context)
   2832 +{
   2833 +    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
   2834 +        output_pixels, output_w, output_h, output_stride_in_bytes,
   2835 +        0,0,1,1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
   2836 +        edge_mode_horizontal, edge_mode_vertical, space);
   2837 +}
   2838 +
   2839 +
   2840 +STBIRDEF int stbir_resize_subpixel(const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2841 +                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2842 +                                   stbir_datatype datatype,
   2843 +                                   int num_channels, int alpha_channel, int flags,
   2844 +                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
   2845 +                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
   2846 +                                   stbir_colorspace space, void *alloc_context,
   2847 +                                   float x_scale, float y_scale,
   2848 +                                   float x_offset, float y_offset)
   2849 +{
   2850 +    float transform[4];
   2851 +    transform[0] = x_scale;
   2852 +    transform[1] = y_scale;
   2853 +    transform[2] = x_offset;
   2854 +    transform[3] = y_offset;
   2855 +    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
   2856 +        output_pixels, output_w, output_h, output_stride_in_bytes,
   2857 +        0,0,1,1,transform,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
   2858 +        edge_mode_horizontal, edge_mode_vertical, space);
   2859 +}
   2860 +
   2861 +STBIRDEF int stbir_resize_region(  const void *input_pixels , int input_w , int input_h , int input_stride_in_bytes,
   2862 +                                         void *output_pixels, int output_w, int output_h, int output_stride_in_bytes,
   2863 +                                   stbir_datatype datatype,
   2864 +                                   int num_channels, int alpha_channel, int flags,
   2865 +                                   stbir_edge edge_mode_horizontal, stbir_edge edge_mode_vertical,
   2866 +                                   stbir_filter filter_horizontal,  stbir_filter filter_vertical,
   2867 +                                   stbir_colorspace space, void *alloc_context,
   2868 +                                   float s0, float t0, float s1, float t1)
   2869 +{
   2870 +    return stbir__resize_arbitrary(alloc_context, input_pixels, input_w, input_h, input_stride_in_bytes,
   2871 +        output_pixels, output_w, output_h, output_stride_in_bytes,
   2872 +        s0,t0,s1,t1,NULL,num_channels,alpha_channel,flags, datatype, filter_horizontal, filter_vertical,
   2873 +        edge_mode_horizontal, edge_mode_vertical, space);
   2874 +}
   2875 +
   2876 +#endif // STB_IMAGE_RESIZE_IMPLEMENTATION
   2877 +
   2878 +/*
   2879 +------------------------------------------------------------------------------
   2880 +This software is available under 2 licenses -- choose whichever you prefer.
   2881 +------------------------------------------------------------------------------
   2882 +ALTERNATIVE A - MIT License
   2883 +Copyright (c) 2017 Sean Barrett
   2884 +Permission is hereby granted, free of charge, to any person obtaining a copy of
   2885 +this software and associated documentation files (the "Software"), to deal in
   2886 +the Software without restriction, including without limitation the rights to
   2887 +use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
   2888 +of the Software, and to permit persons to whom the Software is furnished to do
   2889 +so, subject to the following conditions:
   2890 +The above copyright notice and this permission notice shall be included in all
   2891 +copies or substantial portions of the Software.
   2892 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   2893 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   2894 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   2895 +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   2896 +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   2897 +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
   2898 +SOFTWARE.
   2899 +------------------------------------------------------------------------------
   2900 +ALTERNATIVE B - Public Domain (www.unlicense.org)
   2901 +This is free and unencumbered software released into the public domain.
   2902 +Anyone is free to copy, modify, publish, use, compile, sell, or distribute this
   2903 +software, either in source code form or as a compiled binary, for any purpose,
   2904 +commercial or non-commercial, and by any means.
   2905 +In jurisdictions that recognize copyright laws, the author or authors of this
   2906 +software dedicate any and all copyright interest in the software to the public
   2907 +domain. We make this dedication for the benefit of the public at large and to
   2908 +the detriment of our heirs and successors. We intend this dedication to be an
   2909 +overt act of relinquishment in perpetuity of all present and future rights to
   2910 +this software under copyright law.
   2911 +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   2912 +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   2913 +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   2914 +AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
   2915 +ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
   2916 +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
   2917 +------------------------------------------------------------------------------
   2918 +*/