@kurot/core 1.0.20 → 1.0.22
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/kurot/display/DisplayObject.d.ts.map +1 -1
- package/dist/kurot/display/DisplayObject.js +6 -0
- package/dist/kurot/display/DisplayObject.js.map +1 -1
- package/dist/kurot/display/Mesh.d.ts +5 -2
- package/dist/kurot/display/Mesh.d.ts.map +1 -1
- package/dist/kurot/display/Mesh.js +5 -2
- package/dist/kurot/display/Mesh.js.map +1 -1
- package/dist/kurot/filters/BloomFilter.d.ts +40 -0
- package/dist/kurot/filters/BloomFilter.d.ts.map +1 -0
- package/dist/kurot/filters/BloomFilter.js +51 -0
- package/dist/kurot/filters/BloomFilter.js.map +1 -0
- package/dist/kurot/filters/BloomShaders.d.ts +10 -0
- package/dist/kurot/filters/BloomShaders.d.ts.map +1 -0
- package/dist/kurot/filters/BloomShaders.js +54 -0
- package/dist/kurot/filters/BloomShaders.js.map +1 -0
- package/dist/kurot/filters/BlurFilter.d.ts +4 -0
- package/dist/kurot/filters/BlurFilter.d.ts.map +1 -1
- package/dist/kurot/filters/BlurFilter.js +23 -6
- package/dist/kurot/filters/BlurFilter.js.map +1 -1
- package/dist/kurot/filters/CustomFilter.d.ts +44 -1
- package/dist/kurot/filters/CustomFilter.d.ts.map +1 -1
- package/dist/kurot/filters/CustomFilter.js +56 -17
- package/dist/kurot/filters/CustomFilter.js.map +1 -1
- package/dist/kurot/filters/DropShadowFilter.d.ts.map +1 -1
- package/dist/kurot/filters/DropShadowFilter.js +1 -0
- package/dist/kurot/filters/DropShadowFilter.js.map +1 -1
- package/dist/kurot/filters/Filter.d.ts +15 -0
- package/dist/kurot/filters/Filter.d.ts.map +1 -1
- package/dist/kurot/filters/Filter.js +58 -0
- package/dist/kurot/filters/Filter.js.map +1 -1
- package/dist/kurot/filters/FilterTexture.d.ts +21 -0
- package/dist/kurot/filters/FilterTexture.d.ts.map +1 -0
- package/dist/kurot/filters/FilterTexture.js +2 -0
- package/dist/kurot/filters/FilterTexture.js.map +1 -0
- package/dist/kurot/filters/GlowFilter.d.ts.map +1 -1
- package/dist/kurot/filters/GlowFilter.js +6 -0
- package/dist/kurot/filters/GlowFilter.js.map +1 -1
- package/dist/kurot/filters/MultiPassFilter.d.ts +41 -0
- package/dist/kurot/filters/MultiPassFilter.d.ts.map +1 -0
- package/dist/kurot/filters/MultiPassFilter.js +53 -0
- package/dist/kurot/filters/MultiPassFilter.js.map +1 -0
- package/dist/kurot/filters/index.d.ts +6 -0
- package/dist/kurot/filters/index.d.ts.map +1 -1
- package/dist/kurot/filters/index.js +2 -0
- package/dist/kurot/filters/index.js.map +1 -1
- package/dist/kurot/player/Player.d.ts.map +1 -1
- package/dist/kurot/player/Player.js +1 -0
- package/dist/kurot/player/Player.js.map +1 -1
- package/dist/kurot/player/canvas/CanvasRenderer.d.ts.map +1 -1
- package/dist/kurot/player/canvas/CanvasRenderer.js +26 -16
- package/dist/kurot/player/canvas/CanvasRenderer.js.map +1 -1
- package/dist/kurot/player/pipes/BitmapPipe.d.ts.map +1 -1
- package/dist/kurot/player/pipes/BitmapPipe.js +20 -10
- package/dist/kurot/player/pipes/BitmapPipe.js.map +1 -1
- package/dist/kurot/player/pipes/FilterPipe.d.ts.map +1 -1
- package/dist/kurot/player/pipes/FilterPipe.js +23 -18
- package/dist/kurot/player/pipes/FilterPipe.js.map +1 -1
- package/dist/kurot/player/pipes/MaskPipe.d.ts.map +1 -1
- package/dist/kurot/player/pipes/MaskPipe.js +6 -0
- package/dist/kurot/player/pipes/MaskPipe.js.map +1 -1
- package/dist/kurot/player/pipes/filter-bounds.d.ts +8 -0
- package/dist/kurot/player/pipes/filter-bounds.d.ts.map +1 -0
- package/dist/kurot/player/pipes/filter-bounds.js +25 -0
- package/dist/kurot/player/pipes/filter-bounds.js.map +1 -0
- package/dist/kurot/player/webgl/WebGLFilterSystem.d.ts +27 -0
- package/dist/kurot/player/webgl/WebGLFilterSystem.d.ts.map +1 -0
- package/dist/kurot/player/webgl/WebGLFilterSystem.js +119 -0
- package/dist/kurot/player/webgl/WebGLFilterSystem.js.map +1 -0
- package/dist/kurot/player/webgl/WebGLFilterTargetPool.d.ts +18 -0
- package/dist/kurot/player/webgl/WebGLFilterTargetPool.d.ts.map +1 -0
- package/dist/kurot/player/webgl/WebGLFilterTargetPool.js +80 -0
- package/dist/kurot/player/webgl/WebGLFilterTargetPool.js.map +1 -0
- package/dist/kurot/player/webgl/WebGLFilterTextures.d.ts +17 -0
- package/dist/kurot/player/webgl/WebGLFilterTextures.d.ts.map +1 -0
- package/dist/kurot/player/webgl/WebGLFilterTextures.js +124 -0
- package/dist/kurot/player/webgl/WebGLFilterTextures.js.map +1 -0
- package/dist/kurot/player/webgl/WebGLProgram.d.ts +6 -2
- package/dist/kurot/player/webgl/WebGLProgram.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLProgram.js +29 -8
- package/dist/kurot/player/webgl/WebGLProgram.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderBuffer.d.ts +2 -0
- package/dist/kurot/player/webgl/WebGLRenderBuffer.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderBuffer.js +3 -0
- package/dist/kurot/player/webgl/WebGLRenderBuffer.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderContext.d.ts +15 -6
- package/dist/kurot/player/webgl/WebGLRenderContext.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderContext.js +200 -145
- package/dist/kurot/player/webgl/WebGLRenderContext.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderer.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLRenderer.js +143 -110
- package/dist/kurot/player/webgl/WebGLRenderer.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLUtils.d.ts +2 -2
- package/dist/kurot/player/webgl/WebGLUtils.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLUtils.js +35 -12
- package/dist/kurot/player/webgl/WebGLUtils.js.map +1 -1
- package/dist/kurot/player/webgl/WebGLVertexArrayObject.d.ts +2 -0
- package/dist/kurot/player/webgl/WebGLVertexArrayObject.d.ts.map +1 -1
- package/dist/kurot/player/webgl/WebGLVertexArrayObject.js +3 -1
- package/dist/kurot/player/webgl/WebGLVertexArrayObject.js.map +1 -1
- package/dist/kurot/player/webgl/custom-filter-uniforms.d.ts +6 -0
- package/dist/kurot/player/webgl/custom-filter-uniforms.d.ts.map +1 -0
- package/dist/kurot/player/webgl/custom-filter-uniforms.js +116 -0
- package/dist/kurot/player/webgl/custom-filter-uniforms.js.map +1 -0
- package/dist/kurot/player/webgl/split-mesh.d.ts +9 -0
- package/dist/kurot/player/webgl/split-mesh.d.ts.map +1 -0
- package/dist/kurot/player/webgl/split-mesh.js +29 -0
- package/dist/kurot/player/webgl/split-mesh.js.map +1 -0
- package/dist/kurot/system/Capabilities.js +1 -1
- package/package.json +1 -1
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
import { splitMesh } from './split-mesh.js';
|
|
2
|
+
import { MultiPassFilter } from '../../filters/MultiPassFilter.js';
|
|
3
|
+
import { WebGLFilterSystem } from './WebGLFilterSystem.js';
|
|
4
|
+
import { CustomFilter } from '../../filters/CustomFilter.js';
|
|
5
|
+
import { uploadCustomUniforms } from './custom-filter-uniforms.js';
|
|
6
|
+
import { WebGLFilterTextures } from './WebGLFilterTextures.js';
|
|
1
7
|
import { ColorMatrixFilter } from '../../filters/ColorMatrixFilter.js';
|
|
2
8
|
import { BlurFilter } from '../../filters/BlurFilter.js';
|
|
3
9
|
import { GlowFilter } from '../../filters/GlowFilter.js';
|
|
@@ -10,8 +16,6 @@ import { ShaderLib2, getBlurTier2, makeBlurHFrag2, makeBlurVFrag2 } from './shad
|
|
|
10
16
|
import { SYM_GL_CONTEXT, SYM_PREMULTIPLIED, SYM_DEFAULT_EMPTY, SYM_SMOOTHING } from './WebGLUtils.js';
|
|
11
17
|
import { WebGLRenderBuffer } from './WebGLRenderBuffer.js';
|
|
12
18
|
import { MultiTextureBatcher, makeMultiCmd } from './MultiTextureBatcher.js';
|
|
13
|
-
const BLUR_FRAMEBUFFER_POOL_LIMIT = 16;
|
|
14
|
-
const BLUR_FRAMEBUFFER_POOL_BYTE_LIMIT = 64 * 1024 * 1024;
|
|
15
19
|
const _gcRegistry = new FinalizationRegistry(({ gl, texture }) => {
|
|
16
20
|
gl.deleteTexture(texture);
|
|
17
21
|
});
|
|
@@ -37,6 +41,11 @@ export class WebGLRenderContext {
|
|
|
37
41
|
resolution = 1;
|
|
38
42
|
// ── Private fields ────────────────────────────────────────────────────────
|
|
39
43
|
_vao;
|
|
44
|
+
_filterTextures;
|
|
45
|
+
_filterSystem;
|
|
46
|
+
_filterPassInputs = {};
|
|
47
|
+
_filterOutputWidth = 0;
|
|
48
|
+
_filterOutputHeight = 0;
|
|
40
49
|
_batcher = new MultiTextureBatcher();
|
|
41
50
|
_bufferStack = [];
|
|
42
51
|
_currentBuffer;
|
|
@@ -50,10 +59,6 @@ export class WebGLRenderContext {
|
|
|
50
59
|
_contextRestoredCallbacks = [];
|
|
51
60
|
_trackedBitmapDatas = new Set();
|
|
52
61
|
_uploadedVersions = new WeakMap();
|
|
53
|
-
// ── Blur FBO pool ─────────────────────────────────────────────────────────
|
|
54
|
-
_blurFboPool = new Map();
|
|
55
|
-
_blurFboPoolSize = 0;
|
|
56
|
-
_blurFboPoolBytes = 0;
|
|
57
62
|
constructor(canvas) {
|
|
58
63
|
this.surface = canvas;
|
|
59
64
|
const gl2 = canvas.getContext('webgl2');
|
|
@@ -77,6 +82,8 @@ export class WebGLRenderContext {
|
|
|
77
82
|
this.makeBlurV = makeBlurVFrag;
|
|
78
83
|
}
|
|
79
84
|
const gl = this.gl;
|
|
85
|
+
this._filterTextures = new WebGLFilterTextures(this);
|
|
86
|
+
this._filterSystem = new WebGLFilterSystem(this);
|
|
80
87
|
gl.disable(gl.DEPTH_TEST);
|
|
81
88
|
gl.disable(gl.CULL_FACE);
|
|
82
89
|
gl.enable(gl.BLEND);
|
|
@@ -105,11 +112,11 @@ export class WebGLRenderContext {
|
|
|
105
112
|
// ── Getters ───────────────────────────────────────────────────────────────
|
|
106
113
|
/** Number of reusable framebuffers currently retained by the blur pipeline. */
|
|
107
114
|
get blurFramebufferPoolSize() {
|
|
108
|
-
return this.
|
|
115
|
+
return this._filterSystem.pool.size;
|
|
109
116
|
}
|
|
110
117
|
/** Estimated GPU bytes retained by the reusable blur framebuffer pool. */
|
|
111
118
|
get blurFramebufferPoolBytes() {
|
|
112
|
-
return this.
|
|
119
|
+
return this._filterSystem.pool.bytes;
|
|
113
120
|
}
|
|
114
121
|
get activatedBuffer() {
|
|
115
122
|
return this._currentBuffer;
|
|
@@ -184,10 +191,18 @@ export class WebGLRenderContext {
|
|
|
184
191
|
this.gl.disable(this.gl.SCISSOR_TEST);
|
|
185
192
|
}
|
|
186
193
|
enableScissor(x, y, width, height) {
|
|
187
|
-
this.
|
|
194
|
+
this.flush();
|
|
195
|
+
if (this._currentBuffer) {
|
|
196
|
+
this._currentBuffer.enableScissor(x, y, width, height);
|
|
197
|
+
this._currentBuffer.hasScissor = true;
|
|
198
|
+
}
|
|
188
199
|
}
|
|
189
200
|
disableScissor() {
|
|
190
|
-
this.
|
|
201
|
+
this.flush();
|
|
202
|
+
if (this._currentBuffer) {
|
|
203
|
+
this._currentBuffer.disableScissor();
|
|
204
|
+
this._currentBuffer.hasScissor = false;
|
|
205
|
+
}
|
|
191
206
|
}
|
|
192
207
|
// ── Mask (stencil-based) ──────────────────────────────────────────────────
|
|
193
208
|
pushMask(x, y, width, height) {
|
|
@@ -288,8 +303,13 @@ export class WebGLRenderContext {
|
|
|
288
303
|
return;
|
|
289
304
|
const buf = this._currentBuffer;
|
|
290
305
|
if (meshVertices && meshIndices) {
|
|
291
|
-
|
|
292
|
-
|
|
306
|
+
if (meshVertices.length / 2 > WebGLVertexArrayObject.MAX_VERTICES || meshIndices.length > WebGLVertexArrayObject.MAX_INDICES) {
|
|
307
|
+
for (const chunk of splitMesh(meshVertices, meshUVs, meshIndices)) {
|
|
308
|
+
this.drawTexture(texture, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight, textureWidth, textureHeight, chunk.uvs, chunk.vertices, chunk.indices, _bounds, rotated, smoothing, flipY);
|
|
309
|
+
}
|
|
310
|
+
return;
|
|
311
|
+
}
|
|
312
|
+
if (this._vao.reachMaxSize(meshVertices.length / 2, meshIndices.length))
|
|
293
313
|
this.flush();
|
|
294
314
|
}
|
|
295
315
|
else {
|
|
@@ -299,8 +319,6 @@ export class WebGLRenderContext {
|
|
|
299
319
|
if (smoothing !== undefined && texture[SYM_SMOOTHING] !== smoothing) {
|
|
300
320
|
this.drawCmdManager.pushChangeSmoothing(texture, smoothing);
|
|
301
321
|
}
|
|
302
|
-
if (meshUVs)
|
|
303
|
-
this._vao.changeToMeshIndices();
|
|
304
322
|
// ── Multi-texture path (plain quads without filter) ───────────────────
|
|
305
323
|
const useMulti = !this.activeFilter && !meshVertices && this._maxTextureUnits > 1;
|
|
306
324
|
if (useMulti) {
|
|
@@ -322,6 +340,8 @@ export class WebGLRenderContext {
|
|
|
322
340
|
// ── Single-texture path (filter, mesh, or single-unit device) ─────────
|
|
323
341
|
if (this._vao.isMultiTexture())
|
|
324
342
|
this.flush();
|
|
343
|
+
if (meshUVs)
|
|
344
|
+
this._vao.changeToMeshIndices();
|
|
325
345
|
this._vao.cacheArrays(buf, sourceX, sourceY, sourceWidth, sourceHeight, destX, destY, destWidth, destHeight, textureWidth, textureHeight, meshUVs, meshVertices, meshIndices, rotated, 0, flipY);
|
|
326
346
|
const count = meshIndices ? meshIndices.length / 3 : 2;
|
|
327
347
|
this.drawCmdManager.pushDrawTexture(texture, count, this.activeFilter, textureWidth, textureHeight);
|
|
@@ -339,129 +359,115 @@ export class WebGLRenderContext {
|
|
|
339
359
|
* framebuffer feedback and state leakage.
|
|
340
360
|
*/
|
|
341
361
|
compositeFilterResult(filters, offscreen) {
|
|
342
|
-
const target = offscreen.rootRenderTarget;
|
|
343
|
-
if (!target?.texture) {
|
|
344
|
-
return;
|
|
345
|
-
}
|
|
346
|
-
const w = target.width;
|
|
347
|
-
const h = target.height;
|
|
348
|
-
this.flush();
|
|
349
|
-
for (const filter of filters) {
|
|
350
|
-
if (filter instanceof BlurFilter && (filter.blurX > 0 || filter.blurY > 0)) {
|
|
351
|
-
this._drawBlurPingPong(target.texture, w, h, filter, offscreen, offscreen.resolution);
|
|
352
|
-
}
|
|
353
|
-
}
|
|
354
|
-
if (this._currentBuffer) {
|
|
355
|
-
this._currentBuffer.rootRenderTarget.activate();
|
|
356
|
-
this.onResize(this._currentBuffer.width, this._currentBuffer.height);
|
|
357
|
-
}
|
|
358
|
-
const nonBlurFilter = filters.find(f => !(f instanceof BlurFilter));
|
|
359
|
-
this._filterResolution = offscreen.resolution;
|
|
360
|
-
this.activeFilter = nonBlurFilter;
|
|
361
|
-
this.drawTexture(target.texture, 0, 0, w, h, 0, 0, w / offscreen.resolution, h / offscreen.resolution, w, h);
|
|
362
|
-
this.activeFilter = undefined;
|
|
363
362
|
this.flush();
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
363
|
+
const parent = this._currentBuffer;
|
|
364
|
+
if (!parent || !offscreen.rootRenderTarget.texture)
|
|
365
|
+
return;
|
|
367
366
|
const gl = this.gl;
|
|
368
|
-
|
|
369
|
-
const
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
gl.
|
|
377
|
-
gl.
|
|
378
|
-
gl.
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
|
|
392
|
-
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
if (
|
|
415
|
-
gl.
|
|
416
|
-
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
|
|
421
|
-
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
|
|
426
|
-
return undefined;
|
|
427
|
-
this._blurFboPoolSize--;
|
|
428
|
-
this._blurFboPoolBytes -= entry.byteSize;
|
|
429
|
-
if (entries.length === 0) {
|
|
430
|
-
this._blurFboPool.delete(key);
|
|
367
|
+
const blend = gl.isEnabled(gl.BLEND);
|
|
368
|
+
const stencil = gl.isEnabled(gl.STENCIL_TEST);
|
|
369
|
+
const scissor = gl.isEnabled(gl.SCISSOR_TEST);
|
|
370
|
+
const alpha = parent.globalAlpha;
|
|
371
|
+
const tint = parent.globalTintColor;
|
|
372
|
+
const last = filters[filters.length - 1];
|
|
373
|
+
const finalFilter = last instanceof BlurFilter || last instanceof MultiPassFilter || last instanceof CustomFilter ? undefined : last;
|
|
374
|
+
try {
|
|
375
|
+
gl.disable(gl.BLEND);
|
|
376
|
+
gl.disable(gl.STENCIL_TEST);
|
|
377
|
+
gl.disable(gl.SCISSOR_TEST);
|
|
378
|
+
this._filterSystem.render(finalFilter ? filters.slice(0, -1) : filters, offscreen.rootRenderTarget, offscreen.resolution, output => {
|
|
379
|
+
parent.rootRenderTarget.activate();
|
|
380
|
+
this.onResize(parent.width, parent.height);
|
|
381
|
+
if (blend) {
|
|
382
|
+
gl.enable(gl.BLEND);
|
|
383
|
+
}
|
|
384
|
+
if (stencil) {
|
|
385
|
+
gl.enable(gl.STENCIL_TEST);
|
|
386
|
+
}
|
|
387
|
+
if (scissor) {
|
|
388
|
+
gl.enable(gl.SCISSOR_TEST);
|
|
389
|
+
}
|
|
390
|
+
// Subtree vertices already contain world alpha and tint.
|
|
391
|
+
parent.globalAlpha = 1;
|
|
392
|
+
parent.globalTintColor = 0xffffff;
|
|
393
|
+
this._filterResolution = output.width * offscreen.resolution / offscreen.width;
|
|
394
|
+
this.activeFilter = finalFilter;
|
|
395
|
+
this.drawFramebufferTexture(output.texture, output.width, output.height, 0, 0, offscreen.width / offscreen.resolution, offscreen.height / offscreen.resolution);
|
|
396
|
+
this.flush();
|
|
397
|
+
});
|
|
398
|
+
}
|
|
399
|
+
finally {
|
|
400
|
+
this.activeFilter = undefined;
|
|
401
|
+
this._filterResolution = 1;
|
|
402
|
+
this._filterPassInputs = {};
|
|
403
|
+
parent.globalAlpha = alpha;
|
|
404
|
+
parent.globalTintColor = tint;
|
|
405
|
+
parent.rootRenderTarget.activate();
|
|
406
|
+
this.onResize(parent.width, parent.height);
|
|
407
|
+
if (blend) {
|
|
408
|
+
gl.enable(gl.BLEND);
|
|
409
|
+
}
|
|
410
|
+
else {
|
|
411
|
+
gl.disable(gl.BLEND);
|
|
412
|
+
}
|
|
413
|
+
if (stencil) {
|
|
414
|
+
gl.enable(gl.STENCIL_TEST);
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
gl.disable(gl.STENCIL_TEST);
|
|
418
|
+
}
|
|
419
|
+
if (scissor) {
|
|
420
|
+
gl.enable(gl.SCISSOR_TEST);
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
gl.disable(gl.SCISSOR_TEST);
|
|
424
|
+
}
|
|
431
425
|
}
|
|
432
|
-
return entry;
|
|
433
426
|
}
|
|
434
|
-
|
|
435
|
-
if (
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
427
|
+
$drawFilterPass(filter, input, output, resolution, textures = {}) {
|
|
428
|
+
if (input === output || Object.values(textures).some(value => value.texture === output.texture)) {
|
|
429
|
+
throw new Error('A filter cannot read from its output framebuffer.');
|
|
430
|
+
}
|
|
431
|
+
output.activate();
|
|
432
|
+
this.gl.viewport(0, 0, output.width, output.height);
|
|
433
|
+
// Custom vertex shaders may cover only part of the output or discard fragments.
|
|
434
|
+
output.clear();
|
|
435
|
+
this._filterResolution = filter instanceof CustomFilter ? resolution : resolution * input.width / output.width;
|
|
436
|
+
this._filterOutputWidth = output.width;
|
|
437
|
+
this._filterOutputHeight = output.height;
|
|
438
|
+
this._filterPassInputs = textures;
|
|
439
|
+
try {
|
|
440
|
+
this._drawFullscreenQuad(this._getTextureProgram(filter), input.texture, output.width, output.height, program => this._uploadFilterUniforms(program, filter, input.width, input.height));
|
|
441
|
+
}
|
|
442
|
+
finally {
|
|
443
|
+
this._filterPassInputs = {};
|
|
444
|
+
}
|
|
445
|
+
}
|
|
446
|
+
$drawBlurPass(horizontal, input, output, radius) {
|
|
447
|
+
if (input === output)
|
|
448
|
+
throw new Error('A blur cannot read from its output framebuffer.');
|
|
449
|
+
output.activate();
|
|
450
|
+
this.gl.viewport(0, 0, output.width, output.height);
|
|
451
|
+
const tier = this.blurTierFn(radius);
|
|
452
|
+
const source = horizontal ? this.makeBlurH(tier) : this.makeBlurV(tier);
|
|
453
|
+
const program = WebGLProgram.get(this.gl, this.shaders.fullscreen_vert, source, `blur_${horizontal ? 'h' : 'v'}_${tier}`);
|
|
454
|
+
this._drawFullscreenQuad(program, input.texture, output.width, output.height, prog => {
|
|
455
|
+
const radiusLocation = prog.uniforms[horizontal ? 'blurX' : 'blurY'];
|
|
456
|
+
if (radiusLocation) {
|
|
457
|
+
this.gl.uniform1f(radiusLocation, radius);
|
|
452
458
|
}
|
|
453
|
-
if (
|
|
454
|
-
this.
|
|
459
|
+
if (prog.uniforms.uTextureSize) {
|
|
460
|
+
this.gl.uniform2f(prog.uniforms.uTextureSize, input.width, input.height);
|
|
455
461
|
}
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
this.
|
|
464
|
-
this.
|
|
462
|
+
});
|
|
463
|
+
}
|
|
464
|
+
/**
|
|
465
|
+
* Releases idle effect targets and auxiliary image uploads. Images remain caller-owned.
|
|
466
|
+
*/
|
|
467
|
+
releaseFilterResources() {
|
|
468
|
+
this.flush();
|
|
469
|
+
this._filterSystem.pool.clear();
|
|
470
|
+
this._filterTextures.clear();
|
|
465
471
|
}
|
|
466
472
|
_drawFullscreenQuad(prog, texture, w, h, setUniforms) {
|
|
467
473
|
const gl = this.gl;
|
|
@@ -482,40 +488,44 @@ export class WebGLRenderContext {
|
|
|
482
488
|
gl.enableVertexAttribArray(aColor);
|
|
483
489
|
gl.vertexAttribPointer(aColor, 4, gl.UNSIGNED_BYTE, true, stride, 16);
|
|
484
490
|
}
|
|
491
|
+
setUniforms(prog);
|
|
485
492
|
const uProj = prog.uniforms['projectionVector'];
|
|
486
493
|
if (uProj)
|
|
487
494
|
gl.uniform2f(uProj, w / 2, -h / 2);
|
|
488
495
|
const uSampler = prog.uniforms['uSampler'];
|
|
489
496
|
if (uSampler)
|
|
490
497
|
gl.uniform1i(uSampler, 0);
|
|
498
|
+
gl.activeTexture(gl.TEXTURE0);
|
|
491
499
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
492
|
-
setUniforms(prog);
|
|
493
500
|
const f32 = new Float32Array(20);
|
|
494
501
|
const u32 = new Uint32Array(f32.buffer);
|
|
495
502
|
const packed = 0xffffffff;
|
|
496
503
|
f32[0] = 0;
|
|
497
504
|
f32[1] = 0;
|
|
498
505
|
f32[2] = 0;
|
|
499
|
-
f32[3] =
|
|
506
|
+
f32[3] = 1;
|
|
500
507
|
u32[4] = packed;
|
|
501
508
|
f32[5] = w;
|
|
502
509
|
f32[6] = 0;
|
|
503
510
|
f32[7] = 1;
|
|
504
|
-
f32[8] =
|
|
511
|
+
f32[8] = 1;
|
|
505
512
|
u32[9] = packed;
|
|
506
513
|
f32[10] = w;
|
|
507
514
|
f32[11] = h;
|
|
508
515
|
f32[12] = 1;
|
|
509
|
-
f32[13] =
|
|
516
|
+
f32[13] = 0;
|
|
510
517
|
u32[14] = packed;
|
|
511
518
|
f32[15] = 0;
|
|
512
519
|
f32[16] = h;
|
|
513
520
|
f32[17] = 0;
|
|
514
|
-
f32[18] =
|
|
521
|
+
f32[18] = 0;
|
|
515
522
|
u32[19] = packed;
|
|
516
523
|
gl.bufferData(gl.ARRAY_BUFFER, f32, gl.STREAM_DRAW);
|
|
517
524
|
gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array([0, 1, 2, 0, 2, 3]), gl.STATIC_DRAW);
|
|
518
525
|
gl.drawElements(gl.TRIANGLES, 6, gl.UNSIGNED_SHORT, 0);
|
|
526
|
+
if (this._currentBuffer) {
|
|
527
|
+
this._currentBuffer.drawCalls++;
|
|
528
|
+
}
|
|
519
529
|
gl.bufferData(gl.ARRAY_BUFFER, this._gpuVertexBufferSize, gl.DYNAMIC_DRAW);
|
|
520
530
|
this._bindIndices = false;
|
|
521
531
|
}
|
|
@@ -527,7 +537,40 @@ export class WebGLRenderContext {
|
|
|
527
537
|
}
|
|
528
538
|
// ── Execute ───────────────────────────────────────────────────────────────
|
|
529
539
|
flush() {
|
|
530
|
-
|
|
540
|
+
try {
|
|
541
|
+
this._flush();
|
|
542
|
+
}
|
|
543
|
+
catch (error) {
|
|
544
|
+
this.drawCmdManager.clear();
|
|
545
|
+
this._vao.clear();
|
|
546
|
+
this._batcher.reset();
|
|
547
|
+
this._bindIndices = false;
|
|
548
|
+
throw error;
|
|
549
|
+
}
|
|
550
|
+
}
|
|
551
|
+
$abortFrame(buffer) {
|
|
552
|
+
this.drawCmdManager.clear();
|
|
553
|
+
this._vao.clear();
|
|
554
|
+
this._batcher.reset();
|
|
555
|
+
this._bindIndices = false;
|
|
556
|
+
this.activeFilter = undefined;
|
|
557
|
+
this._bufferStack.length = 0;
|
|
558
|
+
this._bufferStack.push(buffer);
|
|
559
|
+
this._currentBuffer = buffer;
|
|
560
|
+
buffer.stencilList.length = 0;
|
|
561
|
+
buffer.stencilHandleCount = 0;
|
|
562
|
+
buffer.disableStencil();
|
|
563
|
+
buffer.disableScissor();
|
|
564
|
+
buffer.hasScissor = false;
|
|
565
|
+
buffer.rootRenderTarget.activate();
|
|
566
|
+
this.gl.activeTexture(this.gl.TEXTURE0);
|
|
567
|
+
this.gl.enable(this.gl.BLEND);
|
|
568
|
+
this.gl.disable(this.gl.SCISSOR_TEST);
|
|
569
|
+
this.gl.disable(this.gl.STENCIL_TEST);
|
|
570
|
+
this.gl.colorMask(true, true, true, true);
|
|
571
|
+
this.currentBlendMode = 'source-over';
|
|
572
|
+
this._applyBlend('source-over');
|
|
573
|
+
this.onResize(buffer.width, buffer.height);
|
|
531
574
|
}
|
|
532
575
|
// ── Private — flush & dispatch ────────────────────────────────────────────
|
|
533
576
|
_onContextRestored() {
|
|
@@ -543,15 +586,14 @@ export class WebGLRenderContext {
|
|
|
543
586
|
gl.bindBuffer(gl.ARRAY_BUFFER, this._vertexBuffer);
|
|
544
587
|
gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, this._indexBuffer);
|
|
545
588
|
gl.bufferData(gl.ARRAY_BUFFER, this._gpuVertexBufferSize, gl.DYNAMIC_DRAW);
|
|
546
|
-
WebGLProgram.clearCache();
|
|
589
|
+
WebGLProgram.clearCache(gl, true);
|
|
547
590
|
this._bindIndices = false;
|
|
548
591
|
this._batcher.reset();
|
|
549
592
|
this.drawCmdManager.clear();
|
|
550
593
|
this._vao.clear();
|
|
551
594
|
this._defaultEmptyTexture = undefined;
|
|
552
|
-
this.
|
|
553
|
-
this.
|
|
554
|
-
this._blurFboPoolBytes = 0;
|
|
595
|
+
this._filterTextures.clear(true);
|
|
596
|
+
this._filterSystem.pool.clear(true);
|
|
555
597
|
WebGLRenderBuffer.handleContextRestored(this);
|
|
556
598
|
for (const ref of this._trackedBitmapDatas) {
|
|
557
599
|
const bd = ref.deref();
|
|
@@ -730,10 +772,14 @@ export class WebGLRenderContext {
|
|
|
730
772
|
gl.drawElements(gl.TRIANGLES, count * 3, gl.UNSIGNED_SHORT, indexOffset * 6);
|
|
731
773
|
}
|
|
732
774
|
_getTextureProgram(filter) {
|
|
775
|
+
if (filter instanceof CustomFilter) {
|
|
776
|
+
const source = filter.$getProgram(this.isWebGL2);
|
|
777
|
+
return WebGLProgram.get(this.gl, source.vertex ?? this.shaders.fullscreen_vert, source.fragment, 'CustomFilter');
|
|
778
|
+
}
|
|
733
779
|
if (filter instanceof ColorMatrixFilter) {
|
|
734
780
|
return WebGLProgram.get(this.gl, this.shaders.default_vert, this.shaders.colorTransform_frag, 'colorTransform');
|
|
735
781
|
}
|
|
736
|
-
if (filter instanceof
|
|
782
|
+
if (filter instanceof GlowFilter || filter instanceof DropShadowFilter) {
|
|
737
783
|
return WebGLProgram.get(this.gl, this.shaders.default_vert, this.shaders.glow_frag, 'glow');
|
|
738
784
|
}
|
|
739
785
|
return WebGLProgram.get(this.gl, this.shaders.default_vert, this.shaders.texture_frag, 'texture');
|
|
@@ -765,6 +811,16 @@ export class WebGLRenderContext {
|
|
|
765
811
|
if (uSampler)
|
|
766
812
|
gl.uniform1i(uSampler, 0);
|
|
767
813
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
814
|
+
this._uploadFilterUniforms(prog, filter, texW, texH);
|
|
815
|
+
gl.drawElements(gl.TRIANGLES, count * 3, gl.UNSIGNED_SHORT, indexOffset * 6);
|
|
816
|
+
}
|
|
817
|
+
_uploadFilterUniforms(prog, filter, texW, texH) {
|
|
818
|
+
const gl = this.gl;
|
|
819
|
+
if (filter instanceof CustomFilter) {
|
|
820
|
+
uploadCustomUniforms(gl, prog, filter, texW, texH, this._filterResolution, this._filterOutputWidth || texW, this._filterOutputHeight || texH, this._filterPassInputs);
|
|
821
|
+
this._filterTextures.bind(prog, filter, this._filterPassInputs);
|
|
822
|
+
return;
|
|
823
|
+
}
|
|
768
824
|
if (filter instanceof ColorMatrixFilter) {
|
|
769
825
|
const uMatrix = prog.uniforms['matrix'];
|
|
770
826
|
const uAdd = prog.uniforms['colorAdd'];
|
|
@@ -808,7 +864,7 @@ export class WebGLRenderContext {
|
|
|
808
864
|
gl.uniform1f(uDist, filter.distance * this._filterResolution);
|
|
809
865
|
const uAngle = prog.uniforms['angle'];
|
|
810
866
|
if (uAngle)
|
|
811
|
-
gl.uniform1f(uAngle,
|
|
867
|
+
gl.uniform1f(uAngle, (filter.angle / 180) * Math.PI);
|
|
812
868
|
const uHide = prog.uniforms['hideObject'];
|
|
813
869
|
if (uHide)
|
|
814
870
|
gl.uniform1f(uHide, filter.hideObject ? 1 : 0);
|
|
@@ -829,9 +885,8 @@ export class WebGLRenderContext {
|
|
|
829
885
|
gl.uniform1f(uInner, filter instanceof GlowFilter && filter.inner ? 1 : 0);
|
|
830
886
|
const uKnockout = prog.uniforms['knockout'];
|
|
831
887
|
if (uKnockout)
|
|
832
|
-
gl.uniform1f(uKnockout, filter instanceof GlowFilter && filter.knockout ?
|
|
888
|
+
gl.uniform1f(uKnockout, filter instanceof GlowFilter && filter.knockout ? 0 : 1);
|
|
833
889
|
}
|
|
834
|
-
gl.drawElements(gl.TRIANGLES, count * 3, gl.UNSIGNED_SHORT, indexOffset * 6);
|
|
835
890
|
}
|
|
836
891
|
_drawRectBatch(indexOffset, count) {
|
|
837
892
|
const gl = this.gl;
|