Downloads containing Resize v11.asc

Downloads
Name Author Game Mode Rating
Jazz 1 Enemies Violet CLM Other N/A Download file
TrueColor and Resize Violet CLM Other N/A Download file

File preview

  1. //Resize v11.asc: version 1.1 (2019/05/04)
  2. #pragma require "Resize v11.asc"
  3. #include "TrueColor v13.asc"
  4.  
  5. /*
  6. Resize v11.asc lets scriptwriters resize any image, animframe, animation, or animset by any positive multipliers, choosing from a number of different algorithms to see what looks best on any given image (sequence), unlike JJ2+'s normal jjDrawResizedSprite function which only uses nearest neighbor resizing.
  7.  
  8. SAMPLE SCRIPT:
  9.         void onLevelLoad() {
  10.                 Resize::Resize(jjAnimSets[ANIM::RAVEN], 3, 3.0, Resize::Method::Scale2xSAI);
  11.         }
  12.  
  13.        
  14. API:
  15.         jjPIXELMAP@ Resize::Resize(const jjPIXELMAP &in input, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f)
  16.                 Takes an existing jjPIXELMAP object and returns a new one. The returned jjPIXELMAP's width will be equal to scaleX * input.width and its height scaleY * input.height, and the image will be resized accordingly. If scaleY is left at its default value, it will be set to the same value as scaleX instead, meaning the aspect ratio will stay constant. The effects of negative scale values are undefined.
  17.                
  18.                 For the method argument, you are encouraged to pass a member of the Resize::Method enum. There are two categories of these:
  19.                         Algorithms which do not introduce new colors: NearestNeighbor, Scale2x, AdvMAME2x, Eagle
  20.                         Algorithms which blend adjacent colors and thereby introduce new colors: BilinearInterpolation, Regular2xSAI, Scale2xSAI
  21.                 For more information about how these different algorithms differ you are referred to the internet.
  22.                
  23.                 There are also two values in the Resize::Flags enum you may find useful for the method argument. These should be bitwise-OR'd together, e.g. "Resize::Method::Scale2x | Resize::Flags::EdgesRepeat".
  24.                         EdgesRepeat: Toggles whether the resizing algorithms should consider the image to repeat indefinitely outside the boundaries of the pixelmap, or to be surrounded by transparent pixels.
  25.                         OnlySpriteColors: Has an effect only for the algorithms that introduce new colors, restricting them to colors found in the standard sprite palette. You should use this flag if you anticipate calling jjPAL::apply after resizing any sprites.
  26.                        
  27.                        
  28.         TrueColor::Bitmap@ Resize(const TrueColor::Bitmap &in input, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f)
  29.                 Same as the above function, but instead of jjPIXELMAP objects, it works on Bitmap objects from the TrueColor library. The Resize::Flags::OnlySpriteColors flag is ignored when working with TrueColor images, because it would be meaningless.
  30.                        
  31.                        
  32.         void Resize::Resize(jjANIMFRAME & frame, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f)
  33.                 Resizes the image used by a jjANIMFRAME, and also multiplies that frame's hotspot, gunspot, and coldspot properties by the scale arguments. Note that unlike the above two functions, which return new objects, this one modifies the jjANIMFRAME in place.
  34.        
  35.        
  36.         void Resize::Resize(const jjANIMATION & anim, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f)
  37.         void Resize::Resize(jjANIMSET & set, uint animCount, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f)
  38.                 Convenience functions for resizing multiple jjANIMFRAMEs at once while keeping the method and scale values constant. Note that the latter function requires you to state explicitly how many animations are used by the jjANIMSET (e.g. 2 for ANIM::FISH), because JJ2 does not store that number anywhere.
  39.                
  40.                
  41.         void Resize::AllocateAndResizeTrueColorSpriteSheet(const ANIM::Set setID, const TrueColor::Bitmap& bitmap, const array<array<TrueColor::Coordinates>>& setCoordinates, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f)
  42.                 Works the same (and has roughly the same signature) as TrueColor::AllocateSpriteSheet, but resizes each image (in accordance with scaleX/scaleY/method) from the sprite sheet before saving it. The coordinates in the setCoordinates array should refer to the coordinates within the image BEFORE they are resized.
  43.                        
  44. WARNING: All internal code details are subject to change, and any properties, methods, or functions NOT described above should not be used by external scripts for risk of failing to work in later updates to this library.
  45.  
  46. */
  47.  
  48.  
  49.  
  50.  
  51.  
  52.  
  53.  
  54.  
  55.  
  56.  
  57.  
  58.  
  59.  
  60.  
  61.  
  62.  
  63.  
  64.  
  65.  
  66.  
  67.  
  68.  
  69.  
  70.  
  71.  
  72.  
  73.  
  74.  
  75.  
  76.  
  77. namespace Resize {
  78.         enum Method {
  79.                 NearestNeighbor, Scale2x, AdvMAME2x, Eagle, _firstInvolvingFindNearestColor, BilinearInterpolation, Regular2xSAI, Scale2xSAI, Super2xSAI, SuperEagle, HQ2x, xBR, //some of these don't work
  80.                 //http://supercomputingblog.com/graphics/coding-bilinear-interpolation/
  81.                 //http://www.scale2x.it/algorithm
  82.                 //https://github.com/Treeki/libxbr-standalone
  83.                 //https://vdnoort.home.xs4all.nl/emulation/2xsai
  84.                 //https://en.wikipedia.org/wiki/Pixel-art_scaling_algorithms
  85.         };
  86.         enum Flags {
  87.                 None = 0, _firstFlag = 1<<5, OnlySpriteColors = _firstFlag, EdgesRepeat = 1<<6
  88.         };
  89.         bool _edgesRepeat;
  90.        
  91.         class _Color {
  92.                 uint8 index = 0;
  93.                 TrueColor::AlphaColor color;
  94.                 bool isPaletted = true;
  95.                 _Color(uint8 i) { index = i; color = jjPalette.color[i]; }
  96.                 _Color(const TrueColor::AlphaColor &in c) { color = c; isPaletted = false; }
  97.                 bool opEquals(const _Color &in other) const {
  98.                         if (!isPaletted) return color == other.color;
  99.                         return index == other.index;
  100.                 }
  101.         }
  102.        
  103.         class _Image {
  104.                 jjPIXELMAP@ pixelmap = null;
  105.                 TrueColor::Bitmap@ bitmap = null;
  106.                 uint width, height;
  107.                 _Image(const jjPIXELMAP &in pm) {
  108.                         @pixelmap = jjPIXELMAP(width = pm.width, height = pm.height);
  109.                         for (int x = width - 1; x >= 0; --x)
  110.                                 for (int y = height - 1; y >= 0; --y)
  111.                                         pixelmap[x,y] = pm[x,y]; //no native copy constructor available
  112.                 }
  113.                 _Image(const TrueColor::Bitmap &in bm) {
  114.                         @bitmap = TrueColor::Bitmap(bm, 0, 0, width = bm.width, height = bm.height); //copy constructor
  115.                 }
  116.                 _Image(const _Image &in i, uint w, uint h) {
  117.                         width = w; height = h;
  118.                         if (i.bitmap is null)
  119.                                 @pixelmap = jjPIXELMAP(w, h);
  120.                         else
  121.                                 @bitmap = TrueColor::Bitmap(w, h, i.bitmap.usesAlphaChannel);
  122.                 }
  123.                
  124.                 _Color@ Get(int x, int y) const {
  125.                         if (!_edgesRepeat) {
  126.                                 if (x < 0 ||
  127.                                 y < 0 ||
  128.                                 uint(x) >= width ||
  129.                                 uint(y) >= height)
  130.                                         return (bitmap is null) ? _Color(0) : _Color(TrueColor::AlphaColor());
  131.                         } else {
  132.                                 if (x < 0) x = 0;
  133.                                 else if (uint(x) >= width) x = width - 1;
  134.                                 if (y < 0) y = 0;
  135.                                 else if (uint(y) >= height) y = height - 1;
  136.                         }
  137.                        
  138.                         return (bitmap is null) ? _Color(pixelmap[x,y]) : _Color(bitmap.pixels[x][y]);
  139.                 }
  140.                 void Set(int x, int y, const _Color &in color) {
  141.                         if (x < 0 ||
  142.                         y < 0 ||
  143.                         uint(x) >= width ||
  144.                         uint(y) >= height)
  145.                                 return;
  146.                        
  147.                         if (bitmap is null) {
  148.                                 if (color.isPaletted)
  149.                                         pixelmap[x,y] = color.index;
  150.                                 else {
  151.                                         const uint8 index = _palette.findNearestColor(color.color);
  152.                                         const TrueColor::AlphaColor foundColor = _palette.color[index];
  153.                                         if (foundColor.red == 0 && foundColor.green == 0 && foundColor.blue == 0) pixelmap[x,y] = 0; //black = transparent
  154.                                         else pixelmap[x,y] = index;
  155.                                 }
  156.                         } else
  157.                                 bitmap.pixels[x][y] = color.color;
  158.                 }
  159.                 void Set(int x, int y, const TrueColor::AlphaColor &in color) {
  160.                         this.Set(x, y, _Color(color));
  161.                 }
  162.         }
  163.        
  164.         jjPAL _palette;
  165.        
  166.         _Image@ Resize(_Image@ input, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f) {
  167.                 scaleX = abs(scaleX); //undefined?
  168.                 if (scaleY == 0.f) scaleY = scaleX;
  169.                 else scaleY = abs(scaleY);
  170.                                
  171.                 if (scaleX == 1.f && scaleY == 1.f)
  172.                         return @input;
  173.                
  174.                 const auto width = uint(input.width * scaleX), height = uint(input.height * scaleY);
  175.                
  176.                 _palette = jjPalette;
  177.                 const uint flags = method & ~(Flags::_firstFlag - 1);
  178.                 method ^= flags;
  179.                 if ((flags & Flags::OnlySpriteColors) != 0 && input.bitmap is null && method >= _firstInvolvingFindNearestColor) {
  180.                         TrueColor::AlphaColor black;
  181.                         _palette.fill(black, 0, 15); //start
  182.                         _palette.fill(black, 56, 3); //yellow gap
  183.                         _palette.fill(black, 96, 159); //remainder + finish
  184.                 }
  185.                 _edgesRepeat = (flags & Flags::EdgesRepeat) != 0;
  186.                        
  187.                 //non-doubling-based algorithms which work at any size
  188.                 if (method == Method::BilinearInterpolation)
  189.                         return _bilinearInterpolation(input, width,height);
  190.                 if (method == Method::Scale2xSAI)
  191.                         return _scale_2xSaI(input, width,height);
  192.                
  193.                 if ((scaleX > 1.f || scaleY > 1.f) && method != Method::NearestNeighbor) {
  194.                         float progressiveScale = scaleX;
  195.                         if (scaleY > progressiveScale) progressiveScale = scaleY; //max of two
  196.                         while (progressiveScale > 1.f) {
  197.                                 @input = @_double(input, method);
  198.                                 progressiveScale /= 2;
  199.                         }
  200.                         if (progressiveScale == 1.f && scaleX == scaleY)
  201.                                 return @input;
  202.                 }
  203.                
  204.                 return _nearestNeighbor(input, width,height);  //default, or simply last step in case of downscaling (after upscaling or otherwise)
  205.         }
  206.         jjPIXELMAP@ Resize(const jjPIXELMAP &in input, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f) {
  207.                 return Resize(_Image(input), scaleX, method, scaleY).pixelmap;
  208.         }
  209.         TrueColor::Bitmap@ Resize(const TrueColor::Bitmap &in input, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f) {
  210.                 return Resize(_Image(input), scaleX, method, scaleY).bitmap;
  211.         }
  212.        
  213.         void Resize(jjANIMFRAME & frame, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f) {
  214.                 if (scaleY == 0.f) scaleY = scaleX;
  215.                 else scaleY = abs(scaleY);
  216.                 const uint oldWidth = frame.width;
  217.                 const uint oldHeight = frame.height;
  218.                 Resize(jjPIXELMAP(frame), scaleX, method, scaleY).save(frame);
  219.                 frame.hotSpotX = int(frame.hotSpotX * scaleX);
  220.                 frame.hotSpotY = int(frame.hotSpotY * scaleY);
  221.                 frame.gunSpotX = int(frame.gunSpotX * scaleX);
  222.                 frame.gunSpotY = int(frame.gunSpotY * scaleY);
  223.                 frame.coldSpotX = int(frame.coldSpotX * scaleX); //not that this accomplishes anything
  224.                 frame.coldSpotY = int(frame.coldSpotY * scaleY);
  225.         }
  226.        
  227.         void Resize(const jjANIMATION & anim, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f) {
  228.                 const uint numFrames = anim.frameCount;
  229.                 for (uint i = 0; i < numFrames; ++i)
  230.                         Resize(jjAnimFrames[anim + i], scaleX, method, scaleY);
  231.         }
  232.         void Resize(jjANIMSET & set, uint animCount, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f) {
  233.                 if (set == 0)
  234.                         set.load();
  235.                 for (uint i = 0; i < animCount; ++i)
  236.                         Resize(jjAnimations[set + i], scaleX, method, scaleY);
  237.         }
  238.        
  239.         _Image@ _double(const _Image &in input, uint method) {
  240.                 switch (method) {
  241.                         case Method::Scale2x:
  242.                                 return _scale2x(input);
  243.                         case Method::AdvMAME2x:
  244.                                 return _advMAME2x(input);
  245.                         case Method::Eagle:
  246.                                 return _eagle(input);
  247.                         case Method::Regular2xSAI:
  248.                                 return _2xSAI(input);
  249.                         /*case Method::xBR:
  250.                                 return _xBR(input);
  251.                         case Method::HQ2x:
  252.                                 return _HQ2x(input);
  253.                         case Method::Super2xSAI:
  254.                                 return _super2xSAI(input);
  255.                         case Method::SuperEagle:
  256.                                 return _superEagle(input);*/
  257.                 }
  258.                 //default: not yet implemented, etc.
  259.                 return _nearestNeighbor(input, input.width*2, input.height*2);
  260.         }
  261.        
  262.        
  263.        
  264.         void AllocateAndResizeTrueColorSpriteSheet(const ANIM::Set setID, const TrueColor::Bitmap& bitmap, const array<array<TrueColor::Coordinates>>& setCoordinates, float scaleX, uint method = Resize::Method::NearestNeighbor, float scaleY = 0.f) {
  265.                 if (scaleX == 1.f && scaleY == 1.f) {
  266.                         TrueColor::AllocateSpriteSheet(setID, bitmap, setCoordinates);
  267.                         return;
  268.                 }
  269.                 scaleX = abs(scaleX); //undefined?
  270.                 if (scaleY == 0.f) scaleY = scaleX;
  271.                 else scaleY = abs(scaleY);
  272.                
  273.                 array<uint> animSizes(setCoordinates.length);
  274.                 for (uint i = 0; i < animSizes.length; ++i) {
  275.                         animSizes[i] = setCoordinates[i].length * TrueColor::NumberOfFramesPerImage;
  276.                 }
  277.                 jjAnimSets[setID].allocate(animSizes);
  278.                 for (uint animID = 0; animID < animSizes.length; ++animID) {
  279.                         const array<TrueColor::Coordinates>@ animCoordinates = @setCoordinates[animID];
  280.                         for (uint frameID = 0; frameID < animCoordinates.length; ++frameID) {
  281.                                 const TrueColor::Coordinates@ coordinates = animCoordinates[frameID];
  282.                                 const TrueColor::Bitmap@ sprite = TrueColor::Bitmap(bitmap, coordinates.left, coordinates.top, coordinates.width, coordinates.height);
  283.                                 @sprite = Resize::Resize(sprite, scaleX, method, scaleY);
  284.                                 sprite.saveToAnimFrames(
  285.                                         jjAnimations[jjAnimSets[setID].firstAnim + animID].firstFrame + frameID * TrueColor::NumberOfFramesPerImage,
  286.                                         TrueColor::Coordinates(
  287.                                                 0, 0,
  288.                                                 sprite.width, sprite.height,
  289.                                                 int(coordinates.hotSpotX * scaleX), int(coordinates.hotSpotY * scaleY),
  290.                                                 int(coordinates.gunSpotX * scaleX), int(coordinates.gunSpotY * scaleY),
  291.                                                 int(coordinates.coldSpotX * scaleX), int(coordinates.coldSpotY * scaleY),
  292.                                                 coordinates.transparent,
  293.                                                 coordinates.swingingVine
  294.                                         )
  295.                                 );
  296.                         }
  297.                 }
  298.         }
  299.        
  300.        
  301.        
  302.         _Image@ _nearestNeighbor(const _Image &in input, uint width, uint height) {
  303.                 _Image output(input, width, height);
  304.                 for (int x = width - 1; x >= 0; --x)
  305.                         for (int y = height - 1; y >= 0; --y)
  306.                                 output.Set(x, y, input.Get(x * input.width / width, y * input.height / height));
  307.                 return output;
  308.         }
  309.        
  310.         _Image@ _bilinearInterpolation(const _Image &in input, uint width, uint height) {
  311.                 _Image output(input, width, height);
  312.                 for (int x = width - 1; x >= 0; --x) {
  313.                         const float
  314.                                 xx = float(x) * input.width / width,
  315.                                 x1 = floor(xx),
  316.                                 x2 = x1+1,
  317.                                 RX = (x2 - xx);
  318.                         for (int y = height - 1; y >= 0; --y) {
  319.                                 const float
  320.                                         yy = float(y) * input.height / height,
  321.                                         y1 = floor(yy),
  322.                                         y2 = y1+1,
  323.                                         RY = (y2 - yy);
  324.                                 const TrueColor::AlphaColor
  325.                                         TopLeft = input.Get(int(x1), int(y1)).color,
  326.                                         TopRight = input.Get(int(x2), int(y1)).color,
  327.                                         BottomLeft = input.Get(int(x1), int(y2)).color,
  328.                                         BottomRight = input.Get(int(x2), int(y2)).color;
  329.                                        
  330.                                 output.Set(x,y, _blendColors(_blendColors(TopLeft,TopRight,RX), _blendColors(BottomLeft,BottomRight,RX), RY));
  331.                         }
  332.                 }
  333.                 return output;
  334.         }
  335.        
  336.         _Image@ _scale2x(const _Image &in input) {
  337.                 _Image output(input, input.width * 2, input.height * 2);
  338.                 for (int x = output.width - 2, xx = x>>1; x >= 0; x -= 2, --xx)
  339.                         for (int y = output.height - 2, yy = y>>1; y >= 0; y -= 2, --yy) {
  340.                                 const _Color@
  341.                                         B = input.Get(xx, yy-1),
  342.                                         D = input.Get(xx-1, yy),
  343.                                         E = input.Get(xx,yy),
  344.                                         F = input.Get(xx+1, yy),
  345.                                         H = input.Get(xx, yy+1);
  346.                                 if (B != H && D != F) {
  347.                                         const _Color@ result; //needs to be a separate variable to fix an angelscript bug
  348.                                         @result = (D == B) ? D : E; output.Set(x,y, result);
  349.                                         @result = (B == F) ? F : E; output.Set(x+1,y, result);
  350.                                         @result = (D == H) ? D : E; output.Set(x,y+1, result);
  351.                                         @result = (H == F) ? F : E; output.Set(x+1,y+1, result);
  352.                                 } else {
  353.                                         output.Set(x,y, E);
  354.                                         output.Set(x+1,y, E);
  355.                                         output.Set(x,y+1, E);
  356.                                         output.Set(x+1,y+1, E);
  357.                                 }
  358.                         }
  359.                 return output;
  360.         }
  361.        
  362.         _Image@ _advMAME2x(const _Image &in input) {
  363.                 _Image output(input, input.width * 2, input.height * 2);
  364.                 for (int x = output.width - 2, xx = x>>1; x >= 0; x -= 2, --xx)
  365.                         for (int y = output.height - 2, yy = y>>1; y >= 0; y -= 2, --yy) {
  366.                                 const _Color@
  367.                                         A = input.Get(xx, yy-1),
  368.                                         C = input.Get(xx-1, yy),
  369.                                         P = input.Get(xx,yy),
  370.                                         B = input.Get(xx+1, yy),
  371.                                         D = input.Get(xx, yy+1);
  372.                                 const _Color@ result; //needs to be a separate variable to fix an angelscript bug
  373.                                 @result = (C==A && C!=D && A!=B) ? A : P; output.Set(x,y, result);
  374.                                 @result = (A==B && A!=C && B!=D) ? B : P; output.Set(x+1,y, result);
  375.                                 @result = (D==C && D!=B && C!=A) ? C : P; output.Set(x,y+1, result);
  376.                                 @result = (B==D && B!=A && D!=C) ? D : P; output.Set(x+1,y+1, result);
  377.                         }
  378.                 return output;
  379.         }
  380.        
  381.         _Image@ _eagle(const _Image &in input) {
  382.                 _Image output(input, input.width * 2, input.height * 2);
  383.                 for (int x = output.width - 2, xx = x>>1; x >= 0; x -= 2, --xx)
  384.                         for (int y = output.height - 2, yy = y>>1; y >= 0; y -= 2, --yy) {
  385.                                 const _Color@
  386.                                         S = input.Get(xx-1, yy-1),
  387.                                         T = input.Get(xx, yy-1),
  388.                                         U = input.Get(xx+1, yy-1),
  389.                                         V = input.Get(xx-1, yy),
  390.                                         C = input.Get(xx,yy),
  391.                                         W = input.Get(xx+1, yy),
  392.                                         X = input.Get(xx-1, yy+1),
  393.                                         Y = input.Get(xx, yy+1),
  394.                                         Z = input.Get(xx+1, yy+1);
  395.                                 const _Color@ result; //needs to be a separate variable to fix an angelscript bug
  396.                                 @result = (V==S&&S==T) ? S : C; output.Set(x,y, result);
  397.                                 @result = (T==U&&U==W) ? U : C; output.Set(x+1,y, result);
  398.                                 @result = (V==X&&X==Y) ? X : C; output.Set(x,y+1, result);
  399.                                 @result = (W==Z&&Z==Y) ? Z : C; output.Set(x+1,y+1, result);
  400.                         }
  401.                 return output;
  402.         }
  403.        
  404.         TrueColor::AlphaColor _blendColors(const TrueColor::AlphaColor &in a, const TrueColor::AlphaColor &in b, const float balance = 0.5f) {
  405.                 if (a == b)
  406.                         return a;
  407.                 if (balance == 0.5f) {
  408.                         return TrueColor::AlphaColor(
  409.                                 (uint(a.red) + uint(b.red)) >> 1,
  410.                                 (uint(a.green) + uint(b.green)) >> 1,
  411.                                 (uint(a.blue) + uint(b.blue)) >> 1,
  412.                                 (uint(a.alpha) + uint(b.alpha)) >> 1
  413.                         );
  414.                 } else {
  415.                         const float opposite = 1.f - balance;
  416.                         return TrueColor::AlphaColor(
  417.                                 uint8(balance * a.red + opposite * b.red),
  418.                                 uint8(balance * a.green + opposite * b.green),
  419.                                 uint8(balance * a.blue + opposite * b.blue),
  420.                                 uint8(balance * a.alpha + opposite * b.alpha)
  421.                         );
  422.                 }
  423.         }
  424.  
  425.         int _saiGetResult1(const TrueColor::AlphaColor &in A, const TrueColor::AlphaColor &in B, const TrueColor::AlphaColor &in C, const TrueColor::AlphaColor &in D, const TrueColor::AlphaColor &in E)
  426.         {
  427.                 int x = 0;
  428.                 int y = 0;
  429.                 int r = 0;
  430.                 if (A == C) x+=1; else if (B == C) y+=1;
  431.                 if (A == D) x+=1; else if (B == D) y+=1;
  432.                 if (x <= 1) r+=1;
  433.                 if (y <= 1) r-=1;
  434.                 return r;
  435.         }
  436.  
  437.         int _saiGetResult2(const TrueColor::AlphaColor &in A, const TrueColor::AlphaColor &in B, const TrueColor::AlphaColor &in C, const TrueColor::AlphaColor &in D, const TrueColor::AlphaColor &in E)
  438.         {
  439.                 int x = 0;
  440.                 int y = 0;
  441.                 int r = 0;
  442.                 if (A == C) x+=1; else if (B == C) y+=1;
  443.                 if (A == D) x+=1; else if (B == D) y+=1;
  444.                 if (x <= 1) r-=1;
  445.                 if (y <= 1) r+=1;
  446.                 return r;
  447.         }
  448.  
  449.  
  450.         int _saiGetResult(const TrueColor::AlphaColor &in A, const TrueColor::AlphaColor &in B, const TrueColor::AlphaColor &in C, const TrueColor::AlphaColor &in D)
  451.         {
  452.                 int x = 0;
  453.                 int y = 0;
  454.                 int r = 0;
  455.                 if (A == C) x+=1; else if (B == C) y+=1;
  456.                 if (A == D) x+=1; else if (B == D) y+=1;
  457.                 if (x <= 1) r+=1;
  458.                 if (y <= 1) r-=1;
  459.                 return r;
  460.         }
  461.        
  462.         _Image@ _2xSAI(const _Image &in input) {
  463.                 const _Color black(0);
  464.                 _Image@ output = _nearestNeighbor(input, input.width*2, input.height*2);
  465.                 for (int x = output.width - 2, xx = x>>1; x >= 0; x -= 2, --xx)
  466.                         for (int y = output.height - 2, yy = y>>1; y >= 0; y -= 2, --yy) {
  467.                                 //---------------------------------------
  468. // Map of the pixels:                    I|E F|J
  469. //                                       G|A B|K
  470. //                                       H|C D|L
  471. //                                       M|N O|P
  472.                                 const TrueColor::AlphaColor
  473.                                         I = input.Get(xx-1, yy-1).color,
  474.                                         E = input.Get(xx+0, yy-1).color,
  475.                                         F = input.Get(xx+1, yy-1).color,
  476.                                         J = input.Get(xx+2, yy-1).color,
  477.                                         G = input.Get(xx-1, yy+0).color,
  478.                                         A = input.Get(xx+0, yy+0).color,
  479.                                         B = input.Get(xx+1, yy+0).color,
  480.                                         K = input.Get(xx+2, yy+0).color,
  481.                                         H = input.Get(xx-1, yy+1).color,
  482.                                         C = input.Get(xx+0, yy+1).color,
  483.                                         D = input.Get(xx+1, yy+1).color,
  484.                                         L = input.Get(xx+2, yy+1).color,
  485.                                         M = input.Get(xx-1, yy+2).color,
  486.                                         N = input.Get(xx+0, yy+2).color,
  487.                                         O = input.Get(xx+1, yy+2).color,
  488.                                         P = input.Get(xx+2, yy+2).color;
  489.                                 TrueColor::AlphaColor product, product1, product2;
  490.                                
  491.                                 if ((A == D) && (B != C)) {
  492.                                    if ( ((A == E) && (B == L)) ||
  493.                                                 ((A == C) && (A == F) && (B != E) && (B == J)) )
  494.                                           product = A;
  495.                                    else
  496.                                           product = _blendColors(A, B);
  497.  
  498.                                    if (((A == G) && (C == O)) ||
  499.                                            ((A == B) && (A == H) && (G != C) && (C == M)) )
  500.                                           product1 = A;
  501.                                    else
  502.                                           product1 = _blendColors(A, C);
  503.                                    product2 = A;
  504.                                 } else if ((B == C) && (A != D)) {
  505.                                    if (((B == F) && (A == H)) ||
  506.                                            ((B == E) && (B == D) && (A != F) && (A == I)) )
  507.                                           product = B;
  508.                                    else
  509.                                           product = _blendColors(A, B);
  510.  
  511.                                    if (((C == H) && (A == F)) ||
  512.                                            ((C == G) && (C == D) && (A != H) && (A == I)) )
  513.                                           product1 = C;
  514.                                    else
  515.                                           product1 = _blendColors(A, C);
  516.                                    product2 = B;
  517.                                 } else if ((A == D) && (B == C)) {
  518.                                    if (A == B)
  519.                                    {
  520.                                           product = A;
  521.                                           product1 = A;
  522.                                           product2 = A;
  523.                                    } else {
  524.                                           int r = 0;
  525.                                           product1 = _blendColors(A, C);
  526.                                           product = _blendColors(A, B);
  527.  
  528.                                           r += _saiGetResult1(A, B, G, E, I);
  529.                                           r += _saiGetResult2(B, A, K, F, J);
  530.                                           r += _saiGetResult2(B, A, H, N, M);
  531.                                           r += _saiGetResult1(A, B, L, O, P);
  532.  
  533.                                           if (r > 0)
  534.                                                   product2 = A;
  535.                                           else if (r < 0)
  536.                                                   product2 = B;
  537.                                           else
  538.                                                   product2 = _blendColors(_blendColors(A, B), _blendColors(C, D));
  539.                                    }
  540.                                 } else {
  541.                                    product2 = _blendColors(_blendColors(A, B), _blendColors(C, D));
  542.  
  543.                                    if ((A == C) && (A == F) && (B != E) && (B == J))
  544.                                           product = A;
  545.                                    else
  546.                                    if ((B == E) && (B == D) && (A != F) && (A == I))
  547.                                           product = B;
  548.                                    else
  549.                                           product = _blendColors(A, B);
  550.  
  551.                                    if ((A == B) && (A == H) && (G != C) && (C == M))
  552.                                           product1 = A;
  553.                                    else
  554.                                    if ((C == G) && (C == D) && (A != H) && (A == I))
  555.                                           product1 = C;
  556.                                    else
  557.                                           product1 = _blendColors(A, C);
  558.                                 }
  559.                                        
  560.                                 output.Set(x,y, A);
  561.                                 output.Set(x+1,y, product);
  562.                                 output.Set(x,y+1, product1);
  563.                                 output.Set(x+1,y+1, product2);
  564.                         }
  565.                 return output;
  566.         }
  567.        
  568.         _Image@ _scale_2xSaI(const _Image &in input, uint width, uint height) {
  569.                 _Image output(input, width, height);
  570.                 for (int x = width - 1; x >= 0; --x) {
  571.                         const float
  572.                                 xx = float(x) * input.width / width,
  573.                                 RX = 1 - (floor(xx) + 1 - xx);
  574.                         for (int y = height - 1; y >= 0; --y) {
  575.                                 const float
  576.                                         yy = float(y) * input.height / height,
  577.                                         RY = 1 - (floor(yy) + 1 - yy);
  578.                                 const TrueColor::AlphaColor
  579.                                         A = input.Get(int(xx + 0), int(yy + 0)).color,
  580.                                         B = input.Get(int(xx + 1), int(yy + 0)).color,
  581.                                         C = input.Get(int(xx + 0), int(yy + 1)).color,
  582.                                         D = input.Get(int(xx + 1), int(yy + 1)).color,
  583.                                         E = input.Get(int(xx + 0), int(yy - 1)).color,
  584.                                         F = input.Get(int(xx + 1), int(yy - 1)).color,
  585.                                         G = input.Get(int(xx - 1), int(yy + 0)).color,
  586.                                         H = input.Get(int(xx - 1), int(yy + 1)).color,
  587.                                         I = input.Get(int(xx + 2), int(yy + 0)).color,
  588.                                         J = input.Get(int(xx + 2), int(yy + 1)).color,
  589.                                         K = input.Get(int(xx + 0), int(yy + 2)).color,
  590.                                         L = input.Get(int(xx + 1), int(yy + 2)).color;
  591.                                
  592.                                 TrueColor::AlphaColor result;
  593. /*0*/                   if (A == B && C == D && A == C)
  594.                                         result = A;
  595.                                 else {
  596.                                         const float
  597.                                                 FX = (RX / 2) + 0.25f,
  598.                                                 FY = (RY / 2) + 0.25f;
  599. /*1*/                           if (A == D && B != C) {
  600.                                                 if (RY <= FX && A == J && A != E) // close to B
  601.                                                         result = _blendColors(B, A, FX - RY);
  602.                                                 else if (RY >= FX && A == G && A != L) // close to C
  603.                                                         result = _blendColors(C, A, RY - FX);
  604.                                                 else if (RX >= FY && A == E && A != J) // close to
  605.                                                         result = _blendColors(B, A, RX - FY);
  606.                                                 else if (RX <= FY && A == L && A != G) // close to C
  607.                                                         result = _blendColors(C, A, FY - RX);
  608.                                                 else if (RY >= RX) // close to C
  609.                                                         result = _blendColors(C, A, RY - RX);
  610.                                                 else //if (RY <= RX) // close to B
  611.                                                         result = _blendColors(B, A, RX - RY);
  612. /*2*/                           } else if (B == C && A != D) {
  613.                                                 const float
  614.                                                         RXO = (1.f - RX),
  615.                                                         RYO = (1.f - RY);
  616.                                                 if (RYO >= FX && B == H && B != F) // close to A
  617.                                                         result = _blendColors(A, B, RYO - FX);
  618.                                                 else if (RYO <= FX && B == I && B != K) // close to D
  619.                                                         result = _blendColors(D, B, FX - RYO);
  620.                                                 else if (RXO >= FY && B == F && B != H) // close to A
  621.                                                         result = _blendColors(A, B, RXO - FY);
  622.                                                 else if (RXO <= FY && B == K && B != I) // close to D
  623.                                                         result = _blendColors(D, B, FY - RXO);
  624.                                                 else if (RYO >= RX) // close to A
  625.                                                         result = _blendColors(A, B, RYO - RX);
  626.                                                 else //if (RYO <= RX) // close to D
  627.                                                         result = _blendColors(D, B, RX - RYO);
  628. /*3*/                           } else
  629.                                                 result = _blendColors(_blendColors(D, C, RX), _blendColors(B, A, RX), RY); //just use basic bilinear interpolation
  630.                                 }
  631.                                 output.Set(x,y, result);
  632.                         }
  633.                 }
  634.                 return output;
  635.         }
  636. }