/*
* To change this template, choose Tools | Templates
* and open the template in the editor.
*/
package automenta.spacenet.run;
import automenta.spacenet.space.Space;
import automenta.spacenet.space.Spacetime;
import automenta.spacenet.space.control.camera.ArdorCamera;
import automenta.spacenet.space.control.pointer.DefaultKeyboard;
import automenta.spacenet.space.control.pointer.DefaultPointer;
import automenta.spacenet.space.video.PropertiesDialog;
import automenta.spacenet.space.video.PropertiesGameSettings;
import automenta.spacenet.var.physical.Color;
import automenta.spacenet.var.vector.V3;
import com.ardor3d.annotation.MainThread;
import com.ardor3d.example.ExampleBase;
import com.ardor3d.framework.Canvas;
import com.ardor3d.framework.DisplaySettings;
import com.ardor3d.framework.FrameHandler;
import com.ardor3d.framework.NativeCanvas;
import com.ardor3d.framework.Scene;
import com.ardor3d.framework.Updater;
import com.ardor3d.framework.jogl.JoglCanvas;
import com.ardor3d.framework.jogl.JoglCanvasRenderer;
import com.ardor3d.image.TextureStoreFormat;
import com.ardor3d.image.util.AWTImageLoader;
import com.ardor3d.image.util.ScreenShotImageExporter;
import com.ardor3d.input.GrabbedState;
import com.ardor3d.input.Key;
import com.ardor3d.input.MouseButton;
import com.ardor3d.input.MouseManager;
import com.ardor3d.input.PhysicalLayer;
import com.ardor3d.input.awt.AwtFocusWrapper;
import com.ardor3d.input.awt.AwtKeyboardWrapper;
import com.ardor3d.input.awt.AwtMouseManager;
import com.ardor3d.input.awt.AwtMouseWrapper;
import com.ardor3d.input.control.FirstPersonControl;
import com.ardor3d.input.logical.AnyKeyCondition;
import com.ardor3d.input.logical.DummyControllerWrapper;
import com.ardor3d.input.logical.InputTrigger;
import com.ardor3d.input.logical.KeyPressedCondition;
import com.ardor3d.input.logical.LogicalLayer;
import com.ardor3d.input.logical.MouseButtonClickedCondition;
import com.ardor3d.input.logical.MouseButtonPressedCondition;
import com.ardor3d.input.logical.MouseButtonReleasedCondition;
import com.ardor3d.input.logical.TriggerAction;
import com.ardor3d.input.logical.TwoInputStates;
import com.ardor3d.intersection.PickData;
import com.ardor3d.intersection.PickResults;
import com.ardor3d.intersection.PickingUtil;
import com.ardor3d.intersection.PrimitivePickResults;
import com.ardor3d.light.PointLight;
import com.ardor3d.math.ColorRGBA;
import com.ardor3d.math.Ray3;
import com.ardor3d.math.Vector2;
import com.ardor3d.math.Vector3;
import com.ardor3d.renderer.Renderer;
import com.ardor3d.renderer.TextureRendererFactory;
import com.ardor3d.renderer.jogl.JoglTextureRendererProvider;
import com.ardor3d.renderer.queue.RenderBucketType;
import com.ardor3d.renderer.state.LightState;
import com.ardor3d.renderer.state.ShadingState;
import com.ardor3d.renderer.state.ShadingState.ShadingMode;
import com.ardor3d.renderer.state.WireframeState;
import com.ardor3d.renderer.state.ZBufferState;
import com.ardor3d.scenegraph.Spatial;
import com.ardor3d.scenegraph.event.DirtyType;
import com.ardor3d.util.Constants;
import com.ardor3d.util.ContextGarbageCollector;
import com.ardor3d.util.GameTaskQueue;
import com.ardor3d.util.GameTaskQueueManager;
import com.ardor3d.util.ReadOnlyTimer;
import com.ardor3d.util.Timer;
import com.ardor3d.util.geom.Debugger;
import com.ardor3d.util.screen.ScreenExporter;
import com.ardor3d.util.stat.StatCollector;
import com.google.common.base.Predicate;
import com.google.common.base.Predicates;
import java.awt.EventQueue;
import java.awt.event.ComponentAdapter;
import java.awt.event.ComponentEvent;
import java.net.URL;
import java.util.Stack;
import java.util.concurrent.atomic.AtomicReference;
import java.util.logging.Level;
import java.util.logging.Logger;
import javolution.context.ConcurrentContext;
/**
* Adapted from ExampleBase
* @author seh
*/
public class ArdorWindow implements Runnable, Updater, Scene, Spacetime {
private static final Logger logger = Logger.getLogger(ArdorWindow.class.getName());
protected final LogicalLayer inputLogic = new LogicalLayer();
protected PhysicalLayer inputPhy;
protected final Timer timer = new Timer();
protected final FrameHandler frameHandler = new FrameHandler(timer);
protected DisplaySettings videoSettings;
protected LightState lightState;
protected WireframeState wireframeState;
protected volatile boolean _exit = false;
protected static boolean _stereo = false;
protected boolean _showBounds = false;
protected boolean _showNormals = false;
protected boolean _showDepth = false;
protected boolean _doShot = false;
protected NativeCanvas canvas;
protected ScreenShotImageExporter _screenShotExp = new ScreenShotImageExporter();
protected MouseManager mouseManager;
protected FirstPersonControl firstPersonControl;
protected Vector3 worldUp = new Vector3(0, 1, 0);
protected static int _minDepthBits = -1;
protected static int _minAlphaBits = -1;
protected static int _minStencilBits = -1;
protected Color backgroundColor = new Color(Color.GRAY);
private ArdorCamera camera;
private DefaultPointer pointer;
protected final Space root = new Space();
private Space face = new Space();
private Space sky = new Space();
private Space volume = new Space();
public ArdorWindow() {
// Ask for properties
final PropertiesGameSettings prefs = getAttributes(new PropertiesGameSettings("ardorSettings.properties", null));
// Convert to DisplayProperties (XXX: maybe merge these classes?)
final DisplaySettings settings = new DisplaySettings(prefs.getWidth(), prefs.getHeight(), prefs.getDepth(),
prefs.getFrequency(),
// alpha
_minAlphaBits != -1 ? _minAlphaBits : prefs.getAlphaBits(),
// depth
_minDepthBits != -1 ? _minDepthBits : prefs.getDepthBits(),
// stencil
_minStencilBits != -1 ? _minStencilBits : prefs.getStencilBits(),
// samples
prefs.getSamples(),
// other
prefs.isFullscreen(), _stereo);
// get our framework
if ("LWJGL".equalsIgnoreCase(prefs.getRenderer())) {
logger.severe("LWJGL not supported. Use JOGL");
return;
// final LwjglCanvasRenderer canvasRenderer = new LwjglCanvasRenderer(this);
// canvas = new LwjglCanvas(canvasRenderer, settings);
// physical = new PhysicalLayer(new LwjglKeyboardWrapper(), new LwjglMouseWrapper(),
// new LwjglControllerWrapper(), (LwjglCanvas)canvas);
// mouseManager = new LwjglMouseManager();
// TextureRendererFactory.INSTANCE.setProvider(new LwjglTextureRendererProvider());
} else if ("JOGL".equalsIgnoreCase(prefs.getRenderer())) {
final JoglCanvasRenderer canvasRenderer = new JoglCanvasRenderer(this);
canvas = new JoglCanvas(canvasRenderer, settings);
final JoglCanvas jcanvas = (JoglCanvas) this.canvas;
mouseManager = new AwtMouseManager(jcanvas);
inputPhy = new PhysicalLayer(
new AwtKeyboardWrapper(jcanvas),
new AwtMouseWrapper(jcanvas, mouseManager),
DummyControllerWrapper.INSTANCE,
new AwtFocusWrapper(jcanvas));
TextureRendererFactory.INSTANCE.setProvider(new JoglTextureRendererProvider());
}
inputLogic.registerInput(canvas, inputPhy);
// Register our example as an updater.
frameHandler.addUpdater(this);
// register our native canvas
frameHandler.addCanvas(canvas);
new Thread(this).start();
}
public void run() {
try {
frameHandler.init();
while (!_exit) {
frameHandler.updateFrame();
Thread.yield();
}
// grab the graphics context so cleanup will work out.
canvas.getCanvasRenderer().setCurrentContext();
quit(canvas.getCanvasRenderer().getRenderer());
} catch (final Throwable t) {
System.err.println("Throwable caught in MainThread - exiting");
t.printStackTrace(System.err);
}
}
public void stop() {
_exit = true;
}
public MouseManager getMouseManager() {
return mouseManager;
}
@MainThread
public void init() {
int numProcs = Runtime.getRuntime().availableProcessors();
logger.info("Processor Cores: " + numProcs);
ConcurrentContext.setConcurrency(numProcs);
registerInputTriggers();
AWTImageLoader.registerLoader();
// try {
// SimpleResourceLocator srl = new SimpleResourceLocator(ExampleBase.class.getClassLoader().getResource(
// "com/ardor3d/example/media/"));
// ResourceLocatorTool.addResourceLocator(ResourceLocatorTool.TYPE_TEXTURE, srl);
// srl = new SimpleResourceLocator(ExampleBase.class.getClassLoader().getResource(
// "com/ardor3d/example/media/models/"));
// ResourceLocatorTool.addResourceLocator(ResourceLocatorTool.TYPE_MODEL, srl);
// } catch (final URISyntaxException ex) {
// ex.printStackTrace();
// }
root.add(sky);
root.add(volume);
root.add(face);
/**
* Create a ZBuffer to display pixels closest to the camera above farther ones.
*/
final ZBufferState buf = new ZBufferState();
buf.setEnabled(true);
buf.setFunction(ZBufferState.TestFunction.LessThanOrEqualTo);
volume.setRenderState(buf);
final ShadingState shadeState = new ShadingState();
shadeState.setShadingMode(ShadingMode.Smooth);
volume.setRenderState(shadeState);
// ---- LIGHTS
/** Set up a basic, default light. */
final PointLight light = new PointLight();
{
light.setDiffuse(new ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f));
//light.setSpecular(new ColorRGBA(1.0f, 1.0f, 1.0f, 1.0f));
//light.setAmbient(new ColorRGBA(0.5f, 0.5f, 0.5f, 0.5f));
light.setLocation(new Vector3(0, 0, 100));
light.setEnabled(true);
}
{
// light.setDiffuse(new ColorRGBA(0.75f, 0.75f, 0.75f, 0.75f));
// light.setAmbient(new ColorRGBA(0.7f, 0.7f, 0.7f, 0.75f));
// light.setLocation(new Vector3(0, 0, 50));
// light.setAttenuate(true);
// light.setLinear(0.003f);
// light.setQuadratic(0.001f);
}
/** Attach the light to a lightState and the lightState to rootNode. */
lightState = new LightState();
lightState.setEnabled(true);
lightState.attach(light);
volume.setRenderState(lightState);
wireframeState = new WireframeState();
wireframeState.setEnabled(false);
volume.setRenderState(wireframeState);
volume.getSceneHints().setRenderBucketType(RenderBucketType.Opaque);
canvas.setTitle("");
if (canvas instanceof JoglCanvas) {
((JoglCanvas) canvas).addComponentListener(new ComponentAdapter() {
@Override public void componentResized(ComponentEvent e) {
java.awt.Dimension s = e.getComponent().getSize();
canvas.getCanvasRenderer().getCamera().resize(s.width, s.height);
}
});
((JoglCanvas) canvas).setResizable(true);
}
this.camera = new ArdorCamera(this, new V3(0, 0, 4), new V3(0, 0, 0), new V3(0, 1, 0));
root.add(camera);
this.pointer = new DefaultPointer(this);
root.add(pointer); //must be added w/ add(Repeat r)
root.add(new DefaultKeyboard(this, pointer));
afterInit();
}
protected void afterInit() {
}
@MainThread
public void update(final ReadOnlyTimer timer) {
if (canvas.isClosing()) {
stop();
}
/** update stats, if enabled. */
if (Constants.stats) {
StatCollector.update();
}
updateLogicalLayer(timer);
// Execute updateQueue item
GameTaskQueueManager.getManager(canvas.getCanvasRenderer().getRenderContext()).getQueue(GameTaskQueue.UPDATE).execute();
/** Call simpleUpdate in any derived classes of ExampleBase. */
updateFrame(timer);
/** Update controllers/render states/transforms/bounds for rootNode. */
root.updateGeometricState(timer.getTimePerFrame(), true);
}
protected void updateLogicalLayer(final ReadOnlyTimer timer) {
// check and execute any input triggers, if we are concerned with input
if (inputLogic != null) {
inputLogic.checkTriggers(timer.getTimePerFrame());
}
}
protected void updateFrame(final ReadOnlyTimer timer) {
}
@MainThread
public boolean renderUnto(final Renderer renderer) {
// Execute renderQueue item
GameTaskQueueManager.getManager(canvas.getCanvasRenderer().getRenderContext()).getQueue(GameTaskQueue.RENDER).execute(renderer);
// Clean up card garbage such as textures, vbos, etc.
ContextGarbageCollector.doRuntimeCleanup(renderer);
/** Draw the rootNode and all its children. */
if (!canvas.isClosing()) {
/** Call renderExample in any derived classes. */
render(renderer);
renderDebug(renderer);
if (_doShot) {
// force any waiting scene elements to be renderer.
renderer.renderBuckets();
ScreenExporter.exportCurrentScreen(canvas.getCanvasRenderer().getRenderer(), _screenShotExp);
_doShot = false;
}
return true;
} else {
return false;
}
}
protected void render(final Renderer renderer) {
renderer.draw(root);
}
protected void renderDebug(final Renderer renderer) {
if (_showBounds) {
Debugger.drawBounds(volume, renderer, true);
}
if (_showNormals) {
Debugger.drawNormals(volume, renderer);
Debugger.drawTangents(volume, renderer);
}
if (_showDepth) {
renderer.renderBuckets();
Debugger.drawBuffer(TextureStoreFormat.Depth16, Debugger.NORTHEAST, renderer);
}
}
public PickResults doPick(final Ray3 pickRay) {
final PrimitivePickResults pickResults = new PrimitivePickResults();
pickResults.setCheckDistance(true);
PickingUtil.findPick(volume, pickRay, pickResults);
processPicks(pickResults);
return pickResults;
}
protected void processPicks(final PrimitivePickResults pickResults) {
int i = 0;
while (pickResults.getNumber() > 0
&& pickResults.getPickData(i).getIntersectionRecord().getNumberOfIntersections() == 0
&& ++i < pickResults.getNumber()) {
}
if (pickResults.getNumber() > i) {
final PickData pick = pickResults.getPickData(i);
System.err.println("picked: " + pick.getTargetMesh() + " at: "
+ pick.getIntersectionRecord().getIntersectionPoint(0));
} else {
System.err.println("picked: nothing");
}
}
protected void quit(final Renderer renderer) {
ContextGarbageCollector.doFinalCleanup(renderer);
canvas.close();
}
protected static PropertiesGameSettings getAttributes(final PropertiesGameSettings settings) {
// Always show the dialog in these examples.
URL dialogImage = null;
final String dflt = settings.getDefaultSettingsWidgetImage();
if (dflt != null) {
try {
dialogImage = ExampleBase.class.getResource(dflt);
} catch (final Exception e) {
logger.log(Level.SEVERE, "Resource lookup of '" + dflt + "' failed. Proceeding.");
}
}
if (dialogImage == null) {
logger.fine("No dialog image loaded");
} else {
logger.fine("Using dialog image '" + dialogImage + "'");
}
final URL dialogImageRef = dialogImage;
final AtomicReference<PropertiesDialog> dialogRef = new AtomicReference<PropertiesDialog>();
final Stack<Runnable> mainThreadTasks = new Stack<Runnable>();
try {
if (EventQueue.isDispatchThread()) {
dialogRef.set(new PropertiesDialog(settings, dialogImageRef, mainThreadTasks));
} else {
EventQueue.invokeLater(new Runnable() {
public void run() {
dialogRef.set(new PropertiesDialog(settings, dialogImageRef, mainThreadTasks));
}
});
}
} catch (final Exception e) {
logger.logp(Level.SEVERE, ExampleBase.class.getClass().toString(), "ExampleBase.getAttributes(settings)",
"Exception", e);
return null;
}
PropertiesDialog dialogCheck = dialogRef.get();
while (dialogCheck == null || dialogCheck.isVisible()) {
try {
// check worker queue for work
while (!mainThreadTasks.isEmpty()) {
mainThreadTasks.pop().run();
}
// go back to sleep for a while
Thread.sleep(50);
} catch (final InterruptedException e) {
logger.warning("Error waiting for dialog system, using defaults.");
}
dialogCheck = dialogRef.get();
}
if (dialogCheck.isCancelled()) {
System.exit(0);
}
return settings;
}
protected void registerInputTriggers() {
// check if this example worries about input at all
if (inputLogic == null) {
return;
}
firstPersonControl = FirstPersonControl.setupTriggers(inputLogic, worldUp, true);
inputLogic.registerTrigger(new InputTrigger(new MouseButtonClickedCondition(MouseButton.RIGHT),
new TriggerAction() {
public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) {
final Vector2 pos = Vector2.fetchTempInstance().set(
inputStates.getCurrent().getMouseState().getX(),
inputStates.getCurrent().getMouseState().getY());
final Ray3 pickRay = new Ray3();
canvas.getCanvasRenderer().getCamera().getPickRay(pos, false, pickRay);
Vector2.releaseTempInstance(pos);
doPick(pickRay);
}
}));
inputLogic.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.ESCAPE), new TriggerAction() {
public void perform(final Canvas source, final TwoInputStates inputState, final double tpf) {
stop();
}
}));
inputLogic.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.L), new TriggerAction() {
public void perform(final Canvas source, final TwoInputStates inputState, final double tpf) {
lightState.setEnabled(!lightState.isEnabled());
// Either an update or a markDirty is needed here since we did not touch the affected spatial directly.
root.markDirty(DirtyType.RenderState);
}
}));
inputLogic.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.F4), new TriggerAction() {
public void perform(final Canvas source, final TwoInputStates inputState, final double tpf) {
_showDepth = !_showDepth;
}
}));
inputLogic.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.T), new TriggerAction() {
public void perform(final Canvas source, final TwoInputStates inputState, final double tpf) {
wireframeState.setEnabled(!wireframeState.isEnabled());
// Either an update or a markDirty is needed here since we did not touch the affected spatial directly.
root.markDirty(DirtyType.RenderState);
}
}));
inputLogic.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.B), new TriggerAction() {
public void perform(final Canvas source, final TwoInputStates inputState, final double tpf) {
_showBounds = !_showBounds;
}
}));
inputLogic.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.N), new TriggerAction() {
public void perform(final Canvas source, final TwoInputStates inputState, final double tpf) {
_showNormals = !_showNormals;
}
}));
inputLogic.registerTrigger(new InputTrigger(new KeyPressedCondition(Key.F1), new TriggerAction() {
public void perform(final Canvas source, final TwoInputStates inputState, final double tpf) {
_doShot = true;
}
}));
final Predicate<TwoInputStates> clickLeftOrRight = Predicates.or(new MouseButtonClickedCondition(
MouseButton.LEFT), new MouseButtonClickedCondition(MouseButton.RIGHT));
inputLogic.registerTrigger(new InputTrigger(clickLeftOrRight, new TriggerAction() {
public void perform(final Canvas source, final TwoInputStates inputStates, final double tpf) {
System.err.println("clicked: " + inputStates.getCurrent().getMouseState().getClickCounts());
}
}));
inputLogic.registerTrigger(new InputTrigger(new MouseButtonPressedCondition(MouseButton.LEFT),
new TriggerAction() {
public void perform(final Canvas source, final TwoInputStates inputState, final double tpf) {
if (mouseManager.isSetGrabbedSupported()) {
mouseManager.setGrabbed(GrabbedState.GRABBED);
}
}
}));
inputLogic.registerTrigger(new InputTrigger(new MouseButtonReleasedCondition(MouseButton.LEFT),
new TriggerAction() {
public void perform(final Canvas source, final TwoInputStates inputState, final double tpf) {
if (mouseManager.isSetGrabbedSupported()) {
mouseManager.setGrabbed(GrabbedState.NOT_GRABBED);
}
}
}));
inputLogic.registerTrigger(new InputTrigger(new AnyKeyCondition(), new TriggerAction() {
public void perform(final Canvas source, final TwoInputStates inputState, final double tpf) {
System.out.println("Key character pressed: "
+ inputState.getCurrent().getKeyboardState().getKeyEvent().getKeyChar());
}
}));
}
public LogicalLayer getInputLogic() {
return inputLogic;
}
public PhysicalLayer getInputPhy() {
return inputPhy;
}
public ArdorCamera getCamera() {
return camera;
}
public DefaultPointer getPointer() {
return pointer;
}
public Color getBackgroundColor() {
return backgroundColor;
}
public NativeCanvas getVideo() {
return canvas;
}
public Space getFace() {
return face;
}
public Space getSky() {
return sky;
}
public Space getVolume() {
return volume;
}
public Space getRoot() {
return root;
}
public void addCondition(InputTrigger t) {
getInputLogic().registerTrigger(t);
}
public void removeCondition(InputTrigger t) {
getInputLogic().deregisterTrigger(t);
}
public static synchronized void delay(double s) {
try {
Thread.sleep((long) (s * 1000.0));
} catch (InterruptedException ex) {
}
}
public ArdorWindow withVolume(Spatial... addToVolume) {
for (Spatial s : addToVolume) {
getVolume().add(s);
}
return this;
}
}