// copyright (c) 1997,1998 stephen f. white
//
// This program is free software; you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 2, 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 General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with this program; see the file COPYING. If not, write to
// the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
package XOO_CODE;
import java.net.*; // for URL stuff
import java.applet.*;
import vrml.external.*;
import vrml.external.Browser;
import vrml.external.field.*;
import rtpi.*;
import rtpi.transport.*;
import rtpi.transport.orta.*;
import rtpi.reliability.ORTA.*;
import vrml.external.FreeWRLEAI.*;
public class SMVWSceneInterface extends Applet implements SMSceneInterface, EventOutObserver
{
// Known port numbers
public static final int IPC_PORT = 8787;
// Maximum number of viewpoint observers
static final int MAX_OBSERVERS = 256;
// Used for status messages
String status;
// Processes XOO messages
SMDispatcher dispatcher;
// Reference to VRML browser
Browser browser;
// Toggle used to indicate whether this is currently connected
boolean on_line;
// Briefcase path and java object
BContents briefcase = null;
String Briefcase;
public boolean MMap;
public MMapThread mmapThread;
DatagramSocket RAT_out_socket;
DatagramSocket RAT_in_socket;
boolean bubbles;
boolean snames;
int RAT_port=3333;
// fields
Node vNet;
// EventOut's
EventOut position;
EventOut orientation;
EventOut on_off;
// EventIn's
EventInSFBool isConnected;
// rootNode EventIn's
EventInMFNode addChildren;
EventInMFNode removeChildren;
EventInMFNode addHudChild;
EventInMFNode removeHudChild;
int MAXNAMES = 4;
public EventInMFNode[] addNames;
public EventInMFNode[] removeNames;
EventInMFNode addBC;
EventInMFNode removeBC;
EventInSFVec3f hudTranslation;
EventInMFNode children;
VSFVec3f hudStandardTranslation;
// viewpoint EventIn's
EventInSFVec3f viewpointPosition;
EventInSFRotation viewpointOrientation;
EventInSFBool viewpointBind;
// Array of viewpoint observers
EAIObject ViewpointObservers[] = new EAIObject[MAX_OBSERVERS];
// RTP/I object (implements RTP/I protocol)
private Rtpi rtpi;
// RTPI/I local participant information
private RtpiSourceInfo localParticipant;
// Reliability service used by RTP/I
private ORTA reliabilityService;
// Local internet address
private InetAddress myAddress;
// Subcomponent ID base number
private long subIDBase;
// byte mask used to construct subcomponent ID base
private static final int BYTE_MASK = 0x000000FF;
// keep track if we're holding something
private boolean holding = false;
private VRMLObject held_object = null;
// Local writer thread used to get updates for VRMLChair setup
LocalWriterThread local_writer;
// GetView thread
GetView get_view;
//GetGlove thread
GetGlove get_glove;
// Cyberglove gesture thread
vrhand gesture_thread;
// Instantiate the class and start it
public static void main(String[] args) {
SMVWSceneInterface st = new SMVWSceneInterface();
System.out.println("got args: " + args[0] + " " + args[1] + " " + args[2] + " " + args[3] + " " + args[4] + " " + args[5] + " " + args[6] + " " + args[7] + " " + args[8] + " " + args[9] + " " + args[10] + " " + args[11] + " " + "DONE");
st.start_up(args[0], args[1], args[2], args[3], args[4], args[5], args[6], args[7], args[8], args[9], args[10], args[11]);
}
private void start_up(String Avatar, String Username, String Filename, String CompContr, String ActionClass, String Chair, String Glove, String Joystick, String Briefcase, String Minimap, String Bubbles, String SNames) {
System.out.println("Got to start_up");
// Local host name
String hostname = "";
// the following are used for avatar networking purposes.
int port; // orta port number
int ttl; // orta ttl to sent with
String address; // orta address to send to
InetAddress mesh = null; // orta address to send to
// and, for audio networking purposes.
int auport; // orta port number
int auttl; // orta ttl to sent with
String auaddress; // orta address to send to
String[] avatarNames, avatarURLs; // Avatar names and URLs obtained from the VRML world file
// Toggle used to indicate whether a chair setup is being used
boolean vrchair;
// Toggle used to indicate whether a glove is being used
boolean cyberglove;
// Toggle used to indicate whether a joystick is being used
boolean joystick;
// Check if a chair set up is being used
if (Chair.equals("Yes")) {
vrchair = true;
} else {
vrchair = false;
}
if (Glove.equals("Yes")) {
cyberglove = true;
} else {
cyberglove = false;
}
if (Joystick.equals("Yes")) {
joystick = true;
} else {
joystick = false;
}
if (Minimap.equals("Yes")) {
MMap = true;
} else {
MMap = false;
}
if (Bubbles.equals("Yes")) {
bubbles = true;
} else {
bubbles = false;
}
if (SNames.equals("Yes")) {
snames = true;
} else {
snames = false;
}
// Get reference to VRML browser
//onStatus("locating VRML browser...");
while (true) {
System.out.println("try to get browser ");
try {
browser = Browser.getBrowser(this);
} catch (Exception ignored) {
}
if (browser != null)
break;
}
System.out.println("Got browser!\n");
onStatus("vnet v1.1b1 (c) 1998 stephen f. white, jeff sonstein");
// Get references to nodes and event ins/outs from VRML file
Node rootNode = browser.getNode("ROOTNODE");
addChildren = (EventInMFNode) rootNode.getEventIn("addChildren");
removeChildren = (EventInMFNode) rootNode.getEventIn("removeChildren");
children = (EventInMFNode) rootNode.getEventIn("children");
Node viewpoint = browser.getNode("VIEWPOINT");
viewpointPosition = (EventInSFVec3f) viewpoint.getEventIn("position");
viewpointOrientation = (EventInSFRotation) viewpoint.getEventIn("orientation");
viewpointBind = (EventInSFBool) viewpoint.getEventIn("set_bind");
Node box = browser.getNode("BIGBOX");
position = box.getEventOut("position_changed");
orientation = box.getEventOut("orientation_changed");
vNet = browser.getNode("VNET");
avatarNames = ((EventOutMFString) vNet.getEventOut("avatarNames")).getValue();
avatarURLs = ((EventOutMFString) vNet.getEventOut("avatarURLs")).getValue();
Node HUD = browser.getNode("HUDCHILDREN");
addHudChild = (EventInMFNode) HUD.getEventIn("addChildren");
removeHudChild = (EventInMFNode) HUD.getEventIn("removeChildren");
hudTranslation = (EventInSFVec3f) HUD.getEventIn("set_translation");
hudStandardTranslation = new VSFVec3f(((EventOutSFVec3f)HUD.getEventOut("translation")).getValue());
addNames = new EventInMFNode[MAXNAMES];
removeNames = new EventInMFNode[MAXNAMES];
for (int i = 0; i < MAXNAMES; i++) {
String node_name = new String("SHOWNAME" + i);
Node SNAMES = browser.getNode(node_name);
addNames[i] = (EventInMFNode) SNAMES.getEventIn("addChildren");
removeNames[i] = (EventInMFNode) SNAMES.getEventIn("removeChildren");
System.out.println("got node: " + SNAMES + " addnames " + addNames[i] + " removeNames " + removeNames[i]);
}
Node BC = browser.getNode("BRIEFCASE");
addBC = (EventInMFNode) BC.getEventIn("addChildren");
removeBC = (EventInMFNode) BC.getEventIn("removeChildren");
isConnected = ((EventInSFBool) vNet.getEventIn("isConnected"));
port = ((EventOutSFInt32) vNet.getEventOut("port")).getValue();
ttl = ((EventOutSFInt32) vNet.getEventOut("ttl")).getValue();
address = ((EventOutSFString) vNet.getEventOut("address")).getValue();
auport = ((EventOutSFInt32) vNet.getEventOut("auport")).getValue();
auttl = ((EventOutSFInt32) vNet.getEventOut("auttl")).getValue();
auaddress = ((EventOutSFString) vNet.getEventOut("auaddress")).getValue();
System.out.println ("Avatar orta address " + address + " port " + port + " ttl " + ttl);
System.out.println ("Audio orta address " + auaddress + " port " + auport + " ttl " + auttl);
// start up the rtpi layer to allow for sending/receiving
// avatar information to others.
// Convert address into internet address object. Check that it is a multicast address.
try {
mesh = InetAddress.getByName(address);
}
catch (Exception e) {
System.out.println("Invalid address: " + address);
System.exit(0);
}
// Get local internet address
try {
myAddress = InetAddress.getLocalHost();
}
catch (UnknownHostException e) {
System.out.println("Unable to access local address");
}
// Get hostname for world
try {
hostname = myAddress.getHostName();
System.out.println("got hostname: " + hostname);
} catch (Exception e) {
System.out.println(e + " Unable to get hostname");
}
// Cname is the username plus the local host name
String cname = Username + "@" + hostname;
// Using IP address for creating participant ID for now.
byte[] baseBytes = myAddress.getAddress();
subIDBase = (baseBytes[3] & BYTE_MASK) | ((baseBytes[2]&BYTE_MASK) << 8) | ((baseBytes[1]&BYTE_MASK) << 16) | ((baseBytes[0]&BYTE_MASK) << 24);
subIDBase = subIDBase & 0xFFFFFFFFl;
subIDBase = subIDBase - 1000000000;
//System.out.println("subIDBase is: " + subIDBase);
// Create local participant source information object
try {
localParticipant = new RtpiSourceInfo((int)subIDBase, cname);
}
catch (Exception e) {
System.out.println("Unable to create local participant");
System.exit(0);
}
// Set information in source information object
try {
localParticipant.setName(Username);
localParticipant.setLoc(hostname);
}
catch (Exception e) {
System.out.println("Invalid parameter for local participant info");
}
// Create transport and reliability services. Currently using unreliable multicast.
Transport rtcpTransport = null;
try {
reliabilityService = new ORTA(mesh, port, IPC_PORT, 500000, 10000);
}
catch (Exception e) {
System.out.println("Could not create Reliability service");
System.exit(0);
}
try {
rtcpTransport = new ORTATransport(mesh, port+5, IPC_PORT+5, 5000000);
}
catch (Exception e) {
System.out.println("Could not create Transport service");
System.exit(0);
}
// Create actual rtpi layer
rtpi = new Rtpi(reliabilityService, localParticipant, rtcpTransport, 2000, false);
// Join multicast group
rtpi.joinGroup();
// start up the dispatcher with the rtpi layer placed in;
// we just send the audio parameters along, just in case
// we actually do start up audio via the SMClient Thread!
// (SMclientThread started by SMDispatcher)
dispatcher = new SMDispatcher(this,rtpi,auaddress,auport,auttl,localParticipant.getParticipantID(),Avatar,Username, Filename, CompContr, ActionClass);
// Inform this object if the position or the orientation of the local avatar is changed
position.advise(this, position);
orientation.advise(this, orientation);
//System.out.println ("XOO Version 0.1 Running");
// attach to the node for connecting/disconnecting...
// WE CONNECT ALL THE TIME!!! If you want to be able
// to connect/disconnect, uncomment out the following, and
// check touchsensor in .wrl file.
// JAS on_line = false;
// JAS Node EntryCone = browser.getNode("TS");
// JAS on_off = EntryCone.getEventOut("touchTime");
// on_off.advise(this, on_off);
on_line = true; // see comments above...
dispatcher.onNetConnect();
if (vrchair || cyberglove || joystick) {
get_view = new GetView(browser, (vrchair && joystick));
}
if (cyberglove) {
get_glove = new GetGlove(browser);
gesture_thread = new vrhand(browser, this);
gesture_thread.start();
}
// Create briefcase object if specified
if (!Briefcase.equals("none")) {
briefcase = new BContents(browser, Briefcase, this, dispatcher, addBC, removeBC);
briefcase.createBriefcase();
briefcase.showBriefcase();
}
this.Briefcase = Briefcase;
try {
RAT_out_socket = new DatagramSocket();
RAT_in_socket = new DatagramSocket(RAT_port + 3);
} catch (Exception e) {
System.out.println("Failed openeing speaker socket");
}
// Create Minimap thread if required
if (MMap || bubbles || snames) {
mmapThread = new MMapThread(this, browser, dispatcher, RAT_in_socket, RAT_out_socket, (RAT_port+2), MMap, bubbles, snames);
mmapThread.init();
mmapThread.start();
}
}
// Function called when the position or orientation of the local avatar is changed
public void callback(EventOut value, double timeStamp, Object data) {
// If position or orientation of local avatar is changed send an update packet
if ((EventOut)data == position) {
float[] pos = ((EventOutSFVec3f) value).getValue();
VSFVec3f posn = new VSFVec3f(pos);
dispatcher.sendPosition(posn);
} else if ((EventOut)data == orientation) {
float[] rot = ((EventOutSFRotation) value).getValue();
VSFRotation rotn = new VSFRotation(rot);
dispatcher.sendOrientation(rotn);
} else if ((EventOut)data == on_off) {
if (on_line) {
dispatcher.onNetDisconnect();
on_line = false;
} else {
dispatcher.onNetConnect();
on_line = true;
}
} else {
dispatcher.log("unknown callback: " + value);
}
}
// Register an ViewpointObserver
public void RegisterViewpointObserver(EAIObject obj)
{
for (int i = 0; i < MAX_OBSERVERS; i++)
{
if (ViewpointObservers[i] == null )
ViewpointObservers[i] = obj;
}
}
// Print status message
public void onStatus(String str) {
status = str;
System.out.println(status);
}
// Print error message
public void onError(String str) {
onStatus(str);
}
// Add a VRML object to the scene
public void addObject(VRMLObject obj) {
System.out.println("in addObject vrml object: " + obj + " URL: " + obj.getURL());
addChildren.setValue(((EAIObject) obj).nodes);
obj.setVisible(true);
}
// Remove a VRML object from the scene
public void removeObject(VRMLObject obj) {
removeChildren.setValue(((EAIObject) obj).nodes);
obj.setVisible(false);
}
public void addHudObject(VRMLObject obj) {
System.out.println("setting value of addHudChild (" + addHudChild + ") to " + obj);
obj.setField(VIP.POSITION, new VSFVec3f((float)0.0, (float)0.0, (float)0.0));
addHudChild.setValue(((EAIObject) obj).nodes);
}
public void removeHudObject(VRMLObject obj) {
if (MMap) {
mmapThread.removeMMObject(obj.getID());
}
System.out.println("Reached remove HUD object");
removeHudChild.setValue(((EAIObject) obj).nodes);
}
// Remove all objects from the scene (set world to blank)
public void removeAllObjects() {
children.setValue(browser.createVrmlFromString("Group {}"));
}
// Create a new VRML object from the passed URL
public VRMLObject createObject(long parent, long vid, long pID, String url,
VRMLObjectObserver observer, boolean local) {
System.out.println("Calling create Object for pID " + pID + " url " + url);
return new EAIObject(parent, vid, pID, url, browser, observer, local);
}
// Set the position of the viewpoint node
public void setViewpointPosition(VSFVec3f position) {
viewpointBind.setValue(false);
viewpointPosition.setValue(position.getValue());
viewpointBind.setValue(true);
}
// Set the orientation of the viewpoint node
public void setViewpointOrientation(VSFRotation orientation) {
viewpointBind.setValue(false);
viewpointOrientation.setValue(orientation.getValue());
viewpointBind.setValue(true);
for (int i = 0; i < MAX_OBSERVERS; i++)
{
if (ViewpointObservers[i] == null)
break;
else
ViewpointObservers[i].viewChanged(orientation);
}
}
// Set the value of the connected flag
public void setConnect(boolean val) {
isConnected.setValue(val);
}
public VSFVec3f getGlovePosition() {
return get_glove.getPosition();
}
public void graspRequest() {
VRMLObject grasped_object;
// Check if an object is within range, and if so, which object is closest
// for now handle just like a glove pick up
if (!holding) {
System.out.println("Not holding");
// We are not holding something
grasped_object = dispatcher.gloveProximityDetect();
// No object within range... grasping air, so do nothing
if (grasped_object == null)
return;
((EAIObject) grasped_object).pickUp();
held_object = grasped_object;
} else {
System.out.println("Holding ... should drop");
// We are holding something
((EAIObject) held_object).drop();
}
}
public void setHolding(boolean hold) {
holding = hold;
}
public VRMLObject getCurrentBCObject() {
return briefcase.currentObject();
}
public void setCurrentBCObject(VRMLObject object) {
briefcase.setCurrentObject(object);
}
public String getBriefcasePath() {
return Briefcase;
}
}