|
From: Mark R. D. <mdi...@la...> - 2003-08-11 16:46:46
|
Phil Feldman wrote: > Hi Mark, > > Here's the code for DisplaySurface3D. Let me know what questions you have. > I'll take a look at it this evening, thanks! > Initially, I also wanted to separate appearance from behavior, but it > really got too difficult. Imagine an agent that can walk and move its > limbs, with collision detection and response for all surfaces. The > geometry and the behavior are so tied together that separating them > would entail a massive data channel between them, at which point you've > negated the advantage. I don't think I will get that detailed when it comes to rendering, I think initially it should be kept to simple polygons that fit in the grid structure, like in 2D with some similar support like SimGraphics.drawFastCircle()... This way we can start with some simple rendering support and expand from there, but still keep the presentation separate from the data model. Issues such as collision avoidance an animation are probably more advanced features that I would not necessarily want the display engine to handle because theres too much of a mix between model and presentation if one uses them. For example, If one were to write a 2D model, lets say it had individual agents that grew over time to acquire more "grid" locations on an Object2DGrid, then the control over if two agents are occupying the same grid location would be programmed into the model itself and not really be the responsibility of the Object2DDisplay to control. I think grids give us a simple starting point for working with this sort of behavior in 3D as well. > > BTW, it appears that Java3D will not be supported (or at least not > actively developed) by Sun in the future, so I'd reccomend implementing > on some other platform. > > Regards, > > Phil Feldman > This is the benefit of keeping the Data Model and the Presentation separate, depending on the technology that become "prevalent" in the future, there will be room to expand the visualization onto that platform without having to "rewrite" any particular model implementations themselves. With this in mind, working with Java3D is still ok even if Sun's scaling down its development (note, Sun also scaled down its development of JNDI and LDAP after its initial development, yet these are still prevalent packages that get allot of use). I'm sure if other 3D technologies arise for java that there will be discussion in the community in relation to migrating from Java3D to such technologies. Cheers, Mark >> I would be interested in seeing how you've built the (DisplaySurface) >> rendering of your vector of objects in 3D. When it boils down to it, >> even when rendering 2D grids, the optimized way of doing it is to >> iterate over the ArrayList of Agents. We would apply the same strategy >> in 3d, only the Display engine would be the 3D scene graph instead of >> the 2D DisplaySurface >> >> From my understanding of Java 3D theres considerable work to implement >> it on top of graphics acceleration on many different platforms: >> http://www.j3d.org/download.html >> >> I've seen it run quite efficiently on a project that provides Java >> based 3D visualization of Complex Protien Molecules: >> http://mbt.sdsc.edu/ >> >> I've been extending my topology.space library to also support 3D >> spaces as grids. Alot of work still needs to get done in separating >> the displays "presentation" from the Data Model when it comes to >> displaying objects/grids of objects in both 2D and 3D. >> >> Unfortunately, the old space/display library approaches rendering by >> mixing the presentation and data objects at the "Agent" level, this >> means that agents are both "Data Objects" and "Display Objects" for >> the 2D DisplaySurface. This is problematic when using different >> implementations for display rendering 2D, 3D, various GIS tools, etc). >> >> Our future intent it to separate the objects data and presentation >> aspects so that the "presentation" of the object is not encapsulated >> in the same class as the object itself. This way the object may hold >> the information about its position, but the DisplaySurface/Volumn will >> manage the presentation aspects separately via some sort of >> "stylesheet" strategy. >> >> -Mark >> >> Phil Feldman wrote: >> >>> For my stuff, I worked entirely in VectorSpace. Basically, I create a >>> pile of objects and build a java3d scene graph out of them. Then it's >>> a matter of moving things about. For a DescreteSpace (cell-based) >>> system, it might make sense to look at volume rendering, since each >>> texel could cerrespond to a cell. The problem is that I'm not sure if >>> it's yet possible to update a 3D texture in real time on anything >>> other than an SGI. There-s a lot of memory to move. Isosurfaces could >>> also work, but you'd have to avoid the scene graph. SGI and SUN are >>> coming out with "OEM" java bindings to openGL, so that might be the >>> way to go. >>> >>> Phil Feldman >>> >>>> I suspect it would be fun for us to explore the future of >>>> Object3DSpaces for our new topology.space library we've been >>>> building too. with the establishment of a Spaces methods only >>>> accepting/returning "Locations" instead of x/y coordinates, this >>>> would free us up to make > 2 dimensional spaces without being >>>> restricted by the interfaces. >>>> >>>> >>>> interface DiscreteSpace { >>>> >>>> public Location removeLocation(Location loc); >>>> >>>> public Location getLocation(Location loc); >>>> >>>> public void removeObjectAt(Object obj, Location loc); >>>> >>>> public void putObjectAt(Object obj, Location loc); >>>> >>>> public void getObjectAt(Location loc); >>>> >>>> } >>>> >>>> class Discrete2DSpace implements DiscreteSpace { >>>> >>>> ... >>>> >>>> } >>>> >>>> class Discrete3DSpace implements DiscreteSpace { >>>> >>>> ... >>>> >>>> } >>>> >>>> class Object2DLocation implements Location{ >>>> >>>> public int getX(){ >>>> ... >>>> } >>>> >>>> public int getY(){ >>>> ... >>>> } >>>> >>>> } >>>> >>>> >>>> class Object3DLocation extends Object2DLocation{ >>>> >>>> public int getZ(){ >>>> ... >>>> } >>>> >>>> } >>>> >>>> I imagine it would be interesting to have Different "Display >>>> Surfaces" for the space, imagine "top", "side", "front", "isometric" >>>> and "3D adjustable" Displays, the 2D (top, side, front) Could easily >>>> be superimposed on a 2D DisplaySurface while a 3D display surface >>>> would need to be created for isometric and adjustable 3D Displays. >>>> >>>> -Mark >>>> >>>> >>>> Phil Feldman wrote: >>>> >>>>> I've been doing a lot of work in that area for the past year or so. >>>>> It's not quite ready for prime time, but I may be able to help you >>>>> out a bit. >>>>> >>>>> Phil Feldman >>>>> >>>>>> Has anyone done any work on 3d-space models (like Heatbugs in >>>>>> 3d-space) in Repast or anyone planning on it ? Like with Java3D ? >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> >>>>> ------------------------------------------------------- >>>>> This SF.Net email sponsored by: Free pre-built ASP.NET sites including >>>>> Data Reports, E-commerce, Portals, and Forums are available now. >>>>> Download today and enter to win an XBOX or Visual Studio .NET. >>>>> http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01 >>>>> >>>>> _______________________________________________ >>>>> Repast-developer mailing list >>>>> Rep...@li... >>>>> https://lists.sourceforge.net/lists/listinfo/repast-developer >>>> >>>> >>>> >>>> >>>> >>>> >>>> >>>> ------------------------------------------------------- >>>> This SF.Net email sponsored by: Free pre-built ASP.NET sites including >>>> Data Reports, E-commerce, Portals, and Forums are available now. >>>> Download today and enter to win an XBOX or Visual Studio .NET. >>>> http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01 >>>> >>>> _______________________________________________ >>>> Repast-developer mailing list >>>> Rep...@li... >>>> https://lists.sourceforge.net/lists/listinfo/repast-developer >>>> >>> >>> >>> >>> >>> >>> ------------------------------------------------------- >>> This SF.Net email sponsored by: Free pre-built ASP.NET sites including >>> Data Reports, E-commerce, Portals, and Forums are available now. >>> Download today and enter to win an XBOX or Visual Studio .NET. >>> http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01 >>> >>> _______________________________________________ >>> Repast-developer mailing list >>> Rep...@li... >>> https://lists.sourceforge.net/lists/listinfo/repast-developer >> >> >> >> >> >> ------------------------------------------------------- >> This SF.Net email sponsored by: Free pre-built ASP.NET sites including >> Data Reports, E-commerce, Portals, and Forums are available now. >> Download today and enter to win an XBOX or Visual Studio .NET. >> http://aspnet.click-url.com/go/psa00100003ave/direct;at.aspnet_072303_01/01 >> >> _______________________________________________ >> Repast-developer mailing list >> Rep...@li... >> https://lists.sourceforge.net/lists/listinfo/repast-developer >> > > > ------------------------------------------------------------------------ > > package edu.umd.geographs; > > import javax.swing.*; > import java.awt.*; > import java.io.*; > import java.awt.event.*; > import java.lang.reflect.*; > import java.util.ArrayList; > import java.util.Hashtable; > > import javax.media.j3d.*; > import javax.vecmath.*; > > //import com.sun.j3d.utils.geometry.*; > import com.sun.j3d.utils.universe.*; > import com.sun.j3d.utils.image.*; > import com.sun.j3d.utils.picking.*; > import com.sun.j3d.utils.geometry.*; > > import uchicago.src.sim.space.VectorSpace; > import uchicago.src.sim.util.*; > import uchicago.src.sim.gui.Named; > import uchicago.src.sim.engine.CustomProbeable; > import uchicago.src.sim.engine.SimEvent; > import uchicago.src.sim.engine.SimEventListener; > import uchicago.src.reflector.DescriptorContainer; > > > public class DisplaySurface3D > extends JFrame > implements SimEventListener, ItemListener > { > private String name = null; > private JMenu menu = new JMenu("Options"); > private JButton flyDragButton = new JButton("Dragging"); > private JButton freezeThawButton = new JButton("Thawed"); > private Point location = new Point (0, 0); > private SimpleUniverse u = null; > private Canvas3D canvas; > private double rotVal = 0.0; > private BranchGroup rootBG = null; > private TransformGroup rootTG; > private TransformGroup viewerRootTG; > private Xform xform = new Xform(); > private ScrollingMouseData flyMouse; > private ArrayList toRender = new ArrayList(); > private float stepbackDist = 25.0f; > private boolean surfViewable = true; > private boolean isFrozen = false; > private int mouseX = 0; > private int mouseY = 0; > private int index = 0; > private int indent = 0; > private PickCanvas pickCanvas; > private final int BEST_AGENTS = 0; > private final int FASTEST_AGENTS = 1; > private final int NO_AGENTS = 2; > private final int BEST_NODES = 3; > private final int FASTEST_NODES = 4; > private final int NO_NODES = 5; > //private DUpdate du = new DUpdate(); > > private WindowAdapter dsWindowAdapter = new WindowAdapter() > { > public void windowIconified(WindowEvent evt) { > surfViewable = false; > } > > public void windowDeiconified(WindowEvent evt) { > surfViewable = true; > } > > public void windowClosing (WindowEvent evt) { > //f.removeWindowListener (this); > System.out.println("windowClosing "+evt); > removeWindowListener (this); > dispose (); > System.exit (0); > } > > public void windowClosed (WindowEvent evt) { > //System.out.println("windowClosed "+evt); > } > public void windowDeactivated (WindowEvent evt) { > //System.out.println("windowDeactivated "); > } > public void windowStateChanged (WindowEvent evt) { > //System.out.println("windowStateChanged "+evt); > } > }; > > private MouseMotionAdapter dsMouseMotionAdapter = new MouseMotionAdapter() > { > public void mouseDragged(MouseEvent e) > { > //System.out.println("mouseDragged"); > flyMouse.updateDeltas(e.getX(), e.getY()); > } > }; > > private MouseAdapter dsMouseAdapter = new MouseAdapter() > { > public void mousePressed(MouseEvent e) > { > int mods = e.getModifiers(); > if((mods & InputEvent.BUTTON1_MASK) != 0) > flyMouse.setIsRotating(true); // rotate > else if((mods & InputEvent.BUTTON3_MASK) != 0) > flyMouse.setIsRotating(false); // translate > flyMouse.setOldXY(e.getX(), e.getY()); > } > public void mouseReleased(MouseEvent e) > { > flyMouse.reset(); > } > public void mouseClicked(MouseEvent e) > { > pickCanvas.setShapeLocation(e.getX(), e.getY()); > PickResult[] results = pickCanvas.pickAll(); > examinePickResults(results); > } > }; > > class DUpdate implements Runnable > { > public void run() > { > paint(); > } > }; > > > public DisplaySurface3D() > { > this("Untitled"); > } > > public DisplaySurface3D(String name) > { > super(name); > this.name = name; > } > > public void addDisplayabe3D(Drawable3D d) > { > if(d instanceof Drawable3D) > toRender.add(d); > } > > > private void setVisibleFlag(int type) > { > System.out.println("setVisibleFlag = "+type); > for(int i = 0; i < toRender.size(); i++) > { > if(toRender.get(i) instanceof Node3D) > { > //System.out.println("instanceof Node3D"); > Node3D d = (Node3D)toRender.get(i); > if(type == BEST_NODES) > { > d.setDesiredGraphicsStyle(Drawable3D.GR_BEST); > d.switchRenderNode(Drawable3D.GR_BEST); > } > else if(type == FASTEST_NODES) > { > d.setDesiredGraphicsStyle(Drawable3D.GR_FASTEST); > d.switchRenderNode(Drawable3D.GR_FASTEST); > } > else if(type == NO_NODES) > { > d.setDesiredGraphicsStyle(Drawable3D.GR_OFF); > d.switchRenderNode(Drawable3D.GR_OFF); > } > } > else if(toRender.get(i) instanceof Agent3D) > { > Agent3D d = (Agent3D)toRender.get(i); > if(type == BEST_AGENTS) > { > d.setDesiredGraphicsStyle(Drawable3D.GR_BEST); > d.switchRenderNode(Drawable3D.GR_BEST); > } > else if(type == FASTEST_AGENTS) > { > d.setDesiredGraphicsStyle(Drawable3D.GR_FASTEST); > d.switchRenderNode(Drawable3D.GR_FASTEST); > } > else if(type == NO_AGENTS) > { > d.setDesiredGraphicsStyle(Drawable3D.GR_OFF); > d.switchRenderNode(Drawable3D.GR_OFF); > } > } > } > } > > public void itemStateChanged(ItemEvent e) > { > //System.out.println(e.paramString()); > String s = (String)e.getItem(); > if(e.getStateChange() == ItemEvent.SELECTED) > { > System.out.println(s+" selected"); > if(s.equals("Best Agents")) > setVisibleFlag(BEST_AGENTS); > else if(s.equals("Fastest Agents")) > setVisibleFlag(FASTEST_AGENTS); > else if(s.equals("No Agents")) > setVisibleFlag(NO_AGENTS); > else if(s.equals("Best Nodes")) > setVisibleFlag(BEST_NODES); > else if(s.equals("Fastest Nodes")) > setVisibleFlag(FASTEST_NODES); > else if(s.equals("No Nodes")) > setVisibleFlag(NO_NODES); > } > } > > public void simEventPerformed(SimEvent evt) > { > int id = evt.getId(); > //System.out.println("surface got a SimEvent. ID = " + id); > if(id == SimEvent.STOP_EVENT) > { > try{ > //System.out.println("saving mouse position"); > //flyMouse.dump(); > FileOutputStream out = new FileOutputStream("flyMousePos"); > ObjectOutputStream s = new ObjectOutputStream(out); > s.writeObject(flyMouse); > s.flush(); > } > catch (Exception e) > { > //System.out.println("Unable to serialize flyMousePos: "+e); > } > } > } > > public void addVectorSpace(VectorSpace vs) > { > // Go through the VectorSpace's members, see if they are Drawables, > // and if they are, then add them to the toRender list > ArrayList l = vs.getMembers(); > for(int i = 0; i < l.size(); i++) > { > if(l.get(i) instanceof Drawable3D) > toRender.add(l.get(i)); > } > } > > public void setStepBack(float val) > { > stepbackDist = val; > } > > public boolean isRunning() > { > return (!isFrozen); > } > > public boolean isFrozen() > { > return isFrozen; > } > > public boolean isShowing() > { > return surfViewable; > } > > public void hide() > { > super.hide(); > surfViewable = false; > } > > // Creates the 3D display, and for now also loads the scene graph. > // That part may have to be broken out. > public void display() > { > JPanel jp = new JPanel(); > jp.setVisible(true); > jp.setLayout(new BorderLayout()); > > GraphicsConfiguration config = > SimpleUniverse.getPreferredConfiguration(); > canvas = new Canvas3D(config); > > jp.add("Center", canvas); > > try > { > rootBG = createSceneGraph(); > } > catch (FileNotFoundException e) > { > System.out.println(e); > System.exit(-1); > } > //rootBG.compile(); > > u = new SimpleUniverse(canvas); > ViewingPlatform vp = u.getViewingPlatform(); > viewerRootTG = vp.getViewPlatformTransform(); > Viewer viewer = u.getViewer(); > View view = viewer.getView(); > view.setBackClipDistance(100.0); > u.addBranchGraph(rootBG); > pickCanvas = new PickCanvas(canvas, rootBG); > pickCanvas.setMode(PickTool.BOUNDS); > pickCanvas.setTolerance(4.0f); > > setLocation(new Point(10,10)); > setSize(new Dimension(600,500)); > getContentPane().setLayout(new BorderLayout()); > getContentPane().add(jp, BorderLayout.CENTER); > addWindowListener (dsWindowAdapter); > > // make a dropdown menu to support multiple views > String[] views = > { > "home view", > "3/4 view", > "top view" > }; > final JComboBox viewBox = new JComboBox(views); > viewBox.setBorder(BorderFactory.createTitledBorder("Viewing angle")); > viewBox.addActionListener(new ActionListener(){ > public void actionPerformed(ActionEvent e) > { > flyMouse.setIsDragging(true); > flyDragButton.setActionCommand("fly"); > flyDragButton.setText("Dragging"); > flyMouse.setNumberedView(viewBox.getSelectedIndex()); > viewerRootTG.setTransform(flyMouse.getFlyTransform()); > } > }); > > String[] visibleList = > { > "Fastest Agents", > "Best Agents", > "No Agents", > "Fastest Nodes", > "Best Nodes", > "No Nodes", > }; > final JComboBox visibleListBox = new JComboBox(visibleList); > visibleListBox.setBorder( > BorderFactory.createTitledBorder("Visibility")); > visibleListBox.addItemListener(this); > > > > JPanel sidePanel = new JPanel(); > getContentPane().add(sidePanel,BorderLayout.WEST); > > JPanel buttonPanel = new JPanel(); > buttonPanel.setLayout(new GridLayout(6, 1)); > buttonPanel.add(viewBox); > buttonPanel.add(flyDragButton); > buttonPanel.add(freezeThawButton); > buttonPanel.add(visibleListBox); > sidePanel.add(buttonPanel); > setVisible (true); > > canvas.addMouseListener(dsMouseAdapter); > canvas.addMouseMotionListener(dsMouseMotionAdapter); > > flyDragButton.addActionListener(new ActionListener(){ > public void actionPerformed(ActionEvent e) > { > if(e.getActionCommand().equals("fly")) > { > flyMouse.setIsDragging(false); > flyDragButton.setActionCommand("drag"); > flyDragButton.setText("Flying"); > } > if(e.getActionCommand().equals("drag")) > { > flyMouse.setIsDragging(true); > flyDragButton.setActionCommand("fly"); > flyDragButton.setText("Dragging"); > } > } > }); > > freezeThawButton.addActionListener(new ActionListener(){ > public void actionPerformed(ActionEvent e) > { > if(e.getActionCommand().equals("freeze")) > { > freezeThawButton.setActionCommand("thaw"); > freezeThawButton.setText("Frozen"); > isFrozen = true; > } > if(e.getActionCommand().equals("thaw")) > { > freezeThawButton.setActionCommand("freeze"); > freezeThawButton.setText("Thawed"); > isFrozen = false; > } > } > }); > > > // set up the initial viewpoint > try{ > FileInputStream in = new FileInputStream("flyMousePos"); > ObjectInputStream s = new ObjectInputStream(in); > flyMouse = (ScrollingMouseData)s.readObject(); > //System.out.println("Restoring mouse position"); > //flyMouse.dump(); > } > catch (Exception e) > { > flyMouse = new ScrollingMouseData(10.0f); > flyMouse.setIsDragging(false); > flyMouse.stepBack(stepbackDist); > flyMouse.setIsDragging(true); > //System.out.println("Initializing new mouse position: "+e); > } > viewerRootTG.setTransform(flyMouse.getFlyTransform()); > flyDragButton.setActionCommand("fly"); > > freezeThawButton.setActionCommand("freeze"); > } > > // look through an array of PickResults to find an simulation > // object. Basically, this means that we look for a scene graph node > // that has an InfoObject embedded in its userData > private void examinePickResults(PickResult[] results) > { > if(results != null) > { > boolean foundIt = false; > for(int i = 0; i < results.length; i++) > { > // SceneGraphPaths have less irrelevant information than > // PickResult, so just get that > SceneGraphPath path = results[i].getSceneGraphPath(); > if(path != null) > { > // if there are more than one nodes in the branch we're > // looking at, then it's probable that the node we're > // interested in is the 0th node. NOTE!! This needs to > // be rechecked as we start working with more sophisticated > // loaders > //System.out.println(path.toString()); > Node n = null; > if(path.nodeCount() > 0) > { > for(int j = 0; j < path.nodeCount(); j++) > if(checkUserData(path.getNode(j))) > { > foundIt = true; > break; > } > } > else > { > foundIt = checkUserData(path.getObject()); > } > } > if(foundIt) > break; > } > } > } > > private boolean checkUserData(Node n) > { > if(n != null) > { > // Open up a data window as in a RePast Probable object > //System.out.println("Node = " + n.toString()); > ObjectInfo info = (ObjectInfo)n.getUserData(); > if(info != null) > { > //System.out.println("\tInfo = " + info.toString()); > ProbeUtilities.probe(info); > return true; > } > } > return false; > } > > > private void paint() > { > if(flyMouse.isDragging()) > { > rootTG.setTransform(flyMouse.transRot()); > } > else // flying > { > viewerRootTG.setTransform(flyMouse.getFlyTransform()); > } > } > > public void updateDisplay() > { > updateDisplayDirect(); > /*** > try > { > SwingUtilities.invokeAndWait(du); > } > catch(InterruptedException e) > { > // keep interuppting until the thread that called this method > // i.e. BaseControler.runThread terminates. When that terminates > // we are okay. > Thread.currentThread().interrupt(); > } > catch (InvocationTargetException e) > { > e.printStackTrace(); > } > ***/ > } > > public void updateDisplayDirect() > { > paint(); > > } > > public void dispose() > { > System.out.println("Disposing"); > > // Remove all the components from this container > removeAll(); > > // kill the components > canvas.removeMouseListener(dsMouseAdapter); > canvas.removeMouseMotionListener(dsMouseMotionAdapter); > menu = null; > flyDragButton = null; > freezeThawButton = null; > flyMouse = null; > pickCanvas = null; > canvas = null; > rootBG = null; > rootTG = null; > viewerRootTG = null; > for(int i = 0; i < toRender.size(); i++) > { > Object o = toRender.get(i); > o = null; > } > toRender = null; > u.removeAllLocales(); > u = null; > removeWindowListener(dsWindowAdapter); > // serialize the viewpoint information > //f.dispose(); > super.dispose(); > } > > public BranchGroup createSceneGraph() > throws FileNotFoundException > { > BranchGroup rootBG = new BranchGroup(); > rootTG = new TransformGroup(); > > // Add all the renderable elements to the scene graph > for(int i = 0; i < toRender.size(); i++) > { > Drawable3D d = (Drawable3D)toRender.get(i); > BranchGroup bg = d.getBG(); > rootTG.addChild(bg); > } > rootTG.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE); > > rootBG.addChild(rootTG); > > // make lights > Color3f light1Color = new Color3f(1f, 1f, 1f); > // lights need a bounding sphere to know when to turn on > BoundingSphere bounds = > new BoundingSphere(new Point3d(0.0,0.0,0.0), 100.0); > Vector3f light1Direction = new Vector3f(4.0f, -7.0f, -12.0f); > DirectionalLight light1 = > new DirectionalLight(light1Color, light1Direction); > light1.setInfluencingBounds(bounds); > > rootBG.addChild(light1); > > AmbientLight ambientLight = new AmbientLight(new Color3f(.5f,.5f,.5f)); > ambientLight.setInfluencingBounds(bounds); > rootBG.addChild(ambientLight); > > // Set up the background > Color3f bgColor = new Color3f(0.05f, 0.05f, 0.5f); > Background bgNode = new Background(bgColor); > bgNode.setApplicationBounds(bounds); > rootBG.addChild(bgNode); > > rootBG.setCapability(RenderingAttributes.ALLOW_VISIBLE_READ); > rootBG.setCapability(RenderingAttributes.ALLOW_VISIBLE_WRITE); > rootBG.setCapability(Appearance.ALLOW_RENDERING_ATTRIBUTES_READ); > rootBG.setCapability(Appearance.ALLOW_RENDERING_ATTRIBUTES_WRITE); > rootBG.setCapability(RenderingAttributes.ALLOW_VISIBLE_READ); > rootBG.setCapability(RenderingAttributes.ALLOW_VISIBLE_WRITE); > rootBG.setCapability(Shape3D.ALLOW_APPEARANCE_READ); > rootBG.setCapability(Shape3D.ALLOW_APPEARANCE_WRITE); > > return rootBG; > } > } > |