UNPKG

@kitware/vtk.js

Version:

Visualization Toolkit for the Web

249 lines (229 loc) 7.42 kB
import { m as macro } from '../../macros2.js'; // ---------------------------------------------------------------------------- // vtkTexture methods // ---------------------------------------------------------------------------- function vtkTexture(publicAPI, model) { // Set our className model.classHierarchy.push('vtkTexture'); publicAPI.imageLoaded = () => { model.image.removeEventListener('load', publicAPI.imageLoaded); model.imageLoaded = true; publicAPI.modified(); }; publicAPI.setJsImageData = imageData => { if (model.jsImageData === imageData) { return; } // clear other entries if (imageData !== null) { publicAPI.setInputData(null); publicAPI.setInputConnection(null); model.image = null; model.canvas = null; } model.jsImageData = imageData; model.imageLoaded = true; publicAPI.modified(); }; publicAPI.setCanvas = canvas => { if (model.canvas === canvas) { return; } // clear other entries if (canvas !== null) { publicAPI.setInputData(null); publicAPI.setInputConnection(null); model.image = null; model.jsImageData = null; } model.canvas = canvas; publicAPI.modified(); }; publicAPI.setImage = image => { if (model.image === image) { return; } // clear other entries if (image !== null) { publicAPI.setInputData(null); publicAPI.setInputConnection(null); model.canvas = null; model.jsImageData = null; } model.image = image; model.imageLoaded = false; if (image.complete) { publicAPI.imageLoaded(); } else { image.addEventListener('load', publicAPI.imageLoaded); } publicAPI.modified(); }; publicAPI.getDimensionality = () => { let width = 0; let height = 0; let depth = 1; if (publicAPI.getInputData()) { const data = publicAPI.getInputData(); width = data.getDimensions()[0]; height = data.getDimensions()[1]; depth = data.getDimensions()[2]; } if (model.jsImageData) { width = model.jsImageData.width; height = model.jsImageData.height; } if (model.canvas) { width = model.canvas.width; height = model.canvas.height; } if (model.image) { width = model.image.width; height = model.image.height; } const dimensionality = (width > 1) + (height > 1) + (depth > 1); return dimensionality; }; publicAPI.getInputAsJsImageData = () => { if (!model.imageLoaded || publicAPI.getInputData()) return null; if (model.jsImageData) { return model.jsImageData(); } if (model.canvas) { const context = model.canvas.getContext('2d'); const imageData = context.getImageData(0, 0, model.canvas.width, model.canvas.height); return imageData; } if (model.image) { const canvas = document.createElement('canvas'); canvas.width = model.image.width; canvas.height = model.image.height; const context = canvas.getContext('2d'); context.translate(0, canvas.height); context.scale(1, -1); context.drawImage(model.image, 0, 0, model.image.width, model.image.height); const imageData = context.getImageData(0, 0, canvas.width, canvas.height); return imageData; } return null; }; } // Use nativeArray instead of self const generateMipmaps = (nativeArray, width, height, level) => { // TODO: FIX UNEVEN TEXTURE MIP GENERATION: // When textures don't have standard ratios, higher mip levels // result in their color chanels getting messed up and shifting // 3x3 gaussian kernel const g3m = [1, 2, 1]; // eslint-disable-line const g3w = 4; // eslint-disable-line const kernel = g3m; const kernelWeight = g3w; const hs = nativeArray.length / (width * height); // TODO: support for textures with depth more than 1 let currentWidth = width; let currentHeight = height; let imageData = nativeArray; const maps = [imageData]; for (let i = 0; i < level; i++) { const oldData = [...imageData]; currentWidth /= 2; currentHeight /= 2; imageData = new Uint8ClampedArray(currentWidth * currentHeight * hs); const vs = hs * currentWidth; // Scale down let shift = 0; for (let p = 0; p < imageData.length; p += hs) { if (p % vs === 0) { shift += 2 * hs * currentWidth; } for (let c = 0; c < hs; c++) { let sample = oldData[shift + c]; sample += oldData[shift + hs + c]; sample += oldData[shift - 2 * vs + c]; sample += oldData[shift - 2 * vs + hs + c]; sample /= 4; imageData[p + c] = sample; } shift += 2 * hs; } // Horizontal Pass let dataCopy = [...imageData]; for (let p = 0; p < imageData.length; p += hs) { for (let c = 0; c < hs; c++) { let x = -(kernel.length - 1) / 2; let kw = kernelWeight; let value = 0.0; for (let k = 0; k < kernel.length; k++) { let index = p + c + x * hs; const lineShift = index % vs - (p + c) % vs; if (lineShift > hs) index += vs; if (lineShift < -hs) index -= vs; if (dataCopy[index]) { value += dataCopy[index] * kernel[k]; } else { kw -= kernel[k]; } x += 1; } imageData[p + c] = value / kw; } } // Vertical Pass dataCopy = [...imageData]; for (let p = 0; p < imageData.length; p += hs) { for (let c = 0; c < hs; c++) { let x = -(kernel.length - 1) / 2; let kw = kernelWeight; let value = 0.0; for (let k = 0; k < kernel.length; k++) { const index = p + c + x * vs; if (dataCopy[index]) { value += dataCopy[index] * kernel[k]; } else { kw -= kernel[k]; } x += 1; } imageData[p + c] = value / kw; } } maps.push(imageData); } return maps; }; // ---------------------------------------------------------------------------- // Object factory // ---------------------------------------------------------------------------- const DEFAULT_VALUES = { image: null, canvas: null, jsImageData: null, imageLoaded: false, repeat: false, interpolate: false, edgeClamp: false, mipLevel: 0, resizable: false // must be set at construction time if the texture can be resizable }; // ---------------------------------------------------------------------------- function extend(publicAPI, model) { let initialValues = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : {}; Object.assign(model, DEFAULT_VALUES, initialValues); // Build VTK API macro.obj(publicAPI, model); macro.algo(publicAPI, model, 6, 0); macro.get(publicAPI, model, ['canvas', 'image', 'jsImageData', 'imageLoaded', 'resizable']); macro.setGet(publicAPI, model, ['repeat', 'edgeClamp', 'interpolate', 'mipLevel']); vtkTexture(publicAPI, model); } // ---------------------------------------------------------------------------- const newInstance = macro.newInstance(extend, 'vtkTexture'); const STATIC = { generateMipmaps }; // ---------------------------------------------------------------------------- var vtkTexture$1 = { newInstance, extend, ...STATIC }; export { STATIC, vtkTexture$1 as default, extend, newInstance };