unit Utils;

{***********************************************************

Project:    C-evo External Map Generator
Copyright:  1999-2023 P Blackman
License:    GPLv3+

General subroutines that don't belong anywhere else

***********************************************************}


interface


// Returns a value dependent on X, ranging from A to B,
//  scaled to be bewteen 0 and 1
function JumpStep(A, B, X: Double): Double;

// fast Bias & gain functions
//  scaled to work on input byte values with a percentage control
function Bias(TB, A: Integer): Integer;
function Gain(TB, A: Integer): Integer;

// Round to an integer with a probability of rounding up or down
//  that is dependent on how near the value is to the upper or lower bound
function BlendRound(X: Double): Integer;

// Round small numbers up, others down, so 0.1 etc shows as non zero
function MyRound(S: Double): Integer;

// Combine gain & bias
function GainBias(val, G, B: Integer): Integer;


implementation


function MyRound(S: Double): Integer;
begin
    if (S < 1) AND (S > 0.00001) then
        // Round very small values up to 1
        Result := 1
    else
    if S > 3 then
        Result := Trunc(S)
    else
        Result := Round(S);
end;

function BlendRound(X: Double): Integer;
var Base: Integer;
    Test: Double;
begin
    // Offset so 0 is a full band
    if X > 3.5 then
        Result := 3
    else
    begin
        X    := X - 0.5;
        Base := Trunc(X);
        Test := 0.5; //Random;

        if frac(X) > test then
            Inc(base);

        Result := base;
    end;
end;

function JumpStep(A, B, X: Double): Double;
begin
    if X < A then
        Result := 0
    else
    if X >= B then
        Result := 1
    else
        Result := (X - A) / (B - A);
end;

function Bias(TB, A: Integer): Integer;
var T: Double;
begin
    if A <= 0 then
        Result := 0
    else
    if A >= 100 then
        Result := High(Byte)
    else
    begin
        T      := TB / High(Byte);
        Result := Round(High(Byte) * T / ((100 / A - 2) * (1 - T) + 1));
    end;
end;

function Gain(TB, A: Integer): Integer;
var T: Double;
begin
    T := TB / High(Byte);
    A := 100 - A; // Function seems to invert expected results

    if A >= 100 then
        Result := High(Byte) DIV 2 // 50%
    else
    if T < 0.5 then
        if A <= 0 then
            Result := 0
        else
            Result := Round(High(Byte) * T / ((100 / A - 2) * (1 - 2 * T) + 1))
    else
    if A <= 0 then
        Result := High(Byte)
    else
        Result := Round(High(Byte) *
            ((100 / A - 2) * (1 - 2 * T) - T) / ((100 / A - 2) * (1 - 2 * T) - 1));
end;

function GainBias(val, G, B: Integer): Integer;
var temp1,
    temp2,
    Temp3: Integer;
begin
    temp1  := val;
    temp2  := Utils.Gain(temp1, G);
    temp3  := Utils.Bias(temp2, B);
    Result := temp3;
end;

end.
