{
    PixelGraphicNearNeighbour реализует алгоритм масштабирования растровой
    графики «ближайший сосед».

    Copyright © 2016–2017, 2019–2022 Малик Разработчик

    Это свободная программа: вы можете перераспространять её и/или
    изменять её на условиях Стандартной общественной лицензии GNU в том виде,
    в каком она была опубликована Фондом свободного программного обеспечения;
    либо версии 3 лицензии, либо (по вашему выбору) любой более поздней версии.

    Эта программа распространяется в надежде, что она может быть полезна,
    но БЕЗО ВСЯКИХ ГАРАНТИЙ; даже без неявной гарантии ТОВАРНОГО ВИДА
    или ПРИГОДНОСТИ ДЛЯ ОПРЕДЕЛЁННЫХ ЦЕЛЕЙ. Подробнее см. в Стандартной
    общественной лицензии GNU.

    Вы должны были получить копию Стандартной общественной лицензии GNU
    вместе с этой программой. Если это не так, см.
    <http://www.gnu.org/licenses/>.
}

unit PixelGraphicNearNeighbour;

{$MODE DELPHI}

interface

uses
    Lang,
    PixelGraphicScaling;

{%region public }
type
    Algorithm = class(RefCountInterfacedObject, PixelGraphicScalingAlgorithm)
    private
        inp: PIntArray;
        width: int;
        height: int;
        inScanline: int;
        procedure scale(zoom: int; outp: PIntArray; outScanline: int; turned: boolean);
    public
        constructor create();
        procedure setSource(pixels: PIntArray; width, height, scanline: int);
        procedure scale2x(destination: PIntArray; scanline: int; turned: boolean);
        procedure scale3x(destination: PIntArray; scanline: int; turned: boolean);
        procedure scale4x(destination: PIntArray; scanline: int; turned: boolean);
        function getSourceWidth(): int;
        function getSourceHeight(): int;
    end;
{%endregion}

implementation

{%region Algorithm }
    constructor Algorithm.create();
    begin
        inherited create();
    end;

    procedure Algorithm.scale(zoom: int; outp: PIntArray; outScanline: int; turned: boolean);
    var
        inp: PIntArray;
        width: int;
        height: int;
        inScanline: int;
        inCurrLine: int;
        inIndex: int;
        outCurrLine: int;
        outIndex: int;
        i: int;
        j: int;
        k1: int;
        k2: int;
    begin
        inp := self.inp;
        width := self.width;
        height := self.height;
        inScanline := self.inScanline;
        inCurrLine := 0;
        outCurrLine := 0;
        if turned then begin
            outCurrLine := outScanline * (height * zoom - 1);
            outScanline := -outScanline;
        end;
        for j := 0 to height - 1 do begin
            for k1 := 0 to zoom - 1 do begin
                inIndex := inCurrLine;
                outIndex := outCurrLine;
                for i := 0 to width - 1 do begin
                    for k2 := 0 to zoom - 1 do begin
                        outp[outIndex] := inp[inIndex];
                        inc(outIndex);
                    end;
                    inc(inIndex);
                end;
                inc(outCurrLine, outScanline);
            end;
            inc(inCurrLine, inScanline);
        end;
    end;

    procedure Algorithm.setSource(pixels: PIntArray; width, height, scanline: int);
    begin
        self.inp := pixels;
        self.width := width;
        self.height := height;
        self.inScanline := scanline;
    end;

    procedure Algorithm.scale2x(destination: PIntArray; scanline: int; turned: boolean);
    begin
        scale(2, destination, scanline, turned);
    end;

    procedure Algorithm.scale3x(destination: PIntArray; scanline: int; turned: boolean);
    begin
        scale(3, destination, scanline, turned);
    end;

    procedure Algorithm.scale4x(destination: PIntArray; scanline: int; turned: boolean);
    begin
        scale(4, destination, scanline, turned);
    end;

    function Algorithm.getSourceWidth(): int;
    begin
        result := width;
    end;

    function Algorithm.getSourceHeight(): int;
    begin
        result := height;
    end;
{%endregion}

end.

