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 { gl } from '../GLFrame.js';
174514f5e3Sopenharmony_ci
184514f5e3Sopenharmony_ciexport class XTexture {
194514f5e3Sopenharmony_ci  static gi() {
204514f5e3Sopenharmony_ci    if (XTexture.pinstance_ === null) XTexture.pinstance_ = new XTexture();
214514f5e3Sopenharmony_ci    return XTexture.pinstance_;
224514f5e3Sopenharmony_ci  }
234514f5e3Sopenharmony_ci  constructor() {
244514f5e3Sopenharmony_ci    this.ximages = [];
254514f5e3Sopenharmony_ci    this.allCuts = {};
264514f5e3Sopenharmony_ci    this.tmpCutid = 0;
274514f5e3Sopenharmony_ci    this.aiCutid = 100;
284514f5e3Sopenharmony_ci
294514f5e3Sopenharmony_ci    this.textImgs = {};
304514f5e3Sopenharmony_ci    this.textIdxs = {};
314514f5e3Sopenharmony_ci
324514f5e3Sopenharmony_ci    this.textTmpRid = this.loadTexture(1024, 256);
334514f5e3Sopenharmony_ci    this.bfirst = true;
344514f5e3Sopenharmony_ci
354514f5e3Sopenharmony_ci    this.textCvs = document.createElement('canvas');
364514f5e3Sopenharmony_ci    this.textCvs.width = 1024;
374514f5e3Sopenharmony_ci    this.textCvs.height = 256;
384514f5e3Sopenharmony_ci    this.textCtx = this.textCvs.getContext('2d', { willReadFrequently: true });
394514f5e3Sopenharmony_ci    this.textCtx.textBaseline = 'top';
404514f5e3Sopenharmony_ci    this.textCtx.textAlign = 'left';
414514f5e3Sopenharmony_ci  }
424514f5e3Sopenharmony_ci  static initTextureStatus(tex) {
434514f5e3Sopenharmony_ci    gl.activeTexture(gl.TEXTURE0);
444514f5e3Sopenharmony_ci    gl.bindTexture(gl.TEXTURE_2D, tex);
454514f5e3Sopenharmony_ci    gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
464514f5e3Sopenharmony_ci    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
474514f5e3Sopenharmony_ci    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
484514f5e3Sopenharmony_ci    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
494514f5e3Sopenharmony_ci    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
504514f5e3Sopenharmony_ci  }
514514f5e3Sopenharmony_ci  loadTextureFromImage(path, keepdata = false) {
524514f5e3Sopenharmony_ci    if (path === 'CUSTOM_TEXTURE_1') {
534514f5e3Sopenharmony_ci      var rid = this.ximages.length;
544514f5e3Sopenharmony_ci
554514f5e3Sopenharmony_ci      var texture = gl.createTexture();
564514f5e3Sopenharmony_ci      XTexture.initTextureStatus(texture);
574514f5e3Sopenharmony_ci
584514f5e3Sopenharmony_ci      let tmp = new Uint8Array([255, 255, 255, 255]);
594514f5e3Sopenharmony_ci      gl.texImage2D(
604514f5e3Sopenharmony_ci        gl.TEXTURE_2D,
614514f5e3Sopenharmony_ci        0,
624514f5e3Sopenharmony_ci        gl.RGBA,
634514f5e3Sopenharmony_ci        1,
644514f5e3Sopenharmony_ci        1,
654514f5e3Sopenharmony_ci        0,
664514f5e3Sopenharmony_ci        gl.RGBA,
674514f5e3Sopenharmony_ci        gl.UNSIGNED_BYTE,
684514f5e3Sopenharmony_ci        tmp
694514f5e3Sopenharmony_ci      );
704514f5e3Sopenharmony_ci
714514f5e3Sopenharmony_ci      this.ximages[rid] = { stat: 1, path: path, tex: texture, w: 1, h: 1 };
724514f5e3Sopenharmony_ci      return rid;
734514f5e3Sopenharmony_ci    } else {
744514f5e3Sopenharmony_ci      for (let i = 0; i < this.ximages.length; i++) {
754514f5e3Sopenharmony_ci        if (this.ximages[i]['path'] === path) {
764514f5e3Sopenharmony_ci          return i;
774514f5e3Sopenharmony_ci        }
784514f5e3Sopenharmony_ci      }
794514f5e3Sopenharmony_ci      var rid = this.ximages.length;
804514f5e3Sopenharmony_ci      this.ximages[rid] = { stat: 0, path: path, tex: null };
814514f5e3Sopenharmony_ci      var image = new Image();
824514f5e3Sopenharmony_ci      image.src = path; //"http://localhost:8910/"+
834514f5e3Sopenharmony_ci      image.onload = function () {
844514f5e3Sopenharmony_ci        var texture = gl.createTexture();
854514f5e3Sopenharmony_ci        XTexture.initTextureStatus(texture);
864514f5e3Sopenharmony_ci
874514f5e3Sopenharmony_ci        gl.texImage2D(
884514f5e3Sopenharmony_ci          gl.TEXTURE_2D,
894514f5e3Sopenharmony_ci          0,
904514f5e3Sopenharmony_ci          gl.RGBA,
914514f5e3Sopenharmony_ci          gl.RGBA,
924514f5e3Sopenharmony_ci          gl.UNSIGNED_BYTE,
934514f5e3Sopenharmony_ci          image
944514f5e3Sopenharmony_ci        );
954514f5e3Sopenharmony_ci
964514f5e3Sopenharmony_ci        XTexture.pinstance_.ximages[rid].tex = texture;
974514f5e3Sopenharmony_ci        XTexture.pinstance_.ximages[rid].img = image;
984514f5e3Sopenharmony_ci        XTexture.pinstance_.ximages[rid].stat = 1;
994514f5e3Sopenharmony_ci        XTexture.pinstance_.ximages[rid].w = image.width;
1004514f5e3Sopenharmony_ci        XTexture.pinstance_.ximages[rid].h = image.height;
1014514f5e3Sopenharmony_ci      };
1024514f5e3Sopenharmony_ci      return rid;
1034514f5e3Sopenharmony_ci    }
1044514f5e3Sopenharmony_ci  }
1054514f5e3Sopenharmony_ci  TmpCut(rid, x = 0, y = 0, w = -1, h = -1, ww = 1024, hh = 1024) {
1064514f5e3Sopenharmony_ci    if (this.ximages[rid].stat !== 1) return -1;
1074514f5e3Sopenharmony_ci
1084514f5e3Sopenharmony_ci    if (w === -1) w = ww;
1094514f5e3Sopenharmony_ci    if (h === -1) h = hh;
1104514f5e3Sopenharmony_ci    this.allCuts[this.tmpCutid] = {
1114514f5e3Sopenharmony_ci      rid: rid,
1124514f5e3Sopenharmony_ci      x: x,
1134514f5e3Sopenharmony_ci      y: y,
1144514f5e3Sopenharmony_ci      w: w,
1154514f5e3Sopenharmony_ci      h: h,
1164514f5e3Sopenharmony_ci      u0: x / ww,
1174514f5e3Sopenharmony_ci      v0: y / hh,
1184514f5e3Sopenharmony_ci      u1: (x + w) / ww,
1194514f5e3Sopenharmony_ci      v1: y / hh,
1204514f5e3Sopenharmony_ci      u2: (x + w) / ww,
1214514f5e3Sopenharmony_ci      v2: (y + h) / hh,
1224514f5e3Sopenharmony_ci      u3: x / ww,
1234514f5e3Sopenharmony_ci      v3: (y + h) / hh,
1244514f5e3Sopenharmony_ci    };
1254514f5e3Sopenharmony_ci    this.tmpCutid += 1;
1264514f5e3Sopenharmony_ci    return this.tmpCutid - 1;
1274514f5e3Sopenharmony_ci  }
1284514f5e3Sopenharmony_ci  makeCut(rid, x = 0, y = 0, w = -1, h = -1, ww = -1, hh = -1) {
1294514f5e3Sopenharmony_ci    if (ww === -1) ww = this.ximages[rid].w;
1304514f5e3Sopenharmony_ci    if (hh === -1) hh = this.ximages[rid].h;
1314514f5e3Sopenharmony_ci    if (w ===-1) w = ww;
1324514f5e3Sopenharmony_ci    if (h === -1) h = hh;
1334514f5e3Sopenharmony_ci    this.allCuts[this.aiCutid] = {
1344514f5e3Sopenharmony_ci      rid: rid,
1354514f5e3Sopenharmony_ci      x: x,
1364514f5e3Sopenharmony_ci      y: y,
1374514f5e3Sopenharmony_ci      w: w,
1384514f5e3Sopenharmony_ci      h: h,
1394514f5e3Sopenharmony_ci      u0: x / ww,
1404514f5e3Sopenharmony_ci      v0: y / hh,
1414514f5e3Sopenharmony_ci      u1: (x + w) / ww,
1424514f5e3Sopenharmony_ci      v1: y / hh,
1434514f5e3Sopenharmony_ci      u2: (x + w) / ww,
1444514f5e3Sopenharmony_ci      v2: (y + h) / hh,
1454514f5e3Sopenharmony_ci      u3: x / ww,
1464514f5e3Sopenharmony_ci      v3: (y + h) / hh,
1474514f5e3Sopenharmony_ci    };
1484514f5e3Sopenharmony_ci    this.aiCutid += 1;
1494514f5e3Sopenharmony_ci    return this.aiCutid - 1;
1504514f5e3Sopenharmony_ci  }
1514514f5e3Sopenharmony_ci  timenow() {
1524514f5e3Sopenharmony_ci    let myDate = new Date();
1534514f5e3Sopenharmony_ci    return myDate.getTime() / 1000;
1544514f5e3Sopenharmony_ci  }
1554514f5e3Sopenharmony_ci
1564514f5e3Sopenharmony_ci  PutTexture(tex, w, h) {
1574514f5e3Sopenharmony_ci    var rid = this.ximages.length;
1584514f5e3Sopenharmony_ci    this.ximages[rid] = { stat: 1, path: 'put' + rid, tex: tex, w: w, h: h };
1594514f5e3Sopenharmony_ci    return rid;
1604514f5e3Sopenharmony_ci  }
1614514f5e3Sopenharmony_ci
1624514f5e3Sopenharmony_ci  loadTexture(width, height) {
1634514f5e3Sopenharmony_ci    var rid = this.ximages.length;
1644514f5e3Sopenharmony_ci
1654514f5e3Sopenharmony_ci    var texture = gl.createTexture();
1664514f5e3Sopenharmony_ci    XTexture.initTextureStatus(texture);
1674514f5e3Sopenharmony_ci    gl.texImage2D(
1684514f5e3Sopenharmony_ci      gl.TEXTURE_2D,
1694514f5e3Sopenharmony_ci      0,
1704514f5e3Sopenharmony_ci      gl.RGBA,
1714514f5e3Sopenharmony_ci      width,
1724514f5e3Sopenharmony_ci      height,
1734514f5e3Sopenharmony_ci      0,
1744514f5e3Sopenharmony_ci      gl.RGBA,
1754514f5e3Sopenharmony_ci      gl.UNSIGNED_BYTE,
1764514f5e3Sopenharmony_ci      null
1774514f5e3Sopenharmony_ci    );
1784514f5e3Sopenharmony_ci
1794514f5e3Sopenharmony_ci    this.ximages[rid] = {
1804514f5e3Sopenharmony_ci      stat: 1,
1814514f5e3Sopenharmony_ci      path: 'default' + rid,
1824514f5e3Sopenharmony_ci      tex: texture,
1834514f5e3Sopenharmony_ci      w: width,
1844514f5e3Sopenharmony_ci      h: height,
1854514f5e3Sopenharmony_ci    };
1864514f5e3Sopenharmony_ci    return rid;
1874514f5e3Sopenharmony_ci  }
1884514f5e3Sopenharmony_ci  initTextImageData(s, size) {
1894514f5e3Sopenharmony_ci    this.textCtx.clearRect(0, 0, 1024, 256);
1904514f5e3Sopenharmony_ci    this.textCtx.font = size + "px '宋体'";
1914514f5e3Sopenharmony_ci    this.textCtx.fillStyle = 'rgba(255,255,255,1)';
1924514f5e3Sopenharmony_ci    this.textCtx.fillText(s, 1, 1);
1934514f5e3Sopenharmony_ci    let imgd = this.textCtx.getImageData(0, 0, 1024, 256).data;
1944514f5e3Sopenharmony_ci    let w = 1024;
1954514f5e3Sopenharmony_ci    let h = size + 5;
1964514f5e3Sopenharmony_ci    let x = 256;
1974514f5e3Sopenharmony_ci    while (x === 256) {
1984514f5e3Sopenharmony_ci      h -= 1;
1994514f5e3Sopenharmony_ci      for (x = 0; x < 128; x++) {
2004514f5e3Sopenharmony_ci        let p = (h * 1024 + x) * 4;
2014514f5e3Sopenharmony_ci        if (imgd[p] !== 0) break;
2024514f5e3Sopenharmony_ci      }
2034514f5e3Sopenharmony_ci    }
2044514f5e3Sopenharmony_ci    let y = h;
2054514f5e3Sopenharmony_ci    while (y === h) {
2064514f5e3Sopenharmony_ci      w -= 1;
2074514f5e3Sopenharmony_ci      for (y = 0; y < h; y++) {
2084514f5e3Sopenharmony_ci        let p = (y * 1024 + w) * 4;
2094514f5e3Sopenharmony_ci        if (imgd[p] !== 0) break;
2104514f5e3Sopenharmony_ci      }
2114514f5e3Sopenharmony_ci    }
2124514f5e3Sopenharmony_ci    return this.textCtx.getImageData(0, 0, w + 1, h + 1);
2134514f5e3Sopenharmony_ci  }
2144514f5e3Sopenharmony_ci  getText(s, size) {
2154514f5e3Sopenharmony_ci    let textIdx = s + size;
2164514f5e3Sopenharmony_ci
2174514f5e3Sopenharmony_ci    if (textIdx in this.textIdxs) {
2184514f5e3Sopenharmony_ci      this.textIdxs[textIdx].time = this.timenow();
2194514f5e3Sopenharmony_ci      return this.textIdxs[textIdx].cid;
2204514f5e3Sopenharmony_ci    }
2214514f5e3Sopenharmony_ci    let imgd = this.initTextImageData(s, size);
2224514f5e3Sopenharmony_ci    let w = imgd.width;
2234514f5e3Sopenharmony_ci    let h = imgd.height;
2244514f5e3Sopenharmony_ci    let useHeight = Math.floor((h + 31) / 32);
2254514f5e3Sopenharmony_ci    let mask = 0;
2264514f5e3Sopenharmony_ci    for (let i = 0; i < useHeight; i++) mask |= 1 << i;
2274514f5e3Sopenharmony_ci    let rid = -1;
2284514f5e3Sopenharmony_ci    let off = -1;
2294514f5e3Sopenharmony_ci    for (let k in this.textImgs) {
2304514f5e3Sopenharmony_ci      for (let i = 0; i < 32 - useHeight + 1; i++) {
2314514f5e3Sopenharmony_ci        if ((this.textImgs[k].mask & (mask << i)) === 0) {
2324514f5e3Sopenharmony_ci          off = i;
2334514f5e3Sopenharmony_ci          break;
2344514f5e3Sopenharmony_ci        }
2354514f5e3Sopenharmony_ci      }
2364514f5e3Sopenharmony_ci      if (off !== -1) {
2374514f5e3Sopenharmony_ci        rid = k;
2384514f5e3Sopenharmony_ci        break;
2394514f5e3Sopenharmony_ci      }
2404514f5e3Sopenharmony_ci    }
2414514f5e3Sopenharmony_ci    if (rid === -1) {
2424514f5e3Sopenharmony_ci      rid = this.loadTexture(1024, 1024);
2434514f5e3Sopenharmony_ci      this.textImgs[rid] = { mask: 0 };
2444514f5e3Sopenharmony_ci      off = 0;
2454514f5e3Sopenharmony_ci    }
2464514f5e3Sopenharmony_ci    let cid = this.makeCut(rid, 0, off * 32, w, h);
2474514f5e3Sopenharmony_ci    this.textImgs[rid]['mask'] |= mask << off;
2484514f5e3Sopenharmony_ci    this.textIdxs[textIdx] = { cid: cid, rid: rid, mask: mask << off, time: this.timenow(), };
2494514f5e3Sopenharmony_ci    gl.activeTexture(gl.TEXTURE0);
2504514f5e3Sopenharmony_ci    gl.bindTexture(gl.TEXTURE_2D, this.ximages[rid].tex);
2514514f5e3Sopenharmony_ci    gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
2524514f5e3Sopenharmony_ci    gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, off * 32, gl.RGBA, gl.UNSIGNED_BYTE, imgd);
2534514f5e3Sopenharmony_ci    return cid;
2544514f5e3Sopenharmony_ci  }
2554514f5e3Sopenharmony_ci  _FreshText() {
2564514f5e3Sopenharmony_ci    this.tmpCutid = 0;
2574514f5e3Sopenharmony_ci    let nt = this.timenow();
2584514f5e3Sopenharmony_ci    let rm = [];
2594514f5e3Sopenharmony_ci    for (let idx in this.textIdxs) {
2604514f5e3Sopenharmony_ci      if (nt - this.textIdxs[idx].time > 3) {
2614514f5e3Sopenharmony_ci        this.textImgs[this.textIdxs[idx].rid].mask &= ~this.textIdxs[idx].mask;
2624514f5e3Sopenharmony_ci        delete this.allCuts[this.textIdxs[idx].cid];
2634514f5e3Sopenharmony_ci        rm.push(idx);
2644514f5e3Sopenharmony_ci      }
2654514f5e3Sopenharmony_ci    }
2664514f5e3Sopenharmony_ci    for (let idx in rm) {
2674514f5e3Sopenharmony_ci      delete this.textIdxs[rm[idx]];
2684514f5e3Sopenharmony_ci    }
2694514f5e3Sopenharmony_ci  }
2704514f5e3Sopenharmony_ci  static ExpandColor(c) {
2714514f5e3Sopenharmony_ci    return [
2724514f5e3Sopenharmony_ci      ((c >> 16) & 0xff) / 255,
2734514f5e3Sopenharmony_ci      ((c >> 8) & 0xff) / 255,
2744514f5e3Sopenharmony_ci      (c & 0xff) / 255,
2754514f5e3Sopenharmony_ci      ((c >> 24) & 0xff) / 255]; //r,g,b,a
2764514f5e3Sopenharmony_ci  }
2774514f5e3Sopenharmony_ci}
2784514f5e3Sopenharmony_ciXTexture.pinstance_ = null;
279