import com.blaxxun.x3d.*; import com.blaxxun.bx3d.blaxxun3d; import java.awt.*; import java.util.Hashtable; import java.util.Enumeration; /** * d3d - dynamic adding and removing nodes within blaxxun3d * * shows how to realize dynamical adding and removing from nodes * * @author marc kaufmann (mk), blaxxun interactive * @version 1.0 **/ public class d3d extends java.applet.Applet implements EventObserver {//, ItemListener{ java.awt.Choice geometry = new java.awt.Choice(); java.awt.Choice color = new java.awt.Choice(); java.awt.Button insert = new java.awt.Button(); java.awt.Button remove = new java.awt.Button(); java.awt.List messages = new java.awt.List(4); java.awt.Label geometryLabel = new java.awt.Label(); java.awt.Label colorLabel = new java.awt.Label(); protected Browser browser=null; protected Node root=null; protected Field children=null; private Node[] emptyNode=null; protected Hashtable insertedNodes; private final static String CONE="Cone"; private final static String CUBE="Cube"; private final static String SPHERE="Sphere"; private final static float[] RED={1,0,0}; private final static float[] GREEN={0,1,0}; private final static float[] BLUE={0,0,1}; private final static String NO_NODE_SELECTED="No node selected. Please select node in geometry choice box above."; private final static String NO_COLOR_SELECTED="No color selected. Please select color in color choice box above."; private final static String NODE_DOES_NOT_EXIST="Node does not exist!"; /** * Initializes the applet **/ public void init() { insertedNodes=new Hashtable(); setLayout(null); setSize(351,130); geometry.addItem("Cone"); geometry.addItem("Cube"); geometry.addItem("Sphere"); geometry.addItem("Select geometry"); try { geometry.select(3); } catch (IllegalArgumentException e) { } add(geometry); geometry.setBounds(0,24,132,25); add(geometryLabel); geometryLabel.setBounds(0,0,132,24); color.addItem("red"); color.addItem("green"); color.addItem("blue"); color.addItem("Select color"); try { color.select(3); } catch (IllegalArgumentException e) { } add(color); color.setBounds(252,24,100,25); insert.setLabel("insert"); add(insert); insert.setBackground(java.awt.Color.lightGray); insert.setBounds(132,24,60,24); remove.setLabel("remove"); add(remove); remove.setBackground(java.awt.Color.lightGray); remove.setBounds(192,24,60,24); add(messages); messages.setBounds(0,48,351,84); geometryLabel.setText("geometry"); geometryLabel.setAlignment(java.awt.Label.CENTER); add(geometryLabel); colorLabel.setText("color"); colorLabel.setAlignment(java.awt.Label.CENTER); add(colorLabel); colorLabel.setBounds(252,0,100,24); } public void start() { while (browser==null) { browser=blaxxun3d.getBrowser("browser"); System.out.println("Connecting to browser.."); hesitate(); } System.out.println("Got browser.."); browser.addAWTObserver(this); browser.addBrowserObserver(this); // wait till bx3d completes its startup while (browser.getWorld()==null) { hesitate(); } System.out.println("World loaded."); connectNodes(); } /** * waits 500 ms */ private void hesitate() { try { Thread.sleep(500); } catch (InterruptedException e) {} } /** * Destroys the applet **/ public void destroy() { browser.removeAWTObserver(this); browser.removeBrowserObserver(this); super.destroy(); } /** * handles awt event */ public boolean handleEvent(java.awt.Event evt) { switch(evt.id) { case java.awt.Event.ACTION_EVENT: // user clicked on insert button if (evt.target==insert) loadNode();// load node // user clicked on remove button if (evt.target==remove) removeNode();// remove node // user may have changed color value if (evt.target==color) changeColor(); } return false; } /** * Handles awt events sent from the x3d browser * * @param e The java.awt.Event * **/ public boolean onEvent(java.awt.Event event) { // No AWT events are observed in this application. // so simple hand over the event through other event listener return false; } /** * Handles render events sent from the x3d browser * * @param type the type of the event e.g. URL_LOADED, which is of key interest in this * sample. * @param object the object that is associated with the event, Field or Node. object might be * null for certain events, e.g. SHUTDOWN. In case of a URL_LOADED event it contains the parsed * nodes wrapped into a group node * @param userdata the userdata that was specified when registering for the event. This * parameter is normally used to identify different events of the same type. * E.G. you are registering for touch_time events of two touchSensors. Both touch_time * events will be reported to the onEvent method of registered event observer. Both events * have the same event types FIELD_CHANGES. How to differenciate? * Specify your own userData when registering for the event. This userData will also reported * to the event method and enables you to differentiate **/ public boolean onEvent(int type, Object object, Object userData){ switch (type) { // in this example we are only interested in URL_LOADED events case URL_LOADED: { if (userData!=null) { // node parsed messages.addItem("Node "+userData+" loaded and parsed."); Node groupNode=(Node) object; /* Note: the parsed nodes are automatically wrapped by blaxxun3d into a group node so if you want to get special references to nodes inside the parsed node graph, you have to unwrap them with accessing the children node of this group node with Node[] actualNodes=parsedNode.getField("children").getValueNodeArray(0,-1); parsedNode: Group { children [ # here come the actual nodes from the parsed vrml file ] } */ // unwrap Node[] parsedNodes=groupNode.getField("children").getValueNodeArray(0,-1); Node parsedNode=parsedNodes[0]; // access first node insertNode(parsedNode,(String)userData); } } } return false; // let other event handler handle this event also } /** * advise blaxxun3d to create selected node */ private void loadNode() { // get selected item String item=geometry.getSelectedItem(); // Node already inserted? if (insertedNodes.containsKey(item)) { messages.addItem("Node already inserted!"); return; } // load and parse node if (!item.equals("Select geometry")) { String s=new String(getCodeBase()+"vrml/"+geometry.getSelectedItem()+".wrl"); browser.createX3DFromURL(s,this,item); } else { messages.addItem(NO_NODE_SELECTED); return; } } /** * inserts node into the scenegraph. * * @param node the node to insert * @param nodeID the id of the node used as identifier for enabling access later on */ private void insertNode(Node node, String nodeID){ // save reference in hashtable insertedNodes.put(nodeID,node); setChildren(); // update scenegraph } /** * removes node from scenegraph */ private void removeNode() { String item=new String(geometry.getSelectedItem()); if (item.equals("Select geometry")) { messages.addItem(NO_NODE_SELECTED); return; } if (!insertedNodes.containsKey(item)) { messages.addItem(NODE_DOES_NOT_EXIST); return; } else insertedNodes.remove(item); setChildren(); // update scenegraph messages.addItem(item+" removed."); } /** * updates the scenegraph * * to update blaxxun3d's scenegraph the children field of the scene's root node * (connected in the connectNodes method) is set with the complete set of all * nodes (even those already inserted). * * this is to be shure that blaxxun3d updates all fields of the children node */ private void setChildren() { int i=0; // get all inserted nodes Node [] childs=new Node[insertedNodes.size()]; for (Enumeration e=insertedNodes.elements(); e.hasMoreElements(); ) { childs[i]=(Node)e.nextElement(); i++; } // sync with renderer to avoid deadlocks browser.beginUpdate(); // clear root's children field children.setValueNodeArray(0,-1, emptyNode); // set children by manipulating root's children field children.setValueNodeArray(0, -1, childs); // sync renderer browser.endUpdate(); } /** * changes the color of the selected node */ private void changeColor() { String item=new String(geometry.getSelectedItem()); String colr=new String(color.getSelectedItem()); String matID=new String(); Node[] childs=new Node[3]; Node[] newChilds=new Node[2]; Node mat=null; Field diffCol=null; float[] col=new float[3]; boolean found=false; if (item.equals("Select geometry")) { messages.addItem(NO_NODE_SELECTED); return; } if (colr.equals("Select color")) { messages.addItem(NO_COLOR_SELECTED); return; } if (!insertedNodes.containsKey(item)) { messages.addItem(NODE_DOES_NOT_EXIST); return; } // get node to manipulate Node node=(Node)insertedNodes.get(item); /* get access to its diffuse color field e.g. to the diffuse color field of the node cone: this is an extract of the appropriate vrml file to DEF Cone Transform { translation 2.46 10 0 children [ Shape { appearance Appearance { material DEF ConeMat Material { diffuseColor 0.694 0.11 0.584 # <- should be manipulated } } geometry { # here comes the geometry... } ] } */ Node shape=node.getField("children").getValueNodeArray(0,-1)[0]; Node appearance=shape.getField("appearance").getValueNode(); Node material=appearance.getField("material").getValueNode(); Field diffuseColor=material.getField("diffuseColor"); // set color if (colr.equals("red")) col=RED; else if (colr.equals("blue")) col=BLUE; else if (colr.equals("green")) col=GREEN; browser.beginUpdate();// sync renderer diffuseColor.setValueFloatArray(0,-1,col); browser.endUpdate();// sync renderer } /** * Establishes the connection to nodes * * @return false if connection has not been established, else true **/ protected void connectNodes() { // get root try { root=browser.getNode("ROOT"); children=root.getField("children"); } catch (Exception e) { stop(); } messages.addItem("Got nodes."); // create empty node to flush scenegraph when updating scenegraph emptyNode=browser.createX3DFromString("Transform{children[]}"); } /** * Insert node * * @return false if something went wrong **/ protected boolean insertNode() { String item=new String(geometry.getSelectedItem()); System.out.println("selected Node: "+item); // Node already inserted? if (insertedNodes.containsKey(item)) { messages.addItem("Node already inserted!"); return false; } // load and parse node try { if (!item.equals("Select geometry")) { String s=new String(getCodeBase()+"vrml/"+geometry.getSelectedItem()+".wrl"); System.out.println(s); browser.createX3DFromURL(s,this,item); } else { messages.addItem("No node selected."); return false; } } catch (Exception e) { messages.addItem("Loading nodes not successfull! "+e); return false; } // save the type of current node, used as id in hashtable later return true; } }