/*
* Java classes for doing simulations of physical processes
* on the Java3D scene graph.
*
* (C) 2000, 2001 Fred Klingener
* klingener@BrockEng.com
* www.VMech.com
*
* 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
* 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 General Public License for more details.
*
* You should have received a copy of the GNU 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,
* or you may read or obtain a copy at http://www.gnu.org/copyleft/gpl.html
*/
/* PlanF.java 0.0 09/15/01
* This is a program that will be used to illustrate opportunities and
* problems doing physics with the Java 3D API.
*
* Same as Paln E but with new thread, intended to equalize Frame delay
*
It is built using Sun Microsystem's tutorial example
* HelloJava3Dc.java, the Copyright notice of which is
* reproduced below.
*
*
*/
/*
* @(#)HelloJava3Dc.java 1.1 00/09/22 13:55
*
* Copyright (c) 1996-2000 Sun Microsystems, Inc. All Rights Reserved.
*
* Sun grants you ("Licensee") a non-exclusive, royalty free, license to use,
* modify and redistribute this software in source and binary code form,
* provided that i) this copyright notice and license appear on all copies of
* the software; and ii) Licensee does not utilize the software in a manner
* which is disparaging to Sun.
*
* This software is provided "AS IS," without a warranty of any kind. ALL
* EXPRESS OR IMPLIED CONDITIONS, REPRESENTATIONS AND WARRANTIES, INCLUDING ANY
* IMPLIED WARRANTY OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR
* NON-INFRINGEMENT, ARE HEREBY EXCLUDED. SUN AND ITS LICENSORS SHALL NOT BE
* LIABLE FOR ANY DAMAGES SUFFERED BY LICENSEE AS A RESULT OF USING, MODIFYING
* OR DISTRIBUTING THE SOFTWARE OR ITS DERIVATIVES. IN NO EVENT WILL SUN OR ITS
* LICENSORS BE LIABLE FOR ANY LOST REVENUE, PROFIT OR DATA, OR FOR DIRECT,
* INDIRECT, SPECIAL, CONSEQUENTIAL, INCIDENTAL OR PUNITIVE DAMAGES, HOWEVER
* CAUSED AND REGARDLESS OF THE THEORY OF LIABILITY, ARISING OUT OF THE USE OF
* OR INABILITY TO USE SOFTWARE, EVEN IF SUN HAS BEEN ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGES.
*
* This software is not designed or intended for use in on-line control of
* aircraft, air traffic, aircraft navigation or aircraft communications; or in
* the design, construction, operation or maintenance of any nuclear
* facility. Licensee represents and warrants that it will not use or
* redistribute the Software for such purposes.
*/
import java.applet.Applet;
import java.awt.BorderLayout;
import java.awt.Frame;
import java.awt.event.*;
import java.awt.GraphicsConfiguration;
import com.sun.j3d.utils.applet.MainFrame;
import com.sun.j3d.utils.geometry.ColorCube;
import com.sun.j3d.utils.universe.*;
import java.text.*; // 09-24-01 for diagnostics
import java.util.*; // 09-24-01 for Behavior, diagnostics
import javax.media.j3d.*;
import javax.vecmath.*;
/* Basic approach:
* O build a scene-graph-based simulation model for
* run/render in retained or retained/compiled mode.
* O model Behaviors are scheduled to wakeupOnElapsedFrame(0)
* O run the simulation clock in immediate mode. This
* means extending Canvas3D and putting the clock maintenance
* methods in the preRender() method, say.
* o clock members are clock time and time step size
* o at each step,
* - increment clock by time step size
* - Thread.sleep(time step size)
* o public sets and gets
* O build Interpolators that read the simulation clock time, get output from an Alpha
*
*
*
*/
public class PlanF extends Applet
{ String ProgramName = "PlanF.java 10-02-2001";
/*
* simpleU (Simple Universe)
* |
* objRoot (BG)
* |
* objSpin (TG)
* rotator (RotationInterpolator)
* |
* ColorCube
*/
Dali3D canvas3D;
public BranchGroup createScene() // same as HelloJava3D except for Interpolator
{// Create the root of the branch graph
BranchGroup objRoot = new BranchGroup();
// Create the transform group node and initialize it to the
// identity. Add it to the root of the subgraph.
TransformGroup objSpin = new TransformGroup();
objSpin.setCapability(TransformGroup.ALLOW_TRANSFORM_WRITE);
objRoot.addChild(objSpin);
DaliInterpolator rotator =
new DaliRotationInterpolator(canvas3D, new Alpha(-1, 4003), objSpin);
BoundingSphere RotBounds = new BoundingSphere();
rotator.setSchedulingBounds(RotBounds);
objRoot.addChild(rotator);
// Create a simple shape leaf node, add it to the scene graph.
// ColorCube is a Convenience Utility class
objSpin.addChild(new ColorCube(0.4));
return objRoot;
}
// Constructor
public PlanF() // same as HelloJava3D except for extended Canvas
{ setLayout(new BorderLayout());
GraphicsConfiguration config =
SimpleUniverse.getPreferredConfiguration();
canvas3D = new Dali3D(config);
canvas3D.setSize(256, 256);
add("Center", canvas3D);
// SimpleUniverse is a Convenience Utility class
SimpleUniverse simpleU = new SimpleUniverse(canvas3D);
// This will move the ViewPlatform back a bit so the
// objects in the scene can be viewed.
simpleU.getViewingPlatform().setNominalViewingTransform();
BranchGroup scene = createScene();
simpleU.addBranchGraph(scene);
}
// The following allows this to be run as an application
// as well as an applet
public static void main(String[] args)
{ Frame frame = new MainFrame(new PlanF(), 256, 256);
} // end of main
/**<PRE>
* Dali3D. Getit? Clock on a Canvas3D.
* Purpose is to offer a more controllable
* time base for doing simulations.
*
* Overrides preRender()withSimClock+=DeltaT
* and sleep(DeltaT)
*
*
*
* </PRE>
*
* @author klingener@BrockEng.com
*/
public class Dali3D extends Canvas3D implements Runnable
{// Clock
long SimClock;
int DeltaT;
boolean isRunning;
Thread runner;
// Frame counter
private static final boolean debug = true;
private static final boolean html = false;
long FrameCount;
int FrameBlock;
long Then;
private NumberFormat Double1;
// Constructor
public Dali3D(GraphicsConfiguration gc)
{ super(gc);
SimClock = 0;
DeltaT = 10;
runner = new Thread(this);
isRunning = false;
if (debug)
{ Double1 = NumberFormat.getInstance();
Double1.setMaximumFractionDigits(1);
Double1.setMinimumFractionDigits(1);
Then = System.currentTimeMillis();
FrameCount = 0;
FrameBlock = 250;
}
}
public void run()
{ try
{ Thread.sleep(DeltaT);
}
catch(InterruptedException e) {}
}
public void preRender()
{ if (isRunning)
{// first wait for runner to time out
try
{ runner.join();
}
catch(InterruptedException e) {}
// then, restart it again
runner = new Thread(this);
runner.start();
// increment the clock
SimClock += DeltaT;
// diagnostics
if (debug)
{ if (FrameCount++ >= FrameBlock)
{ long Now = System.currentTimeMillis();
double AvgDelay = (double)(Now - Then)/(double)FrameBlock;
if (html)
{ System.out.print("<TR><TD><CODE>"+DeltaT+
"</CODE></TD>\n<TD><CODE>"+AvgDelay+"</CODE></TD>\n");
String s = "";
for (int i=0; i<(int)AvgDelay-DeltaT; i++)
{ s += "*";
}
System.out.print("<TD><CODE>"+s+"</CODE></TD></TR>\n");
}
else // (!html)
{ System.out.print(" "+DeltaT+" "+
Double1.format(AvgDelay)+" ");
String s = "";
for (int i=0; i<(int)AvgDelay-DeltaT; i++)
{ s += "*";
}
System.out.print(s+"\n");
}
// reset counter
Then = Now;
FrameCount = 0;
// increment DeltaT
DeltaT++;
}
}
}
}
public long getSimClock()
{ return SimClock;
}
public void setDeltaT(int dt)
{ DeltaT = dt;
}
public void setSimClock(long p)
{ SimClock = p;
if (debug)
{ Then = System.currentTimeMillis();
FrameCount = 0;
}
}
public void setSimClock(long p, int dt)
{ setDeltaT(dt);
setSimClock(p);
}
/**
* - starts simulation clock
* - resets diagnostics
* - prints diagnostic header on console
*/
public void startSimClock()
{ isRunning = true;
if (debug)
{ Then = System.currentTimeMillis();
FrameCount = 0;
DateFormat DayTime;
DayTime = DateFormat.getDateTimeInstance(DateFormat.SHORT, DateFormat.SHORT);
if (html)
{ System.out.println("<P><CODE>Program: "+ProgramName+"<BR>");
System.out.println("Run "+DayTime.format(new Date())+"<BR>");
System.out.println("OS Arch.: "+System.getProperty("os.arch")+"<BR>");
System.out.println("OS: "+System.getProperty("os.name")+
" Version: "+System.getProperty("os.version")+"<BR></CODE><HR>");
System.out.println("<TR><TH><CODE>DeltaT</CODE></TH>\n"+
"<TH><CODE>Frame<BR>Delay</CODE></TH>"+
"<TH><CODE>Lag</CODE></TH></TR>");
System.out.println("<TR><TH><CODE>(ms)</CODE></TH>\n"+
"<TH><CODE>(ms)</CODE></TH>"+
"<TH><CODE>(ms)</CODE></TH><TR>");
}
else // (!html)
{ System.out.println("");
System.out.print("Program: "+ProgramName+"\n");
System.out.print("Run "+DayTime.format(new Date())+"\n");
System.out.print("OS Arch.: "+System.getProperty("os.arch")+"\n");
System.out.print("OS: "+System.getProperty("os.name")+
" Version: "+System.getProperty("os.version")+"\n");
System.out.print("Averaging block = "+FrameBlock+" Frames\n");
System.out.print("---------------------------------\n");
System.out.print(" Frame\n");
System.out.print("DeltaT Delay Lag\n");
System.out.print("(ms) (ms) (ms)\n");
System.out.print("------ --------- -----------\n");
}
}
}
public void stopSimClock()
{ isRunning = false;
}
}
/**
*
*
*/
public class DaliInterpolator extends Behavior
{// 1. alarm
WakeupCriterion yawn;
// 2. communicate with simulation clock in extended Canvas3D
Dali3D c3d;
// 3. set model
Alpha SimAlpha;
public DaliInterpolator(Dali3D dp, Alpha ap)
{ c3d = dp;
SimAlpha = ap;
yawn = new WakeupOnElapsedFrames(0);
}
public void initialize()
{// 1. alarm
wakeupOn(yawn);
// 2. set sim clock
c3d.setSimClock(0);
c3d.startSimClock();
// 3. set model
SimAlpha.setStartTime(0);
}
public void processStimulus(Enumeration e)
{// 1. alarm
wakeupOn(yawn);
// 2. clock
// nothing here. It's all done in the Canvas3D
// 3. set model
// do everything in the extensions
}
}
public class DaliRotationInterpolator extends DaliInterpolator
{ TransformGroup targetTG;
private Transform3D t3d;
public DaliRotationInterpolator(Dali3D dp, Alpha ap, TransformGroup tg )
{ super(dp, ap);
targetTG = tg;
t3d = new Transform3D();
}
public void initialize()
{ super.initialize();
targetTG.setTransform(t3d);
}
public void processStimulus(Enumeration e)
{ super.processStimulus(e);
t3d.rotY(Math.PI*2.0*SimAlpha.value(c3d.getSimClock()));
targetTG.setTransform(t3d);
} // end method
}
}