---
--- Generated by EmmyLua(https://github.com/EmmyLua)
--- Created by HUAFEI2.
--- DateTime: 2020/6/28 14:59
---

------------------------------------------------------------------------------------------
---KVEC2
------------------------------------------------------------------------------------------

---@class LVec2
LVec2 = LVec2 or class("LVec2");

function LVec2:ctor(x, y)
    self.x = x or 0;
    self.y = y or 0;
end

---@param x number
---@param y number
---@return LVec2
function LVec2:Set(x, y)
    self.x = x;
    self.y = y;
    return self;
end

---@param scalar number
---@return LVec2
function LVec2:SetScalar(scalar)
    self.x = scalar;
    self.y = scalar;
    return self;
end

---@param x number
---@return LVec2
function LVec2:SetX(x)
    self.x = x;
    return self;
end

---@param y number
---@return LVec2
function LVec2:SetY(y)
    self.y = y;
    return self;
end

---@param val LVec2| number
---@return LVec2
function LVec2:Add(val)
    Vec2Add(self, self, val);
    return self;
end

---@param val LVec2 | number
---@return LVec2
function LVec2:Minus(val)
    Vec2Minus(self, self, val);
    return self;
end

---@param val LVec2 | number
---@return LVec2
function LVec2:Multiply(val)
    Vec2Multiply(self, self, val);
    return self;
end

---@param val LVec2 | number
---@return LVec2
function LVec2:Divide(val)
    Vec2Divide(self, self, val)
    return self;
end

---@return LVec2
function LVec2:Negate()
    Vec2Negate(self, self);
    return self;
end

---@param vec LVec2
---@return LVec2
function LVec2:Dot(vec)
    return self.x * vec.x + self.y * vec.y;
end

---@return number
function LVec2:LenSqr()
    return self.x * self.x + self.y * self.y;
end

---@return number
function LVec2:Length()
    return math.sqrt(self.x * self.x + self.y * self.y);
end

---@return number
function LVec2:DistanceTo(vec)
    return math.sqrt(self.distanceToSquared(vec));
end

---@return number
function LVec2:DistanceToSquared(vec)
    local dx = self.x - vec.x;
    local dy = self.y - vec.y;
    return dx * dx + dy * dy;
end

---@return LVec2
function LVec2:Normalize()
    local temp =  self.x * self.x + self.y * self.y ;
    local fMagnitude = math.sqrt(temp);
    if fMagnitude ~= 0.0 then
        fMagnitude = 1.0 / fMagnitude;
        self.x = self.x * fMagnitude;
        self.y = self.y * fMagnitude;
    end
    return self;
end

---@param vec LVec2
---@return LVec2
function LVec2:CopyFrom(vec)
    self.x = vec.x;
    self.y = vec.y;
    return self;
end

---@return LVec2
function LVec2:Clone()
    return LVec2:new(self.x, self.y);
end

---@param vec LVec2
---@return boolean
function LVec2:Equals(vec)
    return (vec.x == self.x) and (vec.y == self.y);
end

---@param array KArray
---@param offset number
---@return LVec2
function LVec2:FromArray(array, offset)
    offset = offset or 0;
    self.x = array.Get(offset);
    self.y = array.Get(offset + 1);
    return self;
end

---@param array KArray
---@param offset number
---@return LVec2
function LVec2:ToArray(array, offset)
    offset = offset or 0;
    array.Set(offset, self.x);
    array.Set(offset + 1, self.y);
    return self;
end

---@param x number
---@param y number
---@return boolean
function LVec2:AlmostEqual(x, y)
    if math.abs(self.x - x) < 0.01 and math.abs(self.y - y) < 0.01 then
        return true;
    end
    return false;
end

---@return KArray
function LVec2:GetData()
    local dataArray = KArray:new();
    self.ToArray(dataArray, 0);
    return dataArray;
end

------------------------------------------------------------------------------------------
---KVEC3
------------------------------------------------------------------------------------------

---@class LVec3
LVec3 = LVec3 or class("LVec3");

function LVec3:ctor(x, y, z)
    self.x = x or 0;
    self.y = y or 0;
    self.z = z or 0;
end

---@param x number
---@param y number
---@param z number
---@return LVec3
function LVec3:Set(x, y, z)
    self.x = x;
    self.y = y;
    self.z = z;
    return self;
end

---@param scalar number
---@return LVec3
function LVec3:SetScalar(scalar)
    self.x = scalar;
    self.y = scalar;
    self.z = scalar;
    return self;
end

---@param x number
---@return LVec3
function LVec3:SetX(x)
    self.x = x;
    return self;
end

---@param y number
---@return LVec3
function LVec3:SetY(y)
    self.y = y;
    return self;
end

---@param z number
---@return LVec3
function LVec3:SetZ(z)
    self.z = z;
    return self;
end

---@param val LVec3 | number
---@return LVec3
function LVec3:Add(val)
    Vec3Add(self, self, val);
    return self;
end

---@param val LVec3 | number
---@return LVec3
function LVec3:Minus(val)
    Vec3Minus(self, self, val);
    return self;
end

---@param val LVec3 | number
---@return LVec3
function LVec3:Multiply(val)
    Vec3Multiply(self, self, val)
    return self;
end

---@param val LVec3 | number
---@return LVec3
function LVec3:Divide(val)
    Vec3Divide(self, self, val);
    return self;
end

---@return LVec3
function LVec3:Negate()
    Vec3Negate(self, self);
    return self;
end

---@param vec LVec3
---@return LVec3
function LVec3:Dot(vec)
    return self.x * vec.x + self.y * vec.y + self.z * vec.z;
end

---@return number
function LVec3:LenSqr()
    return self.x * self.x + self.y * self.y + self.z * self.z;
end

---@return number
function LVec3:Length()
    return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z);
end

---@return number
function LVec3:DistanceTo(vec)
    return math.sqrt(self.distanceToSquared(vec));
end

---@return number
function LVec3:DistanceToSquared(vec)
    local dx = self.x - vec.x;
    local dy = self.y - vec.y;
    local dz = self.z - vec.z;
    return dx * dx + dy * dy + dz * dz;
end

---@return LVec3
function LVec3:Normalize()
    local temp = self.x * self.x + self.y * self.y + self.z * self.z;
    local fMagnitude = math.sqrt(temp);
    if fMagnitude ~= 0.0 then
        fMagnitude = 1.0 / fMagnitude;
        self.x = self.x * fMagnitude;
        self.y = self.y * fMagnitude;
        self.z = self.z * fMagnitude;
    end
    return self;
end

---@param fromVec LVec3
---@return LVec3
function LVec3:CopyFrom(fromVec)
    self.x = fromVec.x;
    self.y = fromVec.y;
    self.z = fromVec.z;
    return self;
end

---@return LVec3
function LVec3:Clone()
    return LVec3:new(self.x, self.y, self.z);
end

---@param vec LVec3
---@return boolean
function LVec3:Equals(vec)
    return (vec.x == self.x) and (vec.y == self.y) and (vec.z == self.z);
end

---@param array KArray
---@param offset number
---@return LVec3
function LVec3:FromArray(array, offset)
    offset = offset or 0;
    self.x = array.Get(offset);
    self.y = array.Get(offset + 1);
    self.z = array.Get(offset + 2);
    return self;
end

---@param array KArray
---@param offset number
---@return LVec3
function LVec3:ToArray(array, offset)
    offset = offset or 0;
    array.Set(offset, self.x);
    array.Set(offset + 1, self.y);
    array.Set(offset + 2, self.z);
    return self;
end

---@param x number
---@param y number
---@param z number
---@return boolean
function LVec3:AlmostEqual(x, y, z)
    if (math.abs(self.x - x) < 0.01 and math.abs(self.y - y) < 0.01 and math.abs(self.z - z) < 0.01) then
        return true;
    end
    return false;
end

---@return KArray
function LVec3:GetData()
    local dataArray = KArray:new();
    self.toArray(dataArray, 0);
    return dataArray;
end

------------------------------------------------------------------------------------------
---KVEC4
------------------------------------------------------------------------------------------

---@class LVec4
LVec4 = LVec4 or class("LVec4");

function LVec4:ctor(x, y, z, w)
    self.x = x or 0;
    self.y = y or 0;
    self.y = z or 0;
    self.w = w or 0;
end

---@param x number
---@param y number
---@param z number
---@param w number
---@return LVec4
function LVec4:Set(x, y, z, w)
    self.x = x;
    self.y = y;
    self.z = z;
    self.w = w;
    return self;
end

---@param scalar number
---@return LVec4
function LVec4:SetScalar(scalar)
    self.x = scalar;
    self.y = scalar;
    self.z = scalar;
    self.w = scalar;
    return self;
end

---@param x number
---@return LVec4
function LVec4:SetX(x)
    self.x = x;
    return self;
end

---@param y number
---@return LVec4
function LVec4:SetY(y)
    self.y = y;
    return self;
end

---@param z number
---@return LVec4
function LVec4:SetZ(z)
    self.z = z;
    return self;
end

---@param w number
---@return LVec4
function LVec4:SetW(w)
    self.z = w;
    return self;
end

---@param val LVec4 | number
---@return LVec4
function LVec4:Add(val)
    Vec4Add(self, self, val);
    return self;
end

---@param val LVec4 | number
---@return LVec4
function LVec4:Minus(val)
    Vec4Minus(self, self, val);
    return self;
end

---@param val LVec4 | number
---@return LVec4
function LVec4:Multiply(val)
    Vec4Multiply(self, self, val);
    return self;
end

---@param val LVec4 | number
---@return LVec4
function LVec4:Divide(val)
    Vec4Divide(self, self, val);
    return self;
end

---@return LVec4
function LVec4:Negate()
    Vec4Negate(self, self);
    return self;
end

---@param vec LVec4
---@return LVec4
function LVec4:Dot(vec)
    return self.x * vec.x + self.y * vec.y + self.z * vec.z + self.w * vec.w;
end

---@return number
function LVec4:LenSqr()
    return self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w;
end

---@return number
function LVec4:Length()
    return math.sqrt(self.x * self.x + self.y * self.y + self.z * self.z + self.w * self.w);
end

---@return number
function LVec4:DistanceTo(vec)
    return math.sqrt(self.distanceToSquared(vec));
end

---@return number
function LVec4:DistanceToSquared(vec)
    local dx = self.x - vec.x;
    local dy = self.y - vec.y;
    local dz = self.z - vec.z;
    local dw = self.w - vec.w;
    return dx * dx + dy * dy + dz * dz + dw * dw;
end

---@return LVec4
function LVec4:Normalize()
    local temp = self.w * self.w + self.x * self.x + self.y * self.y + self.z * self.z;
    local fMagnitude = Math.sqrt(temp);
    if (fMagnitude ~= 0.0) then
        fMagnitude = 1.0 / fMagnitude;
        self.x = self.x * fMagnitude;
        self.y = self.y * fMagnitude;
        self.z = self.z * fMagnitude;
        self.w = self.z * fMagnitude;
    end
    return self;
end

---@param vec LVec4
---@return LVec4
function LVec4:CopyFrom(vec)
    self.x = vec.x;
    self.y = vec.y;
    self.z = vec.z;
    self.w = vec.w;
    return self;
end

---@return LVec4
function LVec4:Clone()
    return LVec4:new(self.x, self.y, self.z, self.w);
end

---@param vec LVec4
---@return boolean
function LVec4:Equals(vec)
    return (vec.x == self.x) and (vec.y == self.y) and (vec.z == self.z) and (vec.w == self.w);
end

---@param array KArray
---@param offset number
---@return LVec4
function LVec4:FromArray(array, offset)
    offset = offset or 0;
    self.x = array.Get(offset);
    self.y = array.Get(offset + 1);
    self.z = array.Get(offset + 2);
    self.w = array.Get(offset + 3);
    return self;
end

---@param array KArray
---@param offset number
---@return LVec4
function LVec4:ToArray(array, offset)
    offset = offset or 0;
    array.Set(offset, self.x);
    array.Set(offset + 1, self.y);
    array.Set(offset + 2, self.z);
    array.Set(offset + 3, self.w);
    return self;
end

---@return number
function LVec4:ToDwColorRGBA()
    local v1 = math.tointeger(self.x * 255.0);
    local v2 = bit.lShiftOp(math.tointeger(self.y * 255.0), 8);
    local v3 = bit.lShiftOp(math.tointeger(self.z * 255.0), 16);
    local v4 = bit.lShiftOp(math.tointeger(self.w * 255.0), 24);
    return v1 + v2 + v3 + v4;
end

---@param c number
---@return LVec4
function LVec4:FromDwColorRGBA(c)
    self.x = bit.andOp(c, 0xff000000) / 255.0;
    self.y = bit.rShiftOp(bit.andOp(c, 0x00ff0000), 8) / 255.0;
    self.z = bit.rShiftOp(bit.andOp(c, 0x0000ff00), 16) / 255.0;
    self.w = bit.rShiftOp(bit.andOp(c, 0x000000ff), 24) / 255.0;
    return self;
end

---@return number
function LVec4:ToDwNormal()
    local v1 = math.tointeger((self.x + 1.0) * 0.5 * 255.0);
    local v2 = bit.lShiftOp(math.tointeger((self.y + 1.0) * 0.5 * 255.0), 8);
    local v3 = bit.lShiftOp(math.tointeger((self.z + 1.0) * 0.5 * 255.0), 16);
    local v4 = bit.lShiftOp(math.tointeger((self.w + 1.0) * 0.5 * 255.0), 24);
    return v1 + v2 + v3 + v4;
end

---@param c number
---@return LVec4
function LVec4:FromDwNormal(c)
    self.x = bit.andOp(c, 0xff000000) / 255.0 * 2.0 - 1.0;
    self.y = bit.rShiftOp(bit.andOp(c, 0x00ff0000), 8) / 255.0 * 2.0 - 1.0;
    self.z = bit.rShiftOp(bit.andOp(c, 0x0000ff00), 16) / 255.0 * 2.0 - 1.0;
    self.w = bit.rShiftOp(bit.andOp(c, 0x000000ff), 24) / 255.0 * 2.0 - 1.0;
    return self;
end

---@param x number
---@param y number
---@param z number
---@param w number
---@return boolean
function LVec4:AlmostEqual(x, y, z, w)
    if math.abs(self.x - x) < 0.01 and math.abs(self.y - y) < 0.01 and
            math.abs(self.z - z) < 0.01 and math.abs(self.w - w) < 0.01 then
        return true;
    end
    return false;
end

---@return KArray
function LVec4:GetData()
    local data = KArray:new();
    self.ToArray(data, 0);
    return data;
end

------------------------------------------------------------------------------------------
---FUNCTIONS
------------------------------------------------------------------------------------------

---@param vec1
---@param vec2
---@return {Number}
function Vev2RotateAngle(vec1, vec2)
    local fEpsilon = 1.0e-6;
    local fPI = Math.acosf(-1.0);
    local fDot = 0;
    local fAngle = 0;
    fDot = vec1.dot(vec2);
    if math.abs(fDot - 1.0) <= fEpsilon then
        fAngle = 0.0;
    elseif math.abs(fDot + 1.0) <= fEpsilon then
        fAngle = fPI;
    else
        fAngle = math.acos(fDot);
        local fCross = vec1.x * vec2.y - vec2.x * vec1.y;
        if fCross < 0.0 then
            fAngle = 2.0 * fPI - fAngle;
        end
    end

    if math.isNan(fAngle) then
        LOG_E("GetRotateAngle error");
    end
    return fAngle;
end

---@param outVec LVec3
---@param va LVec3
---@param vb LVec3
---@return LVec3
function Vec3Cross(outVec, va, vb)
    local x = va.y * vb.z - va.z * vb.y;
    local y = va.z * vb.x - va.x * vb.z;
    local z = va.x * vb.y - va.y * vb.x;

    outVec.x = x;
    outVec.y = y;
    outVec.z = z;
    return outVec;
end

---@param pout LVec4
---@param pv1 LVec4
---@param pv2 LVec4
---@param pv3 LVec4
---@return LVec4
function Vec4Cross(pout, pv1, pv2, pv3)
    local pv1x = pv1.x;
    local pv1y = pv1.y;
    local pv1z = pv1.z;
    local pv1w = pv1.w;
    
    local pv2x = pv2.x;
    local pv2y = pv2.y;
    local pv2z = pv2.z;
    local pv2w = pv2.w;
    
    local pv3x = pv3.x;
    local pv3y = pv3.y;
    local pv3z = pv3.z;
    local pv3w = pv3.w;
    
    local x = pv1y * (pv2z * pv3w - pv3z * pv2w) - pv1z * (pv2y * pv3w - pv3y * pv2w) + pv1w * (pv2y * pv3z - pv2z * pv3y);
    local y = -(pv1x * (pv2z * pv3w - pv3z * pv2w) - pv1z * (pv2x * pv3w - pv3x * pv2w) + pv1w * (pv2x * pv3z - pv3x * pv2z));
    local z = pv1x * (pv2y * pv3w - pv3y * pv2w) - pv1y * (pv2x * pv3w - pv3x * pv2w) + pv1w * (pv2x * pv3y - pv3x * pv2y);
    local w = -(pv1x * (pv2y * pv3z - pv3y * pv2z) - pv1y * (pv2x * pv3z - pv3x * pv2z) + pv1z * (pv2x * pv3y - pv3x * pv2y));
    pout.x = x;
    pout.y = y;
    pout.z = z;
    pout.w = w;
    return pout;
end

---@param outVec LVec2
---@param v1 LVec2
---@param v2 LVec2
---@returns outVec LVec2
function Vec2Add(outVec, v1, v2)
    local x = 0;
    local y = 0;
    if type(v2) == "number" then
        x = v1.x + v2;
        y = v1.y + v2;
    else
        x = v1.x + v2.x;
        y = v1.y + v2.y;
    end
    outVec.x = x;
    outVec.y = y;
    return outVec;
end

---@param outVec LVec2
---@param v1 LVec2
---@param v2 LVec2 | number
---@return LVec2
function Vec2Minus(outVec, v1, v2)
    local x = 0;
    local y = 0;
    if type(v2) == "number" then
        x = v1.x - v2;
        y = v1.y - v2;
    else
        x = v1.x - v2.x;
        y = v1.y - v2.y;
    end
    outVec.x = x;
    outVec.y = y;
    return outVec;
end

---@param outVec LVec2
---@param v1 LVec2
---@param v2 LVec2 | number
---@return LVec2
function Vec2Multiply(outVec, v1, v2)
    local x = 0;
    local y = 0;
    if type(v2) == "number" then
        x = v1.x * v2;
        y = v1.y * v2;
    else
        x = v1.x * v2.x;
        y = v1.y * v2.y;
    end
    outVec.x = x;
    outVec.y = y;
    return outVec;
end

---@param outVec LVec2
---@param v1 LVec2
---@param v2 LVec2 | number
---@return LVec2
function Vec2Divide(outVec, v1, v2)
    local x = 0;
    local y = 0;
    if type(v2) == "number" then
        x = v1.x / v2;
        y = v1.y / v2;
    else
        x = v1.x / v2.x;
        y = v1.y / v2.y;
    end
    outVec.x = x;
    outVec.y = y;
    return outVec;
end

---@param outVec LVec2
---@param v LVec2
---@return LVec2
function Vec2Negate(outVec, v)
    outVec.x = -v.x;
    outVec.y = -v.y;
    return outVec;
end

---@param outVec LVec3
---@param v1 LVec3
---@param v2 LVec3 | number
---@return LVec3
function Vec3Add(outVec, v1, v2)
    local x, y, z;
    if type(v2) == "number" then
        x = v1.x + v2;
        y = v1.y + v2;
        z = v1.z + v2;
    else
        x = v1.x + v2.x;
        y = v1.y + v2.y;
        z = v1.z + v2.z;
    end
    outVec.x = x;
    outVec.y = y;
    outVec.z = z;
    return outVec;
end

---@param outVec LVec3
---@param v1 LVec3
---@param v2 LVec3 | number
---@return LVec3
function Vec3Minus(outVec, v1, v2)
    local x = 0;
    local y = 0;
    local z = 0;
    if type(v2) == "number" then
        x = v1.x - v2;
        y = v1.y - v2;
        z = v1.z - v2;
    else
        x = v1.x - v2.x;
        y = v1.y - v2.y;
        z = v1.z - v2.z;
    end
    outVec.x = x;
    outVec.y = y;
    outVec.z = z;
    return outVec;
end

---@param outVec LVec3
---@param v1 LVec3
---@param v2 LVec3 | number
---@return LVec3
function Vec3Multiply(outVec, v1, v2)
    local x = 0;
    local y = 0;
    local z = 0;
    if type(v2) == "number" then
        x = v1.x * v2;
        y = v1.y * v2;
        z = v1.z * v2;
    else
        x = v1.x * v2.x;
        y = v1.y * v2.y;
        z = v1.z * v2.z;
    end
    outVec.x = x;
    outVec.y = y;
    outVec.z = z;
    return outVec;
end

---@param outVec LVec3
---@param v1 LVec3
---@param v2 LVec3 | number
---@return LVec3
function Vec3Divide(outVec, v1, v2)
    local x = 0;
    local y = 0;
    local z = 0;
    if type(v2) == "number" then
        x = v1.x / v2;
        y = v1.y / v2;
        z = v1.z / v2;
    else
        x = v1.x / v2.x;
        y = v1.y / v2.y;
        z = v1.z / v2.z;
    end
    outVec.x = x;
    outVec.y = y;
    outVec.z = z;
    return outVec;
end

---@param outVec LVec3
---@param v LVec3
---@return LVec3
function Vec3Negate(outVec, v)
    outVec.x = -v.x;
    outVec.y = -v.y;
    outVec.z = -v.z;
    return outVec;
end

---@param outVec LVec4
---@param v1 LVec4
---@param v2 LVec4 | number
---@return LVec4
function Vec4Add(outVec, v1, v2)
    local x, y, z, w;
    if type(v2) == "number" then
        x = v1.x + v2;
        y = v1.y + v2;
        z = v1.z + v2;
        w = v1.w + v2;
    else
        x = v1.x + v2.x;
        y = v1.y + v2.y;
        z = v1.z + v2.z;
        w = v1.w + v2.w;
    end
    outVec.x = x;
    outVec.y = y;
    outVec.z = z;
    outVec.w = w;
    return outVec;
end

---@param outVec LVec4
---@param v1 LVec4
---@param v2 LVec4 | number
---@return LVec4
function Vec4Minus(outVec, v1, v2)
    local x = 0;
    local y = 0;
    local z = 0;
    local w = 0;
    if type(v2) == "number" then
        x = v1.x - v2;
        y = v1.y - v2;
        z = v1.z - v2;
        w = v1.w - v2;
    else
        x = v1.x - v2.x;
        y = v1.y - v2.y;
        z = v1.z - v2.z;
        w = v1.w - v2.w;
    end
    outVec.x = x;
    outVec.y = y;
    outVec.z = z;
    outVec.w = w;
    return outVec;
end

---@param outVec LVec4
---@param v1 LVec4
---@param v2 LVec4 | number
---@return LVec4
function Vec4Multiply(outVec, v1, v2)
    local x = 0;
    local y = 0;
    local z = 0;
    local w = 0;
    if type(v2) == "number" then
        x = v1.x * v2;
        y = v1.y * v2;
        z = v1.z * v2;
        w = v1.w * v2;
    else
        x = v1.x * v2.x;
        y = v1.y * v2.y;
        z = v1.z * v2.z;
        w = v1.w * v2.w;
    end
    outVec.x = x;
    outVec.y = y;
    outVec.z = z;
    outVec.w = w;
    return outVec;
end

---@param outVec LVec4
---@param v1 LVec4
---@param v2 LVec4 | number
---@returns LVec4
function Vec4Divide(outVec, v1, v2)
    local x = 0;
    local y = 0;
    local z = 0;
    local w = 0;
    if type(v2) == "number" then
        x = v1.x / v2;
        y = v1.y / v2;
        z = v1.z / v2;
        w = v1.z / v2;
    else
        x = v1.x / v2.x;
        y = v1.y / v2.y;
        z = v1.z / v2.z;
        w = v1.w / v2.w;
    end
    outVec.x = x;
    outVec.y = y;
    outVec.z = z;
    outVec.w = w;
    return outVec;
end

---@param outVec LVec4
---@param v LVec4
---@return LVec4
function Vec4Negate(outVec, v)
    outVec.x = -v.x;
    outVec.y = -v.y;
    outVec.z = -v.z;
    outVec.w = -v.w;
    return outVec;
end
