/*
*Created on 25. Aug 2007, 17:07
*/
package com.mbien.engine.glsl;
import java.util.ArrayList;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Abstract shader source loader.
* @author Michael Bien
*/
public abstract class ShaderSourceLoader<T> {
private final static Pattern includePattern = Pattern.compile("//import\\s+((?:\\w|/|.)+)\\s*");
public abstract CodeFragment<T> loadShaderSource(T t);
public abstract CodeFragment<T> loadShaderSource(String filePath);
public abstract boolean sameSource(T t, String path);
public final CodeFragment<T>[] loadWithDependencies(String filePath) {
CodeFragment<T> main = loadShaderSource(filePath);
return loadWithDependencies(main, parent(filePath));
}
public final CodeFragment<T>[] loadWithDependencies(CodeFragment<T> main, String path) {
ArrayList<CodeFragment<T>> fragments = new ArrayList<CodeFragment<T>>();
includeAllDependencies(main, path, fragments);
// copy to array in reverse order
CodeFragment[] fragmentArray = new CodeFragment[fragments.size()];
for(int i = 0; i < fragmentArray.length; i++) {
fragmentArray[i] = fragments.get(fragmentArray.length-i-1);
}
return fragmentArray;
}
/**
* concatenates shaders recursively - deepest first.
*/
private final void includeAllDependencies(CodeFragment<T> fragment, String sourcePackage, ArrayList<CodeFragment<T>> fragments) {
fragments.add(fragment);
Matcher matcher = includePattern.matcher(fragment.source);
while (matcher.find()) {
String include = matcher.group(1);
String path = sourcePackage;
while(include.startsWith("../")) {
include = include.substring(3);
path = parent(path);
}
path += "/" + include;
// check if already included
boolean alreadyIncluded = false;
for (int i = 0; i < fragments.size(); i++) {
CodeFragment<T> codeFragment = fragments.get(i);
// if included, move code fragment to end of list
if(sameSource(codeFragment.sourceObj, path)) {
fragments.add(fragments.size()-1, fragments.remove(i));
alreadyIncluded = true;
break;
}
}
if(!alreadyIncluded) {
CodeFragment<T> srcToInclude = loadShaderSource(path);
if(srcToInclude != null) {
includeAllDependencies(srcToInclude, path.substring(0, path.lastIndexOf("/")), fragments);
}
}
}
}
/**
* goto parent folder
*/
protected final String parent(String path) {
for(int i = path.length()-1; i >= 0; i--) {
if(path.charAt(i) == '/') {
return path.substring(0, i);
}
}
return path;
}
}