Browse Source

SDK : Added a way to change the ParticleInfluencer on an emitter in the SDK
- Property of influencers are created through reflection
- One can even add an home brewed influencer.

git-svn-id: https://jmonkeyengine.googlecode.com/svn/trunk@9668 75d07b2b-3a1a-0410-a2c5-0572b91ccdca

rem..om 13 years ago
parent
commit
6f8324169d

+ 92 - 0
jme3-core/src/com/jme3/gde/core/properties/ParticleInfluencerProperty.java

@@ -0,0 +1,92 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.properties;
+
+import com.jme3.effect.ParticleEmitter;
+import com.jme3.effect.influencers.ParticleInfluencer;
+import java.beans.PropertyEditor;
+import java.lang.reflect.InvocationTargetException;
+import java.util.Iterator;
+import java.util.LinkedList;
+import org.netbeans.api.project.Project;
+import org.openide.nodes.PropertySupport;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class ParticleInfluencerProperty extends PropertySupport.ReadWrite<ParticleInfluencer> {
+
+    private LinkedList<ScenePropertyChangeListener> listeners = new LinkedList<ScenePropertyChangeListener>();
+    private ParticleEmitter emitter;
+    private Project project;
+
+    public ParticleInfluencerProperty(ParticleEmitter emitter, Project project) {
+        super("ParticleInfluencer", ParticleInfluencer.class, "Particle Influencer", " ");
+        this.project = project;
+        this.emitter = emitter;
+
+    }
+
+    @Override
+    public ParticleInfluencer getValue() throws IllegalAccessException, InvocationTargetException {
+        return emitter.getParticleInfluencer();
+    }
+
+    @Override
+    public void setValue(final ParticleInfluencer val) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException {
+        ParticleInfluencer pi = getValue();
+        emitter.setParticleInfluencer(val);
+        notifyListeners(pi, val);
+    }
+
+    @Override
+    public PropertyEditor getPropertyEditor() {
+        return new ParticleInfluencerPropertyEditor(emitter.getParticleInfluencer(), project);
+    }
+
+    public void addPropertyChangeListener(ScenePropertyChangeListener listener) {
+        listeners.add(listener);
+    }
+
+    public void removePropertyChangeListener(ScenePropertyChangeListener listener) {
+        listeners.remove(listener);
+    }
+
+    private void notifyListeners(Object before, Object after) {
+        for (Iterator<ScenePropertyChangeListener> it = listeners.iterator(); it.hasNext();) {
+            ScenePropertyChangeListener propertyChangeListener = it.next();
+            propertyChangeListener.propertyChange(getName(), before, after);
+        }
+
+    }
+}

+ 242 - 0
jme3-core/src/com/jme3/gde/core/properties/ParticleInfluencerPropertyEditor.java

@@ -0,0 +1,242 @@
+/*
+ *  Copyright (c) 2009-2010 jMonkeyEngine
+ *  All rights reserved.
+ * 
+ *  Redistribution and use in source and binary forms, with or without
+ *  modification, are permitted provided that the following conditions are
+ *  met:
+ * 
+ *  * Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 
+ *  * Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 
+ *  * Neither the name of 'jMonkeyEngine' nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * 
+ *  THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ *  "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ *  TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ *  PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+ *  CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ *  EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ *  PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ *  PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ *  LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ *  NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ *  SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+package com.jme3.gde.core.properties;
+
+import com.jme3.effect.influencers.ParticleInfluencer;
+import com.jme3.gde.core.assets.ProjectAssetManager;
+import java.awt.Component;
+import java.awt.Graphics;
+import java.awt.Rectangle;
+import java.beans.PropertyChangeEvent;
+import java.beans.PropertyChangeListener;
+import java.beans.PropertyEditor;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.LinkedList;
+import java.util.List;
+import java.util.Set;
+import javax.lang.model.element.TypeElement;
+import javax.lang.model.type.TypeMirror;
+import org.netbeans.api.java.classpath.ClassPath;
+import org.netbeans.api.java.project.JavaProjectConstants;
+import org.netbeans.api.java.source.ClassIndex;
+import org.netbeans.api.java.source.ClassIndex.NameKind;
+import org.netbeans.api.java.source.ClassIndex.SearchScope;
+import org.netbeans.api.java.source.ClasspathInfo;
+import org.netbeans.api.java.source.CompilationController;
+import org.netbeans.api.java.source.ElementHandle;
+import org.netbeans.api.java.source.JavaSource;
+import org.netbeans.api.java.source.JavaSource.Phase;
+import org.netbeans.api.java.source.Task;
+import org.netbeans.api.project.Project;
+import org.netbeans.api.project.SourceGroup;
+import org.netbeans.api.project.Sources;
+import org.openide.DialogDisplayer;
+import org.openide.NotifyDescriptor;
+import org.openide.util.Exceptions;
+
+/**
+ *
+ * @author normenhansen
+ */
+public class ParticleInfluencerPropertyEditor implements PropertyEditor {
+
+    private LinkedList<PropertyChangeListener> listeners = new LinkedList<PropertyChangeListener>();
+    private ParticleInfluencer pi;
+    private Project proj;
+
+    public ParticleInfluencerPropertyEditor() {
+    }
+
+    public ParticleInfluencerPropertyEditor(ParticleInfluencer pi, Project project) {
+        this.pi = pi;
+        this.proj = project;
+    }
+
+    public void setValue(Object value) {
+        if (value instanceof ParticleInfluencer) {
+            pi = (ParticleInfluencer) value;
+        }
+    }
+
+    public Object getValue() {
+        return pi;
+    }
+
+    public boolean isPaintable() {
+        return false;
+    }
+
+    public void paintValue(Graphics gfx, Rectangle box) {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public String getJavaInitializationString() {
+        return null;
+    }
+
+    public String getAsText() {
+        return pi.getClass().getName();
+    }
+
+    public void setAsText(String text) throws IllegalArgumentException {
+        ParticleInfluencer old = pi;
+        ProjectAssetManager manager = (ProjectAssetManager) proj.getLookup().lookup(ProjectAssetManager.class);
+        List<ClassLoader> loaders = manager.getClassLoaders();
+
+
+        Class clazz = null;
+        try {
+            clazz = getClass().getClassLoader().loadClass(text);
+        } catch (ClassNotFoundException ex) {
+        }
+        for (ClassLoader classLoader : loaders) {
+            if (clazz == null) {
+                try {
+                    clazz = classLoader.loadClass(text);
+                } catch (ClassNotFoundException ex) {
+                }
+            }
+        }
+        if (clazz != null) {
+            try {
+                Object obj = clazz.newInstance();
+                if (obj instanceof ParticleInfluencer) {
+                    pi = (ParticleInfluencer) obj;
+                } else {
+                    DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("This is no ParticleInfluencer class!"));
+                }
+            } catch (InstantiationException ex) {
+                Exceptions.printStackTrace(ex);
+                DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("Error instatiating class!"));
+            } catch (IllegalAccessException ex) {
+                Exceptions.printStackTrace(ex);
+                DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("Error instatiating class!"));
+            }
+        } else {
+            DialogDisplayer.getDefault().notifyLater(new NotifyDescriptor.Message("Cannot find class: " + text + "\nMake sure the name is correct and the project is compiled,\nbest enable 'Save on Compile' in the project preferences."));
+        }
+        if (pi != old) {
+            notifyListeners(old, pi);
+        }
+    }
+
+    public String[] getTags() {
+
+        List<String> s = getSources();
+        s.add("com.jme3.effect.influencers.DefaultParticleInfluencer");
+        s.add("com.jme3.effect.influencers.NewtonianParticleInfluencer");
+        s.add("com.jme3.effect.influencers.RadialParticleInfluencer");
+        s.add("com.jme3.effect.influencers.EmptyParticleInfluencer");
+        String[] t = new String[s.size()];
+        return s.toArray(t);
+
+    }
+
+    private List<String> getSources() {
+        Sources sources = proj.getLookup().lookup(Sources.class);
+        final List<String> list = new LinkedList<String>();
+        if (sources != null) {
+            SourceGroup[] groups = sources.getSourceGroups(JavaProjectConstants.SOURCES_TYPE_JAVA);
+            if (groups != null) {
+                for (SourceGroup sourceGroup : groups) {
+                    ClasspathInfo cpInfo = ClasspathInfo.create(ClassPath.getClassPath(sourceGroup.getRootFolder(), ClassPath.BOOT),
+                            ClassPath.getClassPath(sourceGroup.getRootFolder(), ClassPath.COMPILE),
+                            ClassPath.getClassPath(sourceGroup.getRootFolder(), ClassPath.SOURCE));
+
+                    HashSet<SearchScope> set = new HashSet<SearchScope>();
+                    set.add(ClassIndex.SearchScope.SOURCE);
+                    //   set.add(ClassIndex.SearchScope.DEPENDENCIES);
+
+                    Set<ElementHandle<TypeElement>> types = cpInfo.getClassIndex().getDeclaredTypes("", NameKind.PREFIX, set);
+                    for (Iterator<ElementHandle<TypeElement>> it = types.iterator(); it.hasNext();) {
+                        final ElementHandle<TypeElement> elementHandle = it.next();
+                        JavaSource js = JavaSource.create(cpInfo);
+                        try {
+                            js.runUserActionTask(new Task<CompilationController>() {
+
+                                public void run(CompilationController control)
+                                        throws Exception {
+                                    control.toPhase(Phase.RESOLVED);
+                                    //TODO: check with proper casting check.. gotta get TypeMirror of Control interface..
+//                                    TypeUtilities util = control.getTypeUtilities();//.isCastable(Types., null)
+//                                    util.isCastable(null, null);
+                                    TypeElement elem = elementHandle.resolve(control);
+                                    List<? extends TypeMirror> interfaces = elem.getInterfaces();
+                                    for (TypeMirror typeMirror : interfaces) {
+                                        String interfaceName = typeMirror.toString();
+                                        if ("com.jme3.effect.influencers.ParticleInfluencer".equals(interfaceName)) {
+                                            list.add(elem.getQualifiedName().toString());
+                                        }
+                                    }
+                                    TypeMirror superClass = elem.getSuperclass();
+                                    String superClassName = superClass.toString();
+                                    if ("com.jme3.effect.influencers.DefaultParticleInfluencer".equals(superClassName)) {
+                                        list.add(elem.getQualifiedName().toString());
+                                    }
+                                }
+                            }, false);
+                        } catch (Exception ioe) {
+                            Exceptions.printStackTrace(ioe);
+                        }
+                    }
+
+                }
+            }
+        }
+        return list;
+    }
+
+    public Component getCustomEditor() {
+        throw new UnsupportedOperationException("Not supported yet.");
+    }
+
+    public boolean supportsCustomEditor() {
+        return false;
+    }
+
+    public void addPropertyChangeListener(PropertyChangeListener listener) {
+        listeners.add(listener);
+    }
+
+    public void removePropertyChangeListener(PropertyChangeListener listener) {
+        listeners.remove(listener);
+    }
+
+    private void notifyListeners(ParticleInfluencer before, ParticleInfluencer after) {
+        for (Iterator<PropertyChangeListener> it = listeners.iterator(); it.hasNext();) {
+            PropertyChangeListener propertyChangeListener = it.next();
+            //TODO: check what the "programmatic name" is supposed to be here.. for now its Quaternion
+            propertyChangeListener.propertyChange(new PropertyChangeEvent(this, null, before, after));
+        }
+    }
+}

+ 3 - 0
jme3-core/src/com/jme3/gde/core/properties/SceneExplorerProperty.java

@@ -31,6 +31,7 @@
  */
 package com.jme3.gde.core.properties;
 
+import com.jme3.effect.influencers.ParticleInfluencer;
 import com.jme3.effect.shapes.EmitterShape;
 import com.jme3.gde.core.scene.SceneApplication;
 import com.jme3.gde.core.undoredo.AbstractUndoableSceneEdit;
@@ -79,6 +80,8 @@ public class SceneExplorerProperty<T> extends PropertySupport.Reflection<T> {
             setPropertyEditorClass(EmitterShapePropertyEditor.class);
         } else if (valueType == Vector2f.class) {
             setPropertyEditorClass(Vector2fPropertyEditor.class);
+        } else if (valueType == ParticleInfluencer.class) {
+            setPropertyEditorClass(ParticleInfluencerPropertyEditor.class);
         }
 
         for (SceneExplorerPropertyEditor di : Lookup.getDefault().lookupAll(SceneExplorerPropertyEditor.class)) {

+ 43 - 3
jme3-core/src/com/jme3/gde/core/sceneexplorer/nodes/JmeParticleEmitter.java

@@ -34,11 +34,17 @@ package com.jme3.gde.core.sceneexplorer.nodes;
 import com.jme3.effect.shapes.EmitterShape;
 import com.jme3.effect.ParticleEmitter;
 import com.jme3.effect.ParticleMesh;
+import com.jme3.effect.influencers.DefaultParticleInfluencer;
 import com.jme3.effect.influencers.ParticleInfluencer;
+import com.jme3.gde.core.assets.ProjectAssetManager;
+import com.jme3.gde.core.properties.ParticleInfluencerProperty;
+import com.jme3.gde.core.util.PropertyUtils;
 import com.jme3.math.ColorRGBA;
 import com.jme3.math.Vector3f;
 import java.awt.Image;
+import java.beans.PropertyDescriptor;
 import java.beans.PropertyEditor;
+import java.lang.reflect.Field;
 import java.lang.reflect.InvocationTargetException;
 import org.openide.loaders.DataObject;
 import org.openide.nodes.Node;
@@ -74,11 +80,12 @@ public class JmeParticleEmitter extends JmeGeometry {
     public Image getOpenedIcon(int type) {
         return smallImage;
     }
+    Sheet sheet;
 
     @Override
     protected Sheet createSheet() {
         //TODO: multithreading..
-        Sheet sheet = super.createSheet();
+        sheet = super.createSheet();
         Sheet.Set set = Sheet.createPropertiesSet();
         set.setDisplayName("ParticleEmitter");
         set.setName(ParticleEmitter.class.getName());
@@ -101,8 +108,6 @@ public class JmeParticleEmitter extends JmeGeometry {
         set.put(makeProperty(obj, float.class, "getHighLife", "setHighLife", "High Life"));
         set.put(makeProperty(obj, float.class, "getLowLife", "setLowLife", "Low Life"));
         set.put(makeProperty(obj, Vector3f.class, "getGravity", "setGravity", "Gravity"));
-        set.put(makeEmbedProperty(obj.getParticleInfluencer(), ParticleInfluencer.class, Vector3f.class, "getInitialVelocity", "setInitialVelocity", "Initial Velocity"));
-        set.put(makeEmbedProperty(obj.getParticleInfluencer(), ParticleInfluencer.class, float.class, "getVelocityVariation", "setVelocityVariation", "Velocity Variation"));
         set.put(makeProperty(obj, Vector3f.class, "getFaceNormal", "setFaceNormal", "Face Normal"));
         set.put(makeProperty(obj, boolean.class, "isFacingVelocity", "setFacingVelocity", "Facing Velocity"));
         set.put(makeProperty(obj, boolean.class, "isRandomAngle", "setRandomAngle", "Random Angle"));
@@ -112,10 +117,41 @@ public class JmeParticleEmitter extends JmeGeometry {
         set.put(makeProperty(obj, int.class, "getImagesX", "setImagesX", "Images X"));
         set.put(makeProperty(obj, int.class, "getImagesY", "setImagesY", "Images Y"));
         sheet.put(set);
+        set2 = Sheet.createPropertiesSet();
+        createParticleInfluencerSet(sheet, obj);
 
         return sheet;
 
     }
+    Sheet.Set set2;
+
+    private void createParticleInfluencerSet(Sheet sheet, ParticleEmitter obj) {
+        for (Property<?> property : set2.getProperties()) {
+            set2.remove(property.getName());
+        }
+
+        set2.setDisplayName("Particle Influencer" + " - " + obj.getParticleInfluencer().getClass().getSimpleName());
+        set2.setName(obj.getParticleInfluencer().getClass().getName());
+        ParticleInfluencerProperty prop = new ParticleInfluencerProperty(obj, this.getLookup().lookup(ProjectAssetManager.class).getProject());
+        prop.addPropertyChangeListener(this);
+        set2.put(prop);
+
+        if (obj.getParticleInfluencer().getClass().getSuperclass() == DefaultParticleInfluencer.class) {
+            createEmbedFields(DefaultParticleInfluencer.class, set2, obj.getParticleInfluencer());
+        }
+
+        createEmbedFields(obj.getParticleInfluencer().getClass(), set2, obj.getParticleInfluencer());
+        sheet.put(set2);
+    }
+
+    protected void createEmbedFields(Class c, Sheet.Set set, Object obj) throws SecurityException {
+        for (Field field : c.getDeclaredFields()) {
+            PropertyDescriptor prop = PropertyUtils.getPropertyDescriptor(c, field);
+            if (prop != null) {
+                set.put(makeEmbedProperty(obj, obj.getClass(), prop.getPropertyType(), prop.getReadMethod().getName(), prop.getWriteMethod().getName(), prop.getDisplayName()));
+            }
+        }
+    }
 
     @Override
     public void propertyChange(String name, Object before, Object after) {
@@ -124,6 +160,10 @@ public class JmeParticleEmitter extends JmeGeometry {
             fireSave(true);
             firePropertyChange(name, before, after);
         }
+        if (name.equals("ParticleInfluencer")) {
+            geom.setParticleInfluencer((ParticleInfluencer) after);
+            createParticleInfluencerSet(sheet, geom);
+        }
 
     }