14514f5e3Sopenharmony_ci/*
24514f5e3Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd.
34514f5e3Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License");
44514f5e3Sopenharmony_ci * you may not use this file except in compliance with the License.
54514f5e3Sopenharmony_ci * You may obtain a copy of the License at
64514f5e3Sopenharmony_ci *
74514f5e3Sopenharmony_ci *     http://www.apache.org/licenses/LICENSE-2.0
84514f5e3Sopenharmony_ci *
94514f5e3Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software
104514f5e3Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS,
114514f5e3Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
124514f5e3Sopenharmony_ci * See the License for the specific language governing permissions and
134514f5e3Sopenharmony_ci * limitations under the License.
144514f5e3Sopenharmony_ci */
154514f5e3Sopenharmony_ci
164514f5e3Sopenharmony_ciimport { XMat4 } from './XMat4.js';
174514f5e3Sopenharmony_ciimport { XShader } from './XShader.js';
184514f5e3Sopenharmony_ciimport { Scr } from '../XDefine.js';
194514f5e3Sopenharmony_ciimport { XTexture } from './XTexture.js';
204514f5e3Sopenharmony_ciimport { gl } from '../GLFrame.js';
214514f5e3Sopenharmony_ciimport { fAngle, iDistance } from '../XTools.js';
224514f5e3Sopenharmony_ci
234514f5e3Sopenharmony_ciexport class X2DFast {
244514f5e3Sopenharmony_ci  static gi() {
254514f5e3Sopenharmony_ci    if (X2DFast.px2f == null) X2DFast.px2f = new X2DFast();
264514f5e3Sopenharmony_ci    return X2DFast.px2f;
274514f5e3Sopenharmony_ci  }
284514f5e3Sopenharmony_ci
294514f5e3Sopenharmony_ci  constructor() {
304514f5e3Sopenharmony_ci    this.localBuffer = gl.createBuffer();
314514f5e3Sopenharmony_ci    this.texSampleIdx = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
324514f5e3Sopenharmony_ci
334514f5e3Sopenharmony_ci    this.vertexArray = new ArrayBuffer(1024 * 1024 * 4 * 2);
344514f5e3Sopenharmony_ci    this.vertexFloat32 = new Float32Array(this.vertexArray);
354514f5e3Sopenharmony_ci    this.vertexUint32 = new Uint32Array(this.vertexArray);
364514f5e3Sopenharmony_ci    this.whiteImg = XTexture.gi().loadTextureFromImage('CUSTOM_TEXTURE_1');
374514f5e3Sopenharmony_ci    this.whiteCut = XTexture.gi().makeCut(this.whiteImg, 0, 0, 1, 1);
384514f5e3Sopenharmony_ci    XShader.gi();
394514f5e3Sopenharmony_ci
404514f5e3Sopenharmony_ci    this.resetMat();
414514f5e3Sopenharmony_ci  }
424514f5e3Sopenharmony_ci  resetMat() {
434514f5e3Sopenharmony_ci    X2DFast.transform2D.unit();
444514f5e3Sopenharmony_ci    X2DFast.transform2D.orthoMat(0, 0, Scr.logicw, Scr.logich);
454514f5e3Sopenharmony_ci    let tm = X2DFast.transform2D.mat;
464514f5e3Sopenharmony_ci    this.t2dExt = [
474514f5e3Sopenharmony_ci      tm[0][0],
484514f5e3Sopenharmony_ci      tm[1][0],
494514f5e3Sopenharmony_ci      tm[2][0],
504514f5e3Sopenharmony_ci      tm[3][0],
514514f5e3Sopenharmony_ci      tm[0][1],
524514f5e3Sopenharmony_ci      tm[1][1],
534514f5e3Sopenharmony_ci      tm[2][1],
544514f5e3Sopenharmony_ci      tm[3][1],
554514f5e3Sopenharmony_ci      tm[0][2],
564514f5e3Sopenharmony_ci      tm[1][2],
574514f5e3Sopenharmony_ci      tm[2][2],
584514f5e3Sopenharmony_ci      tm[3][2],
594514f5e3Sopenharmony_ci      tm[0][3],
604514f5e3Sopenharmony_ci      tm[1][3],
614514f5e3Sopenharmony_ci      tm[2][3],
624514f5e3Sopenharmony_ci      tm[3][3],
634514f5e3Sopenharmony_ci    ];
644514f5e3Sopenharmony_ci  }
654514f5e3Sopenharmony_ci
664514f5e3Sopenharmony_ci  swapMode2D() {
674514f5e3Sopenharmony_ci    gl.disable(gl.DEPTH_TEST);
684514f5e3Sopenharmony_ci
694514f5e3Sopenharmony_ci    gl.enable(gl.BLEND);
704514f5e3Sopenharmony_ci    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); // ONE_MINUS_SRC_ALPHA
714514f5e3Sopenharmony_ci    // GL_FUNC_ADD、GL_FUNC_SUBTRACT、GL_FUNC_REVERSE_SUBTRACT、GL_MIN、GL_MAX和GL_LOGIC_OP
724514f5e3Sopenharmony_ci  }
734514f5e3Sopenharmony_ci
744514f5e3Sopenharmony_ci  DrawCircle(ox, oy, rw, rh, c = 0xffffffff, lw = 1) {
754514f5e3Sopenharmony_ci    let lx = -1;
764514f5e3Sopenharmony_ci    let ly = -1;
774514f5e3Sopenharmony_ci    let i = 0;
784514f5e3Sopenharmony_ci    let gap = (Math.PI * 2) / 32;
794514f5e3Sopenharmony_ci    while (i < Math.PI * 2 + 0.00001) {
804514f5e3Sopenharmony_ci      let dx = Math.cos(i) * rw + ox;
814514f5e3Sopenharmony_ci      let dy = Math.sin(i) * rh + oy;
824514f5e3Sopenharmony_ci      if (lx !== -1) {
834514f5e3Sopenharmony_ci        this.drawLine(lx, ly, dx, dy, c, lw);
844514f5e3Sopenharmony_ci      }
854514f5e3Sopenharmony_ci      lx = dx;
864514f5e3Sopenharmony_ci      ly = dy;
874514f5e3Sopenharmony_ci      i += gap;
884514f5e3Sopenharmony_ci    }
894514f5e3Sopenharmony_ci  }
904514f5e3Sopenharmony_ci
914514f5e3Sopenharmony_ci  fillRect(x, y, w, h, c = 0xffffffff) {
924514f5e3Sopenharmony_ci    this.drawCut(this.whiteCut, x, y, w, h, 0, 0, 0, c);
934514f5e3Sopenharmony_ci  }
944514f5e3Sopenharmony_ci
954514f5e3Sopenharmony_ci  drawLine(x1, y1, x2, y2, c = 0xffffffff, linewidth = 1) {
964514f5e3Sopenharmony_ci    x1 = parseInt(x1);
974514f5e3Sopenharmony_ci    y1 = parseInt(y1);
984514f5e3Sopenharmony_ci    x2 = parseInt(x2);
994514f5e3Sopenharmony_ci    y2 = parseInt(y2);
1004514f5e3Sopenharmony_ci    this.drawCut(
1014514f5e3Sopenharmony_ci      this.whiteCut,
1024514f5e3Sopenharmony_ci      x1,
1034514f5e3Sopenharmony_ci      y1,
1044514f5e3Sopenharmony_ci      iDistance(x1 - x2, y1 - y2),
1054514f5e3Sopenharmony_ci      linewidth,
1064514f5e3Sopenharmony_ci      fAngle(x2 - x1, y2 - y1),
1074514f5e3Sopenharmony_ci      0,
1084514f5e3Sopenharmony_ci      0, // +0.5
1094514f5e3Sopenharmony_ci      c
1104514f5e3Sopenharmony_ci    );
1114514f5e3Sopenharmony_ci  }
1124514f5e3Sopenharmony_ci
1134514f5e3Sopenharmony_ci  drawRect(x, y, w, h, c = 0xffffffff, lw = 1) {
1144514f5e3Sopenharmony_ci    this.drawLine(x - lw / 2, y, x + w + lw / 2, y, c, lw);
1154514f5e3Sopenharmony_ci    this.drawLine(x, y, x, y + h, c, lw);
1164514f5e3Sopenharmony_ci    this.drawLine(x + w, y + h, x + w, y, c, lw);
1174514f5e3Sopenharmony_ci    this.drawLine(x + w + lw / 2, y + h, x - lw / 2, y + h, c, lw);
1184514f5e3Sopenharmony_ci  }
1194514f5e3Sopenharmony_ci
1204514f5e3Sopenharmony_ci  static testTransform(x, y, sw, sh, ra, ox, oy, realw, realh) {
1214514f5e3Sopenharmony_ci    X2DFast.tmpMat.unit();
1224514f5e3Sopenharmony_ci    if (ox === -1) ox = 0;
1234514f5e3Sopenharmony_ci    if (ox === -2) ox = Math.floor(realw / 2);
1244514f5e3Sopenharmony_ci    if (ox === -3) ox = realw;
1254514f5e3Sopenharmony_ci    if (oy === -1) oy = 0;
1264514f5e3Sopenharmony_ci    if (oy === -2) oy = Math.floor(realh / 2);
1274514f5e3Sopenharmony_ci    if (oy === -3) oy = realh;
1284514f5e3Sopenharmony_ci    if (ox !== 0 || oy !== 0) X2DFast.tmpMat.move(-ox, -oy, 0);
1294514f5e3Sopenharmony_ci    if (sw !== 1 || sh !== 1) X2DFast.tmpMat.scale(sw, sh, 1);
1304514f5e3Sopenharmony_ci    if (ra !== 0) X2DFast.tmpMat.rotate(0, 0, ra);
1314514f5e3Sopenharmony_ci    if (x !== 0 || y !== 0) X2DFast.tmpMat.move(x, y, 0);
1324514f5e3Sopenharmony_ci  }
1334514f5e3Sopenharmony_ci  clearBuffer() {
1344514f5e3Sopenharmony_ci    this.ridDict = {};
1354514f5e3Sopenharmony_ci    this.ridPoint = 0;
1364514f5e3Sopenharmony_ci    this.drawCount = 0;
1374514f5e3Sopenharmony_ci  }
1384514f5e3Sopenharmony_ci  swapC(c) {
1394514f5e3Sopenharmony_ci    let r;
1404514f5e3Sopenharmony_ci    let g;
1414514f5e3Sopenharmony_ci    let b;
1424514f5e3Sopenharmony_ci    let a;
1434514f5e3Sopenharmony_ci    if (isNaN(c)) {
1444514f5e3Sopenharmony_ci      r = Math.floor(c[0] * 63 / 255);
1454514f5e3Sopenharmony_ci      g = Math.floor(c[1] * 63 / 255);
1464514f5e3Sopenharmony_ci      b = Math.floor(c[2] * 63 / 255);
1474514f5e3Sopenharmony_ci      a = Math.floor(c[3] * 63 / 255);
1484514f5e3Sopenharmony_ci    }
1494514f5e3Sopenharmony_ci    else {
1504514f5e3Sopenharmony_ci      if (c === -1) {
1514514f5e3Sopenharmony_ci        c = 0xffffffff;
1524514f5e3Sopenharmony_ci      }
1534514f5e3Sopenharmony_ci      r = Math.floor((((c >> 16) & 0xff) * 63) / 255);
1544514f5e3Sopenharmony_ci      g = Math.floor((((c >> 8) & 0xff) * 63) / 255);
1554514f5e3Sopenharmony_ci      b = Math.floor(((c & 0xff) * 63) / 255);
1564514f5e3Sopenharmony_ci      a = Math.floor((((c >> 24) & 0xff) * 63) / 255);
1574514f5e3Sopenharmony_ci    }
1584514f5e3Sopenharmony_ci    return ((a * 64 + r) * 64 + g) * 64 + b + 0.1;
1594514f5e3Sopenharmony_ci  }
1604514f5e3Sopenharmony_ci  drawCut_(pcut, m00, m01, m10, m11, m22, m30, m31, c = 0xffffffff) {
1614514f5e3Sopenharmony_ci    c = this.swapC(c);
1624514f5e3Sopenharmony_ci    this.vertexFloat32.set([0.0, 0.0, 0.0, pcut.u0, pcut.v0, m00, m01, m10, m11, m22, m30, m31,
1634514f5e3Sopenharmony_ci      this.ridDict[pcut.rid], c,
1644514f5e3Sopenharmony_ci      pcut.w, 0.0, 0.0, pcut.u1, pcut.v1, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,
1654514f5e3Sopenharmony_ci      pcut.w, pcut.h, 0.0, pcut.u2, pcut.v2, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,
1664514f5e3Sopenharmony_ci      0.0, 0.0, 0.0, pcut.u0, pcut.v0, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,
1674514f5e3Sopenharmony_ci      pcut.w, pcut.h, 0.0, pcut.u2, pcut.v2, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,
1684514f5e3Sopenharmony_ci      0.0, pcut.h, 0.0, pcut.u3, pcut.v3, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,],
1694514f5e3Sopenharmony_ci      this.drawCount * 14 * 6);
1704514f5e3Sopenharmony_ci    this.drawCount += 1;
1714514f5e3Sopenharmony_ci  }
1724514f5e3Sopenharmony_ci  drawCutEx(cid, tmat, c = 0xffffffff) {
1734514f5e3Sopenharmony_ci    let pcut = XTexture.pinstance_.allCuts[cid];
1744514f5e3Sopenharmony_ci    if (!(pcut.rid in this.ridDict)) {
1754514f5e3Sopenharmony_ci      this.ridDict[pcut.rid] = this.ridPoint;
1764514f5e3Sopenharmony_ci      this.ridPoint += 1;
1774514f5e3Sopenharmony_ci    }
1784514f5e3Sopenharmony_ci    tmat = tmat.mat;
1794514f5e3Sopenharmony_ci    this.drawCut(pcut, tmat[0][0], tmat[0][1], tmat[1][0], tmat[1][1], tmat[2][2], tmat[3][0], tmat[3][1], c);
1804514f5e3Sopenharmony_ci  }
1814514f5e3Sopenharmony_ci  drawCut(cid, x = 0, y = 0, sw = 1, sh = 1, ra = 0, ox = 0, oy = 0, c = 0xffffffff) {
1824514f5e3Sopenharmony_ci    let intX = parseInt(x);
1834514f5e3Sopenharmony_ci    let intY = parseInt(y);
1844514f5e3Sopenharmony_ci    let pcut = XTexture.gi().allCuts[cid];
1854514f5e3Sopenharmony_ci    if (pcut === null) return;
1864514f5e3Sopenharmony_ci    if (!(pcut.rid in this.ridDict)) {
1874514f5e3Sopenharmony_ci      if (this.ridPoint >= 16) {
1884514f5e3Sopenharmony_ci        this.freshBuffer();
1894514f5e3Sopenharmony_ci        this.clearBuffer();
1904514f5e3Sopenharmony_ci      }
1914514f5e3Sopenharmony_ci      this.ridDict[pcut.rid] = this.ridPoint;
1924514f5e3Sopenharmony_ci      this.ridPoint += 1;
1934514f5e3Sopenharmony_ci    }
1944514f5e3Sopenharmony_ci    X2DFast.testTransform(intX, intY, sw, sh, ra, ox, oy, pcut.w, pcut.h);
1954514f5e3Sopenharmony_ci    let tmat = X2DFast.tmpMat.mat;
1964514f5e3Sopenharmony_ci    this.drawCut_(pcut, tmat[0][0], tmat[0][1], tmat[1][0], tmat[1][1], tmat[2][2], tmat[3][0], tmat[3][1], c);
1974514f5e3Sopenharmony_ci  }
1984514f5e3Sopenharmony_ci  drawText(s, size = 14, x = 0, y = 0, sw = 1, sh = 1, ra = 0, ox = 0, oy = 0, c = 0xffffffff) {
1994514f5e3Sopenharmony_ci    if (s.length <= 0) return 0;
2004514f5e3Sopenharmony_ci    let cid = XTexture.gi().getText(s, size);
2014514f5e3Sopenharmony_ci    if (cid >= 0) this.drawCut(cid, x, y, sw, sh, ra, ox, oy, c);
2024514f5e3Sopenharmony_ci    return XTexture.gi().allCuts[cid].w;
2034514f5e3Sopenharmony_ci  }
2044514f5e3Sopenharmony_ci  getTextWidth(s, size) {
2054514f5e3Sopenharmony_ci    if (s.length <= 0) return 0;
2064514f5e3Sopenharmony_ci    let cid = XTexture.gi().getText(s, size);
2074514f5e3Sopenharmony_ci    return XTexture.gi().allCuts[cid].w;
2084514f5e3Sopenharmony_ci  }
2094514f5e3Sopenharmony_ci  freshBuffer() {
2104514f5e3Sopenharmony_ci    XTexture.gi()._FreshText();
2114514f5e3Sopenharmony_ci    if (this.drawCount === 0) return;
2124514f5e3Sopenharmony_ci    let ps = XShader.gi().use(XShader.ID_SHADER_FAST);
2134514f5e3Sopenharmony_ci    for (let rid in this.ridDict) {
2144514f5e3Sopenharmony_ci      gl.activeTexture(gl.TEXTURE0 + this.ridDict[rid]);
2154514f5e3Sopenharmony_ci      gl.bindTexture(gl.TEXTURE_2D, XTexture.gi().ximages[rid].tex);
2164514f5e3Sopenharmony_ci
2174514f5e3Sopenharmony_ci      gl.uniform1i(ps.tex[this.ridDict[rid]], this.ridDict[rid]);
2184514f5e3Sopenharmony_ci    }
2194514f5e3Sopenharmony_ci
2204514f5e3Sopenharmony_ci    gl.uniformMatrix4fv(ps.uMat, false, this.t2dExt);
2214514f5e3Sopenharmony_ci
2224514f5e3Sopenharmony_ci    gl.bindBuffer(gl.ARRAY_BUFFER, this.localBuffer);
2234514f5e3Sopenharmony_ci    gl.bufferData(gl.ARRAY_BUFFER, this.vertexArray, gl.STATIC_DRAW);
2244514f5e3Sopenharmony_ci    gl.vertexAttribPointer(ps.position, 3, gl.FLOAT, false, 4 * 14, 0);
2254514f5e3Sopenharmony_ci    gl.enableVertexAttribArray(ps.position);
2264514f5e3Sopenharmony_ci    gl.vertexAttribPointer(ps.aTexCoord, 2, gl.FLOAT, false, 4 * 14, 4 * 3);
2274514f5e3Sopenharmony_ci    gl.enableVertexAttribArray(ps.aTexCoord);
2284514f5e3Sopenharmony_ci    gl.vertexAttribPointer(ps.ext1, 4, gl.FLOAT, false, 4 * 14, 4 * 5);
2294514f5e3Sopenharmony_ci    gl.enableVertexAttribArray(ps.ext1);
2304514f5e3Sopenharmony_ci    gl.vertexAttribPointer(ps.ext2, 4, gl.FLOAT, false, 4 * 14, 4 * 9);
2314514f5e3Sopenharmony_ci    gl.enableVertexAttribArray(ps.ext2);
2324514f5e3Sopenharmony_ci    gl.vertexAttribPointer(ps.inColor, 1, gl.FLOAT, false, 4 * 14, 4 * 13);
2334514f5e3Sopenharmony_ci    gl.enableVertexAttribArray(ps.inColor);
2344514f5e3Sopenharmony_ci
2354514f5e3Sopenharmony_ci    gl.drawArrays(gl.TRIANGLES, 0, 6 * this.drawCount);
2364514f5e3Sopenharmony_ci  }
2374514f5e3Sopenharmony_ci}
2384514f5e3Sopenharmony_ciX2DFast.tmpMat = new XMat4();
2394514f5e3Sopenharmony_ciX2DFast.transform2D = new XMat4();
2404514f5e3Sopenharmony_ci
2414514f5e3Sopenharmony_ciX2DFast.px2f = null;
242