1/*
2 * Copyright (c) 2022-2023 Shenzhen Kaihong Digital Industry Development 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';
22const { NapiLog } = require('./../../hcs/NapiLog');
23const COLOR = 0xffffffff;
24const DRAWTEXT_SIZE = 14;
25
26export class X2DFast {
27  static gi() {
28    if (X2DFast.px2f === null) {
29      X2DFast.px2f = new X2DFast();
30    }
31    return X2DFast.px2f;
32  }
33
34  constructor() {
35    this.localBuffer = gl.createBuffer();
36    this.texSampleIdx = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15];
37
38    this.vertexArray = new ArrayBuffer(1024 * 1024 * 4 * 2);
39    this.vertexFloat32 = new Float32Array(this.vertexArray);
40    this.vertexUint32 = new Uint32Array(this.vertexArray);
41    this.whiteImg = XTexture.gi().loadTextureFromImage('CUSTOM_TEXTURE_1');
42    this.whiteCut = XTexture.gi().makeCut(this.whiteImg, 0, 0, 1, 1);
43    XShader.gi();
44
45    this.resetMat();
46  }
47  resetMat() {
48    X2DFast.transform2D.unit();
49    X2DFast.transform2D.orthoMat(0, 0, Scr.logicw, Scr.logich);
50    let tm = X2DFast.transform2D.mat;
51    this.t2dExt = [
52      tm[0][0],
53      tm[1][0],
54      tm[2][0],
55      tm[3][0],
56      tm[0][1],
57      tm[1][1],
58      tm[2][1],
59      tm[3][1],
60      tm[0][2],
61      tm[1][2],
62      tm[2][2],
63      tm[3][2],
64      tm[0][3],
65      tm[1][3],
66      tm[2][3],
67      tm[3][3],
68    ];
69  }
70
71  swapMode2D() {
72    gl.disable(gl.DEPTH_TEST);
73
74    gl.enable(gl.BLEND);
75    gl.blendFunc(gl.SRC_ALPHA, gl.ONE_MINUS_SRC_ALPHA);
76  }
77
78  DrawCircle(ox, oy, rw, rh, c = 0xffffffff, lw = 1) {
79    let lx = -1;
80    let ly = -1;
81    let i = 0;
82    let gap = (Math.PI * 2) / 32;
83    while (i < Math.PI * 2 + 0.00001) {
84      let dx = Math.cos(i) * rw + ox;
85      let dy = Math.sin(i) * rh + oy;
86      if (lx !== -1) {
87        this.drawLine(lx, ly, dx, dy, c, lw);
88      }
89      lx = dx;
90      ly = dy;
91      i += gap;
92    }
93  }
94
95  fillRect(x, y, w, h, c = 0xffffffff) {
96    this.drawCut(this.whiteCut, x, y, w, h, 0, 0, 0, c);
97  }
98
99  drawLine(x1, y1, x2, y2, c = 0xffffffff, linewidth = 1) {
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.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    const LEFT = -1;
122    const MIDDLE = -2;
123    const RIGHT = -3;
124    const UP = -1;
125    const DOWN = -3;
126    const BY_MIDDLE = 2;
127    X2DFast.tmpMat.unit();
128    if (ox === LEFT) {
129      ox = 0;
130    }
131    if (ox === MIDDLE) {
132      ox = Math.floor(realw / BY_MIDDLE);
133    }
134    if (ox === RIGHT) {
135      ox = realw;
136    }
137    if (oy === UP) {
138      oy = 0;
139    }
140    if (oy === MIDDLE) {
141      oy = Math.floor(realh / BY_MIDDLE);
142    }
143    if (oy === DOWN) {
144      oy = realh;
145    }
146    if (ox !== 0 || oy !== 0) {
147      X2DFast.tmpMat.move(-ox, -oy, 0);
148    }
149    if (sw !== 1 || sh !== 1) {
150      X2DFast.tmpMat.scale(sw, sh, 1);
151    }
152    if (ra !== 0) {
153      X2DFast.tmpMat.rotate(0, 0, ra);
154    }
155    if (x !== 0 || y !== 0) {
156      X2DFast.tmpMat.move(x, y, 0);
157    }
158  }
159  clearBuffer() {
160    this.ridDict = {};
161    this.ridPoint = 0;
162    this.drawCount = 0;
163  }
164  swapC(c) {
165    let r = Math.floor((((c >> 16) & 0xff) * 63) / 255);
166    let g = Math.floor((((c >> 8) & 0xff) * 63) / 255);
167    let b = Math.floor(((c & 0xff) * 63) / 255);
168    let a = Math.floor((((c >> 24) & 0xff) * 63) / 255);
169    return ((a * 64 + r) * 64 + g) * 64 + b;
170  }
171  drawCut_(pcut, m00, m01, m10, m11, m22, m30, m31, c = COLOR) {
172    if (c === -1) {
173      c = COLOR;
174    }
175    c = this.swapC(c);
176    this.vertexFloat32.set([0.0, 0.0, 0.0, pcut.u0, pcut.v0, m00, m01, m10, m11, m22, m30, m31,
177      this.ridDict[pcut.rid], c,
178        pcut.w, 0.0, 0.0, pcut.u1, pcut.v1, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,
179        pcut.w, pcut.h, 0.0, pcut.u2, pcut.v2, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,
180        0.0, 0.0, 0.0, pcut.u0, pcut.v0, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,
181        pcut.w, pcut.h, 0.0, pcut.u2, pcut.v2, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,
182      0.0, pcut.h, 0.0, pcut.u3, pcut.v3, m00, m01, m10, m11, m22, m30, m31, this.ridDict[pcut.rid], c,],
183    this.drawCount * 14 * 6);
184    this.drawCount += 1;
185  }
186  drawCutEx(cid, tmat, c = COLOR) {
187    let pcut = XTexture.pinstance_.allCuts[cid];
188    if (!(pcut.rid in this.ridDict)) {
189      this.ridDict[pcut.rid] = this.ridPoint;
190      this.ridPoint += 1;
191    }
192    tmat = tmat.mat;
193    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);
194  }
195  drawCut(cid, x = 0, y = 0, sw = 1, sh = 1, ra = 0, ox = 0, oy = 0, c = COLOR) {
196    let intX = parseInt(x);
197    let intY = parseInt(y);
198    let pcut = XTexture.gi().allCuts[cid];
199    if (pcut === null) {
200      NapiLog.logError('error occured getting object');
201      return;
202    }
203    if (!(pcut.rid in this.ridDict)) {
204      if (this.ridPoint >= 16) {
205        this.freshBuffer();
206        this.clearBuffer();
207      }
208      this.ridDict[pcut.rid] = this.ridPoint;
209      this.ridPoint += 1;
210    }
211    X2DFast.testTransform(intX, intY, sw, sh, ra, ox, oy, pcut.w, pcut.h);
212    let tmat = X2DFast.tmpMat.mat;
213    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);
214  }
215  drawText(s, size = DRAWTEXT_SIZE, x = 0, y = 0, sw = 1, sh = 1, ra = 0, ox = 0, oy = 0, c = COLOR) {
216    if (s.length <= 0) {
217      NapiLog.logError('error occured s is null');
218      return 0;
219    }
220    let cid = XTexture.gi().getText(s, size);
221    if (cid >= 0) {
222      this.drawCut(cid, x, y, sw, sh, ra, ox, oy, c);
223    }
224    return XTexture.gi().allCuts[cid].w;
225  }
226  getTextWidth(s, size) {
227    if (s.length <= 0) {
228      return 0;
229    }
230    let cid = XTexture.gi().getText(s, size);
231    return XTexture.gi().allCuts[cid].w;
232  }
233  freshBuffer() {
234    XTexture.gi()._FreshText();
235    if (this.drawCount === 0) {
236      return;
237    }
238    let ps = XShader.gi().use(XShader.ID_SHADER_FAST);
239    for (let rid in this.ridDict) {
240      gl.activeTexture(gl.TEXTURE0 + this.ridDict[rid]);
241      gl.bindTexture(gl.TEXTURE_2D, XTexture.gi().ximages[rid].tex);
242
243      gl.uniform1i(ps.tex[this.ridDict[rid]], this.ridDict[rid]);
244    }
245
246    gl.uniformMatrix4fv(ps.uMat, false, this.t2dExt);
247
248    gl.bindBuffer(gl.ARRAY_BUFFER, this.localBuffer);
249    gl.bufferData(gl.ARRAY_BUFFER, this.vertexArray, gl.STATIC_DRAW);
250    gl.vertexAttribPointer(ps.position, 3, gl.FLOAT, false, 4 * 14, 0);
251    gl.enableVertexAttribArray(ps.position);
252    gl.vertexAttribPointer(ps.aTexCoord, 2, gl.FLOAT, false, 4 * 14, 4 * 3);
253    gl.enableVertexAttribArray(ps.aTexCoord);
254    gl.vertexAttribPointer(ps.ext1, 4, gl.FLOAT, false, 4 * 14, 4 * 5);
255    gl.enableVertexAttribArray(ps.ext1);
256    gl.vertexAttribPointer(ps.ext2, 4, gl.FLOAT, false, 4 * 14, 4 * 9);
257    gl.enableVertexAttribArray(ps.ext2);
258    gl.vertexAttribPointer(ps.inColor, 1, gl.FLOAT, false, 4 * 14, 4 * 13);
259    gl.enableVertexAttribArray(ps.inColor);
260
261    gl.drawArrays(gl.TRIANGLES, 0, 6 * this.drawCount);
262  }
263}
264X2DFast.tmpMat = new XMat4();
265X2DFast.transform2D = new XMat4();
266
267X2DFast.px2f = null;
268