class MakeMaterial { static defaultScon: ShaderContext = null; static defaultMcon: MaterialContext = null; static heightUsed = false; static emisUsed = false; static subsUsed = false; static getMOut = (): bool => { for (let n of UINodes.inst.getCanvasMaterial().nodes) if (n.type == "OUTPUT_MATERIAL_PBR") return true; return false; } static parseMeshMaterial = () => { let m = Project.materials[0].data; for (let c of m.shader.contexts) { if (c.raw.name == "mesh") { m.shader.raw.contexts.remove(c.raw); m.shader.contexts.remove(c); deleteContext(c); break; } } if (MakeMesh.layerPassCount > 1) { let i = 0; while (i < m.shader.contexts.length) { let c = m.shader.contexts[i]; for (let j = 1; j < MakeMesh.layerPassCount; ++j) { if (c.raw.name == "mesh" + j) { m.shader.raw.contexts.remove(c.raw); m.shader.contexts.remove(c); deleteContext(c); i--; break; } } i++; } i = 0; while (i < m.contexts.length) { let c = m.contexts[i]; for (let j = 1; j < MakeMesh.layerPassCount; ++j) { if (c.raw.name == "mesh" + j) { m.raw.contexts.remove(c.raw); m.contexts.remove(c); i--; break; } } i++; } } let con = MakeMesh.run(new NodeShaderData({ name: "Material", canvas: null })); let scon = new ShaderContext(con.data, (scon: ShaderContext) => {}); scon.overrideContext = {}; if (con.frag.sharedSamplers.length > 0) { let sampler = con.frag.sharedSamplers[0]; scon.overrideContext.shared_sampler = sampler.substr(sampler.lastIndexOf(" ") + 1); } if (!Context.raw.textureFilter) { scon.overrideContext.filter = "point"; } m.shader.raw.contexts.push(scon.raw); m.shader.contexts.push(scon); for (let i = 1; i < MakeMesh.layerPassCount; ++i) { let con = MakeMesh.run(new NodeShaderData({ name: "Material", canvas: null }), i); let scon = new ShaderContext(con.data, (scon: ShaderContext) => {}); scon.overrideContext = {}; if (con.frag.sharedSamplers.length > 0) { let sampler = con.frag.sharedSamplers[0]; scon.overrideContext.shared_sampler = sampler.substr(sampler.lastIndexOf(" ") + 1); } if (!Context.raw.textureFilter) { scon.overrideContext.filter = "point"; } m.shader.raw.contexts.push(scon.raw); m.shader.contexts.push(scon); let mcon = new MaterialContext({ name: "mesh" + i, bind_textures: [] }, (self: MaterialContext) => {}); m.raw.contexts.push(mcon.raw); m.contexts.push(mcon); } Context.raw.ddirty = 2; ///if arm_voxels makeVoxel(m); ///end } static parseParticleMaterial = () => { let m = Context.raw.particleMaterial; let sc: ShaderContext = null; for (let c of m.shader.contexts) { if (c.raw.name == "mesh") { sc = c; break; } } if (sc != null) { m.shader.raw.contexts.remove(sc.raw); m.shader.contexts.remove(sc); } let con = MakeParticle.run(new NodeShaderData({ name: "MaterialParticle", canvas: null })); if (sc != null) deleteContext(sc); sc = new ShaderContext(con.data, (sc: ShaderContext) => {}); m.shader.raw.contexts.push(sc.raw); m.shader.contexts.push(sc); } static parseMeshPreviewMaterial = () => { if (!getMOut()) return; let m = Project.materials[0].data; let scon: ShaderContext = null; for (let c of m.shader.contexts) { if (c.raw.name == "mesh") { scon = c; break; } } m.shader.raw.contexts.remove(scon.raw); m.shader.contexts.remove(scon); let mcon: TMaterialContext = { name: "mesh", bind_textures: [] }; let sd = new NodeShaderData({ name: "Material", canvas: null }); let con = MakeMeshPreview.run(sd, mcon); for (let i = 0; i < m.contexts.length; ++i) { if (m.contexts[i].raw.name == "mesh") { m.contexts[i] = new MaterialContext(mcon, (self: MaterialContext) => {}); break; } } if (scon != null) deleteContext(scon); let compileError = false; scon = new ShaderContext(con.data, (scon: ShaderContext) => { if (scon == null) compileError = true; }); if (compileError) return; m.shader.raw.contexts.push(scon.raw); m.shader.contexts.push(scon); } ///if arm_voxels static makeVoxel = (m: MaterialData) => { let rebuild = heightUsed; if (Config.raw.rp_gi != false && rebuild) { let scon: ShaderContext = null; for (let c of m.shader.contexts) { if (c.raw.name == "voxel") { scon = c; break; } } if (scon != null) MakeVoxel.run(scon); } } ///end static parsePaintMaterial = (bakePreviews = true) => { if (!getMOut()) return; if (bakePreviews) { let current = Graphics2.current; if (current != null) current.end(); bakeNodePreviews(); if (current != null) current.begin(false); } let m = Project.materials[0].data; let scon: ShaderContext = null; let mcon: MaterialContext = null; for (let c of m.shader.contexts) { if (c.raw.name == "paint") { m.shader.raw.contexts.remove(c.raw); m.shader.contexts.remove(c); if (c != defaultScon) deleteContext(c); break; } } for (let c of m.contexts) { if (c.raw.name == "paint") { m.raw.contexts.remove(c.raw); m.contexts.remove(c); break; } } let sdata = new NodeShaderData({ name: "Material", canvas: UINodes.inst.getCanvasMaterial() }); let mcon: TMaterialContext = { name: "paint", bind_textures: [] }; let con = MakeSculpt.run(sdata, mcon); let compileError = false; let scon = new ShaderContext(con.data, (scon: ShaderContext) => { if (scon == null) compileError = true; }); if (compileError) return; scon.overrideContext = {}; scon.overrideContext.addressing = "repeat"; let mcon = new MaterialContext(mcon, (mcon: MaterialContext) => {}); m.shader.raw.contexts.push(scon.raw); m.shader.contexts.push(scon); m.raw.contexts.push(mcon.raw); m.contexts.push(mcon); if (defaultScon == null) defaultScon = scon; if (defaultMcon == null) defaultMcon = mcon; } static bakeNodePreviews = () => { Context.raw.nodePreviewsUsed = []; if (Context.raw.nodePreviews == null) Context.raw.nodePreviews = []; traverseNodes(UINodes.inst.getCanvasMaterial().nodes, null, []); for (let key of Context.raw.nodePreviews.keys()) { if (Context.raw.nodePreviewsUsed.indexOf(key) == -1) { let image = Context.raw.nodePreviews.get(key); Base.notifyOnNextFrame(image.unload); Context.raw.nodePreviews.remove(key); } } } static traverseNodes = (nodes: TNode[], group: TNodeCanvas, parents: TNode[]) => { for (let node of nodes) { bakeNodePreview(node, group, parents); if (node.type == "GROUP") { for (let g of Project.materialGroups) { if (g.canvas.name == node.name) { parents.push(node); traverseNodes(g.canvas.nodes, g.canvas, parents); parents.pop(); break; } } } } } static bakeNodePreview = (node: TNode, group: TNodeCanvas, parents: TNode[]) => { if (node.type == "BLUR") { let id = ParserMaterial.node_name(node, parents); let image = Context.raw.nodePreviews.get(id); Context.raw.nodePreviewsUsed.push(id); let resX = Math.floor(Config.getTextureResX() / 4); let resY = Math.floor(Config.getTextureResY() / 4); if (image == null || image.width != resX || image.height != resY) { if (image != null) image.unload(); image = Image.createRenderTarget(resX, resY); Context.raw.nodePreviews.set(id, image); } ParserMaterial.blur_passthrough = true; UtilRender.makeNodePreview(UINodes.inst.getCanvasMaterial(), node, image, group, parents); ParserMaterial.blur_passthrough = false; } else if (node.type == "DIRECT_WARP") { let id = ParserMaterial.node_name(node, parents); let image = Context.raw.nodePreviews.get(id); Context.raw.nodePreviewsUsed.push(id); let resX = Math.floor(Config.getTextureResX()); let resY = Math.floor(Config.getTextureResY()); if (image == null || image.width != resX || image.height != resY) { if (image != null) image.unload(); image = Image.createRenderTarget(resX, resY); Context.raw.nodePreviews.set(id, image); } ParserMaterial.warp_passthrough = true; UtilRender.makeNodePreview(UINodes.inst.getCanvasMaterial(), node, image, group, parents); ParserMaterial.warp_passthrough = false; } } static parseNodePreviewMaterial = (node: TNode, group: TNodeCanvas = null, parents: TNode[] = null): { scon: ShaderContext, mcon: MaterialContext } => { if (node.outputs.length == 0) return null; let sdata = new NodeShaderData({ name: "Material", canvas: UINodes.inst.getCanvasMaterial() }); let mcon_raw: TMaterialContext = { name: "mesh", bind_textures: [] }; let con = MakeNodePreview.run(sdata, mcon_raw, node, group, parents); let compileError = false; let scon = new ShaderContext(con.data, (scon: ShaderContext) => { if (scon == null) compileError = true; }); if (compileError) return null; let mcon = new MaterialContext(mcon_raw, (mcon: MaterialContext) => {}); return { scon: scon, mcon: mcon }; } static parseBrush = () => { ParserLogic.parse(Context.raw.brush.canvas); } static getDisplaceStrength = (): f32 => { let sc = Context.mainObject().transform.scale.x; return Config.raw.displace_strength * 0.02 * sc; } static voxelgiHalfExtents = (): string => { let ext = Context.raw.vxaoExt; return `const vec3 voxelgiHalfExtents = vec3(${ext}, ${ext}, ${ext});`; } static deleteContext = (c: ShaderContext) => { Base.notifyOnNextFrame(() => { // Ensure pipeline is no longer in use c.delete(); }); } }