hefeihvac_java/node_modules/echarts-gl/lib/util/graphicGL.js

684 lines
19 KiB
JavaScript
Raw Permalink Normal View History

2024-04-07 18:15:00 +08:00
import Mesh from 'claygl/src/Mesh';
import Renderer from 'claygl/src/Renderer';
import Texture2D from 'claygl/src/Texture2D';
import Texture from 'claygl/src/Texture';
import Shader from 'claygl/src/Shader';
import Material from 'claygl/src/Material';
import Node3D from 'claygl/src/Node';
import Geometry from 'claygl/src/Geometry';
import * as echarts from 'echarts/lib/echarts';
import Scene from 'claygl/src/Scene';
import LRUCache from 'zrender/lib/core/LRU';
import textureUtil from 'claygl/src/util/texture';
import EChartsSurface from './EChartsSurface';
import AmbientCubemapLight from 'claygl/src/light/AmbientCubemap';
import AmbientSHLight from 'claygl/src/light/AmbientSH';
import shUtil from 'claygl/src/util/sh';
import retrieve from './retrieve';
import SphereGeometry from 'claygl/src/geometry/Sphere';
import PlaneGeometry from 'claygl/src/geometry/Plane';
import CubeGeometry from 'claygl/src/geometry/Cube';
import AmbientLight from 'claygl/src/light/Ambient';
import DirectionalLight from 'claygl/src/light/Directional';
import PointLight from 'claygl/src/light/Point';
import SpotLight from 'claygl/src/light/Spot';
import PerspectiveCamera from 'claygl/src/camera/Perspective';
import OrthographicCamera from 'claygl/src/camera/Orthographic'; // Math
import Vector2 from 'claygl/src/math/Vector2';
import Vector3 from 'claygl/src/math/Vector3';
import Vector4 from 'claygl/src/math/Vector4';
import Quaternion from 'claygl/src/math/Quaternion';
import Matrix2 from 'claygl/src/math/Matrix2';
import Matrix2d from 'claygl/src/math/Matrix2d';
import Matrix3 from 'claygl/src/math/Matrix3';
import Matrix4 from 'claygl/src/math/Matrix4';
import Plane from 'claygl/src/math/Plane';
import Ray from 'claygl/src/math/Ray';
import BoundingBox from 'claygl/src/math/BoundingBox';
import Frustum from 'claygl/src/math/Frustum';
import animatableMixin from './animatableMixin'; // Some common shaders
import utilGLSL from 'claygl/src/shader/source/util.glsl.js';
import prezGLSL from 'claygl/src/shader/source/prez.glsl.js';
import commonGLSL from './shader/common.glsl.js';
import colorGLSL from './shader/color.glsl.js';
import lambertGLSL from './shader/lambert.glsl.js';
import realisticGLSL from './shader/realistic.glsl.js';
import hatchingGLSL from './shader/hatching.glsl.js';
import shadowGLSL from './shader/shadow.glsl.js';
Object.assign(Node3D.prototype, animatableMixin);
Shader.import(utilGLSL);
Shader.import(prezGLSL);
Shader.import(commonGLSL);
Shader.import(colorGLSL);
Shader.import(lambertGLSL);
Shader.import(realisticGLSL);
Shader.import(hatchingGLSL);
Shader.import(shadowGLSL);
function isValueNone(value) {
return !value || value === 'none';
}
function isValueImage(value) {
return value instanceof HTMLCanvasElement || value instanceof HTMLImageElement || value instanceof Image;
}
function isECharts(value) {
return value.getZr && value.setOption;
} // Overwrite addToScene and removeFromScene
var oldAddToScene = Scene.prototype.addToScene;
var oldRemoveFromScene = Scene.prototype.removeFromScene;
Scene.prototype.addToScene = function (node) {
oldAddToScene.call(this, node);
if (this.__zr) {
var zr = this.__zr;
node.traverse(function (child) {
child.__zr = zr;
if (child.addAnimatorsToZr) {
child.addAnimatorsToZr(zr);
}
});
}
};
Scene.prototype.removeFromScene = function (node) {
oldRemoveFromScene.call(this, node);
node.traverse(function (child) {
var zr = child.__zr;
child.__zr = null;
if (zr && child.removeAnimatorsFromZr) {
child.removeAnimatorsFromZr(zr);
}
});
};
/**
* @param {string} textureName
* @param {string|HTMLImageElement|HTMLCanvasElement} imgValue
* @param {module:echarts/ExtensionAPI} api
* @param {Object} [textureOpts]
*/
Material.prototype.setTextureImage = function (textureName, imgValue, api, textureOpts) {
if (!this.shader) {
return;
}
var zr = api.getZr();
var material = this;
var texture;
material.autoUpdateTextureStatus = false; // disableTexture first
material.disableTexture(textureName);
if (!isValueNone(imgValue)) {
texture = graphicGL.loadTexture(imgValue, api, textureOpts, function (texture) {
material.enableTexture(textureName);
zr && zr.refresh();
}); // Set texture immediately for other code to verify if have this texture.
material.set(textureName, texture);
}
return texture;
};
var graphicGL = {};
graphicGL.Renderer = Renderer;
graphicGL.Node = Node3D;
graphicGL.Mesh = Mesh;
graphicGL.Shader = Shader;
graphicGL.Material = Material;
graphicGL.Texture = Texture;
graphicGL.Texture2D = Texture2D; // Geometries
graphicGL.Geometry = Geometry;
graphicGL.SphereGeometry = SphereGeometry;
graphicGL.PlaneGeometry = PlaneGeometry;
graphicGL.CubeGeometry = CubeGeometry; // Lights
graphicGL.AmbientLight = AmbientLight;
graphicGL.DirectionalLight = DirectionalLight;
graphicGL.PointLight = PointLight;
graphicGL.SpotLight = SpotLight; // Cameras
graphicGL.PerspectiveCamera = PerspectiveCamera;
graphicGL.OrthographicCamera = OrthographicCamera; // Math
graphicGL.Vector2 = Vector2;
graphicGL.Vector3 = Vector3;
graphicGL.Vector4 = Vector4;
graphicGL.Quaternion = Quaternion;
graphicGL.Matrix2 = Matrix2;
graphicGL.Matrix2d = Matrix2d;
graphicGL.Matrix3 = Matrix3;
graphicGL.Matrix4 = Matrix4;
graphicGL.Plane = Plane;
graphicGL.Ray = Ray;
graphicGL.BoundingBox = BoundingBox;
graphicGL.Frustum = Frustum; // Texture utilities
var blankImage = null;
function getBlankImage() {
if (blankImage !== null) {
return blankImage;
}
blankImage = textureUtil.createBlank('rgba(255,255,255,0)').image;
return blankImage;
}
function nearestPowerOfTwo(val) {
return Math.pow(2, Math.round(Math.log(val) / Math.LN2));
}
function convertTextureToPowerOfTwo(texture) {
if ((texture.wrapS === Texture.REPEAT || texture.wrapT === Texture.REPEAT) && texture.image) {
// var canvas = document.createElement('canvas');
var width = nearestPowerOfTwo(texture.width);
var height = nearestPowerOfTwo(texture.height);
if (width !== texture.width || height !== texture.height) {
var canvas = document.createElement('canvas');
canvas.width = width;
canvas.height = height;
var ctx = canvas.getContext('2d');
ctx.drawImage(texture.image, 0, 0, width, height);
texture.image = canvas;
}
}
}
/**
* @param {string|HTMLImageElement|HTMLCanvasElement} imgValue
* @param {module:echarts/ExtensionAPI} api
* @param {Object} [textureOpts]
* @param {Function} cb
*/
// TODO Promise, test
graphicGL.loadTexture = function (imgValue, api, textureOpts, cb) {
if (typeof textureOpts === 'function') {
cb = textureOpts;
textureOpts = {};
}
textureOpts = textureOpts || {};
var keys = Object.keys(textureOpts).sort();
var prefix = '';
for (var i = 0; i < keys.length; i++) {
prefix += keys[i] + '_' + textureOpts[keys[i]] + '_';
}
var textureCache = api.__textureCache = api.__textureCache || new LRUCache(20);
if (isECharts(imgValue)) {
var id = imgValue.__textureid__;
var textureObj = textureCache.get(prefix + id);
if (!textureObj) {
var surface = new EChartsSurface(imgValue);
surface.onupdate = function () {
api.getZr().refresh();
};
textureObj = {
texture: surface.getTexture()
};
for (var i = 0; i < keys.length; i++) {
textureObj.texture[keys[i]] = textureOpts[keys[i]];
}
id = imgValue.__textureid__ || '__ecgl_ec__' + textureObj.texture.__uid__;
imgValue.__textureid__ = id;
textureCache.put(prefix + id, textureObj);
cb && cb(textureObj.texture);
} else {
textureObj.texture.surface.setECharts(imgValue);
cb && cb(textureObj.texture);
}
return textureObj.texture;
} else if (isValueImage(imgValue)) {
var id = imgValue.__textureid__;
var textureObj = textureCache.get(prefix + id);
if (!textureObj) {
textureObj = {
texture: new graphicGL.Texture2D({
image: imgValue
})
};
for (var i = 0; i < keys.length; i++) {
textureObj.texture[keys[i]] = textureOpts[keys[i]];
}
id = imgValue.__textureid__ || '__ecgl_image__' + textureObj.texture.__uid__;
imgValue.__textureid__ = id;
textureCache.put(prefix + id, textureObj);
convertTextureToPowerOfTwo(textureObj.texture); // TODO Next tick?
cb && cb(textureObj.texture);
}
return textureObj.texture;
} else {
var textureObj = textureCache.get(prefix + imgValue);
if (textureObj) {
if (textureObj.callbacks) {
// Add to pending callbacks
textureObj.callbacks.push(cb);
} else {
// TODO Next tick?
cb && cb(textureObj.texture);
}
} else {
// Maybe base64
if (imgValue.match(/.hdr$|^data:application\/octet-stream/)) {
textureObj = {
callbacks: [cb]
};
var texture = textureUtil.loadTexture(imgValue, {
exposure: textureOpts.exposure,
fileType: 'hdr'
}, function () {
texture.dirty();
textureObj.callbacks.forEach(function (cb) {
cb && cb(texture);
});
textureObj.callbacks = null;
});
textureObj.texture = texture;
textureCache.put(prefix + imgValue, textureObj);
} else {
var texture = new graphicGL.Texture2D({
image: new Image()
});
for (var i = 0; i < keys.length; i++) {
texture[keys[i]] = textureOpts[keys[i]];
}
textureObj = {
texture: texture,
callbacks: [cb]
};
var originalImage = texture.image;
originalImage.onload = function () {
texture.image = originalImage;
convertTextureToPowerOfTwo(texture);
texture.dirty();
textureObj.callbacks.forEach(function (cb) {
cb && cb(texture);
});
textureObj.callbacks = null;
};
originalImage.crossOrigin = 'Anonymous';
originalImage.src = imgValue; // Use blank image as place holder.
texture.image = getBlankImage();
textureCache.put(prefix + imgValue, textureObj);
}
}
return textureObj.texture;
}
};
/**
* Create ambientCubemap and ambientSH light. respectively to have specular and diffuse light
* @return {Object} { specular, diffuse }
*/
graphicGL.createAmbientCubemap = function (opt, renderer, api, cb) {
opt = opt || {};
var textureUrl = opt.texture;
var exposure = retrieve.firstNotNull(opt.exposure, 1.0);
var ambientCubemap = new AmbientCubemapLight({
intensity: retrieve.firstNotNull(opt.specularIntensity, 1.0)
});
var ambientSH = new AmbientSHLight({
intensity: retrieve.firstNotNull(opt.diffuseIntensity, 1.0),
coefficients: [0.844, 0.712, 0.691, -0.037, 0.083, 0.167, 0.343, 0.288, 0.299, -0.041, -0.021, -0.009, -0.003, -0.041, -0.064, -0.011, -0.007, -0.004, -0.031, 0.034, 0.081, -0.060, -0.049, -0.060, 0.046, 0.056, 0.050]
});
ambientCubemap.cubemap = graphicGL.loadTexture(textureUrl, api, {
exposure: exposure
}, function () {
// TODO Performance when multiple view
ambientCubemap.cubemap.flipY = false;
if (process.env.NODE_ENV !== 'production') {
var time = Date.now();
}
ambientCubemap.prefilter(renderer, 32);
if (process.env.NODE_ENV !== 'production') {
var dTime = Date.now() - time;
console.log('Prefilter environment map: ' + dTime + 'ms');
}
ambientSH.coefficients = shUtil.projectEnvironmentMap(renderer, ambientCubemap.cubemap, {
lod: 1
});
cb && cb(); // TODO Refresh ?
});
return {
specular: ambientCubemap,
diffuse: ambientSH
};
};
/**
* Create a blank texture for placeholder
*/
graphicGL.createBlankTexture = textureUtil.createBlank;
/**
* If value is image
* @param {*}
* @return {boolean}
*/
graphicGL.isImage = isValueImage;
graphicGL.additiveBlend = function (gl) {
gl.blendEquation(gl.FUNC_ADD);
gl.blendFunc(gl.SRC_ALPHA, gl.ONE);
};
/**
* @param {string|Array.<number>} colorStr
* @param {Array.<number>} [rgba]
* @return {Array.<number>} rgba
*/
graphicGL.parseColor = function (colorStr, rgba) {
if (colorStr instanceof Array) {
if (!rgba) {
rgba = [];
} // Color has been parsed.
rgba[0] = colorStr[0];
rgba[1] = colorStr[1];
rgba[2] = colorStr[2];
if (colorStr.length > 3) {
rgba[3] = colorStr[3];
} else {
rgba[3] = 1;
}
return rgba;
}
rgba = echarts.color.parse(colorStr || '#000', rgba) || [0, 0, 0, 0];
rgba[0] /= 255;
rgba[1] /= 255;
rgba[2] /= 255;
return rgba;
};
/**
* Convert alpha beta rotation to direction.
* @param {number} alpha
* @param {number} beta
* @return {Array.<number>}
*/
graphicGL.directionFromAlphaBeta = function (alpha, beta) {
var theta = alpha / 180 * Math.PI + Math.PI / 2;
var phi = -beta / 180 * Math.PI + Math.PI / 2;
var dir = [];
var r = Math.sin(theta);
dir[0] = r * Math.cos(phi);
dir[1] = -Math.cos(theta);
dir[2] = r * Math.sin(phi);
return dir;
};
/**
* Get shadow resolution from shadowQuality configuration
*/
graphicGL.getShadowResolution = function (shadowQuality) {
var shadowResolution = 1024;
switch (shadowQuality) {
case 'low':
shadowResolution = 512;
break;
case 'medium':
break;
case 'high':
shadowResolution = 2048;
break;
case 'ultra':
shadowResolution = 4096;
break;
}
return shadowResolution;
};
/**
* Shading utilities
*/
graphicGL.COMMON_SHADERS = ['lambert', 'color', 'realistic', 'hatching', 'shadow'];
/**
* Create shader including vertex and fragment
* @param {string} prefix.
*/
graphicGL.createShader = function (prefix) {
if (prefix === 'ecgl.shadow') {
prefix = 'ecgl.displayShadow';
}
var vertexShaderStr = Shader.source(prefix + '.vertex');
var fragmentShaderStr = Shader.source(prefix + '.fragment');
if (!vertexShaderStr) {
console.error('Vertex shader of \'%s\' not exits', prefix);
}
if (!fragmentShaderStr) {
console.error('Fragment shader of \'%s\' not exits', prefix);
}
var shader = new Shader(vertexShaderStr, fragmentShaderStr);
shader.name = prefix;
return shader;
};
graphicGL.createMaterial = function (prefix, defines) {
if (!(defines instanceof Array)) {
defines = [defines];
}
var shader = graphicGL.createShader(prefix);
var material = new Material({
shader: shader
});
defines.forEach(function (defineName) {
if (typeof defineName === 'string') {
material.define(defineName);
}
});
return material;
};
/**
* Set material from model.
* @param {clay.Material} material
* @param {module:echarts/model/Model} model
* @param {module:echarts/ExtensionAPI} api
*/
graphicGL.setMaterialFromModel = function (shading, material, model, api) {
material.autoUpdateTextureStatus = false;
var materialModel = model.getModel(shading + 'Material');
var detailTexture = materialModel.get('detailTexture');
var uvRepeat = retrieve.firstNotNull(materialModel.get('textureTiling'), 1.0);
var uvOffset = retrieve.firstNotNull(materialModel.get('textureOffset'), 0.0);
if (typeof uvRepeat === 'number') {
uvRepeat = [uvRepeat, uvRepeat];
}
if (typeof uvOffset === 'number') {
uvOffset = [uvOffset, uvOffset];
}
var repeatParam = uvRepeat[0] > 1 || uvRepeat[1] > 1 ? graphicGL.Texture.REPEAT : graphicGL.Texture.CLAMP_TO_EDGE;
var textureOpt = {
anisotropic: 8,
wrapS: repeatParam,
wrapT: repeatParam
};
if (shading === 'realistic') {
var roughness = materialModel.get('roughness');
var metalness = materialModel.get('metalness');
if (metalness != null) {
// Try to treat as a texture, TODO More check
if (isNaN(metalness)) {
material.setTextureImage('metalnessMap', metalness, api, textureOpt);
metalness = retrieve.firstNotNull(materialModel.get('metalnessAdjust'), 0.5);
}
} else {
// Default metalness.
metalness = 0;
}
if (roughness != null) {
// Try to treat as a texture, TODO More check
if (isNaN(roughness)) {
material.setTextureImage('roughnessMap', roughness, api, textureOpt);
roughness = retrieve.firstNotNull(materialModel.get('roughnessAdjust'), 0.5);
}
} else {
// Default roughness.
roughness = 0.5;
}
var normalTextureVal = materialModel.get('normalTexture');
material.setTextureImage('detailMap', detailTexture, api, textureOpt);
material.setTextureImage('normalMap', normalTextureVal, api, textureOpt);
material.set({
roughness: roughness,
metalness: metalness,
detailUvRepeat: uvRepeat,
detailUvOffset: uvOffset
}); // var normalTexture = material.get('normalMap');
// if (normalTexture) {
// PENDING
// normalTexture.format = Texture.SRGB;
// }
} else if (shading === 'lambert') {
material.setTextureImage('detailMap', detailTexture, api, textureOpt);
material.set({
detailUvRepeat: uvRepeat,
detailUvOffset: uvOffset
});
} else if (shading === 'color') {
material.setTextureImage('detailMap', detailTexture, api, textureOpt);
material.set({
detailUvRepeat: uvRepeat,
detailUvOffset: uvOffset
});
} else if (shading === 'hatching') {
var tams = materialModel.get('hatchingTextures') || [];
if (tams.length < 6) {
if (process.env.NODE_ENV !== 'production') {
console.error('Invalid hatchingTextures.');
}
}
for (var i = 0; i < 6; i++) {
material.setTextureImage('hatch' + (i + 1), tams[i], api, {
anisotropic: 8,
wrapS: graphicGL.Texture.REPEAT,
wrapT: graphicGL.Texture.REPEAT
});
}
material.set({
detailUvRepeat: uvRepeat,
detailUvOffset: uvOffset
});
}
};
graphicGL.updateVertexAnimation = function (mappingAttributes, previousMesh, currentMesh, seriesModel) {
var enableAnimation = seriesModel.get('animation');
var duration = seriesModel.get('animationDurationUpdate');
var easing = seriesModel.get('animationEasingUpdate');
var shadowDepthMaterial = currentMesh.shadowDepthMaterial;
if (enableAnimation && previousMesh && duration > 0 // Only animate when bar count are not changed
&& previousMesh.geometry.vertexCount === currentMesh.geometry.vertexCount) {
currentMesh.material.define('vertex', 'VERTEX_ANIMATION');
currentMesh.ignorePreZ = true;
if (shadowDepthMaterial) {
shadowDepthMaterial.define('vertex', 'VERTEX_ANIMATION');
}
for (var i = 0; i < mappingAttributes.length; i++) {
currentMesh.geometry.attributes[mappingAttributes[i][0]].value = previousMesh.geometry.attributes[mappingAttributes[i][1]].value;
}
currentMesh.geometry.dirty();
currentMesh.__percent = 0;
currentMesh.material.set('percent', 0);
currentMesh.stopAnimation();
currentMesh.animate().when(duration, {
__percent: 1
}).during(function () {
currentMesh.material.set('percent', currentMesh.__percent);
if (shadowDepthMaterial) {
shadowDepthMaterial.set('percent', currentMesh.__percent);
}
}).done(function () {
currentMesh.ignorePreZ = false;
currentMesh.material.undefine('vertex', 'VERTEX_ANIMATION');
if (shadowDepthMaterial) {
shadowDepthMaterial.undefine('vertex', 'VERTEX_ANIMATION');
}
}).start(easing);
} else {
currentMesh.material.undefine('vertex', 'VERTEX_ANIMATION');
if (shadowDepthMaterial) {
shadowDepthMaterial.undefine('vertex', 'VERTEX_ANIMATION');
}
}
};
export default graphicGL;