1/*
2 * Copyright (c) 2023 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 *     http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15
16import { XMat4 } from './XMat4.js';
17import { XShader } from './XShader.js';
18import { Scr } from '../XDefine.js';
19import { XTexture } from './XTexture.js';
20import { gl } from '../GLFrame.js';
21import { fAngle, iDistance } from '../XTools.js';
22
23export class X2DFast {
24  static gi() {
25    if (X2DFast.px2f == null) X2DFast.px2f = new X2DFast();
26    return X2DFast.px2f;
27  }
28
29  constructor() {
30    this.localBuffer = gl.createBuffer();
31    this.texSampleIdx = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
32
33    this.vertexArray = new ArrayBuffer(1024 * 1024 * 4 * 2);
34    this.vertexFloat32 = new Float32Array(this.vertexArray);
35    this.vertexUint32 = new Uint32Array(this.vertexArray);
36    this.whiteImg = XTexture.gi().loadTextureFromImage('CUSTOM_TEXTURE_1');
37    this.whiteCut = XTexture.gi().makeCut(this.whiteImg, 0, 0, 1, 1);
38    XShader.gi();
39
40    this.resetMat();
41  }
42  resetMat() {
43    X2DFast.transform2D.unit();
44    X2DFast.transform2D.orthoMat(0, 0, Scr.logicw, Scr.logich);
45    let tm = X2DFast.transform2D.mat;
46    this.t2dExt = [
47      tm[0][0],
48      tm[1][0],
49      tm[2][0],
50      tm[3][0],
51      tm[0][1],
52      tm[1][1],
53      tm[2][1],
54      tm[3][1],
55      tm[0][2],
56      tm[1][2],
57      tm[2][2],
58      tm[3][2],
59      tm[0][3],
60      tm[1][3],
61      tm[2][3],
62      tm[3][3],
63    ];
64  }
65
66  swapMode2D() {
67    gl.disable(gl.DEPTH_TEST);
68
69    gl.enable(gl.BLEND);
70    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA); // ONE_MINUS_SRC_ALPHA
71    // GL_FUNC_ADD、GL_FUNC_SUBTRACT、GL_FUNC_REVERSE_SUBTRACT、GL_MIN、GL_MAX和GL_LOGIC_OP
72  }
73
74  DrawCircle(ox, oy, rw, rh, c = 0xffffffff, lw = 1) {
75    let lx = -1;
76    let ly = -1;
77    let i = 0;
78    let gap = (Math.PI * 2) / 32;
79    while (i < Math.PI * 2 + 0.00001) {
80      let dx = Math.cos(i) * rw + ox;
81      let dy = Math.sin(i) * rh + oy;
82      if (lx !== -1) {
83        this.drawLine(lx, ly, dx, dy, c, lw);
84      }
85      lx = dx;
86      ly = dy;
87      i += gap;
88    }
89  }
90
91  fillRect(x, y, w, h, c = 0xffffffff) {
92    this.drawCut(this.whiteCut, x, y, w, h, 0, 0, 0, c);
93  }
94
95  drawLine(x1, y1, x2, y2, c = 0xffffffff, linewidth = 1) {
96    x1 = parseInt(x1);
97    y1 = parseInt(y1);
98    x2 = parseInt(x2);
99    y2 = parseInt(y2);
100    this.drawCut(
101      this.whiteCut,
102      x1,
103      y1,
104      iDistance(x1 - x2, y1 - y2),
105      linewidth,
106      fAngle(x2 - x1, y2 - y1),
107      0,
108      0, // +0.5
109      c
110    );
111  }
112
113  drawRect(x, y, w, h, c = 0xffffffff, lw = 1) {
114    this.drawLine(x - lw / 2, y, x + w + lw / 2, y, c, lw);
115    this.drawLine(x, y, x, y + h, c, lw);
116    this.drawLine(x + w, y + h, x + w, y, c, lw);
117    this.drawLine(x + w + lw / 2, y + h, x - lw / 2, y + h, c, lw);
118  }
119
120  static testTransform(x, y, sw, sh, ra, ox, oy, realw, realh) {
121    X2DFast.tmpMat.unit();
122    if (ox === -1) ox = 0;
123    if (ox === -2) ox = Math.floor(realw / 2);
124    if (ox === -3) ox = realw;
125    if (oy === -1) oy = 0;
126    if (oy === -2) oy = Math.floor(realh / 2);
127    if (oy === -3) oy = realh;
128    if (ox !== 0 || oy !== 0) X2DFast.tmpMat.move(-ox, -oy, 0);
129    if (sw !== 1 || sh !== 1) X2DFast.tmpMat.scale(sw, sh, 1);
130    if (ra !== 0) X2DFast.tmpMat.rotate(0, 0, ra);
131    if (x !== 0 || y !== 0) X2DFast.tmpMat.move(x, y, 0);
132  }
133  clearBuffer() {
134    this.ridDict = {};
135    this.ridPoint = 0;
136    this.drawCount = 0;
137  }
138  swapC(c) {
139    let r;
140    let g;
141    let b;
142    let a;
143    if (isNaN(c)) {
144      r = Math.floor(c[0] * 63 / 255);
145      g = Math.floor(c[1] * 63 / 255);
146      b = Math.floor(c[2] * 63 / 255);
147      a = Math.floor(c[3] * 63 / 255);
148    }
149    else {
150      if (c === -1) {
151        c = 0xffffffff;
152      }
153      r = Math.floor((((c >> 16) & 0xff) * 63) / 255);
154      g = Math.floor((((c >> 8) & 0xff) * 63) / 255);
155      b = Math.floor(((c & 0xff) * 63) / 255);
156      a = Math.floor((((c >> 24) & 0xff) * 63) / 255);
157    }
158    return ((a * 64 + r) * 64 + g) * 64 + b + 0.1;
159  }
160  drawCut_(pcut, m00, m01, m10, m11, m22, m30, m31, c = 0xffffffff) {
161    c = this.swapC(c);
162    this.vertexFloat32.set([0.0, 0.0, 0.0, pcut.u0, pcut.v0, m00, m01, m10, m11, m22, m30, m31,
163      this.ridDict[pcut.rid], c,
164      pcut.w, 0.0, 0.0, pcut.u1, pcut.v1, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,
165      pcut.w, pcut.h, 0.0, pcut.u2, pcut.v2, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,
166      0.0, 0.0, 0.0, pcut.u0, pcut.v0, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,
167      pcut.w, pcut.h, 0.0, pcut.u2, pcut.v2, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,
168      0.0, pcut.h, 0.0, pcut.u3, pcut.v3, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,],
169      this.drawCount * 14 * 6);
170    this.drawCount += 1;
171  }
172  drawCutEx(cid, tmat, c = 0xffffffff) {
173    let pcut = XTexture.pinstance_.allCuts[cid];
174    if (!(pcut.rid in this.ridDict)) {
175      this.ridDict[pcut.rid] = this.ridPoint;
176      this.ridPoint += 1;
177    }
178    tmat = tmat.mat;
179    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);
180  }
181  drawCut(cid, x = 0, y = 0, sw = 1, sh = 1, ra = 0, ox = 0, oy = 0, c = 0xffffffff) {
182    let intX = parseInt(x);
183    let intY = parseInt(y);
184    let pcut = XTexture.gi().allCuts[cid];
185    if (pcut === null) return;
186    if (!(pcut.rid in this.ridDict)) {
187      if (this.ridPoint >= 16) {
188        this.freshBuffer();
189        this.clearBuffer();
190      }
191      this.ridDict[pcut.rid] = this.ridPoint;
192      this.ridPoint += 1;
193    }
194    X2DFast.testTransform(intX, intY, sw, sh, ra, ox, oy, pcut.w, pcut.h);
195    let tmat = X2DFast.tmpMat.mat;
196    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);
197  }
198  drawText(s, size = 14, x = 0, y = 0, sw = 1, sh = 1, ra = 0, ox = 0, oy = 0, c = 0xffffffff) {
199    if (s.length <= 0) return 0;
200    let cid = XTexture.gi().getText(s, size);
201    if (cid >= 0) this.drawCut(cid, x, y, sw, sh, ra, ox, oy, c);
202    return XTexture.gi().allCuts[cid].w;
203  }
204  getTextWidth(s, size) {
205    if (s.length <= 0) return 0;
206    let cid = XTexture.gi().getText(s, size);
207    return XTexture.gi().allCuts[cid].w;
208  }
209  freshBuffer() {
210    XTexture.gi()._FreshText();
211    if (this.drawCount === 0) return;
212    let ps = XShader.gi().use(XShader.ID_SHADER_FAST);
213    for (let rid in this.ridDict) {
214      gl.activeTexture(gl.TEXTURE0 + this.ridDict[rid]);
215      gl.bindTexture(gl.TEXTURE_2D, XTexture.gi().ximages[rid].tex);
216
217      gl.uniform1i(ps.tex[this.ridDict[rid]], this.ridDict[rid]);
218    }
219
220    gl.uniformMatrix4fv(ps.uMat, false, this.t2dExt);
221
222    gl.bindBuffer(gl.ARRAY_BUFFER, this.localBuffer);
223    gl.bufferData(gl.ARRAY_BUFFER, this.vertexArray, gl.STATIC_DRAW);
224    gl.vertexAttribPointer(ps.position, 3, gl.FLOAT, false, 4 * 14, 0);
225    gl.enableVertexAttribArray(ps.position);
226    gl.vertexAttribPointer(ps.aTexCoord, 2, gl.FLOAT, false, 4 * 14, 4 * 3);
227    gl.enableVertexAttribArray(ps.aTexCoord);
228    gl.vertexAttribPointer(ps.ext1, 4, gl.FLOAT, false, 4 * 14, 4 * 5);
229    gl.enableVertexAttribArray(ps.ext1);
230    gl.vertexAttribPointer(ps.ext2, 4, gl.FLOAT, false, 4 * 14, 4 * 9);
231    gl.enableVertexAttribArray(ps.ext2);
232    gl.vertexAttribPointer(ps.inColor, 1, gl.FLOAT, false, 4 * 14, 4 * 13);
233    gl.enableVertexAttribArray(ps.inColor);
234
235    gl.drawArrays(gl.TRIANGLES, 0, 6 * this.drawCount);
236  }
237}
238X2DFast.tmpMat = new XMat4();
239X2DFast.transform2D = new XMat4();
240
241X2DFast.px2f = null;
242