UNPKG

cione-comp-lib

Version:

`$ yarn add cione-comp-lib` 或者 `$ npm i cione-comp-lib -S`

265 lines (264 loc) 7.22 kB
import util from "./core/util.mjs"; import Compositor from "./compositor/Compositor.mjs"; import CompoSceneNode from "./compositor/SceneNode.mjs"; import CompoTextureNode from "./compositor/TextureNode.mjs"; import CompoFilterNode from "./compositor/FilterNode.mjs"; import Shader from "./Shader.mjs"; import Texture from "./Texture.mjs"; import Texture2D from "./Texture2D.mjs"; import TextureCube from "./TextureCube.mjs"; import register from "./shader/registerBuiltinCompositor.mjs"; register(Shader); var shaderSourceReg = /^#source\((.*?)\)/; function createCompositor(json, opts) { var compositor = new Compositor(); opts = opts || {}; var lib = { textures: {}, parameters: {} }; var afterLoad = function(shaderLib, textureLib) { for (var i = 0; i < json.nodes.length; i++) { var nodeInfo = json.nodes[i]; var node = createNode(nodeInfo, lib, opts); if (node) { compositor.addNode(node); } } }; for (var name in json.parameters) { var paramInfo = json.parameters[name]; lib.parameters[name] = convertParameter(paramInfo); } loadTextures(json, lib, opts, function(textureLib) { lib.textures = textureLib; afterLoad(); }); return compositor; } function createNode(nodeInfo, lib, opts) { var type = nodeInfo.type || "filter"; var shaderSource; var inputs; var outputs; if (type === "filter") { var shaderExp = nodeInfo.shader.trim(); var res = shaderSourceReg.exec(shaderExp); if (res) { shaderSource = Shader.source(res[1].trim()); } else if (shaderExp.charAt(0) === "#") { shaderSource = lib.shaders[shaderExp.substr(1)]; } if (!shaderSource) { shaderSource = shaderExp; } if (!shaderSource) { return; } } if (nodeInfo.inputs) { inputs = {}; for (var name in nodeInfo.inputs) { if (typeof nodeInfo.inputs[name] === "string") { inputs[name] = nodeInfo.inputs[name]; } else { inputs[name] = { node: nodeInfo.inputs[name].node, pin: nodeInfo.inputs[name].pin }; } } } if (nodeInfo.outputs) { outputs = {}; for (var name in nodeInfo.outputs) { var outputInfo = nodeInfo.outputs[name]; outputs[name] = {}; if (outputInfo.attachment != null) { outputs[name].attachment = outputInfo.attachment; } if (outputInfo.keepLastFrame != null) { outputs[name].keepLastFrame = outputInfo.keepLastFrame; } if (outputInfo.outputLastFrame != null) { outputs[name].outputLastFrame = outputInfo.outputLastFrame; } if (outputInfo.parameters) { outputs[name].parameters = convertParameter(outputInfo.parameters); } } } var node; if (type === "scene") { node = new CompoSceneNode({ name: nodeInfo.name, scene: opts.scene, camera: opts.camera, outputs }); } else if (type === "texture") { node = new CompoTextureNode({ name: nodeInfo.name, outputs }); } else { node = new CompoFilterNode({ name: nodeInfo.name, shader: shaderSource, inputs, outputs }); } if (node) { if (nodeInfo.parameters) { for (var name in nodeInfo.parameters) { var val = nodeInfo.parameters[name]; if (typeof val === "string") { val = val.trim(); if (val.charAt(0) === "#") { val = lib.textures[val.substr(1)]; } else { node.on( "beforerender", createSizeSetHandler( name, tryConvertExpr(val) ) ); } } else if (typeof val === "function") { node.on("beforerender", val); } node.setParameter(name, val); } } if (nodeInfo.defines && node.pass) { for (var name in nodeInfo.defines) { var val = nodeInfo.defines[name]; node.pass.material.define("fragment", name, val); } } } return node; } function defaultWidthFunc(width, height) { return width; } function defaultHeightFunc(width, height) { return height; } function convertParameter(paramInfo) { var param = {}; if (!paramInfo) { return param; } ["type", "minFilter", "magFilter", "wrapS", "wrapT", "flipY", "useMipmap"].forEach(function(name) { var val = paramInfo[name]; if (val != null) { if (typeof val === "string") { val = Texture[val]; } param[name] = val; } }); var sizeScale = paramInfo.scale || 1; ["width", "height"].forEach(function(name) { if (paramInfo[name] != null) { var val = paramInfo[name]; if (typeof val === "string") { val = val.trim(); param[name] = createSizeParser( name, tryConvertExpr(val), sizeScale ); } else { param[name] = val; } } }); if (!param.width) { param.width = defaultWidthFunc; } if (!param.height) { param.height = defaultHeightFunc; } if (paramInfo.useMipmap != null) { param.useMipmap = paramInfo.useMipmap; } return param; } function loadTextures(json, lib, opts, callback) { if (!json.textures) { callback({}); return; } var textures = {}; var loading = 0; var cbd = false; var textureRootPath = opts.textureRootPath; util.each(json.textures, function(textureInfo, name) { var texture; var path = textureInfo.path; var parameters = convertParameter(textureInfo.parameters); if (Array.isArray(path) && path.length === 6) { if (textureRootPath) { path = path.map(function(item) { return util.relative2absolute(item, textureRootPath); }); } texture = new TextureCube(parameters); } else if (typeof path === "string") { if (textureRootPath) { path = util.relative2absolute(path, textureRootPath); } texture = new Texture2D(parameters); } else { return; } texture.load(path); loading++; texture.once("success", function() { textures[name] = texture; loading--; if (loading === 0) { callback(textures); cbd = true; } }); }); if (loading === 0 && !cbd) { callback(textures); } } function createSizeSetHandler(name, exprFunc) { return function(renderer) { var dpr = renderer.getDevicePixelRatio(); var width = renderer.getWidth(); var height = renderer.getHeight(); var result = exprFunc(width, height, dpr); this.setParameter(name, result); }; } function createSizeParser(name, exprFunc, scale) { scale = scale || 1; return function(renderer) { var dpr = renderer.getDevicePixelRatio(); var width = renderer.getWidth() * scale; var height = renderer.getHeight() * scale; return exprFunc(width, height, dpr); }; } function tryConvertExpr(string) { var exprRes = /^expr\((.*)\)$/.exec(string); if (exprRes) { try { var func = new Function("width", "height", "dpr", "return " + exprRes[1]); func(1, 1); return func; } catch (e) { throw new Error("Invalid expression."); } } } export { createCompositor as default };