From 171007693bdc621318da8498c72470077234b9f3 Mon Sep 17 00:00:00 2001 From: Nehon Date: Sat, 28 Oct 2017 18:13:05 +0200 Subject: [PATCH] De duplicate imports when generating a shader from shader nodes --- .../java/com/jme3/shader/ShaderGenerator.java | 29 ++++++-- .../com/jme3/shader/plugins/GLSLLoader.java | 69 +++++++++++++------ .../jme3/shader/plugins/ShaderAssetKey.java | 24 +++++++ 3 files changed, 94 insertions(+), 28 deletions(-) create mode 100644 jme3-core/src/plugins/java/com/jme3/shader/plugins/ShaderAssetKey.java diff --git a/jme3-core/src/main/java/com/jme3/shader/ShaderGenerator.java b/jme3-core/src/main/java/com/jme3/shader/ShaderGenerator.java index db3878afd..8783b195d 100644 --- a/jme3-core/src/main/java/com/jme3/shader/ShaderGenerator.java +++ b/jme3-core/src/main/java/com/jme3/shader/ShaderGenerator.java @@ -31,14 +31,15 @@ */ package com.jme3.shader; -import com.jme3.asset.AssetKey; import com.jme3.asset.AssetManager; import com.jme3.material.ShaderGenerationInfo; -import com.jme3.material.Technique; import com.jme3.material.TechniqueDef; import com.jme3.shader.Shader.ShaderType; -import java.util.List; -import java.util.regex.*; +import com.jme3.shader.plugins.ShaderAssetKey; + +import java.util.*; +import java.util.regex.Matcher; +import java.util.regex.Pattern; /** * This class is the base for a shader generator using the ShaderNodes system, @@ -66,6 +67,8 @@ public abstract class ShaderGenerator { */ Pattern extensions = Pattern.compile("(#extension.*\\s+)"); + private Map imports = new LinkedHashMap<>(); + /** * Build a shaderGenerator * @@ -126,7 +129,9 @@ public abstract class ShaderGenerator { // Too much code assumes that type is either Vertex or Fragment return null; } - + + imports.clear(); + indent = 0; StringBuilder sourceDeclaration = new StringBuilder(); @@ -145,6 +150,12 @@ public abstract class ShaderGenerator { generateEndOfMainSection(source, info, type); + //insert imports backward + int insertIndex = sourceDeclaration.length(); + for (String importSource : imports.values()) { + sourceDeclaration.insert(insertIndex, importSource); + } + sourceDeclaration.append(source); return moveExtensionsUp(sourceDeclaration); @@ -186,7 +197,13 @@ public abstract class ShaderGenerator { if (shaderNode.getDefinition().getType() == type) { int index = findShaderIndexFromVersion(shaderNode, type); String shaderPath = shaderNode.getDefinition().getShadersPath().get(index); - String loadedSource = (String) assetManager.loadAsset(new AssetKey(shaderPath)); + Map sources = (Map) assetManager.loadAsset(new ShaderAssetKey(shaderPath, false)); + String loadedSource = sources.get("[main]"); + for (String name : sources.keySet()) { + if (!name.equals("[main]")) { + imports.put(name, sources.get(name)); + } + } appendNodeDeclarationAndMain(loadedSource, sourceDeclaration, source, shaderNode, info, shaderPath); } } diff --git a/jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java b/jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java index 88b0ddd45..ce3264b2d 100644 --- a/jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java +++ b/jme3-core/src/plugins/java/com/jme3/shader/plugins/GLSLLoader.java @@ -34,10 +34,7 @@ package com.jme3.shader.plugins; import com.jme3.asset.*; import com.jme3.asset.cache.AssetCache; -import java.io.BufferedReader; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.Reader; +import java.io.*; import java.util.*; /** @@ -129,11 +126,11 @@ public class GLSLLoader implements AssetLoader { private ShaderDependencyNode nextIndependentNode() throws IOException { Collection allNodes = dependCache.values(); - + if (allNodes.isEmpty()) { return null; } - + for (ShaderDependencyNode node : allNodes) { if (node.getDependOnMe().isEmpty()) { return node; @@ -144,11 +141,11 @@ public class GLSLLoader implements AssetLoader { for (ShaderDependencyNode node : allNodes){ System.out.println(node.getName()); } - + throw new IOException("Circular dependency."); } - private String resolveDependencies(ShaderDependencyNode node, Set alreadyInjectedSet, StringBuilder extensions) { + private String resolveDependencies(ShaderDependencyNode node, Set alreadyInjectedSet, StringBuilder extensions, boolean injectDependencies) { if (alreadyInjectedSet.contains(node)) { return "// " + node.getName() + " was already injected at the top.\n"; } else { @@ -160,18 +157,27 @@ public class GLSLLoader implements AssetLoader { if (node.getDependencies().isEmpty()) { return node.getSource(); } else { - StringBuilder sb = new StringBuilder(node.getSource()); - List resolvedShaderNodes = new ArrayList<>(); + if (injectDependencies) { + StringBuilder sb = new StringBuilder(node.getSource()); + List resolvedShaderNodes = new ArrayList<>(); - for (ShaderDependencyNode dependencyNode : node.getDependencies()) { - resolvedShaderNodes.add(resolveDependencies(dependencyNode, alreadyInjectedSet, extensions)); - } - List injectIndices = node.getDependencyInjectIndices(); - for (int i = resolvedShaderNodes.size() - 1; i >= 0; i--) { - // Must insert them backwards .. - sb.insert(injectIndices.get(i), resolvedShaderNodes.get(i)); + for (ShaderDependencyNode dependencyNode : node.getDependencies()) { + resolvedShaderNodes.add(resolveDependencies(dependencyNode, alreadyInjectedSet, extensions, injectDependencies)); + } + + List injectIndices = node.getDependencyInjectIndices(); + for (int i = resolvedShaderNodes.size() - 1; i >= 0; i--) { + // Must insert them backwards .. + sb.insert(injectIndices.get(i), resolvedShaderNodes.get(i)); + } + return sb.toString(); + } else { + for (ShaderDependencyNode dependencyNode : node.getDependencies()) { + resolveDependencies(dependencyNode, alreadyInjectedSet, extensions, injectDependencies); + } + return null; } - return sb.toString(); + } } @@ -181,6 +187,10 @@ public class GLSLLoader implements AssetLoader { // to retrieve the fragment shader, use the content manager this.assetManager = info.getManager(); Reader reader = new InputStreamReader(info.openStream()); + boolean injectDependencies = true; + if (info.getKey() instanceof ShaderAssetKey) { + injectDependencies = ((ShaderAssetKey) info.getKey()).isInjectDependencies(); + } if (info.getKey().getExtension().equals("glsllib")) { // NOTE: Loopback, GLSLLIB is loaded by this loader // and needs data as InputStream @@ -188,10 +198,25 @@ public class GLSLLoader implements AssetLoader { } else { ShaderDependencyNode rootNode = loadNode(reader, "[main]"); StringBuilder extensions = new StringBuilder(); - String code = resolveDependencies(rootNode, new HashSet(), extensions); - extensions.append(code); - dependCache.clear(); - return extensions.toString(); + if (injectDependencies) { + String code = resolveDependencies(rootNode, new HashSet(), extensions, injectDependencies); + extensions.append(code); + dependCache.clear(); + return extensions.toString(); + } else { + Map files = new LinkedHashMap<>(); + HashSet dependencies = new HashSet<>(); + String code = resolveDependencies(rootNode, dependencies, extensions, injectDependencies); + extensions.append(code); + files.put("[main]", extensions.toString()); + + for (ShaderDependencyNode dependency : dependencies) { + files.put(dependency.getName(), dependency.getSource()); + } + + dependCache.clear(); + return files; + } } } } diff --git a/jme3-core/src/plugins/java/com/jme3/shader/plugins/ShaderAssetKey.java b/jme3-core/src/plugins/java/com/jme3/shader/plugins/ShaderAssetKey.java new file mode 100644 index 000000000..e27d92539 --- /dev/null +++ b/jme3-core/src/plugins/java/com/jme3/shader/plugins/ShaderAssetKey.java @@ -0,0 +1,24 @@ +package com.jme3.shader.plugins; + +import com.jme3.asset.AssetKey; + +/** + * Created by Nehon on 28/10/2017. + */ +public class ShaderAssetKey extends AssetKey { + + private boolean injectDependencies = false; + + public ShaderAssetKey(String name, boolean injectDependencies) { + super(name); + this.injectDependencies = injectDependencies; + } + + public boolean isInjectDependencies() { + return injectDependencies; + } + + public void setInjectDependencies(boolean injectDependencies) { + this.injectDependencies = injectDependencies; + } +}