"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.init = exports.updateGraphics = exports.GFX = exports.Canvas = exports.TextAlign = exports.GlyphStyle = exports.GFXBuffer = exports.StackBuffer = exports.ScreenQuadPipeline = exports.UnculledPostDrawPipeline = exports.PointLightPipeline = exports.PostDrawPipeline = exports.UITriPipeline = exports.ShadowPipeline = exports.SolidPipeline = exports.TriPipeline = exports.GFXPipeline = void 0;
const gl_matrix_1 = require("gl-matrix");
const color_1 = require("./color");
const engine_1 = require("./engine");
const model_1 = require("./model");
const Native = require("./native");
const utils_1 = require("./utils");
const shaderFiles = utils_1.readDir('app/assets/shaders');
const vertCapacity = 100000;
const DYNAMIC_DRAW = 100;
const STATIC_DRAW = 101;
const VERTEX_SHADER = 102;
const FRAGMENT_SHADER = 103;
class GFXPipeline {
    constructor(name, _vertex, _fragment, gfx, capacity) {
        this.buffers = [];
        this.name = name;
        this.gfx = gfx;
        this.capacity = capacity;
    }
    newBuffer(size, location, drawType = DYNAMIC_DRAW, content = null) {
        const capacity = drawType !== DYNAMIC_DRAW && content !== null ? -1 : this.capacity;
        const b = new GFXBuffer(capacity, size, location, drawType, content);
        if (drawType === DYNAMIC_DRAW) {
            this.buffers.push(b);
        }
        return b;
    }
    update() {
        for (let i = 0; i < this.buffers.length; i++) {
            this.buffers[i].update();
        }
    }
    reset() {
        for (let i = 0; i < this.buffers.length; i++) {
            this.buffers[i].clear();
        }
    }
    index() {
        return this.buffers[0].index;
    }
    skip(tris) {
        for (const b of this.buffers) {
            b.index = b.index + b.size * tris;
        }
    }
}
exports.GFXPipeline = GFXPipeline;
const v2 = gl_matrix_1.vec2.create();
const v3 = gl_matrix_1.vec3.create();
const v4 = gl_matrix_1.vec4.create();
class TriPipeline extends GFXPipeline {
    constructor() {
        super(...arguments);
        this.tris = null;
        this.normals = null;
    }
    transformTri(v4a, v4b, v4c, normal, t, itT) {
        gl_matrix_1.vec4.set(v4, normal[0], normal[1], normal[2], 0);
        gl_matrix_1.vec4.transformMat4(v4, v4, itT);
        this.normals.vec3x3(v4);
        gl_matrix_1.vec4.transformMat4(v4a, v4a, t);
        this.tris.vec3of4(v4a);
        gl_matrix_1.vec4.transformMat4(v4b, v4b, t);
        this.tris.vec3of4(v4b);
        gl_matrix_1.vec4.transformMat4(v4c, v4c, t);
        this.tris.vec3of4(v4c);
    }
}
exports.TriPipeline = TriPipeline;
class SolidPipeline extends TriPipeline {
    constructor() {
        super(...arguments);
        this.diffuse = null;
        this.ambient = null;
        this.specular = null;
    }
    init() {
        this.tris = this.newBuffer(3, 0);
        this.normals = this.newBuffer(3, 1);
        this.diffuse = this.newBuffer(3, 2);
        this.ambient = this.newBuffer(3, 3);
        this.specular = this.newBuffer(3, 4);
    }
    colors(diffuse, ambient, specular) {
        this.diffuse.vec3x3(diffuse);
        this.ambient.vec3x3(ambient);
        this.specular.vec3x3(specular);
    }
}
exports.SolidPipeline = SolidPipeline;
class ShadowPipeline extends TriPipeline {
    constructor() {
        super(...arguments);
        this.width = 0;
        this.height = 0;
    }
    init(width, height, tris, normals) {
        this.width = width;
        this.height = height;
        tris.point(0);
        this.tris = tris;
        normals.point(1);
        this.normals = normals;
    }
}
exports.ShadowPipeline = ShadowPipeline;
class UITriPipeline extends GFXPipeline {
    constructor() {
        super(...arguments);
        this.tris = null;
        this.rgba = null;
    }
    init() {
        this.tris = this.newBuffer(3, 0);
        this.rgba = this.newBuffer(4, 1);
    }
    transformTri(v4a, v4b, v4c, _normal, t, _itT) {
        gl_matrix_1.vec4.transformMat4(v4a, v4a, t);
        this.tris.vec3of4(v4a);
        gl_matrix_1.vec4.transformMat4(v4b, v4b, t);
        this.tris.vec3of4(v4b);
        gl_matrix_1.vec4.transformMat4(v4c, v4c, t);
        this.tris.vec3of4(v4c);
    }
    colors(diffuse, _ambient, _specular) {
        this.rgba.vec3o4x3(diffuse);
    }
    arrow(start, end, w, z, color) {
        gl_matrix_1.vec2.normalize(v2, gl_matrix_1.vec2.sub(v2, start, end));
        gl_matrix_1.vec2.set(v2, -v2[1], v2[0]);
        gl_matrix_1.vec3.set(v3, start[0] + w * v2[0], start[1] + w * v2[1], z);
        this.tris.vec3(v3);
        gl_matrix_1.vec3.set(v3, end[0], end[1], z);
        this.tris.vec3(v3);
        gl_matrix_1.vec3.set(v3, start[0] - w * v2[0], start[1] - w * v2[1], z);
        this.tris.vec3(v3);
        this.rgba.vec4x3(color);
    }
    line(start, end, w, z, color) {
        gl_matrix_1.vec2.normalize(v2, gl_matrix_1.vec2.sub(v2, start, end));
        gl_matrix_1.vec2.set(v2, -v2[1], v2[0]);
        gl_matrix_1.vec3.set(v3, start[0] + w * v2[0], start[1] + w * v2[1], z);
        this.tris.vec3(v3);
        gl_matrix_1.vec3.set(v3, end[0] + w * v2[0], end[1] + w * v2[1], z);
        this.tris.vec3(v3);
        gl_matrix_1.vec3.set(v3, start[0] - w * v2[0], start[1] - w * v2[1], z);
        this.tris.vec3(v3);
        gl_matrix_1.vec3.set(v3, end[0] + w * v2[0], end[1] + w * v2[1], z);
        this.tris.vec3(v3);
        gl_matrix_1.vec3.set(v3, end[0] - w * v2[0], end[1] - w * v2[1], z);
        this.tris.vec3(v3);
        gl_matrix_1.vec3.set(v3, start[0] - w * v2[0], start[1] - w * v2[1], z);
        this.tris.vec3(v3);
        this.rgba.vec4x3(color);
        this.rgba.vec4x3(color);
    }
    line2(start, end, w, z, color1, color2) {
        gl_matrix_1.vec2.normalize(v2, gl_matrix_1.vec2.sub(v2, start, end));
        gl_matrix_1.vec2.set(v2, -v2[1], v2[0]);
        gl_matrix_1.vec3.set(v3, start[0] + w * v2[0], start[1] + w * v2[1], z);
        this.tris.vec3(v3);
        gl_matrix_1.vec3.set(v3, end[0] + w * v2[0], end[1] + w * v2[1], z);
        this.tris.vec3(v3);
        gl_matrix_1.vec3.set(v3, start[0] - w * v2[0], start[1] - w * v2[1], z);
        this.tris.vec3(v3);
        gl_matrix_1.vec3.set(v3, end[0] + w * v2[0], end[1] + w * v2[1], z);
        this.tris.vec3(v3);
        gl_matrix_1.vec3.set(v3, end[0] - w * v2[0], end[1] - w * v2[1], z);
        this.tris.vec3(v3);
        gl_matrix_1.vec3.set(v3, start[0] - w * v2[0], start[1] - w * v2[1], z);
        this.tris.vec3(v3);
        this.rgba.vec4(color1);
        this.rgba.vec4(color2);
        this.rgba.vec4(color1);
        this.rgba.vec4(color2);
        this.rgba.vec4(color2);
        this.rgba.vec4(color1);
    }
    fill2DPolygon(polygon, z, color) {
        for (let i = 2; i < polygon.length - 4; i = i + 2) {
            gl_matrix_1.vec3.set(v3, polygon[0], polygon[1], z);
            this.tris.vec3(v3);
            gl_matrix_1.vec3.set(v3, polygon[i], polygon[i + 1], z);
            this.tris.vec3(v3);
            gl_matrix_1.vec3.set(v3, polygon[i + 2], polygon[i + 3], z);
            this.tris.vec3(v3);
            this.rgba.vec4x3(color);
        }
    }
}
exports.UITriPipeline = UITriPipeline;
class PostDrawPipeline extends TriPipeline {
    constructor() {
        super(...arguments);
        this.color = null;
    }
    init() {
        this.tris = this.newBuffer(3, 0);
        this.normals = this.newBuffer(3, 1);
        this.color = this.newBuffer(4, 2);
    }
    colors(diffuse, _ambient, _specular) {
        this.color.vec4x3(diffuse);
    }
}
exports.PostDrawPipeline = PostDrawPipeline;
const sphereModel = model_1.Model.build({
    name: 'Icosphere',
});
class PointLightPipeline extends PostDrawPipeline {
    constructor() {
        super(...arguments);
        this.lights = null;
        this.props = null;
    }
    init() {
        this.tris = new GFXBuffer(sphereModel.tris.length, 3, 0, STATIC_DRAW);
        this.color = this.newBuffer(4, 2);
        this.lights = this.newBuffer(4, 3);
        this.props = this.newBuffer(4, 3);
        this.tris.model(sphereModel);
        this.tris.update();
    }
    colors(diffuse, _ambient, _specular) {
        this.color.vec4(diffuse);
    }
}
exports.PointLightPipeline = PointLightPipeline;
class UnculledPostDrawPipeline extends PostDrawPipeline {
}
exports.UnculledPostDrawPipeline = UnculledPostDrawPipeline;
class ScreenQuadPipeline extends GFXPipeline {
    constructor(name, vertex, fragment, gfx) {
        super(name, vertex, fragment, gfx, 4);
        this.tris = null;
        this.texCoords = null;
    }
    init() {
        this.tris = this.newBuffer(2, 0, STATIC_DRAW, ScreenQuadPipeline.screenQuad);
        this.texCoords = this.newBuffer(2, 1, STATIC_DRAW, ScreenQuadPipeline.screenTexCoords);
    }
}
exports.ScreenQuadPipeline = ScreenQuadPipeline;
ScreenQuadPipeline.screenQuad = new Float32Array([-1, 1, -1, -1, 1, -1, 1, 1]);
ScreenQuadPipeline.screenTexCoords = new Float32Array([0, 1, 0, 0, 1, 0, 1, 1]);
const normal = gl_matrix_1.vec3.create();
class StackBuffer {
    constructor(capacity, size, content = null, copy = true) {
        this.bufferID = -1;
        if (capacity === -1 && content !== null) {
            capacity = Math.ceil(content.length / size);
        }
        this.byteSize = capacity * size * Float32Array.BYTES_PER_ELEMENT;
        if (content !== null && !copy) {
            this.array = content;
        }
        else {
            const b = Native.nextBuffer(this.byteSize);
            this.array = new Float32Array(b[0]);
            this.bufferID = b[1];
        }
        this.size = size;
        this.index = 0;
        if (content !== null) {
            if (copy) {
                this.write(content);
            }
            this.index = content.length;
        }
    }
    vec2(v) {
        const i = this.index;
        this.array[i] = v[0];
        this.array[i + 1] = v[1];
        this.index = i + this.size;
    }
    vec3(v) {
        const i = this.index;
        this.array[i] = v[0];
        this.array[i + 1] = v[1];
        this.array[i + 2] = v[2];
        this.index = i + this.size;
    }
    vec3of4(v) {
        const i = this.index;
        this.array[i] = v[0];
        this.array[i + 1] = v[1];
        this.array[i + 2] = v[2];
        this.index = i + this.size;
    }
    vec4(v) {
        const i = this.index;
        this.array[i] = v[0];
        this.array[i + 1] = v[1];
        this.array[i + 2] = v[2];
        this.array[i + 3] = v[3];
        this.index = i + this.size;
    }
    mat3(m) {
        const i = this.index;
        this.array[i] = m[0];
        this.array[i + 1] = m[1];
        this.array[i + 2] = m[2];
        this.array[i + 3] = m[3];
        this.array[i + 4] = m[4];
        this.array[i + 5] = m[5];
        this.array[i + 6] = m[6];
        this.array[i + 7] = m[7];
        this.array[i + 8] = m[8];
        this.index = i + this.size;
    }
    mat4(m) {
        const i = this.index;
        this.array[i] = m[0];
        this.array[i + 1] = m[1];
        this.array[i + 2] = m[2];
        this.array[i + 3] = m[3];
        this.array[i + 4] = m[4];
        this.array[i + 5] = m[5];
        this.array[i + 6] = m[6];
        this.array[i + 7] = m[7];
        this.array[i + 8] = m[8];
        this.array[i + 9] = m[8];
        this.array[i + 10] = m[8];
        this.array[i + 11] = m[11];
        this.array[i + 12] = m[12];
        this.array[i + 13] = m[13];
        this.array[i + 14] = m[14];
        this.array[i + 15] = m[15];
        this.index = i + this.size;
    }
    vec3x3(v) {
        const max = this.index + this.size * 3;
        for (let i = this.index; i <= max; i = i + this.size) {
            this.array[i] = v[0];
            this.array[i + 1] = v[1];
            this.array[i + 2] = v[2];
        }
        this.index = max;
    }
    vec4x3(v) {
        const max = this.index + this.size * 3;
        for (let i = this.index; i <= max; i = i + this.size) {
            this.array[i] = v[0];
            this.array[i + 1] = v[1];
            this.array[i + 2] = v[2];
            this.array[i + 3] = v[3];
        }
        this.index = max;
    }
    vec3o4x3(v) {
        if (v.length === 4) {
            this.vec4x3(v);
        }
        else {
            this.vec3x3(v);
        }
    }
    write(buf) {
        for (let i = 0; i < buf.length; i = i + this.size) {
            for (let j = 0; j < this.size; j++) {
                this.array[this.index + i + j] = buf[i + j];
            }
        }
        this.index = this.index + buf.length;
    }
    model(model) {
        const tris = model.tris;
        const verts = model.verts;
        for (let i = 0; i < tris.length; i++) {
            const tri = tris[i] * 3;
            v3[0] = verts[tri];
            v3[1] = verts[tri + 1];
            v3[2] = verts[tri + 2];
            this.vec3(v3);
        }
    }
    modelNormals(model) {
        const tris = model.tris;
        for (let i = 0; i < tris.length; i = i + 3) {
            const n = model.surfaces[(i / 3) | 0] * 3;
            normal[0] = model.normals[n];
            normal[1] = model.normals[n + 1];
            normal[2] = model.normals[n + 2];
            this.vec3x3(normal);
        }
    }
    clear() {
        this.index = 0;
    }
}
exports.StackBuffer = StackBuffer;
class GFXBuffer extends StackBuffer {
    constructor(capacity, size, location, drawType, content = null) {
        super(capacity, size, content, true);
        this.drawType = drawType;
        this.point(location);
    }
    point(location) {
        this.location = location;
    }
    update() {
        Native.setLength(this.bufferID, this.index);
    }
    getBuffer() { }
}
exports.GFXBuffer = GFXBuffer;
var GlyphStyle;
(function (GlyphStyle) {
    GlyphStyle[GlyphStyle["mono"] = 1] = "mono";
    GlyphStyle[GlyphStyle["sans"] = 2] = "sans";
    GlyphStyle[GlyphStyle["outline"] = 4] = "outline";
})(GlyphStyle = exports.GlyphStyle || (exports.GlyphStyle = {}));
var TextAlign;
(function (TextAlign) {
    TextAlign[TextAlign["left"] = 0] = "left";
    TextAlign[TextAlign["center"] = 1] = "center";
    TextAlign[TextAlign["right"] = 2] = "right";
})(TextAlign = exports.TextAlign || (exports.TextAlign = {}));
const pv2 = gl_matrix_1.vec2.create();
const pv2b = gl_matrix_1.vec2.create();
class Canvas {
    constructor(gfx) {
        this.gfx = gfx;
        this.width = 0;
        this.height = 0;
        this.screenScale = gl_matrix_1.vec3.create();
        this.screenScale4 = gl_matrix_1.vec4.create();
        this.transform = gl_matrix_1.mat4.create();
        this._textAlign = 0;
        this._glyphStyle = 0;
        this._fontSize = 10;
        this._lineWidth = 2;
        this._fillRGBA = gl_matrix_1.vec4.create();
        this._strokeRGBA = gl_matrix_1.vec4.create();
        this.start = gl_matrix_1.vec2.create();
        this.path = [];
        this.lastFill = gl_matrix_1.vec4.fromValues(0, 0, 0, 1);
        this.pipeline = gfx.uiTris;
    }
    resize(w, h) {
        const screenScale = this.screenScale;
        const screenScale4 = this.screenScale4;
        this.width = w;
        this.height = h;
        screenScale[0] = screenScale4[0] = w * 0.5;
        screenScale[1] = screenScale4[1] = -h * 0.5;
        screenScale[2] = screenScale4[2] = -1;
        screenScale4[3] = 1;
        this.lineWidth(2);
    }
    setAlpha(a) {
        this._strokeRGBA[3] = a;
        this._fillRGBA[3] = a;
    }
    lineWidth(w) {
        this._lineWidth = w * 0.5;
    }
    strokeStyle(c) {
        gl_matrix_1.vec4.copy(this._strokeRGBA, c.rgba);
    }
    strokeAlpha(c, a) {
        gl_matrix_1.vec4.copy(this._strokeRGBA, c.rgba);
        this._strokeRGBA[3] = a;
    }
    strokeRGBA(r, g, b, a) {
        gl_matrix_1.vec4.set(this._strokeRGBA, r, g, b, a);
    }
    strokeHSLA(h, s, l, a) {
        color_1.hsla2rgba(this._strokeRGBA, h, s, l, a);
    }
    fillStyle(c) {
        gl_matrix_1.vec4.copy(this._fillRGBA, c.rgba);
    }
    fillAlpha(c, a) {
        gl_matrix_1.vec4.copy(this._fillRGBA, c.rgba);
        this._fillRGBA[3] = a;
    }
    fillRGBA(r, g, b, a) {
        gl_matrix_1.vec4.set(this._fillRGBA, r, g, b, a);
    }
    fillVec4(rgba) {
        gl_matrix_1.vec4.copy(this._fillRGBA, rgba);
    }
    fillHSLA(h, s, l, a) {
        color_1.hsla2rgba(this._fillRGBA, h, s, l, a);
    }
    textAlign(alignment) {
        this._textAlign = alignment;
    }
    style(style) {
        this._glyphStyle = style;
    }
    fontSize(size) {
        this._fontSize = size;
    }
    moveTo(x, y) {
        this.path.length = 0;
        gl_matrix_1.vec2.set(this.start, x, y);
        this.path.push(x, y);
        gl_matrix_1.vec2.set(pv2, x, y);
    }
    lineTo(x, y) {
        this.path.push(x, y);
    }
    closePath() {
        this.path.push(this.start[0], this.start[1]);
    }
    pathRect(x, y, w, h) {
        this.moveTo(x, y);
        this.lineTo(x + w, y);
        this.lineTo(x + w, y + h);
        this.lineTo(x, y + h);
        this.closePath();
    }
    pathPolygon(...path) {
        this.moveTo(path[0], path[1]);
        for (let i = 2; i < path.length; i += 2) {
            this.lineTo(path[i], path[i + 1]);
        }
        this.closePath();
    }
    strokeLine(start, end, z) {
        const pipeline = this.pipeline;
        pipeline.line(start, end, this._lineWidth, z, this._strokeRGBA);
    }
    strokeLine2(start, end, z) {
        const pipeline = this.pipeline;
        pipeline.line(start, end, this._lineWidth, z, this._strokeRGBA);
    }
    stroke() {
        for (let i = 0; i < this.path.length - 2; i = i + 2) {
            gl_matrix_1.vec2.set(pv2, this.path[i], this.path[i + 1]);
            gl_matrix_1.vec2.set(pv2b, this.path[i + 2], this.path[i + 3]);
            this.strokeLine(pv2, pv2b, 0);
        }
    }
    strokeColors(colors) {
        for (let i = 0; i < this.path.length - 2; i = i + 2) {
            const start = pv2;
            const end = pv2b;
            const z = 0;
            const pipeline = this.pipeline;
            gl_matrix_1.vec2.set(pv2, this.path[i], this.path[i + 1]);
            gl_matrix_1.vec2.set(pv2b, this.path[i + 2], this.path[i + 3]);
            pipeline.line2(start, end, this._lineWidth, z, colors.slice(i * 4, i * 4 + 4), colors.slice((i + 1) * 4, (i + 1) * 4 + 4));
        }
    }
    fill() {
        this.pipeline.fill2DPolygon(this.path, 0, this._fillRGBA);
    }
    renderText(text, x, y, color, style, width = 0) {
        const [si, len] = Native.writeString(text);
        if (len === 0) {
            return;
        }
        if (this._textAlign !== TextAlign.left) {
            const w = width === 0
                ? this.measureText(text)
                : Math.min(this.measureText(text), width);
            if (this._textAlign === TextAlign.center) {
                x = x - w / 2;
            }
            else {
                x = x - w;
            }
        }
        if (!gl_matrix_1.vec4.equals(this.lastFill, color)) {
            Native.command(12, color[0], color[1], color[2], color[3]);
            gl_matrix_1.vec4.copy(this.lastFill, color);
        }
        Native.command(10, si, len, x, y, this._fontSize, (this._textAlign << 16) | this._glyphStyle | style, width);
    }
    fillText(text, x, y, w = 0) {
        this.renderText(text, x, y, this._fillRGBA, 0, w);
    }
    strokeText(text, x, y, w = 0) {
        this.renderText(text, x, y, this._strokeRGBA, 4, w);
    }
    drawText(text, x, y, w = 0) {
        this.renderText(text, x, y, this._fillRGBA, 0, w);
        this.renderText(text, x, y, this._strokeRGBA, 4, w);
    }
    roughMeasureText(text) {
        return text.length * (this._fontSize / 32) * 19.39;
    }
    measureText(text) {
        return Native.measureText(text, this._fontSize, this._glyphStyle);
    }
    drawImage(_img, _x, _y, _w, _h) {
    }
    strokeRect(x, y, w, h) {
        this.strokeLine(gl_matrix_1.vec2.set(pv2, x, y), gl_matrix_1.vec2.set(pv2b, x + w, y), 0);
        this.strokeLine(pv2b, gl_matrix_1.vec2.set(pv2, x + w, y + h), 0);
        this.strokeLine(pv2, gl_matrix_1.vec2.set(pv2b, x, y + h), 0);
        this.strokeLine(pv2b, gl_matrix_1.vec2.set(pv2, x, y), 0);
    }
    fillRect(x, y, w, h) {
        this.pathRect(x, y, w, h);
        this.fill();
    }
}
exports.Canvas = Canvas;
class GFX {
    constructor() {
        this.width = 0;
        this.height = 0;
        this.viewport = null;
        this.view = null;
        this.projection = null;
        this.transform = null;
        this.lightTransform = null;
        this.uiTransform = null;
        this.cameraPosition = null;
        this.cameraVector = null;
        this.solid = null;
        this.shadow = null;
        this.deferred = null;
        this.ssao = null;
        this.postDraws = [];
        this.transparent = null;
        this.unculled = null;
        this.pointLights = null;
        this.uiTris = null;
        this.compileShaders = (shaders) => {
            let failed = false;
            for (const [file, source] of shaders) {
                const type = file.endsWith('.vs') ? VERTEX_SHADER : FRAGMENT_SHADER;
                const ok = Native.GL.compileShader(file.slice(0, -3), type === VERTEX_SHADER, source);
                if (!ok) {
                    console.warn('Failed to compile shader on Native:', file, source);
                    engine_1.dbg.log('Shader failed to compile! ' + file);
                }
            }
            if (!Native.GL.checkShaders()) {
                failed = true;
            }
            if (failed) {
                console.log('Shaders failed to compile');
                engine_1.dbg.log('Shaders failed to compile!');
            }
        };
    }
    camera(view, projection, transform, position, _direction, uiTransform) {
        gl_matrix_1.mat4.copy(this.view, view);
        gl_matrix_1.mat4.copy(this.projection, projection);
        gl_matrix_1.mat4.copy(this.transform, transform);
        gl_matrix_1.vec3.copy(this.cameraPosition, position);
        gl_matrix_1.mat4.copy(this.uiTransform, uiTransform);
    }
    setCameraVector(v) {
        gl_matrix_1.vec3.copy(this.cameraVector, v);
    }
    init() {
        const buffers = [];
        console.log('GFX initializing');
        this.compileShaders(shaderFiles);
        let pool = Native.nextPool(Float32Array.BYTES_PER_ELEMENT * 2);
        buffers.push(pool[1]);
        this.viewport = new Float32Array(pool[0]);
        pool = Native.nextPool(Float32Array.BYTES_PER_ELEMENT * 16);
        buffers.push(pool[1]);
        this.view = new Float32Array(pool[0]);
        pool = Native.nextPool(Float32Array.BYTES_PER_ELEMENT * 16);
        buffers.push(pool[1]);
        this.projection = new Float32Array(pool[0]);
        pool = Native.nextPool(Float32Array.BYTES_PER_ELEMENT * 16);
        buffers.push(pool[1]);
        this.transform = new Float32Array(pool[0]);
        pool = Native.nextPool(Float32Array.BYTES_PER_ELEMENT * 16);
        buffers.push(pool[1]);
        this.lightTransform = new Float32Array(pool[0]);
        pool = Native.nextPool(Float32Array.BYTES_PER_ELEMENT * 16);
        buffers.push(pool[1]);
        this.uiTransform = new Float32Array(pool[0]);
        pool = Native.nextPool(Float32Array.BYTES_PER_ELEMENT * 3);
        buffers.push(pool[1]);
        this.cameraPosition = new Float32Array(pool[0]);
        pool = Native.nextPool(Float32Array.BYTES_PER_ELEMENT * 3);
        buffers.push(pool[1]);
        this.cameraVector = new Float32Array(pool[0]);
        this.solid = new SolidPipeline('solid', 'solid', 'solid', this, vertCapacity);
        this.shadow = new ShadowPipeline('shadow', 'shadow', 'shadow', this, vertCapacity);
        this.transparent = new PostDrawPipeline('transparency', 'transparent', 'transparent', this, vertCapacity);
        this.unculled = new UnculledPostDrawPipeline('unculled', 'transparent', 'transparent', this, vertCapacity);
        this.pointLights = new PointLightPipeline('pointlights', 'pointlight', 'pointlight', this, vertCapacity);
        this.postDraws = [this.transparent, this.unculled, this.pointLights];
        this.deferred = new ScreenQuadPipeline('gbuff', 'gbuff', 'gbuff', this);
        this.uiTris = new UITriPipeline('uitris', 'uitri', 'uitri', this, vertCapacity);
        gl_matrix_1.mat4.ortho(this.lightTransform, -325, 325, -150, 150, -300, 150);
        gl_matrix_1.mat4.rotateX(this.lightTransform, this.lightTransform, Math.PI * -0.575);
        this.solid.init();
        this.shadow.init(1 << 12, 1 << 12, this.solid.tris, this.solid.normals);
        for (let i = 0; i < this.postDraws.length; i++) {
            this.postDraws[i].init();
        }
        this.deferred.init();
        this.uiTris.init();
        buffers.push(this.solid.tris.bufferID, this.solid.normals.bufferID, this.solid.diffuse.bufferID, this.solid.ambient.bufferID, this.solid.specular.bufferID, this.shadow.tris.bufferID, this.shadow.normals.bufferID, this.uiTris.tris.bufferID, this.uiTris.rgba.bufferID, this.deferred.tris.bufferID, this.deferred.texCoords.bufferID, this.transparent.tris.bufferID, this.transparent.normals.bufferID, this.transparent.color.bufferID, this.unculled.tris.bufferID, this.unculled.normals.bufferID, this.unculled.color.bufferID, this.pointLights.tris.bufferID, this.pointLights.color.bufferID, this.pointLights.lights.bufferID, this.pointLights.props.bufferID);
        Native.GL.setBuffers(buffers);
        Native.ready();
        this.updateViewport();
    }
    renderFrame() {
        this.solid.update();
        this.uiTris.update();
        for (let i = 0; i < this.postDraws.length; i++) {
            this.postDraws[i].update();
        }
        this.solid.reset();
        this.uiTris.reset();
        for (let i = 0; i < this.postDraws.length; i++) {
            this.postDraws[i].reset();
        }
    }
    updateViewport() {
        this.width = this.viewport[0];
        this.height = this.viewport[1];
    }
}
exports.GFX = GFX;
const updateGraphics = (settings) => {
    settings.antialias = (settings.antialias ?? 1) >> 0;
    settings.shadowQuality = (settings.shadowQuality ?? 2) >> 0;
    settings.ssaoQuality = (settings.ssaoQuality ?? 2) >> 0;
    settings.save();
    Native.setAntialias(settings.antialias);
    Native.setShadowQuality(settings.shadowQuality);
    Native.setSsaoQuality(settings.ssaoQuality);
};
exports.updateGraphics = updateGraphics;
const init = (settings) => {
    const gfx = new GFX();
    global.gfx = gfx;
    gfx.init();
    if (settings.fullscreen === 'Fullscreen') {
        Native.toggleFullscreen();
    }
    exports.updateGraphics(settings);
    return gfx;
};
exports.init = init;
//# sourceMappingURL=gfx.js.map