/* ========================
* JSynoptic : a free Synoptic editor
* ========================
*
* Project Info: http://jsynoptic.sourceforge.net/index.html
*
* This program is free software; you can redistribute it and/or modify it under the terms
* of the GNU Lesser General Public License as published by the Free Software Foundation;
* either version 2.1 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 Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License along with this
* program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330,
* Boston, MA 02111-1307, USA.
*
* (C) Copyright 2001-2004, by :
* Corporate:
* EADS Corporate Research Center
* Individual:
* Nicolas Brodu
*
* $Id: SceneNodeJava3D.java,v 1.18 2007/06/05 14:32:30 ogor Exp $
*
* Changes
* -------
* 19-Mar-2004 : Creation date (NB);
*
*/
package syn3d.nodes.java3d;
import java.io.File;
import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.BitSet;
import java.util.List;
import javax.media.j3d.AmbientLight;
import javax.media.j3d.Appearance;
import javax.media.j3d.BoundingSphere;
import javax.media.j3d.BranchGroup;
import javax.media.j3d.Canvas3D;
import javax.media.j3d.ColoringAttributes;
import javax.media.j3d.DirectionalLight;
import javax.media.j3d.Group;
import javax.media.j3d.LineArray;
import javax.media.j3d.Node;
import javax.media.j3d.PolygonAttributes;
import javax.media.j3d.Shape3D;
import javax.media.j3d.Switch;
import javax.swing.JFileChooser;
import javax.swing.JOptionPane;
import javax.swing.filechooser.FileFilter;
import javax.vecmath.Color3f;
import javax.vecmath.Matrix4f;
import javax.vecmath.Point3d;
import javax.vecmath.Vector3f;
import syn3d.base.ActiveNode;
import syn3d.nodes.NodeResourcesManager;
import syn3d.nodes.SceneChangeListener;
import syn3d.nodes.SceneNode;
import syn3d.ui.java3d.Frame3DJava3D;
import syn3d.util.AxisMaker;
import syn3d.base.PluginManager;
import com.sun.j3d.utils.universe.SimpleUniverse;
/**
*
*/
public class SceneNodeJava3D extends SceneNode implements SceneChangeListener, Serializable {
static final long serialVersionUID = 764198042804925685L;
protected transient SimpleUniverse universe;
protected transient BranchGroup rootGroup, branchgroup;
protected transient Canvas3D canvas3D;
protected transient Frame3DJava3D frame;
protected transient DirectionalLight[] lights;
// -1 : rotate view, >=0 : rotate light[rotationMode]
protected int lightRotationMode = -1;
protected transient Shape3D lightVector = null;
protected int detachKey = 0;
protected transient Switch mainSwitch;
protected transient BranchGroup axisGroup;
// Properties related to the frame 3D and serialized
private transient boolean isVisible = false;
private transient Matrix4f rot,zoom,trans;
private transient int x,y,width,height;
private transient int pos2DX, pos2DY;
/** A reference to the pluginManager scene **/
protected transient PluginManager pluginManager;
public SceneNodeJava3D(ActiveNode parent, PluginManager pm) {
super(parent);
setName( NodeResourcesManager.getResources().getString("SceneName") + (parent.getChildren().size()));
pluginManager = pm;
java.awt.GraphicsConfiguration r = SimpleUniverse.getPreferredConfiguration();
canvas3D = new Canvas3D(r);
canvas3D.setDoubleBufferEnable(true);
universe = new SimpleUniverse(canvas3D);
rootGroup = new BranchGroup();
rootGroup.setCapability(BranchGroup.ALLOW_DETACH);
rootGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
rootGroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
rootGroup.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
branchgroup = new BranchGroup();
branchgroup.setCapability(BranchGroup.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
branchgroup.setCapability(BranchGroup.ALLOW_BOUNDS_READ);
branchgroup.setCapability(BranchGroup.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);
branchgroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
branchgroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
branchgroup.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
// TODO use light factories
AmbientLight alight = new AmbientLight(true,new Color3f(0.5f,0.5f,0.5f));
alight.setEnable(true);
rootGroup.addChild(alight);
BoundingSphere bounds = new BoundingSphere (new Point3d (0, 0.0, 0), 1E100);
alight.setInfluencingBounds(bounds);
lights = new DirectionalLight[1];
for (int i=0; i<lights.length; ++i) {
// TODO : position lights around the object
lights[i] = new DirectionalLight(true,new Color3f(1.0f,1.0f,1.0f),new Vector3f(-1,-1,-1));
lights[i].setCapability(DirectionalLight.ALLOW_DIRECTION_READ);
lights[i].setCapability(DirectionalLight.ALLOW_DIRECTION_WRITE);
lights[i].setCapabilityIsFrequent(DirectionalLight.ALLOW_DIRECTION_READ);
lights[i].setCapabilityIsFrequent(DirectionalLight.ALLOW_DIRECTION_WRITE);
lights[i].setEnable(true);
lights[i].setInfluencingBounds(bounds);
rootGroup.addChild(lights[i]);
}
// X axis in blue
axisGroup = new BranchGroup();
float[] axis = AxisMaker.makeAxis(0);
LineArray la = new LineArray(axis.length/3, LineArray.COORDINATES);
la.setCoordinates(0,axis);
Appearance a = new Appearance();
a.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_LINE, PolygonAttributes.CULL_NONE, 0));
ColoringAttributes ca = new ColoringAttributes();
ca.setColor(0.0f,0.0f,1.0f);
a.setColoringAttributes(ca);
Shape3D saxis = new Shape3D(la, a);
axisGroup.addChild(saxis);
// Y axis in green
axis = AxisMaker.makeAxis(1);
la = new LineArray(axis.length/3, LineArray.COORDINATES);
la.setCoordinates(0,axis);
a = new Appearance();
a.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_LINE, PolygonAttributes.CULL_NONE, 0));
ca = new ColoringAttributes();
ca.setColor(0.0f,1.0f,0.0f);
a.setColoringAttributes(ca);
saxis = new Shape3D(la, a);
axisGroup.addChild(saxis);
// Z axis in purple
axis = AxisMaker.makeAxis(2);
la = new LineArray(axis.length/3, LineArray.COORDINATES);
la.setCoordinates(0,axis);
a = new Appearance();
a.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_LINE, PolygonAttributes.CULL_NONE, 0));
ca = new ColoringAttributes();
ca.setColor(1.0f,0.0f,1.0f);
a.setColoringAttributes(ca);
saxis = new Shape3D(la, a);
axisGroup.addChild(saxis);
mainSwitch = new Switch(Switch.CHILD_MASK);
mainSwitch.addChild(branchgroup);
mainSwitch.addChild(axisGroup);
mainSwitch.setCapability(Switch.ALLOW_SWITCH_READ);
mainSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE);
BitSet bs = mainSwitch.getChildMask();
bs.set(0,true);
bs.set(1,true);
mainSwitch.setChildMask(bs);
rootGroup.addChild(mainSwitch);
universe.addBranchGraph(rootGroup);
// Picking setup
//rootGroup.setPickable(true);
//branchgroup.setPickable(true);
branchgroup.setUserData(this);
frame = null; // lazy creation
}
public List getActions() {
List l = super.getActions();
for (int i=0; i<lights.length; ++i) {
if (i!=lightRotationMode)
l.add("Rotate Light "+(i+1));
}
if (lightRotationMode!=-1)
l.add("Rotate View");
if (mainSwitch.getChildMask().get(1))
l.add("Hide axis");
else l.add("Show axis");
if (fileName!=null)
l.add(NodeResourcesManager.getResources().getStringValue("Save"));
l.add(NodeResourcesManager.getResources().getStringValue("SaveAs"));
l.add(NodeResourcesManager.getResources().getStringValue("Delete"));
return l;
}
public void doAction(Object action) {
if (action.toString().startsWith("Rotate Light ")) {
lightRotationMode = Integer.parseInt(action.toString().substring("Rotate Light ".length())) - 1;
Vector3f direction = new Vector3f();
lights[lightRotationMode].getDirection(direction);
showLightVector(direction.x,direction.y,direction.z);
}else if (action.equals("Rotate View")) {
lightRotationMode = -1;
if (lightVector!=null) {
detach();
rootGroup.removeChild(lightVector);
lightVector = null;
attach();
}
}else if (action.equals("Hide axis")) {
BitSet bs = mainSwitch.getChildMask();
bs.set(1,false);
mainSwitch.setChildMask(bs);
}else if (action.equals("Show axis")) {
BitSet bs = mainSwitch.getChildMask();
bs.set(1,true);
mainSwitch.setChildMask(bs);
}else if (action.equals(NodeResourcesManager.getResources().getStringValue("SaveAs"))) {
// Select a Systema file
Java3DPlugin3DFileFilter filter = new Java3DPlugin3DFileFilter();
JFileChooser chooser = new JFileChooser();
chooser.setAcceptAllFileFilterUsed(false);
chooser.setFileFilter(filter);
int returnVal = chooser.showDialog(null, NodeResourcesManager.getResources().getString("SaveAs"));
if (returnVal == JFileChooser.APPROVE_OPTION){
File f = chooser.getSelectedFile();
fileName = new String();
String sceneName = new String();
if (f.getAbsolutePath().indexOf(".") != -1){
fileName = f.getAbsolutePath().substring(0,f.getAbsolutePath().indexOf("."));
sceneName = f.getName().substring(0,f.getName().indexOf("."));
}else{
fileName = f.getAbsolutePath();
sceneName = f.getName();
}
f = new File(fileName + "." + NodeResourcesManager.getResources().getStringValue("Java3DFilterExtension"));
saveSceneJava3D(f);
setName(sceneName);
}
}else if (action.equals(NodeResourcesManager.getResources().getString("Save"))) {
File f = new File(fileName + "." + NodeResourcesManager.getResources().getString("Java3DFilterExtension"));
saveSceneJava3D(f);
}else if (action.equals(NodeResourcesManager.getResources().getStringValue("Delete"))) {
removeSceneJ3D();
}
super.doAction(action);
}
// don't know how or why the scene would be removed, but let's do it cleanly
public void remove() {
if (frame!=null) frame.getPeerWindow().dispose();
super.remove();
}
public Object get3DObject() {
return branchgroup;
}
/* (non-Javadoc)
* @see syn3d.nodes.SceneNode#isVisible()
*/
public boolean isVisible() {
if (frame==null) return false;
return frame.getPeerWindow().isVisible();
}
/* (non-Javadoc)
* @see syn3d.nodes.SceneNode#setVisible(boolean)
*/
public void setVisible(boolean status) {
if (frame==null) {
frame = new Frame3DJava3D(this, "Java3D frame",-1,-1,400,400, pluginManager);
addListener(this);
}
else frame.getPeerWindow().setVisible(status);
}
/**
* Restore scene : subclasses can restore the scene once all ActiveNOde have been initialised
* @param pm
*/
public void restoreScene(PluginManager pm){
super.restoreScene(pm);
pluginManager = pm;
// Restore properties related the the frame 3D
if (isVisible){
frame = new Frame3DJava3D(this, "Java3D frame",x,y,width,height, pluginManager);
frame.setRot(rot);
frame.setTrans( trans);
frame.setZoom(zoom);
frame.setPos2DX(pos2DX);
frame.setPos2DY(pos2DY);
addListener(this);
frame.getPeerWindow().setVisible(true);
}
}
/**
* @return Returns the canvas3D associated to this universe
*/
public Canvas3D getCanvas3D() {
return canvas3D;
}
/**
* @return Returns the universe.
*/
public SimpleUniverse getUniverse() {
return universe;
}
/**
* @return Returns the lights.
*/
public DirectionalLight[] getLights() {
return lights;
}
/**
* @return Returns the rotationMode.
*/
public int getLightRotationMode() {
return lightRotationMode;
}
/**
* @return Returns the branchgroup.
*/
public BranchGroup getBranchgroup() {
return branchgroup;
}
/** Allow modifications to the scene by detaching the main branchgroup */
public void detach() {
detach(0);
}
/** Allow the scene to be displayed by attaching the main branchgroup */
public void attach() {
attach(0);
}
/** Allow modifications to the scene by detaching the main branchgroup */
public static void detach(ActiveNode node) {
detach(node, 0);
}
/** Allow the scene to be displayed by attaching the main branchgroup */
public static void attach(ActiveNode node) {
attach(node,0);
}
/**
* Allow modifications to the scene by detaching the main branchgroup
* Attaching will be accepted only with the given key
* => this allows a code to detach once for all, and call functions
* that do attach/detach with other or no keys
* => the higher level detach/attach is the only one taken in account
* Tip: use Object.hashCode() to get a unique ID.
* Note: key 0 is the default. Thus, a current detachKey != 0 prevents
* default attach/detach ops.
*/
public void detach(int key) {
if ((detachKey!=0) && (key!=detachKey)) return;
universe.getLocale().removeBranchGraph(rootGroup);
detachKey = key;
}
/** Allow the scene to be displayed by attaching the main branchgroup */
public void attach(int key) {
if (key!=detachKey) return;
universe.getLocale().addBranchGraph(rootGroup);
detachKey = 0; // reset to allow default detach ops to work
}
/** Allow modifications to the scene by detaching the main branchgroup */
public static void detach(ActiveNode node, int key) {
SceneNodeJava3D scene = (SceneNodeJava3D)SceneNode.getScene(node);
scene.detach(key);
}
/** Allow the scene to be displayed by attaching the main branchgroup */
public static void attach(ActiveNode node, int key) {
SceneNodeJava3D scene = (SceneNodeJava3D)SceneNode.getScene(node);
scene.attach(key);
}
/** Helper to add a child to a group at run-time. Avoids code dup */
public static void addChildToParentGroup(Group j3dGroup, Node j3dChild) {
Object o = j3dChild.getUserData();
if (o instanceof ActiveNode) {
SceneNodeJava3D scene = (SceneNodeJava3D)SceneNode.getScene((ActiveNode)o);
if (scene!=null) scene.detach();
j3dGroup.setCapability(Group.ALLOW_CHILDREN_EXTEND);
j3dGroup.addChild(j3dChild);
if (scene!=null) scene.attach();
}
}
/** Helper to remove a child from a group at run-time. Avoids code dup */
public static void removeChildFromParentGroup(Node j3dChild) {
Object o = j3dChild.getUserData();
if (o instanceof ActiveNode) {
SceneNodeJava3D scene = (SceneNodeJava3D)SceneNode.getScene((ActiveNode)o);
if (scene!=null) scene.detach();
// cannot get parent of live object => wait till now to check if parent is really a group
((Group)j3dChild.getParent()).setCapability(Group.ALLOW_CHILDREN_WRITE);
((Group)j3dChild.getParent()).removeChild(j3dChild);
if (scene!=null) scene.attach();
}
}
/* (non-Javadoc)
* @see syn3d.nodes.SceneChangeListener#sceneChanged(syn3d.nodes.SceneNode)
*/
public void sceneChanged(SceneNode scene) {
if (isVisible()) {
frame.getView().repaint();
}
}
public void showLightVector(float x, float y, float z) {
detach();
if (lightVector!=null) rootGroup.removeChild(lightVector);
float[] vectorCoords = new float[] {
0,0,0, x,y,z
};
LineArray la = new LineArray(2, LineArray.COORDINATES);
la.setCoordinates(0,vectorCoords);
Appearance a = new Appearance();
a.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_LINE, PolygonAttributes.CULL_NONE, 0));
ColoringAttributes ca = new ColoringAttributes();
ca.setColor(1.0f,1.0f,0.0f);
a.setColoringAttributes(ca);
lightVector = new Shape3D(la, a);
rootGroup.addChild(lightVector);
attach();
}
// Parent overloads => redirect to the frame
public void init2DPosition(int posX, int posY) {
frame.init2DPosition(posX, posY);
}
public void rotate2D(int newX, int newY) {
frame.rotate2D(newX, newY);
}
public void translate2D(int newX, int newY) {
frame.translate2D(newX, newY);
}
public void zoom(int zoomIncrement) {
frame.zoom(zoomIncrement);
}
public void zoom2D(int newX, int newY) {
frame.zoom2D(newX, newY);
}
public void changeProjection() {
frame.changeProjection();
}
public void reset() {
frame.reset();
}
public void autoZoom() {
frame.autoZoom();
}
public ArrayList toggleSinglePick(int posX, int posY) {
return frame.toggleSinglePick(posX,posY);
}
public ArrayList toggleAllPicks(int posX, int posY) {
return frame.toggleAllPicks(posX,posY);
}
public ActiveNode pick(int posX, int posY) {
return frame.pick(posX,posY);
}
private void writeObject(java.io.ObjectOutputStream out) throws java.io.IOException {
out.defaultWriteObject();
if (frame!=null){
out.writeBoolean(true);
// visible
out.writeBoolean(this.isVisible());
// taille et position de la fenetre
out.writeInt(frame.getPeerWindow().getX());
out.writeInt(frame.getPeerWindow().getY());
out.writeInt(frame.getPeerWindow().getWidth());
out.writeInt(frame.getPeerWindow().getHeight());
// Matrices de transformation, rotation et zoom concernant la cam�ra
out.writeObject(frame.getRot());
out.writeObject(frame.getTrans());
out.writeObject(frame.getZoom());
out.writeInt(frame.getPos2DX());
out.writeInt(frame.getPos2DY());
}else
out.writeBoolean(false);
}
private void readObject(java.io.ObjectInputStream in) throws java.lang.ClassNotFoundException, java.io.IOException {
in.defaultReadObject();
// Restore properties related to the frame 3D
if (in.readBoolean()){
isVisible = in.readBoolean();
// taille et position de la fenetre
x = in.readInt();
y = in.readInt();
width = in.readInt();
height = in.readInt();
// Matrices de transformation, rotation et zoom concernant la cam�ra
rot = (Matrix4f)in.readObject();
trans = (Matrix4f)in.readObject();
zoom = (Matrix4f)in.readObject();
pos2DX = in.readInt();
pos2DY = in.readInt();
}
java.awt.GraphicsConfiguration r = SimpleUniverse.getPreferredConfiguration();
canvas3D = new Canvas3D(r);
canvas3D.setDoubleBufferEnable(true);
universe = new SimpleUniverse(canvas3D);
rootGroup = new BranchGroup();
rootGroup.setCapability(BranchGroup.ALLOW_DETACH);
rootGroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
rootGroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
rootGroup.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
branchgroup = new BranchGroup();
branchgroup.setCapability(BranchGroup.ALLOW_AUTO_COMPUTE_BOUNDS_READ);
branchgroup.setCapability(BranchGroup.ALLOW_BOUNDS_READ);
branchgroup.setCapability(BranchGroup.ALLOW_AUTO_COMPUTE_BOUNDS_WRITE);
branchgroup.setCapability(BranchGroup.ALLOW_CHILDREN_READ);
branchgroup.setCapability(BranchGroup.ALLOW_CHILDREN_WRITE);
branchgroup.setCapability(BranchGroup.ALLOW_CHILDREN_EXTEND);
// TODO use light factories
AmbientLight alight = new AmbientLight(true,new Color3f(0.5f,0.5f,0.5f));
alight.setEnable(true);
rootGroup.addChild(alight);
BoundingSphere bounds = new BoundingSphere (new Point3d (0, 0.0, 0), 1E100);
alight.setInfluencingBounds(bounds);
lights = new DirectionalLight[1];
for (int i=0; i<lights.length; ++i) {
// TODO : position lights around the object
lights[i] = new DirectionalLight(true,new Color3f(1.0f,1.0f,1.0f),new Vector3f(-1,-1,-1));
lights[i].setCapability(DirectionalLight.ALLOW_DIRECTION_READ);
lights[i].setCapability(DirectionalLight.ALLOW_DIRECTION_WRITE);
lights[i].setCapabilityIsFrequent(DirectionalLight.ALLOW_DIRECTION_READ);
lights[i].setCapabilityIsFrequent(DirectionalLight.ALLOW_DIRECTION_WRITE);
lights[i].setEnable(true);
lights[i].setInfluencingBounds(bounds);
rootGroup.addChild(lights[i]);
}
// X axis in blue
axisGroup = new BranchGroup();
float[] axis = AxisMaker.makeAxis(0);
LineArray la = new LineArray(axis.length/3, LineArray.COORDINATES);
la.setCoordinates(0,axis);
Appearance a = new Appearance();
a.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_LINE, PolygonAttributes.CULL_NONE, 0));
ColoringAttributes ca = new ColoringAttributes();
ca.setColor(0.0f,0.0f,1.0f);
a.setColoringAttributes(ca);
Shape3D saxis = new Shape3D(la, a);
axisGroup.addChild(saxis);
// Y axis in green
axis = AxisMaker.makeAxis(1);
la = new LineArray(axis.length/3, LineArray.COORDINATES);
la.setCoordinates(0,axis);
a = new Appearance();
a.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_LINE, PolygonAttributes.CULL_NONE, 0));
ca = new ColoringAttributes();
ca.setColor(0.0f,1.0f,0.0f);
a.setColoringAttributes(ca);
saxis = new Shape3D(la, a);
axisGroup.addChild(saxis);
// Z axis in purple
axis = AxisMaker.makeAxis(2);
la = new LineArray(axis.length/3, LineArray.COORDINATES);
la.setCoordinates(0,axis);
a = new Appearance();
a.setPolygonAttributes(new PolygonAttributes(PolygonAttributes.POLYGON_LINE, PolygonAttributes.CULL_NONE, 0));
ca = new ColoringAttributes();
ca.setColor(1.0f,0.0f,1.0f);
a.setColoringAttributes(ca);
saxis = new Shape3D(la, a);
axisGroup.addChild(saxis);
mainSwitch = new Switch(Switch.CHILD_MASK);
mainSwitch.addChild(branchgroup);
mainSwitch.addChild(axisGroup);
mainSwitch.setCapability(Switch.ALLOW_SWITCH_READ);
mainSwitch.setCapability(Switch.ALLOW_SWITCH_WRITE);
BitSet bs = mainSwitch.getChildMask();
bs.set(0,true);
bs.set(1,true);
mainSwitch.setChildMask(bs);
rootGroup.addChild(mainSwitch);
universe.addBranchGraph(rootGroup);
// Picking setup
//rootGroup.setPickable(true);
//branchgroup.setPickable(true);
branchgroup.setUserData(this);
frame = null; // lazy creation
}
public boolean saveSceneJava3D(File f){
System.out.println("saving" + f.getName());
try {
FileOutputStream fos = new FileOutputStream(f);
ObjectOutputStream os = new ObjectOutputStream(fos);
os.writeObject(this);
os.writeObject(null); // ascending compatibility
os.flush();
os.close();
fos.close(); // also closes the file
} catch (java.io.IOException ioe) {
ioe.printStackTrace();
System.err.println(NodeResourcesManager.getResources().getStringValue("cannotSaveFile") + f.getName());
return false;
}
System.out.println(NodeResourcesManager.getResources().getStringValue("saveOk") + f.getName());
return true;
}
public void removeSceneJ3D(){
removeNodeTree();
}
class Java3DPlugin3DFileFilter extends FileFilter{
public boolean accept(File f) {
if (f.isDirectory()) return true;
String name = f.getName();
return name.toLowerCase().endsWith("." + NodeResourcesManager.getResources().getStringValue("Java3DFilterExtension"));
}
public String getDescription() {
return NodeResourcesManager.getResources().getStringValue("Java3DFilterDescription") + " (*." + NodeResourcesManager.getResources().getStringValue("Java3DFilterExtension") + ")";
}
}
}