@ -34,13 +34,17 @@ package com.jme3.shader.plugins;
import com.jme3.asset.AssetInfo ;
import com.jme3.asset.AssetInfo ;
import com.jme3.asset.AssetKey ;
import com.jme3.asset.AssetKey ;
import com.jme3.asset.AssetLoadException ;
import com.jme3.asset.AssetLoader ;
import com.jme3.asset.AssetLoader ;
import com.jme3.asset.AssetManager ;
import com.jme3.asset.AssetManager ;
import com.jme3.asset.cache.AssetCache ;
import com.jme3.asset.cache.AssetCache ;
import com.jme3.asset.plugins.ClasspathLocator ;
import com.jme3.system.JmeSystem ;
import java.io.BufferedReader ;
import java.io.BufferedReader ;
import java.io.IOException ;
import java.io.IOException ;
import java.io.InputStream ;
import java.io.InputStream ;
import java.io.InputStreamReader ;
import java.io.InputStreamReader ;
import java.io.Reader ;
import java.util.* ;
import java.util.* ;
/ * *
/ * *
@ -48,39 +52,16 @@ import java.util.*;
* /
* /
public class GLSLLoader implements AssetLoader {
public class GLSLLoader implements AssetLoader {
private AssetManager own er;
private AssetManager assetManag er;
private Map < String , DependencyNode > dependCache = new HashMap < String , DependencyNode > ( ) ;
private Map < String , Shader DependencyNode> dependCache = new HashMap < String , Shader DependencyNode> ( ) ;
private class DependencyNode {
/ * *
* Used to load { @link ShaderDependencyNode } s .
private String shaderSource ;
* Asset caching is disabled .
private String shaderName ;
* /
private class ShaderDependencyKey extends AssetKey < Reader > {
private final Set < DependencyNode > dependsOn = new HashSet < DependencyNode > ( ) ;
private final Set < DependencyNode > dependOnMe = new HashSet < DependencyNode > ( ) ;
public DependencyNode ( String shaderName ) {
this . shaderName = shaderName ;
}
public void setSource ( String source ) {
this . shaderSource = source ;
}
public void addDependency ( DependencyNode node ) {
if ( this . dependsOn . contains ( node ) )
return ; // already contains dependency
// System.out.println(shaderName + " depend on "+node.shaderName);
this . dependsOn . add ( node ) ;
node . dependOnMe . add ( this ) ;
}
}
private class GlslDependKey extends AssetKey < InputStream > {
public GlslDepend Key( String name ) {
public ShaderDependencyKey ( String name ) {
super ( name ) ;
super ( name ) ;
}
}
@ -91,124 +72,119 @@ public class GLSLLoader implements AssetLoader {
}
}
}
}
private DependencyNode loadNode ( InputStream in , String nodeName ) throws IOException {
/ * *
DependencyNode node = new DependencyNode ( nodeName ) ;
* Creates a { @link ShaderDependencyNode } from a stream representing shader code .
if ( in = = null )
*
throw new IOException ( "Dependency " + nodeName + " cannot be found." ) ;
* @param in The input stream containing shader code
* @param nodeName
* @return
* @throws IOException
* /
private ShaderDependencyNode loadNode ( Reader reader , String nodeName ) {
ShaderDependencyNode node = new ShaderDependencyNode ( nodeName ) ;
StringBuilder sb = new StringBuilder ( ) ;
StringBuilder sb = new StringBuilder ( ) ;
BufferedReader r = new BufferedReader ( new InputStreamReader ( in ) ) ;
BufferedReader bufReader = new BufferedReader ( reader ) ;
while ( r . ready ( ) ) {
try {
String ln = r . readLine ( ) ;
while ( bufReader . ready ( ) ) {
if ( ln . startsWith ( "#import " ) ) {
String ln = bufReader . readLine ( ) ;
ln = ln . substring ( 8 ) . trim ( ) ;
if ( ln . trim ( ) . startsWith ( "#import " ) ) {
if ( ln . startsWith ( "\"" ) & & ln . endsWith ( "\"" ) & & ln . length ( ) > 3 ) {
ln = ln . trim ( ) . substring ( 8 ) . trim ( ) ;
if ( ln . startsWith ( "\"" ) & & ln . endsWith ( "\"" ) & & ln . length ( ) > 3 ) {
// import user code
// import user code
// remove quotes to get filename
// remove quotes to get filename
ln = ln . substring ( 1 , ln . length ( ) - 1 ) ;
ln = ln . substring ( 1 , ln . length ( ) - 1 ) ;
if ( ln . equals ( nodeName ) )
if ( ln . equals ( nodeName ) ) {
throw new IOException ( "Node depends on itself." ) ;
throw new IOException ( "Node depends on itself." ) ;
}
// check cache first
// check cache first
DependencyNode dependNode = dependCache . get ( ln ) ;
ShaderDependencyNode dependNode = dependCache . get ( ln ) ;
if ( dependNode = = null ) {
GlslDependKey key = new GlslDependKey ( ln ) ;
if ( dependNode = = null ) {
// make sure not to register an input stream with
Reader dependNodeReader = assetManager . loadAsset ( new ShaderDependencyKey ( ln ) ) ;
// the cache..
dependNode = loadNode ( dependNodeReader , ln ) ;
InputStream stream = ( InputStream ) owner . loadAsset ( key ) ;
}
dependNode = loadNode ( stream , ln ) ;
}
node . addDependency ( sb . length ( ) , dependNode ) ;
node . addDependency ( dependNode ) ;
}
}
} else {
// }else if (ln.startsWith("uniform") || ln.startsWith("varying") || ln.startsWith("attribute")){
// // these variables are included as dependencies as well
// DependencyNode dependNode = dependCache.get(ln);
// if (dependNode == null){
// // the source and name are the same for variable dependencies
// dependNode = new DependencyNode(ln);
// dependNode.setSource(ln);
// dependCache.put(ln, dependNode);
// }
// node.addDependency(dependNode);
} else {
sb . append ( ln ) . append ( '\n' ) ;
sb . append ( ln ) . append ( '\n' ) ;
}
}
}
}
r . close ( ) ;
} catch ( IOException ex ) {
if ( bufReader ! = null ) {
try {
bufReader . close ( ) ;
} catch ( IOException ex1 ) {
}
}
throw new AssetLoadException ( "Failed to load shader node: " + nodeName , ex ) ;
}
node . setSource ( sb . toString ( ) ) ;
node . setSource ( sb . toString ( ) ) ;
dependCache . put ( nodeName , node ) ;
dependCache . put ( nodeName , node ) ;
return node ;
return node ;
}
}
private DependencyNode nextIndependentNode ( List < DependencyNode > checkedNodes ) {
private ShaderDependencyNode nextIndependentNode ( ) throws IOException {
Collection < DependencyNode > allNodes = dependCache . values ( ) ;
Collection < ShaderDependencyNode > allNodes = dependCache . values ( ) ;
if ( allNodes = = null | | allNodes . isEmpty ( ) )
if ( allNodes = = null | | allNodes . isEmpty ( ) ) {
return null ;
return null ;
}
for ( DependencyNode node : allNodes ) {
for ( Shader DependencyNode node : allNodes ) {
if ( node . dependsOn . isEmpty ( ) ) {
if ( node . getDependOnMe ( ) . isEmpty ( ) ) {
return node ;
return node ;
}
}
}
}
// circular dependency found..
// Circular dependency found..
for ( DependencyNode node : allNodes ) {
for ( ShaderDependencyNode node : allNodes ) {
System . out . println ( node . shaderName ) ;
System . out . println ( node . getName ( ) ) ;
}
throw new RuntimeException ( "Circular dependency." ) ;
}
}
private String resolveDependencies ( DependencyNode root ) {
throw new IOException ( "Circular dependency." ) ;
StringBuilder sb = new StringBuilder ( ) ;
}
List < DependencyNode > checkedNodes = new ArrayList < DependencyNode > ( ) ;
checkedNodes . add ( root ) ;
while ( true ) {
DependencyNode indepnNode = nextIndependentNode ( checkedNodes ) ;
if ( indepnNode = = null )
break ;
sb . append ( indepnNode . shaderSource ) . append ( '\n' ) ;
dependCache . remove ( indepnNode . shaderName ) ;
// take out this dependency
private String resolveDependencies ( ShaderDependencyNode node , Set < ShaderDependencyNode > alreadyInjectedSet ) {
for ( Iterator < DependencyNode > iter = indepnNode . dependOnMe . iterator ( ) ;
if ( alreadyInjectedSet . contains ( node ) ) {
iter . hasNext ( ) ; ) {
return "// " + node . getName ( ) + " was already injected at the top.\n" ;
DependencyNode dependNode = iter . next ( ) ;
} else {
iter . remove ( ) ;
alreadyInjectedSet . add ( node ) ;
dependNode . dependsOn . remove ( indepnNode ) ;
}
}
if ( node . getDependencies ( ) . isEmpty ( ) ) {
return node . getSource ( ) ;
} else {
StringBuilder sb = new StringBuilder ( node . getSource ( ) ) ;
List < String > resolvedShaderNodes = new ArrayList < String > ( ) ;
for ( ShaderDependencyNode dependencyNode : node . getDependencies ( ) ) {
resolvedShaderNodes . add ( resolveDependencies ( dependencyNode , alreadyInjectedSet ) ) ;
}
List < Integer > injectIndices = node . getDependencyInjectIndices ( ) ;
for ( int i = resolvedShaderNodes . size ( ) - 1 ; i > = 0 ; i - - ) {
// Must insert them backwards ..
sb . insert ( injectIndices . get ( i ) , resolvedShaderNodes . get ( i ) ) ;
}
}
// System.out.println(sb.toString());
// System.out.println("--------------------------------------------------");
return sb . toString ( ) ;
return sb . toString ( ) ;
}
}
}
/ * *
*
* @param info
* @return String of GLSL code
* @throws java . io . IOException
* /
public Object load ( AssetInfo info ) throws IOException {
public Object load ( AssetInfo info ) throws IOException {
// The input stream provided is for the vertex shader,
// The input stream provided is for the vertex shader,
// to retrieve the fragment shader, use the content manager
// to retrieve the fragment shader, use the content manager
this . owner = info . getManager ( ) ;
this . assetManager = info . getManager ( ) ;
if ( info . getKey ( ) . getExtension ( ) . equals ( "glsllib" ) ) {
Reader reader = new InputStreamReader ( info . openStream ( ) ) ;
if ( info . getKey ( ) . getExtension ( ) . equals ( "glsllib" ) ) {
// NOTE: Loopback, GLSLLIB is loaded by this loader
// NOTE: Loopback, GLSLLIB is loaded by this loader
// and needs data as InputStream
// and needs data as InputStream
return info . openStream ( ) ;
return reader ;
} else {
} else {
// GLSLLoader wants result as String for
ShaderDependencyNode rootNode = loadNode ( reader , "[main]" ) ;
// fragment shader
String code = resolveDependencies ( rootNode , new HashSet < ShaderDependencyNode > ( ) ) ;
DependencyNode rootNode = loadNode ( info . openStream ( ) , "[main]" ) ;
String code = resolveDependencies ( rootNode ) ;
dependCache . clear ( ) ;
dependCache . clear ( ) ;
return code ;
return code ;
}
}
}
}
}
}