@luma.gl/webgl 9.0.11 → 9.1.0-alpha.1
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/LICENSE +34 -0
- package/dist/adapter/converters/device-parameters.d.ts.map +1 -1
- package/dist/adapter/converters/device-parameters.js +12 -1
- 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 +31 -32
- package/dist/adapter/device-helpers/webgl-device-features.js +1 -1
- 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 +368 -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 +1 -3
- package/dist/adapter/resources/webgl-render-pipeline.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-render-pipeline.js +45 -20
- package/dist/adapter/resources/webgl-shader.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-shader.js +2 -2
- 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 +58 -172
- package/dist/adapter/resources/webgl-texture.d.ts.map +1 -1
- package/dist/adapter/resources/webgl-texture.js +402 -510
- 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-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 +4 -3
- package/dist/adapter/webgl-device.d.ts.map +1 -1
- package/dist/adapter/webgl-device.js +6 -5
- 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 +2 -1
- package/dist/classic/copy-and-blit.d.ts.map +1 -1
- package/dist/classic/copy-and-blit.js +11 -9
- 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.d.ts.map +1 -1
- package/dist/context/debug/spector.js +2 -1
- 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/state-tracker/track-context-state.d.ts.map +1 -1
- package/dist/context/state-tracker/track-context-state.js +5 -6
- package/dist/dist.dev.js +870 -1261
- package/dist/dist.min.js +2 -2
- package/dist/index.cjs +859 -1137
- package/dist/index.cjs.map +4 -4
- package/dist/index.d.ts +0 -4
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +0 -3
- 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/package.json +6 -5
- package/src/adapter/converters/device-parameters.ts +13 -1
- package/src/adapter/converters/texture-formats.ts +45 -42
- package/src/adapter/device-helpers/webgl-device-features.ts +1 -1
- package/src/adapter/device-helpers/webgl-device-limits.ts +1 -1
- package/src/adapter/helpers/webgl-texture-utils.ts +481 -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 +4 -5
- package/src/adapter/resources/webgl-render-pipeline.ts +48 -23
- package/src/adapter/resources/webgl-shader.ts +3 -3
- package/src/adapter/resources/webgl-texture-view.ts +1 -3
- package/src/adapter/resources/webgl-texture.ts +432 -784
- package/src/adapter/resources/webgl-vertex-array.ts +8 -7
- package/src/adapter/webgl-canvas-context.ts +4 -1
- package/src/adapter/webgl-device.ts +10 -18
- package/src/classic/accessor.ts +31 -11
- package/src/classic/clear.ts +3 -6
- package/src/classic/copy-and-blit.ts +19 -19
- package/src/classic/format-utils.ts +0 -3
- package/src/classic/typed-array-utils.ts +1 -1
- package/src/context/debug/spector.ts +2 -1
- package/src/context/debug/webgl-developer-tools.ts +3 -7
- package/src/context/parameters/webgl-parameter-tables.ts +3 -3
- package/src/context/state-tracker/track-context-state.ts +5 -6
- package/src/index.ts +0 -6
- 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/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/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 = this.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,129 @@ export class WEBGLTexture extends Texture {
|
|
|
207
230
|
}
|
|
208
231
|
const parameters = convertSamplerParametersToWebGL(samplerProps);
|
|
209
232
|
this._setSamplerParameters(parameters);
|
|
210
|
-
return this;
|
|
211
|
-
}
|
|
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
233
|
}
|
|
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
|
-
* @param mipMapLevel -
|
|
271
|
-
* @param {GLenum} format - format of image data.
|
|
272
|
-
* @param {GLenum} type
|
|
273
|
-
* - format of array (autodetect from type) or
|
|
274
|
-
* - (WEBGL2) format of buffer
|
|
275
|
-
* @param {Number} offset - (WEBGL2) offset from start of buffer
|
|
276
|
-
* @parameters - temporary settings to be applied, can be used to supply pixel store settings.
|
|
277
|
-
*/
|
|
278
|
-
// eslint-disable-next-line max-statements, complexity
|
|
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
|
+
setTexture1DData(data) {
|
|
267
|
+
throw new Error('setTexture1DData not supported in WebGL.');
|
|
268
|
+
}
|
|
269
|
+
/** Set a simple texture */
|
|
270
|
+
setTexture2DData(lodData, depth = 0, glTarget = this.glTarget) {
|
|
271
|
+
this.bind();
|
|
272
|
+
const lodArray = normalizeTextureData(lodData, this);
|
|
273
|
+
// If the user provides multiple LODs, then automatic mipmap
|
|
274
|
+
// generation generateMipmap() should be disabled to avoid overwriting them.
|
|
275
|
+
if (lodArray.length > 1 && this.props.mipmaps !== false) {
|
|
276
|
+
log.warn(`Texture ${this.id} mipmap and multiple LODs.`)();
|
|
332
277
|
}
|
|
333
|
-
|
|
334
|
-
const
|
|
335
|
-
this.
|
|
278
|
+
for (let lodLevel = 0; lodLevel < lodArray.length; lodLevel++) {
|
|
279
|
+
const imageData = lodArray[lodLevel];
|
|
280
|
+
this._setMipLevel(depth, lodLevel, imageData);
|
|
336
281
|
}
|
|
337
|
-
this.
|
|
338
|
-
return this;
|
|
282
|
+
this.unbind();
|
|
339
283
|
}
|
|
340
284
|
/**
|
|
341
|
-
*
|
|
342
|
-
*
|
|
343
|
-
* Redefines an area of an existing texture
|
|
285
|
+
* Sets a 3D texture
|
|
286
|
+
* @param data
|
|
344
287
|
*/
|
|
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;
|
|
359
|
-
}
|
|
360
|
-
// Support ndarrays
|
|
361
|
-
if (data && data.data) {
|
|
362
|
-
const ndarray = data;
|
|
363
|
-
data = ndarray.data;
|
|
364
|
-
width = ndarray.shape[0];
|
|
365
|
-
height = ndarray.shape[1];
|
|
288
|
+
setTexture3DData(data) {
|
|
289
|
+
if (this.props.dimension !== '3d') {
|
|
290
|
+
throw new Error(this.id);
|
|
366
291
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
data = data.handle;
|
|
292
|
+
if (ArrayBuffer.isView(data)) {
|
|
293
|
+
copyCPUDataToMipLevel(this.device.gl, data, this);
|
|
370
294
|
}
|
|
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
295
|
}
|
|
397
296
|
/**
|
|
398
|
-
*
|
|
399
|
-
*
|
|
400
|
-
*
|
|
401
|
-
*
|
|
402
|
-
* Note that binding a texture into a Framebuffer's color buffer and
|
|
403
|
-
* rendering can be faster.
|
|
297
|
+
* Set a Texture Cube Data
|
|
298
|
+
* @todo - could support TextureCubeArray with depth
|
|
299
|
+
* @param data
|
|
300
|
+
* @param index
|
|
404
301
|
*/
|
|
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);
|
|
417
|
-
}
|
|
418
|
-
gl.bindTexture(this.target, this.handle);
|
|
419
|
-
return textureUnit;
|
|
420
|
-
}
|
|
421
|
-
unbind(textureUnit = this.textureUnit) {
|
|
422
|
-
const { gl } = this;
|
|
423
|
-
if (textureUnit !== undefined) {
|
|
424
|
-
this.textureUnit = textureUnit;
|
|
425
|
-
gl.activeTexture(33984 + textureUnit);
|
|
302
|
+
setTextureCubeData(data, depth = 0) {
|
|
303
|
+
if (this.props.dimension !== 'cube') {
|
|
304
|
+
throw new Error(this.id);
|
|
426
305
|
}
|
|
427
|
-
|
|
428
|
-
|
|
306
|
+
// for (const face of Texture.CubeFaces) {
|
|
307
|
+
// // this.setTextureCubeFaceData(face, data[face]);
|
|
308
|
+
// }
|
|
429
309
|
}
|
|
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' };
|
|
310
|
+
/**
|
|
311
|
+
* Sets an entire texture array
|
|
312
|
+
* @param data
|
|
313
|
+
*/
|
|
314
|
+
setTextureArrayData(data) {
|
|
315
|
+
if (this.props.dimension !== '2d-array') {
|
|
316
|
+
throw new Error(this.id);
|
|
447
317
|
}
|
|
448
|
-
|
|
449
|
-
return { data, dataType: 'browser-object' };
|
|
450
|
-
}
|
|
451
|
-
// HELPER METHODS
|
|
452
|
-
_deduceParameters(opts) {
|
|
453
|
-
const { format, data } = opts;
|
|
454
|
-
let { width, height, dataFormat, type, compressed } = opts;
|
|
455
|
-
// Deduce format and type from format
|
|
456
|
-
const parameters = getWebGLTextureParameters(format);
|
|
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 };
|
|
318
|
+
throw new Error('setTextureArrayData not implemented.');
|
|
462
319
|
}
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
else if (typeof HTMLImageElement !== 'undefined' && data instanceof HTMLImageElement) {
|
|
470
|
-
size = { width: data.naturalWidth, height: data.naturalHeight };
|
|
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;
|
|
320
|
+
/**
|
|
321
|
+
* Sets an entire texture cube array
|
|
322
|
+
* @param data
|
|
323
|
+
*/
|
|
324
|
+
setTextureCubeArrayData(data) {
|
|
325
|
+
throw new Error('setTextureCubeArrayData not supported in WebGL2.');
|
|
491
326
|
}
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
//
|
|
500
|
-
//
|
|
501
|
-
// GL.
|
|
502
|
-
// GL.
|
|
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
|
-
}));
|
|
327
|
+
setTextureCubeFaceData(lodData, face, depth = 0) {
|
|
328
|
+
// assert(this.props.dimension === 'cube');
|
|
329
|
+
// If the user provides multiple LODs, then automatic mipmap
|
|
330
|
+
// generation generateMipmap() should be disabled to avoid overwriting them.
|
|
331
|
+
if (Array.isArray(lodData) && lodData.length > 1 && this.props.mipmaps !== false) {
|
|
332
|
+
log.warn(`${this.id} has mipmap and multiple LODs.`)();
|
|
333
|
+
}
|
|
334
|
+
// const glFace = GL.TEXTURE_CUBE_MAP_POSITIVE_X + Texture.CubeFaces.indexOf(face);
|
|
335
|
+
// const glType = GL.UNSIGNED_BYTE;
|
|
336
|
+
// const {width, height, format = GL.RGBA, type = GL.UNSIGNED_BYTE} = this;
|
|
337
|
+
// const {width, height, format = GL.RGBA, type = GL.UNSIGNED_BYTE} = this;
|
|
514
338
|
this.bind();
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
});
|
|
530
|
-
});
|
|
339
|
+
// for (let lodLevel = 0; lodLevel < lodData.length; lodLevel++) {
|
|
340
|
+
// const imageData = lodData[lodLevel];
|
|
341
|
+
// if (imageData instanceof ArrayBuffer) {
|
|
342
|
+
// // const imageData = image instanceof ArrayBuffer ? new ImageData(new Uint8ClampedArray(image), this.width) : image;
|
|
343
|
+
// this.device.gl.texImage2D?.(
|
|
344
|
+
// glFace,
|
|
345
|
+
// lodLevel,
|
|
346
|
+
// this.glInternalFormat,
|
|
347
|
+
// this.glInternalFormat,
|
|
348
|
+
// glType,
|
|
349
|
+
// imageData
|
|
350
|
+
// );
|
|
351
|
+
// }
|
|
352
|
+
// }
|
|
531
353
|
this.unbind();
|
|
532
354
|
}
|
|
355
|
+
// INTERNAL METHODS
|
|
533
356
|
/** @todo update this method to accept LODs */
|
|
534
357
|
setImageDataForFace(options) {
|
|
535
358
|
const { face, width, height, pixels, data, format = 6408, type = 5121
|
|
@@ -551,85 +374,154 @@ export class WEBGLTexture extends Texture {
|
|
|
551
374
|
else {
|
|
552
375
|
gl.texImage2D(face, 0, format, format, type, imageData);
|
|
553
376
|
}
|
|
554
|
-
return this;
|
|
555
377
|
}
|
|
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);
|
|
567
|
-
}
|
|
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);
|
|
378
|
+
_getImageDataMap(faceData) {
|
|
379
|
+
for (let i = 0; i < Texture.CubeFaces.length; ++i) {
|
|
380
|
+
const faceName = Texture.CubeFaces[i];
|
|
381
|
+
if (faceData[faceName]) {
|
|
382
|
+
faceData[34069 + i] = faceData[faceName];
|
|
383
|
+
delete faceData[faceName];
|
|
571
384
|
}
|
|
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
385
|
}
|
|
580
|
-
|
|
581
|
-
return this;
|
|
386
|
+
return faceData;
|
|
582
387
|
}
|
|
583
388
|
// RESOURCE METHODS
|
|
584
389
|
/**
|
|
585
390
|
* Sets sampler parameters on texture
|
|
586
391
|
*/
|
|
587
392
|
_setSamplerParameters(parameters) {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
return;
|
|
591
|
-
}
|
|
592
|
-
logParameters(parameters);
|
|
593
|
-
this.gl.bindTexture(this.target, this.handle);
|
|
393
|
+
log.log(1, 'texture sampler parameters', parameters)();
|
|
394
|
+
this.gl.bindTexture(this.glTarget, this.handle);
|
|
594
395
|
for (const [pname, pvalue] of Object.entries(parameters)) {
|
|
595
396
|
const param = Number(pname);
|
|
596
397
|
const value = pvalue;
|
|
597
|
-
// Apparently
|
|
398
|
+
// Apparently integer/float issues require two different texture parameter setting functions in JavaScript.
|
|
598
399
|
// For now, pick the float version for parameters specified as GLfloat.
|
|
599
400
|
switch (param) {
|
|
600
401
|
case 33082:
|
|
601
402
|
case 33083:
|
|
602
|
-
this.gl.texParameterf(this.
|
|
403
|
+
this.gl.texParameterf(this.glTarget, param, value);
|
|
404
|
+
break;
|
|
405
|
+
case 10241:
|
|
406
|
+
this.gl.texParameteri(this.glTarget, param, value);
|
|
407
|
+
break;
|
|
408
|
+
case 10242:
|
|
409
|
+
case 10243:
|
|
410
|
+
this.gl.texParameteri(this.glTarget, param, value);
|
|
411
|
+
break;
|
|
412
|
+
case 34046:
|
|
413
|
+
// We have to query feature before using it
|
|
414
|
+
if (this.device.features.has('texture-filterable-anisotropic-webgl')) {
|
|
415
|
+
this.gl.texParameteri(this.glTarget, param, value);
|
|
416
|
+
}
|
|
603
417
|
break;
|
|
604
418
|
default:
|
|
605
|
-
this.gl.texParameteri(this.
|
|
419
|
+
this.gl.texParameteri(this.glTarget, param, value);
|
|
606
420
|
break;
|
|
607
421
|
}
|
|
608
422
|
}
|
|
609
|
-
this.gl.bindTexture(this.
|
|
610
|
-
return;
|
|
423
|
+
this.gl.bindTexture(this.glTarget, null);
|
|
611
424
|
}
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
425
|
+
// CLASSIC
|
|
426
|
+
/*
|
|
427
|
+
setCubeMapData(options: {
|
|
428
|
+
width: number;
|
|
429
|
+
height: number;
|
|
430
|
+
data: Record<GL, Texture2DData> | Record<TextureCubeFace, Texture2DData>;
|
|
431
|
+
format?: any;
|
|
432
|
+
type?: any;
|
|
433
|
+
/** @deprecated Use .data *
|
|
434
|
+
pixels: any;
|
|
435
|
+
}): void {
|
|
436
|
+
const {gl} = this;
|
|
437
|
+
|
|
438
|
+
const {width, height, pixels, data, format = GL.RGBA, type = GL.UNSIGNED_BYTE} = options;
|
|
439
|
+
|
|
440
|
+
// pixel data (imageDataMap) is an Object from Face to Image or Promise.
|
|
441
|
+
// For example:
|
|
442
|
+
// {
|
|
443
|
+
// GL.TEXTURE_CUBE_MAP_POSITIVE_X : Image-or-Promise,
|
|
444
|
+
// GL.TEXTURE_CUBE_MAP_NEGATIVE_X : Image-or-Promise,
|
|
445
|
+
// ... }
|
|
446
|
+
// To provide multiple level-of-details (LODs) this can be Face to Array
|
|
447
|
+
// of Image or Promise, like this
|
|
448
|
+
// {
|
|
449
|
+
// GL.TEXTURE_CUBE_MAP_POSITIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
|
|
450
|
+
// GL.TEXTURE_CUBE_MAP_NEGATIVE_X : [Image-or-Promise-LOD-0, Image-or-Promise-LOD-1],
|
|
451
|
+
// ... }
|
|
452
|
+
|
|
453
|
+
const imageDataMap = this._getImageDataMap(pixels || data);
|
|
454
|
+
|
|
455
|
+
const resolvedFaces = WEBGLTexture.FACES.map(face => {
|
|
456
|
+
const facePixels = imageDataMap[face];
|
|
457
|
+
return Array.isArray(facePixels) ? facePixels : [facePixels];
|
|
458
|
+
});
|
|
459
|
+
this.bind();
|
|
460
|
+
|
|
461
|
+
WEBGLTexture.FACES.forEach((face, index) => {
|
|
462
|
+
if (resolvedFaces[index].length > 1 && this.props.mipmaps !== false) {
|
|
463
|
+
// If the user provides multiple LODs, then automatic mipmap
|
|
464
|
+
// generation generateMipmap() should be disabled to avoid overwritting them.
|
|
465
|
+
log.warn(`${this.id} has mipmap and multiple LODs.`)();
|
|
466
|
+
}
|
|
467
|
+
resolvedFaces[index].forEach((image, lodLevel) => {
|
|
468
|
+
// TODO: adjust width & height for LOD!
|
|
469
|
+
if (width && height) {
|
|
470
|
+
gl.texImage2D(face, lodLevel, format, width, height, 0 /* border*, format, type, image);
|
|
471
|
+
} else {
|
|
472
|
+
gl.texImage2D(face, lodLevel, format, format, type, image);
|
|
473
|
+
}
|
|
474
|
+
});
|
|
475
|
+
});
|
|
476
|
+
|
|
477
|
+
this.unbind();
|
|
478
|
+
}
|
|
479
|
+
*/
|
|
480
|
+
// INTERNAL SETTERS
|
|
481
|
+
/**
|
|
482
|
+
* Copy a region of data from a CPU memory buffer into this texture.
|
|
483
|
+
* @todo - GLUnpackParameters parameters
|
|
484
|
+
*/
|
|
485
|
+
_setMipLevel(depth, level, textureData, offset = 0) {
|
|
486
|
+
// if (!textureData) {
|
|
487
|
+
// clearMipLevel(this.device.gl, {...this, depth, level});
|
|
488
|
+
// return;
|
|
489
|
+
// }
|
|
490
|
+
if (Texture.isExternalImage(textureData)) {
|
|
491
|
+
copyCPUImageToMipLevel(this.device.gl, textureData, { ...this, depth, level });
|
|
492
|
+
return;
|
|
493
|
+
}
|
|
494
|
+
// @ts-expect-error
|
|
495
|
+
if (this.isTextureLevelData(textureData)) {
|
|
496
|
+
copyCPUDataToMipLevel(this.device.gl, textureData.data, {
|
|
497
|
+
...this,
|
|
498
|
+
depth,
|
|
499
|
+
level
|
|
500
|
+
});
|
|
501
|
+
return;
|
|
502
|
+
}
|
|
503
|
+
throw new Error('Texture: invalid image data');
|
|
504
|
+
}
|
|
505
|
+
// HELPERS
|
|
506
|
+
getActiveUnit() {
|
|
507
|
+
return this.gl.getParameter(34016) - 33984;
|
|
508
|
+
}
|
|
509
|
+
bind(textureUnit) {
|
|
510
|
+
const { gl } = this;
|
|
511
|
+
if (textureUnit !== undefined) {
|
|
512
|
+
this.textureUnit = textureUnit;
|
|
513
|
+
gl.activeTexture(33984 + textureUnit);
|
|
514
|
+
}
|
|
515
|
+
gl.bindTexture(this.glTarget, this.handle);
|
|
516
|
+
return textureUnit;
|
|
517
|
+
}
|
|
518
|
+
unbind(textureUnit) {
|
|
519
|
+
const { gl } = this;
|
|
520
|
+
if (textureUnit !== undefined) {
|
|
521
|
+
this.textureUnit = textureUnit;
|
|
522
|
+
gl.activeTexture(33984 + textureUnit);
|
|
523
|
+
}
|
|
524
|
+
gl.bindTexture(this.glTarget, null);
|
|
525
|
+
return textureUnit;
|
|
631
526
|
}
|
|
632
|
-
}
|
|
633
|
-
function logParameters(parameters) {
|
|
634
|
-
log.log(1, 'texture sampler parameters', parameters)();
|
|
635
527
|
}
|