Skip to content

refactor(OpenGL/Texture): use named parameters #3224

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 40 commits into
base: beta
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
40 commits
Select commit Hold shift + click to select a range
7d4c58f
perf: pre-set range of ImageMapper scalars to improve performance
jmannau Jan 19, 2025
47e308e
docs: Update JSDoc with optional arguments
jmannau Feb 18, 2025
8c6f597
docs: fix typo and update comment based on PR review
jmannau Feb 18, 2025
934916d
style: run `npm run reformat`
jmannau Feb 19, 2025
46f2bb2
docs: Update comment and fix typo
jmannau Feb 21, 2025
d58e0ab
style: eslint fix
jmannau Feb 21, 2025
27b5574
refactor: add getRanges function DataArray public api
jmannau Feb 22, 2025
a594e19
docs: Updated rages arg comment as per PR review
jmannau Feb 22, 2025
c6a52ba
refactor: Updated ImageMapper to set range regardless of sliceMode
jmannau Feb 23, 2025
ac8f207
docs: typo
jmannau Mar 6, 2025
f9aafc5
docs: Add DataArray.getRanges documentation
jmannau Mar 6, 2025
1618a20
fix(DataArray): update getRanges
jmannau Mar 6, 2025
0c948b0
feat(DataArray): copy ranges in DataArray.deepCopy
jmannau Mar 6, 2025
0973512
fix(DataArray): fix typescript getRanges arg type
jmannau Mar 7, 2025
1cb7040
fix(DataArray): PR review fixes
jmannau Mar 7, 2025
56e04ea
test(DataArray): Update DataArray.getRanges tests to remove need for …
jmannau Mar 9, 2025
8c75878
revert(DataArray): revert unneeded change
jmannau Mar 9, 2025
79a15c7
feat: add ranges to create3DFilterableFromRaw
jmannau Mar 10, 2025
572c38d
fix(dataarray): clone ranges in DataArray.deepCopy
jmannau Mar 12, 2025
d7715a9
docs(imagemapper): fix spelling error
jmannau Mar 12, 2025
844edca
docs(dataarray): update getRanges description to include details on m…
jmannau Mar 12, 2025
307ce44
fix(webxr): remove controllers rays when stopping XR
munozco Feb 18, 2025
0f13c25
feat(OpenGL/Texture): update sub-image extents
floryst Mar 14, 2025
efbaa80
chore: only run patch-package for build targets
floryst Mar 14, 2025
5193998
fix(AbstractPicker): model.pickFromList type is boolean
PaulHax Mar 11, 2025
22b4dce
fix(index.d.ts): fix getPixelWorldHeightAtCoord missing parameter
QQBoxy Mar 27, 2025
575d628
fix(camerasynchronizer): fix src/dest renderer changed listeners regi…
bourdaisj Feb 14, 2025
2580459
fix(actor2d): add setters and getters for actor2D layer number
sankhesh Jan 31, 2025
a78800e
style: keep the pass name and traversal together
sankhesh Jan 31, 2025
c45a809
feat(actor2d): overlay 2D actors in the order of their layer number
sankhesh Jan 31, 2025
a85de03
docs(actor2d): add typescript definitions for [set/get]LayerNumber in…
sankhesh Jan 31, 2025
7cd3f35
test(actor2d): testing for vtkActor2D layer number
sankhesh Jan 31, 2025
bdad677
fix(actor2d): ensure that the actor2D instances are re-sorted each frame
sankhesh Feb 4, 2025
0296cfe
fix(viewnode): add optional ability to maintain node ordering
sankhesh Mar 21, 2025
c510277
feat(mappers): set opacity/color/label tex widths
floryst Apr 4, 2025
d15d50f
fix(mapper): add docs and support max texture size
floryst Apr 8, 2025
e735988
Merge branch 'master' into beta
floryst Apr 18, 2025
19500bd
refactor: move the updatedExtent API to properties
floryst Apr 18, 2025
eab8556
refactor(OpenGL/Texture): use named parameters
floryst Feb 25, 2025
281b5a6
docs(BREAKING_CHANGES): add v33 breaking changes
floryst Feb 27, 2025
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions BREAKING_CHANGES.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
## From 32.x to 33

- **vtkMapper**: many properties have moved to `vtkVolumeProperty`. The full list of changed methods is: `getAnisotropy`, `getComputeNormalFromOpacity`, `getFilterMode`, `getFilterModeAsString`, `getGlobalIlluminationReach`, `getIpScalarRange`, `getIpScalarRangeByReference`, `getLAOKernelRadius`, `getLAOKernelSize`, `getLocalAmbientOcclusion`, `getPreferSizeOverAccuracy`, `getVolumetricScatteringBlending`, `setAnisotropy`, `setAverageIPScalarRange`, `setComputeNormalFromOpacity`, `setFilterMode`, `setFilterModeToNormalized`, `setFilterModeToOff`, `setFilterModeToRaw`, `setGlobalIlluminationReach`, `setIpScalarRange`, `setIpScalarRangeFrom`, `setLAOKernelRadius`, `setLAOKernelSize`, `setLocalAmbientOcclusion`, `setPreferSizeOverAccuracy`, `setVolumetricScatteringBlending`.
- **vtkOpenGLTexture**: The public `create2D*` and `create3D*` methods used to have positional parameters. These methods now use named parameters via passing in an object record.

## From 31.x to 32

- **vtkMapper**: remove `mapScalarsToTexture` from the public API. The function becomes protected and its API changes. This shouldn't cause any issue in most cases.
Expand Down
17 changes: 17 additions & 0 deletions Sources/Common/Core/DataArray/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,23 @@ export interface vtkDataArray extends vtkObject {
*/
setRange(rangeValue: vtkRange, componentIndex: number): Range;

/**
* Returns an array of the ranges for each component of the DataArray.
* Defaults to computing all the ranges if they aren't already computed.
*
* If the number of components is greater than 1, the last element in the
* ranges array is the min,max magnitude of the dataset. This is the same as
* calling `getRange(-1)`.
*
* Passing `getRanges(false)` will return a clone of the ranges that have
* already been computed. This is useful when you want to avoid recomputing
* the ranges, which can be expensive.
*
* @param {boolean} [computeRanges] (default: true)
* @returns {vtkRange[]}
*/
getRanges(computeRanges: boolean): vtkRange[];

/**
* Set the given tuple at the given index.
* @param {Number} idx
Expand Down
35 changes: 35 additions & 0 deletions Sources/Common/Core/DataArray/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,35 @@ function vtkDataArray(publicAPI, model) {
return model.rangeTuple;
};

publicAPI.getRanges = (computeRanges = true) => {
if (!computeRanges) {
return structuredClone(model.ranges);
}
/** @type {import('../../../interfaces').vtkRange[]} */
const ranges = [];
for (let i = 0; i < model.numberOfComponents; i++) {
const [min, max] = publicAPI.getRange(i);
/** @type {import('../../../interfaces').vtkRange} */
const range = {
min,
max,
};
ranges.push(range);
}
// where the number of components is greater than 1, the last element in
// the range array is the min,max magnitude of the entire dataset.
if (model.numberOfComponents > 1) {
const [min, max] = publicAPI.getRange(-1);
/** @type {import('../../../interfaces').vtkRange} */
const range = {
min,
max,
};
ranges.push(range);
}
return ranges;
};

publicAPI.setTuple = (idx, tuple) => {
const offset = idx * model.numberOfComponents;
for (let i = 0; i < model.numberOfComponents; i++) {
Expand Down Expand Up @@ -447,12 +476,18 @@ function vtkDataArray(publicAPI, model) {
return sortedObj;
};

/**
* @param {import("./index").vtkDataArray} other
*/
publicAPI.deepCopy = (other) => {
// Retain current dataType and array reference before shallowCopy call.
const currentType = publicAPI.getDataType();
const currentArray = model.values;
publicAPI.shallowCopy(other);

// set the ranges
model.ranges = structuredClone(other.getRanges());

// Avoid array reallocation if size already sufficient
// and dataTypes match.
if (
Expand Down
122 changes: 122 additions & 0 deletions Sources/Common/Core/DataArray/test/testDataArray.js
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,36 @@ test('Test vtkDataArray getRange function with NaN values.', (t) => {
t.end();
});

test('Test vtkDataArray getRanges function with single-channel data.', (t) => {
// create a data array with a single channel.
const newArray = new Uint16Array(256 * 3);

// fill the new array with the pattern 0,1,2,3,4,5, ..., 767.
for (let i = 0; i < 256 * 3; ++i) {
newArray[i] = i;
}

const da = vtkDataArray.newInstance({
numberOfComponents: 1,
values: newArray,
});

t.ok(
da.getRanges().length === 1,
'getRanges should return an array of 1 vtkRange objects'
);
t.ok(
da.getRanges()[0].min === 0,
'the first component returned by getRanges minimum value should be 0'
);
t.ok(
da.getRanges()[0].max === 767,
'the first component returned by getRanges maximum value should be 767'
);

t.end();
});

test('Test vtkDataArray getTuple', (t) => {
const da = vtkDataArray.newInstance({
numberOfComponents: 3,
Expand Down Expand Up @@ -202,6 +232,98 @@ test('Test vtkDataArray getRange function with multi-channel data.', (t) => {
t.end();
});

test('Test vtkDataArray getRanges function with multi-channel data.', (t) => {
// create a data array with 3 channel data.
const numberOfPixels = 10;
const numberOfComponents = 4;
const newArray = new Uint16Array(numberOfPixels * numberOfComponents);

// fill the new array with the pattern 1,2,3, 1,2,3
// such that each channel has 1,1,1 2,2,2 3,3,3 respectively.
for (let i = 0; i < numberOfPixels; ++i) {
newArray[i * numberOfComponents] = i;
newArray[i * numberOfComponents + 1] = i * 2;
newArray[i * numberOfComponents + 2] = i * 3;
newArray[i * numberOfComponents + 3] = i * 4;
}

const da = vtkDataArray.newInstance({
numberOfComponents,
values: newArray,
});

const ranges = da.getRanges();

t.ok(
ranges.length === numberOfComponents + 1,
'getRanges should return an array of 5 vtkRange objects'
);
t.ok(ranges[0].min === 0, 'component:0 minimum value should be 0');
t.ok(ranges[0].max === 9, 'component:0 maximum value should be 9');
t.ok(ranges[1].min === 0, 'component:1 minimum value should be 0');
t.ok(ranges[1].max === 18, 'component:1 maximum value should be 18');
t.ok(ranges[2].min === 0, 'component:2 minimum value should be 0');
t.ok(ranges[2].max === 27, 'component:2 maximum value should be 27 ');
t.ok(
ranges[2].min === 0,
'component:-1 vector magnitude minimum should be 0'
);
t.ok(
ranges[3].max === 36,
'component:-1 vector magnitude maximum should be 36'
);

t.end();
});

test('Test vtkDataArray getRanges(false) (`computeRanges=false`) function with multi-channel data', (t) => {
// create a data array with 3 channel data.
const numberOfPixels = 10;
const numberOfComponents = 4;
const newArray = new Uint16Array(numberOfPixels * numberOfComponents);

// fill the new array with the pattern 1,2,3, 1,2,3
// such that each channel has 1,1,1 2,2,2 3,3,3 respectively.
for (let i = 0; i < numberOfPixels; ++i) {
newArray[i * numberOfComponents] = i;
newArray[i * numberOfComponents + 1] = i * 2;
newArray[i * numberOfComponents + 2] = i * 3;
newArray[i * numberOfComponents + 3] = i * 4;
}

const da = vtkDataArray.newInstance({
numberOfComponents,
values: newArray,
});

// set `computeRanges` to false. This will prevent the ranges from being
// computed and will return only the ranges previously computer (if any).
const ranges = da.getRanges(false);

t.ok(ranges === undefined, `getRanges should return undefined`);

// now fetch the range for component 0.
da.getRange(0);

// now fetch the ranges again with `computeRanges` set to false.
const updatedRanges = da.getRanges(false);

// `updatedRanges` should now be only the range for component 0. because if
// was computed in `da.getRange(0)`
t.ok(
updatedRanges.length === numberOfComponents + 1,
'getRanges should return an array of 5 vtkRange objects'
);
t.ok(updatedRanges[0].min === 0, 'component:0 minimum value should be 0');
t.ok(updatedRanges[0].max === 9, 'component:0 maximum value should be 9');
t.ok(updatedRanges[1] === null, 'component:1 should be null');
t.ok(updatedRanges[2] === null, 'component:2 should be null');
t.ok(updatedRanges[3] === null, 'component:3 should be null');
t.ok(updatedRanges[4] === null, 'component:-1 should be null');

t.end();
});

test('Test vtkDataArray insertNextTuple', (t) => {
const dataArray = vtkDataArray.newInstance({
dataType: VtkDataTypes.UNSIGNED_CHAR,
Expand Down
81 changes: 81 additions & 0 deletions Sources/Rendering/Core/AbstractImageMapper/index.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,87 @@ export interface vtkAbstractImageMapper extends vtkAbstractMapper3D {
* @param customDisplayExtent
*/
setCustomDisplayExtentFrom(customDisplayExtent: number[]): boolean;

/**
* Set the opacity texture width.
*
* The default width (1024) should be fine in most instances.
* Only set this property if your opacity function range width is
* larger than 1024.
*
* A reasonable max texture size would be either 2048 or 4096, as those
* widths are supported by the vast majority of devices. Any width larger
* than that will have issues with device support.
*
* Specifying a width that is less than or equal to 0 will use the largest
* possible texture width on the device. Use this with caution! The max texture
* width of one device may not be the same for another device.
*
* You can find more information about supported texture widths at the following link:
* https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE
*
* @param {Number} width the texture width (defaults to 1024)
*/
setOpacityTextureWidth(width: number): boolean;

/**
* Get the opacity texture width.
*/
getOpacityTextureWidth(): number;

/**
* Set the color texture width.
*
* The default width (1024) should be fine in most instances.
* Only set this property if your color transfer function range width is
* larger than 1024.
*
* A reasonable max texture size would be either 2048 or 4096, as those
* widths are supported by the vast majority of devices. Any width larger
* than that will have issues with device support.
*
* Specifying a width that is less than or equal to 0 will use the largest
* possible texture width on the device. Use this with caution! The max texture
* width of one device may not be the same for another device.
*
* You can find more information about supported texture widths at the following link:
* https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE
*
* @param {Number} width the texture width (defaults to 1024)
*/
setColorTextureWidth(width: number): boolean;

/**
* Get the color texture width.
*/
getColorTextureWidth(): number;

/**
* Set the label outline texture width.
*
* The default width (1024) should be fine in most instances.
* Only set this property if you have more than 1024 labels
* that you want to render with thickness.
*
* A reasonable max texture size would be either 2048 or 4096, as those
* widths are supported by the vast majority of devices. Any width larger
* than that will have issues with device support.
*
* Specifying a width that is less than or equal to 0 will use the largest
* possible texture width on the device. Use this with caution! The max texture
* width of one device may not be the same for another device.
*
* You can find more information about supported texture widths at the following link:
* https://web3dsurvey.com/webgl/parameters/MAX_TEXTURE_SIZE
*
* @param {Number} width the texture width (defaults to 1024)
*/
setLabelOutlineTextureWidth(width: number): boolean;

/**
* Get the label outline texture width.
*/
getLabelOutlineTextureWidth(): number;
}

/**
Expand Down
11 changes: 10 additions & 1 deletion Sources/Rendering/Core/AbstractImageMapper/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,9 @@ const DEFAULT_VALUES = {
customDisplayExtent: [0, 0, 0, 0, 0, 0],
useCustomExtents: false,
backgroundColor: [0, 0, 0, 1],
colorTextureWidth: 1024,
opacityTextureWidth: 1024,
labelOutlineTextureWidth: 1024,
};

// ----------------------------------------------------------------------------
Expand All @@ -40,7 +43,13 @@ export function extend(publicAPI, model, initialValues = {}) {
// Build VTK API
vtkAbstractMapper3D.extend(publicAPI, model, initialValues);

macro.setGet(publicAPI, model, ['slice', 'useCustomExtents']);
macro.setGet(publicAPI, model, [
'slice',
'useCustomExtents',
'colorTextureWidth',
'opacityTextureWidth',
'labelOutlineTextureWidth',
]);
macro.setGetArray(publicAPI, model, ['customDisplayExtent'], 6);
macro.setGetArray(publicAPI, model, ['backgroundColor'], 4);

Expand Down
Loading
Loading