"use strict";
var __extends = (this && this.__extends) || (function () {
    var extendStatics = function (d, b) {
        extendStatics = Object.setPrototypeOf ||
            ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
            function (d, b) { for (var p in b) if (Object.prototype.hasOwnProperty.call(b, p)) d[p] = b[p]; };
        return extendStatics(d, b);
    };
    return function (d, b) {
        if (typeof b !== "function" && b !== null)
            throw new TypeError("Class extends value " + String(b) + " is not a constructor or null");
        extendStatics(d, b);
        function __() { this.constructor = d; }
        d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
    };
})();
Object.defineProperty(exports, "__esModule", { value: true });
exports.WebGlRenderContext2D = exports.ELineDrawMode = exports.calculateAbsoluteRenderLayer = void 0;
var app_1 = require("../../constants/app");
var Guard_1 = require("../../Core/Guard");
var Rect_1 = require("../../Core/Rect");
var createNativeRect_1 = require("../Visuals/Helpers/createNativeRect");
var NativeObject_1 = require("../Visuals/Helpers/NativeObject");
var DeletableEntity_1 = require("../../Core/DeletableEntity");
var performance_1 = require("../../utils/performance");
var Point_1 = require("../../Core/Point");
var AnchorPoint_1 = require("../../types/AnchorPoint");
var TextPosition_1 = require("../../types/TextPosition");
var colorUtil_1 = require("../../utils/colorUtil");
var parseColor_1 = require("../../utils/parseColor");
var text_1 = require("../../utils/text");
var SURFACE_LAYER_STEP = 1000;
/**
 * @param surfaceOrder layer z-order offset of the surface
 * @param layerStep specifies the capacity of layers that could be potentially added between the default chart layers
 * @param relativeRenderLayer layer number relative to the specific surface layers
 * @returns absolute order of the layer on the chart (considering parent chart and previous subChart surface layers)
 */
var calculateAbsoluteRenderLayer = function (surfaceOrder, layerStep, relativeRenderLayer) {
    return surfaceOrder * SURFACE_LAYER_STEP + relativeRenderLayer * layerStep;
};
exports.calculateAbsoluteRenderLayer = calculateAbsoluteRenderLayer;
/**
 * Defines enumeration constants for Line Drawing modes
 */
var ELineDrawMode;
(function (ELineDrawMode) {
    /**
     * Points provided define a poly-line (continuous line)
     */
    ELineDrawMode["PolyLine"] = "PolyLine";
    /**
     * Points provided define discontinuous lines, e.g. x1y1 x2y2  is one line, x3y3 x4y4 is the next
     */
    ELineDrawMode["DiscontinuousLine"] = "DiscontinuousLine";
})(ELineDrawMode = exports.ELineDrawMode || (exports.ELineDrawMode = {}));
/**
 * The WebGlRenderContext2D provides methods for drawing to a WebGL2 / WebAssembly canvas powered by SciChart's Visual Xccelerator engine.
 * This context class is used in SciChart's High Performance Realtime {@link https://www.scichart.com/javascript-chart-features | JavaScript Charts}
 * to draw shapes, lines, fills, images and more
 */
var WebGlRenderContext2D = /** @class */ (function (_super) {
    __extends(WebGlRenderContext2D, _super);
    /**
     * Creates an instance of the WebGlRenderContext2D
     * @param webAssemblyContext The {@link TSciChart | SciChart WebAssembly Context} containing native methods and access to our WebGL2 Engine
     * @param viewportSize The Viewport {@link Size}
     */
    function WebGlRenderContext2D(webAssemblyContext, viewportSize, canvasId) {
        var _this = _super.call(this) || this;
        _this.layers = new Map();
        _this.effects = [];
        _this.webAssemblyContext = webAssemblyContext;
        _this.viewportSize = viewportSize;
        _this.canvasId = canvasId;
        _this.currentClipRect = Rect_1.Rect.create(0, 0, viewportSize.width, viewportSize.height);
        _this.currentRotation = 0;
        _this.currentTranslationX = 0;
        _this.currentTranslationY = 0;
        return _this;
    }
    /**
     * Get the native {@link SCRTRenderContext} for direct access to SciChart's WebAssembly Visual Xccelerator engine
     */
    WebGlRenderContext2D.prototype.getNativeContext = function () {
        if (!this.nativeContext) {
            this.nativeContext = this.webAssemblyContext.SCRTGetMainRenderContext2D();
        }
        return this.nativeContext;
    };
    /**
     * Draw lines: grid lines, etc.
     * @param vertices
     * @param pen
     * @param lineDrawMode
     * @param left - offset in pixels from left, typically used for axes
     * @param top - offset in pixels from top, typically used for axes
     */
    WebGlRenderContext2D.prototype.drawLinesNative = function (vertices, pen, lineDrawMode, clipRect, left, top) {
        if (left === void 0) { left = 0; }
        if (top === void 0) { top = 0; }
        var isStrips = lineDrawMode === ELineDrawMode.PolyLine;
        var nativeContext = this.getNativeContext();
        this.resetTransform();
        this.translate(left, top);
        this.setClipRect(clipRect);
        var drawLineParams = new this.webAssemblyContext.SCRTDrawLinesParams();
        drawLineParams.m_Type = isStrips
            ? this.webAssemblyContext.SCRTLineType.Strip
            : this.webAssemblyContext.SCRTLineType.List;
        drawLineParams.SetPen(pen);
        drawLineParams.SetPointsVec(vertices);
        nativeContext.DrawLines(drawLineParams);
        drawLineParams.delete();
    };
    /**
     * Draw rectangles: grid bands, etc.
     * @param vertices
     * @param brush
     * @param left - offset in pixels from left, typically used for axes
     * @param top - offset in pixels from top, typically used for axes
     */
    WebGlRenderContext2D.prototype.drawRects = function (vertices, brush, clipRect, left, top) {
        if (left === void 0) { left = 0; }
        if (top === void 0) { top = 0; }
        var anchorParams = (0, NativeObject_1.getVector4)(this.webAssemblyContext, 0, 0, 0, 0);
        var nativeContext = this.getNativeContext();
        this.resetTransform();
        this.translate(left, top);
        this.setClipRect(clipRect);
        // this.EnsureContextTransform(left, top, clipRect);
        var drawRectsParams = new this.webAssemblyContext.SCRTDrawRectsParams();
        drawRectsParams.SetVerticesVec(vertices);
        drawRectsParams.SetBrush(brush);
        drawRectsParams.m_vAnchorParams = anchorParams;
        nativeContext.DrawRects(drawRectsParams);
        drawRectsParams === null || drawRectsParams === void 0 ? void 0 : drawRectsParams.delete();
    };
    WebGlRenderContext2D.prototype.drawEllipses = function (vertices, pen, left, top) {
        if (left === void 0) { left = 0; }
        if (top === void 0) { top = 0; }
        var nativeContext = this.getNativeContext();
        this.resetTransform();
        this.translate(left, top);
        var drawRectsParams = new this.webAssemblyContext.SCRTDrawRectsParams();
        drawRectsParams.SetVerticesVec(vertices);
        drawRectsParams.SetPen(pen);
        drawRectsParams.SetBrush(null);
        drawRectsParams.m_bIsEllipses = true;
        nativeContext.DrawRects(drawRectsParams);
        drawRectsParams === null || drawRectsParams === void 0 ? void 0 : drawRectsParams.delete();
    };
    /**
     *
     * @param vertices
     * @param xCenter
     * @param yCenter Pixel-space Y of the arc centre (Y-down, same convention as other primitives)
     * @param rotation2 Rotation in Radians
     * @param clipRect
     * @param pen
     * @param brush
     * @param left
     * @param top
     */
    WebGlRenderContext2D.prototype.drawArcs = function (vertices, xCenter, yCenter, rotation, clipRect, pen, brush, left, top) {
        if (left === void 0) { left = 0; }
        if (top === void 0) { top = 0; }
        var rotation2 = -rotation;
        var nativeContext = this.getNativeContext();
        var dx = 0;
        var dy = 0;
        if (rotation2 !== 0) {
            var l = Math.sqrt(xCenter * xCenter + yCenter * yCenter);
            var a = Math.atan2(yCenter, xCenter);
            dx = xCenter - l * Math.cos(a + rotation2);
            dy = yCenter - l * Math.sin(a + rotation2);
        }
        this.resetTransform();
        this.translate(dx + left, dy + top);
        this.rotate((rotation2 * 180) / Math.PI);
        this.setClipRect(clipRect);
        var drawArcsParams = new this.webAssemblyContext.SCRTDrawArcsParams();
        drawArcsParams.SetVerticesVec(vertices);
        drawArcsParams.SetPen(pen ? pen : null);
        drawArcsParams.SetBrush(brush ? brush : null);
        nativeContext.DrawArcs(drawArcsParams);
        drawArcsParams === null || drawArcsParams === void 0 ? void 0 : drawArcsParams.delete();
    };
    /**
     * Enqueues a draw operation to the specified layer. Use in combination with {@link drawLayers} to flush layered draws
     * @param drawFunction the {@link TDrawFunction | Draw Function} to enqueue
     * @param layer the {@link ERenderLayer | Layer} to draw to
     */
    WebGlRenderContext2D.prototype.enqueueLayeredDraw = function (drawFunction, layer) {
        if (!this.layers.has(layer)) {
            this.layers.set(layer, []);
        }
        this.layers.get(layer).push(drawFunction);
    };
    /**
     * Flushes the {@link layers} which have been enqueued with drawing operations in order.
     * Use this in combination with {@link enqueueLayeredDraw} to draw in layers
     */
    WebGlRenderContext2D.prototype.drawLayers = function () {
        var _a, _b;
        var parentContextId = this.canvasId;
        var allLayersDrawStartMark = performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.AllLayersDrawStart, {
            parentContextId: parentContextId,
            level: performance_1.EPerformanceDebugLevel.Verbose
        });
        var keys = Array.from(this.layers.keys()).sort(function (a, b) { return a - b; });
        for (var _i = 0, keys_1 = keys; _i < keys_1.length; _i++) {
            var key = keys_1[_i];
            var layerDrawStartMark = performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.SingleLayerDrawStart, {
                contextId: "Layer-".concat(key),
                parentContextId: parentContextId,
                level: performance_1.EPerformanceDebugLevel.Verbose
            });
            var drawFunctionsInCurrentLayer = this.layers.get(key);
            for (var _c = 0, drawFunctionsInCurrentLayer_1 = drawFunctionsInCurrentLayer; _c < drawFunctionsInCurrentLayer_1.length; _c++) {
                var drawFunc = drawFunctionsInCurrentLayer_1[_c];
                drawFunc();
            }
            performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.SingleLayerDrawEnd, {
                relatedId: (_a = layerDrawStartMark === null || layerDrawStartMark === void 0 ? void 0 : layerDrawStartMark.detail) === null || _a === void 0 ? void 0 : _a.relatedId,
                contextId: "Layer-".concat(key),
                parentContextId: parentContextId,
                level: performance_1.EPerformanceDebugLevel.Verbose
            });
        }
        performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.AllLayersDrawEnd, {
            relatedId: (_b = allLayersDrawStartMark === null || allLayersDrawStartMark === void 0 ? void 0 : allLayersDrawStartMark.detail) === null || _b === void 0 ? void 0 : _b.relatedId,
            parentContextId: parentContextId,
            level: performance_1.EPerformanceDebugLevel.Verbose
        });
    };
    /**
     * Applies a {@link ShaderEffect} to the rendering pipeline. Calling {@link WebGL2RenderingContext.popShaderEffect} pops the effect from the stack
     * reverting to normal drawing
     * @param effect the {@link ShaderEffect} to apply to subsequent draw operations
     */
    WebGlRenderContext2D.prototype.pushShaderEffect = function (effect) {
        if (effect) {
            this.effects.push(effect);
            if (!app_1.IS_TEST_ENV) {
                this.getNativeContext().AddSeriesEffect(effect.getNativeEffect());
            }
        }
    };
    /**
     * Pops a {@link ShaderEffect} from the rendering pipeline. Call {@link WebGL2RenderingContext.pushShaderEffect} to apply an effect
     */
    WebGlRenderContext2D.prototype.popShaderEffect = function () {
        var effect = this.effects.pop();
        if (effect && !app_1.IS_TEST_ENV) {
            this.getNativeContext().RemoveSeriesEffect(effect.getNativeEffect());
        }
    };
    /**
     * @inheritDoc
     */
    WebGlRenderContext2D.prototype.createPen = function (stroke, strokeThickness, strokeDashArray, antiAliased) {
        if (strokeDashArray === void 0) { strokeDashArray = []; }
        if (antiAliased === void 0) { antiAliased = true; }
        throw new Error("Use Pen2DCache for creating pens instead!");
    };
    /**
     * @inheritDoc
     */
    WebGlRenderContext2D.prototype.createSolidBrush = function (fill, opacity) {
        throw new Error("Use BrushCache for creating brushes instead!");
    };
    /**
     * @inheritDoc
     */
    WebGlRenderContext2D.prototype.delete = function () {
        // Todo: Any cached items delete here
    };
    /**
     * @inheritDoc
     */
    WebGlRenderContext2D.prototype.drawLine = function (x1, y1, x2, y2, pen, offsetRect, clipRect) {
        if (!x1 && !y1 && !x2 && !y2) {
            return;
        }
        Guard_1.Guard.notNull(pen, "pen");
        Guard_1.Guard.isTrue(pen.getPenType() === "WasmPen", "pen must be an instance of WasmPen to be used with the WasmRenderContext");
        var scrtPen = pen.scrtPen;
        Guard_1.Guard.notNull(scrtPen, "WasmPen.scrtPen");
        var isStrips = true;
        var nativeContext = this.getNativeContext();
        var vertices = (0, NativeObject_1.getVectorColorVertex)(this.webAssemblyContext);
        var vertex0 = (0, NativeObject_1.getVertex)(this.webAssemblyContext, x1, y1);
        vertices.push_back(vertex0);
        var vertex1 = (0, NativeObject_1.getVertex)(this.webAssemblyContext, x2, y2);
        vertices.push_back(vertex1);
        this.resetTransform();
        this.translate(offsetRect.x, offsetRect.y);
        this.setClipRect(clipRect);
        var drawLineParams = new this.webAssemblyContext.SCRTDrawLinesParams();
        drawLineParams.m_Type = isStrips
            ? this.webAssemblyContext.SCRTLineType.Strip
            : this.webAssemblyContext.SCRTLineType.List;
        drawLineParams.SetPen(scrtPen);
        drawLineParams.SetPointsVec(vertices);
        nativeContext.DrawLines(drawLineParams);
        drawLineParams.delete();
    };
    /**
     * @inheritDoc
     */
    WebGlRenderContext2D.prototype.drawLines = function (xyValues, strokePen, offsetRect, clipRect, lineDrawMode) {
        if (lineDrawMode === void 0) { lineDrawMode = ELineDrawMode.PolyLine; }
        Guard_1.Guard.notNull(strokePen, "pen");
        Guard_1.Guard.notNull(xyValues, "xyValues");
        Guard_1.Guard.isTrue(strokePen.getPenType() === "WasmPen", "pen must be an instance of WasmPen to be used with the WasmRenderContext");
        Guard_1.Guard.isTrue(xyValues.length > 0 && xyValues.length % 2 === 0, "xyValues length must be a multiple of 2, values arranged as x0y0 x1y1 x2y2...");
        var scrtPen = strokePen.scrtPen;
        Guard_1.Guard.notNull(scrtPen, "WebGlPen.scrtPen");
        var isStrips = lineDrawMode === ELineDrawMode.PolyLine;
        var nativeContext = this.getNativeContext();
        var vertices = (0, NativeObject_1.getVectorColorVertex)(this.webAssemblyContext);
        for (var i = 0; i < xyValues.length; i += 2) {
            var vertex = (0, NativeObject_1.getVertex)(this.webAssemblyContext, xyValues[i], xyValues[i + 1]);
            // Setting a sub-property directly MUST BE AVOIDED because it creates a copy of an object and leaks the memory
            // Never do this: vertex.m_vPosition.z = 0;
            vertices.push_back(vertex);
        }
        this.resetTransform();
        this.translate(offsetRect.x, offsetRect.y);
        this.setClipRect(clipRect);
        var drawLineParams = new this.webAssemblyContext.SCRTDrawLinesParams();
        drawLineParams.m_Type = isStrips
            ? this.webAssemblyContext.SCRTLineType.Strip
            : this.webAssemblyContext.SCRTLineType.List;
        drawLineParams.SetPen(scrtPen);
        drawLineParams.SetPointsVec(vertices);
        nativeContext.DrawLines(drawLineParams);
        drawLineParams.delete();
    };
    /**
     * @inheritDoc
     */
    WebGlRenderContext2D.prototype.drawTriangleStrip = function (xValues, yValues, offsetRect, clipRect, fillBrush) {
        if (fillBrush) {
            Guard_1.Guard.arraysSameLength(xValues, "xValues", yValues, "yValues");
            var nativeContext = this.getNativeContext();
            var scrtBrush = fillBrush.scrtBrush;
            Guard_1.Guard.notNull(scrtBrush, "WebGlBrush.scrtBrush");
            var vertices = (0, NativeObject_1.getVectorColorTextureVertex)(this.webAssemblyContext);
            var size = xValues.length;
            for (var i = 0; i < size; i++) {
                var x = xValues[i];
                var y = yValues[i];
                var vertex = (0, NativeObject_1.getTextureVertex)(this.webAssemblyContext, x, y);
                vertices.push_back(vertex);
            }
            this.resetTransform();
            this.translate(offsetRect.x, offsetRect.y);
            this.setClipRect(clipRect);
            var drawParams = new this.webAssemblyContext.SCRTDrawPrimitivesParams();
            drawParams.SetVerticesVec(vertices);
            drawParams.SetBrush(scrtBrush);
            nativeContext.DrawPrimitives(drawParams);
            drawParams.delete();
        }
    };
    /**
     * Helper function to draw a texture a {@link SCRTRectVertex}
     * @param webAssemblyContext The {@link TSciChart | SciChart 2D WebAssembly Context} containing native methods and
     * access to our WebGL2 Engine and WebAssembly numerical methods
     * @param texture
     * @param x
     * @param y
     * @param width
     * @param height
     */
    WebGlRenderContext2D.prototype.drawTexture = function (texture, x, y, width, height) {
        var nativeContext = this.getNativeContext();
        var brush = new this.webAssemblyContext.SCRTTextureBrush(texture, this.webAssemblyContext.eSCRTBrushMappingMode.PerPrimitive, 1);
        // draw as a single strip with 4 verts
        var quadVerts = (0, NativeObject_1.getVectorColorTextureVertex)(this.webAssemblyContext);
        var bottomLeft = (0, NativeObject_1.getTextureVertex)(this.webAssemblyContext, x, y, app_1.NEUTRAL_COLOR, 0, 0);
        quadVerts.push_back(bottomLeft);
        var topLeft = (0, NativeObject_1.getTextureVertex)(this.webAssemblyContext, x + width, y, app_1.NEUTRAL_COLOR, 1, 0);
        quadVerts.push_back(topLeft);
        var bottomRight = (0, NativeObject_1.getTextureVertex)(this.webAssemblyContext, x, y + height, app_1.NEUTRAL_COLOR, 0, 1);
        quadVerts.push_back(bottomRight);
        var topRight = (0, NativeObject_1.getTextureVertex)(this.webAssemblyContext, x + width, y + height, app_1.NEUTRAL_COLOR, 1, 1);
        quadVerts.push_back(topRight);
        var drawParams = new this.webAssemblyContext.SCRTDrawPrimitivesParams();
        drawParams.SetVerticesVec(quadVerts);
        drawParams.SetBrush(brush);
        nativeContext.DrawPrimitives(drawParams);
        brush === null || brush === void 0 ? void 0 : brush.delete();
        drawParams.delete();
    };
    WebGlRenderContext2D.prototype.drawRotatedRect = function (width, height, baselineHeight, padding, verticalAnchorPoint, horizontalAnchorPoint, position, rotation, clipRect, fillBrush) {
        var scrtBrush = fillBrush.scrtBrush;
        Guard_1.Guard.notNull(scrtBrush, "WebGlBrush.scrtBrush");
        var fromCenterToTop;
        var fromCenterToBottom;
        switch (verticalAnchorPoint) {
            case AnchorPoint_1.EVerticalAnchorPoint.Bottom:
                fromCenterToTop = baselineHeight + padding.bottom + padding.top;
                fromCenterToBottom = height - baselineHeight;
                break;
            case AnchorPoint_1.EVerticalAnchorPoint.Top:
                fromCenterToTop = 0;
                fromCenterToBottom = height + padding.bottom + padding.top;
                break;
            default:
                fromCenterToTop = baselineHeight / 2 + (padding.bottom + padding.top) / 2;
                fromCenterToBottom = height - baselineHeight / 2 + (padding.bottom + padding.top) / 2;
        }
        var fromCenterToLeft;
        var fromCenterToRight;
        switch (horizontalAnchorPoint) {
            case AnchorPoint_1.EHorizontalAnchorPoint.Right:
                fromCenterToLeft = width + padding.left + padding.right;
                fromCenterToRight = 0;
                break;
            case AnchorPoint_1.EHorizontalAnchorPoint.Left:
                fromCenterToLeft = 0;
                fromCenterToRight = width + padding.left + padding.right;
                break;
            default:
                fromCenterToLeft = width / 2 + padding.left;
                fromCenterToRight = width / 2 + padding.right;
        }
        var rect = Rect_1.Rect.createWithPoints(new Point_1.Point(-fromCenterToLeft, -fromCenterToTop), new Point_1.Point(fromCenterToRight, fromCenterToBottom));
        var nativeContext = this.getNativeContext();
        var vertices = (0, NativeObject_1.getVectorRectVertex)(this.webAssemblyContext);
        var anchorParams = (0, NativeObject_1.getVector4)(this.webAssemblyContext, 0, 0, 0, 0);
        var nativeRect = (0, createNativeRect_1.createNativeRect)(this.webAssemblyContext, rect.x, rect.y, rect.right, rect.bottom);
        vertices.push_back(nativeRect);
        this.resetTransform();
        this.translate(position.x, position.y);
        this.rotate(rotation);
        this.setClipRect(clipRect);
        var drawRectsParams = new this.webAssemblyContext.SCRTDrawRectsParams();
        drawRectsParams.SetVerticesVec(vertices);
        drawRectsParams.SetBrush(scrtBrush);
        drawRectsParams.m_vAnchorParams = anchorParams;
        nativeContext.DrawRects(drawRectsParams);
        drawRectsParams === null || drawRectsParams === void 0 ? void 0 : drawRectsParams.delete();
    };
    /**
     * @inheritDoc
     */
    WebGlRenderContext2D.prototype.drawRect = function (rect, offsetRect, clipRect, strokePen, fillBrush, bevelCorners, strokeThickness) {
        if (fillBrush) {
            var nativeContext = this.getNativeContext();
            var scrtBrush = fillBrush.scrtBrush;
            Guard_1.Guard.notNull(scrtBrush, "WebGlBrush.scrtBrush");
            var vertices = (0, NativeObject_1.getVectorRectVertex)(this.webAssemblyContext);
            var anchorParams = (0, NativeObject_1.getVector4)(this.webAssemblyContext, 0, 0, 0, 0);
            var nativeRect = (0, createNativeRect_1.createNativeRect)(this.webAssemblyContext, rect.x, rect.y, rect.right, rect.bottom);
            vertices.push_back(nativeRect);
            this.resetTransform();
            this.translate(offsetRect.x, offsetRect.y);
            this.setClipRect(clipRect);
            var drawRectsParams = new this.webAssemblyContext.SCRTDrawRectsParams();
            drawRectsParams.SetVerticesVec(vertices);
            drawRectsParams.SetBrush(scrtBrush);
            drawRectsParams.m_vAnchorParams = anchorParams;
            nativeContext.DrawRects(drawRectsParams);
            drawRectsParams === null || drawRectsParams === void 0 ? void 0 : drawRectsParams.delete();
        }
        if (strokePen) {
            if (bevelCorners) {
                this.drawLines([
                    rect.right,
                    rect.top,
                    rect.right,
                    rect.bottom,
                    rect.left,
                    rect.bottom,
                    rect.left,
                    rect.top,
                    rect.right,
                    rect.top,
                    rect.right,
                    rect.bottom
                ], strokePen, offsetRect, clipRect, ELineDrawMode.PolyLine);
            }
            else {
                var hst = Math.round(strokeThickness / 2) - 1;
                this.drawLines([
                    rect.right,
                    rect.top - hst,
                    rect.right,
                    rect.bottom + hst,
                    rect.right,
                    rect.bottom,
                    rect.left,
                    rect.bottom,
                    rect.left,
                    rect.bottom + hst,
                    rect.left,
                    rect.top - hst,
                    rect.left,
                    rect.top,
                    rect.right,
                    rect.top
                ], strokePen, offsetRect, clipRect, ELineDrawMode.DiscontinuousLine);
            }
        }
    };
    WebGlRenderContext2D.prototype.drawTextBackground = function (textWidth, textHeight, rotation, rotationCenter, chartViewRect, verticalAnchorPoint, horizontalAnchorPoint, padding, fillBrush) {
        this.drawRotatedRect(textWidth, textHeight, textHeight, padding, verticalAnchorPoint, horizontalAnchorPoint, rotationCenter, rotation, chartViewRect, fillBrush);
    };
    WebGlRenderContext2D.prototype.drawNativeText = function (rotationRadians, xCoord, yCoord, offsetRect, chartViewRect, fontFamily, fontSize, textColor, textColorOpacity, backgroundFillBrush, verticalAnchorPoint, horizontalAnchorPoint, text, padding, scale, lineSpacing) {
        if (scale === void 0) { scale = 1; }
        if (lineSpacing === void 0) { lineSpacing = 3; }
        var colorNum = (0, parseColor_1.parseColorToUIntArgb)(textColor);
        var colorNumWithOpacity = (0, colorUtil_1.uintArgbColorOverrideOpacity)(colorNum, textColorOpacity);
        var style = {
            fontFamily: fontFamily,
            fontSize: fontSize
        };
        var font = this.getFont(style, false, false);
        var textBounds = (0, NativeObject_1.getTextBounds)(this.webAssemblyContext);
        font.CalculateStringBounds(text !== null && text !== void 0 ? text : "", textBounds, lineSpacing);
        var rotationCenterX = xCoord + offsetRect.x;
        var rotationCenterY = yCoord + offsetRect.y;
        var _a = (0, text_1.getNativeTextPosition)(xCoord, yCoord, horizontalAnchorPoint, verticalAnchorPoint, textBounds, padding), textPositionX = _a.x, textPositionY = _a.y;
        var textWidth = textBounds.m_fWidth;
        var textHeight = textBounds.m_fHeight;
        var alignMode = (0, TextPosition_1.convertMultiLineAlignment)(TextPosition_1.EMultiLineAlignment.Center, this.webAssemblyContext);
        var oldScale = font.GetScale();
        var scaleChanged = false;
        if (oldScale !== scale) {
            font.SetScale(scale);
            scaleChanged = true;
        }
        var x = textPositionX + offsetRect.x;
        var y = textPositionY + offsetRect.y;
        if (backgroundFillBrush) {
            this.drawTextBackground(textWidth, textHeight, -((rotationRadians * 180) / Math.PI), new Point_1.Point(rotationCenterX, rotationCenterY), chartViewRect, verticalAnchorPoint, horizontalAnchorPoint, padding, backgroundFillBrush);
            this.resetTransform();
        }
        var rotationVector = (0, NativeObject_1.getVector4)(this.webAssemblyContext, rotationCenterX, rotationCenterY, rotationRadians, 0);
        font.DrawStringAdvanced(text, colorNumWithOpacity, Math.round(x), Math.round(y), rotationVector, alignMode, lineSpacing);
        if (scaleChanged) {
            font.SetScale(oldScale);
        }
        // always drawing immediately
        font.End();
    };
    /**
     * Draw text using Slug (GPU Bezier) rendering. Slug evaluates quadratic Bezier curves directly
     * in the fragment shader, producing mathematically exact glyphs at any scale or rotation.
     */
    WebGlRenderContext2D.prototype.drawSlugText = function (rotationRadians, xCoord, yCoord, offsetRect, chartViewRect, fontFamily, fontSize, textColor, textColorOpacity, backgroundFillBrush, verticalAnchorPoint, horizontalAnchorPoint, text, padding, scale, lineSpacing) {
        if (scale === void 0) { scale = 1; }
        if (lineSpacing === void 0) { lineSpacing = 3; }
        var colorNum = (0, parseColor_1.parseColorToUIntArgb)(textColor);
        var colorNumWithOpacity = (0, colorUtil_1.uintArgbColorOverrideOpacity)(colorNum, textColorOpacity);
        var style = {
            fontFamily: fontFamily,
            fontSize: fontSize
        };
        var fontKey = (0, NativeObject_1.getSlugFontKey)(this.webAssemblyContext, style);
        var nativeContext = this.getNativeContext();
        var font = nativeContext.AquireFont(fontKey);
        if (!font) {
            throw new Error("Could not create slug font " + fontKey.m_strName);
        }
        if (!font.m_isDrawing) {
            font.Begin(nativeContext.GetCommandBuffer());
        }
        var textBounds = (0, NativeObject_1.getTextBounds)(this.webAssemblyContext);
        font.CalculateStringBounds(text !== null && text !== void 0 ? text : "", textBounds, lineSpacing);
        var rotationCenterX = xCoord + offsetRect.x;
        var rotationCenterY = yCoord + offsetRect.y;
        var _a = (0, text_1.getNativeTextPosition)(xCoord, yCoord, horizontalAnchorPoint, verticalAnchorPoint, textBounds, padding), textPositionX = _a.x, textPositionY = _a.y;
        var textWidth = textBounds.m_fWidth;
        var textHeight = textBounds.m_fHeight;
        var alignMode = (0, TextPosition_1.convertMultiLineAlignment)(TextPosition_1.EMultiLineAlignment.Center, this.webAssemblyContext);
        var oldScale = font.GetScale();
        var scaleChanged = false;
        if (oldScale !== scale) {
            font.SetScale(scale);
            scaleChanged = true;
        }
        var x = textPositionX + offsetRect.x;
        var y = textPositionY + offsetRect.y;
        if (backgroundFillBrush) {
            this.drawTextBackground(textWidth, textHeight, -((rotationRadians * 180) / Math.PI), new Point_1.Point(rotationCenterX, rotationCenterY), chartViewRect, verticalAnchorPoint, horizontalAnchorPoint, padding, backgroundFillBrush);
            this.resetTransform();
        }
        var rotationVector = (0, NativeObject_1.getVector4)(this.webAssemblyContext, rotationCenterX, rotationCenterY, rotationRadians, 0);
        font.DrawStringAdvanced(text, colorNumWithOpacity, Math.round(x), Math.round(y), rotationVector, alignMode, lineSpacing);
        if (scaleChanged) {
            font.SetScale(oldScale);
        }
        // always drawing immediately
        font.End();
    };
    /**
     * Get a native font.  Fonts are cached and shared within webassembly so there is no need to cache them in JS.
     * Set advanced: true if you are planning to rotate or scale the text.
     * Set drawEarly: true if you are planning to call font.End() early.  Otherwise all native text will be drawn at the end of the render cycle.
     */
    WebGlRenderContext2D.prototype.getFont = function (labelStyle, advanced, drawEarly) {
        var _this = this;
        if (advanced === void 0) { advanced = false; }
        if (drawEarly === void 0) { drawEarly = false; }
        var fontKey = (0, NativeObject_1.getFontKey)(this.webAssemblyContext, labelStyle, advanced, drawEarly);
        var nativeContext = this.getNativeContext();
        var nativeFont = nativeContext.AquireFont(fontKey);
        if (!nativeFont) {
            throw new Error("Could not create font " + fontKey.m_strName);
        }
        else {
            if (!nativeFont.m_isDrawing) {
                nativeFont.Begin(nativeContext.GetCommandBuffer());
            }
        }
        var currentFontName = nativeFont.GetFaceName();
        if (currentFontName === "SCRT_Loading") {
            setTimeout(function () {
                var _a;
                performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.Invalidate, { parentContextId: _this.canvasId });
                _this.webAssemblyContext.TSRRequestCanvasDraw((_a = _this.canvasId) !== null && _a !== void 0 ? _a : "undefinedCanvasId");
            }, 100);
        }
        else if (currentFontName !== fontKey.m_strName) {
            // @ts-ignore
            if (!fontKey.warned) {
                console.warn("Font ".concat(fontKey.m_strName, " could not be found on the server and has not been registered. Falling back to default font.\n                Use await scichartSurface.registerFont if you need to load the font from a remote url"));
                // @ts-ignore
                fontKey.warned = true;
            }
        }
        return nativeFont;
    };
    /** End all fonts, causing text to be drawn */
    WebGlRenderContext2D.prototype.endFonts = function (force) {
        var _a;
        if (force === void 0) { force = false; }
        var mark = performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.DrawNativeTextStart, {
            contextId: this.canvasId,
            level: performance_1.EPerformanceDebugLevel.Verbose
        });
        var nativeContext = this.getNativeContext();
        var keys = (0, NativeObject_1.getAllFontKeys)(this.webAssemblyContext);
        for (var _i = 0, keys_2 = keys; _i < keys_2.length; _i++) {
            var fontKey = keys_2[_i];
            var nativeFont = nativeContext.AquireFont(fontKey);
            if (nativeFont && nativeFont.m_isDrawing) {
                nativeFont.End();
            }
        }
        performance_1.PerformanceDebugHelper.mark(performance_1.EPerformanceMarkType.DrawNativeTextEnd, {
            contextId: this.canvasId,
            relatedId: (_a = mark === null || mark === void 0 ? void 0 : mark.detail) === null || _a === void 0 ? void 0 : _a.relatedId,
            level: performance_1.EPerformanceDebugLevel.Verbose
        });
    };
    WebGlRenderContext2D.prototype.setClipRect = function (clipRect) {
        var nativeContext = this.getNativeContext();
        nativeContext.SetClipRect(clipRect.x, clipRect.y, clipRect.width, clipRect.height);
        this.currentClipRect = clipRect;
    };
    /**
     *
     * @param clipRect Clipping rectangle
     * @param translationX Translation on X axis in pixels
     * @param translationY Translation on Y axis in pixels
     * @param angle Angle in degrees
     */
    WebGlRenderContext2D.prototype.setTranslationRotationAndClip = function (clipRect, translationX, translationY, angle) {
        if (angle === void 0) { angle = 0; }
        this.resetTransform();
        this.translate(translationX, translationY);
        if (angle !== 0)
            this.rotate(angle);
        this.setClipRect(clipRect);
    };
    WebGlRenderContext2D.prototype.resetAndClip = function (clipRect) {
        this.resetTransform();
        this.setClipRect(clipRect);
    };
    WebGlRenderContext2D.prototype.rotate = function (rotationAngle) {
        var nativeContext = this.getNativeContext();
        nativeContext.Rotate(rotationAngle);
    };
    WebGlRenderContext2D.prototype.translate = function (translationX, translationY) {
        var nativeContext = this.getNativeContext();
        nativeContext.Translate(translationX, translationY);
    };
    WebGlRenderContext2D.prototype.resetTransform = function () {
        var nativeContext = this.getNativeContext();
        nativeContext.ResetTransform();
    };
    /**
     * Should store references to all cached WebGlResources {@link ICacheable}
     * Is used to invalidate the resources when the WebGL context is lost.
     */
    WebGlRenderContext2D.webGlResourcesRefs = new Set();
    return WebGlRenderContext2D;
}(DeletableEntity_1.DeletableEntity));
exports.WebGlRenderContext2D = WebGlRenderContext2D;
