javax.media.j3d.InputDeviceScheduler Maven / Gradle / Ivy
/*
* Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
*
* This code is free software; you can redistribute it and/or modify it
* under the terms of the GNU General Public License version 2 only, as
* published by the Free Software Foundation. Sun designates this
* particular file as subject to the "Classpath" exception as provided
* by Sun in the LICENSE file that accompanied this code.
*
* This code 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
* version 2 for more details (a copy is included in the LICENSE file that
* accompanied this code).
*
* You should have received a copy of the GNU General Public License version
* 2 along with this work; if not, write to the Free Software Foundation,
* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
*
* Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
* CA 95054 USA or visit www.sun.com if you need additional information or
* have any questions.
*
*/
package javax.media.j3d;
import java.util.ArrayList;
/**
* This thread manages all input device scheduling. It monitors and caches
* all device additions and removals. It spawns new threads for blocking
* devices, manages all non-blocking drivers itself, and tags the sensors
* of demand_driven devices. This implementation assume that
* processMode of InputDevice will not change after addInputDevice().
*
*/
class InputDeviceScheduler extends J3dThread {
// list of devices that have been added with the phys env interface
ArrayList nonBlockingDevices = new ArrayList(1);
// This condition holds blockingDevices.size() == threads.size()
ArrayList blockingDevices = new ArrayList(1);
ArrayList threads = new ArrayList(1);
// This is used by MasterControl to keep track activeViewRef
PhysicalEnvironment physicalEnv;
J3dThreadData threadData = new J3dThreadData();
boolean active = false;
// The time to sleep before next processAndProcess() is invoked
// for non-blocking input device
static int samplingTime = 5;
// Some variables used to name threads correctly
private static int numInstances = 0;
private int instanceNum = -1;
private synchronized int newInstanceNum() {
return (++numInstances);
}
@Override
int getInstanceNum() {
if (instanceNum == -1)
instanceNum = newInstanceNum();
return instanceNum;
}
InputDeviceScheduler(ThreadGroup threadGroup,
PhysicalEnvironment physicalEnv) {
super(threadGroup);
setName("J3D-InputDeviceScheduler-" + getInstanceNum());
threadData.threadType = J3dThread.INPUT_DEVICE_SCHEDULER;
threadData.thread = this;
this.physicalEnv = physicalEnv;
synchronized (physicalEnv.devices) {
for (InputDevice each : physicalEnv.devices) {
addInputDevice(each);
}
physicalEnv.inputsched = this;
}
}
void addInputDevice(InputDevice device) {
switch(device.getProcessingMode()) {
case InputDevice.BLOCKING:
InputDeviceBlockingThread thread =
VirtualUniverse.mc.getInputDeviceBlockingThread(device);
thread.start();
synchronized (blockingDevices) {
threads.add(thread);
blockingDevices.add(device);
}
break;
case InputDevice.NON_BLOCKING:
synchronized (nonBlockingDevices) {
nonBlockingDevices.add(device);
if (active && (nonBlockingDevices.size() == 1)) {
VirtualUniverse.mc.addInputDeviceScheduler(this);
}
}
break;
default: // InputDevice.DEMAND_DRIVEN:
// tag the sensors
for (int i=device.getSensorCount()-1; i>=0; i--) {
device.getSensor(i).demand_driven = true;
}
break;
}
}
void removeInputDevice(InputDevice device) {
switch(device.getProcessingMode()) {
case InputDevice.BLOCKING:
// tell the thread to clean up and permanently block
synchronized (blockingDevices) {
int idx = blockingDevices.indexOf(device);
InputDeviceBlockingThread thread =
(InputDeviceBlockingThread) threads.remove(idx);
thread.finish();
blockingDevices.remove(idx);
}
break;
case InputDevice.NON_BLOCKING:
// remove references that are in this thread
synchronized (nonBlockingDevices) {
nonBlockingDevices.remove(nonBlockingDevices.indexOf(device));
if (active && (nonBlockingDevices.size() == 0)) {
VirtualUniverse.mc.removeInputDeviceScheduler(this);
}
}
break;
default: // InputDevice.DEMAND_DRIVEN:
// untag the sensors
for (int i=device.getSensorCount()-1; i>=0; i--) {
device.getSensor(i).demand_driven = false;
}
}
}
// Add this thread to MC (Callback from MC thread)
void activate() {
if (!active) {
active = true;
synchronized (nonBlockingDevices) {
if (nonBlockingDevices.size() > 0) {
VirtualUniverse.mc.addInputDeviceScheduler(this);
}
}
// run all spawn threads
synchronized (blockingDevices) {
for (int i=threads.size()-1; i >=0; i--) {
((InputDeviceBlockingThread)threads.get(i)).restart();
}
}
}
}
// Remove this thread from MC (Callback from MC thread)
void deactivate() {
if (active) {
synchronized (nonBlockingDevices) {
if (nonBlockingDevices.size() > 0) {
VirtualUniverse.mc.removeInputDeviceScheduler(this);
}
}
// stop all spawn threads
synchronized (blockingDevices) {
for (int i=threads.size()-1; i >=0; i--) {
((InputDeviceBlockingThread)threads.get(i)).sleep();
}
}
active = false;
}
}
J3dThreadData getThreadData() {
return threadData;
}
@Override
void doWork(long referenceTime) {
synchronized (nonBlockingDevices) {
for (int i = nonBlockingDevices.size()-1; i >=0; i--) {
((InputDevice)nonBlockingDevices.get(i)).pollAndProcessInput();
}
}
}
@Override
void shutdown() {
// stop all spawn threads
for (int i=threads.size()-1; i >=0; i--) {
((InputDeviceBlockingThread)threads.get(i)).finish();
}
// for gc
threads.clear();
blockingDevices.clear();
nonBlockingDevices.clear();
}
}