@luma.gl/webgl 9.0.17 → 9.1.0-alpha.10
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/adapter/converters/device-parameters.d.ts.map +1 -1
- package/dist/adapter/converters/device-parameters.js +30 -12
- package/dist/adapter/converters/texture-formats.d.ts +22 -16
- package/dist/adapter/converters/texture-formats.d.ts.map +1 -1
- package/dist/adapter/converters/texture-formats.js +39 -47
- package/dist/adapter/device-helpers/webgl-device-features.d.ts.map +1 -1
- package/dist/adapter/device-helpers/webgl-device-features.js +1 -2
- package/dist/adapter/device-helpers/webgl-device-limits.js +1 -1
- package/dist/adapter/helpers/webgl-texture-utils.d.ts +300 -0
- package/dist/adapter/helpers/webgl-texture-utils.d.ts.map +1 -0
- package/dist/adapter/helpers/webgl-texture-utils.js +370 -0
- package/dist/adapter/helpers/webgl-topology-utils.d.ts.map +1 -1
- package/dist/adapter/helpers/webgl-topology-utils.js +0 -4
- package/dist/adapter/resources/webgl-buffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-buffer.js +2 -2
- package/dist/adapter/resources/webgl-command-buffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-command-buffer.js +6 -9
- package/dist/adapter/resources/webgl-framebuffer.d.ts +32 -5
- package/dist/adapter/resources/webgl-framebuffer.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-framebuffer.js +42 -60
- package/dist/adapter/resources/webgl-render-pass.d.ts +3 -2
- package/dist/adapter/resources/webgl-render-pass.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-render-pass.js +18 -7
- package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-render-pipeline.js +46 -21
- package/dist/adapter/resources/webgl-shader.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-shader.js +3 -3
- package/dist/adapter/resources/webgl-texture-view.d.ts +1 -1
- package/dist/adapter/resources/webgl-texture-view.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-texture-view.js +1 -1
- package/dist/adapter/resources/webgl-texture.d.ts +76 -172
- package/dist/adapter/resources/webgl-texture.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-texture.js +397 -511
- package/dist/adapter/resources/webgl-vertex-array.d.ts +3 -2
- package/dist/adapter/resources/webgl-vertex-array.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-vertex-array.js +2 -2
- package/dist/adapter/webgl-adapter.d.ts +21 -0
- package/dist/adapter/webgl-adapter.d.ts.map +1 -0
- package/dist/adapter/webgl-adapter.js +91 -0
- package/dist/adapter/webgl-canvas-context.d.ts +3 -1
- package/dist/adapter/webgl-canvas-context.d.ts.map +1 -1
- package/dist/adapter/webgl-canvas-context.js +2 -0
- package/dist/adapter/webgl-device.d.ts +19 -30
- package/dist/adapter/webgl-device.d.ts.map +1 -1
- package/dist/adapter/webgl-device.js +35 -114
- package/dist/classic/accessor.d.ts +22 -1
- package/dist/classic/accessor.d.ts.map +1 -1
- package/dist/classic/accessor.js +1 -9
- package/dist/classic/clear.d.ts.map +1 -1
- package/dist/classic/clear.js +2 -5
- package/dist/classic/copy-and-blit.d.ts +3 -1
- package/dist/classic/copy-and-blit.d.ts.map +1 -1
- package/dist/classic/copy-and-blit.js +21 -18
- package/dist/classic/format-utils.d.ts.map +1 -1
- package/dist/classic/format-utils.js +0 -3
- package/dist/classic/typed-array-utils.d.ts +1 -1
- package/dist/classic/typed-array-utils.d.ts.map +1 -1
- package/dist/context/debug/spector-types.d.ts +1108 -0
- package/dist/context/debug/spector-types.d.ts.map +1 -0
- package/dist/context/debug/spector-types.js +697 -0
- package/dist/context/debug/spector.d.ts +12 -8
- package/dist/context/debug/spector.d.ts.map +1 -1
- package/dist/context/debug/spector.js +25 -18
- package/dist/context/debug/webgl-developer-tools.d.ts +1 -1
- package/dist/context/debug/webgl-developer-tools.d.ts.map +1 -1
- package/dist/context/debug/webgl-developer-tools.js +2 -5
- package/dist/context/parameters/webgl-parameter-tables.js +1 -1
- package/dist/context/polyfills/polyfill-webgl1-extensions.d.ts +9 -0
- package/dist/context/polyfills/polyfill-webgl1-extensions.d.ts.map +1 -0
- package/dist/context/polyfills/polyfill-webgl1-extensions.js +181 -0
- package/dist/context/state-tracker/webgl-state-tracker.d.ts +43 -0
- package/dist/context/state-tracker/webgl-state-tracker.d.ts.map +1 -0
- package/dist/context/state-tracker/{track-context-state.js → webgl-state-tracker.js} +46 -77
- package/dist/context/state-tracker/with-parameters.d.ts.map +1 -1
- package/dist/context/state-tracker/with-parameters.js +5 -4
- package/dist/dist.dev.js +1112 -1380
- package/dist/dist.min.js +2 -2
- package/dist/index.cjs +1122 -1284
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +3 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -5
- package/dist/utils/fill-array.d.ts +8 -0
- package/dist/utils/fill-array.d.ts.map +1 -0
- package/dist/utils/fill-array.js +26 -0
- package/dist/utils/load-script.d.ts +8 -0
- package/dist/utils/load-script.d.ts.map +1 -0
- package/dist/utils/load-script.js +26 -0
- package/dist/utils/split-uniforms-and-bindings.d.ts +9 -0
- package/dist/utils/split-uniforms-and-bindings.d.ts.map +1 -0
- package/dist/utils/split-uniforms-and-bindings.js +20 -0
- package/dist/utils/uid.d.ts +7 -0
- package/dist/utils/uid.d.ts.map +1 -0
- package/dist/utils/uid.js +14 -0
- package/package.json +6 -5
- package/src/adapter/converters/device-parameters.ts +31 -13
- package/src/adapter/converters/texture-formats.ts +51 -56
- package/src/adapter/device-helpers/webgl-device-features.ts +1 -2
- package/src/adapter/device-helpers/webgl-device-limits.ts +1 -1
- package/src/adapter/helpers/webgl-texture-utils.ts +484 -0
- package/src/adapter/helpers/webgl-topology-utils.ts +0 -4
- package/src/adapter/resources/webgl-buffer.ts +2 -2
- package/src/adapter/resources/webgl-command-buffer.ts +8 -10
- package/src/adapter/resources/webgl-framebuffer.ts +22 -56
- package/src/adapter/resources/webgl-render-pass.ts +21 -9
- package/src/adapter/resources/webgl-render-pipeline.ts +50 -24
- package/src/adapter/resources/webgl-shader.ts +4 -4
- package/src/adapter/resources/webgl-texture-view.ts +1 -3
- package/src/adapter/resources/webgl-texture.ts +445 -784
- package/src/adapter/resources/webgl-vertex-array.ts +8 -7
- package/src/adapter/webgl-adapter.ts +113 -0
- package/src/adapter/webgl-canvas-context.ts +4 -1
- package/src/adapter/webgl-device.ts +40 -151
- package/src/classic/accessor.ts +31 -11
- package/src/classic/clear.ts +3 -6
- package/src/classic/copy-and-blit.ts +32 -27
- package/src/classic/format-utils.ts +0 -3
- package/src/classic/typed-array-utils.ts +1 -1
- package/src/context/debug/spector-types.ts +1154 -0
- package/src/context/debug/spector.ts +40 -30
- package/src/context/debug/webgl-developer-tools.ts +3 -7
- package/src/context/parameters/webgl-parameter-tables.ts +3 -3
- package/src/context/polyfills/polyfill-webgl1-extensions.ts +202 -0
- package/src/context/state-tracker/{track-context-state.ts → webgl-state-tracker.ts} +57 -97
- package/src/context/state-tracker/with-parameters.ts +5 -4
- package/src/index.ts +5 -13
- package/src/utils/fill-array.ts +35 -0
- package/src/utils/load-script.ts +30 -0
- package/src/utils/split-uniforms-and-bindings.ts +31 -0
- package/src/utils/uid.ts +16 -0
- package/dist/adapter/objects/constants-to-keys.d.ts +0 -3
- package/dist/adapter/objects/constants-to-keys.d.ts.map +0 -1
- package/dist/adapter/objects/constants-to-keys.js +0 -22
- package/dist/adapter/objects/webgl-renderbuffer.d.ts +0 -43
- package/dist/adapter/objects/webgl-renderbuffer.d.ts.map +0 -1
- package/dist/adapter/objects/webgl-renderbuffer.js +0 -95
- package/dist/adapter/objects/webgl-resource.d.ts +0 -32
- package/dist/adapter/objects/webgl-resource.d.ts.map +0 -1
- package/dist/adapter/objects/webgl-resource.js +0 -114
- package/dist/context/state-tracker/track-context-state.d.ts +0 -22
- package/dist/context/state-tracker/track-context-state.d.ts.map +0 -1
- package/src/adapter/objects/constants-to-keys.ts +0 -27
- package/src/adapter/objects/webgl-renderbuffer.ts +0 -132
- package/src/adapter/objects/webgl-resource.ts +0 -183
|
@@ -1,82 +1,208 @@
|
|
|
1
1
|
// luma.gl
|
|
2
2
|
// SPDX-License-Identifier: MIT
|
|
3
3
|
// Copyright (c) vis.gl contributors
|
|
4
|
-
import {
|
|
4
|
+
// import {decodeTextureFormat} from '@luma.gl/core';
|
|
5
|
+
// import {Buffer, Texture, log} from '@luma.gl/core';
|
|
6
|
+
import { Texture, log } from '@luma.gl/core';
|
|
5
7
|
import { GL } from '@luma.gl/constants';
|
|
8
|
+
// import {GLPixelDataType} from '@luma.gl/constants';
|
|
6
9
|
import { withGLParameters } from "../../context/state-tracker/with-parameters.js";
|
|
7
|
-
|
|
10
|
+
// getTextureFormatBytesPerPixel
|
|
11
|
+
import { getTextureFormatWebGL } from "../converters/texture-formats.js";
|
|
8
12
|
import { convertSamplerParametersToWebGL } from "../converters/sampler-parameters.js";
|
|
9
|
-
import {
|
|
13
|
+
// import {WEBGLBuffer} from './webgl-buffer';
|
|
10
14
|
import { WEBGLSampler } from "./webgl-sampler.js";
|
|
11
15
|
import { WEBGLTextureView } from "./webgl-texture-view.js";
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
16
|
+
// import type {WebGLSetTextureOptions, WebGLCopyTextureOptions} from '../helpers/webgl-texture-utils';
|
|
17
|
+
import { initializeTextureStorage,
|
|
18
|
+
// clearMipLevel,
|
|
19
|
+
copyCPUImageToMipLevel, copyCPUDataToMipLevel,
|
|
20
|
+
// copyGPUBufferToMipLevel,
|
|
21
|
+
getWebGLTextureTarget } from "../helpers/webgl-texture-utils.js";
|
|
22
|
+
// PORTABLE HELPERS (Move to methods on Texture?)
|
|
23
|
+
/**
|
|
24
|
+
* Normalize TextureData to an array of TextureLevelData / ExternalImages
|
|
25
|
+
* @param data
|
|
26
|
+
* @param options
|
|
27
|
+
* @returns array of TextureLevelData / ExternalImages
|
|
28
|
+
*/
|
|
29
|
+
function normalizeTextureData(data, options) {
|
|
30
|
+
let lodArray;
|
|
31
|
+
if (ArrayBuffer.isView(data)) {
|
|
32
|
+
lodArray = [
|
|
33
|
+
{
|
|
34
|
+
// ts-expect-error does data really need to be Uint8ClampedArray?
|
|
35
|
+
data,
|
|
36
|
+
width: options.width,
|
|
37
|
+
height: options.height
|
|
38
|
+
// depth: options.depth
|
|
39
|
+
}
|
|
40
|
+
];
|
|
41
|
+
}
|
|
42
|
+
else if (!Array.isArray(data)) {
|
|
43
|
+
lodArray = [data];
|
|
44
|
+
}
|
|
45
|
+
else {
|
|
46
|
+
lodArray = data;
|
|
47
|
+
}
|
|
48
|
+
return lodArray;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* WebGL... the texture API from hell... hopefully made simpler
|
|
52
|
+
*/
|
|
23
53
|
export class WEBGLTexture extends Texture {
|
|
24
|
-
// TODO - remove?
|
|
25
|
-
static FACES = [
|
|
26
|
-
34069,
|
|
27
|
-
34070,
|
|
28
|
-
34071,
|
|
29
|
-
34072,
|
|
30
|
-
34073,
|
|
31
|
-
34074
|
|
32
|
-
];
|
|
33
54
|
MAX_ATTRIBUTES;
|
|
34
55
|
device;
|
|
35
56
|
gl;
|
|
36
57
|
handle;
|
|
37
|
-
//
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
// data;
|
|
41
|
-
glFormat = undefined;
|
|
42
|
-
type = undefined;
|
|
43
|
-
dataFormat = undefined;
|
|
44
|
-
mipmaps = undefined;
|
|
58
|
+
sampler = undefined; // TODO - currently unused in WebGL. Create dummy sampler?
|
|
59
|
+
view = undefined; // TODO - currently unused in WebGL. Create dummy view?
|
|
60
|
+
mipmaps = false;
|
|
45
61
|
/**
|
|
46
62
|
* @note `target` cannot be modified by bind:
|
|
47
63
|
* textures are special because when you first bind them to a target,
|
|
48
|
-
*
|
|
49
|
-
* GL_TEXTURE_2D, you are saying that this texture is a 2D texture.
|
|
64
|
+
* When you first bind a texture as a GL_TEXTURE_2D, you are saying that this texture is a 2D texture.
|
|
50
65
|
* And it will always be a 2D texture; this state cannot be changed ever.
|
|
51
66
|
* A texture that was first bound as a GL_TEXTURE_2D, must always be bound as a GL_TEXTURE_2D;
|
|
52
67
|
* attempting to bind it as GL_TEXTURE_3D will give rise to a run-time error
|
|
53
|
-
* */
|
|
54
|
-
target;
|
|
55
|
-
textureUnit = undefined;
|
|
56
|
-
/**
|
|
57
|
-
* Program.draw() checks the loaded flag of all textures to avoid
|
|
58
|
-
* Textures that are still loading from promises
|
|
59
|
-
* Set to true as soon as texture has been initialized with valid data
|
|
60
68
|
*/
|
|
61
|
-
|
|
62
|
-
|
|
69
|
+
glTarget;
|
|
70
|
+
// Texture type
|
|
71
|
+
/** The WebGL format - essentially channel structure */
|
|
72
|
+
glFormat;
|
|
73
|
+
/** The WebGL data format - the type of each channel */
|
|
74
|
+
glType;
|
|
75
|
+
/** The WebGL constant corresponding to the WebGPU style constant in format */
|
|
76
|
+
glInternalFormat;
|
|
77
|
+
/** Whether the internal format is compressed */
|
|
78
|
+
compressed;
|
|
79
|
+
// data;
|
|
80
|
+
// inherited props
|
|
81
|
+
// dimension: ...
|
|
82
|
+
// format: GLTextureTarget;
|
|
83
|
+
// width: number = undefined;
|
|
84
|
+
// height: number = undefined;
|
|
85
|
+
// depth: number = undefined;
|
|
86
|
+
// state
|
|
87
|
+
/** Texture binding slot */
|
|
88
|
+
textureUnit = 0;
|
|
89
|
+
/** For automatically updating video */
|
|
90
|
+
_video = null;
|
|
63
91
|
constructor(device, props) {
|
|
64
|
-
|
|
92
|
+
// Note: Clear out `props.data` so that we don't hold a reference to any big memory chunks
|
|
93
|
+
super(device, { ...Texture.defaultProps, ...props, data: undefined });
|
|
65
94
|
this.device = device;
|
|
66
95
|
this.gl = this.device.gl;
|
|
67
|
-
|
|
68
|
-
this.
|
|
69
|
-
this
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
this.
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
96
|
+
// Note: In WebGL the texture target defines the type of texture on first bind.
|
|
97
|
+
this.glTarget = getWebGLTextureTarget(this.props.dimension);
|
|
98
|
+
// The target format of this texture
|
|
99
|
+
const format = getTextureFormatWebGL(this.props.format);
|
|
100
|
+
this.glInternalFormat = format.internalFormat;
|
|
101
|
+
this.glFormat = format.format;
|
|
102
|
+
this.glType = format.type;
|
|
103
|
+
this.compressed = format.compressed;
|
|
104
|
+
if (typeof HTMLVideoElement !== 'undefined' &&
|
|
105
|
+
props.data instanceof HTMLVideoElement &&
|
|
106
|
+
// @ts-expect-error
|
|
107
|
+
props.data.readyState < HTMLVideoElement.HAVE_METADATA) {
|
|
108
|
+
const video = props.data;
|
|
109
|
+
this._video = null; // Declare member before the object is sealed
|
|
110
|
+
video.addEventListener('loadeddata', () => this.initialize(props));
|
|
76
111
|
}
|
|
77
|
-
|
|
112
|
+
// We removed data, we need to add it again.
|
|
113
|
+
// @ts-expect-error
|
|
114
|
+
this.initialize({ ...this.props, data: props.data });
|
|
78
115
|
Object.seal(this);
|
|
79
116
|
}
|
|
117
|
+
/**
|
|
118
|
+
* Initialize texture with supplied props
|
|
119
|
+
*/
|
|
120
|
+
// eslint-disable-next-line max-statements
|
|
121
|
+
initialize(props = {}) {
|
|
122
|
+
this.handle = this.props.handle || this.gl.createTexture();
|
|
123
|
+
this.device.setSpectorMetadata(this.handle, { ...this.props, data: typeof this.props.data });
|
|
124
|
+
const data = props.data;
|
|
125
|
+
// const {parameters = {} as Record<GL, any>} = props;
|
|
126
|
+
let { width, height } = props;
|
|
127
|
+
if (!width || !height) {
|
|
128
|
+
const textureSize = Texture.getTextureDataSize(data);
|
|
129
|
+
width = textureSize?.width || 1;
|
|
130
|
+
height = textureSize?.height || 1;
|
|
131
|
+
}
|
|
132
|
+
// Store opts for accessors
|
|
133
|
+
this.width = width;
|
|
134
|
+
this.height = height;
|
|
135
|
+
this.depth = props.depth;
|
|
136
|
+
// Set texture sampler parameters
|
|
137
|
+
this.setSampler(props.sampler);
|
|
138
|
+
// @ts-ignore
|
|
139
|
+
this.view = new WEBGLTextureView(this.device, { ...this.props, texture: this });
|
|
140
|
+
this.bind();
|
|
141
|
+
if (!this.props.data) {
|
|
142
|
+
initializeTextureStorage(this.gl, this.mipLevels, this);
|
|
143
|
+
}
|
|
144
|
+
if (props.data) {
|
|
145
|
+
// prettier-ignore
|
|
146
|
+
switch (props.dimension) {
|
|
147
|
+
case '1d':
|
|
148
|
+
this.setTexture1DData(props.data);
|
|
149
|
+
break;
|
|
150
|
+
case '2d':
|
|
151
|
+
this.setTexture2DData(props.data);
|
|
152
|
+
break;
|
|
153
|
+
case '3d':
|
|
154
|
+
this.setTexture3DData(props.data);
|
|
155
|
+
break;
|
|
156
|
+
case 'cube':
|
|
157
|
+
this.setTextureCubeData(props.data);
|
|
158
|
+
break;
|
|
159
|
+
case '2d-array':
|
|
160
|
+
this.setTextureArrayData(props.data);
|
|
161
|
+
break;
|
|
162
|
+
case 'cube-array':
|
|
163
|
+
this.setTextureCubeArrayData(props.data);
|
|
164
|
+
break;
|
|
165
|
+
// @ts-expect-error
|
|
166
|
+
default: throw new Error(props.dimension);
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
this.mipmaps = Boolean(props.mipmaps);
|
|
170
|
+
if (this.mipmaps) {
|
|
171
|
+
this.generateMipmap();
|
|
172
|
+
}
|
|
173
|
+
// if (isVideo) {
|
|
174
|
+
// this._video = {
|
|
175
|
+
// video: data,
|
|
176
|
+
// // TODO - should we be using the sampler parameters here?
|
|
177
|
+
// parameters: {},
|
|
178
|
+
// // @ts-expect-error HTMLVideoElement.HAVE_CURRENT_DATA is not declared
|
|
179
|
+
// lastTime: data.readyState >= HTMLVideoElement.HAVE_CURRENT_DATA ? data.currentTime : -1
|
|
180
|
+
// };
|
|
181
|
+
// }
|
|
182
|
+
}
|
|
183
|
+
/*
|
|
184
|
+
initializeCube(props?: TextureProps): void {
|
|
185
|
+
const {mipmaps = true} = props; // , parameters = {} as Record<GL, any>} = props;
|
|
186
|
+
|
|
187
|
+
// Store props for accessors
|
|
188
|
+
// this.props = props;
|
|
189
|
+
|
|
190
|
+
// @ts-expect-error
|
|
191
|
+
this.setCubeMapData(props).then(() => {
|
|
192
|
+
// TODO - should genMipmap() be called on the cubemap or on the faces?
|
|
193
|
+
// TODO - without generateMipmap() cube textures do not work at all!!! Why?
|
|
194
|
+
if (mipmaps) {
|
|
195
|
+
this.generateMipmap(props);
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
this.setSampler(props.sampler);
|
|
199
|
+
|
|
200
|
+
// v8 compatibility?
|
|
201
|
+
// const {parameters = {} as Record<GL, any>} = props;
|
|
202
|
+
// this._setSamplerParameters(parameters);
|
|
203
|
+
});
|
|
204
|
+
}
|
|
205
|
+
*/
|
|
80
206
|
destroy() {
|
|
81
207
|
if (this.handle) {
|
|
82
208
|
this.gl.deleteTexture(this.handle);
|
|
@@ -92,109 +218,6 @@ export class WEBGLTexture extends Texture {
|
|
|
92
218
|
createView(props) {
|
|
93
219
|
return new WEBGLTextureView(this.device, { ...props, texture: this });
|
|
94
220
|
}
|
|
95
|
-
// eslint-disable-next-line max-statements
|
|
96
|
-
initialize(props = {}) {
|
|
97
|
-
// Cube textures
|
|
98
|
-
if (this.props.dimension === 'cube') {
|
|
99
|
-
return this.initializeCube(props);
|
|
100
|
-
}
|
|
101
|
-
let data = props.data;
|
|
102
|
-
if (data instanceof Promise) {
|
|
103
|
-
data.then(resolvedImageData => this.initialize(Object.assign({}, props, {
|
|
104
|
-
pixels: resolvedImageData,
|
|
105
|
-
data: resolvedImageData
|
|
106
|
-
})));
|
|
107
|
-
return this;
|
|
108
|
-
}
|
|
109
|
-
const isVideo = typeof HTMLVideoElement !== 'undefined' && data instanceof HTMLVideoElement;
|
|
110
|
-
// @ts-expect-error
|
|
111
|
-
if (isVideo && data.readyState < HTMLVideoElement.HAVE_METADATA) {
|
|
112
|
-
this._video = null; // Declare member before the object is sealed
|
|
113
|
-
// @ts-expect-error
|
|
114
|
-
data.addEventListener('loadeddata', () => this.initialize(props));
|
|
115
|
-
return this;
|
|
116
|
-
}
|
|
117
|
-
const { parameters = {} } = props;
|
|
118
|
-
const { pixels = null, pixelStore = {}, textureUnit = undefined, mipmaps = true } = props;
|
|
119
|
-
// pixels variable is for API compatibility purpose
|
|
120
|
-
if (!data) {
|
|
121
|
-
// TODO - This looks backwards? Commenting out for now until we decide
|
|
122
|
-
// which prop to use
|
|
123
|
-
// log.deprecated('data', 'pixels')();
|
|
124
|
-
data = pixels;
|
|
125
|
-
}
|
|
126
|
-
let { width, height, dataFormat, type, compressed = false } = props;
|
|
127
|
-
const { depth = 0 } = props;
|
|
128
|
-
const glFormat = convertTextureFormatToGL(props.format);
|
|
129
|
-
// Deduce width and height
|
|
130
|
-
({ width, height, compressed, dataFormat, type } = this._deduceParameters({
|
|
131
|
-
format: props.format,
|
|
132
|
-
type,
|
|
133
|
-
dataFormat,
|
|
134
|
-
compressed,
|
|
135
|
-
data,
|
|
136
|
-
width,
|
|
137
|
-
height
|
|
138
|
-
}));
|
|
139
|
-
// Store opts for accessors
|
|
140
|
-
this.width = width;
|
|
141
|
-
this.height = height;
|
|
142
|
-
// this.depth = depth;
|
|
143
|
-
this.glFormat = glFormat;
|
|
144
|
-
this.type = type;
|
|
145
|
-
this.dataFormat = dataFormat;
|
|
146
|
-
this.textureUnit = textureUnit;
|
|
147
|
-
if (Number.isFinite(this.textureUnit)) {
|
|
148
|
-
this.gl.activeTexture(33984 + this.textureUnit);
|
|
149
|
-
this.gl.bindTexture(this.target, this.handle);
|
|
150
|
-
}
|
|
151
|
-
this.mipmaps = mipmaps;
|
|
152
|
-
this.setImageData({
|
|
153
|
-
data,
|
|
154
|
-
width,
|
|
155
|
-
height,
|
|
156
|
-
depth,
|
|
157
|
-
format: glFormat,
|
|
158
|
-
type,
|
|
159
|
-
dataFormat,
|
|
160
|
-
// @ts-expect-error
|
|
161
|
-
parameters: pixelStore,
|
|
162
|
-
compressed
|
|
163
|
-
});
|
|
164
|
-
// Set texture sampler parameters
|
|
165
|
-
this.setSampler(props.sampler);
|
|
166
|
-
this._setSamplerParameters(parameters);
|
|
167
|
-
this.view = this.createView({ ...this.props, mipLevelCount: 1, arrayLayerCount: 1 });
|
|
168
|
-
if (mipmaps && this.device.isTextureFormatFilterable(props.format)) {
|
|
169
|
-
this.generateMipmap();
|
|
170
|
-
}
|
|
171
|
-
if (isVideo) {
|
|
172
|
-
this._video = {
|
|
173
|
-
video: data,
|
|
174
|
-
parameters,
|
|
175
|
-
// @ts-expect-error
|
|
176
|
-
lastTime: data.readyState >= HTMLVideoElement.HAVE_CURRENT_DATA ? data.currentTime : -1
|
|
177
|
-
};
|
|
178
|
-
}
|
|
179
|
-
return this;
|
|
180
|
-
}
|
|
181
|
-
initializeCube(props) {
|
|
182
|
-
const { mipmaps = true, parameters = {} } = props;
|
|
183
|
-
// Store props for accessors
|
|
184
|
-
// this.props = props;
|
|
185
|
-
// @ts-expect-error
|
|
186
|
-
this.setCubeMapImageData(props).then(() => {
|
|
187
|
-
this.loaded = true;
|
|
188
|
-
// TODO - should genMipmap() be called on the cubemap or on the faces?
|
|
189
|
-
// TODO - without generateMipmap() cube textures do not work at all!!! Why?
|
|
190
|
-
if (mipmaps) {
|
|
191
|
-
this.generateMipmap(props);
|
|
192
|
-
}
|
|
193
|
-
this.setSampler(props.sampler);
|
|
194
|
-
this._setSamplerParameters(parameters);
|
|
195
|
-
});
|
|
196
|
-
return this;
|
|
197
|
-
}
|
|
198
221
|
setSampler(sampler = {}) {
|
|
199
222
|
let samplerProps;
|
|
200
223
|
if (sampler instanceof WEBGLSampler) {
|
|
@@ -207,329 +230,122 @@ export class WEBGLTexture extends Texture {
|
|
|
207
230
|
}
|
|
208
231
|
const parameters = convertSamplerParametersToWebGL(samplerProps);
|
|
209
232
|
this._setSamplerParameters(parameters);
|
|
210
|
-
return this;
|
|
211
233
|
}
|
|
212
|
-
/**
|
|
213
|
-
* If size has changed, reinitializes with current format
|
|
214
|
-
* @note note clears image and mipmaps
|
|
215
|
-
*/
|
|
216
|
-
resize(options) {
|
|
217
|
-
const { height, width, mipmaps = false } = options;
|
|
218
|
-
if (width !== this.width || height !== this.height) {
|
|
219
|
-
return this.initialize({
|
|
220
|
-
width,
|
|
221
|
-
height,
|
|
222
|
-
format: this.format,
|
|
223
|
-
type: this.type,
|
|
224
|
-
dataFormat: this.dataFormat,
|
|
225
|
-
mipmaps
|
|
226
|
-
});
|
|
227
|
-
}
|
|
228
|
-
return this;
|
|
229
|
-
}
|
|
230
|
-
/** Update external texture (video frame) */
|
|
234
|
+
/** Update external texture (video frame or canvas) */
|
|
231
235
|
update() {
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
236
|
+
log.warn('Texture.update() not implemented');
|
|
237
|
+
// if (this._video) {
|
|
238
|
+
// const {video, parameters, lastTime} = this._video;
|
|
239
|
+
// // @ts-expect-error
|
|
240
|
+
// if (lastTime === video.currentTime || video.readyState < HTMLVideoElement.HAVE_CURRENT_DATA) {
|
|
241
|
+
// return;
|
|
242
|
+
// }
|
|
243
|
+
// this.setSubImageData({
|
|
244
|
+
// data: video,
|
|
245
|
+
// parameters
|
|
246
|
+
// });
|
|
247
|
+
// if (this.mipmaps) {
|
|
248
|
+
// this.generateMipmap();
|
|
249
|
+
// }
|
|
250
|
+
// this._video.lastTime = video.currentTime;
|
|
251
|
+
// }
|
|
247
252
|
}
|
|
248
253
|
// Call to regenerate mipmaps after modifying texture(s)
|
|
249
254
|
generateMipmap(params = {}) {
|
|
255
|
+
if (!this.props.data) {
|
|
256
|
+
return;
|
|
257
|
+
}
|
|
250
258
|
this.mipmaps = true;
|
|
251
|
-
this.gl.bindTexture(this.
|
|
259
|
+
this.gl.bindTexture(this.glTarget, this.handle);
|
|
252
260
|
withGLParameters(this.gl, params, () => {
|
|
253
|
-
this.gl.generateMipmap(this.
|
|
261
|
+
this.gl.generateMipmap(this.glTarget);
|
|
254
262
|
});
|
|
255
|
-
this.gl.bindTexture(this.
|
|
256
|
-
return this;
|
|
263
|
+
this.gl.bindTexture(this.glTarget, null);
|
|
257
264
|
}
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
setImageData(options) {
|
|
280
|
-
if (this.props.dimension === '3d' || this.props.dimension === '2d-array') {
|
|
281
|
-
return this.setImageData3D(options);
|
|
282
|
-
}
|
|
283
|
-
this.trackDeallocatedMemory('Texture');
|
|
284
|
-
const { target = this.target, pixels = null, level = 0, glFormat = this.glFormat, offset = 0, parameters = {} } = options;
|
|
285
|
-
let { data = null, type = this.type, width = this.width, height = this.height, dataFormat = this.dataFormat, compressed = false } = options;
|
|
286
|
-
// pixels variable is for API compatibility purpose
|
|
287
|
-
if (!data) {
|
|
288
|
-
data = pixels;
|
|
289
|
-
}
|
|
290
|
-
({ type, dataFormat, compressed, width, height } = this._deduceParameters({
|
|
291
|
-
format: this.props.format,
|
|
292
|
-
type,
|
|
293
|
-
dataFormat,
|
|
294
|
-
compressed,
|
|
295
|
-
data,
|
|
296
|
-
width,
|
|
297
|
-
height
|
|
298
|
-
}));
|
|
299
|
-
const { gl } = this;
|
|
300
|
-
gl.bindTexture(this.target, this.handle);
|
|
301
|
-
let dataType = null;
|
|
302
|
-
({ data, dataType } = this._getDataType({ data, compressed }));
|
|
303
|
-
withGLParameters(this.gl, parameters, () => {
|
|
304
|
-
switch (dataType) {
|
|
305
|
-
case 'null':
|
|
306
|
-
gl.texImage2D(target, level, glFormat, width, height, 0 /* border*/, dataFormat, type, data);
|
|
307
|
-
break;
|
|
308
|
-
case 'typed-array':
|
|
309
|
-
gl.texImage2D(target, level, glFormat, width, height, 0, // border (must be 0)
|
|
310
|
-
dataFormat, type, data, offset);
|
|
311
|
-
break;
|
|
312
|
-
case 'buffer':
|
|
313
|
-
// WebGL2 enables creating textures directly from a WebGL buffer
|
|
314
|
-
this.device.gl.bindBuffer(35052, data.handle || data);
|
|
315
|
-
this.device.gl.texImage2D(target, level, glFormat, width, height, 0 /* border*/, dataFormat, type, offset);
|
|
316
|
-
this.device.gl.bindBuffer(35052, null);
|
|
317
|
-
break;
|
|
318
|
-
case 'browser-object':
|
|
319
|
-
gl.texImage2D(target, level, glFormat, width, height, 0 /* border*/, dataFormat, type, data);
|
|
320
|
-
break;
|
|
321
|
-
case 'compressed':
|
|
322
|
-
for (const [levelIndex, levelData] of data.entries()) {
|
|
323
|
-
gl.compressedTexImage2D(target, levelIndex, levelData.format, levelData.width, levelData.height, 0 /* border, must be 0 */, levelData.data);
|
|
324
|
-
}
|
|
325
|
-
break;
|
|
326
|
-
default:
|
|
327
|
-
assert(false, 'Unknown image data type');
|
|
328
|
-
}
|
|
329
|
-
});
|
|
330
|
-
if (data && data.byteLength) {
|
|
331
|
-
this.trackAllocatedMemory(data.byteLength, 'Texture');
|
|
265
|
+
// Image Data Setters
|
|
266
|
+
copyExternalImage(options) {
|
|
267
|
+
const size = Texture.getExternalImageSize(options.image);
|
|
268
|
+
const opts = { ...Texture.defaultCopyExternalImageOptions, ...size, ...options };
|
|
269
|
+
const { depth, mipLevel: lodLevel, image } = opts;
|
|
270
|
+
this.bind();
|
|
271
|
+
this._setMipLevel(depth, lodLevel, image);
|
|
272
|
+
this.unbind();
|
|
273
|
+
return { width: opts.width, height: opts.height };
|
|
274
|
+
}
|
|
275
|
+
setTexture1DData(data) {
|
|
276
|
+
throw new Error('setTexture1DData not supported in WebGL.');
|
|
277
|
+
}
|
|
278
|
+
/** Set a simple texture */
|
|
279
|
+
setTexture2DData(lodData, depth = 0) {
|
|
280
|
+
this.bind();
|
|
281
|
+
const lodArray = normalizeTextureData(lodData, this);
|
|
282
|
+
// If the user provides multiple LODs, then automatic mipmap
|
|
283
|
+
// generation generateMipmap() should be disabled to avoid overwriting them.
|
|
284
|
+
if (lodArray.length > 1 && this.props.mipmaps !== false) {
|
|
285
|
+
log.warn(`Texture ${this.id} mipmap and multiple LODs.`)();
|
|
332
286
|
}
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
this.
|
|
287
|
+
for (let lodLevel = 0; lodLevel < lodArray.length; lodLevel++) {
|
|
288
|
+
const imageData = lodArray[lodLevel];
|
|
289
|
+
this._setMipLevel(depth, lodLevel, imageData);
|
|
336
290
|
}
|
|
337
|
-
this.
|
|
338
|
-
return this;
|
|
291
|
+
this.unbind();
|
|
339
292
|
}
|
|
340
293
|
/**
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
* Redefines an area of an existing texture
|
|
294
|
+
* Sets a 3D texture
|
|
295
|
+
* @param data
|
|
344
296
|
*/
|
|
345
|
-
|
|
346
|
-
(
|
|
347
|
-
|
|
348
|
-
type,
|
|
349
|
-
dataFormat,
|
|
350
|
-
compressed,
|
|
351
|
-
data,
|
|
352
|
-
width,
|
|
353
|
-
height
|
|
354
|
-
}));
|
|
355
|
-
assert(this.depth === 1, 'texSubImage not supported for 3D textures');
|
|
356
|
-
// pixels variable is for API compatibility purpose
|
|
357
|
-
if (!data) {
|
|
358
|
-
data = pixels;
|
|
297
|
+
setTexture3DData(data) {
|
|
298
|
+
if (this.props.dimension !== '3d') {
|
|
299
|
+
throw new Error(this.id);
|
|
359
300
|
}
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
width = ndarray.shape[0];
|
|
365
|
-
height = ndarray.shape[1];
|
|
366
|
-
}
|
|
367
|
-
// Support buffers
|
|
368
|
-
if (data instanceof WEBGLBuffer) {
|
|
369
|
-
data = data.handle;
|
|
301
|
+
if (ArrayBuffer.isView(data)) {
|
|
302
|
+
this.bind();
|
|
303
|
+
copyCPUDataToMipLevel(this.device.gl, data, this);
|
|
304
|
+
this.unbind();
|
|
370
305
|
}
|
|
371
|
-
this.gl.bindTexture(this.target, this.handle);
|
|
372
|
-
withGLParameters(this.gl, parameters, () => {
|
|
373
|
-
// TODO - x,y parameters
|
|
374
|
-
if (compressed) {
|
|
375
|
-
this.gl.compressedTexSubImage2D(target, level, x, y, width, height, glFormat, data);
|
|
376
|
-
}
|
|
377
|
-
else if (data === null) {
|
|
378
|
-
this.gl.texSubImage2D(target, level, x, y, width, height, dataFormat, type, null);
|
|
379
|
-
}
|
|
380
|
-
else if (ArrayBuffer.isView(data)) {
|
|
381
|
-
this.gl.texSubImage2D(target, level, x, y, width, height, dataFormat, type, data, offset);
|
|
382
|
-
}
|
|
383
|
-
else if (typeof WebGLBuffer !== 'undefined' && data instanceof WebGLBuffer) {
|
|
384
|
-
// WebGL2 allows us to create texture directly from a WebGL buffer
|
|
385
|
-
// This texImage2D signature uses currently bound GL.PIXEL_UNPACK_BUFFER
|
|
386
|
-
this.device.gl.bindBuffer(35052, data);
|
|
387
|
-
this.device.gl.texSubImage2D(target, level, x, y, width, height, dataFormat, type, offset);
|
|
388
|
-
this.device.gl.bindBuffer(35052, null);
|
|
389
|
-
}
|
|
390
|
-
else {
|
|
391
|
-
// Assume data is a browser supported object (ImageData, Canvas, ...)
|
|
392
|
-
this.device.gl.texSubImage2D(target, level, x, y, width, height, dataFormat, type, data);
|
|
393
|
-
}
|
|
394
|
-
});
|
|
395
|
-
this.gl.bindTexture(this.target, null);
|
|
396
306
|
}
|
|
397
307
|
/**
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
* Note that binding a texture into a Framebuffer's color buffer and
|
|
403
|
-
* rendering can be faster.
|
|
308
|
+
* Set a Texture Cube Data
|
|
309
|
+
* @todo - could support TextureCubeArray with depth
|
|
310
|
+
* @param data
|
|
311
|
+
* @param index
|
|
404
312
|
*/
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
}
|
|
409
|
-
getActiveUnit() {
|
|
410
|
-
return this.gl.getParameter(34016) - 33984;
|
|
411
|
-
}
|
|
412
|
-
bind(textureUnit = this.textureUnit) {
|
|
413
|
-
const { gl } = this;
|
|
414
|
-
if (textureUnit !== undefined) {
|
|
415
|
-
this.textureUnit = textureUnit;
|
|
416
|
-
gl.activeTexture(33984 + textureUnit);
|
|
313
|
+
setTextureCubeData(data, depth = 0) {
|
|
314
|
+
if (this.props.dimension !== 'cube') {
|
|
315
|
+
throw new Error(this.id);
|
|
417
316
|
}
|
|
418
|
-
|
|
419
|
-
|
|
420
|
-
}
|
|
421
|
-
unbind(textureUnit = this.textureUnit) {
|
|
422
|
-
const { gl } = this;
|
|
423
|
-
if (textureUnit !== undefined) {
|
|
424
|
-
this.textureUnit = textureUnit;
|
|
425
|
-
gl.activeTexture(33984 + textureUnit);
|
|
317
|
+
for (const face of Texture.CubeFaces) {
|
|
318
|
+
this.setTextureCubeFaceData(data[face], face);
|
|
426
319
|
}
|
|
427
|
-
gl.bindTexture(this.target, null);
|
|
428
|
-
return textureUnit;
|
|
429
320
|
}
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
if (
|
|
436
|
-
|
|
437
|
-
}
|
|
438
|
-
if (ArrayBuffer.isView(data)) {
|
|
439
|
-
return { data, dataType: 'typed-array' };
|
|
440
|
-
}
|
|
441
|
-
if (data instanceof WEBGLBuffer) {
|
|
442
|
-
return { data: data.handle, dataType: 'buffer' };
|
|
443
|
-
}
|
|
444
|
-
// Raw WebGL handle (not a luma wrapper)
|
|
445
|
-
if (typeof WebGLBuffer !== 'undefined' && data instanceof WebGLBuffer) {
|
|
446
|
-
return { data, dataType: 'buffer' };
|
|
321
|
+
/**
|
|
322
|
+
* Sets an entire texture array
|
|
323
|
+
* @param data
|
|
324
|
+
*/
|
|
325
|
+
setTextureArrayData(data) {
|
|
326
|
+
if (this.props.dimension !== '2d-array') {
|
|
327
|
+
throw new Error(this.id);
|
|
447
328
|
}
|
|
448
|
-
|
|
449
|
-
return { data, dataType: 'browser-object' };
|
|
329
|
+
throw new Error('setTextureArrayData not implemented.');
|
|
450
330
|
}
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
dataFormat = dataFormat || parameters.dataFormat;
|
|
458
|
-
type = type || parameters.type;
|
|
459
|
-
compressed = compressed || parameters.compressed;
|
|
460
|
-
({ width, height } = this._deduceImageSize(data, width, height));
|
|
461
|
-
return { dataFormat, type, compressed, width, height, format, data };
|
|
331
|
+
/**
|
|
332
|
+
* Sets an entire texture cube array
|
|
333
|
+
* @param data
|
|
334
|
+
*/
|
|
335
|
+
setTextureCubeArrayData(data) {
|
|
336
|
+
throw new Error('setTextureCubeArrayData not supported in WebGL2.');
|
|
462
337
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
else if (typeof HTMLCanvasElement !== 'undefined' && data instanceof HTMLCanvasElement) {
|
|
473
|
-
size = { width: data.width, height: data.height };
|
|
474
|
-
}
|
|
475
|
-
else if (typeof ImageBitmap !== 'undefined' && data instanceof ImageBitmap) {
|
|
476
|
-
size = { width: data.width, height: data.height };
|
|
477
|
-
}
|
|
478
|
-
else if (typeof HTMLVideoElement !== 'undefined' && data instanceof HTMLVideoElement) {
|
|
479
|
-
size = { width: data.videoWidth, height: data.videoHeight };
|
|
480
|
-
}
|
|
481
|
-
else if (!data) {
|
|
482
|
-
size = { width: width >= 0 ? width : 1, height: height >= 0 ? height : 1 };
|
|
483
|
-
}
|
|
484
|
-
else {
|
|
485
|
-
size = { width, height };
|
|
486
|
-
}
|
|
487
|
-
assert(size, 'Could not deduced texture size');
|
|
488
|
-
assert(width === undefined || size.width === width, 'Deduced texture width does not match supplied width');
|
|
489
|
-
assert(height === undefined || size.height === height, 'Deduced texture height does not match supplied height');
|
|
490
|
-
return size;
|
|
491
|
-
}
|
|
492
|
-
// CUBE MAP METHODS
|
|
493
|
-
/* eslint-disable max-statements, max-len */
|
|
494
|
-
async setCubeMapImageData(options) {
|
|
495
|
-
const { gl } = this;
|
|
496
|
-
const { width, height, pixels, data, format = 6408, type = 5121 } = options;
|
|
497
|
-
const imageDataMap = pixels || data;
|
|
498
|
-
// pixel data (imageDataMap) is an Object from Face to Image or Promise.
|
|
499
|
-
// For example:
|
|
500
|
-
// {
|
|
501
|
-
// GL.TEXTURE_CUBE_MAP_POSITIVE_X : Image-or-Promise,
|
|
502
|
-
// GL.TEXTURE_CUBE_MAP_NEGATIVE_X : Image-or-Promise,
|
|
503
|
-
// ... }
|
|
504
|
-
// To provide multiple level-of-details (LODs) this can be Face to Array
|
|
505
|
-
// of Image or Promise, like this
|
|
506
|
-
// {
|
|
507
|
-
// GL.TEXTURE_CUBE_MAP_POSITIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
|
|
508
|
-
// GL.TEXTURE_CUBE_MAP_NEGATIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
|
|
509
|
-
// ... }
|
|
510
|
-
const resolvedFaces = await Promise.all(WEBGLTexture.FACES.map(face => {
|
|
511
|
-
const facePixels = imageDataMap[face];
|
|
512
|
-
return Promise.all(Array.isArray(facePixels) ? facePixels : [facePixels]);
|
|
513
|
-
}));
|
|
514
|
-
this.bind();
|
|
515
|
-
WEBGLTexture.FACES.forEach((face, index) => {
|
|
516
|
-
if (resolvedFaces[index].length > 1 && this.props.mipmaps !== false) {
|
|
517
|
-
// If the user provides multiple LODs, then automatic mipmap
|
|
518
|
-
// generation generateMipmap() should be disabled to avoid overwritting them.
|
|
519
|
-
log.warn(`${this.id} has mipmap and multiple LODs.`)();
|
|
520
|
-
}
|
|
521
|
-
resolvedFaces[index].forEach((image, lodLevel) => {
|
|
522
|
-
// TODO: adjust width & height for LOD!
|
|
523
|
-
if (width && height) {
|
|
524
|
-
gl.texImage2D(face, lodLevel, format, width, height, 0 /* border*/, format, type, image);
|
|
525
|
-
}
|
|
526
|
-
else {
|
|
527
|
-
gl.texImage2D(face, lodLevel, format, format, type, image);
|
|
528
|
-
}
|
|
529
|
-
});
|
|
530
|
-
});
|
|
531
|
-
this.unbind();
|
|
338
|
+
setTextureCubeFaceData(lodData, face, depth = 0) {
|
|
339
|
+
// assert(this.props.dimension === 'cube');
|
|
340
|
+
// If the user provides multiple LODs, then automatic mipmap
|
|
341
|
+
// generation generateMipmap() should be disabled to avoid overwriting them.
|
|
342
|
+
if (Array.isArray(lodData) && lodData.length > 1 && this.props.mipmaps !== false) {
|
|
343
|
+
log.warn(`${this.id} has mipmap and multiple LODs.`)();
|
|
344
|
+
}
|
|
345
|
+
const faceDepth = Texture.CubeFaces.indexOf(face);
|
|
346
|
+
this.setTexture2DData(lodData, faceDepth);
|
|
532
347
|
}
|
|
348
|
+
// INTERNAL METHODS
|
|
533
349
|
/** @todo update this method to accept LODs */
|
|
534
350
|
setImageDataForFace(options) {
|
|
535
351
|
const { face, width, height, pixels, data, format = 6408, type = 5121
|
|
@@ -551,85 +367,155 @@ export class WEBGLTexture extends Texture {
|
|
|
551
367
|
else {
|
|
552
368
|
gl.texImage2D(face, 0, format, format, type, imageData);
|
|
553
369
|
}
|
|
554
|
-
return this;
|
|
555
370
|
}
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
const webglTextureFormat = getWebGLTextureParameters(format);
|
|
563
|
-
withGLParameters(this.gl, parameters, () => {
|
|
564
|
-
if (ArrayBuffer.isView(data)) {
|
|
565
|
-
this.gl.texImage3D(this.target, level, webglTextureFormat.format, width, height, depth, 0 /* border, must be 0 */, webglTextureFormat.dataFormat, webglTextureFormat.type, // dataType: getWebGL,
|
|
566
|
-
data);
|
|
371
|
+
_getImageDataMap(faceData) {
|
|
372
|
+
for (let i = 0; i < Texture.CubeFaces.length; ++i) {
|
|
373
|
+
const faceName = Texture.CubeFaces[i];
|
|
374
|
+
if (faceData[faceName]) {
|
|
375
|
+
faceData[34069 + i] = faceData[faceName];
|
|
376
|
+
delete faceData[faceName];
|
|
567
377
|
}
|
|
568
|
-
if (data instanceof WEBGLBuffer) {
|
|
569
|
-
this.gl.bindBuffer(35052, data.handle);
|
|
570
|
-
this.gl.texImage3D(this.target, level, dataFormat, width, height, depth, 0 /* border, must be 0 */, format, type, offset);
|
|
571
|
-
}
|
|
572
|
-
});
|
|
573
|
-
if (data && data.byteLength) {
|
|
574
|
-
this.trackAllocatedMemory(data.byteLength, 'Texture');
|
|
575
|
-
}
|
|
576
|
-
else {
|
|
577
|
-
const bytesPerPixel = getTextureFormatBytesPerPixel(this.props.format);
|
|
578
|
-
this.trackAllocatedMemory(this.width * this.height * this.depth * bytesPerPixel, 'Texture');
|
|
579
378
|
}
|
|
580
|
-
|
|
581
|
-
return this;
|
|
379
|
+
return faceData;
|
|
582
380
|
}
|
|
583
381
|
// RESOURCE METHODS
|
|
584
382
|
/**
|
|
585
383
|
* Sets sampler parameters on texture
|
|
586
384
|
*/
|
|
587
385
|
_setSamplerParameters(parameters) {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
logParameters(parameters);
|
|
593
|
-
this.gl.bindTexture(this.target, this.handle);
|
|
386
|
+
log.log(1, 'texture sampler parameters', parameters)();
|
|
387
|
+
this.gl.bindTexture(this.glTarget, this.handle);
|
|
594
388
|
for (const [pname, pvalue] of Object.entries(parameters)) {
|
|
595
389
|
const param = Number(pname);
|
|
596
390
|
const value = pvalue;
|
|
597
|
-
// Apparently
|
|
391
|
+
// Apparently integer/float issues require two different texture parameter setting functions in JavaScript.
|
|
598
392
|
// For now, pick the float version for parameters specified as GLfloat.
|
|
599
393
|
switch (param) {
|
|
600
394
|
case 33082:
|
|
601
395
|
case 33083:
|
|
602
|
-
this.gl.texParameterf(this.
|
|
396
|
+
this.gl.texParameterf(this.glTarget, param, value);
|
|
397
|
+
break;
|
|
398
|
+
case 10241:
|
|
399
|
+
this.gl.texParameteri(this.glTarget, param, value);
|
|
400
|
+
break;
|
|
401
|
+
case 10242:
|
|
402
|
+
case 10243:
|
|
403
|
+
this.gl.texParameteri(this.glTarget, param, value);
|
|
404
|
+
break;
|
|
405
|
+
case 34046:
|
|
406
|
+
// We have to query feature before using it
|
|
407
|
+
if (this.device.features.has('texture-filterable-anisotropic-webgl')) {
|
|
408
|
+
this.gl.texParameteri(this.glTarget, param, value);
|
|
409
|
+
}
|
|
603
410
|
break;
|
|
604
411
|
default:
|
|
605
|
-
this.gl.texParameteri(this.
|
|
412
|
+
this.gl.texParameteri(this.glTarget, param, value);
|
|
606
413
|
break;
|
|
607
414
|
}
|
|
608
415
|
}
|
|
609
|
-
this.gl.bindTexture(this.
|
|
610
|
-
return;
|
|
416
|
+
this.gl.bindTexture(this.glTarget, null);
|
|
611
417
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
418
|
+
// CLASSIC
|
|
419
|
+
/*
|
|
420
|
+
setCubeMapData(options: {
|
|
421
|
+
width: number;
|
|
422
|
+
height: number;
|
|
423
|
+
data: Record<GL, Texture2DData> | Record<TextureCubeFace, Texture2DData>;
|
|
424
|
+
format?: any;
|
|
425
|
+
type?: any;
|
|
426
|
+
/** @deprecated Use .data *
|
|
427
|
+
pixels: any;
|
|
428
|
+
}): void {
|
|
429
|
+
const {gl} = this;
|
|
430
|
+
|
|
431
|
+
const {width, height, pixels, data, format = GL.RGBA, type = GL.UNSIGNED_BYTE} = options;
|
|
432
|
+
|
|
433
|
+
// pixel data (imageDataMap) is an Object from Face to Image or Promise.
|
|
434
|
+
// For example:
|
|
435
|
+
// {
|
|
436
|
+
// GL.TEXTURE_CUBE_MAP_POSITIVE_X : Image-or-Promise,
|
|
437
|
+
// GL.TEXTURE_CUBE_MAP_NEGATIVE_X : Image-or-Promise,
|
|
438
|
+
// ... }
|
|
439
|
+
// To provide multiple level-of-details (LODs) this can be Face to Array
|
|
440
|
+
// of Image or Promise, like this
|
|
441
|
+
// {
|
|
442
|
+
// GL.TEXTURE_CUBE_MAP_POSITIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
|
|
443
|
+
// GL.TEXTURE_CUBE_MAP_NEGATIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
|
|
444
|
+
// ... }
|
|
445
|
+
|
|
446
|
+
const imageDataMap = this._getImageDataMap(pixels || data);
|
|
447
|
+
|
|
448
|
+
const resolvedFaces = WEBGLTexture.FACES.map(face => {
|
|
449
|
+
const facePixels = imageDataMap[face];
|
|
450
|
+
return Array.isArray(facePixels) ? facePixels : [facePixels];
|
|
451
|
+
});
|
|
452
|
+
this.bind();
|
|
453
|
+
|
|
454
|
+
WEBGLTexture.FACES.forEach((face, index) => {
|
|
455
|
+
if (resolvedFaces[index].length > 1 && this.props.mipmaps !== false) {
|
|
456
|
+
// If the user provides multiple LODs, then automatic mipmap
|
|
457
|
+
// generation generateMipmap() should be disabled to avoid overwritting them.
|
|
458
|
+
log.warn(`${this.id} has mipmap and multiple LODs.`)();
|
|
459
|
+
}
|
|
460
|
+
resolvedFaces[index].forEach((image, lodLevel) => {
|
|
461
|
+
// TODO: adjust width & height for LOD!
|
|
462
|
+
if (width && height) {
|
|
463
|
+
gl.texImage2D(face, lodLevel, format, width, height, 0 /* border*, format, type, image);
|
|
464
|
+
} else {
|
|
465
|
+
gl.texImage2D(face, lodLevel, format, format, type, image);
|
|
466
|
+
}
|
|
467
|
+
});
|
|
468
|
+
});
|
|
469
|
+
|
|
470
|
+
this.unbind();
|
|
471
|
+
}
|
|
472
|
+
*/
|
|
473
|
+
// INTERNAL SETTERS
|
|
474
|
+
/**
|
|
475
|
+
* Copy a region of data from a CPU memory buffer into this texture.
|
|
476
|
+
* @todo - GLUnpackParameters parameters
|
|
477
|
+
*/
|
|
478
|
+
_setMipLevel(depth, level, textureData, glTarget = this.glTarget) {
|
|
479
|
+
// if (!textureData) {
|
|
480
|
+
// clearMipLevel(this.device.gl, {...this, depth, level});
|
|
481
|
+
// return;
|
|
482
|
+
// }
|
|
483
|
+
if (Texture.isExternalImage(textureData)) {
|
|
484
|
+
copyCPUImageToMipLevel(this.device.gl, textureData, { ...this, depth, level, glTarget });
|
|
485
|
+
return;
|
|
486
|
+
}
|
|
487
|
+
// @ts-expect-error
|
|
488
|
+
if (Texture.isTextureLevelData(textureData)) {
|
|
489
|
+
copyCPUDataToMipLevel(this.device.gl, textureData.data, {
|
|
490
|
+
...this,
|
|
491
|
+
depth,
|
|
492
|
+
level,
|
|
493
|
+
glTarget
|
|
494
|
+
});
|
|
495
|
+
return;
|
|
496
|
+
}
|
|
497
|
+
throw new Error('Texture: invalid image data');
|
|
498
|
+
}
|
|
499
|
+
// HELPERS
|
|
500
|
+
getActiveUnit() {
|
|
501
|
+
return this.gl.getParameter(34016) - 33984;
|
|
502
|
+
}
|
|
503
|
+
bind(textureUnit) {
|
|
504
|
+
const { gl } = this;
|
|
505
|
+
if (textureUnit !== undefined) {
|
|
506
|
+
this.textureUnit = textureUnit;
|
|
507
|
+
gl.activeTexture(33984 + textureUnit);
|
|
508
|
+
}
|
|
509
|
+
gl.bindTexture(this.glTarget, this.handle);
|
|
510
|
+
return textureUnit;
|
|
511
|
+
}
|
|
512
|
+
unbind(textureUnit) {
|
|
513
|
+
const { gl } = this;
|
|
514
|
+
if (textureUnit !== undefined) {
|
|
515
|
+
this.textureUnit = textureUnit;
|
|
516
|
+
gl.activeTexture(33984 + textureUnit);
|
|
517
|
+
}
|
|
518
|
+
gl.bindTexture(this.glTarget, null);
|
|
519
|
+
return textureUnit;
|
|
631
520
|
}
|
|
632
|
-
}
|
|
633
|
-
function logParameters(parameters) {
|
|
634
|
-
log.log(1, 'texture sampler parameters', parameters)();
|
|
635
521
|
}
|