@swf2es/context3d 0.1.17 → 0.1.19
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/backend.d.ts +30 -4
- package/dist/backend.d.ts.map +1 -1
- package/dist/backend.js +17 -0
- package/dist/backend.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/webgl/context.d.ts +27 -3
- package/dist/webgl/context.d.ts.map +1 -1
- package/dist/webgl/context.js +196 -29
- package/dist/webgl/context.js.map +1 -1
- package/dist/webgl/textures.d.ts +2 -0
- package/dist/webgl/textures.d.ts.map +1 -1
- package/dist/webgl/textures.js.map +1 -1
- package/package.json +1 -1
- package/src/backend.ts +51 -4
- package/src/index.ts +2 -0
- package/src/webgl/context.ts +256 -33
- package/src/webgl/textures.ts +2 -0
package/src/webgl/context.ts
CHANGED
|
@@ -5,6 +5,7 @@ import {
|
|
|
5
5
|
type CompareMode,
|
|
6
6
|
type Context3D,
|
|
7
7
|
type CullFace,
|
|
8
|
+
MOST_BACK_BUFFER,
|
|
8
9
|
type Program3D,
|
|
9
10
|
SAMPLER_FILTERS,
|
|
10
11
|
SAMPLER_MIPS,
|
|
@@ -14,6 +15,7 @@ import {
|
|
|
14
15
|
type SamplerWrap,
|
|
15
16
|
ScissorBoundsError,
|
|
16
17
|
type StencilAction,
|
|
18
|
+
screenPixels,
|
|
17
19
|
type Texture3D,
|
|
18
20
|
TextureBindingError,
|
|
19
21
|
type TextureFormat,
|
|
@@ -94,6 +96,13 @@ export class WebGLContext3D implements Context3D {
|
|
|
94
96
|
private readonly drawState: GlState;
|
|
95
97
|
width = 0;
|
|
96
98
|
height = 0;
|
|
99
|
+
/**
|
|
100
|
+
* The back buffer's storage: its size, or less where the GPU allows less. The SWF still
|
|
101
|
+
* sees the size it asked for, drawn at this one and stretched to it when presented.
|
|
102
|
+
*/
|
|
103
|
+
private drawnWidth = 0;
|
|
104
|
+
private drawnHeight = 0;
|
|
105
|
+
private gpuMost: Int32Array | null = null;
|
|
97
106
|
disposed = false;
|
|
98
107
|
samplerFormats = true;
|
|
99
108
|
private readonly buffers = new Map<Buffer3D, BufferState>();
|
|
@@ -134,6 +143,8 @@ export class WebGLContext3D implements Context3D {
|
|
|
134
143
|
private resolveDirty = false;
|
|
135
144
|
private depthBuffer: WebGLRenderbuffer | null = null;
|
|
136
145
|
private antiAlias = 0;
|
|
146
|
+
/** The back buffer's pixels to a CSS pixel and to a scissor rectangle's unit. */
|
|
147
|
+
private scale = 1;
|
|
137
148
|
private depthWrite = true;
|
|
138
149
|
private depthCompare: CompareMode = "less";
|
|
139
150
|
private blendEnabled = false;
|
|
@@ -225,7 +236,12 @@ export class WebGLContext3D implements Context3D {
|
|
|
225
236
|
}
|
|
226
237
|
}
|
|
227
238
|
this.drawState.bindFramebuffer(state ? targetFramebuffer(state) : this.framebuffer);
|
|
228
|
-
this.drawState.viewport(
|
|
239
|
+
this.drawState.viewport(
|
|
240
|
+
0,
|
|
241
|
+
0,
|
|
242
|
+
texture?.width ?? this.drawnWidth,
|
|
243
|
+
texture?.height ?? this.drawnHeight,
|
|
244
|
+
);
|
|
229
245
|
}
|
|
230
246
|
|
|
231
247
|
/** Temporary attachments and separate READ/DRAW bindings bypass the hot target cache. */
|
|
@@ -234,10 +250,10 @@ export class WebGLContext3D implements Context3D {
|
|
|
234
250
|
this.gl.bindFramebuffer(target, framebuffer);
|
|
235
251
|
}
|
|
236
252
|
|
|
237
|
-
configure(width: number, height: number, depth = false, antiAlias = 0): void {
|
|
253
|
+
configure(width: number, height: number, depth = false, antiAlias = 0, scale = 1): void {
|
|
238
254
|
this.alive();
|
|
239
|
-
range(32, width - 32,
|
|
240
|
-
range(32, height - 32,
|
|
255
|
+
range(32, width - 32, MOST_BACK_BUFFER);
|
|
256
|
+
range(32, height - 32, MOST_BACK_BUFFER);
|
|
241
257
|
if (this.renderTexture) {
|
|
242
258
|
throw new Context3DError(
|
|
243
259
|
"operation",
|
|
@@ -254,11 +270,20 @@ export class WebGLContext3D implements Context3D {
|
|
|
254
270
|
depth === (this.depthBuffer !== null) &&
|
|
255
271
|
antiAlias === this.antiAlias
|
|
256
272
|
) {
|
|
273
|
+
if (scale !== this.scale) {
|
|
274
|
+
this.scale = scale;
|
|
275
|
+
this.showAt();
|
|
276
|
+
this.applyScissor();
|
|
277
|
+
}
|
|
278
|
+
|
|
257
279
|
return;
|
|
258
280
|
}
|
|
259
281
|
|
|
260
282
|
const samples = selectSamples(this.gl, antiAlias, depth);
|
|
261
283
|
const gl = this.gl;
|
|
284
|
+
const most = this.storageLimit();
|
|
285
|
+
const drawnWidth = Math.min(width, most[0]);
|
|
286
|
+
const drawnHeight = Math.min(height, most[1]);
|
|
262
287
|
const texture = gl.createTexture();
|
|
263
288
|
const framebuffer = gl.createFramebuffer();
|
|
264
289
|
const depthBuffer = depth ? gl.createRenderbuffer() : null;
|
|
@@ -279,7 +304,17 @@ export class WebGLContext3D implements Context3D {
|
|
|
279
304
|
gl.bindTexture(gl.TEXTURE_2D, texture);
|
|
280
305
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
|
|
281
306
|
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
|
|
282
|
-
gl.texImage2D(
|
|
307
|
+
gl.texImage2D(
|
|
308
|
+
gl.TEXTURE_2D,
|
|
309
|
+
0,
|
|
310
|
+
gl.RGBA8,
|
|
311
|
+
drawnWidth,
|
|
312
|
+
drawnHeight,
|
|
313
|
+
0,
|
|
314
|
+
gl.RGBA,
|
|
315
|
+
gl.UNSIGNED_BYTE,
|
|
316
|
+
null,
|
|
317
|
+
);
|
|
283
318
|
this.bindFramebuffer(gl.FRAMEBUFFER, resolveFramebuffer ?? framebuffer);
|
|
284
319
|
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
|
|
285
320
|
if (resolveFramebuffer) {
|
|
@@ -289,7 +324,13 @@ export class WebGLContext3D implements Context3D {
|
|
|
289
324
|
|
|
290
325
|
this.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
|
|
291
326
|
gl.bindRenderbuffer(gl.RENDERBUFFER, colorBuffer);
|
|
292
|
-
gl.renderbufferStorageMultisample(
|
|
327
|
+
gl.renderbufferStorageMultisample(
|
|
328
|
+
gl.RENDERBUFFER,
|
|
329
|
+
samples,
|
|
330
|
+
gl.RGBA8,
|
|
331
|
+
drawnWidth,
|
|
332
|
+
drawnHeight,
|
|
333
|
+
);
|
|
293
334
|
gl.framebufferRenderbuffer(
|
|
294
335
|
gl.FRAMEBUFFER,
|
|
295
336
|
gl.COLOR_ATTACHMENT0,
|
|
@@ -304,11 +345,11 @@ export class WebGLContext3D implements Context3D {
|
|
|
304
345
|
gl.RENDERBUFFER,
|
|
305
346
|
samples,
|
|
306
347
|
gl.DEPTH24_STENCIL8,
|
|
307
|
-
|
|
308
|
-
|
|
348
|
+
drawnWidth,
|
|
349
|
+
drawnHeight,
|
|
309
350
|
);
|
|
310
351
|
} else {
|
|
311
|
-
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8,
|
|
352
|
+
gl.renderbufferStorage(gl.RENDERBUFFER, gl.DEPTH24_STENCIL8, drawnWidth, drawnHeight);
|
|
312
353
|
}
|
|
313
354
|
gl.framebufferRenderbuffer(
|
|
314
355
|
gl.FRAMEBUFFER,
|
|
@@ -345,14 +386,81 @@ export class WebGLContext3D implements Context3D {
|
|
|
345
386
|
this.antiAlias = antiAlias;
|
|
346
387
|
this.width = width;
|
|
347
388
|
this.height = height;
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
this.
|
|
351
|
-
|
|
389
|
+
this.drawnWidth = drawnWidth;
|
|
390
|
+
this.drawnHeight = drawnHeight;
|
|
391
|
+
this.scale = scale;
|
|
392
|
+
gl.canvas.width = drawnWidth;
|
|
393
|
+
gl.canvas.height = drawnHeight;
|
|
394
|
+
this.showAt();
|
|
395
|
+
// Readback's storage waits for a read: a back buffer as large as a 4K screen is 33 MB each.
|
|
396
|
+
this.pixels = new Uint8Array(0);
|
|
397
|
+
this.topDown = new Uint8Array(0);
|
|
352
398
|
this.applyScissor();
|
|
353
399
|
this.clear(0, 0, 0, 1);
|
|
354
400
|
}
|
|
355
401
|
|
|
402
|
+
/**
|
|
403
|
+
* Shown at the size asked for, in CSS pixels, as an unstyled canvas of that size would be,
|
|
404
|
+
* divided by its scale: a best-resolution back buffer shows its pixels at the screen's.
|
|
405
|
+
*/
|
|
406
|
+
private showAt(): void {
|
|
407
|
+
const style = (this.gl.canvas as Partial<HTMLCanvasElement>).style;
|
|
408
|
+
if (!style) {
|
|
409
|
+
return;
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const plain = this.scale === 1;
|
|
413
|
+
style.width = plain && this.drawnWidth === this.width ? "" : `${this.width / this.scale}px`;
|
|
414
|
+
style.height = plain && this.drawnHeight === this.height ? "" : `${this.height / this.scale}px`;
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
/** The largest back buffer storage the GPU gives: a texture, a renderbuffer and a viewport. */
|
|
418
|
+
private storageLimit(): Int32Array {
|
|
419
|
+
if (!this.gpuMost) {
|
|
420
|
+
const gl = this.gl;
|
|
421
|
+
const viewport = gl.getParameter(gl.MAX_VIEWPORT_DIMS) as Int32Array;
|
|
422
|
+
const side = Math.min(
|
|
423
|
+
gl.getParameter(gl.MAX_TEXTURE_SIZE) as number,
|
|
424
|
+
gl.getParameter(gl.MAX_RENDERBUFFER_SIZE) as number,
|
|
425
|
+
);
|
|
426
|
+
this.gpuMost = Int32Array.of(Math.min(side, viewport[0]), Math.min(side, viewport[1]));
|
|
427
|
+
}
|
|
428
|
+
|
|
429
|
+
return this.gpuMost;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
unconfigure(): void {
|
|
433
|
+
this.alive();
|
|
434
|
+
if (this.renderTexture) {
|
|
435
|
+
throw new Context3DError(
|
|
436
|
+
"operation",
|
|
437
|
+
"Context3D experiment: resize while rendering to texture",
|
|
438
|
+
);
|
|
439
|
+
}
|
|
440
|
+
|
|
441
|
+
const gl = this.gl;
|
|
442
|
+
gl.deleteTexture(this.texture);
|
|
443
|
+
gl.deleteFramebuffer(this.framebuffer);
|
|
444
|
+
gl.deleteFramebuffer(this.resolveFramebuffer);
|
|
445
|
+
gl.deleteRenderbuffer(this.depthBuffer);
|
|
446
|
+
gl.deleteRenderbuffer(this.colorBuffer);
|
|
447
|
+
this.drawState.forget();
|
|
448
|
+
this.texture = null;
|
|
449
|
+
this.framebuffer = null;
|
|
450
|
+
this.resolveFramebuffer = null;
|
|
451
|
+
this.colorBuffer = null;
|
|
452
|
+
this.depthBuffer = null;
|
|
453
|
+
this.resolveDirty = false;
|
|
454
|
+
this.antiAlias = 0;
|
|
455
|
+
this.scale = 1;
|
|
456
|
+
this.width = 0;
|
|
457
|
+
this.height = 0;
|
|
458
|
+
this.drawnWidth = 0;
|
|
459
|
+
this.drawnHeight = 0;
|
|
460
|
+
this.pixels = new Uint8Array(0);
|
|
461
|
+
this.topDown = new Uint8Array(0);
|
|
462
|
+
}
|
|
463
|
+
|
|
356
464
|
clear(
|
|
357
465
|
red: number,
|
|
358
466
|
green: number,
|
|
@@ -565,15 +673,36 @@ export class WebGLContext3D implements Context3D {
|
|
|
565
673
|
|
|
566
674
|
const width = this.renderTexture?.width ?? this.width;
|
|
567
675
|
const height = this.renderTexture?.height ?? this.height;
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
676
|
+
let left = Math.max(0, Math.min(width, this.scissorLeft));
|
|
677
|
+
let top = Math.max(0, Math.min(height, this.scissorTop));
|
|
678
|
+
let right = Math.max(0, Math.min(width, this.scissorRight));
|
|
679
|
+
let bottom = Math.max(0, Math.min(height, this.scissorBottom));
|
|
680
|
+
// AIR tells a rectangle outside from its own unit, then scales it to a back buffer
|
|
681
|
+
// configured for best resolution, whose pixels are the screen's.
|
|
572
682
|
this.scissorOutside = right <= left || bottom <= top;
|
|
683
|
+
if (!this.renderTexture && this.scale !== 1) {
|
|
684
|
+
const scale = this.scale;
|
|
685
|
+
left = Math.max(0, Math.min(width, screenPixels(this.scissorLeft, scale)));
|
|
686
|
+
top = Math.max(0, Math.min(height, screenPixels(this.scissorTop, scale)));
|
|
687
|
+
right = Math.max(0, Math.min(width, screenPixels(this.scissorRight, scale)));
|
|
688
|
+
bottom = Math.max(0, Math.min(height, screenPixels(this.scissorBottom, scale)));
|
|
689
|
+
}
|
|
690
|
+
let drawnHeight = height;
|
|
691
|
+
if (!this.renderTexture && (this.drawnWidth !== width || this.drawnHeight !== height)) {
|
|
692
|
+
// The back buffer's storage is smaller than its size: the rectangle shrinks with it.
|
|
693
|
+
const x = this.drawnWidth / width;
|
|
694
|
+
const y = this.drawnHeight / height;
|
|
695
|
+
left = Math.round(left * x);
|
|
696
|
+
right = Math.round(right * x);
|
|
697
|
+
top = Math.round(top * y);
|
|
698
|
+
bottom = Math.round(bottom * y);
|
|
699
|
+
drawnHeight = this.drawnHeight;
|
|
700
|
+
}
|
|
701
|
+
|
|
573
702
|
gl.enable(gl.SCISSOR_TEST);
|
|
574
703
|
gl.scissor(
|
|
575
704
|
left,
|
|
576
|
-
this.renderTexture ? top :
|
|
705
|
+
this.renderTexture ? top : drawnHeight - bottom,
|
|
577
706
|
Math.max(0, right - left),
|
|
578
707
|
Math.max(0, bottom - top),
|
|
579
708
|
);
|
|
@@ -630,7 +759,7 @@ export class WebGLContext3D implements Context3D {
|
|
|
630
759
|
}
|
|
631
760
|
}
|
|
632
761
|
|
|
633
|
-
createBuffer(count: number, stride: number): Buffer3D {
|
|
762
|
+
createBuffer(count: number, stride: number, dynamic = false): Buffer3D {
|
|
634
763
|
this.alive();
|
|
635
764
|
range(1, count - 1, stride === 0 ? 524287 : 65535);
|
|
636
765
|
range(0, stride, 64);
|
|
@@ -661,7 +790,7 @@ export class WebGLContext3D implements Context3D {
|
|
|
661
790
|
}
|
|
662
791
|
gl.bindVertexArray(this.vao);
|
|
663
792
|
gl.bindBuffer(target, handle);
|
|
664
|
-
gl.bufferData(target, bytes, gl.STATIC_DRAW);
|
|
793
|
+
gl.bufferData(target, bytes, dynamic ? gl.DYNAMIC_DRAW : gl.STATIC_DRAW);
|
|
665
794
|
const state: BufferState = {
|
|
666
795
|
handle,
|
|
667
796
|
indices: stride === 0 ? new Uint16Array(count) : null,
|
|
@@ -834,8 +963,9 @@ export class WebGLContext3D implements Context3D {
|
|
|
834
963
|
height: number,
|
|
835
964
|
cube = false,
|
|
836
965
|
format: TextureFormat = "bgra",
|
|
966
|
+
streaming = 0,
|
|
837
967
|
): Texture3D {
|
|
838
|
-
return this.allocateTexture(width, height, cube, false, format);
|
|
968
|
+
return this.allocateTexture(width, height, cube, false, format, streaming);
|
|
839
969
|
}
|
|
840
970
|
|
|
841
971
|
createRectangleTexture(width: number, height: number): Texture3D {
|
|
@@ -885,6 +1015,7 @@ export class WebGLContext3D implements Context3D {
|
|
|
885
1015
|
cube: boolean,
|
|
886
1016
|
rectangle: boolean,
|
|
887
1017
|
format: TextureFormat,
|
|
1018
|
+
streaming = 0,
|
|
888
1019
|
): Texture3D {
|
|
889
1020
|
this.alive();
|
|
890
1021
|
range(1, width - 1, 2048);
|
|
@@ -898,6 +1029,7 @@ export class WebGLContext3D implements Context3D {
|
|
|
898
1029
|
|
|
899
1030
|
const faces = cube ? 6 : 1;
|
|
900
1031
|
const levels = rectangle ? 1 : 1 + Math.floor(Math.log2(Math.max(width, height)));
|
|
1032
|
+
range(streaming, 1, levels);
|
|
901
1033
|
if (!rectangle && ((width & (width - 1)) !== 0 || (height & (height - 1)) !== 0)) {
|
|
902
1034
|
throw new Context3DError(
|
|
903
1035
|
"texturePowerOfTwo",
|
|
@@ -963,6 +1095,7 @@ export class WebGLContext3D implements Context3D {
|
|
|
963
1095
|
multisample: null,
|
|
964
1096
|
samples: 0,
|
|
965
1097
|
antiAlias: 0,
|
|
1098
|
+
base: 0,
|
|
966
1099
|
};
|
|
967
1100
|
const texture: Texture3D = {
|
|
968
1101
|
width,
|
|
@@ -971,6 +1104,7 @@ export class WebGLContext3D implements Context3D {
|
|
|
971
1104
|
cube,
|
|
972
1105
|
rectangle,
|
|
973
1106
|
format,
|
|
1107
|
+
streaming,
|
|
974
1108
|
upload: (pixels, level = 0, face = 0, sourceWidth, sourceHeight) => {
|
|
975
1109
|
this.alive();
|
|
976
1110
|
this.textureState(texture);
|
|
@@ -1800,7 +1934,10 @@ export class WebGLContext3D implements Context3D {
|
|
|
1800
1934
|
throw new TextureBindingError("unuploaded");
|
|
1801
1935
|
}
|
|
1802
1936
|
}
|
|
1803
|
-
|
|
1937
|
+
const base = texture.streaming
|
|
1938
|
+
? this.streamingBase(texture, resource, this.samplerStates[slot] >>> 5 !== 0)
|
|
1939
|
+
: 0;
|
|
1940
|
+
for (let face = 0; !texture.streaming && face < resource.uploaded.length; face++) {
|
|
1804
1941
|
if (!texture.cube && !(resource.uploaded[face] & 1)) {
|
|
1805
1942
|
throw new TextureBindingError("unuploaded");
|
|
1806
1943
|
}
|
|
@@ -1823,6 +1960,13 @@ export class WebGLContext3D implements Context3D {
|
|
|
1823
1960
|
gl.bindSampler(slot, this.sampler(this.samplerStates[slot]));
|
|
1824
1961
|
this.texturesApplied[slot] = 1;
|
|
1825
1962
|
}
|
|
1963
|
+
if (resource.base !== base) {
|
|
1964
|
+
const target = texture.cube ? gl.TEXTURE_CUBE_MAP : gl.TEXTURE_2D;
|
|
1965
|
+
gl.activeTexture(gl.TEXTURE0 + slot);
|
|
1966
|
+
gl.bindTexture(target, resource.handle);
|
|
1967
|
+
gl.texParameteri(target, gl.TEXTURE_BASE_LEVEL, base);
|
|
1968
|
+
resource.base = base;
|
|
1969
|
+
}
|
|
1826
1970
|
if (!state.samplersSet) {
|
|
1827
1971
|
gl.uniform1i(binding.location, slot);
|
|
1828
1972
|
}
|
|
@@ -1852,6 +1996,50 @@ export class WebGLContext3D implements Context3D {
|
|
|
1852
1996
|
this.changedTarget();
|
|
1853
1997
|
}
|
|
1854
1998
|
|
|
1999
|
+
/**
|
|
2000
|
+
* The level a streaming texture is drawn from, as AIR 51 draws one: with mip filtering, the
|
|
2001
|
+
* finest whose levels down to the smallest are uploaded on every face, which must reach its
|
|
2002
|
+
* streaming level (#3700 before); without, its level 0 alone (#3713), as a texture that
|
|
2003
|
+
* does not stream.
|
|
2004
|
+
*/
|
|
2005
|
+
private streamingBase(texture: Texture3D, resource: TextureState, mip: boolean): number {
|
|
2006
|
+
const faces = resource.uploaded.length;
|
|
2007
|
+
let uploaded = 0;
|
|
2008
|
+
for (let face = 0; face < faces; face++) {
|
|
2009
|
+
uploaded |= resource.uploaded[face];
|
|
2010
|
+
}
|
|
2011
|
+
if (!uploaded) {
|
|
2012
|
+
throw new TextureBindingError("unuploaded");
|
|
2013
|
+
}
|
|
2014
|
+
if (!mip) {
|
|
2015
|
+
for (let face = 0; face < faces; face++) {
|
|
2016
|
+
if (!(resource.uploaded[face] & 1)) {
|
|
2017
|
+
throw new TextureBindingError("streaming");
|
|
2018
|
+
}
|
|
2019
|
+
}
|
|
2020
|
+
|
|
2021
|
+
return 0;
|
|
2022
|
+
}
|
|
2023
|
+
|
|
2024
|
+
let base = texture.levels;
|
|
2025
|
+
while (base > 0) {
|
|
2026
|
+
let whole = true;
|
|
2027
|
+
for (let face = 0; face < faces; face++) {
|
|
2028
|
+
whole &&= (resource.uploaded[face] & (1 << (base - 1))) !== 0;
|
|
2029
|
+
}
|
|
2030
|
+
if (!whole) {
|
|
2031
|
+
break;
|
|
2032
|
+
}
|
|
2033
|
+
|
|
2034
|
+
base--;
|
|
2035
|
+
}
|
|
2036
|
+
if (base > texture.streaming) {
|
|
2037
|
+
throw new TextureBindingError("mipmaps");
|
|
2038
|
+
}
|
|
2039
|
+
|
|
2040
|
+
return base;
|
|
2041
|
+
}
|
|
2042
|
+
|
|
1855
2043
|
private uniforms(
|
|
1856
2044
|
locations: (WebGLUniformLocation | null)[],
|
|
1857
2045
|
bank: Constants,
|
|
@@ -1899,12 +2087,12 @@ export class WebGLContext3D implements Context3D {
|
|
|
1899
2087
|
gl.blitFramebuffer(
|
|
1900
2088
|
0,
|
|
1901
2089
|
0,
|
|
1902
|
-
this.
|
|
1903
|
-
this.
|
|
2090
|
+
this.drawnWidth,
|
|
2091
|
+
this.drawnHeight,
|
|
1904
2092
|
0,
|
|
1905
2093
|
0,
|
|
1906
|
-
this.
|
|
1907
|
-
this.
|
|
2094
|
+
this.drawnWidth,
|
|
2095
|
+
this.drawnHeight,
|
|
1908
2096
|
gl.COLOR_BUFFER_BIT,
|
|
1909
2097
|
gl.NEAREST,
|
|
1910
2098
|
);
|
|
@@ -1922,12 +2110,46 @@ export class WebGLContext3D implements Context3D {
|
|
|
1922
2110
|
this.target(true);
|
|
1923
2111
|
this.resolve();
|
|
1924
2112
|
const gl = this.gl;
|
|
2113
|
+
const scaleX = this.drawnWidth / this.width;
|
|
2114
|
+
const scaleY = this.drawnHeight / this.height;
|
|
2115
|
+
const drawnWidth = Math.min(this.drawnWidth, Math.ceil(width * scaleX));
|
|
2116
|
+
const drawnHeight = Math.min(this.drawnHeight, Math.ceil(height * scaleY));
|
|
2117
|
+
if (this.pixels.length < drawnWidth * drawnHeight * 4) {
|
|
2118
|
+
this.pixels = new Uint8Array(drawnWidth * drawnHeight * 4);
|
|
2119
|
+
}
|
|
2120
|
+
if (this.topDown.length < width * height * 4) {
|
|
2121
|
+
this.topDown = new Uint8Array(width * height * 4);
|
|
2122
|
+
}
|
|
2123
|
+
|
|
1925
2124
|
// GL's rows run bottom-up, so the top-left region starts height rows below the top.
|
|
1926
|
-
gl.readPixels(
|
|
2125
|
+
gl.readPixels(
|
|
2126
|
+
0,
|
|
2127
|
+
this.drawnHeight - drawnHeight,
|
|
2128
|
+
drawnWidth,
|
|
2129
|
+
drawnHeight,
|
|
2130
|
+
gl.RGBA,
|
|
2131
|
+
gl.UNSIGNED_BYTE,
|
|
2132
|
+
this.pixels,
|
|
2133
|
+
);
|
|
1927
2134
|
const row = width * 4;
|
|
2135
|
+
if (drawnWidth === width && drawnHeight === height) {
|
|
2136
|
+
for (let y = 0; y < height; y++) {
|
|
2137
|
+
const from = (height - y - 1) * row;
|
|
2138
|
+
this.topDown.set(this.pixels.subarray(from, from + row), y * row);
|
|
2139
|
+
}
|
|
2140
|
+
|
|
2141
|
+
return this.topDown;
|
|
2142
|
+
}
|
|
2143
|
+
|
|
2144
|
+
// Storage smaller than the back buffer: each pixel is the stored one it falls on.
|
|
2145
|
+
const source = new Uint32Array(this.pixels.buffer, 0, drawnWidth * drawnHeight);
|
|
2146
|
+
const target = new Uint32Array(this.topDown.buffer, 0, width * height);
|
|
1928
2147
|
for (let y = 0; y < height; y++) {
|
|
1929
|
-
const from =
|
|
1930
|
-
|
|
2148
|
+
const from =
|
|
2149
|
+
(drawnHeight - 1 - Math.min(drawnHeight - 1, Math.floor(y * scaleY))) * drawnWidth;
|
|
2150
|
+
for (let x = 0; x < width; x++) {
|
|
2151
|
+
target[y * width + x] = source[from + Math.min(drawnWidth - 1, Math.floor(x * scaleX))];
|
|
2152
|
+
}
|
|
1931
2153
|
}
|
|
1932
2154
|
|
|
1933
2155
|
return this.topDown;
|
|
@@ -1942,15 +2164,16 @@ export class WebGLContext3D implements Context3D {
|
|
|
1942
2164
|
if (this.scissor) {
|
|
1943
2165
|
gl.disable(gl.SCISSOR_TEST);
|
|
1944
2166
|
}
|
|
2167
|
+
// To the drawing buffer the browser gave, which it may have made smaller than the canvas.
|
|
1945
2168
|
gl.blitFramebuffer(
|
|
1946
2169
|
0,
|
|
1947
2170
|
0,
|
|
1948
|
-
this.
|
|
1949
|
-
this.
|
|
2171
|
+
this.drawnWidth,
|
|
2172
|
+
this.drawnHeight,
|
|
1950
2173
|
0,
|
|
1951
2174
|
0,
|
|
1952
|
-
|
|
1953
|
-
|
|
2175
|
+
gl.drawingBufferWidth,
|
|
2176
|
+
gl.drawingBufferHeight,
|
|
1954
2177
|
gl.COLOR_BUFFER_BIT,
|
|
1955
2178
|
gl.NEAREST,
|
|
1956
2179
|
);
|
package/src/webgl/textures.ts
CHANGED
|
@@ -20,6 +20,8 @@ export interface TextureState {
|
|
|
20
20
|
multisample: MultisampleTarget | null;
|
|
21
21
|
samples: number;
|
|
22
22
|
antiAlias: number;
|
|
23
|
+
/** TEXTURE_BASE_LEVEL: a streaming texture's finest level whole to the smallest. */
|
|
24
|
+
base: number;
|
|
23
25
|
}
|
|
24
26
|
|
|
25
27
|
/** The staging array, made base-sized at its first use: a texture given only blocks on S3TC has none. */
|