001: /*
002: * $RCSfile: InputDeviceScheduler.java,v $
003: *
004: * Copyright 1997-2008 Sun Microsystems, Inc. All Rights Reserved.
005: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
006: *
007: * This code is free software; you can redistribute it and/or modify it
008: * under the terms of the GNU General Public License version 2 only, as
009: * published by the Free Software Foundation. Sun designates this
010: * particular file as subject to the "Classpath" exception as provided
011: * by Sun in the LICENSE file that accompanied this code.
012: *
013: * This code is distributed in the hope that it will be useful, but WITHOUT
014: * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
015: * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
016: * version 2 for more details (a copy is included in the LICENSE file that
017: * accompanied this code).
018: *
019: * You should have received a copy of the GNU General Public License version
020: * 2 along with this work; if not, write to the Free Software Foundation,
021: * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
022: *
023: * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa Clara,
024: * CA 95054 USA or visit www.sun.com if you need additional information or
025: * have any questions.
026: *
027: * $Revision: 1.5 $
028: * $Date: 2008/02/28 20:17:25 $
029: * $State: Exp $
030: */
031:
032: package javax.media.j3d;
033:
034: import java.util.*;
035:
036: /**
037: * This thread manages all input device scheduling. It monitors and caches
038: * all device additions and removals. It spawns new threads for blocking
039: * devices, manages all non-blocking drivers itself, and tags the sensors
040: * of demand_driven devices. This implementation assume that
041: * processMode of InputDevice will not change after addInputDevice().
042: *
043: */
044:
045: class InputDeviceScheduler extends J3dThread {
046:
047: // list of devices that have been added with the phys env interface
048: ArrayList nonBlockingDevices = new ArrayList(1);
049:
050: // This condition holds blockingDevices.size() == threads.size()
051: ArrayList blockingDevices = new ArrayList(1);
052: ArrayList threads = new ArrayList(1);
053:
054: // This is used by MasterControl to keep track activeViewRef
055: PhysicalEnvironment physicalEnv;
056:
057: // store all inputDevices
058: Vector devices = new Vector(1);
059:
060: J3dThreadData threadData = new J3dThreadData();
061: boolean active = false;
062:
063: // The time to sleep before next processAndProcess() is invoked
064: // for non-blocking input device
065: static int samplingTime = 5;
066:
067: // Some variables used to name threads correctly
068: private static int numInstances = 0;
069: private int instanceNum = -1;
070:
071: private synchronized int newInstanceNum() {
072: return (++numInstances);
073: }
074:
075: int getInstanceNum() {
076: if (instanceNum == -1)
077: instanceNum = newInstanceNum();
078: return instanceNum;
079: }
080:
081: InputDeviceScheduler(ThreadGroup threadGroup,
082: PhysicalEnvironment physicalEnv) {
083: super (threadGroup);
084: setName("J3D-InputDeviceScheduler-" + getInstanceNum());
085: threadData.threadType = J3dThread.INPUT_DEVICE_SCHEDULER;
086: threadData.thread = this ;
087: this .physicalEnv = physicalEnv;
088:
089: synchronized (physicalEnv.devices) {
090: Enumeration elm = physicalEnv.devices.elements();
091: while (elm.hasMoreElements()) {
092: addInputDevice((InputDevice) elm.nextElement());
093: }
094: physicalEnv.inputsched = this ;
095: }
096:
097: }
098:
099: void addInputDevice(InputDevice device) {
100:
101: switch (device.getProcessingMode()) {
102: case InputDevice.BLOCKING:
103: InputDeviceBlockingThread thread = VirtualUniverse.mc
104: .getInputDeviceBlockingThread(device);
105: thread.start();
106: synchronized (blockingDevices) {
107: threads.add(thread);
108: blockingDevices.add(device);
109: }
110: break;
111: case InputDevice.NON_BLOCKING:
112: synchronized (nonBlockingDevices) {
113: nonBlockingDevices.add(device);
114: if (active && (nonBlockingDevices.size() == 1)) {
115: VirtualUniverse.mc.addInputDeviceScheduler(this );
116: }
117: }
118: break;
119: default: // InputDevice.DEMAND_DRIVEN:
120: // tag the sensors
121: for (int i = device.getSensorCount() - 1; i >= 0; i--) {
122: device.getSensor(i).demand_driven = true;
123: }
124: break;
125: }
126:
127: }
128:
129: void removeInputDevice(InputDevice device) {
130:
131: switch (device.getProcessingMode()) {
132: case InputDevice.BLOCKING:
133: // tell the thread to clean up and permanently block
134: synchronized (blockingDevices) {
135: int idx = blockingDevices.indexOf(device);
136: InputDeviceBlockingThread thread = (InputDeviceBlockingThread) threads
137: .remove(idx);
138: thread.finish();
139: blockingDevices.remove(idx);
140: }
141: break;
142: case InputDevice.NON_BLOCKING:
143: // remove references that are in this thread
144: synchronized (nonBlockingDevices) {
145: nonBlockingDevices.remove(nonBlockingDevices
146: .indexOf(device));
147: if (active && (nonBlockingDevices.size() == 0)) {
148: VirtualUniverse.mc.removeInputDeviceScheduler(this );
149: }
150: }
151: break;
152: default: // InputDevice.DEMAND_DRIVEN:
153: // untag the sensors
154: for (int i = device.getSensorCount() - 1; i >= 0; i--) {
155: device.getSensor(i).demand_driven = false;
156: }
157: }
158: }
159:
160: // Add this thread to MC (Callback from MC thread)
161: void activate() {
162: if (!active) {
163: active = true;
164:
165: synchronized (nonBlockingDevices) {
166: if (nonBlockingDevices.size() > 0) {
167: VirtualUniverse.mc.addInputDeviceScheduler(this );
168: }
169: }
170: // run all spawn threads
171: synchronized (blockingDevices) {
172: for (int i = threads.size() - 1; i >= 0; i--) {
173: ((InputDeviceBlockingThread) threads.get(i))
174: .restart();
175: }
176: }
177: }
178: }
179:
180: // Remove this thread from MC (Callback from MC thread)
181: void deactivate() {
182: if (active) {
183: synchronized (nonBlockingDevices) {
184: if (nonBlockingDevices.size() > 0) {
185: VirtualUniverse.mc.removeInputDeviceScheduler(this );
186: }
187: }
188:
189: // stop all spawn threads
190: synchronized (blockingDevices) {
191: for (int i = threads.size() - 1; i >= 0; i--) {
192: ((InputDeviceBlockingThread) threads.get(i))
193: .sleep();
194: }
195: }
196: active = false;
197: }
198: }
199:
200: J3dThreadData getThreadData() {
201: return threadData;
202: }
203:
204: void doWork(long referenceTime) {
205: synchronized (nonBlockingDevices) {
206: for (int i = nonBlockingDevices.size() - 1; i >= 0; i--) {
207: ((InputDevice) nonBlockingDevices.get(i))
208: .pollAndProcessInput();
209: }
210: }
211: }
212:
213: void shutdown() {
214: // stop all spawn threads
215: for (int i = threads.size() - 1; i >= 0; i--) {
216: ((InputDeviceBlockingThread) threads.get(i)).finish();
217: }
218: // for gc
219: threads.clear();
220: blockingDevices.clear();
221: nonBlockingDevices.clear();
222: devices.clear();
223: }
224:
225: }
|