• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
16 import { gl } from '../GLFrame.js';
17 
18 export class XTexture {
19   static gi() {
20     if (XTexture.pinstance_ == null) XTexture.pinstance_ = new XTexture();
21     return XTexture.pinstance_;
22   }
23   constructor() {
24     this.ximages = [];
25     this.allCuts = {};
26     this.tmpCutid = 0;
27     this.aiCutid = 100;
28 
29     this.textImgs = {};
30     this.textIdxs = {};
31 
32     this.textTmpRid = this.loadTexture(1024, 256);
33     this.bfirst = true;
34 
35     this.textCvs = document.createElement('canvas');
36     this.textCvs.width = 1024;
37     this.textCvs.height = 256;
38     this.textCtx = this.textCvs.getContext('2d', { willReadFrequently: true });
39     this.textCtx.textBaseline = 'top';
40     this.textCtx.textAlign = 'left';
41   }
42   static initTextureStatus(tex) {
43     gl.activeTexture(gl.TEXTURE0);
44     gl.bindTexture(gl.TEXTURE_2D, tex);
45     gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
46     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
47     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
48     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
49     gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
50   }
51   loadTextureFromImage(path, keepdata = false) {
52     if (path === 'CUSTOM_TEXTURE_1') {
53       var rid = this.ximages.length;
54 
55       var texture = gl.createTexture();
56       XTexture.initTextureStatus(texture);
57 
58       let tmp = new Uint8Array([255, 255, 255, 255]);
59       gl.texImage2D(
60         gl.TEXTURE_2D,
61         0,
62         gl.RGBA,
63         1,
64         1,
65         0,
66         gl.RGBA,
67         gl.UNSIGNED_BYTE,
68         tmp
69       );
70 
71       this.ximages[rid] = { stat: 1, path: path, tex: texture, w: 1, h: 1 };
72       return rid;
73     } else {
74       for (let i = 0; i < this.ximages.length; i++) {
75         if (this.ximages[i]['path'] === path) {
76           return i;
77         }
78       }
79       var rid = this.ximages.length;
80       this.ximages[rid] = { stat: 0, path: path, tex: null };
81       var image = new Image();
82       image.src = path; //"http://localhost:8910/"+
83       image.onload = function () {
84         var texture = gl.createTexture();
85         XTexture.initTextureStatus(texture);
86 
87         gl.texImage2D(
88           gl.TEXTURE_2D,
89           0,
90           gl.RGBA,
91           gl.RGBA,
92           gl.UNSIGNED_BYTE,
93           image
94         );
95 
96         XTexture.pinstance_.ximages[rid].tex = texture;
97         XTexture.pinstance_.ximages[rid].img = image;
98         XTexture.pinstance_.ximages[rid].stat = 1;
99         XTexture.pinstance_.ximages[rid].w = image.width;
100         XTexture.pinstance_.ximages[rid].h = image.height;
101       };
102       return rid;
103     }
104   }
105   TmpCut(rid, x = 0, y = 0, w = -1, h = -1, ww = 1024, hh = 1024) {
106     if (this.ximages[rid].stat !== 1) return -1;
107 
108     if (w === -1) w = ww;
109     if (h === -1) h = hh;
110     this.allCuts[this.tmpCutid] = {
111       rid: rid,
112       x: x,
113       y: y,
114       w: w,
115       h: h,
116       u0: x / ww,
117       v0: y / hh,
118       u1: (x + w) / ww,
119       v1: y / hh,
120       u2: (x + w) / ww,
121       v2: (y + h) / hh,
122       u3: x / ww,
123       v3: (y + h) / hh,
124     };
125     this.tmpCutid += 1;
126     return this.tmpCutid - 1;
127   }
128   makeCut(rid, x = 0, y = 0, w = -1, h = -1, ww = -1, hh = -1) {
129     if (ww === -1) ww = this.ximages[rid].w;
130     if (hh === -1) hh = this.ximages[rid].h;
131     if (w === -1) w = ww;
132     if (h === -1) h = hh;
133     this.allCuts[this.aiCutid] = {
134       rid: rid,
135       x: x,
136       y: y,
137       w: w,
138       h: h,
139       u0: x / ww,
140       v0: y / hh,
141       u1: (x + w) / ww,
142       v1: y / hh,
143       u2: (x + w) / ww,
144       v2: (y + h) / hh,
145       u3: x / ww,
146       v3: (y + h) / hh,
147     };
148     this.aiCutid += 1;
149     return this.aiCutid - 1;
150   }
151   timenow() {
152     let myDate = new Date();
153     return myDate.getTime() / 1000;
154   }
155 
156   PutTexture(tex, w, h) {
157     var rid = this.ximages.length;
158     this.ximages[rid] = { stat: 1, path: 'put' + rid, tex: tex, w: w, h: h };
159     return rid;
160   }
161 
162   loadTexture(width, height) {
163     var rid = this.ximages.length;
164 
165     var texture = gl.createTexture();
166     XTexture.initTextureStatus(texture);
167     gl.texImage2D(
168       gl.TEXTURE_2D,
169       0,
170       gl.RGBA,
171       width,
172       height,
173       0,
174       gl.RGBA,
175       gl.UNSIGNED_BYTE,
176       null
177     );
178 
179     this.ximages[rid] = {
180       stat: 1,
181       path: 'default' + rid,
182       tex: texture,
183       w: width,
184       h: height,
185     };
186     return rid;
187   }
188   initTextImageData(s, size) {
189     this.textCtx.clearRect(0, 0, 1024, 256);
190     this.textCtx.font = size + "px '宋体'";
191     this.textCtx.fillStyle = 'rgba(255,255,255,1)';
192     this.textCtx.fillText(s, 1, 1);
193     let imgd = this.textCtx.getImageData(0, 0, 1024, 256).data;
194     let w = 1024;
195     let h = size + 5;
196     let x = 256;
197     while (x === 256) {
198       h -= 1;
199       for (x = 0; x < 128; x++) {
200         let p = (h * 1024 + x) * 4;
201         if (imgd[p] !== 0) break;
202       }
203     }
204     let y = h;
205     while (y === h) {
206       w -= 1;
207       for (y = 0; y < h; y++) {
208         let p = (y * 1024 + w) * 4;
209         if (imgd[p] !== 0) break;
210       }
211     }
212     return this.textCtx.getImageData(0, 0, w + 1, h + 1);
213   }
214   getText(s, size) {
215     let textIdx = s + size;
216 
217     if (textIdx in this.textIdxs) {
218       this.textIdxs[textIdx].time = this.timenow();
219       return this.textIdxs[textIdx].cid;
220     }
221     let imgd = this.initTextImageData(s, size);
222     let w = imgd.width;
223     let h = imgd.height;
224     let useHeight = Math.floor((h + 31) / 32);
225     let mask = 0;
226     for (let i = 0; i < useHeight; i++) mask |= 1 << i;
227     let rid = -1;
228     let off = -1;
229     for (let k in this.textImgs) {
230       for (let i = 0; i < 32 - useHeight + 1; i++) {
231         if ((this.textImgs[k].mask & (mask << i)) === 0) {
232           off = i;
233           break;
234         }
235       }
236       if (off !== -1) {
237         rid = k;
238         break;
239       }
240     }
241     if (rid === -1) {
242       rid = this.loadTexture(1024, 1024);
243       this.textImgs[rid] = { mask: 0 };
244       off = 0;
245     }
246     let cid = this.makeCut(rid, 0, off * 32, w, h);
247     this.textImgs[rid]['mask'] |= mask << off;
248     this.textIdxs[textIdx] = { cid: cid, rid: rid, mask: mask << off, time: this.timenow(), };
249     gl.activeTexture(gl.TEXTURE0);
250     gl.bindTexture(gl.TEXTURE_2D, this.ximages[rid].tex);
251     gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false);
252     gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, off * 32, gl.RGBA, gl.UNSIGNED_BYTE, imgd);
253     return cid;
254   }
255   _FreshText() {
256     this.tmpCutid = 0;
257     let nt = this.timenow();
258     let rm = [];
259     for (let idx in this.textIdxs) {
260       if (nt - this.textIdxs[idx].time > 3) {
261         this.textImgs[this.textIdxs[idx].rid].mask &= ~this.textIdxs[idx].mask;
262         delete this.allCuts[this.textIdxs[idx].cid];
263         rm.push(idx);
264       }
265     }
266     for (let idx in rm) {
267       delete this.textIdxs[rm[idx]];
268     }
269   }
270   static ExpandColor(c) {
271     return [
272       ((c >> 16) & 0xff) / 255,
273       ((c >> 8) & 0xff) / 255,
274       (c & 0xff) / 255,
275       ((c >> 24) & 0xff) / 255];//r,g,b,a
276   }
277 }
278 XTexture.pinstance_ = null;
279