"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.default = void 0; var _Mesh = require("claygl/src/Mesh"); var _Renderer = require("claygl/src/Renderer"); var _Texture2D = require("claygl/src/Texture2D"); var _Texture = require("claygl/src/Texture"); var _Shader = require("claygl/src/Shader"); var _Material = require("claygl/src/Material"); var _Node = require("claygl/src/Node"); var _Geometry = require("claygl/src/Geometry"); var echarts = require("echarts/index.blank"); var _Scene = require("claygl/src/Scene"); var _LRU = require("zrender/lib/core/LRU"); var _texture = require("claygl/src/util/texture"); var _EChartsSurface = require("./EChartsSurface"); var _AmbientCubemap = require("claygl/src/light/AmbientCubemap"); var _AmbientSH = require("claygl/src/light/AmbientSH"); var _sh = require("claygl/src/util/sh"); var _retrieve = require("./retrieve"); var _Sphere = require("claygl/src/geometry/Sphere"); var _Plane = require("claygl/src/geometry/Plane"); var _Cube = require("claygl/src/geometry/Cube"); var _Ambient = require("claygl/src/light/Ambient"); var _Directional = require("claygl/src/light/Directional"); var _Point = require("claygl/src/light/Point"); var _Spot = require("claygl/src/light/Spot"); var _Perspective = require("claygl/src/camera/Perspective"); var _Orthographic = require("claygl/src/camera/Orthographic"); var _Vector = require("claygl/src/math/Vector2"); var _Vector2 = require("claygl/src/math/Vector3"); var _Vector3 = require("claygl/src/math/Vector4"); var _Quaternion = require("claygl/src/math/Quaternion"); var _Matrix = require("claygl/src/math/Matrix2"); var _Matrix2d = require("claygl/src/math/Matrix2d"); var _Matrix2 = require("claygl/src/math/Matrix3"); var _Matrix3 = require("claygl/src/math/Matrix4"); var _Plane2 = require("claygl/src/math/Plane"); var _Ray = require("claygl/src/math/Ray"); var _BoundingBox = require("claygl/src/math/BoundingBox"); var _Frustum = require("claygl/src/math/Frustum"); var _animatableMixin = require("./animatableMixin"); var _utilGlsl = require("claygl/src/shader/source/util.glsl.js"); var _prezGlsl = require("claygl/src/shader/source/prez.glsl.js"); var _commonGlsl = require("./shader/common.glsl.js"); var _colorGlsl = require("./shader/color.glsl.js"); var _lambertGlsl = require("./shader/lambert.glsl.js"); var _realisticGlsl = require("./shader/realistic.glsl.js"); var _hatchingGlsl = require("./shader/hatching.glsl.js"); var _shadowGlsl = require("./shader/shadow.glsl.js"); // Math // Some common shaders Object.assign(_Node.default.prototype, _animatableMixin.default); _Shader.default.import(_utilGlsl.default); _Shader.default.import(_prezGlsl.default); _Shader.default.import(_commonGlsl.default); _Shader.default.import(_colorGlsl.default); _Shader.default.import(_lambertGlsl.default); _Shader.default.import(_realisticGlsl.default); _Shader.default.import(_hatchingGlsl.default); _Shader.default.import(_shadowGlsl.default); 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.default.prototype.addToScene; var oldRemoveFromScene = _Scene.default.prototype.removeFromScene; _Scene.default.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.default.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.default.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.default; graphicGL.Node = _Node.default; graphicGL.Mesh = _Mesh.default; graphicGL.Shader = _Shader.default; graphicGL.Material = _Material.default; graphicGL.Texture = _Texture.default; graphicGL.Texture2D = _Texture2D.default; // Geometries graphicGL.Geometry = _Geometry.default; graphicGL.SphereGeometry = _Sphere.default; graphicGL.PlaneGeometry = _Plane.default; graphicGL.CubeGeometry = _Cube.default; // Lights graphicGL.AmbientLight = _Ambient.default; graphicGL.DirectionalLight = _Directional.default; graphicGL.PointLight = _Point.default; graphicGL.SpotLight = _Spot.default; // Cameras graphicGL.PerspectiveCamera = _Perspective.default; graphicGL.OrthographicCamera = _Orthographic.default; // Math graphicGL.Vector2 = _Vector.default; graphicGL.Vector3 = _Vector2.default; graphicGL.Vector4 = _Vector3.default; graphicGL.Quaternion = _Quaternion.default; graphicGL.Matrix2 = _Matrix.default; graphicGL.Matrix2d = _Matrix2d.default; graphicGL.Matrix3 = _Matrix2.default; graphicGL.Matrix4 = _Matrix3.default; graphicGL.Plane = _Plane2.default; graphicGL.Ray = _Ray.default; graphicGL.BoundingBox = _BoundingBox.default; graphicGL.Frustum = _Frustum.default; // Texture utilities var blankImage = _texture.default.createBlank('rgba(255,255,255,0)').image; function nearestPowerOfTwo(val) { return Math.pow(2, Math.round(Math.log(val) / Math.LN2)); } function convertTextureToPowerOfTwo(texture) { if ((texture.wrapS === _Texture.default.REPEAT || texture.wrapT === _Texture.default.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 _LRU.default(20); if (isECharts(imgValue)) { var id = imgValue.__textureid__; var textureObj = textureCache.get(prefix + id); if (!textureObj) { var surface = new _EChartsSurface.default(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 = _texture.default.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.src = imgValue; // Use blank image as place holder. texture.image = blankImage; 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.default.firstNotNull(opt.exposure, 1.0); var ambientCubemap = new _AmbientCubemap.default({ intensity: _retrieve.default.firstNotNull(opt.specularIntensity, 1.0) }); var ambientSH = new _AmbientSH.default({ intensity: _retrieve.default.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 = _sh.default.projectEnvironmentMap(renderer, ambientCubemap.cubemap, { lod: 1 }); cb && cb(); // TODO Refresh ? }); return { specular: ambientCubemap, diffuse: ambientSH }; }; /** * Create a blank texture for placeholder */ graphicGL.createBlankTexture = _texture.default.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.} colorStr * @param {Array.} [rgba] * @return {Array.} 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.} */ 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.default.source(prefix + '.vertex'); var fragmentShaderStr = _Shader.default.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.default(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.default({ 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.default.firstNotNull(materialModel.get('textureTiling'), 1.0); var uvOffset = _retrieve.default.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.default.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.default.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'); } } }; var _default = graphicGL; exports.default = _default;