1/* 2* Copyright (c) 2022 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 { gl } from "../GLFrame.js" 17 18export 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 = {};//rid,{mask} 30 this.textIdxs = {};//text,{} 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"); 39 this.textCtx.textBaseline = 'top' 40 this.textCtx.textAlign = 'left' 41 } 42 static initTextureStatus(tex) 43 { 44 gl.activeTexture(gl.TEXTURE0); 45 gl.bindTexture(gl.TEXTURE_2D, tex); 46 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); 47 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST); 48 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST); 49 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE); 50 gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE); 51 } 52 loadTextureFromImage(path, keepdata = false) { 53 if (path == "CUSTOM_TEXTURE_1") { 54 var rid = this.ximages.length; 55 56 var texture = gl.createTexture(); 57 XTexture.initTextureStatus(texture); 58 59 let tmp=new Uint8Array([255,255,255,255]) 60 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, tmp) 61 62 this.ximages[rid] = { "stat": 1, "path": path, "tex": texture ,"w":1,"h":1}; 63 return rid 64 } 65 else { 66 for (let i = 0; i < this.ximages.length; i++) { 67 if (this.ximages[i]["path"] == path) { 68 return i; 69 } 70 } 71 var rid = this.ximages.length; 72 this.ximages[rid] = { "stat": 0, "path": path, "tex": null }; 73 var image = new Image(); 74 image.src = path;//"http://localhost:8910/"+ 75 image.onload = function () { 76 var texture = gl.createTexture(); 77 XTexture.initTextureStatus(texture) 78 79 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, gl.RGBA, gl.UNSIGNED_BYTE, image); 80 81 XTexture.pinstance_.ximages[rid].tex = texture; 82 XTexture.pinstance_.ximages[rid].img = image; 83 XTexture.pinstance_.ximages[rid].stat = 1; 84 XTexture.pinstance_.ximages[rid].w = image.width; 85 XTexture.pinstance_.ximages[rid].h = image.height; 86 }; 87 return rid; 88 } 89 } 90 TmpCut(rid, x = 0, y = 0, w = -1, h = -1, ww = 1024, hh = 1024) { 91 if (this.ximages[rid].stat != 1) return -1; 92 93 if (w == -1) w = ww; 94 if (h == -1) h = hh; 95 this.allCuts[this.tmpCutid] = { 96 "rid": rid, 97 "x": x, "y": y, 98 "w": w, "h": h, 99 "u0": x / ww, "v0": y / hh, 100 "u1": (x + w) / ww, "v1": y / hh, 101 "u2": (x + w) / ww, "v2": (y + h) / hh, 102 "u3": x / ww, "v3": (y + h) / hh 103 }; 104 this.tmpCutid += 1; 105 return this.tmpCutid - 1; 106 } 107 makeCut(rid, x = 0, y = 0, w = -1, h = -1, ww = -1, hh = -1) { 108 if (this.ximages[rid].stat != 1) return -1; 109 110 if (ww == -1) ww = this.ximages[rid].w; 111 if (hh == -1) hh = this.ximages[rid].h; 112 if (w == -1) w = ww; 113 if (h == -1) h = hh; 114 this.allCuts[this.aiCutid] = { 115 "rid": rid, 116 "x": x, "y": y, 117 "w": w, "h": h, 118 "u0": x / ww, "v0": y / hh, 119 "u1": (x + w) / ww, "v1": y / hh, 120 "u2": (x + w) / ww, "v2": (y + h) / hh, 121 "u3": x / ww, "v3": (y + h) / hh 122 }; 123 this.aiCutid += 1; 124 return this.aiCutid - 1; 125 } 126 timenow() { 127 let myDate = new Date(); 128 return myDate.getTime() / 1000; 129 } 130 131 PutTexture(tex, w, h) { 132 var rid = this.ximages.length; 133 this.ximages[rid] = { "stat": 1, "path": "put" + rid, "tex": tex, "w": w, "h": h }; 134 return rid; 135 } 136 137 loadTexture(width, height) { 138 var rid = this.ximages.length; 139 140 var texture = gl.createTexture(); 141 XTexture.initTextureStatus(texture) 142 gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, width, height, 0, gl.RGBA, gl.UNSIGNED_BYTE, null) 143 144 this.ximages[rid] = { "stat": 1, "path": "default" + rid, "tex": texture, "w": width, "h": height }; 145 return rid; 146 } 147 initTextImageData(s, size) { 148 this.textCtx.clearRect(0, 0, 1024, 256) 149 this.textCtx.font = size + "px 'Consolas'" 150 this.textCtx.fillStyle = "rgba(255,255,255,1)"; 151 this.textCtx.fillText(s, 1, 1) 152 let imgd = this.textCtx.getImageData(0, 0, 1024, 256).data 153 let w = 1024; 154 let h = size+5; 155 let x = 256; 156 while (x == 256) { 157 h -= 1; 158 for (x = 0; x < 128; x++) { 159 let p = (h * 1024 + x) * 4; 160 if (imgd[p] != 0) break; 161 } 162 } 163 let y = h 164 while (y == h) { 165 w -= 1 166 for (y = 0; y < h; y++) { 167 let p = (y * 1024 + w) * 4; 168 if (imgd[p] != 0) break; 169 } 170 } 171 return this.textCtx.getImageData(0, 0, w + 1, h + 1) 172 } 173 getText(s, size) { 174 let textIdx = s + size 175 176 if (textIdx in this.textIdxs) { 177 this.textIdxs[textIdx].time = this.timenow() 178 return this.textIdxs[textIdx].cid 179 } 180 let imgd = this.initTextImageData(s, size) 181 let w = imgd.width 182 let h = imgd.height 183 let useHeight = Math.floor((h + 31) / 32) 184 let mask = 0 185 for (let i = 0; i < useHeight; i++) 186 mask |= (1 << i); 187 let rid = -1; 188 let off = -1; 189 for (let k in this.textImgs) { 190 for (let i = 0; i < 32 - useHeight + 1; i++) { 191 if ((this.textImgs[k].mask & (mask << i)) == 0) { 192 off = i; 193 break; 194 } 195 } 196 if (off != -1) { 197 rid = k; 198 break; 199 } 200 } 201 if (rid == -1) { 202 rid = this.loadTexture(1024, 1024) 203 this.textImgs[rid] = { "mask": 0 } 204 off = 0 205 } 206 let cid = this.makeCut(rid, 0, off * 32, w, h) 207 this.textImgs[rid]["mask"] |= mask << off 208 this.textIdxs[textIdx] = { "cid": cid, "rid": rid, "mask": mask << off, "time": this.timenow() } 209 gl.activeTexture(gl.TEXTURE0); 210 gl.bindTexture(gl.TEXTURE_2D, this.ximages[rid].tex); 211 gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, false); 212 gl.texSubImage2D(gl.TEXTURE_2D, 0, 0, off * 32, gl.RGBA, gl.UNSIGNED_BYTE, imgd); 213 return cid 214 } 215 _FreshText() { 216 this.tmpCutid = 0; 217 let nt=this.timenow() 218 let rm=[] 219 for(let idx in this.textIdxs) 220 { 221 if(nt-this.textIdxs[idx].time>10) 222 { 223 this.textImgs[this.textIdxs[idx].rid].mask&=(~this.textIdxs[idx].mask) 224 delete this.allCuts[this.textIdxs[idx].cid] 225 rm.push(idx) 226 } 227 } 228 for(let idx in rm) 229 { 230 delete this.textIdxs[rm[idx]] 231 } 232 } 233} 234XTexture.pinstance_ = null;