/*******************************************************************************
* Breakout Cave Survey Visualizer
*
* Copyright (C) 2014 James Edwards
*
* jedwards8 at fastmail dot fm
*
* This program is free software; you can redistribute it and/or modify it under
* the terms of the GNU General Public License as published by the Free Software
* Foundation; either version 2 of the License, or (at your option) any later
* version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
* details.
*
* You should have received a copy of the GNU General Public License along with
* this program; if not, write to the Free Software Foundation, Inc., 51
* Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*******************************************************************************/
package org.andork.jogl.shadelet;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public abstract class Shadelet {
protected static Pattern PROPERTY_PATTERN = Pattern.compile("\\$(\\$|[a-zA-Z_][a-zA-Z0-9_]*)");
protected static Pattern VARIABLE_PATTERN = Pattern
.compile("([a-zA-Z_][a-zA-Z0-9_]*)\\s*(\\[\\s*(\\S+)\\s*\\])?\\s*;");
protected static Pattern VARIABLE_DECL_PATTERN = Pattern.compile(
"(/\\*\\s*(vertex|fragment)\\s*\\*/)?\\s*(uniform|attribute|varying)?\\s*([a-zA-Z][a-zA-Z0-9_]+)\\s*([a-zA-Z_][a-zA-Z0-9_]*)\\s*(\\[\\s*(\\S+)\\s*\\])?\\s*;");
protected static Pattern VERTEX_COMMENT_PATTERN = Pattern.compile("/\\*\\s*vertex\\s*\\*/");
protected static Pattern FRAGMENT_COMMENT_PATTERN = Pattern.compile("/\\*\\s*fragment\\s*\\*/");
private static Pattern STATEMENT_PATTERN = Pattern.compile("^\\s*([^{};]+)\\s*;");
private static Pattern BLOCK_START_PATTERN = Pattern
.compile("^\\s*(for\\s*\\(\\s*[^{};]*\\s*;\\s*[^{};]*\\s*;\\s*[^{};]*\\s*\\)|[^{};]+)\\s*\\{");
private static Pattern BLOCK_END_PATTERN = Pattern.compile("^\\s*\\}");
public static void main(String[] args) {
Matcher m = VARIABLE_DECL_PATTERN.matcher("uniform float a[ hello]; // test");
m.find();
System.out.println(m.group());
System.out.println(m.group(1));
System.out.println(m.group(2));
System.out.println(m.group(3));
System.out.println(m.group(4));
System.out.println(m.group(5));
System.out.println(m.group(6));
System.out.println(prettyPrint(
"int test; void main() { // this is a test\n test = test1; test2 = test3; for (x = 1; ; x++) { int test3; } }"));
}
public static String prettyPrint(String code) {
StringBuffer sb = new StringBuffer();
String tabs = "";
Matcher m;
while (code.length() > 0) {
m = BLOCK_START_PATTERN.matcher(code);
if (m.find()) {
sb.append(tabs).append(m.group(1)).append('\n').append(tabs).append("{\n");
tabs += " ";
code = code.substring(m.end());
continue;
}
m = STATEMENT_PATTERN.matcher(code);
if (m.find()) {
int i = 0;
for (String s : m.group(1).split("\\s*\r\n|\n\r|\r|\n\\s*")) {
if (i++ > 0) {
sb.append('\n');
}
sb.append(tabs).append(s);
}
sb.append(";\n");
code = code.substring(m.end());
continue;
}
m = BLOCK_END_PATTERN.matcher(code);
if (m.find()) {
tabs = tabs.substring(2);
sb.append(tabs).append("}\n");
code = code.substring(m.end());
continue;
}
sb.append(code);
code = "";
}
return sb.toString();
}
protected static String variableKey(String variableDecl) {
Matcher m = VARIABLE_PATTERN.matcher(variableDecl);
if (m.find()) {
return m.group(1);
}
return variableDecl;
}
private final Map<String, Object> properties = new HashMap<String, Object>();
public String createFragmentShaderCode() {
StringBuffer sb = new StringBuffer();
for (String variableDecl : getFragmentShaderVariableDecls()) {
sb.append(variableDecl);
}
sb.append("void main() {");
for (String variableDecl : getFragmentShaderLocalDecls()) {
sb.append(variableDecl);
}
sb.append(getFragmentShaderMainCode()).append('}');
for (String functionDecl : getFragmentShaderFunctionDecls()) {
sb.append(functionDecl);
}
return replaceProperties(sb.toString());
}
public String createVertexShaderCode() {
StringBuffer sb = new StringBuffer();
for (String variableDecl : getVertexShaderVariableDecls()) {
sb.append(variableDecl);
}
sb.append("void main() {");
for (String variableDecl : getVertexShaderLocalDecls()) {
sb.append(variableDecl);
}
sb.append(getVertexShaderMainCode()).append('}');
for (String functionDecl : getVertexShaderFunctionDecls()) {
sb.append(functionDecl);
}
return replaceProperties(sb.toString());
}
protected List<String> getDefaultVariableDecls(boolean forVertex, boolean forFragment, boolean forLocal) {
List<String> result = new ArrayList<String>();
for (Map.Entry<String, Object> entry : properties.entrySet()) {
if (entry.getKey().endsWith("Declaration")) {
String declaration = replaceProperties("$" + entry.getKey());
Matcher m = VARIABLE_PATTERN.matcher(declaration);
if (m.find()) {
boolean varying = declaration.contains("varying");
boolean attribute = declaration.contains("attribute");
boolean uniform = declaration.contains("uniform");
boolean local = !varying && !attribute && !uniform;
boolean vertexOnly = VERTEX_COMMENT_PATTERN.matcher(declaration).find();
boolean fragmentOnly = FRAGMENT_COMMENT_PATTERN.matcher(declaration).find();
if (local == forLocal &&
(forVertex || !attribute) &&
(forVertex && !fragmentOnly ||
forFragment && !vertexOnly)) {
if (vertexOnly) {
declaration = declaration.replaceAll(VERTEX_COMMENT_PATTERN.pattern(), "");
}
if (fragmentOnly) {
declaration = declaration.replaceAll(FRAGMENT_COMMENT_PATTERN.pattern(), "");
}
result.add(declaration);
}
}
}
}
return result;
}
public Collection<String> getFragmentShaderFunctionDecls() {
return Collections.emptyList();
}
public Collection<String> getFragmentShaderLocalDecls() {
return getDefaultVariableDecls(false, true, true);
}
public String getFragmentShaderMainCode() {
return "";
}
public Collection<String> getFragmentShaderVariableDecls() {
return getDefaultVariableDecls(false, true, false);
}
public Collection<String> getVertexShaderFunctionDecls() {
return Collections.emptyList();
}
public Collection<String> getVertexShaderLocalDecls() {
return getDefaultVariableDecls(true, false, true);
}
public String getVertexShaderMainCode() {
return "";
}
public Collection<String> getVertexShaderVariableDecls() {
return getDefaultVariableDecls(true, false, false);
}
protected final List<String> replaceProperties(Collection<String> text) {
List<String> result = new ArrayList<String>();
for (String s : text) {
result.add(replaceProperties(s));
}
return result;
}
protected final String replaceProperties(String text) {
StringBuilder sb = new StringBuilder();
int lastEnd = 0;
Matcher m = PROPERTY_PATTERN.matcher(text);
while (m.find()) {
sb.append(text.substring(lastEnd, m.start()));
String prop = m.group(1);
if ("$".equals(prop)) {
sb.append('$');
} else {
Object value = properties.get(prop);
if (value != null) {
sb.append(replaceProperties(value.toString()));
}
}
lastEnd = m.end();
}
sb.append(text.substring(lastEnd));
return sb.toString();
}
protected final void setProperty(String propertyName, Object value) {
properties.put(propertyName, value);
}
}