@kitware/vtk.js 33.0.0-beta.2 → 33.0.0-beta.4
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/Common/Core/DataArray.d.ts +21 -0
- package/Common/Core/DataArray.js +39 -0
- package/Common/Core/Math/index.js +1 -1
- package/Common/Core/Math.js +1 -1
- package/Common/Core/URLExtract.js +2 -6
- package/Common/DataModel/Line.js +1 -0
- package/Common/DataModel/PolyLine.js +4 -0
- package/Filters/Core/ThresholdPoints.d.ts +72 -0
- package/Filters/Core/ThresholdPoints.js +219 -0
- package/Filters/General/ContourTriangulator/helper.js +1 -1
- package/IO/Core/DataAccessHelper/JSZipDataAccessHelper.js +1 -1
- package/IO/Geometry/DracoReader.d.ts +4 -4
- package/IO/Geometry/DracoReader.js +154 -105
- package/IO/Geometry/GLTFImporter/Animations.js +239 -0
- package/IO/Geometry/GLTFImporter/Constants.js +87 -0
- package/IO/Geometry/GLTFImporter/Decoder.js +69 -0
- package/IO/Geometry/GLTFImporter/Extensions.js +110 -0
- package/IO/Geometry/GLTFImporter/ORMTexture.worker.js +42 -0
- package/IO/Geometry/GLTFImporter/Parser.js +359 -0
- package/IO/Geometry/GLTFImporter/Reader.js +518 -0
- package/IO/Geometry/GLTFImporter/Utils.js +165 -0
- package/IO/Geometry/GLTFImporter.d.ts +266 -0
- package/IO/Geometry/GLTFImporter.js +245 -0
- package/IO/Geometry/IFCImporter.d.ts +163 -0
- package/IO/Geometry/IFCImporter.js +270 -0
- package/IO/Geometry/STLReader.d.ts +14 -0
- package/IO/Geometry/STLReader.js +57 -1
- package/IO/Geometry.js +5 -1
- package/IO/Image/HDRReader/Utils.js +1 -1
- package/IO/Image/HDRReader.js +1 -1
- package/IO/Image/TGAReader/Constants.js +28 -0
- package/IO/Image/TGAReader.d.ts +121 -0
- package/IO/Image/TGAReader.js +418 -0
- package/IO/Image/TIFFReader.d.ts +133 -0
- package/IO/Image/TIFFReader.js +144 -0
- package/IO/Image.js +5 -1
- package/IO/XML/XMLPolyDataWriter.js +1 -0
- package/Interaction/Manipulators/MouseCameraTrackballRollManipulator.js +1 -1
- package/Interaction/Style/InteractorStyleTrackballCamera.js +1 -1
- package/Rendering/Core/AbstractImageMapper.d.ts +81 -0
- package/Rendering/Core/AbstractImageMapper.js +5 -2
- package/Rendering/Core/AbstractPicker.d.ts +13 -13
- package/Rendering/Core/AbstractPicker.js +1 -1
- package/Rendering/Core/Actor2D.d.ts +22 -0
- package/Rendering/Core/Actor2D.js +1 -1
- package/Rendering/Core/CellPicker.js +4 -1
- package/Rendering/Core/Glyph3DMapper.d.ts +45 -29
- package/Rendering/Core/ImageCPRMapper.js +6 -5
- package/Rendering/Core/ImageProperty.d.ts +42 -1
- package/Rendering/Core/ImageProperty.js +7 -5
- package/Rendering/Core/ImageResliceMapper.d.ts +1 -2
- package/Rendering/Core/ImageResliceMapper.js +5 -4
- package/Rendering/Core/PointPicker.js +10 -1
- package/Rendering/Core/Prop3D.js +1 -1
- package/Rendering/Core/RenderWindowInteractor.d.ts +1 -1
- package/Rendering/Core/RenderWindowInteractor.js +1 -1
- package/Rendering/Core/Viewport.js +13 -3
- package/Rendering/Core/VolumeMapper.d.ts +70 -0
- package/Rendering/Core/VolumeMapper.js +10 -5
- package/Rendering/Core/VolumeProperty.d.ts +20 -1
- package/Rendering/Core/VolumeProperty.js +7 -5
- package/Rendering/Misc/CanvasView.js +4 -2
- package/Rendering/Misc/RemoteView.d.ts +9 -3
- package/Rendering/Misc/RemoteView.js +7 -3
- package/Rendering/Misc/SynchronizableRenderWindow/BehaviorManager/CameraSynchronizer.js +2 -2
- package/Rendering/Misc/SynchronizableRenderWindow/ObjectManager.d.ts +1 -1
- package/Rendering/OpenGL/ImageCPRMapper.js +18 -2
- package/Rendering/OpenGL/ImageMapper.js +42 -11
- package/Rendering/OpenGL/ImageResliceMapper.js +20 -4
- package/Rendering/OpenGL/Renderer.js +1 -1
- package/Rendering/OpenGL/Texture/supportsNorm16Linear.js +97 -0
- package/Rendering/OpenGL/Texture.d.ts +29 -8
- package/Rendering/OpenGL/Texture.js +172 -34
- package/Rendering/OpenGL/VolumeMapper.js +22 -4
- package/Rendering/SceneGraph/ViewNode.js +12 -2
- package/Rendering/WebXR/RenderWindowHelper.js +9 -0
- package/Widgets/Core/WidgetManager.d.ts +12 -1
- package/Widgets/Representations/WidgetRepresentation.d.ts +1 -7
- package/Widgets/Widgets3D/AngleWidget/behavior.js +2 -0
- package/Widgets/Widgets3D/InteractiveOrientationWidget.js +1 -1
- package/Widgets/Widgets3D/ResliceCursorWidget/behavior.js +17 -0
- package/Widgets/Widgets3D/ResliceCursorWidget/helpers.js +1 -0
- package/Widgets/Widgets3D/ResliceCursorWidget.d.ts +1 -8
- package/Widgets/Widgets3D/ShapeWidget/behavior.js +3 -0
- package/_virtual/rollup-plugin-worker-loader__module_Sources/IO/Geometry/GLTFImporter/ORMTexture.worker.js +296 -0
- package/index.d.ts +5 -0
- package/package.json +19 -17
|
@@ -162,6 +162,76 @@ export interface vtkVolumeMapper extends vtkAbstractMapper3D {
|
|
|
162
162
|
*
|
|
163
163
|
*/
|
|
164
164
|
update(): void;
|
|
165
|
+
|
|
166
|
+
/**
|
|
167
|
+
* Set the opacity texture width.
|
|
168
|
+
*
|
|
169
|
+
* The default width (1024) should be fine in most instances.
|
|
170
|
+
* Only set this property if your opacity function range width is
|
|
171
|
+
* larger than 1024.
|
|
172
|
+
*
|
|
173
|
+
* @param {Number} width the texture width (defaults to 1024)
|
|
174
|
+
*/
|
|
175
|
+
setOpacityTextureWidth(width: number): boolean;
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Get the opacity texture width.
|
|
179
|
+
*/
|
|
180
|
+
getOpacityTextureWidth(): number;
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Set the color texture width.
|
|
184
|
+
*
|
|
185
|
+
* The default width (1024) should be fine in most instances.
|
|
186
|
+
* Only set this property if your color transfer function range width is
|
|
187
|
+
* larger than 1024.
|
|
188
|
+
*
|
|
189
|
+
* A reasonable max texture size would be either 2048 or 4096, as those
|
|
190
|
+
* widths are supported by the vast majority of devices. Any width larger
|
|
191
|
+
* than that will have issues with device support.
|
|
192
|
+
*
|
|
193
|
+
* Specifying a width that is less than or equal to 0 will use the largest
|
|
194
|
+
* possible texture width on the device. Use this with caution! The max texture
|
|
195
|
+
* width of one device may not be the same for another device.
|
|
196
|
+
*
|
|
197
|
+
* You can find more information about supported texture widths at the following link:
|
|
198
|
+
* https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE
|
|
199
|
+
*
|
|
200
|
+
* @param {Number} width the texture width (defaults to 1024)
|
|
201
|
+
*/
|
|
202
|
+
setColorTextureWidth(width: number): boolean;
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Get the color texture width.
|
|
206
|
+
*/
|
|
207
|
+
getColorTextureWidth(): number;
|
|
208
|
+
|
|
209
|
+
/**
|
|
210
|
+
* Set the label outline texture width.
|
|
211
|
+
*
|
|
212
|
+
* The default width (1024) should be fine in most instances.
|
|
213
|
+
* Only set this property if you have more than 1024 labels
|
|
214
|
+
* that you want to render with thickness.
|
|
215
|
+
*
|
|
216
|
+
* A reasonable max texture size would be either 2048 or 4096, as those
|
|
217
|
+
* widths are supported by the vast majority of devices. Any width larger
|
|
218
|
+
* than that will have issues with device support.
|
|
219
|
+
*
|
|
220
|
+
* Specifying a width that is less than or equal to 0 will use the largest
|
|
221
|
+
* possible texture width on the device. Use this with caution! The max texture
|
|
222
|
+
* width of one device may not be the same for another device.
|
|
223
|
+
*
|
|
224
|
+
* You can find more information about supported texture widths at the following link:
|
|
225
|
+
* https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE
|
|
226
|
+
*
|
|
227
|
+
* @param {Number} width the texture width (defaults to 1024)
|
|
228
|
+
*/
|
|
229
|
+
setLabelOutlineTextureWidth(width: number): boolean;
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Get the label outline texture width.
|
|
233
|
+
*/
|
|
234
|
+
getLabelOutlineTextureWidth(): number;
|
|
165
235
|
}
|
|
166
236
|
|
|
167
237
|
/**
|
|
@@ -81,7 +81,8 @@ function vtkVolumeMapper(publicAPI, model) {
|
|
|
81
81
|
// Object factory
|
|
82
82
|
// ----------------------------------------------------------------------------
|
|
83
83
|
|
|
84
|
-
|
|
84
|
+
// TODO: what values to use for averageIPScalarRange to get GLSL to use max / min values like [-Math.inf, Math.inf]?
|
|
85
|
+
const defaultValues = initialValues => ({
|
|
85
86
|
bounds: [...vtkBoundingBox.INIT_BOUNDS],
|
|
86
87
|
sampleDistance: 1.0,
|
|
87
88
|
imageSampleDistance: 1.0,
|
|
@@ -90,16 +91,20 @@ const DEFAULT_VALUES = {
|
|
|
90
91
|
initialInteractionScale: 1.0,
|
|
91
92
|
interactionSampleDistanceFactor: 1.0,
|
|
92
93
|
blendMode: BlendMode.COMPOSITE_BLEND,
|
|
93
|
-
volumeShadowSamplingDistFactor: 5.0
|
|
94
|
-
|
|
94
|
+
volumeShadowSamplingDistFactor: 5.0,
|
|
95
|
+
colorTextureWidth: 1024,
|
|
96
|
+
opacityTextureWidth: 1024,
|
|
97
|
+
labelOutlineTextureWidth: 1024,
|
|
98
|
+
...initialValues
|
|
99
|
+
});
|
|
95
100
|
|
|
96
101
|
// ----------------------------------------------------------------------------
|
|
97
102
|
|
|
98
103
|
function extend(publicAPI, model) {
|
|
99
104
|
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
100
|
-
Object.assign(model,
|
|
105
|
+
Object.assign(model, defaultValues(initialValues));
|
|
101
106
|
vtkAbstractMapper3D.extend(publicAPI, model, initialValues);
|
|
102
|
-
macro.setGet(publicAPI, model, ['sampleDistance', 'imageSampleDistance', 'maximumSamplesPerRay', 'autoAdjustSampleDistances', 'initialInteractionScale', 'interactionSampleDistanceFactor', 'blendMode', 'volumeShadowSamplingDistFactor']);
|
|
107
|
+
macro.setGet(publicAPI, model, ['sampleDistance', 'imageSampleDistance', 'maximumSamplesPerRay', 'autoAdjustSampleDistances', 'initialInteractionScale', 'interactionSampleDistanceFactor', 'blendMode', 'volumeShadowSamplingDistFactor', 'colorTextureWidth', 'opacityTextureWidth', 'labelOutlineTextureWidth']);
|
|
103
108
|
macro.event(publicAPI, model, 'lightingActivated');
|
|
104
109
|
|
|
105
110
|
// Object methods
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import vtkPiecewiseFunction from './../../Common/DataModel/PiecewiseFunction';
|
|
2
2
|
import { vtkObject } from './../../interfaces';
|
|
3
|
-
import { Nullable } from './../../types';
|
|
3
|
+
import { Extent, Nullable } from './../../types';
|
|
4
4
|
import vtkColorTransferFunction from './ColorTransferFunction';
|
|
5
5
|
import { ColorMixPreset, InterpolationType, OpacityMode } from './VolumeProperty/Constants';
|
|
6
6
|
|
|
@@ -486,6 +486,25 @@ export interface vtkVolumeProperty extends vtkObject {
|
|
|
486
486
|
* @param LAOKernelRadius
|
|
487
487
|
*/
|
|
488
488
|
setLAOKernelRadius(LAOKernelRadius: number): void;
|
|
489
|
+
|
|
490
|
+
/**
|
|
491
|
+
* Informs the mapper to only update the specified extents at the next render.
|
|
492
|
+
*
|
|
493
|
+
* If there are zero extents, the mapper updates the entire volume texture.
|
|
494
|
+
* Otherwise, the mapper will only update the texture by the specified extents
|
|
495
|
+
* during the next render call.
|
|
496
|
+
*
|
|
497
|
+
* This array is cleared after a successful render.
|
|
498
|
+
* @param extents
|
|
499
|
+
*/
|
|
500
|
+
setUpdatedExtents(extents: Extent[]): boolean;
|
|
501
|
+
|
|
502
|
+
/**
|
|
503
|
+
* Retrieves the updated extents.
|
|
504
|
+
*
|
|
505
|
+
* This array is cleared after every successful render.
|
|
506
|
+
*/
|
|
507
|
+
getUpdatedExtents(): Extent[];
|
|
489
508
|
}
|
|
490
509
|
|
|
491
510
|
/**
|
|
@@ -228,7 +228,7 @@ function vtkVolumeProperty(publicAPI, model) {
|
|
|
228
228
|
// Object factory
|
|
229
229
|
// ----------------------------------------------------------------------------
|
|
230
230
|
|
|
231
|
-
const
|
|
231
|
+
const defaultValues = initialValues => ({
|
|
232
232
|
colorMixPreset: ColorMixPreset.DEFAULT,
|
|
233
233
|
independentComponents: true,
|
|
234
234
|
interpolationType: InterpolationType.FAST_LINEAR,
|
|
@@ -254,14 +254,16 @@ const DEFAULT_VALUES = {
|
|
|
254
254
|
// local ambient occlusion
|
|
255
255
|
localAmbientOcclusion: false,
|
|
256
256
|
LAOKernelSize: 15,
|
|
257
|
-
LAOKernelRadius: 7
|
|
258
|
-
|
|
257
|
+
LAOKernelRadius: 7,
|
|
258
|
+
updatedExtents: [],
|
|
259
|
+
...initialValues
|
|
260
|
+
});
|
|
259
261
|
|
|
260
262
|
// ----------------------------------------------------------------------------
|
|
261
263
|
|
|
262
264
|
function extend(publicAPI, model) {
|
|
263
265
|
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
264
|
-
Object.assign(model,
|
|
266
|
+
Object.assign(model, defaultValues(initialValues));
|
|
265
267
|
|
|
266
268
|
// Build VTK API
|
|
267
269
|
macro.obj(publicAPI, model);
|
|
@@ -287,7 +289,7 @@ function extend(publicAPI, model) {
|
|
|
287
289
|
}
|
|
288
290
|
macro.setGet(publicAPI, model, ['colorMixPreset', 'independentComponents', 'interpolationType', 'shade', 'ambient', 'diffuse', 'specular', 'specularPower', 'useLabelOutline', 'labelOutlineOpacity',
|
|
289
291
|
// Properties moved from volume mapper
|
|
290
|
-
'filterMode', 'preferSizeOverAccuracy', 'computeNormalFromOpacity', 'volumetricScatteringBlending', 'globalIlluminationReach', 'anisotropy', 'localAmbientOcclusion', 'LAOKernelSize', 'LAOKernelRadius']);
|
|
292
|
+
'filterMode', 'preferSizeOverAccuracy', 'computeNormalFromOpacity', 'volumetricScatteringBlending', 'globalIlluminationReach', 'anisotropy', 'localAmbientOcclusion', 'LAOKernelSize', 'LAOKernelRadius', 'updatedExtents']);
|
|
291
293
|
|
|
292
294
|
// Property moved from volume mapper
|
|
293
295
|
macro.setGetArray(publicAPI, model, ['ipScalarRange'], 2);
|
|
@@ -134,8 +134,10 @@ function extend(publicAPI, model) {
|
|
|
134
134
|
Object.assign(model, DEFAULT_VALUES, initialValues);
|
|
135
135
|
|
|
136
136
|
// Create internal instances
|
|
137
|
-
model.canvas
|
|
138
|
-
|
|
137
|
+
if (!model.canvas) {
|
|
138
|
+
model.canvas = document.createElement('canvas');
|
|
139
|
+
model.canvas.style.width = '100%';
|
|
140
|
+
}
|
|
139
141
|
|
|
140
142
|
// Create internal bgImage
|
|
141
143
|
model.bgImage = new Image();
|
|
@@ -13,21 +13,27 @@ interface IRemoteViewInitialValues {
|
|
|
13
13
|
rpcGestureEvent?: any;
|
|
14
14
|
rpcWheelEvent?: any;
|
|
15
15
|
viewStream?: vtkViewStream;
|
|
16
|
+
canvasElement?: HTMLCanvasElement;
|
|
16
17
|
}
|
|
17
18
|
|
|
18
19
|
export interface vtkRemoteView extends vtkObject {
|
|
19
20
|
/**
|
|
20
|
-
* Get container element
|
|
21
|
+
* Get container HTML element
|
|
21
22
|
*/
|
|
22
23
|
getContainer(): HTMLElement;
|
|
23
24
|
|
|
24
25
|
/**
|
|
25
|
-
*
|
|
26
|
+
* Get vtkViewStream object
|
|
26
27
|
*/
|
|
27
28
|
getViewStream(): vtkViewStream;
|
|
28
29
|
|
|
29
30
|
/**
|
|
30
|
-
*
|
|
31
|
+
* Get the canvas HTML element
|
|
32
|
+
*/
|
|
33
|
+
getCanvasElement(): HTMLCanvasElement;
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Get the vtkCanvasView object
|
|
31
37
|
*/
|
|
32
38
|
getCanvasView(): vtkCanvasView;
|
|
33
39
|
|
|
@@ -17,7 +17,9 @@ function vtkRemoteView(publicAPI, model) {
|
|
|
17
17
|
model.classHierarchy.push('vtkRemoteView');
|
|
18
18
|
|
|
19
19
|
// Constructor
|
|
20
|
-
model.canvasView = vtkCanvasView.newInstance(
|
|
20
|
+
model.canvasView = vtkCanvasView.newInstance({
|
|
21
|
+
canvas: model.canvasElement
|
|
22
|
+
});
|
|
21
23
|
model.interactorStyle = vtkInteractorStyleRemoteMouse.newInstance();
|
|
22
24
|
model.interactor = vtkRenderWindowInteractor.newInstance();
|
|
23
25
|
model.interactor.setView(model.canvasView);
|
|
@@ -60,6 +62,7 @@ function vtkRemoteView(publicAPI, model) {
|
|
|
60
62
|
model.viewStream.delete();
|
|
61
63
|
}
|
|
62
64
|
}, publicAPI.delete);
|
|
65
|
+
publicAPI.getCanvasElement = () => model.canvasView.getCanvas();
|
|
63
66
|
|
|
64
67
|
// --------------------------------------------------------------------------
|
|
65
68
|
// remote handing
|
|
@@ -194,7 +197,8 @@ const DEFAULT_VALUES = {
|
|
|
194
197
|
stillRatio: 1,
|
|
195
198
|
rpcMouseEvent: 'viewport.mouse.interaction',
|
|
196
199
|
rpcGestureEvent: null,
|
|
197
|
-
rpcWheelEvent: null
|
|
200
|
+
rpcWheelEvent: null,
|
|
201
|
+
canvasElement: null
|
|
198
202
|
};
|
|
199
203
|
|
|
200
204
|
// ----------------------------------------------------------------------------
|
|
@@ -203,7 +207,7 @@ function extend(publicAPI, model) {
|
|
|
203
207
|
let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {};
|
|
204
208
|
Object.assign(model, DEFAULT_VALUES, initialValues);
|
|
205
209
|
macro.obj(publicAPI, model, initialValues);
|
|
206
|
-
macro.get(publicAPI, model, ['container', 'viewStream', 'canvasView', 'interactor', 'interactorStyle', 'interactiveQuality', 'interactiveRatio', 'stillQuality', 'stillRatio']);
|
|
210
|
+
macro.get(publicAPI, model, ['container', 'viewStream', 'canvasView', 'interactor', 'interactorStyle', 'interactiveQuality', 'interactiveRatio', 'stillQuality', 'stillRatio', 'canvasElement']);
|
|
207
211
|
macro.setGet(publicAPI, model, ['session', 'rpcMouseEvent', 'rpcGestureEvent', 'rpcWheelEvent']);
|
|
208
212
|
|
|
209
213
|
// Object methods
|
|
@@ -33,8 +33,8 @@ function vtkCameraSynchronizer(publicAPI, model) {
|
|
|
33
33
|
}
|
|
34
34
|
|
|
35
35
|
// Update listeners automatically
|
|
36
|
-
model.
|
|
37
|
-
model.
|
|
36
|
+
model._onSrcRendererChanged = updateListeners;
|
|
37
|
+
model._onDstRendererChanged = updateListeners;
|
|
38
38
|
function updatePreviousValues(position, focalPoint, viewUp) {
|
|
39
39
|
if (cameraState[0] !== position[0] || cameraState[1] !== position[1] || cameraState[2] !== position[2] || cameraState[3] !== focalPoint[0] || cameraState[4] !== focalPoint[1] || cameraState[5] !== focalPoint[2] || cameraState[6] !== viewUp[0] || cameraState[7] !== viewUp[1] || cameraState[8] !== viewUp[2]) {
|
|
40
40
|
cameraState[0] = position[0];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { vtkObject } from './../../../interfaces';
|
|
2
2
|
import { Nullable } from './../../../types';
|
|
3
|
-
import { ISynchronizerContext, IViewState } from '
|
|
3
|
+
import { ISynchronizerContext, IViewState } from '../SynchronizableRenderWindow';
|
|
4
4
|
|
|
5
5
|
export type BuilderFunction = <T extends vtkObject>(
|
|
6
6
|
type: string,
|
|
@@ -147,6 +147,7 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
|
|
|
147
147
|
publicAPI.buildBufferObjects = (ren, actor) => {
|
|
148
148
|
const image = model.currentImageDataInput;
|
|
149
149
|
const centerline = model.currentCenterlineInput;
|
|
150
|
+
const property = actor.getProperty();
|
|
150
151
|
|
|
151
152
|
// Rebuild the volumeTexture if the data has changed
|
|
152
153
|
const scalars = image?.getPointData()?.getScalars();
|
|
@@ -156,6 +157,8 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
|
|
|
156
157
|
const cachedScalarsEntry = model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
|
|
157
158
|
const volumeTextureHash = getImageDataHash(image, scalars);
|
|
158
159
|
const reBuildTex = !cachedScalarsEntry?.oglObject?.getHandle() || cachedScalarsEntry?.hash !== volumeTextureHash;
|
|
160
|
+
const updatedExtents = property.getUpdatedExtents();
|
|
161
|
+
const hasUpdatedExtents = !!updatedExtents.length;
|
|
159
162
|
if (reBuildTex) {
|
|
160
163
|
model.volumeTexture = vtkOpenGLTexture.newInstance();
|
|
161
164
|
model.volumeTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
@@ -174,6 +177,13 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
|
|
|
174
177
|
} else {
|
|
175
178
|
model.volumeTexture = cachedScalarsEntry.oglObject;
|
|
176
179
|
}
|
|
180
|
+
if (hasUpdatedExtents) {
|
|
181
|
+
// If hasUpdatedExtents, then the texture is partially updated.
|
|
182
|
+
// clear the array to acknowledge the update.
|
|
183
|
+
property.setUpdatedExtents([]);
|
|
184
|
+
const dims = image.getDimensions();
|
|
185
|
+
model.volumeTexture.create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars, false, updatedExtents);
|
|
186
|
+
}
|
|
177
187
|
|
|
178
188
|
// Rebuild the color texture if needed
|
|
179
189
|
const numComp = scalars.getNumberOfComponents();
|
|
@@ -190,7 +200,10 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
|
|
|
190
200
|
const cachedColorEntry = model._openGLRenderWindow.getGraphicsResourceForObject(firstColorTransferFunc);
|
|
191
201
|
const reBuildColorTexture = !cachedColorEntry?.oglObject?.getHandle() || cachedColorEntry?.hash !== colorTextureHash;
|
|
192
202
|
if (reBuildColorTexture) {
|
|
193
|
-
|
|
203
|
+
let cWidth = model.renderable.getColorTextureWidth();
|
|
204
|
+
if (cWidth <= 0) {
|
|
205
|
+
cWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
|
|
206
|
+
}
|
|
194
207
|
const cSize = cWidth * textureHeight * 3;
|
|
195
208
|
const cTable = new Uint8ClampedArray(cSize);
|
|
196
209
|
model.colorTexture = vtkOpenGLTexture.newInstance();
|
|
@@ -247,7 +260,10 @@ function vtkOpenGLImageCPRMapper(publicAPI, model) {
|
|
|
247
260
|
const cachedPwfEntry = model._openGLRenderWindow.getGraphicsResourceForObject(firstPwFunc);
|
|
248
261
|
const reBuildPwf = !cachedPwfEntry?.oglObject?.getHandle() || cachedPwfEntry?.hash !== pwfTextureHash;
|
|
249
262
|
if (reBuildPwf) {
|
|
250
|
-
|
|
263
|
+
let pwfWidth = model.renderable.getOpacityTextureWidth();
|
|
264
|
+
if (pwfWidth <= 0) {
|
|
265
|
+
pwfWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
|
|
266
|
+
}
|
|
251
267
|
const pwfSize = pwfWidth * textureHeight;
|
|
252
268
|
const pwfTable = new Uint8ClampedArray(pwfSize);
|
|
253
269
|
model.pwfTexture = vtkOpenGLTexture.newInstance();
|
|
@@ -167,9 +167,9 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
167
167
|
// check for the outline thickness and opacity
|
|
168
168
|
const vtkImageLabelOutline = actor.getProperty().getUseLabelOutline();
|
|
169
169
|
if (vtkImageLabelOutline === true) {
|
|
170
|
-
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::LabelOutline::Dec', ['uniform int outlineThickness;', 'uniform float vpWidth;', 'uniform float vpHeight;', 'uniform float vpOffsetX;', 'uniform float vpOffsetY;', 'uniform mat4 PCWCMatrix;', 'uniform mat4 vWCtoIDX;', 'uniform ivec3 imageDimensions;']).result;
|
|
170
|
+
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::LabelOutline::Dec', ['uniform int outlineThickness;', 'uniform float vpWidth;', 'uniform float vpHeight;', 'uniform float vpOffsetX;', 'uniform float vpOffsetY;', 'uniform mat4 PCWCMatrix;', 'uniform mat4 vWCtoIDX;', 'uniform ivec3 imageDimensions;', 'uniform int sliceAxis;']).result;
|
|
171
171
|
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::ImageLabelOutlineOn', '#define vtkImageLabelOutlineOn').result;
|
|
172
|
-
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::LabelOutlineHelperFunction', ['#ifdef vtkImageLabelOutlineOn', 'vec3 fragCoordToIndexSpace(vec4 fragCoord) {', ' vec4 pcPos = vec4(', ' (fragCoord.x / vpWidth - vpOffsetX - 0.5) * 2.0,', ' (fragCoord.y / vpHeight - vpOffsetY - 0.5) * 2.0,', ' (fragCoord.z - 0.5) * 2.0,', ' 1.0);', '', ' vec4 worldCoord = PCWCMatrix * pcPos;', ' vec4 vertex = (worldCoord/worldCoord.w);', '', ' vec3 index = (vWCtoIDX * vertex).xyz;', '', ' // half voxel fix for labelmapOutline', ' return (index + vec3(0.5)) / vec3(imageDimensions);', '}', '#endif']).result;
|
|
172
|
+
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::LabelOutlineHelperFunction', ['#ifdef vtkImageLabelOutlineOn', 'vec3 fragCoordToIndexSpace(vec4 fragCoord) {', ' vec4 pcPos = vec4(', ' (fragCoord.x / vpWidth - vpOffsetX - 0.5) * 2.0,', ' (fragCoord.y / vpHeight - vpOffsetY - 0.5) * 2.0,', ' (fragCoord.z - 0.5) * 2.0,', ' 1.0);', '', ' vec4 worldCoord = PCWCMatrix * pcPos;', ' vec4 vertex = (worldCoord/worldCoord.w);', '', ' vec3 index = (vWCtoIDX * vertex).xyz;', '', ' // half voxel fix for labelmapOutline', ' return (index + vec3(0.5)) / vec3(imageDimensions);', '}', 'vec2 getSliceCoords(vec3 coord, int axis) {', ' if (axis == 0) return coord.yz;', ' if (axis == 1) return coord.xz;', ' if (axis == 2) return coord.xy;', '}', '#endif']).result;
|
|
173
173
|
}
|
|
174
174
|
if (iComps) {
|
|
175
175
|
const rgba = ['r', 'g', 'b', 'a'];
|
|
@@ -201,7 +201,7 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
201
201
|
FSSource = vtkShaderProgram.substitute(FSSource, '//VTK::TCoord::Impl', [...splitStringOnEnter(`
|
|
202
202
|
#ifdef vtkImageLabelOutlineOn
|
|
203
203
|
vec3 centerPosIS = fragCoordToIndexSpace(gl_FragCoord);
|
|
204
|
-
float centerValue = texture2D(texture1, centerPosIS
|
|
204
|
+
float centerValue = texture2D(texture1, getSliceCoords(centerPosIS, sliceAxis)).r;
|
|
205
205
|
bool pixelOnBorder = false;
|
|
206
206
|
vec3 tColor = texture2D(colorTexture1, vec2(centerValue * cscale0 + cshift0, 0.5)).rgb;
|
|
207
207
|
float scalarOpacity = texture2D(pwfTexture1, vec2(centerValue * pwfscale0 + pwfshift0, 0.5)).r;
|
|
@@ -212,7 +212,7 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
212
212
|
int actualThickness = int(textureValue * 255.0);
|
|
213
213
|
|
|
214
214
|
if (segmentIndex == 0){
|
|
215
|
-
gl_FragData[0] = vec4(0.0,
|
|
215
|
+
gl_FragData[0] = vec4(0.0, 0.0, 0.0, 0.0);
|
|
216
216
|
return;
|
|
217
217
|
}
|
|
218
218
|
|
|
@@ -225,7 +225,7 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
225
225
|
gl_FragCoord.y + float(j),
|
|
226
226
|
gl_FragCoord.z, gl_FragCoord.w);
|
|
227
227
|
vec3 neighborPosIS = fragCoordToIndexSpace(neighborPixelCoord);
|
|
228
|
-
float value = texture2D(texture1, neighborPosIS
|
|
228
|
+
float value = texture2D(texture1, getSliceCoords(neighborPosIS, sliceAxis)).r;
|
|
229
229
|
if (value != centerValue) {
|
|
230
230
|
pixelOnBorder = true;
|
|
231
231
|
break;
|
|
@@ -474,7 +474,14 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
474
474
|
if (vtkImageLabelOutline === true) {
|
|
475
475
|
const worldToIndex = image.getWorldToIndex();
|
|
476
476
|
const imageDimensions = image.getDimensions();
|
|
477
|
-
|
|
477
|
+
let sliceAxis = model.renderable.getClosestIJKAxis().ijkMode;
|
|
478
|
+
|
|
479
|
+
// SlicingMode.NONE equates to SlicingMode.K
|
|
480
|
+
if (sliceAxis === SlicingMode.NONE) {
|
|
481
|
+
sliceAxis = SlicingMode.K;
|
|
482
|
+
}
|
|
483
|
+
program.setUniform3i('imageDimensions', imageDimensions[0], imageDimensions[1], imageDimensions[2]);
|
|
484
|
+
program.setUniformi('sliceAxis', sliceAxis);
|
|
478
485
|
program.setUniformMatrix('vWCtoIDX', worldToIndex);
|
|
479
486
|
const labelOutlineKeyMats = model.openGLCamera.getKeyMatrices(ren);
|
|
480
487
|
|
|
@@ -583,7 +590,10 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
583
590
|
resizable: true
|
|
584
591
|
});
|
|
585
592
|
model.colorTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
586
|
-
|
|
593
|
+
let cWidth = model.renderable.getColorTextureWidth();
|
|
594
|
+
if (cWidth <= 0) {
|
|
595
|
+
cWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
|
|
596
|
+
}
|
|
587
597
|
const cSize = cWidth * textureHeight * 3;
|
|
588
598
|
const cTable = new Uint8ClampedArray(cSize);
|
|
589
599
|
// set interpolation on the texture based on property setting
|
|
@@ -646,7 +656,10 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
646
656
|
// rebuild opacity tfun?
|
|
647
657
|
const reBuildPwf = !pwfTex?.oglObject?.getHandle() || pwfTex?.hash !== pwfunToString;
|
|
648
658
|
if (reBuildPwf) {
|
|
649
|
-
|
|
659
|
+
let pwfWidth = model.renderable.getOpacityTextureWidth();
|
|
660
|
+
if (pwfWidth <= 0) {
|
|
661
|
+
pwfWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
|
|
662
|
+
}
|
|
650
663
|
const pwfSize = pwfWidth * textureHeight;
|
|
651
664
|
const pwfTable = new Uint8ClampedArray(pwfSize);
|
|
652
665
|
model.pwfTexture = vtkOpenGLTexture.newInstance({
|
|
@@ -856,10 +869,25 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
856
869
|
vtkErrorMacro('Reformat slicing not yet supported.');
|
|
857
870
|
}
|
|
858
871
|
|
|
872
|
+
/**
|
|
873
|
+
*
|
|
874
|
+
* Fetch the ranges of the source volume, `imgScalars`, and use them when
|
|
875
|
+
* creating the texture. Whilst the pre-calculated ranges may not be
|
|
876
|
+
* strictly correct for the slice, it is guaranteed to be within the
|
|
877
|
+
* source volume's range.
|
|
878
|
+
*
|
|
879
|
+
* There is a significant performance improvement by pre-setting the range
|
|
880
|
+
* of the scalars array particularly when scrolling through the source
|
|
881
|
+
* volume as there is no need to calculate the range of the slice scalar.
|
|
882
|
+
*
|
|
883
|
+
* @type{ import("../../../interfaces").vtkRange[] }
|
|
884
|
+
*/
|
|
885
|
+
const ranges = imgScalars.getRanges();
|
|
886
|
+
|
|
859
887
|
// Don't share this resource as `scalars` is created in this function
|
|
860
888
|
// so it is impossible to share
|
|
861
889
|
model.openGLTexture.resetFormatAndType();
|
|
862
|
-
model.openGLTexture.create2DFilterableFromRaw(dims[0], dims[1], numComp, imgScalars.getDataType(), scalars, model.renderable.getPreferSizeOverAccuracy?.());
|
|
890
|
+
model.openGLTexture.create2DFilterableFromRaw(dims[0], dims[1], numComp, imgScalars.getDataType(), scalars, model.renderable.getPreferSizeOverAccuracy?.(), ranges);
|
|
863
891
|
model.openGLTexture.activate();
|
|
864
892
|
model.openGLTexture.sendParameters();
|
|
865
893
|
model.openGLTexture.deactivate();
|
|
@@ -896,7 +924,7 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
896
924
|
}
|
|
897
925
|
};
|
|
898
926
|
publicAPI.updatelabelOutlineThicknessTexture = image => {
|
|
899
|
-
const labelOutlineThicknessArray = image.getProperty().
|
|
927
|
+
const labelOutlineThicknessArray = image.getProperty().getLabelOutlineThicknessByReference();
|
|
900
928
|
const lTex = model._openGLRenderWindow.getGraphicsResourceForObject(labelOutlineThicknessArray);
|
|
901
929
|
|
|
902
930
|
// compute the join of the labelOutlineThicknessArray so that
|
|
@@ -905,7 +933,10 @@ function vtkOpenGLImageMapper(publicAPI, model) {
|
|
|
905
933
|
const toString = `${labelOutlineThicknessArray.join('-')}`;
|
|
906
934
|
const reBuildL = !lTex?.oglObject?.getHandle() || lTex?.hash !== toString;
|
|
907
935
|
if (reBuildL) {
|
|
908
|
-
|
|
936
|
+
let lWidth = model.renderable.getLabelOutlineTextureWidth();
|
|
937
|
+
if (lWidth <= 0) {
|
|
938
|
+
lWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
|
|
939
|
+
}
|
|
909
940
|
const lHeight = 1;
|
|
910
941
|
const lSize = lWidth * lHeight;
|
|
911
942
|
const lTable = new Uint8Array(lSize);
|
|
@@ -245,6 +245,7 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
245
245
|
return model.VBOBuildTime.getMTime() < imageData.getMTime();
|
|
246
246
|
}) || model.VBOBuildTime.getMTime() < model.resliceGeom.getMTime() || model.scalarTextures.length !== model.currentValidInputs.length || !model.scalarTextures.every(texture => !!texture?.getHandle()) || !model.colorTexture?.getHandle() || !model.pwfTexture?.getHandle();
|
|
247
247
|
publicAPI.buildBufferObjects = (ren, actor) => {
|
|
248
|
+
const actorProperties = actor.getProperties();
|
|
248
249
|
model.currentValidInputs.forEach((_ref3, component) => {
|
|
249
250
|
let {
|
|
250
251
|
imageData
|
|
@@ -254,7 +255,10 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
254
255
|
const tex = model._openGLRenderWindow.getGraphicsResourceForObject(scalars);
|
|
255
256
|
const scalarsHash = getImageDataHash(imageData, scalars);
|
|
256
257
|
const reBuildTex = !tex?.oglObject?.getHandle() || tex?.hash !== scalarsHash;
|
|
257
|
-
|
|
258
|
+
const actorProperty = actorProperties[component];
|
|
259
|
+
const updatedExtents = actorProperty.getUpdatedExtents();
|
|
260
|
+
const hasUpdatedExtents = !!updatedExtents.length;
|
|
261
|
+
if (reBuildTex && !hasUpdatedExtents) {
|
|
258
262
|
const newScalarTexture = vtkOpenGLTexture.newInstance();
|
|
259
263
|
newScalarTexture.setOpenGLRenderWindow(model._openGLRenderWindow);
|
|
260
264
|
// Build the textures
|
|
@@ -268,11 +272,17 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
268
272
|
} else {
|
|
269
273
|
model.scalarTextures[component] = tex.oglObject;
|
|
270
274
|
}
|
|
275
|
+
if (hasUpdatedExtents) {
|
|
276
|
+
// If hasUpdatedExtents, then the texture is partially updated.
|
|
277
|
+
// clear the array to acknowledge the update.
|
|
278
|
+
actorProperty.setUpdatedExtents([]);
|
|
279
|
+
const dims = imageData.getDimensions();
|
|
280
|
+
model.scalarTextures[component].create3DFilterableFromDataArray(dims[0], dims[1], dims[2], scalars, false, updatedExtents);
|
|
281
|
+
}
|
|
271
282
|
replaceGraphicsResource(model._openGLRenderWindow, model._scalarTexturesCore[component], scalars);
|
|
272
283
|
model._scalarTexturesCore[component] = scalars;
|
|
273
284
|
});
|
|
274
285
|
const firstValidInput = model.currentValidInputs[0];
|
|
275
|
-
const actorProperties = actor.getProperties();
|
|
276
286
|
const firstActorProperty = actorProperties[firstValidInput.inputIndex];
|
|
277
287
|
const iComps = firstActorProperty.getIndependentComponents();
|
|
278
288
|
const numIComps = iComps ? model.numberOfComponents : 1;
|
|
@@ -286,7 +296,10 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
286
296
|
const cTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstColorTransferFunc);
|
|
287
297
|
const reBuildC = !cTex?.oglObject?.getHandle() || cTex?.hash !== colorFuncHash;
|
|
288
298
|
if (reBuildC) {
|
|
289
|
-
|
|
299
|
+
let cWidth = model.renderable.getColorTextureWidth();
|
|
300
|
+
if (cWidth <= 0) {
|
|
301
|
+
cWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
|
|
302
|
+
}
|
|
290
303
|
const cSize = cWidth * textureHeight * 3;
|
|
291
304
|
const cTable = new Uint8ClampedArray(cSize);
|
|
292
305
|
const newColorTexture = vtkOpenGLTexture.newInstance();
|
|
@@ -345,7 +358,10 @@ function vtkOpenGLImageResliceMapper(publicAPI, model) {
|
|
|
345
358
|
const pwfTex = model._openGLRenderWindow.getGraphicsResourceForObject(firstPwFunc);
|
|
346
359
|
const reBuildPwf = !pwfTex?.oglObject?.getHandle() || pwfTex?.hash !== opacityFuncHash;
|
|
347
360
|
if (reBuildPwf) {
|
|
348
|
-
|
|
361
|
+
let pwfWidth = model.renderable.getOpacityTextureWidth();
|
|
362
|
+
if (pwfWidth <= 0) {
|
|
363
|
+
pwfWidth = model.context.getParameter(model.context.MAX_TEXTURE_SIZE);
|
|
364
|
+
}
|
|
349
365
|
const pwfSize = pwfWidth * textureHeight;
|
|
350
366
|
const pwfTable = new Uint8ClampedArray(pwfSize);
|
|
351
367
|
const newOpacityTexture = vtkOpenGLTexture.newInstance();
|
|
@@ -24,7 +24,7 @@ function vtkOpenGLRenderer(publicAPI, model) {
|
|
|
24
24
|
publicAPI.updateLights();
|
|
25
25
|
publicAPI.prepareNodes();
|
|
26
26
|
publicAPI.addMissingNode(model.renderable.getActiveCamera());
|
|
27
|
-
publicAPI.addMissingNodes(model.renderable.getViewPropsWithNestedProps());
|
|
27
|
+
publicAPI.addMissingNodes(model.renderable.getViewPropsWithNestedProps(), true);
|
|
28
28
|
publicAPI.removeUnusedNodes();
|
|
29
29
|
}
|
|
30
30
|
};
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Even when the EXT_texture_norm16 extension is present, linear filtering
|
|
3
|
+
* might not be supported for normalized fixed point textures.
|
|
4
|
+
*
|
|
5
|
+
* This is a driver bug. See https://github.com/KhronosGroup/WebGL/issues/3706
|
|
6
|
+
* @return {boolean}
|
|
7
|
+
*/
|
|
8
|
+
function supportsNorm16Linear() {
|
|
9
|
+
try {
|
|
10
|
+
const canvasSize = 4;
|
|
11
|
+
const texWidth = 2;
|
|
12
|
+
const texHeight = 1;
|
|
13
|
+
const texData = new Int16Array([0, 2 ** 15 - 1]);
|
|
14
|
+
const pixelToCheck = [1, 1];
|
|
15
|
+
const canvas = document.createElement('canvas');
|
|
16
|
+
canvas.width = canvasSize;
|
|
17
|
+
canvas.height = canvasSize;
|
|
18
|
+
const gl = canvas.getContext('webgl2');
|
|
19
|
+
if (!gl) {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
const ext = gl.getExtension('EXT_texture_norm16');
|
|
23
|
+
if (!ext) {
|
|
24
|
+
return false;
|
|
25
|
+
}
|
|
26
|
+
const vs = `#version 300 es
|
|
27
|
+
void main() {
|
|
28
|
+
gl_PointSize = ${canvasSize.toFixed(1)};
|
|
29
|
+
gl_Position = vec4(0, 0, 0, 1);
|
|
30
|
+
}
|
|
31
|
+
`;
|
|
32
|
+
const fs = `#version 300 es
|
|
33
|
+
precision highp float;
|
|
34
|
+
precision highp int;
|
|
35
|
+
precision highp sampler2D;
|
|
36
|
+
|
|
37
|
+
uniform sampler2D u_image;
|
|
38
|
+
|
|
39
|
+
out vec4 color;
|
|
40
|
+
|
|
41
|
+
void main() {
|
|
42
|
+
vec4 intColor = texture(u_image, gl_PointCoord.xy);
|
|
43
|
+
color = vec4(vec3(intColor.rrr), 1);
|
|
44
|
+
}
|
|
45
|
+
`;
|
|
46
|
+
const vertexShader = gl.createShader(gl.VERTEX_SHADER);
|
|
47
|
+
gl.shaderSource(vertexShader, vs);
|
|
48
|
+
gl.compileShader(vertexShader);
|
|
49
|
+
if (!gl.getShaderParameter(vertexShader, gl.COMPILE_STATUS)) {
|
|
50
|
+
return false;
|
|
51
|
+
}
|
|
52
|
+
const fragmentShader = gl.createShader(gl.FRAGMENT_SHADER);
|
|
53
|
+
gl.shaderSource(fragmentShader, fs);
|
|
54
|
+
gl.compileShader(fragmentShader);
|
|
55
|
+
if (!gl.getShaderParameter(fragmentShader, gl.COMPILE_STATUS)) {
|
|
56
|
+
return false;
|
|
57
|
+
}
|
|
58
|
+
const program = gl.createProgram();
|
|
59
|
+
gl.attachShader(program, vertexShader);
|
|
60
|
+
gl.attachShader(program, fragmentShader);
|
|
61
|
+
gl.linkProgram(program);
|
|
62
|
+
if (!gl.getProgramParameter(program, gl.LINK_STATUS)) {
|
|
63
|
+
return false;
|
|
64
|
+
}
|
|
65
|
+
const tex = gl.createTexture();
|
|
66
|
+
gl.bindTexture(gl.TEXTURE_2D, tex);
|
|
67
|
+
gl.texImage2D(gl.TEXTURE_2D, 0, ext.R16_SNORM_EXT, texWidth, texHeight, 0, gl.RED, gl.SHORT, texData);
|
|
68
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
|
|
69
|
+
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
|
|
70
|
+
gl.useProgram(program);
|
|
71
|
+
gl.drawArrays(gl.POINTS, 0, 1);
|
|
72
|
+
const pixel = new Uint8Array(4);
|
|
73
|
+
gl.readPixels(pixelToCheck[0], pixelToCheck[1], 1, 1, gl.RGBA, gl.UNSIGNED_BYTE, pixel);
|
|
74
|
+
const [r, g, b] = pixel;
|
|
75
|
+
const webglLoseContext = gl.getExtension('WEBGL_lose_context');
|
|
76
|
+
if (webglLoseContext) {
|
|
77
|
+
webglLoseContext.loseContext();
|
|
78
|
+
}
|
|
79
|
+
return r === g && g === b && r !== 0;
|
|
80
|
+
} catch (e) {
|
|
81
|
+
return false;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
/**
|
|
86
|
+
* @type {boolean | undefined}
|
|
87
|
+
*/
|
|
88
|
+
let supportsNorm16LinearCache;
|
|
89
|
+
function supportsNorm16LinearCached() {
|
|
90
|
+
// Only create a canvas+texture+shaders the first time
|
|
91
|
+
if (supportsNorm16LinearCache === undefined) {
|
|
92
|
+
supportsNorm16LinearCache = supportsNorm16Linear();
|
|
93
|
+
}
|
|
94
|
+
return supportsNorm16LinearCache;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export { supportsNorm16LinearCached as default };
|