";
+ private String BUILD_IN_VAR_COLOR = "";
+ private String KEYWORD_COLOR = "";
+
+ private int priority;
+
+ public GlslCompletionItem(String key, GLSLElementDescriptor content, String prefix, int carretPosition) {
+
+ this.key = key;
+ this.content = content;
+ this.prefix = prefix;
+ this.carretPosition = carretPosition;
+
+ leftText = createLeftText();
+ rightText = content.type;
+
+ // low prority is first in completion list
+ switch (content.category) {
+ case TYPE:
+ priority = 10;
+ break;
+ case JUMP:
+ priority = 9;
+ break;
+ case SELECTION:
+ priority = 8;
+ break;
+ case ITERATION:
+ priority = 7;
+ break;
+ case KEYWORD:
+ priority = 6;
+ break;
+ case QUALIFIER:
+ priority = 5;
+ break;
+ case BUILD_IN_FUNC:
+ priority = 4;
+ break;
+ case BUILD_IN_VAR:
+ priority = 3;
+ break;
+ }
+ }
+
+ private String createLeftText() {
+
+ StringBuilder text = new StringBuilder();
+
+ switch (content.category) {
+ case TYPE:
+ case JUMP:
+ case SELECTION:
+ case ITERATION:
+ case KEYWORD:
+ case QUALIFIER:
+ text.append(KEYWORD_COLOR);
+ break;
+ case BUILD_IN_VAR:
+ text.append(BUILD_IN_VAR_COLOR);
+ break;
+ }
+
+ text.append("");
+ text.append(key);
+ text.append("");
+
+ if (content.arguments != null) {
+ text.append(ARGUMENTS_COLOR);
+ text.append(content.arguments);
+ text.append("");
+ }
+ return text.toString();
+ }
+
+ public void defaultAction(JTextComponent component) {
+ Completion.get().hideAll();
+ // replace prefix with key
+ try {
+ component.getDocument().remove(carretPosition-prefix.length(), prefix.length());
+ component.getDocument().insertString(carretPosition-prefix.length(), key, null);
+ } catch (BadLocationException e) {
+ LOGGER.notify(e);
+ }
+ }
+
+ public void processKeyEvent(KeyEvent evt) {
+ // TODO: if "." then Completion.get().showCompletion()
+ }
+
+ public int getPreferredWidth(Graphics g, Font defaultFont) {
+ return CompletionUtilities.getPreferredWidth(leftText, rightText, g, defaultFont);
+ }
+
+ public void render(Graphics g, Font defaultFont, Color defaultColor, Color backgroundColor, int width, int height, boolean selected) {
+
+ CompletionUtilities.renderHtml(null, leftText, rightText, g, defaultFont, defaultColor, width, height, selected);
+
+ }
+
+ public CompletionTask createDocumentationTask() {
+
+ if (content.doc == null) {
+ return null;
+ }
+
+ return new AsyncCompletionTask(new AsyncCompletionQuery() {
+ private GlslDocItem item = new GlslDocItem(key, content);
+
+ protected void query(CompletionResultSet completionResultSet, Document document, int i) {
+ completionResultSet.setDocumentation(item);
+ completionResultSet.finish();
+ }
+ });
+ }
+
+ public CompletionTask createToolTipTask() {
+ return null;
+ }
+
+ public boolean instantSubstitution(JTextComponent component) {
+ defaultAction(component);
+ return true;
+ }
+
+ public int getSortPriority() {
+ return priority;
+ }
+
+ public CharSequence getSortText() {
+ return key;
+ }
+
+ public CharSequence getInsertPrefix() {
+ return prefix;
+ }
+ }
+
+ private static class GlslDocItem implements CompletionDocumentation {
+
+ private String text;
+
+ public GlslDocItem(String item, GLSLElementDescriptor content) {
+
+ StringBuilder sb = new StringBuilder();
+ sb.append("");
+ if(content.type != null) {
+ sb.append(content.type);
+ sb.append(" ");
+ }
+ sb.append("");
+ sb.append(item);
+ sb.append("");
+ if(content.arguments != null) {
+ sb.append(content.arguments);
+ }
+ sb.append("
");
+ sb.append(content.doc);
+ sb.append("
");
+
+ text = sb.toString();
+ }
+
+ public String getText() {
+ return text;
+ }
+
+ public URL getURL() {
+ return null;
+ }
+
+ public CompletionDocumentation resolveLink(String link) {
+ return null;
+ }
+
+ public Action getGotoSourceAction() {
+ return null;
+ }
+ }
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/GlslShaderFileObserver.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/GlslShaderFileObserver.java
new file mode 100644
index 000000000..2bd30a671
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/GlslShaderFileObserver.java
@@ -0,0 +1,65 @@
+package net.java.nboglpack.glsleditor;
+
+/**
+ * Created on 26. March 2007, 00:49
+ *
+ */
+
+import javax.swing.event.DocumentEvent;
+import javax.swing.event.DocumentListener;
+//import net.java.nboglpack.glslcompiler.GLSLCompilerService;
+import org.openide.loaders.DataObject;
+import org.openide.util.Lookup;
+import org.openide.util.RequestProcessor;
+
+/**
+ * Observes an DataObject for document updates and starts compilation automatically.
+ * @author Michael Bien
+ */
+public class GlslShaderFileObserver implements DocumentListener {
+
+ private final DataObject observedDao;
+ private final static RequestProcessor RP = new RequestProcessor("compiler");
+ private final RequestProcessor.Task compilerTask;
+ private boolean runOnDocUpdate = true;
+ private int compileDelay = 500;
+
+ public GlslShaderFileObserver(DataObject dao) {
+ observedDao = dao;
+
+ compilerTask = RP.create(new Runnable() {
+ public void run() {
+// GLSLCompilerService compiler = Lookup.getDefault().lookup(GLSLCompilerService.class);
+// compiler.compileShader(new DataObject[] {observedDao}, false);
+ }
+ });
+ compilerTask.setPriority(Thread.MIN_PRIORITY);
+ }
+
+
+ // DocumentListener
+ public void insertUpdate(DocumentEvent arg0) {
+ if(runOnDocUpdate)
+ runCompileTask();
+ }
+ public void removeUpdate(DocumentEvent arg0) {
+ if(runOnDocUpdate)
+ runCompileTask();
+ }
+ public void changedUpdate(DocumentEvent arg0) {
+ }
+
+
+ public final void runCompileTask() {
+ compilerTask.schedule(compileDelay);
+ }
+
+ public void setCompileDelay(int compileDelay) {
+ this.compileDelay = compileDelay;
+ }
+
+ public void setRunOnDocUpdate(boolean runOnDocUpdate) {
+ this.runOnDocUpdate = runOnDocUpdate;
+ }
+
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/GlslVocabularyManager.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/GlslVocabularyManager.java
new file mode 100644
index 000000000..98078f36e
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/GlslVocabularyManager.java
@@ -0,0 +1,172 @@
+/*
+ * GlslVocabularyManager.java
+ *
+ * Created on 12. Februar 2006, 03:37
+ *
+ */
+
+package net.java.nboglpack.glsleditor;
+
+import java.io.InputStream;
+import java.util.AbstractSet;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.Map;
+import java.util.Set;
+import javax.xml.bind.JAXBContext;
+import javax.xml.bind.Unmarshaller;
+import net.java.nboglpack.glsleditor.dataobject.GlslFragmentShaderDataLoader;
+import net.java.nboglpack.glsleditor.dataobject.GlslGeometryShaderDataLoader;
+import net.java.nboglpack.glsleditor.dataobject.GlslVertexShaderDataLoader;
+import net.java.nboglpack.glsleditor.vocabulary.GLSLElementDescriptor;
+import net.java.nboglpack.glsleditor.vocabulary.GLSLVocabulary;
+import org.openide.ErrorManager;
+import org.openide.filesystems.FileObject;
+import org.openide.filesystems.FileUtil;
+
+/**
+ *
+ * @author mhenze
+ * @author Michael Bien
+ */
+public class GlslVocabularyManager {
+
+ private static final ErrorManager LOGGER = ErrorManager.getDefault().getInstance(GlslVocabularyManager.class.getName());
+ private static final HashMap instances = new HashMap();
+ private static GLSLVocabulary vocabulary = null;
+
+ private final String mimetype;
+ private final Set keySet;
+ private final Map vocabularyExtention;
+
+ /** Creates a new instance of GlslVocabularyManager */
+ private GlslVocabularyManager(String mimetype) {
+
+ if( !mimetype.equals(GlslFragmentShaderDataLoader.REQUIRED_MIME)
+ && !mimetype.equals(GlslVertexShaderDataLoader.REQUIRED_MIME)
+ && !mimetype.equals(GlslGeometryShaderDataLoader.REQUIRED_MIME)) {
+ throw new IllegalArgumentException(mimetype+" is no GLSL mime type");
+ }
+
+
+ this.mimetype = mimetype;
+
+ if(vocabulary == null)
+ loadVocabulary();
+
+ if(mimetype.equals(GlslFragmentShaderDataLoader.REQUIRED_MIME)) {
+ vocabularyExtention = vocabulary.fragmentShaderVocabulary;
+ }else if(mimetype.equals(GlslVertexShaderDataLoader.REQUIRED_MIME)) {
+ vocabularyExtention = vocabulary.vertexShaderVocabulary;
+ }else {
+ vocabularyExtention = vocabulary.geometryShaderVocabulary;
+ }
+
+ // merges two views
+ keySet = new AbstractSet() {
+
+ private final Set mainSet = vocabulary.mainVocabulary.keySet();
+ private final Set extSet = vocabularyExtention.keySet();
+
+
+ public Iterator iterator() {
+ return new Iterator(){
+
+ Iterator mainIt = mainSet.iterator();
+ Iterator extIt = extSet.iterator();
+
+ public boolean hasNext() {
+ return mainIt.hasNext() || extIt.hasNext();
+ }
+
+ public String next() {
+ if(mainIt.hasNext())
+ return mainIt.next();
+ else
+ return extIt.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException("Not supported yet.");
+ }
+
+ };
+ }
+
+ public int size() {
+ return mainSet.size()+extSet.size();
+ }
+
+ };
+
+ }
+
+ public static GlslVocabularyManager getInstance(String mimetype) {
+
+ GlslVocabularyManager instance = instances.get(mimetype);
+
+ if(instance == null) {
+ instance = new GlslVocabularyManager(mimetype);
+ instances.put(mimetype,instance);
+ }
+
+ return instance;
+ }
+
+ private void loadVocabulary() {
+
+ FileObject vocabularyfile = FileUtil.getConfigFile("Editors/"+mimetype+"/vocabulary.xml");
+
+ if (vocabularyfile != null) {
+
+ InputStream is = null;
+
+ try {
+
+ is = vocabularyfile.getInputStream();
+
+ // workaround; nb does not allow usage of jdk's jaxb implementation
+ // => we have to provide JAXB as library wrapper module and load it via module classloader
+ JAXBContext jc = JAXBContext.newInstance("net.java.nboglpack.glsleditor.vocabulary", this.getClass().getClassLoader());
+
+ Unmarshaller unmarshaller = jc.createUnmarshaller();
+ vocabulary = (GLSLVocabulary)unmarshaller.unmarshal(is);
+
+ } catch (Exception ex) {
+
+ // create empty vocab
+ vocabulary = new GLSLVocabulary();
+ LOGGER.notify(ex);
+
+ } finally {
+
+ if(is != null) {
+ try {
+ is.close();
+ } catch (Exception e) {
+ LOGGER.notify(e);
+ }
+ }
+
+ }
+
+ }
+
+ }
+
+ public Set getKeys() {
+ return keySet;
+ }
+
+ public GLSLElementDescriptor[] getDesc(String key) {
+
+ GLSLElementDescriptor[] desc = vocabulary.mainVocabulary.get(key);
+
+ if(desc == null)
+ desc = vocabularyExtention.get(key);
+
+ return desc;
+ }
+
+
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/Bundle.properties b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/Bundle.properties
new file mode 100644
index 000000000..c5e2ea05a
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/Bundle.properties
@@ -0,0 +1,11 @@
+Services/MIMEResolver/GlslVertexShaderResolver.xml=GLSL Vertex Shader Files
+Services/MIMEResolver/GlslFragmentShaderResolver.xml=GLSL Fragment Shader Files
+Services/MIMEResolver/GlslGeometryShaderResolver.xml=GLSL Geometry Shader Files
+
+Templates/OpenGL/VertexShader.vert=GLSL Vertex Shader File
+Templates/OpenGL/FragmentShader.frag=GLSL Fragment Shader File
+Templates/OpenGL/GeometryShader.geom=GLSL Geometry Shader File
+
+LBL_glsl_vertex_shader_loader_name=GLSL Vertex Shader Files
+LBL_glsl_fragment_shader_loader_name=GLSL Fragment Shader Files
+LBL_glsl_geometry_shader_loader_name=GLSL Geometry Shader Files
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslFragmentShaderDataLoader.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslFragmentShaderDataLoader.java
new file mode 100644
index 000000000..45bbae64a
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslFragmentShaderDataLoader.java
@@ -0,0 +1,40 @@
+package net.java.nboglpack.glsleditor.dataobject;
+
+import java.io.IOException;
+import org.openide.filesystems.FileObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.MultiDataObject;
+import org.openide.loaders.UniFileLoader;
+import org.openide.util.NbBundle;
+
+public class GlslFragmentShaderDataLoader extends UniFileLoader {
+
+ public static final String REQUIRED_MIME = "text/x-glsl-fragment-shader";
+
+ private static final long serialVersionUID = 1L;
+
+ public GlslFragmentShaderDataLoader() {
+ super("net.java.nboglpack.glsleditor.dataobject.GlslFragmentShaderDataObject");
+ }
+
+ @Override
+ protected String defaultDisplayName() {
+ return NbBundle.getMessage(GlslFragmentShaderDataLoader.class, "LBL_glsl_fragment_shader_loader_name");
+ }
+
+ @Override
+ protected void initialize() {
+ super.initialize();
+ getExtensions().addMimeType(REQUIRED_MIME);
+ }
+
+ protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
+ return new GlslFragmentShaderDataObject(primaryFile, this);
+ }
+
+ @Override
+ protected String actionsContext() {
+ return "Loaders/" + REQUIRED_MIME + "/Actions";
+ }
+
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslFragmentShaderDataLoaderBeanInfo.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslFragmentShaderDataLoaderBeanInfo.java
new file mode 100644
index 000000000..1484e3065
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslFragmentShaderDataLoaderBeanInfo.java
@@ -0,0 +1,32 @@
+package net.java.nboglpack.glsleditor.dataobject;
+
+import java.awt.Image;
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.SimpleBeanInfo;
+import org.openide.loaders.UniFileLoader;
+import org.openide.util.ImageUtilities;
+
+public class GlslFragmentShaderDataLoaderBeanInfo extends SimpleBeanInfo {
+
+ public static final String IMAGE_ICON_BASE = "net/java/nboglpack/glsleditor/resources/FragmentShaderIcon.gif";
+
+ @Override
+ public BeanInfo[] getAdditionalBeanInfo() {
+ try {
+ return new BeanInfo[]{Introspector.getBeanInfo(UniFileLoader.class)};
+ } catch (IntrospectionException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public Image getIcon(int type) {
+ if (type == BeanInfo.ICON_COLOR_16x16 || type == BeanInfo.ICON_MONO_16x16) {
+ return ImageUtilities.loadImage(IMAGE_ICON_BASE);
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslFragmentShaderDataNode.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslFragmentShaderDataNode.java
new file mode 100644
index 000000000..7b65c9f10
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslFragmentShaderDataNode.java
@@ -0,0 +1,24 @@
+package net.java.nboglpack.glsleditor.dataobject;
+
+import org.openide.loaders.DataNode;
+import org.openide.nodes.Children;
+
+public class GlslFragmentShaderDataNode extends DataNode
+{
+ public GlslFragmentShaderDataNode(GlslFragmentShaderDataObject obj)
+ {
+ super(obj, Children.LEAF);
+ setIconBaseWithExtension(GlslFragmentShaderDataLoaderBeanInfo.IMAGE_ICON_BASE);
+ }
+// /** Creates a property sheet. */
+// protected Sheet createSheet() {
+// Sheet s = super.createSheet();
+// Sheet.Set ss = s.get(Sheet.PROPERTIES);
+// if (ss == null) {
+// ss = Sheet.createPropertiesSet();
+// s.put(ss);
+// }
+// // TODO add some relevant properties: ss.put(...)
+// return s;
+// }
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslFragmentShaderDataObject.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslFragmentShaderDataObject.java
new file mode 100644
index 000000000..01bff6b0e
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslFragmentShaderDataObject.java
@@ -0,0 +1,57 @@
+package net.java.nboglpack.glsleditor.dataobject;
+
+import net.java.nboglpack.glsleditor.GlslShaderFileObserver;
+import java.beans.PropertyChangeEvent;
+import java.io.IOException;
+import java.beans.PropertyChangeListener;
+import javax.swing.text.Document;
+import org.openide.filesystems.FileObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.MultiDataObject;
+import org.openide.nodes.CookieSet;
+import org.openide.nodes.Node;
+import org.openide.text.CloneableEditorSupport;
+import org.openide.text.DataEditorSupport;
+
+
+
+public class GlslFragmentShaderDataObject extends MultiDataObject {
+
+ private final GlslShaderFileObserver observer;
+
+ public GlslFragmentShaderDataObject(FileObject pf, GlslFragmentShaderDataLoader loader) throws DataObjectExistsException, IOException {
+
+ super(pf, loader);
+
+ CookieSet cookies = getCookieSet();
+ observer= new GlslShaderFileObserver(this);
+
+ final CloneableEditorSupport support= DataEditorSupport.create(this, getPrimaryEntry(), cookies);
+ support.addPropertyChangeListener(
+ new PropertyChangeListener(){
+ public void propertyChange(PropertyChangeEvent event) {
+ if("document".equals(event.getPropertyName())){
+ if(event.getNewValue()!=null)
+ {
+ support.getDocument().addDocumentListener(observer);
+ observer.runCompileTask();
+ }
+ else if(event.getOldValue()!=null)
+ {
+ // cylab: I think this is never called.
+ // But I don't know if unregistering the observer makes any difference...
+ ((Document)event.getOldValue()).removeDocumentListener(observer);
+ }
+ }
+ }
+ }
+ );
+ cookies.add((Node.Cookie) support);
+ }
+
+ @Override
+ protected Node createNodeDelegate() {
+ return new GlslFragmentShaderDataNode(this);
+ }
+
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslGeometryShaderDataLoader.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslGeometryShaderDataLoader.java
new file mode 100644
index 000000000..6b98e854a
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslGeometryShaderDataLoader.java
@@ -0,0 +1,44 @@
+package net.java.nboglpack.glsleditor.dataobject;
+
+import java.io.IOException;
+import org.openide.filesystems.FileObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.MultiDataObject;
+import org.openide.loaders.UniFileLoader;
+import org.openide.util.NbBundle;
+
+
+/**
+ * @author Michael Bien
+ */
+public class GlslGeometryShaderDataLoader extends UniFileLoader {
+
+ public static final String REQUIRED_MIME = "text/x-glsl-geometry-shader";
+
+ private static final long serialVersionUID = 1L;
+
+ public GlslGeometryShaderDataLoader() {
+ super("net.java.nboglpack.glsleditor.dataobject.GlslGeometryShaderDataObject");
+ }
+
+ @Override
+ protected String defaultDisplayName() {
+ return NbBundle.getMessage(GlslGeometryShaderDataLoader.class, "LBL_glsl_geometry_shader_loader_name");
+ }
+
+ @Override
+ protected void initialize() {
+ super.initialize();
+ getExtensions().addMimeType(REQUIRED_MIME);
+ }
+
+ protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
+ return new GlslGeometryShaderDataObject(primaryFile, this);
+ }
+
+ @Override
+ protected String actionsContext() {
+ return "Loaders/" + REQUIRED_MIME + "/Actions";
+ }
+
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslGeometryShaderDataLoaderBeanInfo.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslGeometryShaderDataLoaderBeanInfo.java
new file mode 100644
index 000000000..708b47a63
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslGeometryShaderDataLoaderBeanInfo.java
@@ -0,0 +1,37 @@
+package net.java.nboglpack.glsleditor.dataobject;
+
+import java.awt.Image;
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.SimpleBeanInfo;
+import org.openide.loaders.UniFileLoader;
+import org.openide.util.ImageUtilities;
+
+
+/**
+ * @author Michael Bien
+ */
+public class GlslGeometryShaderDataLoaderBeanInfo extends SimpleBeanInfo {
+
+ public static final String IMAGE_ICON_BASE = "net/java/nboglpack/glsleditor/resources/GeometryShaderIcon.gif";
+
+ @Override
+ public BeanInfo[] getAdditionalBeanInfo() {
+ try {
+ return new BeanInfo[] {Introspector.getBeanInfo(UniFileLoader.class)};
+ } catch (IntrospectionException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public Image getIcon(int type) {
+ if (type == BeanInfo.ICON_COLOR_16x16 || type == BeanInfo.ICON_MONO_16x16) {
+ return ImageUtilities.loadImage(IMAGE_ICON_BASE);
+ } else {
+ return null;
+ }
+ }
+
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslGeometryShaderDataNode.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslGeometryShaderDataNode.java
new file mode 100644
index 000000000..9706b7b31
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslGeometryShaderDataNode.java
@@ -0,0 +1,34 @@
+package net.java.nboglpack.glsleditor.dataobject;
+
+import org.openide.loaders.DataNode;
+import org.openide.nodes.Children;
+import org.openide.util.Lookup;
+
+
+/**
+ * @author Michael Bien
+ */
+public class GlslGeometryShaderDataNode extends DataNode {
+
+ public GlslGeometryShaderDataNode(GlslGeometryShaderDataObject obj) {
+ super(obj, Children.LEAF);
+ setIconBaseWithExtension(GlslGeometryShaderDataLoaderBeanInfo.IMAGE_ICON_BASE);
+ }
+ GlslGeometryShaderDataNode(GlslGeometryShaderDataObject obj, Lookup lookup) {
+ super(obj, Children.LEAF, lookup);
+ setIconBaseWithExtension(GlslGeometryShaderDataLoaderBeanInfo.IMAGE_ICON_BASE);
+ }
+
+ // /** Creates a property sheet. */
+ // protected Sheet createSheet() {
+ // Sheet s = super.createSheet();
+ // Sheet.Set ss = s.get(Sheet.PROPERTIES);
+ // if (ss == null) {
+ // ss = Sheet.createPropertiesSet();
+ // s.put(ss);
+ // }
+ // // TODO add some relevant properties: ss.put(...)
+ // return s;
+ // }
+
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslGeometryShaderDataObject.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslGeometryShaderDataObject.java
new file mode 100644
index 000000000..15acd890a
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslGeometryShaderDataObject.java
@@ -0,0 +1,60 @@
+package net.java.nboglpack.glsleditor.dataobject;
+
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.IOException;
+import javax.swing.text.Document;
+import net.java.nboglpack.glsleditor.GlslShaderFileObserver;
+import org.openide.filesystems.FileObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.MultiDataObject;
+import org.openide.nodes.CookieSet;
+import org.openide.nodes.Node;
+import org.openide.text.CloneableEditorSupport;
+import org.openide.util.Lookup;
+import org.openide.text.DataEditorSupport;
+
+
+/**
+ * @author Michael Bien
+ */
+public class GlslGeometryShaderDataObject extends MultiDataObject {
+
+ private GlslShaderFileObserver observer;
+
+ public GlslGeometryShaderDataObject(FileObject pf, GlslGeometryShaderDataLoader loader) throws DataObjectExistsException, IOException {
+
+ super(pf, loader);
+
+ CookieSet cookies = getCookieSet();
+ observer = new GlslShaderFileObserver(this);
+
+ final CloneableEditorSupport support = DataEditorSupport.create(this, getPrimaryEntry(), cookies);
+ support.addPropertyChangeListener(new PropertyChangeListener() {
+
+ public void propertyChange(PropertyChangeEvent event) {
+ if ("document".equals(event.getPropertyName())) {
+ if (event.getNewValue() != null) {
+ support.getDocument().addDocumentListener(observer);
+ observer.runCompileTask();
+ } else if (event.getOldValue() != null) {
+ // cylab: I think this is never called.
+ // But I don't know if unregistering the observer makes any difference...
+ ((Document) event.getOldValue()).removeDocumentListener(observer);
+ }
+ }
+ }
+ });
+ cookies.add((Node.Cookie) support);
+ }
+
+ @Override
+ protected Node createNodeDelegate() {
+ return new GlslGeometryShaderDataNode(this, getLookup());
+ }
+
+ @Override
+ public Lookup getLookup() {
+ return getCookieSet().getLookup();
+ }
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslVertexShaderDataLoader.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslVertexShaderDataLoader.java
new file mode 100644
index 000000000..252d55539
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslVertexShaderDataLoader.java
@@ -0,0 +1,40 @@
+package net.java.nboglpack.glsleditor.dataobject;
+
+import java.io.IOException;
+import org.openide.filesystems.FileObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.MultiDataObject;
+import org.openide.loaders.UniFileLoader;
+import org.openide.util.NbBundle;
+
+public class GlslVertexShaderDataLoader extends UniFileLoader {
+
+ public static final String REQUIRED_MIME = "text/x-glsl-vertex-shader";
+
+ private static final long serialVersionUID = 1L;
+
+ public GlslVertexShaderDataLoader() {
+ super("net.java.nboglpack.glsleditor.dataobject.GlslVertexShaderDataObject");
+ }
+
+ @Override
+ protected String defaultDisplayName() {
+ return NbBundle.getMessage(GlslFragmentShaderDataLoader.class, "LBL_glsl_vertex_shader_loader_name");
+ }
+
+ @Override
+ protected void initialize() {
+ super.initialize();
+ getExtensions().addMimeType(REQUIRED_MIME);
+ }
+
+ protected MultiDataObject createMultiObject(FileObject primaryFile) throws DataObjectExistsException, IOException {
+ return new GlslVertexShaderDataObject(primaryFile, this);
+ }
+
+ @Override
+ protected String actionsContext() {
+ return "Loaders/" + REQUIRED_MIME + "/Actions";
+ }
+
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslVertexShaderDataLoaderBeanInfo.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslVertexShaderDataLoaderBeanInfo.java
new file mode 100644
index 000000000..959d965bb
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslVertexShaderDataLoaderBeanInfo.java
@@ -0,0 +1,32 @@
+package net.java.nboglpack.glsleditor.dataobject;
+
+import java.awt.Image;
+import java.beans.BeanInfo;
+import java.beans.IntrospectionException;
+import java.beans.Introspector;
+import java.beans.SimpleBeanInfo;
+import org.openide.loaders.UniFileLoader;
+import org.openide.util.ImageUtilities;
+
+public class GlslVertexShaderDataLoaderBeanInfo extends SimpleBeanInfo {
+
+ public static final String IMAGE_ICON_BASE = "net/java/nboglpack/glsleditor/resources/VertexShaderIcon.gif";
+
+ @Override
+ public BeanInfo[] getAdditionalBeanInfo() {
+ try {
+ return new BeanInfo[]{Introspector.getBeanInfo(UniFileLoader.class)};
+ } catch (IntrospectionException e) {
+ throw new AssertionError(e);
+ }
+ }
+
+ @Override
+ public Image getIcon(int type) {
+ if (type == BeanInfo.ICON_COLOR_16x16 || type == BeanInfo.ICON_MONO_16x16) {
+ return ImageUtilities.loadImage(IMAGE_ICON_BASE);
+ } else {
+ return null;
+ }
+ }
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslVertexShaderDataNode.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslVertexShaderDataNode.java
new file mode 100644
index 000000000..25ca7e600
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslVertexShaderDataNode.java
@@ -0,0 +1,24 @@
+package net.java.nboglpack.glsleditor.dataobject;
+
+import org.openide.loaders.DataNode;
+import org.openide.nodes.Children;
+
+public class GlslVertexShaderDataNode extends DataNode
+{
+ public GlslVertexShaderDataNode(GlslVertexShaderDataObject obj)
+ {
+ super(obj, Children.LEAF);
+ setIconBaseWithExtension(GlslVertexShaderDataLoaderBeanInfo.IMAGE_ICON_BASE);
+ }
+// /** Creates a property sheet. */
+// protected Sheet createSheet() {
+// Sheet s = super.createSheet();
+// Sheet.Set ss = s.get(Sheet.PROPERTIES);
+// if (ss == null) {
+// ss = Sheet.createPropertiesSet();
+// s.put(ss);
+// }
+// // TODO add some relevant properties: ss.put(...)
+// return s;
+// }
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslVertexShaderDataObject.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslVertexShaderDataObject.java
new file mode 100644
index 000000000..c753284f2
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/dataobject/GlslVertexShaderDataObject.java
@@ -0,0 +1,54 @@
+package net.java.nboglpack.glsleditor.dataobject;
+
+import net.java.nboglpack.glsleditor.GlslShaderFileObserver;
+import net.java.nboglpack.glsleditor.GlslShaderFileObserver;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.io.IOException;
+import javax.swing.text.Document;
+import org.openide.filesystems.FileObject;
+import org.openide.loaders.DataObjectExistsException;
+import org.openide.loaders.MultiDataObject;
+import org.openide.nodes.CookieSet;
+import org.openide.nodes.Node;
+import org.openide.text.CloneableEditorSupport;
+import org.openide.text.DataEditorSupport;
+
+public class GlslVertexShaderDataObject extends MultiDataObject {
+
+ private GlslShaderFileObserver observer;
+
+ public GlslVertexShaderDataObject(FileObject pf, GlslVertexShaderDataLoader loader) throws DataObjectExistsException, IOException {
+
+ super(pf, loader);
+ CookieSet cookies = getCookieSet();
+ observer= new GlslShaderFileObserver(this);
+
+ final CloneableEditorSupport support= DataEditorSupport.create(this, getPrimaryEntry(), cookies);
+ support.addPropertyChangeListener(
+ new PropertyChangeListener(){
+ public void propertyChange(PropertyChangeEvent event) {
+ if("document".equals(event.getPropertyName())){
+ if(event.getNewValue()!=null)
+ {
+ support.getDocument().addDocumentListener(observer);
+ observer.runCompileTask();
+ }
+ else if(event.getOldValue()!=null)
+ {
+ // cylab: I think this is never called.
+ // But I don't know if unregistering the observer makes any difference...
+ ((Document)event.getOldValue()).removeDocumentListener(observer);
+ }
+ }
+ }
+ }
+ );
+ cookies.add((Node.Cookie) support);
+ }
+
+ @Override
+ protected Node createNodeDelegate() {
+ return new GlslVertexShaderDataNode(this);
+ }
+}
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/glsl/Bundle.properties b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/glsl/Bundle.properties
new file mode 100644
index 000000000..abf92fabf
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/glsl/Bundle.properties
@@ -0,0 +1,4 @@
+LBL_SYNTAX_ERROR=Syntax error.
+LBL_UNEXPECTED_CHARACTER=Unexpected character.
+LBL_RESERVED_KEYWORD=Reserved keyword.
+
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/glsl/GLSL_120.nbs b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/glsl/GLSL_120.nbs
new file mode 100644
index 000000000..cd5ca6d2b
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/glsl/GLSL_120.nbs
@@ -0,0 +1,316 @@
+################################################################################
+# OpenGL Shading Language 1.20 GLF file ########################################
+################################################################################
+# @date 10.09.2007 #
+# @author Michael Bien #
+# @email mbien@fh-landshut.de #
+################################################################################
+
+BUNDLE "net.java.nboglpack.glsleditor.glsl.Bundle"
+
+SKIP:WHITESPACE
+SKIP:END_OF_LINE
+SKIP:COMMENT
+SKIP:ML_COMMENT
+
+## error highlighting ##########################################################
+MARK:ERROR: {
+ type:"Error";
+ message:"LBL_SYNTAX_ERROR";
+}
+MARK:error: {
+ type:"Error";
+ message:"LBL_UNEXPECTED_CHARACTER";
+}
+MARK:reserved: {
+ type:"Warning";
+ message:"LBL_RESERVED_KEYWORD";
+}
+
+FOLD:function_body: {
+ fold_display_name:"{...}";
+}
+FOLD:struct_body: {
+ fold_display_name:"{...}";
+}
+FOLD:ML_COMMENT: {
+ fold_display_name:"/*...*/";
+}
+
+BRACE "(:)"
+BRACE "{:}"
+BRACE "[:]"
+
+COMPLETE "(:)"
+COMPLETE "{:}"
+COMPLETE "[:]"
+
+INDENT "(:)"
+INDENT "{:}"
+INDENT "[:]"
+INDENT "\\s*(((if|while)\\s*\\(|else\\s*|else\\s+if\\s*\\(|for\\s*\\(.*\\))[^{;]*)"
+
+SELECTION ( ["a"-"z" "A"-"Z" "0"-"9" "_"] )
+
+NAVIGATOR:global_preprocessor: {
+ display_name: net.java.nboglpack.glsleditor.glsl.Glsl.createPreprocessorString;
+ icon: "net/java/nboglpack/glsleditor/resources/preprocessor.png";
+ isLeaf: "true";
+}
+NAVIGATOR:global_declared_identifier, struct_declarator: {
+ display_name: net.java.nboglpack.glsleditor.glsl.Glsl.createFieldDeclarationString;
+ icon: "net/java/nboglpack/glsleditor/resources/field.gif";
+ isLeaf: "true";
+}
+NAVIGATOR:function: {
+ display_name: net.java.nboglpack.glsleditor.glsl.Glsl.createFunctionDeclarationString;
+ icon: "net/java/nboglpack/glsleditor/resources/function.gif";
+ isLeaf: "true";
+}
+#AST {
+# process: net.java.nboglpack.glsleditor.glsl.Glsl.process;
+#}
+#PROPERTIES {
+# traceSteps:"true";
+# printRules:"true";
+# printFirst:"true";
+#}
+
+##### GLSL 1.2 grammar #########################################################
+
+S = declaration*;
+
+
+## constants ###################################################################
+type_specifier = "float"
+ | "int"
+ | "bool"
+ | "vec2"
+ | "vec3"
+ | "vec4"
+ | "bvec2"
+ | "bvec3"
+ | "bvec4"
+ | "ivec2"
+ | "ivec3"
+ | "ivec4"
+ | "mat2"
+ | "mat3"
+ | "mat4"
+ | "mat2x2"
+ | "mat2x3"
+ | "mat2x4"
+ | "mat3x2"
+ | "mat3x3"
+ | "mat3x4"
+ | "mat4x2"
+ | "mat4x3"
+ | "mat4x4"
+ | "sampler1D"
+ | "sampler2D"
+ | "sampler3D"
+ | "samplerCube"
+ | "sampler1DShadow"
+ | "sampler2DShadow";
+
+type_specifier_or_identifier = type_specifier | ;
+
+type_qualifier = "const";
+
+global_type_qualifier = type_qualifier
+ | "attribute" # Vertex only.
+ | "varying"
+ | ("centroid" "varying")
+ | ("invariant" ["centroid"] "varying")
+ | "uniform";
+
+parameter_declaration_qualifier = "in" | "out" | "inout";
+
+boolean_literal = "true" | "false"; # TODO move boolean literal to lexer?
+
+
+assignment_operator =
+ |
+ |
+ |
+ |
+ | # reserved
+ | # reserved
+ | # reserved
+ | # reserved
+ | # reserved
+ | ; # reserved
+
+comperator = | | | | | ;
+
+operator =
+ |
+ |
+ |
+ |
+ |
+ | # reserved
+ |
+ |
+ | # reserved
+ | # reserved
+ | # reserved
+ | ; # reserved
+
+unary_operator =
+ |
+ |
+ | ; # reserved
+
+increment_or_decrement_operator = | ;
+
+reserved = "asm"
+ | "class"
+ | "union"
+ | "enum"
+ | "typedef"
+ | "template"
+ | "this"
+ | "packed"
+ | "goto"
+ | "switch"
+ | "default"
+ | "inline"
+ | "noinline"
+ | "volatile"
+ | "public"
+ | "static"
+ | "extern"
+ | "external"
+ | "interface"
+ | "long"
+ | "short"
+ | "double"
+ | "half"
+ | "fixed"
+ | "unsigned"
+ | "lowp"
+ | "mediump"
+ | "highp"
+ | "precision"
+ | "input"
+ | "output"
+ | "hvec2"
+ | "hvec3"
+ | "hvec4"
+ | "dvec2"
+ | "dvec3"
+ | "dvec4"
+ | "fvec2"
+ | "fvec3"
+ | "fvec4"
+ | "sampler2DRect"
+ | "sampler3DRect"
+ | "sampler2DRectShadow"
+ | "sizeof"
+ | "cast"
+ | "namespace"
+ | "using";
+
+
+## declarations ################################################################
+declaration = type_specifier_or_identifier [array_index] (function | (global_identifier_list ));
+declaration = "void" function;
+declaration = global_type_qualifier struct_declaration ;
+declaration = global_type_qualifier global_type_declaration ;
+declaration = struct_declaration ;
+declaration = global_preprocessor;
+
+global_identifier_list = global_declared_identifier [array_index] ( global_declared_identifier [array_index])*;
+global_declared_identifier = ;
+global_preprocessor = ;
+
+struct_declaration = "struct" struct_body [global_identifier_list];
+struct_body = "{" (local_type_declaration )+ "}";
+
+global_type_declaration = type_specifier_or_identifier [array_index] global_identifier_list [ expression];
+type_declaration = type_specifier_or_identifier [array_index] [array_index] ( [array_index])*;
+
+local_type_declaration = [type_qualifier] type_declaration;
+
+## function ####################################################################
+function = "(" [parameter_declaration_list] ")" (function_body | );
+function_body = code_block;
+
+parameter_declaration = [type_qualifier] [parameter_declaration_qualifier] type_specifier_or_identifier ((array_index ) | ( [array_index]));
+parameter_declaration_list = "void" | (parameter_declaration ( parameter_declaration)*);
+
+statement = ;
+statement = expression_hack ; # statement = local_type_declaration [ expression] ;
+statement = conditional_statement;
+statement = "return" [expression] ;
+statement = "break" ; # break just in loops allowed
+statement = "continue" ;# continue just in loops allowed
+statement = "discard" ; # Fragment shader only.
+
+code_block = "{" statement* "}";
+
+## expresstions and operations #################################################
+# ternary operator
+expression = expression1 ["?" expression1 ":" expression1];
+
+expression1 = [unary_operator] expression2 operation_or_comparison*;
+expression1 = [unary_operator] "(" expression ")" operation_or_comparison*;
+
+expression2 = ( [increment_or_decrement_operator] ( | ) (field_access)* [increment_or_decrement_operator] [assignment])
+ | ((function_call | constructor_call) (field_access)*)
+ |
+ |
+ | boolean_literal;
+
+
+
+expression_hack = unary_operator expression1_hack operation_or_comparison*;
+expression_hack = unary_operator "(" expression ")" operation_or_comparison*;
+expression_hack = expression1_hack operation_or_comparison*;
+expression_hack = "(" expression ")" operation_or_comparison*;
+
+expression_hack = (field_access)* [increment_or_decrement_operator] [assignment];
+expression_hack = (field_access)* [array_index] ( [array_index])*;
+expression_hack = type_specifier (field_access)* [array_index] ( [array_index])*;
+
+expression1_hack = (increment_or_decrement_operator ( | ) (field_access)* [increment_or_decrement_operator] [assignment])
+ | ( (field_access)* [increment_or_decrement_operator] [assignment])
+ | ((function_call | constructor_call) (field_access)*)
+ |
+ |
+ | boolean_literal;
+
+
+
+assignment = assignment_operator expression;
+operation_or_comparison = (comperator | operator) expression;
+
+field_access = array_index;
+field_access = ;
+
+array_index = "[" [expression] "]";
+
+function_call = ( | ) "(" [expression_list] ")";
+# Note constructor call is something like that: vec2(1.0, 2.0) or float[2] (1.0, 2.0)
+constructor_call = type_specifier [array_index] "(" [expression_list] ")"; #TODO custom structs
+
+expression_list = "void" | (expression ( expression)*);
+
+## code flow ###################################################################
+conditional_statement = if_statement
+ | for_statement
+ | while_statement
+ | do_while_statement;
+
+# TODO if rule not 100% correct, multiple else allowed even before else if
+if_statement = "if" condition statement_or_code_block ("else" ["if" condition] statement_or_code_block)*;
+while_statement = "while" condition statement_or_code_block;
+do_while_statement = "do" statement_or_code_block "while" condition ;
+# TODO for rule could be more restrictive
+for_statement = "for" "(" [[type_specifier] assignment] [expression] [expression] ")" statement_or_code_block;
+
+condition = "(" expression ")";
+statement_or_code_block = (statement | code_block);
+
+
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/glsl/GLSL_130.nbs b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/glsl/GLSL_130.nbs
new file mode 100644
index 000000000..120c4b19f
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/glsl/GLSL_130.nbs
@@ -0,0 +1,389 @@
+################################################################################
+# OpenGL Shading Language 1.30 GLF file ########################################
+################################################################################
+# @date 10.09.2007 #
+# @author Michael Bien #
+# @email mbien@fh-landshut.de #
+################################################################################
+
+BUNDLE "net.java.nboglpack.glsleditor.glsl.Bundle"
+
+SKIP:WHITESPACE
+SKIP:END_OF_LINE
+SKIP:COMMENT
+SKIP:ML_COMMENT
+
+## error highlighting ##########################################################
+MARK:ERROR: {
+ type:"Error";
+ message:"LBL_SYNTAX_ERROR";
+}
+MARK:error: {
+ type:"Error";
+ message:"LBL_UNEXPECTED_CHARACTER";
+}
+MARK:reserved: {
+ type:"Warning";
+ message:"LBL_RESERVED_KEYWORD";
+}
+
+FOLD:function_body: {
+ fold_display_name:"{...}";
+}
+FOLD:struct_body: {
+ fold_display_name:"{...}";
+}
+FOLD:ML_COMMENT: {
+ fold_display_name:"/*...*/";
+}
+
+BRACE "(:)"
+BRACE "{:}"
+BRACE "[:]"
+
+COMPLETE "(:)"
+COMPLETE "{:}"
+COMPLETE "[:]"
+
+INDENT "(:)"
+INDENT "{:}"
+INDENT "[:]"
+INDENT "\\s*(((if|while)\\s*\\(|else\\s*|else\\s+if\\s*\\(|for\\s*\\(.*\\))[^{;]*)"
+
+SELECTION ( ["a"-"z" "A"-"Z" "0"-"9" "_"] )
+
+AST {
+ process: net.java.nboglpack.glsleditor.glsl.Glsl.process;
+}
+NAVIGATOR:global_preprocessor: {
+ display_name: net.java.nboglpack.glsleditor.glsl.Glsl.createPreprocessorString;
+ icon: "net/java/nboglpack/glsleditor/resources/preprocessor.png";
+ isLeaf: "true";
+}
+NAVIGATOR:global_declared_identifier: {
+ display_name: net.java.nboglpack.glsleditor.glsl.Glsl.createFieldDeclarationString;
+ icon: "net/java/nboglpack/glsleditor/resources/field.gif";
+ isLeaf: "true";
+}
+NAVIGATOR:function: {
+ display_name: net.java.nboglpack.glsleditor.glsl.Glsl.createFunctionDeclarationString;
+ icon: "net/java/nboglpack/glsleditor/resources/function.gif";
+ isLeaf: "true";
+}
+#PROPERTIES {
+# traceSteps:"true";
+# printRules:"true";
+# printFirst:"true";
+#}
+
+##### GLSL 1.3 grammar #########################################################
+
+S = declaration*;
+
+
+## constants ###################################################################
+type_specifier = "float"
+ | "int"
+ | "uint"
+ | "bool"
+ | "vec2"
+ | "vec3"
+ | "vec4"
+ | "bvec2"
+ | "bvec3"
+ | "bvec4"
+ | "ivec2"
+ | "ivec3"
+ | "ivec4"
+ | "uvec2"
+ | "uvec3"
+ | "uvec4"
+ | "mat2"
+ | "mat3"
+ | "mat4"
+ | "mat2x2"
+ | "mat2x3"
+ | "mat2x4"
+ | "mat3x2"
+ | "mat3x3"
+ | "mat3x4"
+ | "mat4x2"
+ | "mat4x3"
+ | "mat4x4"
+ | "sampler1D"
+ | "sampler2D"
+ | "sampler3D"
+ | "samplerCube"
+ | "sampler1DShadow"
+ | "sampler2DShadow"
+ | "sampler1DArray"
+ | "sampler2DArray"
+ | "sampler1DArrayShadow"
+ | "sampler2DArrayShadow"
+ | "isampler1D"
+ | "isampler2D"
+ | "isampler3D"
+ | "isamplerCube"
+ | "isampler1DArray"
+ | "isampler2DArray"
+ | "usampler1D"
+ | "usampler2D"
+ | "usampler3D"
+ | "usamplerCube"
+ | "usampler1DArray"
+ | "usampler2DArray";
+
+type_specifier_or_identifier = type_specifier | ;
+
+type_qualifier = "const";
+
+interpolation_type_qualifier = "smooth"
+ | "flat"
+ | "noperspective";
+
+inout_type_qualifier = "in" | "out";
+
+global_type_qualifier = type_qualifier
+ | (inout_type_qualifier ["invariant"] ["centroid"])
+ | (interpolation_type_qualifier ["invariant"] ["centroid"] [inout_type_qualifier])
+ | ("centroid" [interpolation_type_qualifier] [inout_type_qualifier])
+ | ("invariant" ["centroid"] [inout_type_qualifier])
+ | "attribute" # Vertex only.
+ | "varying"
+ | ("centroid" "varying")
+ | ("invariant" ["centroid"] "varying")
+ | "uniform";
+
+parameter_declaration_qualifier = "in" | "out" | "inout";
+
+boolean_literal = "true" | "false"; # TODO move boolean literal to lexer?
+
+precision_qualifier = "highp"
+ | "mediump"
+ | "lowp";
+
+assignment_operator =
+ |
+ |
+ |
+ |
+ | # reserved
+ | # reserved
+ | # reserved
+ | # reserved
+ | # reserved
+ | ; # reserved
+
+comperator = | | | | | ;
+
+operator =
+ |
+ |
+ |
+ |
+ |
+ | # reserved
+ |
+ |
+ | # reserved
+ | # reserved
+ | # reserved
+ | ; # reserved
+
+unary_operator =
+ |
+ |
+ | ; # reserved
+
+increment_or_decrement_operator = | ;
+
+reserved = "asm"
+ | "common"
+ | "partition"
+ | "active"
+ | "class"
+ | "union"
+ | "enum"
+ | "typedef"
+ | "template"
+ | "this"
+ | "packed"
+ | "goto"
+ | "inline"
+ | "noinline"
+ | "volatile"
+ | "public"
+ | "static"
+ | "extern"
+ | "external"
+ | "interface"
+ | "long"
+ | "short"
+ | "double"
+ | "half"
+ | "fixed"
+ | "unsigned"
+ | "superp"
+ | "input"
+ | "output"
+ | "hvec2"
+ | "hvec3"
+ | "hvec4"
+ | "dvec2"
+ | "dvec3"
+ | "dvec4"
+ | "fvec2"
+ | "fvec3"
+ | "fvec4"
+ | "sampler2DRect"
+ | "sampler3DRect"
+ | "sampler2DRectShadow"
+ | "samplerBuffer"
+ | "filter"
+ | "image1D"
+ | "image2D"
+ | "image3D"
+ | "imageCube"
+ | "iimage1D"
+ | "iimage2D"
+ | "iimage3D"
+ | "iimageCube"
+ | "uimage1D"
+ | "uimage2D"
+ | "uimage3D"
+ | "uimageCube"
+ | "image1DArray"
+ | "image2DArray"
+ | "iimage1DArray"
+ | "iimage2DArray"
+ | "uimage1DArray"
+ | "uimage2DArray"
+ | "image1DShadow"
+ | "image2DShadow"
+ | "image1DArrayShadow"
+ | "image2DArrayShadow"
+ | "imageBuffer"
+ | "iimageBuffer"
+ | "uimageBuffer"
+ | "sizeof"
+ | "cast"
+ | "namespace"
+ | "using"
+ | "row_major";
+
+
+## declarations ################################################################
+declaration = [precision_qualifier] type_specifier_or_identifier [array_index] (function | (global_identifier_list [assignment2] ));
+declaration = "void" function;
+declaration = field_declaration ;
+declaration = struct_declaration ;
+declaration = precision_declaration ;
+declaration = global_preprocessor;
+
+global_identifier_list = global_declared_identifier [array_index] ( global_declared_identifier [array_index])*;
+global_declared_identifier = ;
+global_preprocessor = ;
+
+field_declaration = global_type_qualifier struct_declaration;
+field_declaration = global_type_qualifier global_type_declaration [assignment2];
+
+struct_declaration = "struct" struct_body [global_identifier_list];
+struct_body = "{" (local_type_declaration )+ "}";
+
+global_type_declaration = [precision_qualifier] type_specifier_or_identifier [array_index] global_identifier_list [ expression];
+type_declaration = [precision_qualifier] type_specifier_or_identifier [array_index] [array_index] ( [array_index])*;
+
+local_type_declaration = [type_qualifier] type_declaration;
+
+precision_declaration = "precision" precision_qualifier type_specifier;
+
+## function ####################################################################
+function = "(" [parameter_declaration_list] ")" (function_body | );
+function_body = code_block;
+
+parameter_declaration = [type_qualifier] [parameter_declaration_qualifier] [precision_qualifier] type_specifier_or_identifier ((array_index ) | ( [array_index]));
+parameter_declaration_list = "void" | (parameter_declaration ( parameter_declaration)*);
+
+statement = ;
+statement = expression_hack ; # statement = local_type_declaration [ expression] ;
+statement = conditional_statement;
+statement = "return" [expression] ;
+statement = "break" ; # break just in loops allowed
+statement = "continue" ;# continue just in loops allowed
+statement = "discard" ; # Fragment shader only.
+
+code_block = "{" code_block* "}";
+code_block = "{" statement* "}";
+
+## expresstions and operations #################################################
+# ternary operator
+expression = expression1 ["?" expression1 ":" expression1];
+
+expression1 = [unary_operator] expression2 operation_or_comparison*;
+expression1 = [unary_operator] "(" expression ")" operation_or_comparison*;
+
+expression2 = ( [increment_or_decrement_operator] ( | ) (field_access)* [increment_or_decrement_operator] [assignment])
+ | ((function_call | constructor_call) (field_access)*)
+ |
+ |
+ | boolean_literal;
+
+
+
+expression_hack = unary_operator expression1_hack operation_or_comparison*;
+expression_hack = unary_operator "(" expression ")" operation_or_comparison*;
+expression_hack = expression1_hack operation_or_comparison*;
+expression_hack = "(" expression ")" operation_or_comparison*;
+
+expression_hack = (field_access)* [increment_or_decrement_operator] [assignment];
+expression_hack = (field_access)* [array_index] ( [array_index])*;
+expression_hack = type_specifier (field_access)* [array_index] ( [array_index])*;
+
+expression1_hack = (increment_or_decrement_operator ( | ) (field_access)* [increment_or_decrement_operator] [assignment])
+ | ( (field_access)* [increment_or_decrement_operator] [assignment])
+ | ((function_call | constructor_call) (field_access)*)
+ |
+ |
+ | boolean_literal;
+
+
+
+assignment = assignment_operator expression;
+assignment2 = expression;
+operation_or_comparison = (comperator | operator) expression;
+
+field_access = array_index;
+field_access = ;
+
+array_index = "[" [expression] "]";
+
+function_call = ( | ) "(" [expression_list] ")";
+# Note constructor call is something like that: vec2(1.0, 2.0) or float[2] (1.0, 2.0)
+constructor_call = type_specifier [array_index] "(" [expression_list] ")"; #TODO custom structs
+
+expression_list = "void" | (expression ( expression)*);
+
+## code flow ###################################################################
+conditional_statement = if_statement
+ | for_statement
+ | while_statement
+ | do_while_statement
+ | switch_statement;
+
+# TODO if rule not 100% correct, multiple else allowed even before else if
+if_statement = "if" condition statement_or_code_block ("else" ["if" condition] statement_or_code_block)*;
+
+while_statement = "while" condition statement_or_code_block;
+do_while_statement = "do" statement_or_code_block "while" condition ;
+
+# TODO for rule could be more restrictive
+for_statement = "for" "(" [[type_specifier] assignment] [expression] [expression] ")" statement_or_code_block;
+
+switch_statement = "switch" condition "{" case* "}";
+case = ("case" expression ":" statement*)
+ | ("default" ":" statement*);
+
+condition = "(" expression ")";
+statement_or_code_block = (statement | code_block);
+
+
diff --git a/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/glsl/Glsl.java b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/glsl/Glsl.java
new file mode 100644
index 000000000..3d0b1344f
--- /dev/null
+++ b/sdk/jme3-glsl-support/src/net/java/nboglpack/glsleditor/glsl/Glsl.java
@@ -0,0 +1,361 @@
+/*
+ * Glsl.java
+ *
+ * Created on 24.09.2007, 00:46:53
+ *
+ */
+
+package net.java.nboglpack.glsleditor.glsl;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import javax.swing.text.AbstractDocument;
+import net.java.nboglpack.glsleditor.lexer.GlslTokenId;
+import net.java.nboglpack.glsleditor.vocabulary.GLSLElementDescriptor;
+import org.netbeans.api.languages.ASTItem;
+import org.netbeans.api.languages.ASTNode;
+import org.netbeans.api.languages.ASTToken;
+import org.netbeans.api.languages.SyntaxContext;
+import org.netbeans.api.lexer.Token;
+import org.netbeans.api.lexer.TokenHierarchy;
+import org.netbeans.api.lexer.TokenSequence;
+import org.netbeans.api.lexer.TokenUtilities;
+
+/**
+ * Utility methods called from GLSL.nbs.
+ * @author Michael Bien
+ */
+public final class Glsl {
+
+ private final static String KEYWORD_FONT_COLOR = "";
+
+ public final static Map declaredFunctions = new HashMap();
+
+ private Glsl() {}
+
+ /**
+ * Assembles a human readable String containing the declaraton of a function.
+ * Asumes that the current token of the SyntaxContext represents the function name.
+ */
+ public static final String createFunctionDeclarationString(SyntaxContext context) {
+
+ AbstractDocument document = (AbstractDocument)context.getDocument();
+
+ StringBuilder sb = new StringBuilder();
+
+ try {
+
+ document.readLock();
+
+ TokenSequence sequence = TokenHierarchy.get(context.getDocument()).tokenSequence();
+ sequence.move(context.getOffset());
+ sequence.moveNext();
+
+ sb.append("");
+
+ int moved = 0;
+ while(sequence.movePrevious() && isIgnoredToken(sequence.token()))
+ moved++;
+
+ String type = sequence.token().toString();
+ while(moved-- >= 0)
+ sequence.moveNext();
+
+ // append function name
+ sb.append(sequence.token().text());
+
+ while(!TokenUtilities.equals(sequence.token().text(), "("))
+ sequence.moveNext();
+
+ sb.append("(");
+
+ Token token;
+ boolean first = true;
+ while(sequence.moveNext() && !TokenUtilities.equals(sequence.token().text(), ")")) {
+
+ token = sequence.token();
+
+ if(!isIgnoredToken(token)) {
+
+ if(first) {
+ sb.append(KEYWORD_FONT_COLOR);
+ }else if(token.id() != GlslTokenId.COMMA && token.id() != GlslTokenId.BRACKET && token.id() != GlslTokenId.INTEGER_LITERAL) {
+ sb.append(" ");
+ }
+
+ if(!TokenUtilities.equals(token.text(), "void")) {
+
+ moved = 0;
+ while(sequence.moveNext() && isIgnoredToken(sequence.token()))
+ moved++;
+
+ if(sequence.token().id() == GlslTokenId.COMMA || TokenUtilities.equals(sequence.token().text(), ")"))
+ sb.append("");
+
+ while(moved-- >= 0)
+ sequence.movePrevious();
+
+ sb.append(token.text());
+
+ if(token.id() == GlslTokenId.COMMA)
+ sb.append(KEYWORD_FONT_COLOR);
+ }
+
+ first = false;
+ }
+
+ }
+
+ sb.append(")");
+
+ if(!"void".equals(type)) {
+ sb.append(" : ");
+ sb.append(KEYWORD_FONT_COLOR);
+ sb.append(type);
+ sb.append("");
+ }
+ sb.append("");
+
+ } finally {
+ document.readUnlock();
+ }
+
+ return sb.toString();
+ }
+
+ /**
+ * Assambles a human readable String containing the declaraton of a field and the field name itself.
+ * Asumes that the current token of the SyntaxContext represents the field name.
+ */
+ public static final String createFieldDeclarationString(SyntaxContext context) {
+
+ AbstractDocument document = (AbstractDocument)context.getDocument();
+
+ StringBuilder sb = new StringBuilder();
+
+ try {
+
+ document.readLock();
+
+ TokenSequence sequence = TokenHierarchy.get(context.getDocument()).tokenSequence();
+ sequence.move(context.getOffset());
+ sequence.moveNext();
+
+ sb.append("");
+ sb.append(sequence.token().text());
+ sb.append(KEYWORD_FONT_COLOR);
+ sb.append(" :");
+
+ int insertIndex = sb.length();
+
+ // read forward
+ int moved = 0;
+ Token token;
+ while( sequence.moveNext()
+ && sequence.token().id() != GlslTokenId.SEMICOLON
+ && sequence.token().id() != GlslTokenId.COMMA
+ && sequence.token().id() != GlslTokenId.EQ ) {
+ token = sequence.token();
+ if(!isIgnoredToken(token))
+ sb.append(token);
+ moved++;
+ }
+ while(moved-- >= 0)
+ sequence.movePrevious();
+
+ // read backwards throw the declaration
+ boolean skipToken = false;
+
+ while( sequence.movePrevious()
+ && sequence.token().id() != GlslTokenId.SEMICOLON
+ && sequence.token().id() != GlslTokenId.END_OF_LINE ) {
+
+ token = sequence.token();
+
+ if(!isIgnoredToken(token)) {
+
+ // we have a struct declaration; skip everything between { }
+ if(token.id() == GlslTokenId.BRACE && TokenUtilities.equals(token.text(), "}")) {
+ movePreviousUntil(sequence, GlslTokenId.BRACE, "}", "{");
+ continue;
+ }
+
+ // skip token in case of an comma seperated identifier list
+ if(skipToken) {
+ if( token.id() == GlslTokenId.BRACKET
+ && TokenUtilities.equals(token.text(), "]") ) {
+ movePreviousUntil(sequence, GlslTokenId.BRACKET, "]", "[");
+ skipToken = false;
+ }else {
+ skipToken = false;
+ }
+ continue;
+ }
+
+ if(token.id() == GlslTokenId.COMMA) {
+ skipToken = true;
+ continue;
+ }
+
+ if(!TokenUtilities.equals(token.text(), "struct")) {
+ sb.insert(insertIndex, token.text());
+ sb.insert(insertIndex, " ");
+ }
+ }
+
+ }
+
+ sb.append("");
+ } finally {
+ document.readUnlock();
+ }
+
+
+ return sb.toString();
+ }
+
+
+ public static final String createPreprocessorString(SyntaxContext context) {
+
+ ASTNode node = (ASTNode)context.getASTPath().getLeaf();
+ List